Added a way to contribute wizard pages for templates
authorEugene Ostroukhov <eugeneo@symbian.org>
Mon, 16 Aug 2010 16:23:25 -0700
changeset 465 87920e15f8eb
parent 464 0b02f3d6f52c
child 466 129c94e78375
Added a way to contribute wizard pages for templates
org.symbian.tools.mtw.ui/META-INF/MANIFEST.MF
org.symbian.tools.mtw.ui/plugin.xml
org.symbian.tools.mtw.ui/schema/projectTemplate.exsd
org.symbian.tools.mtw.ui/schema/wizardPages.exsd
org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/internal/ui/project/ProjectTemplateImpl.java
org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/internal/ui/wizard/FacetsSelectionPage.java
org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/internal/ui/wizard/FacetsSelectionPanel.java
org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/internal/ui/wizard/NewApplicationFacetsWizardPage.java
org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/internal/ui/wizard/NewApplicationWizard.java
org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/internal/ui/wizard/PageContributions.java
org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/internal/ui/wizard/WizardContext.java
org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/ui/project/INewApplicationWizardPage.java
org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/ui/project/IProjectTemplate.java
org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/ui/project/IProjectTemplateContext.java
org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/ui/project/IProjectTemplateManager.java
org.symbian.tools.wrttools/plugin.xml
org.symbian.tools.wrttools/src/org/symbian/tools/wrttools/util/CompoundValidator.java
org.symbian.tools.wrttools/src/org/symbian/tools/wrttools/wizards/NewFlickrApplicationWizardPage.java
--- a/org.symbian.tools.mtw.ui/META-INF/MANIFEST.MF	Fri Aug 13 17:26:00 2010 -0700
+++ b/org.symbian.tools.mtw.ui/META-INF/MANIFEST.MF	Mon Aug 16 16:23:25 2010 -0700
@@ -25,7 +25,8 @@
 Bundle-ClassPath: lib/org.bluecove_2.1.1.jar,
  .
 Export-Package: org.symbian.tools.tmw.ui,
- org.symbian.tools.tmw.ui.deployment
+ org.symbian.tools.tmw.ui.deployment,
+ org.symbian.tools.tmw.ui.project
 Import-Package: org.apache.velocity;version="1.5.0",
  org.apache.velocity.app;version="1.5.0",
  org.apache.velocity.context;version="1.5.0"
--- a/org.symbian.tools.mtw.ui/plugin.xml	Fri Aug 13 17:26:00 2010 -0700
+++ b/org.symbian.tools.mtw.ui/plugin.xml	Mon Aug 16 16:23:25 2010 -0700
@@ -4,6 +4,7 @@
    <extension-point id="deploymentTargetType" name="Provides targets for project deployments" schema="schema/deploymentTargetType.exsd"/>
    <extension-point id="targetPresentation" name="Deployment Target Presentation" schema="schema/targetPresentation.exsd"/>
    <extension-point id="projectTemplate" name="Mobile Application Project Templates" schema="schema/projectTemplate.exsd"/>
+   <extension-point id="wizardPages" name="Extensions for the New Application Wizard" schema="schema/wizardPages.exsd"/>
 	<!-- Navigator Extensions -->
 	<extension point="org.eclipse.ui.navigator.viewer">
 	  <viewerActionBinding
--- a/org.symbian.tools.mtw.ui/schema/projectTemplate.exsd	Fri Aug 13 17:26:00 2010 -0700
+++ b/org.symbian.tools.mtw.ui/schema/projectTemplate.exsd	Mon Aug 16 16:23:25 2010 -0700
@@ -63,6 +63,13 @@
             <element ref="supported-runtime"/>
             <element ref="default-parameter-value"/>
          </choice>
+         <attribute name="id" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
          <attribute name="name" type="string" use="required">
             <annotation>
                <documentation>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.symbian.tools.mtw.ui/schema/wizardPages.exsd	Mon Aug 16 16:23:25 2010 -0700
@@ -0,0 +1,117 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.symbian.tools.tmw.ui" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+      <appinfo>
+         <meta.schema plugin="org.symbian.tools.tmw.ui" id="wizardPages" name="Extensions for the New Application Wizard"/>
+      </appinfo>
+      <documentation>
+         [Enter description of this extension point.]
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <annotation>
+         <appinfo>
+            <meta.element />
+         </appinfo>
+      </annotation>
+      <complexType>
+         <choice minOccurs="1" maxOccurs="unbounded">
+            <element ref="template-page"/>
+         </choice>
+         <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="template-page">
+      <annotation>
+         <documentation>
+            This page will be shown when user creates project based on the selected template.
+         </documentation>
+      </annotation>
+      <complexType>
+         <attribute name="template-id" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="identifier" basedOn="org.symbian.tools.tmw.ui.projectTemplate/template/@id"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+         <attribute name="class" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="java" basedOn=":org.symbian.tools.tmw.ui.project.INewApplicationWizardPage"/>
+               </appinfo>
+            </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/org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/internal/ui/project/ProjectTemplateImpl.java	Fri Aug 13 17:26:00 2010 -0700
+++ b/org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/internal/ui/project/ProjectTemplateImpl.java	Mon Aug 16 16:23:25 2010 -0700
@@ -158,4 +158,7 @@
         return parameters;
     }
 
+    public String getId() {
+        return element.getAttribute("id");
+    }
 }
