Universal Welcome

Background

This document represents a description of a new welcome implementation that will be used by Eclipse products that want to promote contributions into the Welcome pages. The implementation will be provided by Eclipse platform and available for use and configuration.

The Problem

The Welcome framework in Eclipse provides for defining welcome pages with unique contribution points or 'anchors'. Other components can provide extensions that add content into these anchors. Although this mechanism worked well for closed solutions, it is increasingly hard to maintain for large products. Due to the 'bottom-up' nature of contributions from clients into the welcome pages, it is hard to control the final result and resolve conflicting contributions.

Take a provider of a reusable Eclipse feature as an example. He/she has created a useful feature consisting of a number of plug-ins. The feature can take part in several products, each one having its own Welcome implementation. There are several problems that the feature provider will face when creating Welcome contribution:

It is clearly obvious that the Welcome contribution of a reusable feature would be much easier to develop with the following conditions in place:

The Solution

Based on the conclusions made in the previous section, the User Assistance team now provides a recommended Welcome implementation that will be used by all products that want to support better Welcome control. Eclipse Platform and SDK products will switch to this implementation and others will be encouraged to follow suit.

The universal Welcome solution is based on our experience with Welcome implementations and the need to have an implementation in place that contributors can count on. The implementation is built using the current Welcome framework which has been minimally enhanced to better support it. For this reason, all existing Welcome implementation will continue to work and clients will be able to switch to the new model according to their schedules. Of course, as long as they don't switch, they will not reap the benefits of the new implementation such as intelligent content merging, new visual solution etc.

Design Principles

While designing the universal welcome implementation, we started from the following principles:

  1. Products should be able to point at this implementation without the need to implement Welcome from scratch
  2. Each product should be able to configure Welcome to a certain degree (title, branding image, presentation theme)
  3. A number of root pages that cover most of the products' needs will be provided. However, the list of pages to show will be configurable.
  4. Visual design of the universal Welcome should be sufficiently product-agnostic to better suit the increasingly componentized world. It should work well with both monolithic products and 'best of bread' Eclipse products composed of components created by different companies.
  5. End-users should also be able to configure universal Welcome in a user-friendly way.

Hooking to the universal Welcome

In order to hook to the universal Welcome, developers should have a product-based Eclipse application. This requires the use of the org.eclipse.runtime.products extension point (the assumption is that the product has already been defined):

<extension
	id="foo"
	point="org.eclipse.core.runtime.products">
   <product
      application="org.eclipse.ui.ide.workbench"
      description="Product Foo to use for testing the universal intro"
      name="Product Foo">
   </product>
</extension>

For this example, assume that the extension is define in plugin.xml file sitting in the bundle with the bundle id of com.example.intro. A long-existing feature of the Eclipse intro support is the ability to hook products and intros using the product-intro binding:

<extension
	point="org.eclipse.ui.intro">
   <introProductBinding
      introId="org.eclipse.ui.intro.universal"
      productId="com.example.intro.foo"/>
</extension>

The extension above binds the universal intro implementation (org.eclipse.ui.intro.universal) and our product id.

Universal intro customization is split between product branding properties and preferences. Product branding properties are set by the product and cannot be modified. They include product title, branding image and branding image text:

      <product
            application="org.eclipse.ui.ide.workbench"
            description="Product Foo to use for testing the universal intro"
            name="Product Foo">
         <property
               name="introTitle"
               value="Welcome to Product Bar"/>
         <property
               name="introBrandingImage"
               value="product:eclipse.png"/>
         <property
       	       name="introBrandingImageText"
               value="XYZ Company"/>
      </product>

Product properties whose values represent a file name relative to the product bundle must be qualified with the 'product:' prefix. The following properties are supported:

Second half of universal intro variables are accessible as preferences. The split is due to the fact that these variables can be configured by users and are exposed in the new Welcome preference page. The initial values for these preferences should be placed in the 'plugin_customization.ini' file that is referenced from the product extension. These preferences are:

Adding Welcome Customization preference page

