refactor to allow better support for multiple layers
authordadubrow
Mon, 26 Jul 2010 15:11:10 -0500
changeset 1684 c2eba6dabd38
parent 1679 4dbd593daf6d
child 1689 8e2b71714488
refactor to allow better support for multiple layers
core/com.nokia.carbide.discovery.ui/plugin.xml
core/com.nokia.carbide.discovery.ui/schema/portalPage.exsd
core/com.nokia.carbide.discovery.ui/schema/portalPageLayer.exsd
core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/editor/ActionUIUpdater.java
core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/editor/NavigationBar.java
core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/editor/PortalEditor.java
core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/editor/PortalPage.java
core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/editor/TaskBar.java
core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/extension/AbstractBrowserPortalPage.java
core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/extension/AbstractMultiLayerPortalPage.java
core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/extension/IPortalEditor.java
core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/extension/IPortalExtension.java
core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/extension/IPortalPage.java
core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/view/InstallExtensionsPage.java
core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/view/InstallExtensionsPortalExtension.java
--- a/core/com.nokia.carbide.discovery.ui/plugin.xml	Fri Jul 23 15:40:47 2010 -0500
+++ b/core/com.nokia.carbide.discovery.ui/plugin.xml	Mon Jul 26 15:11:10 2010 -0500
@@ -2,6 +2,7 @@
 <?eclipse version="3.4"?>
 <plugin>
    <extension-point id="portalPage" name="Portal Page" schema="schema/portalPage.exsd"/>
+   <extension-point id="portalPageLayer" name="Portal Page Layer" schema="schema/portalPageLayer.exsd"/>
    <extension
          point="org.eclipse.help.contexts">
       <contexts
@@ -48,21 +49,21 @@
  <extension
        point="com.nokia.carbide.discovery.ui.portalPage">
     <portalPage
-          class="com.nokia.carbide.internal.discovery.ui.view.InstallExtensionsPage"
+          class="com.nokia.carbide.internal.discovery.ui.view.InstallExtensionsPortalExtension"
+          id="installExtensionsPage"
+          order="50"
           rank="50">
     </portalPage>
- </extension>
- <extension
-       point="com.nokia.carbide.discovery.ui.portalPage">
     <portalPage
           class="com.nokia.carbide.internal.discovery.ui.view.HomePage"
+          id="homePage"
+          order="1"
           rank="1">
     </portalPage>
- </extension>
- <extension
-       point="com.nokia.carbide.discovery.ui.portalPage">
     <portalPage
           class="com.nokia.carbide.internal.discovery.ui.view.SupportPage"
+          id="supportPage"
+          order="100"
           rank="100">
     </portalPage>
  </extension>
--- a/core/com.nokia.carbide.discovery.ui/schema/portalPage.exsd	Fri Jul 23 15:40:47 2010 -0500
+++ b/core/com.nokia.carbide.discovery.ui/schema/portalPage.exsd	Mon Jul 26 15:11:10 2010 -0500
@@ -18,7 +18,7 @@
       </annotation>
       <complexType>
          <sequence>
-            <element ref="portalPage"/>
+            <element ref="portalPage" minOccurs="1" maxOccurs="unbounded"/>
          </sequence>
          <attribute name="point" type="string" use="required">
             <annotation>
@@ -49,20 +49,27 @@
 
    <element name="portalPage">
       <complexType>
-         <attribute name="class" type="string">
+         <attribute name="class" type="string" use="required">
             <annotation>
                <documentation>
                   
                </documentation>
                <appinfo>
-                  <meta.attribute kind="java" basedOn=":com.nokia.carbide.internal.discovery.ui.extension.IPortalPage"/>
+                  <meta.attribute kind="java" basedOn=":com.nokia.carbide.internal.discovery.ui.extension.IPortalExtension"/>
                </appinfo>
             </annotation>
          </attribute>
-         <attribute name="rank" type="string">
+         <attribute name="order" type="string">
             <annotation>
                <documentation>
-                  relative ordering of pages in the navigation bar (1-100)
+                  relative ordering of pages in the navigation bar (integer used to sort pages)
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  identifier for the page - required for multi-layer pages
                </documentation>
             </annotation>
          </attribute>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/com.nokia.carbide.discovery.ui/schema/portalPageLayer.exsd	Mon Jul 26 15:11:10 2010 -0500