--- a/org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/internal/ui/wizard/FacetsSelectionPage.java	Fri Aug 13 17:26:00 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-package org.symbian.tools.tmw.internal.ui.wizard;
-
-import java.util.Set;
-
-import org.eclipse.jface.wizard.WizardPage;
-import org.eclipse.swt.events.DisposeEvent;
-import org.eclipse.swt.events.DisposeListener;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.help.IWorkbenchHelpSystem;
-import org.eclipse.wst.common.project.facet.core.IFacetedProjectWorkingCopy;
-import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion;
-import org.eclipse.wst.common.project.facet.core.events.IFacetedProjectEvent;
-import org.eclipse.wst.common.project.facet.core.events.IFacetedProjectListener;
-import org.eclipse.wst.common.project.facet.core.runtime.RuntimeManager;
-import org.eclipse.wst.common.project.facet.core.runtime.events.IRuntimeLifecycleEvent;
-import org.eclipse.wst.common.project.facet.core.runtime.events.IRuntimeLifecycleListener;
-import org.eclipse.wst.common.project.facet.ui.FacetUiHelpContextIds;
-import org.eclipse.wst.common.project.facet.ui.internal.FacetedProjectFrameworkImages;
-
-/**
- * @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a>
- */
-
-@SuppressWarnings("restriction")
-public final class FacetsSelectionPage extends WizardPage {
-    public FacetsSelectionPanel panel;
-    private final IFacetedProjectWorkingCopy fpjwc;
-
-    public FacetsSelectionPage(final Set<IProjectFacetVersion> base, final IFacetedProjectWorkingCopy fpjwc) {
-        super("facets.selection.page"); //$NON-NLS-1$
-
-        setTitle("Project Facets");
-        setDescription("Select the facets that should be enabled for this project.");
-        setImageDescriptor(FacetedProjectFrameworkImages.BANNER_IMAGE.getImageDescriptor());
-
-        this.fpjwc = fpjwc;
-    }
-
-    public void createControl(final Composite parent) {
-        this.panel = new FacetsSelectionPanel(parent, this.fpjwc);
-
-        updatePageState();
-
-        this.fpjwc.addListener(new IFacetedProjectListener() {
-            public void handleEvent(final IFacetedProjectEvent event) {
-                updatePageState();
-            }
-        }, IFacetedProjectEvent.Type.PROJECT_MODIFIED);
-
-        final IRuntimeLifecycleListener runtimeLifecycleListener = new IRuntimeLifecycleListener() {
-            public void handleEvent(final IRuntimeLifecycleEvent event) {
-                updatePageState();
-            }
-        };
-
-        RuntimeManager.addListener(runtimeLifecycleListener, IRuntimeLifecycleEvent.Type.VALIDATION_STATUS_CHANGED);
-
-        this.panel.addDisposeListener(new DisposeListener() {
-            public void widgetDisposed(final DisposeEvent e) {
-                RuntimeManager.removeListener(runtimeLifecycleListener);
-            }
-        });
-
-        final IWorkbenchHelpSystem h = PlatformUI.getWorkbench().getHelpSystem();
-        h.setHelp(this.panel, FacetUiHelpContextIds.FACETS_SELECTION_PAGE);
-
-        setControl(this.panel);
-    }
-
-    private void updatePageState() {
-        if (!Thread.currentThread().equals(this.panel.getDisplay().getThread())) {
-            final Runnable uiRunnable = new Runnable() {
-                public void run() {
-                    updatePageState();
-                }
-            };
-
-            this.panel.getDisplay().asyncExec(uiRunnable);
-            return;
-        }
-
-        setPageComplete(this.panel.isSelectionValid());
-
-        if (getContainer().getCurrentPage() != null) {
-            getContainer().updateButtons();
-        }
-    }
-
-    public void setVisible(final boolean visible) {
-        super.setVisible(visible);
-
-        if (visible) {
-            this.panel.setFocus();
-        }
-    }
-}
--- a/org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/internal/ui/wizard/FacetsSelectionPanel.java	Fri Aug 13 17:26:00 2010 -0700
+++ b/org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/internal/ui/wizard/FacetsSelectionPanel.java	Mon Aug 16 16:23:25 2010 -0700
@@ -49,6 +49,8 @@
 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.Composite;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Display;
@@ -57,6 +59,7 @@
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Table;
 import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.swt.widgets.Text;
 import org.eclipse.ui.ISharedImages;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.wst.common.project.facet.core.IFacetedProjectWorkingCopy;
@@ -70,14 +73,13 @@
 import org.eclipse.wst.common.project.facet.core.runtime.events.IRuntimeLifecycleListener;
 import org.eclipse.wst.common.project.facet.ui.IDecorationsProvider;
 import org.eclipse.wst.common.project.facet.ui.internal.FacetUiPlugin;
-import org.eclipse.wst.common.project.facet.ui.internal.util.BasicToolTip;
-import org.eclipse.wst.common.project.facet.ui.internal.util.HeaderToolTip;
 import org.symbian.tools.tmw.core.TMWCore;
 
 /**
  * @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a>
  */
 
