Jump to: navigation, search

Corona HowTo: Add a new page to Project Container View

Eclipse Home Wiki Home Development

This approach is depreciated in Corona M9 / Europa M6. It needs to be updated!!

The Project Container View (PCV) can be easily extended to contain new pages. Even the default pages are added by extension mechanism.

First thing to note is that there are two kinds of pages:

  • per project container
    Displays information that are not connected with any repository, but rather with project container itself. This pages are displayed for every project container, no matter what it contains.
  • per repository
    Shows information defined in a repository. This kind of page is displayed only if the page matches a repository, defined in the project container.

The later sections shows step-by-step how to add your own PCV page.

Define extension

First, you need to provide an extension to Corona PCV page extension point. This step is required no matter if you provide a per project container or per repository page. To achieve it, do following:

  1. Open plugin.xml editor.
  2. Switch to Dependencies tab.
  3. Add org.eclipse.corona.container.project.ui to required plug-ins.
  4. Switch to Extensions tab.
  5. Click the Add button and select org.eclipse.corona.container.project.ui.page and click Finish

Save changes to the plugin.xml. This point will be taken as a start point for both; add per project container page and add per repository page.

Common interfaces for pages

Both types of pages are in fact extended Eclipse views. They implement a specialized interfaces which are in fact extension of three basic Eclipse interfaces:

The class must also provide a default public constructor. For both classes there are abstract default implementations that provide default implementations to most methods.

Per project container page

You have plugin.xml editor opened on Extensions tab. Now, we need to create the page. So do fallowing:

  1. Right-click org.eclipse.corona.container.project.ui.page in All Extensions list.
  2. Select New -> projectPage from the pop-up menu.
  3. On the right side in Extension Element Details fill the page information:
    • 'id' - the unique identifier of the page within the Eclipse installation. It should be prefixed with plugin name, to ensure uniqueness.
    • 'name' - the name of the page, which will be displayed in the page tab; used for UI only.
    • 'class' - the full qualified name of class that implement the page; the class must implement org.eclipse.corona.container.project.ui.view.page.IProjectContainerPage interface.
  4. Save changes in plugin.xml.
  5. Implement the page view class.

The page class org.eclipse.corona.container.project.ui.view.page.IProjectContainerPage interface, which contains interfaces described in previous section plus provides a new init method that is used to provide the project container which is the subject of the page.

For your convenience we provided also an abstract class which provides default implementations of methods - org.eclipse.corona.container.project.ui.view.page.AbstractProjectContainerPage. Unless you have your inheritance structure, you should probably use it instead of implementing IProjectContainerPage from scratch.

Example

Lets create a simple page that simply shows a a name of project container as it content. First, you need to define the extension as described earlier. It should look as at the image below.

Corona howto namepage1.png

The corresponding plugin.xml fragment should look like this:

  <extension
        point="org.eclipse.corona.container.project.ui.page">
     <projectPage
           class="org.eclipse.corona.examples.pcv.page.ProjectNamePage"
           id="org.eclipse.corona.examples.pcv.page.projectNamePage"
           name="Project Name"/>
  </extension>

Now it is time to implement the view class. Let's use the abstract class instead of the interface, it will make the example much simpler. Note that the project context container is already set as a field and is ready to use. The default abstract class implementation saves the project context in a field.

package org.eclipse.corona.examples.pcv.page;

import org.eclipse.corona.container.project.ui.view.page.AbstractProjectContainerPage;
import org.eclipse.corona.container.project.ui.view.page.IProjectContainerPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;

public class ProjectNamePage extends AbstractProjectContainerPage 
                             implements IProjectContainerPage {

	public void createPartControl(Composite parent) {
		new Label(parent, SWT.NONE).setText("Name: " + this.container.getName());
	}
}

Now simply run Eclipse with your plugin added and the result should be similar to the picture below.

Corona howto namepage2.png

Simple, isn't it? :)

Per repository page

The per repository pages are a bit more complicated. The problem is in matching the repository page with the repository descriptor. To do the matching, two parameters from the repository definition are taken:

  • content-type. This property defines the content type of the repository. To ensure uniqueness, the value is URI.
  • access-type. This property defines either the format of the repository or the way of accessing it. For instance, it may say that it represents CVS, or some XML format data. Again the form is URI to ensure uniqueness.