The combination of product properties and default preference values can fully configure the Universal Welcome if no further customization is desired. For products that want to allow users to customize Welcome, a preference page is available. The following code should be added to the product's plugin.xml:

   <extension
         point="org.eclipse.ui.preferencePages">
      <page
            category="org.eclipse.ui.preferencePages.Workbench"
            class="org.eclipse.ui.intro.universal.ExtensionFactory:welcomeCustomization"
            id="com.example.intro.introCustomization"
            name="%introCustomizationPreference.name">
         <keywordReference id="org.eclipse.ui.ide.appearance"/>
      </page>
   </extension>

This code will add the Welcome customization preference page:

The page allows users to select the presentation theme. The original choice is provided by the theme preference in the plugin_customization.ini file. In addition, users can choose from the list of available root pages. Checking the root page causes the related tab to appear at the top of the dialog.

When saved, this preference page will prefix the variables with the product id so that it does not interfere with the settings made for other products in the same workbench. Alternatively, selecting the checkbox above will not prefix the variables, making the stored settings visible to all the products.

Extending the Universal Welcome

When launching the universal Welcome configured as shown above, you will notice that all of the second level page that branch off the root page have an empty content area. This is because shared Welcome does not have content of its own. These areas are populated using intro config extensions.

The traditional way of contributing config extensions is to specify a full path of the anchor element in the target page. This method is still supported but it has proven to be somewhat fragile. As mentioned before, specifying an exact place where the extension will end up in the target is premature for extension authors. They may not know all the products in which their extension will end up, and therefore don't know where they should appear according to each product's focus. In the universal Welcome, this decision is left to product authors. Extension authors now have the option of specifying an incomplete target path, allowing the product author to fill in the blanks.

Config extensions that want to use late target path resolution need to fulfill three conditions:

  1. Config extension needs to specify a unique identifier using the 'id' attribute. Extensions without the id will be ignored. This is important because id will be used to refer to the extension by the product author.
  2. Config extension needs to specify a user-friendly name using the 'name' attribute. This is important if the customization preference page will be used because extensions will show up in the UI.
  3. The target path should have the following form: "page_id/@" where 'page_id' is the identifier of the target page. When '/@' is detected in the target path, an attempt will be made to dynamically resolve the path into the expected full form.

The ability to resolve extension target paths is a new intro support feature in Eclipse 3.2 added to make universal Welcome more powerful. The feature itself is generic in that it can be used in other Welcome implementations, not just the universal one. In Eclipse 3.2, CustomizableIntroPart can accept an optional intro customizer class that can affect its behavior in several ways. One of the roles of the customizer is to perform late target path resolution. Of course, as far as product authors are concerned, this is all just implementation detail because in universal Welcome implementation, late target path resolution is performed using the data file mentioned earlier. This file is stored using the org.eclipse.ui.intro/INTRO_DATA preference.

The 'INTRO_DATA' file uses XML format and allows product authors to control the content of the main Welcome pages. Welcome contribution authors are required to specify only the page Id in their target paths. The rest is defined in this file. The file contains a sequence of 'page' elements, each containing a number of 'group' elements. Group elements specify page-relative path and have contributions for children. Contribution elements are used to specify two aspects: 

<extensions>
   <page id="overview">
      <group path="page-content/top-left">
          <extension id="foo1" importance="high"/>
          <extension id="bar"  importance="high"/>
	  <extension id="foo2" importance="medium"/>
      </group>
      <group path="page-content/top-right">
           <extension id="foo3" importance="low"/>
           <extension id="foo4" importance="low"/>
           <extension id="foo5" importance="callout"/>
      </group>
      <hidden>
            <extension id="foo6"/>
            <extension id="foo7"/>
      </hidden>
   </page>
   <page id="whatsnew">
       ...
   </page>
</extensions>

In the example above, contributions 'foo1', 'bar' and foo2' will be in the left, and 'foo3', 'foo4' and 'foo5' in the right column on the page. The relative order of contributions is also extracted from this file. In addition, contributions are classified based on the importance attribute that can have four valid values: high, medium, low and callout, with low as the default. Each value has matching presentation that makes it stand out on the page. First three are simply different levels of importance according to the product author (note that the same contribution may receive a different importance classification in two separate products). The last one (callout) is used to single out contributions that are of a completely different nature (for example, a contribution that offers links to videos or animation).