@@ -0,0 +1,116 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="com.nokia.carbide.discovery.ui" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+      <appinfo>
+         <meta.schema plugin="com.nokia.carbide.discovery.ui" id="portalPageLayer" name="Portal Page Layer"/>
+      </appinfo>
+      <documentation>
+         [Enter description of this extension point.]
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <annotation>
+         <appinfo>
+            <meta.element />
+         </appinfo>
+      </annotation>
+      <complexType>
+         <sequence minOccurs="1" maxOccurs="unbounded">
+            <element ref="portalPageLayer"/>
+         </sequence>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute translatable="true"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="portalPageLayer">
+      <complexType>
+         <attribute name="class" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="java" basedOn=":com.nokia.carbide.internal.discovery.ui.extension.IPortalExtension"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+         <attribute name="order" type="string">
+            <annotation>
+               <documentation>
+                  relative ordering of layers in a page navigation bar (integer used to sort layers)
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="pageId" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="since"/>
+      </appinfo>
+      <documentation>
+         [Enter the first release in which this extension point appears.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="examples"/>
+      </appinfo>
+      <documentation>
+         [Enter extension point usage example here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="apiinfo"/>
+      </appinfo>
+      <documentation>
+         [Enter API information here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="implementation"/>
+      </appinfo>
+      <documentation>
+         [Enter information about supplied implementation of this extension point.]
+      </documentation>
+   </annotation>
+
+
+</schema>
--- a/core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/editor/ActionUIUpdater.java	Fri Jul 23 15:40:47 2010 -0500
+++ b/core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/editor/ActionUIUpdater.java	Mon Jul 26 15:11:10 2010 -0500
@@ -19,7 +19,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import com.nokia.carbide.internal.discovery.ui.extension.IPortalPage.IActionUIUpdater;
+import com.nokia.carbide.internal.discovery.ui.extension.IPortalExtension.IActionUIUpdater;
 
 class ActionUIUpdater implements IActionUIUpdater {
 	
--- a/core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/editor/NavigationBar.java	Fri Jul 23 15:40:47 2010 -0500
+++ b/core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/editor/NavigationBar.java	Mon Jul 26 15:11:10 2010 -0500
@@ -32,8 +32,6 @@
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 
-import com.nokia.carbide.internal.discovery.ui.extension.IPortalPage;
-
 class NavigationBar extends RoundedCornerComposite {
 
 	private PortalEditor portalEditor;
@@ -47,7 +45,7 @@
 		}
 	}
 
-	private Map<Button, IPortalPage> buttonToPageMap;
+	private Map<Button, PortalPage> buttonToPageMap;
 	private SelectionListener listener;
 	private Font buttonFont;
 	private Font selectedButtonFont;
@@ -57,7 +55,7 @@
 				parent.getDisplay().getSystemColor(SWT.COLOR_BLACK),
 				parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
 		this.portalEditor = portalEditor;
-		buttonToPageMap = new LinkedHashMap<Button, IPortalPage>();
+		buttonToPageMap = new LinkedHashMap<Button, PortalPage>();
 		RowLayoutFactory.swtDefaults().margins(3, 3).wrap(false).applyTo(this);
 		listener = new ButtonListener();
 		selectedButtonFont = JFaceResources.getHeaderFont();
@@ -75,11 +73,11 @@
 		selectNavButton(buttonToPageMap.keySet().iterator().next());
 	}
 
-	public void addNavButton(NavigationBar bar, IPortalPage page) {
+	public void addNavButton(NavigationBar bar, PortalPage page) {
 		Button b = new Button(bar, SWT.TOGGLE | SWT.FLAT);
 		b.setFont(buttonFont);
-		b.setText(page.getText());
-		b.setImage(portalEditor.createImage(page.getImageDescriptor(), 16, 16));
+		b.setText(page.getPortalExtension().getText());
+		b.setImage(portalEditor.createImage(page.getPortalExtension().getImageDescriptor(), 16, 16));
 		b.addSelectionListener(listener);
 		RowDataFactory.swtDefaults().applyTo(b);
 		buttonToPageMap.put(b, page);
--- a/core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/editor/PortalEditor.java	Fri Jul 23 15:40:47 2010 -0500
+++ b/core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/editor/PortalEditor.java	Mon Jul 26 15:11:10 2010 -0500
@@ -20,9 +20,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IConfigurationElement;
@@ -45,6 +43,7 @@
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
 import org.eclipse.ui.IEditorSite;
 import org.eclipse.ui.IPersistableElement;
 import org.eclipse.ui.PartInitException;
@@ -53,64 +52,63 @@
 
 import com.nokia.carbide.discovery.ui.Activator;
 import com.nokia.carbide.discovery.ui.Messages;
-import com.nokia.carbide.internal.discovery.ui.extension.IPortalPage;
-import com.nokia.carbide.internal.discovery.ui.extension.IPortalPage.IActionBar;
+import com.nokia.carbide.internal.discovery.ui.extension.IPortalEditor;
+import com.nokia.carbide.internal.discovery.ui.extension.IPortalExtension;
+import com.nokia.carbide.internal.discovery.ui.extension.IPortalExtension.IActionBar;
 import com.nokia.cpp.internal.api.utils.core.Pair;
 import com.nokia.cpp.internal.api.utils.ui.WorkbenchUtils;
 
-public class PortalEditor extends EditorPart {
+public class PortalEditor extends EditorPart implements IPortalEditor {
 
 	private static final String ID = "com.nokia.carbide.discovery.ui.portalEditor"; //$NON-NLS-1$
 	private static final String CONTEXT_ID = ID + ".context"; //$NON-NLS-1$
 	private static IEditorInput input;
-	private List<IPortalPage> uninitializedPages;
+	private List<PortalPage> pages;
 	private Composite backgroundParent;
 	private Image oldBGImg;
 	private List<Resource> resources;
 	private StackComposite stackComposite;
-	
-	private Map<IPortalPage, Control> pageToControlMap;
 	private NavigationBar navigationBar;
 
 	public PortalEditor() {
 		resources = new ArrayList<Resource>();
 		loadPortalPages();
-		pageToControlMap = new HashMap<IPortalPage, Control>();
 	}
 	
 	private void loadPortalPages() {
-		List<Pair<IPortalPage, Integer>> pageExtensions = new ArrayList<Pair<IPortalPage,Integer>>();
+		List<Pair<PortalPage, Integer>> pageList = new ArrayList<Pair<PortalPage, Integer>>();
 		IConfigurationElement[] elements = 
 			Platform.getExtensionRegistry().getConfigurationElementsFor(Activator.PLUGIN_ID + ".portalPage"); //$NON-NLS-1$
 		for (IConfigurationElement element : elements) {
 			try {
-				IPortalPage portalPage = (IPortalPage) element.createExecutableExtension("class"); //$NON-NLS-1$
-				String rankString = element.getAttribute("rank"); //$NON-NLS-1$
-				int rank = Integer.MAX_VALUE;
-				if (rankString != null) {
+				IPortalExtension portalExtension = (IPortalExtension) element.createExecutableExtension("class"); //$NON-NLS-1$
+				String id = element.getAttribute("id"); //$NON-NLS-1$
+				String orderString = element.getAttribute("order"); //$NON-NLS-1$
+				int order = Integer.MAX_VALUE;
+				if (orderString != null) {
 					try {
-						rank = Integer.parseInt(rankString);
+						order = Integer.parseInt(orderString);
 					}
 					catch (NumberFormatException e) {
 						Activator.logError(MessageFormat.format(Messages.PortalEditor_PageRankError,
-										portalPage.getClass().getName()), e);
+										portalExtension.getClass().getName()), e);
 					}
 				}
-				pageExtensions.add(new Pair<IPortalPage, Integer>(portalPage, rank));
+				pageList.add(new Pair<PortalPage, Integer>(new PortalPage(portalExtension, id), order));
 			} 
 			catch (CoreException e) {
 				Activator.logError(Messages.PortalEditor_PageLoadError, e);
 			}
 		}
-		Collections.sort(pageExtensions, new Comparator<Pair<IPortalPage, Integer>>() {
+		Collections.sort(pageList, new Comparator<Pair<PortalPage, Integer>>() {
 			@Override
-			public int compare(Pair<IPortalPage, Integer> o1, Pair<IPortalPage, Integer> o2) {
+			public int compare(Pair<PortalPage, Integer> o1, Pair<PortalPage, Integer> o2) {
 				return o1.second.compareTo(o2.second);
 			}
 		});
-		uninitializedPages = new ArrayList<IPortalPage>();
-		for (Pair<IPortalPage, Integer> pair : pageExtensions) {
-			uninitializedPages.add(pair.first);
+		pages = new ArrayList<PortalPage>();
+		for (Pair<PortalPage, Integer> pair : pageList) {
+			pages.add(pair.first);
 		}
 	}
 
@@ -151,7 +149,7 @@
 		backgroundParent = new Composite(parent, SWT.NONE);
 		applyBG(backgroundParent);
 		GridLayoutFactory.fillDefaults().applyTo(backgroundParent);
-		// create top naviation bar
+		// create top navigation bar
 		navigationBar = createNavigationBar(backgroundParent);
 		GridDataFactory.swtDefaults().grab(true, false).align(SWT.CENTER, SWT.TOP).indent(10, 10).applyTo(navigationBar);
 		// create stack composite
@@ -161,14 +159,13 @@
 
 	private void createStackComposite(Composite parent, NavigationBar bar) {
 		stackComposite = new StackComposite(parent, backgroundParent);
-		for (IPortalPage page : uninitializedPages) {
-			Control control = createPage(page);
-			pageToControlMap.put(page, control);
+		for (PortalPage page : pages) {
+			page.setControl(createPage(page.getPortalExtension()));
 		}
 		GridDataFactory.fillDefaults().grab(true, true).applyTo(stackComposite);
 	}
 
-	private Control createPage(IPortalPage page) {
+	private Control createPage(IPortalExtension page) {
 		Composite pageComposite = new SharedBackgroundComposite(stackComposite, backgroundParent);
 		GridLayoutFactory.fillDefaults().numColumns(2).spacing(20, 0).extendedMargins(20, 20, 20, 0).applyTo(pageComposite);
 		ActionUIUpdater updater = new ActionUIUpdater();
@@ -199,19 +196,18 @@
 
 	private NavigationBar createNavigationBar(Composite parent) {
 		NavigationBar bar = new NavigationBar(this, parent);
-		for (IPortalPage page : uninitializedPages) {
+		for (PortalPage page : pages) {
 			bar.addNavButton(bar, page);
 		}
 		
 		return bar;
 	}
 	
-	void showPage(IPortalPage page) {
-		if (uninitializedPages.contains(page)) {
-			uninitializedPages.remove(page);
-			page.init();
+	void showPage(PortalPage page) {
+		if (!page.isInitialized()) {
+			page.getPortalExtension().init();
 		}
-		stackComposite.showControl(pageToControlMap.get(page));
+		stackComposite.showControl(page.getControl());
 	}
 
 	private void applyBG(final Composite composite) {
@@ -319,4 +315,14 @@
 		return backgroundParent;
 	}
 
+	@Override
+	public IEditorPart getEditorPart() {
+		return this;
+	}
+
+	@Override
+	public void refreshCommandBars() {
+		// TODO ask portal page to recreate command bars
+	}
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/editor/PortalPage.java	Mon Jul 26 15:11:10 2010 -0500
@@ -0,0 +1,60 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+package com.nokia.carbide.internal.discovery.ui.editor;
+
+import org.eclipse.swt.widgets.Control;
+
+import com.nokia.carbide.internal.discovery.ui.extension.IPortalExtension;
+
+
+public class PortalPage {
+	
+	private IPortalExtension portalExtension;
+	private String pageId;
+	private Control control;
+	private boolean initialized;
+	
+	public PortalPage(IPortalExtension portalExtension, String pageId) {
+		this.portalExtension = portalExtension;
+		this.pageId = pageId;
+	}
+
+	public IPortalExtension getPortalExtension() {
+		return portalExtension;
+	}
+	
+	public String getPageId() {
+		return pageId;
+	}
+	
+	public void setControl(Control control) {
+		this.control = control;
+	}
+	
+	public Control getControl() {
+		return control;
+	}
+
+	public void setInitialized(boolean initialized) {
+		this.initialized = initialized;
+	}
+	
+	public boolean isInitialized() {
+		return initialized;
+	}
+	
+}
--- a/core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/editor/TaskBar.java	Fri Jul 23 15:40:47 2010 -0500
+++ b/core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/editor/TaskBar.java	Mon Jul 26 15:11:10 2010 -0500
@@ -31,7 +31,7 @@
 import org.eclipse.ui.forms.events.IHyperlinkListener;
 import org.eclipse.ui.forms.widgets.Hyperlink;
 
-import com.nokia.carbide.internal.discovery.ui.extension.IPortalPage.IActionBar;
+import com.nokia.carbide.internal.discovery.ui.extension.IPortalExtension.IActionBar;
 
 class TaskBar extends RoundedCornerComposite {
 
--- a/core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/extension/AbstractBrowserPortalPage.java	Fri Jul 23 15:40:47 2010 -0500
+++ b/core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/extension/AbstractBrowserPortalPage.java	Mon Jul 26 15:11:10 2010 -0500
@@ -35,10 +35,11 @@
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.ui.IEditorPart;
 
+import com.nokia.carbide.internal.discovery.ui.extension.IPortalExtension;
 import com.nokia.carbide.discovery.ui.Activator;
 import com.nokia.carbide.discovery.ui.Messages;
 
-public abstract class AbstractBrowserPortalPage implements IPortalPage {
+public abstract class AbstractBrowserPortalPage implements IPortalExtension {
 
 	private final class NavigationActionBar implements IActionBar {
 		private List<IAction> actions;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/extension/AbstractMultiLayerPortalPage.java	Mon Jul 26 15:11:10 2010 -0500
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+package com.nokia.carbide.internal.discovery.ui.extension;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IEditorPart;
+
+import com.nokia.carbide.internal.discovery.ui.editor.PortalEditor;
+import com.nokia.carbide.internal.discovery.ui.editor.StackComposite;
+import com.nokia.carbide.internal.discovery.ui.extension.IPortalExtension;
+
+/**
+ * An abstract class implementing IPortalPage allowing a single portal page
+ * to contain multiple layers controlled by a command bar
+ */
+public abstract class AbstractMultiLayerPortalPage implements IPortalExtension {
+
+	private StackComposite stackComposite;
+
+	@Override
+	public Control createControl(Composite parent, IEditorPart part) {
+		PortalEditor portalEditor = (PortalEditor) part.getAdapter(PortalEditor.class);
+		stackComposite = new StackComposite(parent, portalEditor.getBackgroundParent());
+		return stackComposite;
+	}
+	
+	
+
+	@Override
+	public void init() {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public IActionBar[] createCommandBars(IEditorPart part, IActionUIUpdater updater) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/extension/IPortalEditor.java	Mon Jul 26 15:11:10 2010 -0500
@@ -0,0 +1,28 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+package com.nokia.carbide.internal.discovery.ui.extension;
+
+import org.eclipse.ui.IEditorPart;
+
+
+public interface IPortalEditor {
+	
+	IEditorPart getEditorPart();
+
+	void refreshCommandBars();
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/extension/IPortalExtension.java	Mon Jul 26 15:11:10 2010 -0500
@@ -0,0 +1,113 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+package com.nokia.carbide.internal.discovery.ui.extension;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IEditorPart;
+
+/**
+ * Interface to a portal extension
+ */
+public interface IPortalExtension {
+
+	/**
+	 * Interface to an action/navigation bar for the portal extension
+	 */
+	public interface IActionBar {
+		
+		/**
+		 * Required title for the action bar
+		 * @return String
+		 */
+		String getTitle();
+		
+		/**
+		 * Actions shown in the action bar:
+		 * Required: text and run() methods
+		 * Optional: tool tip text
+		 * Unused: image/check
+		 * @return IAction
+		 */
+		IAction[] getActions();
+		
+		/**
+		 * Action ids for actions that should be emphasized in the action bar (e.g., bold font)
+		 * @return String[] or null
+		 */
+		String[] getHighlightedActionIds();
+
+	}
+	
+	/**
+	 * Interface allowing the UI for provided actions of an IActionBar to be updated (e.g., enabled state)
+	 */
+	public interface IActionUIUpdater {
+		
+		/**
+		 * Update the UI for a specific action by id
+		 * @param actionId
+		 */
+		void update(String actionId);
+		
+		/**
+		 * Update the UI for all actions in the IActionBar
+		 */
+		void updateAll();
+		
+	}
+
+	/**
+	 * Required title text used by main navigation bar
+	 * @return String
+	 */
+	String getText();
+	
+	/**
+	 * Required image descriptor used by main navigation bar
+	 * @return ImageDescriptor
+	 */
+	ImageDescriptor getImageDescriptor();
+	
+	/**
+	 * Called to create the control for the extension
+	 * @param parent Composite
+	 * @param part IEditorPart
+	 * @return Control
+	 */
+	Control createControl(Composite parent, IEditorPart part);
+	
+	/**
+	 * Called to initialize the extension when shown for the first time
+	 */
+	void init();
+	
+	/**
+	 * Return action bars for the extension
+	 * @param part IEditorPart
+	 * @param updater IActionUIUpdater
+	 * @return IActionBar[]
+	 */
+	IActionBar[] createCommandBars(IEditorPart part, IActionUIUpdater updater);
+	
+	/**
+	 * Called to dispose internal resources of the extension
+	 */
+	void dispose();
+}
--- a/core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/extension/IPortalPage.java	Fri Jul 23 15:40:47 2010 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-/*
-* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
-* All rights reserved.
-* This component and the accompanying materials are made available
-* under the terms of the License "Eclipse Public License v1.0"
-* which accompanies this distribution, and is available
-* at the URL "http://www.eclipse.org/legal/epl-v10.html".
-*
-* Initial Contributors:
-* Nokia Corporation - initial contribution.
-*
-* Contributors:
-*
-* Description: 
-*
-*/
-package com.nokia.carbide.internal.discovery.ui.extension;
-
-import org.eclipse.jface.action.IAction;
-import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.ui.IEditorPart;
-
-/**
- * Interface to a portal page extension
- */
-public interface IPortalPage {
-
-	/**
-	 * Interface to an action/navigation bar for the portal page
-	 */
-	public interface IActionBar {
-		
-		/**
-		 * Required title for the action bar
-		 * @return String
-		 */
-		String getTitle();
-		
-		/**
-		 * Actions shown in the action bar:
-		 * Required: text and run() methods
-		 * Optional: tool tip text
-		 * Unused: image
-		 * @return IAction
-		 */
-		IAction[] getActions();
-		
-		/**
-		 * Action ids for actions that should be emphasized in the action bar (e.g., bold font)
-		 * @return String[] or null
-		 */
-		String[] getHighlightedActionIds();
-
-	}
-	
-	/**
-	 * Interface allowing the UI for provided actions of an IActionBar to be updated (e.g., enabled state)
-	 */
-	public interface IActionUIUpdater {
-		
-		/**
-		 * Update the UI for a specific action by id
-		 * @param actionId
-		 */
-		void update(String actionId);
-		
-		/**
-		 * Update the UI for all actions in the IActionBar
-		 */
-		void updateAll();
-		
-	}
-
-	/**
-	 * Required title text used by main navigation bar
-	 * @return String
-	 */
-	String getText();
-	
-	/**
-	 * Required image descriptor used by main navigation bar
-	 * @return ImageDescriptor
-	 */
-	ImageDescriptor getImageDescriptor();
-	
-	/**
-	 * Called to create the control for the page
-	 * @param parent Composite
-	 * @param part IEditorPart
-	 * @return Control
-	 */
-	Control createControl(Composite parent, IEditorPart part);
-	
-	/**
-	 * Called to initialize the page when shown for the first time
-	 */
-	void init();
-	
-	/**
-	 * Return action bars for the page (can't be null)
-	 * @param part IEditorPart
-	 * @param updater IActionUIUpdater
-	 * @return IActionBar[]
-	 */
-	IActionBar[] createCommandBars(IEditorPart part, IActionUIUpdater updater);
-	
-	/**
-	 * Called to dispose internal resources of the page
-	 */
-	void dispose();
-}
--- a/core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/view/InstallExtensionsPage.java	Fri Jul 23 15:40:47 2010 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,346 +0,0 @@
-package com.nokia.carbide.internal.discovery.ui.view;
-
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.eclipse.equinox.internal.p2.discovery.Catalog;
-import org.eclipse.equinox.internal.p2.discovery.DiscoveryCore;
-import org.eclipse.equinox.internal.p2.discovery.compatibility.BundleDiscoveryStrategy;
-import org.eclipse.equinox.internal.p2.discovery.compatibility.RemoteBundleDiscoveryStrategy;
-import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem;
-import org.eclipse.equinox.internal.p2.ui.discovery.DiscoveryUi;
-import org.eclipse.equinox.internal.p2.ui.discovery.wizards.CatalogConfiguration;
-import org.eclipse.equinox.internal.p2.ui.discovery.wizards.CatalogViewer;
-import org.eclipse.equinox.p2.core.IProvisioningAgent;
-import org.eclipse.equinox.p2.operations.ProvisioningSession;
-import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager;
-import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
-import org.eclipse.equinox.p2.ui.ProvisioningUI;
-import org.eclipse.jface.action.Action;
-import org.eclipse.jface.action.IAction;
-import org.eclipse.jface.dialogs.ProgressMonitorDialog;
-import org.eclipse.jface.layout.GridDataFactory;
-import org.eclipse.jface.layout.GridLayoutFactory;
-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.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.Shell;
-import org.eclipse.ui.IActionBars;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.PartInitException;
-import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.actions.BaseSelectionListenerAction;
-import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
-
-import com.nokia.carbide.discovery.ui.Activator;
-import com.nokia.carbide.discovery.ui.Messages;
-import com.nokia.carbide.internal.discovery.ui.extension.IPortalPage;
-import com.nokia.cpp.internal.api.utils.ui.WorkbenchUtils;
-
-@SuppressWarnings("restriction")
-public class InstallExtensionsPage implements IPortalPage {
-
-	private static final String INSTALL_ACTION_ID = InstallExtensionsPage.class.getName() + ".install"; //$NON-NLS-1$
-
-	private final class RunnableContextDialog extends ProgressMonitorDialog {
-		private final String title;
-
-		private RunnableContextDialog(Shell parent, String title) {
-			super(parent);
-			this.title = title;
-		}
-
-		@Override
-		protected void configureShell(Shell shell) {
-			super.configureShell(shell);
-			shell.setText(title);
-		}
-		
-	}
-
-	private final class ActionBar implements IActionBar {
-		private IAction[] actions;
-
-		public ActionBar(IEditorPart part) {
-			actions = makeActions(part);
-		}
-		
-		@Override
-		public String getTitle() {
-			return Messages.InstallExtensionsPage_ActionBarTitle;
-		}
-
-		@Override
-		public IAction[] getActions() {
-			return actions;
-		}
-
-		@Override
-		public String[] getHighlightedActionIds() {
-			return new String[] {INSTALL_ACTION_ID};
-		}
-	}
-	
-	private final class LinkBar implements IActionBar {
-		@Override
-		public String getTitle() {
-			return Messages.InstallExtensionsPage_LinkBarTitle;
-		}
-
-		@Override
-		public IAction[] getActions() {
-			IAction action = new Action(Messages.InstallExtensionsPage_BuzillaActionName) {
-				@Override
-				public void run() {
-					try {
-						URL url = new URL("https://xdabug001.ext.nokia.com/bugzilla"); //$NON-NLS-1$
-						IWorkbenchBrowserSupport browserSupport = PlatformUI.getWorkbench().getBrowserSupport();
-						browserSupport.createBrowser(null).openURL(url);
-					} catch (MalformedURLException e) {
-					} catch (PartInitException e) {
-					}
-				}
-			};
-			return new IAction[] { action };
-		}
-
-		@Override
-		public String[] getHighlightedActionIds() {
-			return null;
-		}
-	}
-
-	private static final String DIRECTORY_KEY = "com.nokia.carbide.discovery.directory"; //$NON-NLS-1$
-
-	private CatalogViewer viewer;
-	private List<ISelectionChangedListener> selectionListeners;
-	private IActionUIUpdater updater;
-
-	public InstallExtensionsPage() {
-	}
-
-	@Override
-	public String getText() {
-		return Messages.InstallExtensionsPage_Title;
-	}
-
-	@Override
-	public ImageDescriptor getImageDescriptor() {
-		return Activator.getImageDescriptor("icons/icon-discovery.png"); //$NON-NLS-1$
-	}
-
-	@Override
-	public Control createControl(Composite parent, IEditorPart part) {
-		Composite c = new Composite(parent, SWT.NONE);
-		GridLayoutFactory.swtDefaults().applyTo(c);
-		viewer = new CatalogViewer(getCatalog(), part.getEditorSite(), 
-				new RunnableContextDialog(part.getEditorSite().getShell(), 
-						Messages.InstallExtensionsPage_GatherExtensionsTitle), 
-				getConfiguration());
-		viewer.createControl(c);
-		GridDataFactory.fillDefaults().grab(true, true).applyTo(viewer.getControl());
-		
-		// Create the help context id for the viewer's control
-		PlatformUI.getWorkbench().getHelpSystem().setHelp(viewer.getControl(), 
-				"com.nokia.carbide.discovery.ui.view.DiscoveryView.catalogviewer"); //$NON-NLS-1$
-		return c;
-	}
-
-	@Override
-	public void init() {
-		if (!WorkbenchUtils.isJUnitRunning()) { // do not initialize the catalog if JUnit is running
-			Display.getDefault().asyncExec(new Runnable() {
-				@Override
-				public void run() {
-					for (ISelectionChangedListener listener : selectionListeners) {
-						viewer.addSelectionChangedListener(listener);
-					}
-					viewer.updateCatalog();
-				}
-			});
-		}
-	}
-	
-	@Override
-	public IActionBar[] createCommandBars(IEditorPart part, IActionUIUpdater updater) {
-		this.updater = updater;
-		return new IActionBar[] { new ActionBar(part), new LinkBar() };
-	}
-
-	private CatalogConfiguration getConfiguration() {
-		CatalogConfiguration configuration = new CatalogConfiguration();
-		configuration.setShowTagFilter(false);
-		return configuration;
-	}
-
-	private Catalog getCatalog() {
-		Catalog catalog = new Catalog();
-		catalog.setEnvironment(DiscoveryCore.createEnvironment());
-		catalog.setVerifyUpdateSiteAvailability(false);
-		
-		// look for remote descriptor
-		RemoteBundleDiscoveryStrategy remoteDiscoveryStrategy = new RemoteBundleDiscoveryStrategy();
-		String url = Activator.getFromServerProperties(DIRECTORY_KEY);
-		if (url != null) {
-			remoteDiscoveryStrategy.setDirectoryUrl(url);
-			catalog.getDiscoveryStrategies().add(remoteDiscoveryStrategy);
-		}
-		else // look for descriptors from installed bundles
-			catalog.getDiscoveryStrategies().add(new BundleDiscoveryStrategy());
-
-		return catalog;
-	}
-
-	private IAction[] makeActions(final IEditorPart part) {
-		selectionListeners = new ArrayList<ISelectionChangedListener>();
-		List<IAction> actions = new ArrayList<IAction>();
-		IAction action;
-		
-		// install
-		action = new BaseSelectionListenerAction(Messages.InstallExtensionsPage_InstallLabel) {
-			public void run() {
-				DiscoveryUi.install(viewer.getCheckedItems(), 
-						new RunnableContextDialog(part.getEditorSite().getShell(), 
-								Messages.InstallExtensionsPage_GatheringInstallInfoTitle));
-			};
-			
-			protected boolean updateSelection(IStructuredSelection selection) {
-				scheduleUpdateAllActionUIs();
-				return !selection.isEmpty();
-			};
-		};
-		action.setToolTipText(Messages.InstallExtensionsPage_InstallTip);
-		action.setId(INSTALL_ACTION_ID);
-		selectionListeners.add((ISelectionChangedListener) action);
-		actions.add(action);
-		
-		// refresh
-		action = new Action(Messages.InstallExtensionsPage_RefreshLabel) {
-			public void run() {
-				viewer.setSelection(StructuredSelection.EMPTY);
-				viewer.updateCatalog();
-				viewer.refresh();
-			}
-		};
-		actions.add(action);
-		
-		// check all
-		action = new BaseSelectionListenerAction(Messages.InstallExtensionsPage_CheckAllLabel) {
-			public void run() {
-				viewer.setSelection(StructuredSelection.EMPTY);
-				viewer.setSelection(getAllItemsSelection());
-				viewer.refresh();
-			}
-
-			private IStructuredSelection getAllItemsSelection() {
-				List<CatalogItem> catalogItems = new ArrayList<CatalogItem>();
-				for (CatalogItem catalogItem : viewer.getCatalog().getItems()) {
-					if (!catalogItem.isInstalled())
-						catalogItems.add(catalogItem);
-				}	
-				return new StructuredSelection(catalogItems);
-			}
-
-			protected boolean updateSelection(IStructuredSelection selection) {
-				scheduleUpdateAllActionUIs();
-				return !getAllItemsSelection().equals(selection);
-			}
-		};
-		action.setId(InstallExtensionsPage.class.getName() + ".checkAll"); //$NON-NLS-1$
-		selectionListeners.add((ISelectionChangedListener) action);
-		actions.add(action);
-		
-		// uncheck all
-		action = new BaseSelectionListenerAction(Messages.InstallExtensionsPage_UncheckAllLabel) {
-			public void run() {
-				viewer.setSelection(StructuredSelection.EMPTY);
-				viewer.refresh();
-			};
-			
-			protected boolean updateSelection(IStructuredSelection selection) {
-				scheduleUpdateAllActionUIs();
-				return !selection.isEmpty();
-			};
-		};
-		action.setId(InstallExtensionsPage.class.getName() + ".uncheckAll"); //$NON-NLS-1$
-		selectionListeners.add((ISelectionChangedListener) action);
-		actions.add(action);
-		
-		// advanced install
-		action = new Action(Messages.InstallExtensionsPage_AdvancedInstallLabel) {
-			public void run() {
-				showInstallWizard();
-			}
-		};
-		actions.add(action);
-		
-		ISelectionChangedListener selectionListener = new ISelectionChangedListener() {
-			@Override
-			public void selectionChanged(SelectionChangedEvent event) {
-				IStructuredSelection selection = (IStructuredSelection) event.getSelection();
-				IActionBars bars = part.getEditorSite().getActionBars();
-				bars.getStatusLineManager().setMessage(
-						selection.isEmpty() ? null : MessageFormat.format(
-								Messages.InstallExtensionsPage_StatusLineFmt, selection.size()));
-			}
-		};
-		selectionListeners.add(selectionListener);
-		
-		return (IAction[]) actions.toArray(new IAction[actions.size()]);
-	}
-	
-	@Override
-	public void dispose() {
-		for (ISelectionChangedListener listener : selectionListeners) {
-			viewer.removeSelectionChangedListener(listener);
-		}
-	}
-
-	private void showInstallWizard() {
-		ProvisioningUI defaultUI = ProvisioningUI.getDefaultUI();
-		ProvisioningSession session = defaultUI.getSession();
-		IProvisioningAgent agent = session.getProvisioningAgent();
-		IMetadataRepositoryManager metadataManager = (IMetadataRepositoryManager) agent.getService(IMetadataRepositoryManager.SERVICE_NAME);
-		IArtifactRepositoryManager artifactManager = (IArtifactRepositoryManager) agent.getService(IArtifactRepositoryManager.SERVICE_NAME);
-		for (URI uri : getCatalogURIs()) {
-			metadataManager.addRepository(uri);
-			artifactManager.addRepository(uri);
-		}
-		defaultUI.openInstallWizard(null, null, null);
-	}
-
-	private Collection<URI> getCatalogURIs() {
-		Set<URI> uris = new HashSet<URI>();
-		for (CatalogItem catalogItem : viewer.getCatalog().getItems()) {
-			try {
-				uris.add(new URI(catalogItem.getSiteUrl()));
-			} catch (URISyntaxException e) {
-				// ignore bad URIs
-			}
-		}
-		return uris;
-	};
-
-	private void scheduleUpdateAllActionUIs() {
-		Display.getDefault().asyncExec(new Runnable() {
-			@Override
-			public void run() {
-				updater.updateAll();
-			}
-		});
-	};
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/view/InstallExtensionsPortalExtension.java	Mon Jul 26 15:11:10 2010 -0500
@@ -0,0 +1,346 @@
+package com.nokia.carbide.internal.discovery.ui.view;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.equinox.internal.p2.discovery.Catalog;
+import org.eclipse.equinox.internal.p2.discovery.DiscoveryCore;
+import org.eclipse.equinox.internal.p2.discovery.compatibility.BundleDiscoveryStrategy;
+import org.eclipse.equinox.internal.p2.discovery.compatibility.RemoteBundleDiscoveryStrategy;
+import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem;
+import org.eclipse.equinox.internal.p2.ui.discovery.DiscoveryUi;
+import org.eclipse.equinox.internal.p2.ui.discovery.wizards.CatalogConfiguration;
+import org.eclipse.equinox.internal.p2.ui.discovery.wizards.CatalogViewer;
+import org.eclipse.equinox.p2.core.IProvisioningAgent;
+import org.eclipse.equinox.p2.operations.ProvisioningSession;
+import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager;
+import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
+import org.eclipse.equinox.p2.ui.ProvisioningUI;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+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.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.Shell;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.BaseSelectionListenerAction;
+import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
+
+import com.nokia.carbide.discovery.ui.Activator;
+import com.nokia.carbide.discovery.ui.Messages;
+import com.nokia.carbide.internal.discovery.ui.extension.IPortalExtension;
+import com.nokia.cpp.internal.api.utils.ui.WorkbenchUtils;
+
+@SuppressWarnings("restriction")
+public class InstallExtensionsPortalExtension implements IPortalExtension {
+
+	private static final String INSTALL_ACTION_ID = InstallExtensionsPortalExtension.class.getName() + ".install"; //$NON-NLS-1$
+
+	private final class RunnableContextDialog extends ProgressMonitorDialog {
+		private final String title;
+
+		private RunnableContextDialog(Shell parent, String title) {
+			super(parent);
+			this.title = title;
+		}
+
+		@Override
+		protected void configureShell(Shell shell) {
+			super.configureShell(shell);
+			shell.setText(title);
+		}
+		
+	}
+
+	private final class ActionBar implements IActionBar {
+		private IAction[] actions;
+
+		public ActionBar(IEditorPart part) {
+			actions = makeActions(part);
+		}
+		
+		@Override
+		public String getTitle() {
+			return Messages.InstallExtensionsPage_ActionBarTitle;
+		}
+
+		@Override
+		public IAction[] getActions() {
+			return actions;
+		}
+
+		@Override
+		public String[] getHighlightedActionIds() {
+			return new String[] {INSTALL_ACTION_ID};
+		}
+	}
+	
+	private final class LinkBar implements IActionBar {
+		@Override
+		public String getTitle() {
+			return Messages.InstallExtensionsPage_LinkBarTitle;
+		}
+
+		@Override
+		public IAction[] getActions() {
+			IAction action = new Action(Messages.InstallExtensionsPage_BuzillaActionName) {
+				@Override
+				public void run() {
+					try {
+						URL url = new URL("https://xdabug001.ext.nokia.com/bugzilla"); //$NON-NLS-1$
+						IWorkbenchBrowserSupport browserSupport = PlatformUI.getWorkbench().getBrowserSupport();
+						browserSupport.createBrowser(null).openURL(url);
+					} catch (MalformedURLException e) {
+					} catch (PartInitException e) {
+					}
+				}
+			};
+			return new IAction[] { action };
+		}
+
+		@Override
+		public String[] getHighlightedActionIds() {
+			return null;
+		}
+	}
+
+	private static final String DIRECTORY_KEY = "com.nokia.carbide.discovery.directory"; //$NON-NLS-1$
+
+	private CatalogViewer viewer;
+	private List<ISelectionChangedListener> selectionListeners;
+	private IActionUIUpdater updater;
+
+	public InstallExtensionsPortalExtension() {
+	}
+
+	@Override
+	public String getText() {
+		return Messages.InstallExtensionsPage_Title;
+	}
+
+	@Override
+	public ImageDescriptor getImageDescriptor() {
+		return Activator.getImageDescriptor("icons/icon-discovery.png"); //$NON-NLS-1$
+	}
+
+	@Override
+	public Control createControl(Composite parent, IEditorPart part) {
+		Composite c = new Composite(parent, SWT.NONE);
+		GridLayoutFactory.swtDefaults().applyTo(c);
+		viewer = new CatalogViewer(getCatalog(), part.getEditorSite(), 
+				new RunnableContextDialog(part.getEditorSite().getShell(), 
+						Messages.InstallExtensionsPage_GatherExtensionsTitle), 
+				getConfiguration());
+		viewer.createControl(c);
+		GridDataFactory.fillDefaults().grab(true, true).applyTo(viewer.getControl());
+		
+		// Create the help context id for the viewer's control
+		PlatformUI.getWorkbench().getHelpSystem().setHelp(viewer.getControl(), 
+				"com.nokia.carbide.discovery.ui.view.DiscoveryView.catalogviewer"); //$NON-NLS-1$
+		return c;
+	}
+
+	@Override
+	public void init() {
+		if (!WorkbenchUtils.isJUnitRunning()) { // do not initialize the catalog if JUnit is running
+			Display.getDefault().asyncExec(new Runnable() {
+				@Override
+				public void run() {
+					for (ISelectionChangedListener listener : selectionListeners) {
+						viewer.addSelectionChangedListener(listener);
+					}
+					viewer.updateCatalog();
+				}
+			});
+		}
+	}
+	
+	@Override
+	public IActionBar[] createCommandBars(IEditorPart part, IActionUIUpdater updater) {
+		this.updater = updater;
+		return new IActionBar[] { new ActionBar(part), new LinkBar() };
+	}
+
+	private CatalogConfiguration getConfiguration() {
+		CatalogConfiguration configuration = new CatalogConfiguration();
+		configuration.setShowTagFilter(false);
+		return configuration;
+	}
+
+	private Catalog getCatalog() {
+		Catalog catalog = new Catalog();
+		catalog.setEnvironment(DiscoveryCore.createEnvironment());
+		catalog.setVerifyUpdateSiteAvailability(false);
+		
+		// look for remote descriptor
+		RemoteBundleDiscoveryStrategy remoteDiscoveryStrategy = new RemoteBundleDiscoveryStrategy();
+		String url = Activator.getFromServerProperties(DIRECTORY_KEY);
+		if (url != null) {
+			remoteDiscoveryStrategy.setDirectoryUrl(url);
+			catalog.getDiscoveryStrategies().add(remoteDiscoveryStrategy);
+		}
+		else // look for descriptors from installed bundles
+			catalog.getDiscoveryStrategies().add(new BundleDiscoveryStrategy());
+
+		return catalog;
+	}
+
+	private IAction[] makeActions(final IEditorPart part) {
+		selectionListeners = new ArrayList<ISelectionChangedListener>();
+		List<IAction> actions = new ArrayList<IAction>();
+		IAction action;
+		
+		// install
+		action = new BaseSelectionListenerAction(Messages.InstallExtensionsPage_InstallLabel) {
+			public void run() {
+				DiscoveryUi.install(viewer.getCheckedItems(), 
+						new RunnableContextDialog(part.getEditorSite().getShell(), 
+								Messages.InstallExtensionsPage_GatheringInstallInfoTitle));
+			};
+			
+			protected boolean updateSelection(IStructuredSelection selection) {
+				scheduleUpdateAllActionUIs();
+				return !selection.isEmpty();
+			};
+		};
+		action.setToolTipText(Messages.InstallExtensionsPage_InstallTip);
+		action.setId(INSTALL_ACTION_ID);
+		selectionListeners.add((ISelectionChangedListener) action);
+		actions.add(action);
+		
+		// refresh
+		action = new Action(Messages.InstallExtensionsPage_RefreshLabel) {
+			public void run() {
+				viewer.setSelection(StructuredSelection.EMPTY);
+				viewer.updateCatalog();
+				viewer.refresh();
+			}
+		};
+		actions.add(action);
+		
+		// check all
+		action = new BaseSelectionListenerAction(Messages.InstallExtensionsPage_CheckAllLabel) {
+			public void run() {
+				viewer.setSelection(StructuredSelection.EMPTY);
+				viewer.setSelection(getAllItemsSelection());
+				viewer.refresh();
+			}
+
+			private IStructuredSelection getAllItemsSelection() {
+				List<CatalogItem> catalogItems = new ArrayList<CatalogItem>();
+				for (CatalogItem catalogItem : viewer.getCatalog().getItems()) {
+					if (!catalogItem.isInstalled())
+						catalogItems.add(catalogItem);
+				}	
+				return new StructuredSelection(catalogItems);
+			}
+
+			protected boolean updateSelection(IStructuredSelection selection) {
+				scheduleUpdateAllActionUIs();
+				return !getAllItemsSelection().equals(selection);
+			}
+		};
+		action.setId(InstallExtensionsPortalExtension.class.getName() + ".checkAll"); //$NON-NLS-1$
+		selectionListeners.add((ISelectionChangedListener) action);
+		actions.add(action);
+		
+		// uncheck all
+		action = new BaseSelectionListenerAction(Messages.InstallExtensionsPage_UncheckAllLabel) {
+			public void run() {
+				viewer.setSelection(StructuredSelection.EMPTY);
+				viewer.refresh();
+			};
+			
+			protected boolean updateSelection(IStructuredSelection selection) {
+				scheduleUpdateAllActionUIs();
+				return !selection.isEmpty();
+			};
+		};
+		action.setId(InstallExtensionsPortalExtension.class.getName() + ".uncheckAll"); //$NON-NLS-1$
+		selectionListeners.add((ISelectionChangedListener) action);
+		actions.add(action);
+		
+		// advanced install
+		action = new Action(Messages.InstallExtensionsPage_AdvancedInstallLabel) {
+			public void run() {
+				showInstallWizard();
+			}
+		};
+		actions.add(action);
+		
+		ISelectionChangedListener selectionListener = new ISelectionChangedListener() {
+			@Override
+			public void selectionChanged(SelectionChangedEvent event) {
+				IStructuredSelection selection = (IStructuredSelection) event.getSelection();
+				IActionBars bars = part.getEditorSite().getActionBars();
+				bars.getStatusLineManager().setMessage(
+						selection.isEmpty() ? null : MessageFormat.format(
+								Messages.InstallExtensionsPage_StatusLineFmt, selection.size()));
+			}
+		};
+		selectionListeners.add(selectionListener);
+		
+		return (IAction[]) actions.toArray(new IAction[actions.size()]);
+	}
+	
+	@Override
+	public void dispose() {
+		for (ISelectionChangedListener listener : selectionListeners) {
+			viewer.removeSelectionChangedListener(listener);
+		}
+	}
+
+	private void showInstallWizard() {
+		ProvisioningUI defaultUI = ProvisioningUI.getDefaultUI();
+		ProvisioningSession session = defaultUI.getSession();
+		IProvisioningAgent agent = session.getProvisioningAgent();
+		IMetadataRepositoryManager metadataManager = (IMetadataRepositoryManager) agent.getService(IMetadataRepositoryManager.SERVICE_NAME);
+		IArtifactRepositoryManager artifactManager = (IArtifactRepositoryManager) agent.getService(IArtifactRepositoryManager.SERVICE_NAME);
+		for (URI uri : getCatalogURIs()) {
+			metadataManager.addRepository(uri);
+			artifactManager.addRepository(uri);
+		}
+		defaultUI.openInstallWizard(null, null, null);
+	}
+
+	private Collection<URI> getCatalogURIs() {
+		Set<URI> uris = new HashSet<URI>();
+		for (CatalogItem catalogItem : viewer.getCatalog().getItems()) {
+			try {
+				uris.add(new URI(catalogItem.getSiteUrl()));
+			} catch (URISyntaxException e) {
+				// ignore bad URIs
+			}
+		}
+		return uris;
+	};
+
+	private void scheduleUpdateAllActionUIs() {
+		Display.getDefault().asyncExec(new Runnable() {
+			@Override
+			public void run() {
+				updater.updateAll();
+			}
+		});
+	};
+}