So, for instance if you have a repository, which contains a workbench project and it is kept in CVS, then content-type will be workbench project, while access-type CVS. Another example; a project home page will have content-type something like home page, while access-type would be web page. Bugzilla through WWW - bugzilla and web page respectively. I hope it clarifies a bit.

NOTE: The provided access and content types are not valid values. Those are just human-readable form of URIs, just to give you an idea.

Now, to open a page for a repository, we need to somehow match declared pages with repositories they can handle. The taken approach is that you defined either content-type or access-type or even both. Whichever you provide there must fully match with your filter. Lets have some examples to clarify it:

  • If you have a page that knows how to display HTML pages, you would register your page for any repository that has access-type set to web page. No matter if it contains a project web page, or Bugzilla bugs - your view always know how to display it. So you register it with filter only on access-type set to web page.
  • If you have a special page for Bugzilla, which is able to parse its pages and display some additional information. In this case you would register a page with definition of both access-type = web page and content-type = bugzilla.
  • If you want to display some information regardless of how they are stored, then you simply add content-type value. An example of such approach is in team member page, which is focused on displaying members rather than taking care of how to access it. Usually this approach requires usage of repository adapters which allows you to access repository in format agnostic way.

Note, that if you would deploy above examples, then for Bugzilla you would have two repository pages available. The fist one, would be simply web browser, while the second one, would be the special Bugzilla page, with output parsing ability. For now we keep this approach, we don't know if we should move to something like best match.

Adding the page

The procedure of adding a new page is very similar to the per project container repository page:

  1. Right-click org.eclipse.corona.container.project.ui.page in All Extensions list.
  2. Select New -> repositoryPage from the pop-up menu.
  3. On the right side in Extension Element Details fill the page information:
    • 'id' - the unique identifier of the page within the Eclipse installation. It should be prefixed with our plugin name to ensure uniqueness.
    • 'name' - the name of the page, which will be displayed in the page tab; used for UI only.
    • 'class' - the full qualified name of class that implement the page; the class must implement org.eclipse.corona.container.project.ui.view.page.IRepositoryPage interface.
    • 'contentType' and/or 'accessType' to define filter for which repositories the page will be used.
  4. Save changes in plugin.xml.
  5. Implement the page view class.

As previously, the org.eclipse.corona.container.project.ui.view.page.IRepositoryPage is a simply set of three interfaces as described earlier, with one additional init method. This method provides information about project container and repository for which the page was created.

As you could find out from the introduction to the "per repository pages", there are two possible ways of creating repository pages:

  • descriptor based - when your page displays information based only on repository descriptor
  • adapter based - when your page requires a repository adapter which will read repository content for you.

For both situations there are predefined abstract classes to handle basic scenarios - org.eclipse.corona.container.project.ui.view.page.AbstractRepositoryPage and org.eclipse.corona.container.project.ui.view.page.AbstractRepositoryAdapterPage respectively.

Note, that in fact those situations do not differ that much. The only difference is in implementation. You can obtain it even without using the above abstract classes. It is enough if your repository page implements org.eclipse.corona.container.project.ui.view.page.IRepositoryPage

Example 1 - repository based page

Let's create a simple repository page for team member repository. As a first step we will display some information from the repository descriptor. To do it we need to declare the extension to the PCV. The content type value should be set to http://www.eclipse.org/corona/contentTypes/teamContent, which represents team member repository.
It should look as at the picture below.

Corona howto pcvpage repo1.png

The corresponding plugin.xml fragment should look like this:

<extension point="org.eclipse.corona.container.project.ui.page">
   <repositoryPage
         class="org.eclipse.corona.examples.pcv.page.TeamRepositoryPage"
         contentType="http://www.eclipse.org/corona/contentTypes/teamContent"
         id="org.eclipse.corona.examples.pcv.page.teamRepository"
         name="Team Repository"/>
</extension>

Now it is time to implement the page. You can again use the org.eclipse.corona.container.project.ui.view.page.IRepositoryPage interface, or use abstract class, to minimize implementation effort. In this example, we chose the path with abstract class. The code below is a sample implementation of page that prints connection parameters for a repository.

package org.eclipse.corona.examples.pcv.page;