+@SuppressWarnings("restriction")
 public final class FacetsSelectionPanel extends Composite implements ISelectionProvider {
     private final Composite topComposite;
     private final SashForm sform1;
@@ -91,14 +93,10 @@
     private final Map<IProjectFacet, IProjectFacetVersion> selectedVersions;
     private final List<ISelectionChangedListener> selectionListeners;
     private Object selection;
-
-    /**
-     * Holds images used throughout the panel.
-     */
-
     private final ImageRegistry imageRegistry;
-
     private final IRuntimeLifecycleListener runtimeLifecycleListener;
+    private final Text description;
+    private final Composite facets;
 
     public interface IFilter {
         boolean check(IProjectFacetVersion fv);
@@ -119,22 +117,29 @@
         this.imageRegistry = new ImageRegistry();
         // Layout the panel.
 
-        setLayout(glmargins(gl(1), 0, 0));
+        setLayout(glmargins(new GridLayout(1, false), 0, 0));
 
         this.topComposite = new Composite(this, SWT.NONE);
-        this.topComposite.setLayout(glmargins(gl(4), 0, 0));
+        this.topComposite.setLayout(glmargins(new GridLayout(4, false), 0, 0));
 
         this.sform1 = new SashForm(this.topComposite, SWT.VERTICAL | SWT.SMOOTH);
         this.sform1.setLayoutData(gdhspan(gdfill(), 4));
 
-        this.table = new Table(this.sform1, SWT.BORDER | SWT.CHECK);
+        facets = new Composite(sform1, SWT.NONE);
+        facets.setLayout(new GridLayout(2, false));
+        this.table = new Table(facets, SWT.BORDER | SWT.CHECK);
+        GridData gd = new GridData(GridData.FILL_VERTICAL);
+        gd.widthHint = 250;
+        table.setLayoutData(gd);
+        description = new Text(facets, SWT.MULTI | SWT.READ_ONLY | SWT.WRAP | SWT.BORDER);
+        gd = new GridData(GridData.FILL_BOTH);
+        description.setLayoutData(gd);
         this.tableViewer = new CheckboxTableViewer(this.table);
 
         this.tableViewer.setLabelProvider(new FacetColumnLabelProvider());
         this.tableViewer.setContentProvider(new ContentProvider());
         this.tableViewer.setSorter(new Sorter());
 
-        new FacetToolTip(this.table);
         this.fixedFacetToolTip = new FixedFacetToolTip(this.table);
 
         this.tableViewer.setInput(new Object());
@@ -211,7 +216,7 @@
         final int prefWidthTree = getPreferredWidth(this.table);
         final int prefWidth = prefWidthTree + 80;
 
-        this.topComposite.setLayoutData(gdwhint(gdhhint(gdfill(), 500), prefWidth));
+        this.topComposite.setLayoutData(gdwhint(gdhhint(gdfill(), 200), prefWidth));
 
         this.sform1.setWeights(new int[] { 70, 30 });
 
@@ -363,6 +368,7 @@
 
         if (selection != null && selection instanceof IProjectFacet) {
             selection = getSelectedVersion((IProjectFacet) selection);
+            description.setText(((IProjectFacetVersion) selection).getProjectFacet().getDescription());
         }
 
         if (selection != this.selection) {
@@ -489,7 +495,7 @@
 
         if (getFilteredProblems().length == 0) {
             if (this.sform1.getMaximizedControl() == null) {
-                this.sform1.setMaximizedControl(this.tableViewer.getControl());
+                this.sform1.setMaximizedControl(facets);
             }
         } else {
             if (this.sform1.getMaximizedControl() != null) {
@@ -515,20 +521,6 @@
         }
     }
 
-    private TableItem getTreeItem(final int x, final int y) {
-        return getTreeItemHelper(x, y, this.table.getItems());
-    }
-
-    private static TableItem getTreeItemHelper(final int x, final int y, final TableItem[] items) {
-        for (TableItem item : items) {
-            if (item.getBounds().contains(x, y)) {
-                return item;
-            }
-        }
-
-        return null;
-    }
-
     private IStatus[] getFilteredProblems() {
         final IStatus[] unfiltered = this.fpjwc.validate().getChildren();
         boolean somethingToRemove = false;
@@ -649,39 +641,13 @@
         }
     }
 
-    private final class FacetToolTip extends HeaderToolTip {
-        public FacetToolTip(final Control control) {
-            super(control);
-        }
+    private final class FixedFacetToolTip extends ToolTip {
+        private static final int FAKE_EVENT_TYPE = -9999;
+
+        private String message = ""; //$NON-NLS-1$
 
         @Override
-        protected final boolean shouldCreateToolTip(final Event event) {
-            if (getShowToolTips() == false) {
-                return false;
-            }
-
-            final TableItem treeItem = getTreeItem(event.x, event.y);
-            String description = null;
-
-            if (treeItem != null && treeItem.getBounds(0).contains(event.x, event.y)) {
-                final Object treeItemData = treeItem.getData();
-
-                if (treeItemData instanceof IProjectFacet) {
-                    description = ((IProjectFacet) treeItemData).getDescription();
-                }
-            }
-
-            return (description != null && description.trim().length() > 0);
-        }
-
-        @Override
-        protected String getToolTipTitle(final Event event) {
-            final IProjectFacet f = (IProjectFacet) getTreeItem(event.x, event.y).getData();
-            return getSelectedVersion(f).toString();
-        }
-
-        @Override
-        protected Composite createContentArea(final Event event, final Composite parent) {
+        protected Composite createToolTipContentArea(final Event event, final Composite parent) {
             final Display display = parent.getDisplay();
 
             final Composite composite = new Composite(parent, SWT.NONE);
@@ -689,22 +655,21 @@
             composite.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
 
             final Label label = new Label(composite, SWT.WRAP);
-            label.setLayoutData(gdfill());
+            label.setLayoutData(gdwhint(gdfill(), 300));
             label.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
-
-            final IProjectFacet f = (IProjectFacet) getTreeItem(event.x, event.y).getData();
-            label.setText(f.getDescription());
+            label.setText(this.message);
 
             return composite;
         }
-    }
 
-    private final class FixedFacetToolTip extends BasicToolTip {
-        private static final int FAKE_EVENT_TYPE = -9999;
+        public void setMessage(final String message) {
+            this.message = message;
+        }
 
         public FixedFacetToolTip(final Control control) {
             super(control);
             setPopupDelay(0);
+            setShift(new Point(10, 3));
         }
 
         public void show(final Point location) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/internal/ui/wizard/NewApplicationFacetsWizardPage.java	Mon Aug 16 16:23:25 2010 -0700
@@ -0,0 +1,97 @@
+package org.symbian.tools.tmw.internal.ui.wizard;
+
+import java.util.Set;
+
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.help.IWorkbenchHelpSystem;
+import org.eclipse.wst.common.project.facet.core.IFacetedProjectWorkingCopy;
+import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion;
+import org.eclipse.wst.common.project.facet.core.events.IFacetedProjectEvent;
+import org.eclipse.wst.common.project.facet.core.events.IFacetedProjectListener;
+import org.eclipse.wst.common.project.facet.core.runtime.RuntimeManager;
+import org.eclipse.wst.common.project.facet.core.runtime.events.IRuntimeLifecycleEvent;
+import org.eclipse.wst.common.project.facet.core.runtime.events.IRuntimeLifecycleListener;
+import org.eclipse.wst.common.project.facet.ui.FacetUiHelpContextIds;
+import org.eclipse.wst.common.project.facet.ui.internal.FacetedProjectFrameworkImages;
+
+/**
+ * @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a>
+ */
+
+@SuppressWarnings("restriction")
+public final class NewApplicationFacetsWizardPage extends WizardPage {
+    public FacetsSelectionPanel panel;
+    private final IFacetedProjectWorkingCopy fpjwc;
+
+    public NewApplicationFacetsWizardPage(final Set<IProjectFacetVersion> base, final IFacetedProjectWorkingCopy fpjwc) {
+        super("facets.selection.page"); //$NON-NLS-1$
+
+        setTitle("Project Facets");
+        setDescription("Select the facets that should be enabled for this project.");
+        setImageDescriptor(FacetedProjectFrameworkImages.BANNER_IMAGE.getImageDescriptor());
+
+        this.fpjwc = fpjwc;
+    }
+
+    public void createControl(final Composite parent) {
+        this.panel = new FacetsSelectionPanel(parent, this.fpjwc);
+
+        updatePageState();
+
+        this.fpjwc.addListener(new IFacetedProjectListener() {
+            public void handleEvent(final IFacetedProjectEvent event) {
+                updatePageState();
+            }
+        }, IFacetedProjectEvent.Type.PROJECT_MODIFIED);
+
+        final IRuntimeLifecycleListener runtimeLifecycleListener = new IRuntimeLifecycleListener() {
+            public void handleEvent(final IRuntimeLifecycleEvent event) {
+                updatePageState();
+            }
+        };
+
+        RuntimeManager.addListener(runtimeLifecycleListener, IRuntimeLifecycleEvent.Type.VALIDATION_STATUS_CHANGED);
+
+        this.panel.addDisposeListener(new DisposeListener() {
+            public void widgetDisposed(final DisposeEvent e) {
+                RuntimeManager.removeListener(runtimeLifecycleListener);
+            }
+        });
+
+        final IWorkbenchHelpSystem h = PlatformUI.getWorkbench().getHelpSystem();
+        h.setHelp(this.panel, FacetUiHelpContextIds.FACETS_SELECTION_PAGE);
+
+        setControl(this.panel);
+    }
+
+    private void updatePageState() {
+        if (!Thread.currentThread().equals(this.panel.getDisplay().getThread())) {
+            final Runnable uiRunnable = new Runnable() {
+                public void run() {
+                    updatePageState();
+                }
+            };
+
+            this.panel.getDisplay().asyncExec(uiRunnable);
+            return;
+        }
+
+        setPageComplete(this.panel.isSelectionValid());
+
+        if (getContainer().getCurrentPage() != null) {
+            getContainer().updateButtons();
+        }
+    }
+
+    public void setVisible(final boolean visible) {
+        super.setVisible(visible);
+
+        if (visible) {
+            this.panel.setFocus();
+        }
+    }
+}
--- a/org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/internal/ui/wizard/NewApplicationWizard.java	Fri Aug 13 17:26:00 2010 -0700
+++ b/org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/internal/ui/wizard/NewApplicationWizard.java	Mon Aug 16 16:23:25 2010 -0700
@@ -34,18 +34,21 @@
 import org.eclipse.wst.common.project.facet.ui.ModifyFacetedProjectWizard;
 import org.symbian.tools.tmw.core.TMWCore;
 import org.symbian.tools.tmw.core.projects.IFProjSupport;
+import org.symbian.tools.tmw.ui.project.INewApplicationWizardPage;
+import org.symbian.tools.tmw.ui.project.IProjectTemplate;
 
 /**
  * @author Eugene Ostroukhov (eugeneo@symbian.org)
  */
 public final class NewApplicationWizard extends ModifyFacetedProjectWizard implements INewWizard {
+    private final PageContributions contributions = new PageContributions();
     private final DataBindingContext databindingContext = new DataBindingContext();
+    private NewApplicationFacetsWizardPage facetsPage;
     private NewApplicationDetailsWizardPage firstPage;
     private IStructuredSelection selection;
+    private NewApplicationTemplateWizardPage templatesPage;
     private final WizardContext wizardContext = new WizardContext();
     private IWorkbench workbench;
-    private FacetsSelectionPage facetsPage;
-    private NewApplicationTemplateWizardPage templatesPage;
 
     public NewApplicationWizard() {
         setShowFacetsSelectionPage(false);
@@ -61,7 +64,7 @@
         } else {
             facets = project.getProjectFacets();
         }
-        facetsPage = new FacetsSelectionPage(facets, getFacetedProjectWorkingCopy());
+        facetsPage = new NewApplicationFacetsWizardPage(facets, getFacetedProjectWorkingCopy());
         addPage(facetsPage);
         templatesPage = new NewApplicationTemplateWizardPage(wizardContext, databindingContext);
         addPage(templatesPage);
@@ -96,13 +99,37 @@
         return nextPage;
     }
 
+    private IProjectTemplate template = null;
+    private INewApplicationWizardPage[] templatePages = new INewApplicationWizardPage[0];
+
     public IWizardPage[] getPages() {
+        final IProjectTemplate current = wizardContext.getTemplate();
+        if (template != current) {
+            for (INewApplicationWizardPage page : templatePages) {
+                page.remove();
+                page.dispose();
+            }
+            if (current == null) {
+                template = null;
+                templatePages = new INewApplicationWizardPage[0];
+            } else {
+                template = current;
+                templatePages = contributions.createPages(template.getId());
+                for (INewApplicationWizardPage page : templatePages) {
+                    page.setWizard(this);
+                    page.init(wizardContext, databindingContext);
+                }
+            }
+        }
         final IWizardPage[] base = super.getPages();
-        final IWizardPage[] pages = new IWizardPage[base.length + 3];
+        final IWizardPage[] pages = new IWizardPage[base.length + 3 + templatePages.length];
 
         pages[0] = this.firstPage;
         pages[1] = this.templatesPage;
         pages[2] = this.facetsPage;
+        if (templatePages.length > 0) {
+            System.arraycopy(templatePages, 0, pages, 3, templatePages.length);
+        }
         System.arraycopy(base, 0, pages, 2, base.length);
 
         return pages;
@@ -122,7 +149,6 @@
      * @return the selection that this wizard was launched from
      * @since 1.4
      */
-
     public IStructuredSelection getSelection() {
         return this.selection;
     }
@@ -133,7 +159,6 @@
      * @return the workbench that this wizard belongs to
      * @since 1.4
      */
-
     public IWorkbench getWorkbench() {
         return this.workbench;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/internal/ui/wizard/PageContributions.java	Mon Aug 16 16:23:25 2010 -0700
@@ -0,0 +1,69 @@
+/**
+ * Copyright (c) 2010 Symbian Foundation 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:
+ * Symbian Foundation - initial contribution.
+ * Contributors:
+ * Description:
+ * Overview:
+ * Details:
+ * Platforms/Drives/Compatibility:
+ * Assumptions/Requirement/Pre-requisites:
+ * Failures and causes:
+ */
+package org.symbian.tools.tmw.internal.ui.wizard;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+import org.symbian.tools.tmw.ui.TMWCoreUI;
+import org.symbian.tools.tmw.ui.project.INewApplicationWizardPage;
+
+public class PageContributions {
+    private Map<String, List<IConfigurationElement>> templatePages;
+
+    public INewApplicationWizardPage[] createPages(final String id) {
+        if (templatePages == null) {
+            walkExtensions();
+        }
+        final List<IConfigurationElement> pages = templatePages.get(id);
+        if (pages == null || pages.size() == 0) {
+            return new INewApplicationWizardPage[0];
+        }
+        final INewApplicationWizardPage[] newPages = new INewApplicationWizardPage[pages.size()];
+        for (int i = 0; i < pages.size(); i++) {
+            IConfigurationElement element = pages.get(i);
+            try {
+                newPages[i] = (INewApplicationWizardPage) element.createExecutableExtension("class");
+            } catch (CoreException e) {
+                TMWCoreUI.log(e);
+            }
+        }
+        return newPages;
+    }
+
+    private void walkExtensions() {
+        final IConfigurationElement[] elements = Platform.getExtensionRegistry().getConfigurationElementsFor(
+                TMWCoreUI.PLUGIN_ID, "wizardPages");
+        templatePages = new TreeMap<String, List<IConfigurationElement>>();
+        for (IConfigurationElement element : elements) {
+            final String id = element.getAttribute("template-id");
+            List<IConfigurationElement> extensions = templatePages.get(id);
+            if (extensions == null) {
+                extensions = new LinkedList<IConfigurationElement>();
+                templatePages.put(id, extensions);
+            }
+            extensions.add(element);
+        }
+    }
+}
--- a/org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/internal/ui/wizard/WizardContext.java	Fri Aug 13 17:26:00 2010 -0700
+++ b/org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/internal/ui/wizard/WizardContext.java	Mon Aug 16 16:23:25 2010 -0700
@@ -13,7 +13,9 @@
 import org.eclipse.core.databinding.beans.BeansObservables;
 import org.eclipse.core.databinding.observable.Observables;
 import org.eclipse.core.databinding.observable.map.IObservableMap;
+import org.eclipse.core.databinding.observable.value.AbstractObservableValue;
 import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.observable.value.ValueDiff;
 import org.eclipse.core.databinding.validation.IValidator;
 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IFile;
@@ -39,31 +41,23 @@
 import org.symbian.tools.tmw.ui.project.IProjectTemplateContext;
 
 public class WizardContext implements IProjectTemplateContext {
-    //    public static final String CSS_FILE = "cssFile";
-    //    public static final String HTML_FILE = "htmlFile";
-    //    public static final String JS_FILE = "jsFile";
+    public static final String PROJECT_NAME = "projectName";
+    public static final String RUNTIME = "runtime";
     public static final String TEMPLATE = "template";
+    public static final String TEMPLATES = "templates";
     public static final String WIDGET_ID = "widgetId";
     public static final String WIDGET_NAME = "widgetName";
-    //    public static final String HOME_SCREEN = "homeScreen";
-    public static final String RUNTIME = "runtime";
-    //    public static final String LIBRARIES = "libraries";
-    public static final String PROJECT_NAME = "projectName";
-    public static final String TEMPLATES = "templates";
 
-    //    private String cssFile;
+    private final Map<String, Object> extensions = new TreeMap<String, Object>();
+    private final Map<String, IObservableValue> observables = new TreeMap<String, IObservableValue>();
     private String projectName = "";
-    //    private String htmlFile;
-    //    private String jsFile;
     private final PropertyChangeSupport propertySupport = new PropertyChangeSupport(this);
+    private IMobileWebRuntime runtime;
     private IProjectTemplate template = null;
+
     private String widgetId;
+
     private String widgetName;
-    private Map<String, String> extensions = new TreeMap<String, String>();
-    //    private boolean homeScreen;
-    private IMobileWebRuntime runtime;
-
-    //    private Set<JSLibrary> libraries = new HashSet<JSLibrary>();
 
     public WizardContext() {
         IMobileWebRuntime[] runtimes = TMWCore.getRuntimesManager().getAllRuntimes();
@@ -72,6 +66,17 @@
         }
     }
 
+    public void addFile(IProject project, IPath name, InputStream contents, IProgressMonitor monitor)
+            throws CoreException {
+        monitor.beginTask(name.toOSString(), 100);
+        final IFile file = project.getFile(name);
+        if (!file.exists()) {
+            create(file.getParent());
+        }
+        file.create(contents, false, new SubProgressMonitor(monitor, 100));
+        monitor.done();
+    }
+
     public void addPropertyChangeListener(PropertyChangeListener arg0) {
         propertySupport.addPropertyChangeListener(arg0);
     }
@@ -80,10 +85,146 @@
         propertySupport.addPropertyChangeListener(arg0, arg1);
     }
 
+    private void create(IContainer parent) throws CoreException {
+        if (!parent.exists() && parent instanceof IFolder) {
+            create(parent.getParent());
+            ((IFolder) parent).create(false, true, new NullProgressMonitor());
+        }
+    }
+
+    protected void createLabel(Composite root, String text) {
+        Label label = new Label(root, SWT.NONE);
+        label.setText(text);
+    }
+
+    private Text createText(Composite root, IObservableValue model, String propertyName,
+            DataBindingContext bindingContext, AbstractDataBindingPage page, IValidator... validators) {
+        Text text = new Text(root, SWT.BORDER);
+        text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+        ISWTObservableValue view = SWTObservables.observeText(text, SWT.Modify);
+        UpdateValueStrategy strategy = new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE);
+        NonEmptyStringValidator validator = new NonEmptyStringValidator(propertyName, page);
+        strategy.setBeforeSetValidator(validators.length == 0 ? validator
+                : new CompoundValidator(validator, validators));
+        bindingContext.bindValue(view, model, strategy, null);
+        return text;
+    }
+
+    protected Text createText(Composite root, String property, String propertyName, DataBindingContext bindingContext,
+            AbstractDataBindingPage page, IValidator... validators) {
+        return createText(root, BeansObservables.observeValue(this, property), propertyName, bindingContext, page,
+                validators);
+    }
+
+    protected Text createTextForExt(Composite root, String property, String propertyName,
+            DataBindingContext bindingContext, AbstractDataBindingPage page) {
+        IObservableMap map = BeansObservables.observeMap(this, "extensions");
+        IObservableValue entry = Observables.observeMapEntry(map, property, String.class);
+        return createText(root, entry, propertyName, bindingContext, page);
+    }
+
+    private IProjectTemplate getDefaultTemplate(IMobileWebRuntime runtime) {
+        return TMWCoreUI.getProjectTemplateManager().getDefaultTemplate(runtime);
+    }
+
+    private String getDefaultWidgetId() {
+        String name = Util.removeSpaces(getWidgetName());
+        return MessageFormat.format("com.company.{0}", name.length() > 0 ? name : "ApplicationName");
+    }
+
+    public Map<String, Object> getExtensions() {
+        return extensions;
+    }
+
+    public Object getParameter(String parameter) {
+        return getTemplateVars().get(parameter);
+    }
+
+    public String[] getParameterNames() {
+        Set<String> keys = getTemplateVars().keySet();
+        return keys.toArray(new String[keys.size()]);
+    }
+
+    public IObservableValue getParameterObservable(String name) {
+        IObservableValue value = observables.get(name);
+        if (value == null) {
+            value = new ObservableParameter(name);
+            observables.put(name, value);
+        }
+        return value;
+    }
+
     public String getProjectName() {
         return projectName;
     }
 
+    public IMobileWebRuntime getRuntime() {
+        return runtime;
+    }
+
+    public IProjectTemplate getTemplate() {
+        if (template == null) {
+            return getDefaultTemplate(getRuntime());
+        }
+        return template;
+    }
+
+    public IProjectTemplate[] getTemplates() {
+        return TMWCoreUI.getProjectTemplateManager().getProjectTemplates(getRuntime());
+    }
+
+    private Map<String, Object> getTemplateVars() {
+        Map<String, Object> vars = new TreeMap<String, Object>();
+
+        if (runtime != null) {
+            vars.putAll(TMWCoreUI.getProjectTemplateManager().getDefaultTemplateParameterValues(runtime));
+        }
+        final IProjectTemplate t = getTemplate();
+        if (t != null) {
+            vars.putAll(t.getDefaultParameterValues());
+        }
+
+        vars.put("widgetName", getWidgetName());
+        vars.put("widgetId", getWidgetId());
+        vars.putAll(extensions);
+
+        return vars;
+    }
+
+    public String getWidgetId() {
+        if (widgetId == null) {
+            return getDefaultWidgetId();
+        }
+        return widgetId;
+    }
+
+    public String getWidgetName() {
+        return widgetName == null ? getProjectName() : widgetName;
+    }
+
+    public void initialize(IProject project, IProgressMonitor monitor) {
+        final IProjectTemplate template = getTemplate();
+        if (template != null) {
+            template.init(project, this, monitor);
+        }
+    }
+
+    public void putParameter(String key, Object value) {
+        if (value != null) {
+            extensions.put(key, value);
+        } else {
+            extensions.remove(key);
+        }
+    }
+
+    public void removePropertyChangeListener(PropertyChangeListener arg0) {
+        propertySupport.removePropertyChangeListener(arg0);
+    }
+
+    public void removePropertyChangeListener(String arg0, PropertyChangeListener arg1) {
+        propertySupport.removePropertyChangeListener(arg0, arg1);
+    }
+
     public void setProjectName(String projectName) {
         String prev = getProjectName();
         String prevId = getWidgetId();
@@ -98,115 +239,27 @@
         }
     }
 
-    //    public String getCssFile() {
-    //        if (cssFile == null) {
-    //            if (template != null) {
-    //                return template.getDefaultCssFile();
-    //            }
-    //        }
-    //        return cssFile;
-    //    }
-    //
-    private String getDefaultWidgetId() {
-        String name = Util.removeSpaces(getWidgetName());
-        return MessageFormat.format("com.company.{0}", name.length() > 0 ? name : "ApplicationName");
-    }
-
-    //
-    //    public String getHtmlFile() {
-    //        if (htmlFile == null) {
-    //            if (template != null) {
-    //                return template.getDefaultHtmlFile();
-    //            }
-    //        }
-    //        return htmlFile;
-    //    }
-    //
-    //    public String getJsFile() {
-    //        if (jsFile == null) {
-    //            if (template != null) {
-    //                return template.getDefaultJsFile();
-    //            }
-    //        }
-    //        return jsFile;
-    //    }
-
-    public IProjectTemplate getTemplate() {
+    public void setRuntime(IMobileWebRuntime runtime) {
+        final IProjectTemplate[] prevTemplates = getTemplates();
+        final IProjectTemplate prevTemplate;
         if (template == null) {
-            return getDefaultTemplate(getRuntime());
+            prevTemplate = getTemplate();
+        } else {
+            prevTemplate = null;
         }
-        return template;
-    }
-
-    private IProjectTemplate getDefaultTemplate(IMobileWebRuntime runtime) {
-        return TMWCoreUI.getProjectTemplateManager().getDefaultTemplate(runtime);
+        final IMobileWebRuntime prev = this.runtime;
+        this.runtime = runtime;
+        propertySupport.firePropertyChange(RUNTIME, prev, runtime);
+        propertySupport.firePropertyChange(TEMPLATES, prevTemplates, getTemplates());
+        if (prevTemplate == null) {
+            propertySupport.firePropertyChange(TEMPLATE, prevTemplate, getTemplate());
+        }
     }
 
-    public String getWidgetId() {
-        if (widgetId == null) {
-            return getDefaultWidgetId();
-        }
-        return widgetId;
-    }
-
-    public String getWidgetName() {
-        return widgetName == null ? getProjectName() : widgetName;
-    }
-
-    public void removePropertyChangeListener(PropertyChangeListener arg0) {
-        propertySupport.removePropertyChangeListener(arg0);
-    }
-
-    public void removePropertyChangeListener(String arg0, PropertyChangeListener arg1) {
-        propertySupport.removePropertyChangeListener(arg0, arg1);
-    }
-
-    //    public void setCssFile(String cssFile) {
-    //        if (template != null && template.getDefaultCssFile().equals(cssFile)) {
-    //            cssFile = null;
-    //        }
-    //        String prev = this.cssFile;
-    //        this.cssFile = cssFile;
-    //        propertySupport.firePropertyChange(CSS_FILE, cssFile, prev);
-    //    }
-    //
-    //    public void setHtmlFile(String htmlFile) {
-    //        if (template != null && template.getDefaultHtmlFile().equals(htmlFile)) {
-    //            htmlFile = null;
-    //        }
-    //        String prev = this.htmlFile;
-    //        this.htmlFile = htmlFile;
-    //        propertySupport.firePropertyChange(HTML_FILE, htmlFile, prev);
-    //    }
-    //
-    //    public void setJsFile(String jsFile) {
-    //        if (template != null && template.getDefaultJsFile().equals(jsFile)) {
-    //            jsFile = null;
-    //        }
-    //        String prev = this.jsFile;
-    //        this.jsFile = jsFile;
-    //        propertySupport.firePropertyChange(JS_FILE, jsFile, prev);
-    //    }
-    //
     public void setTemplate(IProjectTemplate template) {
-        //        String html = getHtmlFile();
-        //        String js = getJsFile();
-        //        String css = getCssFile();
         IProjectTemplate prev = this.template;
         this.template = template;
         propertySupport.firePropertyChange(TEMPLATE, template, prev);
-        //        if (htmlFile == null) {
-        //            propertySupport.firePropertyChange(HTML_FILE, getHtmlFile(), html);
-        //        }
-        //        if (jsFile == null) {
-        //            propertySupport.firePropertyChange(JS_FILE, getJsFile(), js);
-        //        }
-        //        if (cssFile == null) {
-        //            propertySupport.firePropertyChange(CSS_FILE, getCssFile(), css);
-        //        }
-        //        if (cssFile == null) {
-        //            propertySupport.firePropertyChange(LIBRARIES, getLibraries(), libraries);
-        //        }
     }
 
     public void setWidgetId(String widgetId) {
@@ -232,184 +285,38 @@
         }
     }
 
-    public void setExtensions(Map<String, String> extensions) {
-        this.extensions = extensions;
-    }
+    private final class ObservableParameter extends AbstractObservableValue {
+        private final String name;
 
-    public Map<String, String> getExtensions() {
-        return extensions;
-    }
+        public ObservableParameter(String name) {
+            this.name = name;
+        }
 
-    private Map<String, String> getTemplateVars() {
-        Map<String, String> vars = new TreeMap<String, String>();
+        public Object getValueType() {
+            return Object.class;
+        }
 
-        if (runtime != null) {
-            vars.putAll(TMWCoreUI.getProjectTemplateManager().getDefaultTemplateParameterValues(runtime));
-        }
-        final IProjectTemplate t = getTemplate();
-        if (t != null) {
-            vars.putAll(t.getDefaultParameterValues());
+        @Override
+        protected Object doGetValue() {
+            return getParameter(name);
         }
 
-        vars.put("widgetName", getWidgetName());
-        vars.put("widgetId", getWidgetId());
-        //        vars.put("mainHtml", getHtmlFileName());
-        //        vars.put("mainCss", getCssFileName());
-        //        vars.put("mainJs", getJsFileName());
-        //        vars.put("homeScreen", String.valueOf(isHomeScreen()));
-        vars.putAll(extensions);
-
-        return vars;
-    }
-
-    //
-    //    public boolean isHomeScreen() {
-    //        return homeScreen;
-    //    }
-
-    //    public void setHomeScreen(boolean homeScreen) {
-    //        boolean old = homeScreen;
-    //        this.homeScreen = homeScreen;
-    //        propertySupport.firePropertyChange(HOME_SCREEN, old, homeScreen);
-    //    }
-
-    //    public String getHtmlFileName() {
-    //        return stripExtension(getHtmlFile(), "htm", "html");
-    //    }
-    //
-    //    public String getJsFileName() {
-    //        return stripExtension(getJsFile(), "js");
-    //    }
-    //
-    //    public String getCssFileName() {
-    //        return stripExtension(getCssFile(), "css");
-    //    }
-
-    //    private String stripExtension(String fileName, String... extensions) {
-    //        for (String extension : extensions) {
-    //            String extensionAndDot = "." + extension;
-    //            if (fileName.endsWith(extensionAndDot)) {
-    //                return fileName.substring(0, fileName.length() - extensionAndDot.length());
-    //            }
-    //        }
-    //        return fileName;
-    //    }
-
-    //    public boolean isRequiredLibrary(JSLibrary element) {
-    //        return template != null && template.requires(element);
-    //    }
-    //
-    //    public Set<JSLibrary> getLibraries() {
-    //        final Set<JSLibrary> set = new HashSet<JSLibrary>(libraries);
-    //        if (template != null) {
-    //            set.addAll(Arrays.asList(template.getRequiredLibraries()));
-    //        }
-    //        return set;
-    //    }
-
-    //    public void setLibraries(Set<JSLibrary> libraries) {
-    //        Set<JSLibrary> prev = this.libraries;
-    //        this.libraries = libraries;
-    //        propertySupport.firePropertyChange(LIBRARIES, prev, libraries);
-    //    }
-
-    //    public Map<String, String> getLibraryParameters(JSLibrary library) {
-    //        return Collections.emptyMap();
-    //    }
-
-    protected Text createText(Composite root, String property, String propertyName, DataBindingContext bindingContext,
-            AbstractDataBindingPage page, IValidator... validators) {
-        return createText(root, BeansObservables.observeValue(this, property), propertyName, bindingContext, page,
-                validators);
-    }
-
-    protected Text createTextForExt(Composite root, String property, String propertyName,
-            DataBindingContext bindingContext, AbstractDataBindingPage page) {
-        IObservableMap map = BeansObservables.observeMap(this, "extensions");
-        IObservableValue entry = Observables.observeMapEntry(map, property, String.class);
-        return createText(root, entry, propertyName, bindingContext, page);
-    }
+        @Override
+        protected void doSetValue(final Object value) {
+            final Object prev = getParameter(name);
+            putParameter(name, value);
+            fireValueChange(new ValueDiff() {
 
-    private Text createText(Composite root, IObservableValue model, String propertyName,
-            DataBindingContext bindingContext, AbstractDataBindingPage page, IValidator... validators) {
-        Text text = new Text(root, SWT.BORDER);
-        text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
-        ISWTObservableValue view = SWTObservables.observeText(text, SWT.Modify);
-        UpdateValueStrategy strategy = new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE);
-        NonEmptyStringValidator validator = new NonEmptyStringValidator(propertyName, page);
-        strategy.setBeforeSetValidator(validators.length == 0 ? validator
-                : new CompoundValidator(validator, validators));
-        bindingContext.bindValue(view, model, strategy, null);
-        return text;
-    }
-
-    protected void createLabel(Composite root, String text) {
-        Label label = new Label(root, SWT.NONE);
-        label.setText(text);
-    }
-
-    public void setRuntime(IMobileWebRuntime runtime) {
-        final IProjectTemplate[] prevTemplates = getTemplates();
-        final IProjectTemplate prevTemplate;
-        if (template == null) {
-            prevTemplate = getTemplate();
-        } else {
-            prevTemplate = null;
-        }
-        final IMobileWebRuntime prev = this.runtime;
-        this.runtime = runtime;
-        propertySupport.firePropertyChange(RUNTIME, prev, runtime);
-        propertySupport.firePropertyChange(TEMPLATES, prevTemplates, getTemplates());
-        if (prevTemplate == null) {
-            propertySupport.firePropertyChange(TEMPLATE, prevTemplate, getTemplate());
-        }
-    }
-
-    public IMobileWebRuntime getRuntime() {
-        return runtime;
-    }
+                @Override
+                public Object getOldValue() {
+                    return prev;
+                }
 
-    public IProjectTemplate[] getTemplates() {
-        return TMWCoreUI.getProjectTemplateManager().getProjectTemplates(getRuntime());
-    }
-
-    public void initialize(IProject project, IProgressMonitor monitor) {
-        final IProjectTemplate template = getTemplate();
-        if (template != null) {
-            template.init(project, this, monitor);
-        }
-    }
-
-    public Object getParameter(String parameter) {
-        return getTemplateVars().get(parameter);
-    }
-
-    public String[] getParameterNames() {
-        Set<String> keys = getTemplateVars().keySet();
-        return keys.toArray(new String[keys.size()]);
-    }
-
-    public void putParameter(String key, Object value) {
-        if (value instanceof String) {
-            extensions.put(key, (String) value);
-        }
-    }
-
-    public void addFile(IProject project, IPath name, InputStream contents, IProgressMonitor monitor)
-            throws CoreException {
-        monitor.beginTask(name.toOSString(), 100);
-        final IFile file = project.getFile(name);
-        if (!file.exists()) {
-            create(file.getParent());
-        }
-        file.create(contents, false, new SubProgressMonitor(monitor, 100));
-        monitor.done();
-    }
-
-    private void create(IContainer parent) throws CoreException {
-        if (!parent.exists() && parent instanceof IFolder) {
-            create(parent.getParent());
-            ((IFolder) parent).create(false, true, new NullProgressMonitor());
+                @Override
+                public Object getNewValue() {
+                    return value;
+                }
+            });
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/ui/project/INewApplicationWizardPage.java	Mon Aug 16 16:23:25 2010 -0700
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2010 Symbian Foundation 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:
+ * Symbian Foundation - initial contribution.
+ * Contributors:
+ * Description:
+ * Overview:
+ * Details:
+ * Platforms/Drives/Compatibility:
+ * Assumptions/Requirement/Pre-requisites:
+ * Failures and causes:
+ */
+package org.symbian.tools.tmw.ui.project;
+
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.jface.wizard.IWizardPage;
+
+public interface INewApplicationWizardPage extends IWizardPage {
+    void init(IProjectTemplateContext context, DataBindingContext bindingContext);
+
+    void remove();
+}
--- a/org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/ui/project/IProjectTemplate.java	Fri Aug 13 17:26:00 2010 -0700
+++ b/org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/ui/project/IProjectTemplate.java	Mon Aug 16 16:23:25 2010 -0700
@@ -89,4 +89,9 @@
      * Returns default template parameter values
      */
     Map<String, String> getDefaultParameterValues();
+
+    /**
+     * @return template ID
+     */
+    String getId();
 }
--- a/org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/ui/project/IProjectTemplateContext.java	Fri Aug 13 17:26:00 2010 -0700
+++ b/org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/ui/project/IProjectTemplateContext.java	Mon Aug 16 16:23:25 2010 -0700
@@ -20,6 +20,7 @@
 
 import java.io.InputStream;
 
+import org.eclipse.core.databinding.observable.value.IObservableValue;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
@@ -33,10 +34,43 @@
  * @author Eugene Ostroukhov (eugeneo@symbian.org)
  */
 public interface IProjectTemplateContext extends IProjectSetupAction {
+    /**
+     * @return runtime that the project targets
+     */
     IMobileWebRuntime getRuntime();
+
+    /**
+     * @param parameter name of the parameter
+     * @return parameter value. In most cases parameters will be string values 
+     * but template developers can use any types
+     */
     Object getParameter(String parameter);
+
+    /**
+     * @return array of parameter names
+     */
     String[] getParameterNames();
+
     void putParameter(String key, Object value);
-    void addFile(IProject project, IPath name, InputStream contents, IProgressMonitor monitor)
-            throws CoreException;
+
+    /**
+     * Allows the framework to reduce dependance on exact project layout. I.e. 
+     * some IDEs may want to introduce separation of the web resources and 
+     * JavaScript source files.
+     * 
+     * @param project project to add file to
+     * @param name file path relative to application root
+     * @param contents stream with file contents
+     * @param monitor progress monitor
+     * @throws CoreException
+     */
+    void addFile(IProject project, IPath name, InputStream contents, IProgressMonitor monitor) throws CoreException;
+
+    /**
+     * Allows binding to parameter value from UI.
+     * 
+     * @param name parameter value
+     * @return observable that may be used to bind value
+     */
+    IObservableValue getParameterObservable(String name);
 }
--- a/org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/ui/project/IProjectTemplateManager.java	Fri Aug 13 17:26:00 2010 -0700
+++ b/org.symbian.tools.mtw.ui/src/org/symbian/tools/tmw/ui/project/IProjectTemplateManager.java	Mon Aug 16 16:23:25 2010 -0700
@@ -24,7 +24,9 @@
 
 public interface IProjectTemplateManager {
     IProjectTemplate[] getProjectTemplates(IMobileWebRuntime runtime);
+
     IProjectTemplate getDefaultTemplate(IMobileWebRuntime runtime);
+
     ITemplateInstaller getEmptyProjectTemplate(IMobileWebRuntime runtime);
 
     /**
--- a/org.symbian.tools.wrttools/plugin.xml	Fri Aug 13 17:26:00 2010 -0700
+++ b/org.symbian.tools.wrttools/plugin.xml	Mon Aug 16 16:23:25 2010 -0700
@@ -836,6 +836,7 @@
          point="org.symbian.tools.tmw.ui.projectTemplate">
       <template
             icon="icons/flickr.gif"
+            id="org.symbian.wrt11.flickr"
             name="Flickr Project"
             weight="3">
          <archive
@@ -863,6 +864,10 @@
                name="mainHtml"
                value="flickr">
          </default-parameter-value>
+         <default-parameter-value
+               name="flickrUrl"
+               value="http://flickr.com/photos/symbianfoundation">
+         </default-parameter-value>
       </template>
       <runtime-template
             runtime-id="org.symbian.tools.wrttools.wrt"
@@ -888,5 +893,12 @@
          </default-parameter-value>
       </runtime-template>
    </extension>
+   <extension
+         point="org.symbian.tools.tmw.ui.wizardPages">
+      <template-page
+            class="org.symbian.tools.wrttools.wizards.NewFlickrApplicationWizardPage"
+            template-id="org.symbian.wrt11.flickr">
+      </template-page>
+   </extension>
  
 </plugin>
--- a/org.symbian.tools.wrttools/src/org/symbian/tools/wrttools/util/CompoundValidator.java	Fri Aug 13 17:26:00 2010 -0700
+++ b/org.symbian.tools.wrttools/src/org/symbian/tools/wrttools/util/CompoundValidator.java	Mon Aug 16 16:23:25 2010 -0700
@@ -21,7 +21,6 @@
 import org.eclipse.core.databinding.validation.IValidator;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
-import org.symbian.tools.wrttools.wizards.NonEmptyStringValidator;
 
 
 public class CompoundValidator implements IValidator {
@@ -31,7 +30,7 @@
 		this.validators = validators;
 	}
 	
-	public CompoundValidator(NonEmptyStringValidator validator,
+    public CompoundValidator(IValidator validator,
 			IValidator[] validators) {
 		this.validators = new IValidator[validators.length + 1];
 		this.validators[0] = validator;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.symbian.tools.wrttools/src/org/symbian/tools/wrttools/wizards/NewFlickrApplicationWizardPage.java	Mon Aug 16 16:23:25 2010 -0700
@@ -0,0 +1,142 @@
+/**
+ * Copyright (c) 2010 Symbian Foundation 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:
+ * Symbian Foundation - initial contribution.
+ * Contributors:
+ * Description:
+ * Overview:
+ * Details:
+ * Platforms/Drives/Compatibility:
+ * Assumptions/Requirement/Pre-requisites:
+ * Failures and causes:
+ */
+package org.symbian.tools.wrttools.wizards;
+
+import java.text.MessageFormat;
+import java.util.Collection;
+import java.util.LinkedList;
+
+import org.eclipse.core.databinding.Binding;
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.UpdateValueStrategy;
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.validation.IValidator;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.databinding.swt.ISWTObservableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.wizard.WizardPageSupport;
+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.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.symbian.tools.tmw.ui.project.INewApplicationWizardPage;
+import org.symbian.tools.tmw.ui.project.IProjectTemplate;
+import org.symbian.tools.tmw.ui.project.IProjectTemplateContext;
+import org.symbian.tools.wrttools.Activator;
+import org.symbian.tools.wrttools.util.CompoundValidator;
+
+public class NewFlickrApplicationWizardPage extends WizardPage implements INewApplicationWizardPage {
+    private static class NonEmptyStringValidator implements IValidator {
+        private final String propertyName;
+
+        public NonEmptyStringValidator(String propertyName) {
+            this.propertyName = propertyName;
+        }
+
+        public IStatus validate(Object value) {
+            if (value == null || value.toString().trim().length() == 0) {
+                return new Status(IStatus.ERROR, Activator.PLUGIN_ID, MessageFormat.format("Field {0} is empty",
+                        propertyName));
+            }
+            return Status.OK_STATUS;
+        }
+    }
+    private DataBindingContext bindingContext;
+    private final Collection<Binding> bindings = new LinkedList<Binding>();
+    private IProjectTemplateContext context;
+
+    public NewFlickrApplicationWizardPage() {
+        super("FlickrFiles");
+        setTitle("Application Files");
+        setDescription("Specify application file names");
+    }
+
+    protected void addTemplateControls(Composite root) {
+        createLabel(root, "Flickr URL:");
+        createText(root, "flickrUrl", "Flickr URL", bindingContext);
+        createLabel(root, "");
+        createLabel(root, "");
+    }
+
+    public void createControl(Composite parent) {
+        Composite root = new Composite(parent, SWT.NONE);
+        WizardPageSupport.create(this, bindingContext);
+        root.setLayout(new GridLayout(2, false));
+
+        createLabel(root, "Name of main HTML:");
+        createText(root, IProjectTemplate.CommonKeys.main_html, "HTML file name", bindingContext);
+        createLabel(root, "");
+        createLabel(root, "");
+        createLabel(root, "Name of CSS file:");
+        createText(root, IProjectTemplate.CommonKeys.main_css, "CSS file name", bindingContext);
+        createLabel(root, "");
+        createLabel(root, "");
+        createLabel(root, "Name of JavaScript file:");
+        createText(root, IProjectTemplate.CommonKeys.main_js, "JavaScript file name", bindingContext);
+
+        createLabel(root, "");
+        Button homeScreen = new Button(root, SWT.CHECK);
+        homeScreen.setText("Enable HomeScreen");
+
+        createLabel(root, "");
+        createLabel(root, "");
+
+        IObservableValue view = SWTObservables.observeSelection(homeScreen);
+        IObservableValue model = context.getParameterObservable(WizardContext.HOME_SCREEN);
+        bindingContext.bindValue(view, model);
+
+        addTemplateControls(root);
+
+        setControl(root);
+    }
+
+    protected void createLabel(Composite root, String text) {
+        Label label = new Label(root, SWT.NONE);
+        label.setText(text);
+    }
+
+    protected Text createText(Composite root, String property, String propertyName, DataBindingContext bindingContext,
+            IValidator... validators) {
+        Text text = new Text(root, SWT.BORDER);
+        text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+        ISWTObservableValue view = SWTObservables.observeText(text, SWT.Modify);
+        UpdateValueStrategy strategy = new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE);
+        NonEmptyStringValidator validator = new NonEmptyStringValidator(propertyName);
+        strategy.setBeforeSetValidator(validators.length == 0 ? validator
+                : new CompoundValidator(validator, validators));
+        bindings.add(bindingContext.bindValue(view, context.getParameterObservable(property), strategy, null));
+        return text;
+    }
+
+    public void init(IProjectTemplateContext context, DataBindingContext bindingContext) {
+        this.context = context;
+        this.bindingContext = bindingContext;
+    }
+
+    public void remove() {
+        for (Binding binding : bindings) {
+            bindingContext.removeBinding(binding);
+        }
+    }
+}