Contributions that are not listed are appended after the listed contributions and assigned a low importance value. This is important for contributions added after the product has shipped - they still need to show up.

Contributions not relevant to the project can be hidden by explicitly listing them as children of the 'hidden' element.

Contributing into extensions

An extension contributed into one of the root pages can itself contain anchors, providing for others to add content. This causes a problem because the final resolved path of the content in the extension is not known in advance. For this reason, target paths for content in extensions that use late path resolution must itself be resolved:

<?xml version="1.0" encoding="utf-8" ?>
<introContent>
   <extensionContent id="extra" name="Extra" alt-style="css/swt.properties" style="css/overview.css" path="overview/@">
      <group id="extra-group" style-id="content-group">
         <link label="Extra Overview link" url="http://org.eclipse.ui.intro/showPage?id=extraOverview" 
					  id="extra-overview">
      	    <text>Showing the third-level extra page for overview</text>
         </link>
         <anchor id="additions"/>
      </group>
   </extensionContent>
</introContent>

In order to contribute into the anchor 'additions' in the extension above, we should use the following path: "overview/@extra/extra-group/additions". The segment '@extra' will be replaced with the resolved path of the extension with the id 'extra' in the 'overview' page. For example, if the extension is placed in the upper left segment of the page, the resolved path will be: "overview/page-content/upper-left/extra-group/additions".

Seeding the introData file

In addition to providing intro customization to the end users for the first time, Welcome preference page will allow product authors to create the introData.xml file to be used for the first startup. The procedure is simple:

  1. Launch the product for the first time
  2. Open the Welcome preference page (a quick way to do this is from the local tool bar of the Welcome view where a new tool bar button opens the Preferences into the right page)
  3. For each page, manipulate the available extensions by moving them between the four page quadrants (upper-left, upper-right, lower-left, lower-right) and the Available list, or moving extensions up or down within the same list (relative order). Use drag and drop to get the desired results.
  4. If needed, add the separator between the extension within the quadrant.
  5. All extensions have the default importance setting of 'Low'. To change it, click on the extension image to get the drop-down list to open and pick a different setting from the list (e.g. High, Medium or Callout).
  6. Press OK to see the preferences applied to Welcome.
  7. If satisfied, open the preference page again and press 'Save As...' button.
  8. Store the file as 'introData.xml' in the product plug-in.
  9. Set org.eclipse.ui.intro.universal/INTRO_DATA preference to the value 'product:introData.xml'.
  10. Start the product on a fresh workspace to test if the data from the file has been picked up.

List 'Available Extensions' holds all the extensions that are currently hidden. They can be moved to one of the four quadrants of each page.

Handling multiple products

The intent of the shared Welcome implementation is that all products that want intelligent content merging should point at it instead of creating their own Welcome. This implies that it is possible to end up in a situation where multiple products all pointing at the same shared Welcome coexist in the Eclipse workbench. Intro is handling this situation as follows:

[Note: the above currently does not work - only active product intro data is consulted]

Following links from the main Welcome pages

Most of the extensions coming into the main Welcome pages offer links to open further pages contributed by the extensions themselves. It is recommended to create these pages in such a way as to continue with the shared Welcome visual design. The main requirement is to show the appropriate navigator at the top of the page.

It is fairly easy to do that using the 'include' element. The idea is to include the navigation content at the beginning of contributed page. Unlike the current Welcome implementation, shared Welcome main pages have navigation section that is different for each page. For this reason, pages that branch off these pages should include the navigation from the parent page. For example:

<?xml version="1.0" encoding="utf-8" ?>
<introContent>
   <extensionContent id="extra" name="Extra" alt-style="css/swt.properties" style="css/overview.css" path="overview/@">
      <link label="Extra Overview link" url="http://org.eclipse.ui.intro/showPage?id=extraOverview" 
					  id="extra-overview">
      		<text>Showing the third-level extra page for overview</text>
      </link>
   </extensionContent>
   <page id="extraOverview" style="$theme$/html/overview.css" style-id="page">
      <title style-id="intro-header">$introTitle$</title>
      <group id="extra-group1" filteredFrom="swt"/>
      <include path="overview/navigation-links"/>
      <group id="page-content">
            <group id="content-header" label="EXTRA OVERVIEW" filteredFrom="swt">
            </group>
            <text style-id="page-title" id="page-title" filteredFrom="html">EXTRA OVERVIEW</text>
            <text style-id="page-description" id="page-description">Extra overview page description.</text>
	    <!-- Add content here -->
      </group>
   </page>