import org.eclipse.corona.container.project.ui.view.page.AbstractRepositoryPage;
import org.eclipse.corona.model.container.RepositoryConfiguration;
import org.eclipse.corona.model.container.RepositoryConnectionParameter;
import org.eclipse.corona.model.container.RepositoryConnectionParameters;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;

public class TeamRepositoryPage extends AbstractRepositoryPage {

    public void createPartControl(Composite parent) {
        parent.setLayout(new RowLayout(SWT.VERTICAL));

        // project name - the same as in project page example
        new Label(parent, SWT.NONE).setText("Name: " + this.container.getName());

        // just a nice label
        new Label(parent, SWT.NONE).setText( "Connection parameters:" );
        // print connection parameters
        RepositoryConfiguration rc = repository.getDefaultRepositoryConfiguration();
        for ( Object paramsObj : rc.getRepositoryConnectionParameters() ) {
            RepositoryConnectionParameters params = (RepositoryConnectionParameters) paramsObj;
            for ( Object paramObj : params.getRepositoryConnectionParameter() ) {
                RepositoryConnectionParameter param = (RepositoryConnectionParameter) paramObj;
                new Label(parent, SWT.NONE)
                    .setText("\t" + param.getName() + "=" + param.getValue());
            }
        }
    }
}

As you can see in the code above, the abstract class for repository contains also the same set of fields, as abstract class for project. Of course it adds a new field, which holds repository descriptor.

The result of above example should look like the image below:

Corona howto pcvpage repo2.png

Example 2 - adapter based pages

The example with adapter based page will extend example 1. So, we will simply add a section which lists all team members.

IMPORTANT: Before you start it, you must add dependency to org.eclipse.corona.repository plugin. This plugin provides interface for repository adapter.

Now, we will just change the previous example. First of all the class now extends org.eclipse.corona.container.project.ui.view.page.AbstractRepositoryAdapterPage. This abstract class is in fact only an extension of org.eclipse.corona.container.project.ui.view.page.AbstractRepositoryPage used for description based pages, so the previous code is now still valid. We just need to add the listing of the items in the repository.

The new page code is below. The changed sections, are marked in bold.

package org.eclipse.corona.examples.pcv.page;

import org.eclipse.corona.container.project.ui.view.page.AbstractRepositoryAdapterPage;
import org.eclipse.corona.model.container.RepositoryConfiguration;
import org.eclipse.corona.model.container.RepositoryConnectionParameter;
import org.eclipse.corona.model.container.RepositoryConnectionParameters;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;

public class TeamRepositoryPage extends AbstractRepositoryAdapterPage {

    public void createPartControl(Composite parent) {
        parent.setLayout(new RowLayout(SWT.VERTICAL));

        // project name - the same as in project page example
        new Label(parent, SWT.NONE).setText("Name: " + this.container.getName());

        // just a nice label
        new Label(parent, SWT.NONE).setText( "Connection parameters:" );
        // print connection parameters
        RepositoryConfiguration rc = repository.getDefaultRepositoryConfiguration();
        for ( Object paramsObj : rc.getRepositoryConnectionParameters() ) {
            RepositoryConnectionParameters params = (RepositoryConnectionParameters) paramsObj;
            for ( Object paramObj : params.getRepositoryConnectionParameter() ) {
                RepositoryConnectionParameter param = (RepositoryConnectionParameter) paramObj;
                new Label(parent, SWT.NONE)
                    .setText("\t" + param.getName() + "=" + param.getValue());
            }
        }

        // print team members storred in the repository
        new Label(parent, SWT.NONE).setText( "Team members:" );
        if ( repositoryAdapter != null) {
            try {
                repositoryAdapter.open();
                for ( Object memberId : repositoryAdapter.listResourceIds() ) {
                    new Label(parent, SWT.NONE)
                        .setText("\t" + repositoryAdapter.fetchResource(memberId));
                }
                repositoryAdapter.close();
            } catch (Exception e) {
                new Label(parent, SWT.NONE).setText("\tError while loading users");
            }
        } else {
            new Label(parent, SWT.NONE).setText("\tNo adapter for team repository");
        }
    }
}

The result of the code above should be similar to the picture below:

Corona howto pcvpage repo3.png

See also