</introContent>

The extension above contributed into the overview page contributes a link that shows another page whose definition is part of the extension. Note how we define the title element using substitution variable (the variable will be resolved based on the product property). We also include the group 'navigation-links' that belongs to the 'overview' page at the beginning of the page content definition. We also add the 'extra-group1' div because it is can be used by some themes for adding additional page decoration (indeed, it is used in 'Purple Mesh' theme for that exact purpose).

Enhancements of the Welcome framework in 3.2

In order to make universal welcome possible, we made a number of enhancements in the Welcome framework. These enhancements are of general nature and are are applicable to other Welcome implementations:

Welcome Themes

New in 3.2 is support for Welcome themes. Themes can be plugged is using the new element that is part of org.eclipse.ui.intro.configExtension extension point. Plug-in org.eclipse.ui.intro.universal plugs in two themes:

   <extension
         point="org.eclipse.ui.intro.configExtension">
      <theme
            default="true"
            id="org.eclipse.ui.intro.universal.circles"
            name="%theme.name.circles"
            path="$nl$/themes/circles"
            previewImage="themes/circles/preview.png">
            <property name="launchbarBackground"
            		value="#a1c2cb"/>
            <property name="launchbarOverviewIcon"
            		  value="$theme$graphics/launchbar/overview16.png"/>
            <property name="launchbarFirststepsIcon"
            		  value="$theme$graphics/launchbar/firststeps16.png"/>
            <property name="launchbarTutorialsIcon"
            		  value="$theme$graphics/launchbar/tutorials16.png"/>
            <property name="launchbarSamplesIcon"
            		  value="$theme$graphics/launchbar/samples16.png"/>
            <property name="launchbarWhatsnewIcon"
            		  value="$theme$graphics/launchbar/whatsnew16.png"/>
            <property name="launchbarMigrateIcon"
            		  value="$theme$graphics/launchbar/migrate16.png"/>
            <property name="launchbarWebresourcesIcon"
            		  value="$theme$graphics/launchbar/webresources16.png"/>
      </theme>
      <theme
            id="org.eclipse.ui.intro.universal.purpleMesh"
            name="%theme.name.purpleMesh"
            path="$nl$/themes/purpleMesh"
            previewImage="themes/purpleMesh/preview.png">
            <property name="launchbarBackground"
            		value="#c6c3e8"/>
            <property name="launchbarOverviewIcon"
            		  value="$theme$graphics/launchbar/overview.gif"/>
            <property name="launchbarFirststepsIcon"
            		  value="$theme$graphics/launchbar/firststeps16.png"/>
            <property name="launchbarTutorialsIcon"
            		  value="$theme$graphics/launchbar/tutorials.gif"/>
            <property name="launchbarSamplesIcon"
            		  value="$theme$graphics/launchbar/samples.gif"/>
            <property name="launchbarWhatsnewIcon"
            		  value="$theme$graphics/launchbar/whatsnew.gif"/>
            <property name="launchbarMigrateIcon"
            		  value="$theme$graphics/launchbar/migrate16.png"/>
            <property name="launchbarWebresourcesIcon"
            		  value="$theme$graphics/launchbar/webresources16.png"/>
      </theme>
   </extension>

Each theme has a unique identifier, translatable name, preview image and a path to the root theme folder. Intro plug-in does not provide any UI for theme manipulation. The only way to select a theme is via the preference org.eclipse.ui.intro/INTRO_THEME in plugin_customization.ini.

Theme support by itself does not make intro implementations theme-enabled. It is simply a way of grouping all the presentation files (styles and images) in one place that can be pointed at or switched as one. Concrete intro implementations can choose to expose themes in a more substantial way (and in fact Universal Welcome implementation does exactly that).

Theme-enabled intro implementation must make all the references to style and presentation resources using the $theme$ substitution variable. Absolute paths for images, pages, styles etc. will be computed by resolving the substitution variable using the path of the currently active theme.