| <!doctype html public "-//w3c//dtd html 4.0 transitional//en"> | |
| <html> | |
| <head> | |
| <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> | |
| <meta name="Author" content="Build"> | |
| <meta name="GENERATOR" content="Mozilla/4.5 [en] (WinNT; I) [Netscape]"> | |
| <title>Using Perspectives in the Eclipse UI</title> | |
| <link rel="stylesheet" href="../default_style.css"> | |
| </head> | |
| <body> | |
| <div align=right> <font face="Times New Roman, Times, serif"><font size=-1>Copyright | |
| © 2001 Object Technology International, Inc.</font></font></div> | |
| <table BORDER=0 CELLSPACING=0 CELLPADDING=2 WIDTH="100%" > | |
| <caption><TBODY> | |
| <br></TBODY></caption> | |
| <tr> | |
| <td ALIGN=LEFT VALIGN=TOP COLSPAN="2" BGCOLOR="#0080C0"><b><font face="Arial,Helvetica"><font color="#FFFFFF"> Eclipse | |
| Corner Article</font></font></b></td> | |
| </tr> | |
| </table> | |
| <h1> | |
| <img SRC="Idea.jpg" height=86 width=120 align=CENTER></h1> | |
| <center> | |
| <h1> | |
| Using Perspectives in the Eclipse UI</h1></center> | |
| <h3> | |
| Summary</h3> | |
| In the Eclipse Platform a Perspective determines the visible actions and | |
| views within a window. Perspectives also go well beyond this by providing | |
| mechanisms for task oriented interaction with resources in the Eclipse | |
| Platform, multi-tasking and information filtering. In this article | |
| the concepts behind perspectives are examined. The process for perspective | |
| definition, extension and instantiation will also be covered in detail | |
| with coding examples and sample scenarios. | |
| <p><b>By Dave Springgay, OTI</b> | |
| <br>August 27, 2001 | |
| <h3> | |
| <hr WIDTH="100%"></h3> | |
| <h3> | |
| Introduction</h3> | |
| In the Eclipse Platform there are two main layers: the model layer and | |
| the user interface layer. The underlying model, known as the Workspace, | |
| is a collection of resources (projects, folders and files). The user | |
| interface, or Workbench, defines the presentation for those resources. | |
| Within the workbench the Perspective feature is used to control the visibility | |
| of items in the model and the user interface. It controls what you | |
| see in the model (which project, folder or files) and what you see in the | |
| user interface (which actions or views). These controls make it possible | |
| to navigate through and modify the workspace in a way which suits the user | |
| task. | |
| <p>In this article the perspective concept will be explored in detail. | |
| In particular, we'll look at how it relates to task oriented interaction, | |
| multi-tasking and information filtering. We'll also look at the techniques | |
| to define a new perspective, extend an existing perspective, or instantiate | |
| a new perspective at runtime within the workbench. Coding samples | |
| are provided for each technique. | |
| <h3> | |
| What is a Perspective?</h3> | |
| A perspective is a visual container for a set of views and editors (parts). | |
| These parts exist wholly within the perspective and are not shared. | |
| A perspective is also like a page within a book. It exists within | |
| a window along with any number of other perspectives and, like a page within | |
| a book, only one perspective is visible at any time. | |
| <p>Each perspective has an <i>input</i> and a <i>type</i>. The <i>input</i> | |
| attribute is used to define which resources are visible in the workspace | |
| and the | |
| <i>type</i> attribute is used to define which actions and views | |
| are visible in the user interface. This design is a reflection of | |
| 3 key concepts. | |
| <br> | |
| <ol> | |
| <li> | |
| Information Filtering</li> | |
| <li> | |
| Task Oriented Interaction with Your Information</li> | |
| <li> | |
| Two is Always Better than One</li> | |
| </ol> | |
| <p><br>Each of these will be covered in detail below. But before | |
| getting into the details, let's explore the idea of input and type. | |
| <p>On startup the workbench will most likely consist of one window with | |
| one perspective. For instance, the window may contain a Resource | |
| perspective on the entire workspace. This perspective has<i> input | |
| = the Workspace</i> and <i>type = Resource</i>. If you select a project | |
| or folder in the Navigator you can open a new perspective by invoking Open | |
| Perspective > Java™ from the object context menu. This new perspective | |
| has a different input and type: <i>input = the Project</i> and <i>type | |
| = Java</i>. Now there are two perspectives. The visible resources | |
| in the second perspective are a subset of those in the first. Each | |
| perspective contains a set of views and editors which exist wholly within | |
| the perspective and are not shared with the other. These parts define | |
| the presentation for a shared, underlying model. | |
| <h4> | |
| Information Filtering</h4> | |
| In a large, real world project the Eclipse Workspace may contain hundreds | |
| or thousands of resources. For instance, consider the following project | |
| in Eclipse. It may be small, but this project represents a typical | |
| three tier B2C web application. There are three folders: ClientSide, | |
| MiddleTier and DatabaseServer. Each folder represents a different | |
| tier in the application. The files types in each folder are also | |
| different. | |
| <pre>WebApplicationProject | |
| ClientSide | |
| index.html | |
| link1.html | |
| image1.html | |
| ... | |
| MiddleTier | |
| script1.jsp | |
| script2.cgi | |
| script3.perl | |
| Main.java | |
| DataBase.java | |
| ... | |
| DatabaseServer | |
| sqlScripts.script | |
| serverConguration.config | |
| ...</pre> | |
| The contents of this project are very typical of application development | |
| in the Internet age. No single language or technology can do it all, | |
| and software development involves the application of many technologies | |
| rather than just one. | |
| <p>An important tool for comprehension is information filtering. | |
| In other words, remove the irrelevant so you can see the relevant. | |
| In Eclipse this is performed in two ways, by using the inherent structure | |
| of the information (the resource tree) and the unstructured attributes | |
| of the information (file name, nature, resource type, etc.). For | |
| this discussion only the first style of information filtering is relevant. | |
| <p>In a large project the resources are usually structured within a hierarchy. | |
| The workspace contains many projects containing many folders containing | |
| many files. It's a tree, and each subtree within the whole defines | |
| a physical subset of information. This idea is the basis for information | |
| filtering within the workbench. The user can open a perspective on | |
| any resource subtree within the workspace. In the resulting perspective | |
| only the children of the subtree root are visible. The subtree root | |
| is known as the <i>input</i>. For example, if you open a perspective | |
| on MiddleTier within the WebApplicationProject only the children of MiddleTier | |
| are visible within the resulting perspective. The <i>input = MiddleTier</i>. | |
| <h4> | |
| Task Oriented Interaction with Your Information</h4> | |
| As a development platform Eclipse was designed to fulfill the needs of | |
| a large product development team, from product manager to content developer | |
| to product tester. It is fully extensible and may be configured with | |
| hundreds of action, wizard, view and editor extensions for any number of | |
| languages, tasks, roles, and phases within the development life cycle. | |
| In other words, it may contain a lot of junk you'll never use. To | |
| avoid the visual overload and confusion which would occur if everything | |
| was visible in the UI some mechanism is required to filter the user interface. | |
| <p>In Eclipse a task oriented approach was taken to filtering. Consider | |
| a Java developer. Within a single development cycle a Java developer | |
| may iterate through the following phases: Analysis and Design, Implementation, | |
| Debug, Testing and Documentation. In one phase the developer may | |
| use a UML modeling tool. In another you use a Problem Reporting tool. | |
| The time spent in each phase will vary but rapid transition between phases | |
| may occur several times a day. If we say that each phase is a "task" | |
| then it is possible to say there is rapid transition between tasks. | |
| In addition, the preferred way to look at resources in the workspace will | |
| change with the active task. | |
| <p>In Eclipse task orientation is embodied by perspective type. A | |
| perspective determines the visible actions, views, and view layout within | |
| the window. There are many types of perspective, and each one defines | |
| the layout in a different way. Ideally, the layout should be tailored | |
| to suit a particular set of related tasks. For instance, the standard | |
| Eclipse platform includes a Java perspective and a Team perspective. | |
| The Java perspective defines a layout containing the Package, Hierarchy, | |
| Outline and Tasks view. This is useful for java development. | |
| The Team perspective defines a layout containing the Repositories and Synchronize | |
| view. This is useful for code sharing and versioning. In Eclipse | |
| the user can open a new perspective with a particular type, switch from | |
| one perspective to another with different type, or change the type (layout) | |
| of an existing perspective as they move from one task to another. | |
| <h4> | |
| Two is Always Better than One</h4> | |
| In an earlier section we saw how information filtering can be used to limit | |
| information overload. When information filtering is implemented a | |
| new need develops: the need to see information which is not visible. | |
| For instance, a Java developer may explore one class hierarchy while they | |
| modify code in another. In Eclipse this functionality is provided | |
| by opening a second perspective on the information required. The | |
| ability to create two separate perspectives (or more) makes it possible | |
| to switch between information without loss of context. | |
| <p>The ability to open more than one perspective is also crucial for multi-tasking | |
| support. Developers often multi-task without even knowing it. | |
| For instance, in a team environment a coworker may walk into your office | |
| to ask a question. In response, you open up a class hierarchy and | |
| explore the code for a few minutes. This is a new task and it should | |
| have no impact upon your previous task. It demands good task separation. | |
| In Eclipse the creation of the second task can be accomplished by just | |
| opening a new perspective. When the task is complete you can close | |
| the perspective and return to the old task without loss of context. | |
| <h3> | |
| Moving from Concept to Implementation</h3> | |
| At a conceptual level a perspective is quite simple. A perspective | |
| is a visual container for a set of views and editors. It has an input | |
| and type. A perspective is also like a page within a book. | |
| It exists within a window along with any number of other perspectives and, | |
| like a page within a book, only one perspective is visible at any time. | |
| <p>At the implementation level things become more complex. The platform | |
| user interface is exposed through a series of interfaces in <tt>org.eclipse.ui</tt>. | |
| The root of the user interface is accessed by invoking <tt>PlatformUI.getWorkbench( | |
| )</tt>. This returns an object of type <tt>IWorkbench</tt>. | |
| A workbench has one or more windows of type <tt>IWorkbenchWindow</tt>. | |
| And each window has a collection of pages of type <tt>IWorkbenchPage</tt>. | |
| In the user interface a page is known as a "perspective". Within | |
| each window there is at most one active and visible page. | |
| <p>The structure of the workbench is exposed within the following diagram. | |
| The workbench window is outlined in red. Within this window there | |
| is a single open perspective. It's purple. But to be truly | |
| accurate, the user calls it a "perspective". At the implementation | |
| level it is an <tt>IWorkbenchPage</tt>. | |
| <center> | |
| <p><img SRC="workbench_decomposed.jpg" height=578 width=480 align=ABSCENTER></center> | |
| <p>While the workbench is running new windows and pages can be created | |
| interactively by invoking Open Perspective from the window menu or from | |
| the Navigator context menu. A page can also be created programmatically | |
| using public API on <tt>IWorkbenchWindow</tt>. For instance, the | |
| following code demonstrates the creation of a new page. | |
| <pre>// fWindow is an IWorkbenchWindow. | |
| fWindow.openPage("org.eclipse.ui.resourcePerspective", ResourcesPlugin.getWorkspace());</pre> | |
| In this example the two parameters to <tt>openPage</tt> identify the perspective | |
| type and input, in that order. The perspective type is identified | |
| by a string. Each perspective has a unique id. In this case | |
| <tt>"org.eclipse.ui.resourcePerspective"</tt> | |
| identifies the Resource perspective. The perspective input may be | |
| any object of type <tt>IAdaptable</tt>. In this case the input is | |
| the entire workspace. | |
| <p>The <tt>openPage</tt> method creates and returns an object of type <tt>IWorkbenchPage</tt>. | |
| Given a page, you can get the input and perspective type by using the following | |
| methods. | |
| <pre>public IAdaptable getInput(); | |
| public IPerspectiveDescriptor getPerspective();</pre> | |
| There is an interesting twist here. When a new page is created you | |
| identify the perspective type by id. In the <tt>openPage</tt> method | |
| the id is mapped to a perspective descriptor within a list of known perspectives | |
| types and the result is stored within the return page. The <tt>getPerspective</tt> | |
| method on <tt>IWorkbenchPage</tt> returns an object of type <tt>IPerspectiveDescriptor</tt>. | |
| This object has accessor methods for the perspective id, label and icon. | |
| <p>The page input determines which resources are visible in the page. | |
| In practice, resource visibility in a page is implemented through collaboration | |
| between the page and the views within that page. The page itself | |
| is a visual container for views and editors. It doesn't provide any | |
| presentation for resources. That is delegated to the parts within the page. | |
| The hand-off usually occurs during part creation. In the early stages | |
| of part life cycle a part can obtain a handle to the containing <tt>IWorkbenchPage</tt> | |
| and from this it may call <tt>getInput</tt>. The result will be used | |
| as the initial input for this view. For instance, if a new perspective | |
| containing the Navigator is opened the Navigator will use the page input | |
| as its own input. The Packages view does the same. In some | |
| cases the view may provide additional actions to dynamically change the | |
| view input. In the Navigator the Go Into, Go Up, Go Back, and Go | |
| Forward actions can be used to navigate around the workspace tree. | |
| <p>The perspective determines which views are visible in a page. | |
| For instance, if you open a new page with the Resource perspective the | |
| Navigator, Outline, and editor area will be visible. If you open | |
| a new page with the Java perspective the Packages, Hierarchy, Tasks, and | |
| editor area will be visible. The visible views are determined by | |
| the perspective type. The type also influences the visible action sets | |
| within a page. For instance, the Java and Debug Action Sets are typically | |
| visible in the Java perspective but not in the Team perspective. | |
| This influence will be discussed in greater detail in <a href="#Adding a New Perspective">Adding | |
| a New Perspective</a>. | |
| <h3> | |
| <a NAME="Adding a New Perspective"></a>Adding a New Perspective</h3> | |
| Within the workbench a new perspective can be defined in two ways. | |
| An ISV can add a new perspective using the perspective extension point | |
| in the plug-in registry. A user can add a new perspective or override | |
| an existing perspective by using the customization and persistence features | |
| built in to the Eclipse user interface. This section will focus on | |
| the ISV scenario. | |
| <p>The definition of a new perspective is a three step process. | |
| <br> | |
| <ol> | |
| <li> | |
| Create a plug-in.</li> | |
| <li> | |
| Add a perspective extension to the plugin.xml file.</li> | |
| <li> | |
| Define a perspective class for the extension within the plug-in.</li> | |
| </ol> | |
| <p><br>This process will be illustrated by defining a plugin with a perspective | |
| called "Test". The Test Perspective will contain the Navigator View, | |
| the Outline View, and an editor area. The layout for the perspective | |
| is illustrated in the quick sketch below. | |
| <center> | |
| <p><img SRC="TestPerspectiveSketch.jpg" height=281 width=374></center> | |
| <p>In the first step a new plug-in is created. The process of plug-in | |
| creation is explained in detail in <a href="http://www.eclipsecorner.org/articles/Your%20First%20Plug-in.html">Your | |
| First Plugin</a>, by Jim Amsden, so I won't go into the details here. | |
| For this article I created a Perspective Plugin with following plugin.xml | |
| file. | |
| <pre><plugin | |
| id="org.eclipse.ui.articles.perspective" | |
| name="Perspective Article Plugin" | |
| version="1.0.0"></pre> | |
| <pre><requires> | |
| <import plugin="org.eclipse.core.runtime"/> | |
| <import plugin="org.eclipse.core.resources"/> | |
| <import plugin="org.eclipse.ui"/> | |
| </requires></pre> | |
| <pre><runtime> | |
| <library name="perspective.jar"/> | |
| </runtime></pre> | |
| <pre></plugin></pre> | |
| The <tt>org.eclipse.ui</tt> plug-in defines a single extension point for | |
| perspective contribution: <tt>org.eclipse.ui.perspectives</tt>. A | |
| new perspective is added to the workbench by defining an extension for | |
| this point. In the example below a perspective extension is defined | |
| for the Test Perspective. This declaration contains the basic elements: | |
| id, name and class. | |
| <pre><extension point="org.eclipse.ui.perspectives"> | |
| <perspective | |
| name="Test" | |
| class="org.eclipse.ui.articles.perspective.TestPerspective" | |
| id="org.eclipse.ui.articles.perspective.Test"> | |
| </perspective> | |
| </extension></pre> | |
| A complete description of the extension point and the syntax are available | |
| in the developer documentation for <tt>org.eclipse.ui</tt>. The attributes | |
| are described as follows. | |
| <br> | |
| <ul> | |
| <li> | |
| <b>id</b> - a unique name that will be used to identify this perspective.</li> | |
| <li> | |
| <b>name</b> - a translatable name that will be used in the workbench window | |
| menu bar to represent this perspective.</li> | |
| <li> | |
| <b>class</b> – a fully qualified name of the class that implements | |
| <tt>org.eclipse.ui.IPerspectiveFactory</tt> | |
| interface.</li> | |
| <li> | |
| <b>icon</b> - a relative name of the icon that will be associated with | |
| this perspective.</li> | |
| </ul> | |
| <p><br>Perhaps the most important attribute in the perspective declaration | |
| is <i>class</i>. This attribute names a class that will define the | |
| initial layout for the perspective. In this example the layout for | |
| the Test perspective is defined by <tt>org.eclipse.ui.articles.perspective.TestPerspective</tt>. | |
| The implementation of <tt>TestPerspective</tt> will be examined in a few | |
| paragraphs. | |
| <p>Once a perspective extension has been declared for the Test Perspective | |
| it will appear in the Perspective > Open menu and in the Open Perspective | |
| menu of the Navigator. If the user invokes either of these actions | |
| a new workbench page will be created. During this process the following | |
| steps are taken. | |
| <br> | |
| <ol> | |
| <li> | |
| A new <tt>IWorkbenchPage</tt> object is created with perspective id = "org.eclipse.ui.articles.perspective.Test".</li> | |
| <li> | |
| The perspective id is used to lookup the actual perspective extension in | |
| the plugin registry. Within the workbench a list of the registered | |
| perspective extensions are stored within the <tt>IPerspectiveRegistry</tt> | |
| (available from the <tt>IWorkbench</tt> interface). The <tt>findPerspectiveWithId</tt> | |
| method is called to get a complete description of the perspective. | |
| This method returns an object of type <tt>IPerspectiveDescriptor</tt>.</li> | |
| <li> | |
| The perspective class is retrieved from the <tt>IPerspectiveDescriptor</tt>. | |
| This class must implement <tt>IPerspectiveFactory</tt>.</li> | |
| <li> | |
| An instance of the perspective class is created, yielding a <tt>IPerspectiveFactory</tt>.</li> | |
| <li> | |
| The <tt>createInitialLayout</tt> method is called on the <tt>IPerspectiveFactory</tt>. | |
| This method defines the initial layout for a page. Implementors may add | |
| views, folders, actions and action sets to the page layout.</li> | |
| <li> | |
| The <tt>IPerspectiveFactory</tt> is dereferenced and is not used again | |
| during the life cycle of the page.</li> | |
| <li> | |
| The <tt>IWorkbenchPage</tt> is activated.</li> | |
| </ol> | |
| <p><br>In the next few paragraphs we'll concentrate on point # 5. | |
| When <tt>createInitialLayout</tt> is called on an <tt>IPerspectiveFactory</tt> | |
| the page layout consists of an editor area with no additional views. | |
| Within <tt>createInitialLayout</tt> you can add views, folders, and view | |
| place holders to the page layout. A <i>folder</i> is a stack of views. | |
| A <i>place holder</i> marks the position of a view within the page. | |
| The view itself is not initially open, but when opened will occupy the | |
| position marked by the place holder. | |
| <p>In the example below you can see how <tt>createInitialLayout</tt> is | |
| implemented in the <tt>TestPerspective</tt> class. For clarity the | |
| algorithm has been split into two parts which define the actions and layout: | |
| <tt>defineActions</tt> | |
| and <tt>defineLayout</tt>. | |
| <pre>public void createInitialLayout(IPageLayout layout) { | |
| defineActions(layout); | |
| defineLayout(layout); | |
| }</pre> | |
| In <tt>defineActions</tt> a number of items and action sets are added to | |
| the window. A perspective may add items to the File > New, Show View, | |
| or Perspective > Open menus of the window. You can also add complete | |
| action sets to the menu or toolbar of the window. In this example | |
| a few File > New and Show View items are added. | |
| <pre>public void defineActions(IPageLayout layout) { | |
| // Add "new wizards". | |
| layout.addNewWizardShortcut("org.eclipse.ui.wizards.new.folder"); | |
| layout.addNewWizardShortcut("org.eclipse.ui.wizards.new.file"); | |
| // Add "show views". | |
| layout.addShowViewShortcut(IPageLayout.ID_RES_NAV); | |
| layout.addShowViewShortcut(IPageLayout.ID_BOOKMARKS); | |
| layout.addShowViewShortcut(IPageLayout.ID_OUTLINE); | |
| layout.addShowViewShortcut(IPageLayout.ID_PROP_SHEET); | |
| layout.addShowViewShortcut(IPageLayout.ID_TASK_LIST); | |
| }</pre> | |
| In <tt>defineLayout</tt> the TestPerspective factory adds two views to | |
| the layout. When <tt>createInitialLayout</tt> is called the page | |
| layout consists of an editor area with no additional views. Additional | |
| views are added using the editor area as the initial point of reference. | |
| In <tt>defineLayout</tt> the factory gets the id of the editor area. | |
| Then it creates a folder to the left of this area and adds the Navigator | |
| view and Outline view to this folder. | |
| <pre>public void defineLayout(IPageLayout layout) { | |
| // Editors are placed for free. | |
| String editorArea = layout.getEditorArea(); | |
| // Place navigator and outline to left of | |
| // editor area. | |
| IFolderLayout left = | |
| layout.createFolder("left", IPageLayout.LEFT, (float) 0.26, editorArea); | |
| left.addView(IPageLayout.ID_RES_NAV); | |
| left.addView(IPageLayout.ID_OUTLINE); | |
| }</pre> | |
| The <tt>createFolder</tt> method adds a new folder to the page layout. | |
| The position and relative size of the folder are expressed as a fraction | |
| of an existing part. In the example above a folder is created with | |
| the name "left". It is positioned to the left of the editor area | |
| and occupies 26% of the original space of the editor area. The positioning | |
| constants are defined on <tt>IPageLayout</tt>, and include <tt>TOP, BOTTOM, | |
| LEFT </tt>and<tt> RIGHT</tt>. | |
| <p>In some situations a perspective within one plug-in may be referenced | |
| by another plug-in. For convenience, the unique id for each perspective | |
| should be declared on a public interface in the source plug-in. The | |
| unique id is usually derived by concatenating the plug-in id with some | |
| plug-in unique perspective id. For instance, the following approach | |
| was used for the Perspective plugin and perspective. | |
| <pre>public interface IPerspectivePlugin { | |
| /** | |
| * Plugin id. | |
| */ | |
| public final static String PLUGIN_ID = "org.eclipse.ui.articles.perspective"; | |
| | |
| /** | |
| * Test perspective id. | |
| */ | |
| public final static String TEST_PERSPECTIVE_ID = PLUGIN_ID + ".Test"; | |
| }</pre> | |
| The Test perspective is now ready to use. To test the new perspective | |
| I installed the Perspective plugin in the Eclipse plugins directory and | |
| then restarted Eclipse. From the Perspective > Open > Other... dialog | |
| I selected the Test perspective. After pressing OK the following | |
| page appeared within my window. | |
| <center> | |
| <p><img SRC="TestPerspective.jpg" height=406 width=559></center> | |
| <h4> | |
| Why is Layout Declaration done in Code Rather than XML?</h4> | |
| During the design of perspectives both options were considered. Within | |
| Eclipse XML is typically used to declare the presence of an extension and | |
| the circumstances under which it should be loaded. The information | |
| is used to load the extension and its plugin lazily for better startup | |
| performance. Now let's apply this logic to perspectives. When | |
| a perspective is selected from the Open Perspective menu the load conditions | |
| are met, so we can load the extension and move forward using Java. | |
| Java code provides the benefits of code completion and error detection | |
| at development time. | |
| <h4> | |
| Can I Remove the Editor Area Completely?</h4> | |
| In some scenarios the ideal layout for a perspective may be made up of | |
| one or more views with no editor area. To achieve this you can invoke | |
| <tt>IPageLayout.setEditorAreaVisible(boolean)</tt> to hide or show the | |
| editor area. This state will be honored unless the user decides to | |
| override it from the Perspective menu. | |
| <p>As a philosophical point, wouldn't it be great if you could punt the | |
| editor area completely? In fact, the workbench user interface favors | |
| the user more than the ISV. While the ISV may wish to define a closed | |
| environment with a fixed set of views, the user always has the ability | |
| to show any view from the Perspective > Show View menu. If the user | |
| can show any view they can also open any resource in an editor, and this | |
| necessitates an editor area. This underscores a very important point. | |
| A perspective definition is just a suggestion. The user can override | |
| it at any time and probably will. For more information on this idea | |
| see <a href="#User Customization and Persistance">User Customization and | |
| Persistence</a>. | |
| <h4> | |
| Do I Need a Perspective?</h4> | |
| The temptation to create a new perspective is strong. The dark side | |
| beckons. As an ISV, if you add a view extension to the platform you'd | |
| like some way to make it visible. One way to do that is to copy an | |
| existing perspective, say the Resource perspective, and add your view to | |
| the factory class. If every ISV took this approach the user would | |
| soon be overwhelmed by perspective choices. In all likelihood the | |
| user would ignore them all and create their own. | |
| <p>In general, a perspective should only be created when there is a certain | |
| group of related tasks which would benefit from a predefined configuration | |
| of actions and views. For instance, the Java Perspective is a good | |
| context for the completion of Java related tasks. It contains a Packages | |
| view and Hierarchy view for class navigation. The Tasks view is good | |
| for problem navigation. And the Outline view is useful for navigation | |
| within an editor. Together, these views are useful for many Java | |
| oriented tasks and the creation of a Java Perspective is justified. | |
| <p>In some situations it may be better to augment an existing perspective. | |
| For instance, if you create a single view which is Java centric it is probably | |
| better to add that view to the standard Java perspective rather than defining | |
| a new perspective. This strategy provides better integration with | |
| the existing platform. For more information on this process check | |
| out <a href="#Extend an Existing Perspective">Extending an Existing Perspective</a>. | |
| <h3> | |
| <a NAME="User Customization and Persistance"></a>User Customization and | |
| Persistence</h3> | |
| In the previous section we examined the techniques an ISV would use to | |
| add a perspective to the workbench. The user can also add a new perspective | |
| to the Eclipse user interface or override an existing perspective. | |
| This section will focus on those aspects of user customization. | |
| <p>When Eclipse is installed the plug-in registry contains a number of | |
| perspective extensions. These extensions are contributed by plug-ins | |
| from various ISV's and form the initial set of perspectives available to | |
| the user. In my own experience the perspectives contributed by an | |
| ISV usually fail to completely meet my needs, so I quickly customize them. | |
| I add views, remove views, add action sets, customize the menus, etc., | |
| until the user interface reflects the way I work. Then I save the | |
| new layout to the original perspective. | |
| <p>The initial layout for a page is determined by the perspective. | |
| To be more precise, it is determined by an <tt>IPerspectiveFactory</tt> | |
| as explained in <a href="#Adding a New Perspective">Adding a New Perspective</a>. | |
| Once a page is open the user may modify the part layout or the visible | |
| action sets within the page. If this page is closed the new layout | |
| is discarded. However, if this page is open when the workbench is | |
| closed the state of the page (and in fact every window, page and part) | |
| is saved to an XML file in the <tt>org.eclipse.ui</tt> plug-in. This | |
| file is used to restore the state of the page when the workbench is restarted | |
| and contains every important attribute of the page: the visible views, | |
| their layout, the visible action sets and other state attributes. | |
| In fact, the <tt>IPerspectiveFactory</tt> which defined the initial layout | |
| for the page is not consulted when the page is restored. | |
| <p>The user can also create a new perspective by invoking Perspective > | |
| Save. In response a dialog appears where the user can type a user | |
| friendly name for the new perspective. Depending on the option chosen | |
| by the user, this action will create a new perspective with the layout | |
| of the current page or override the layout for an existing perspective. | |
| The resulting perspective has all of the privileges of an ISV perspective. | |
| The user can open a page with the custom perspective, use it as the default | |
| perspective, or delete it. The layout of the custom perspective is | |
| saved as an XML file using the same mechanism described above for workbench | |
| session persistence, so there is no <tt>IPerspectiveFactory</tt>. | |
| <h3> | |
| Opening a New Perspective</h3> | |
| In the workbench a new perspective can be created interactively by the | |
| user or programmatically through public API on <tt>IWorkbench, IWorkbenchWindow | |
| or IWorkbenchPage</tt>. For instance, the user may select a container | |
| in the Navigator and invoke Open Perspective > Java. This is an explicit | |
| command from the user to the view to create a new perspective. A | |
| new perspective may also be created as a step within some other action. | |
| For instance, if Project > Open Type is invoked an option exists to open | |
| a new Hierarchy Perspective. In this section the implementation of | |
| both will be discussed. | |
| <p>In the Navigator a user may open a new perspective with specific input | |
| and type by invoking Open Perspective from the context menu. This | |
| ability is an important element of information filtering and should be | |
| included in any view where the resource tree is visible. This will | |
| lead to user interface consistency and ease of use. | |
| <p>The easiest way to add Open Perspective functionality to a view or menu | |
| is with the <tt>OpenPerspectiveMenu</tt>. This class is supplied | |
| in | |
| <tt>org.eclipse.ui.actions</tt> and can be included in any popup menu. | |
| For instance, the following code demonstrates its use within the Navigator. | |
| <pre>/** | |
| * Add "open to" actions to the context sensitive menu. | |
| * @param menu the context sensitive menu | |
| * @param selection the current selection in the project explorer | |
| */ | |
| void fillOpenToMenu(IMenuManager menu, IStructuredSelection selection) | |
| { | |
| // If one file is selected get it. | |
| // Otherwise, do not show the "open with" menu. | |
| if (selection.size() != 1) | |
| return; | |
| IAdaptable element = (IAdaptable) selection.getFirstElement(); | |
| if (!(element instanceof IContainer)) | |
| return; | |
| // Create a menu flyout. | |
| MenuManager submenu = new MenuManager(ResourceNavigatorMessages.getString("ResourceNavigator.openPerspective")); //$NON-NLS-1$ | |
| submenu.add(new OpenPerspectiveMenu(getSite().getWorkbenchWindow(), element)); | |
| menu.add(submenu); | |
| }</pre> | |
| In this example the popup menu for the navigator is populated dynamically | |
| just before the menu is about to show. The <tt>fillOpenToMenu</tt> | |
| method is called from within <tt>menuAboutToShow</tt>. If the selection | |
| is a container (project or folder) the Open Perspective submenu is created | |
| and then populated automatically using the <tt>OpenPerspectiveMenu</tt>. | |
| The contents of this submenu are determined by the customized settings | |
| of the active perspective. For instance, if the Perspective > Open | |
| menu contains "Resource, Java, and Team" your context menu will also contain | |
| "Resource, Java, and Team". | |
| <p>In the workbench the behavior of Open Perspective in flexible. | |
| In fact, the user can configure this behavior in the workbench preferences. | |
| The "Open a New Perspective" behavior may be defined as "Open in Same Window", | |
| "Open in New Window", or "Replace Current". The meaning of | |
| "Open in Same Window" and "Open in New Window" are obvious. The meaning | |
| of "Replace Current" is less so. Each page has a perspective. | |
| If "Replace Current" is invoked the active perspective within the page | |
| is replaced by a new perspective. This causes the view layout and | |
| visible action sets within the page to change, and is equivalent to changing | |
| the layout in MS Studio. | |
| <p>The <tt>OpenPerspectiveMenu </tt>class implements the preferred behavior | |
| for "Open Perspective" and supports the selection of alternate behaviors | |
| when the Control or Shift keys are pressed. After the addition of | |
| an <tt>OpenPerspectiveMenu</tt> object to the context menu no other action | |
| is required to implement the Open Perspective behavior. | |
| <p>A new perspective may also be created as a step within some other action. | |
| For instance, if Project > Open Type is invoked the implementing action | |
| will open a new page with the Hierarchy perspective. In this | |
| scenario a new IWorkbenchPage must be created explicitly using the API's | |
| available on <tt>IWorkbenchWindow</tt>. The following code illustrates | |
| this process. | |
| <pre><tt>// Open the page. | |
| try { | |
| getWindow().openPage(IPerspectivePlugin.TEST_PERSPECTIVE_ID, pageInput); | |
| } catch (WorkbenchException e) { | |
| MessageDialog.openError(getWindow().getShell(), | |
| "Problem Opening Perspective", | |
| e.getMessage()); | |
| }</tt></pre> | |
| In the code above the active workbench window is retrieved and then <tt>openPage</tt> | |
| is invoked with a perspective type and input. As we saw in <a href="#Adding a New Perspective">Adding | |
| a New Perspective</a>, the id of each perspective should be exposed on | |
| a public interface in the source plug-in for convenient access by other | |
| plug-ins in Java code. In this example the Test perspective id is | |
| referenced from the <tt>IPerspectivePlugin</tt> class. The perspective | |
| id is mapped to an <tt>IPerspectiveDescriptor</tt> within the perspective | |
| registry. Then the page is opened. If any problems occur during | |
| the creation of the page an exception will be thrown. | |
| <p>As a philosophical point, should a hard coded constant be used to specify | |
| perspective type? In my own experience it is difficult to predict | |
| the usage pattern for any perspective. For instance, one user may | |
| prefer to develop java code in the Java perspective. Another may | |
| prefer to develop java code in the Resource perspective. If a hard | |
| coded constant is used to specify a perspective type the user may become | |
| frustrated if the wrong perspective is chosen. It may be better to | |
| let the user choose the perspective type or disable this behavior completely. | |
| <p>If you need to open a perspective from within an action there is one | |
| detail to be aware of: the user may change the default behavior for Open | |
| Perspective in the workbench preferences. In most scenarios your | |
| action should honor this preference. | |
| <p>To demonstrate the use of the Open Perspective preference I created | |
| an Action Set containing one action: "Open Test Perspective". When | |
| this action is invoked a new Test Perspective is opened using the preferred | |
| behavior. At the implementation level the action implements | |
| <tt>IWorkbenchWindowActionDelegate</tt>. | |
| Within the <tt>run</tt> method the preference is retrieved from the workbench | |
| plugin and then the perspective is opened. Here is an snippet containing | |
| the relevant details of my action delegate class. | |
| <pre>public void run(IAction action) { | |
| openPerspective(IPerspectivePlugin.TEST_PERSPECTIVE_ID, | |
| ResourcesPlugin.getWorkspace()); | |
| } | |
| /** | |
| * Implements Open Perspective. | |
| */ | |
| private void openPerspective(String perspId, IAdaptable input) { | |
| // Get "Open Behavior" preference. | |
| AbstractUIPlugin plugin = (AbstractUIPlugin)Platform.getPlugin(PlatformUI.PLUGIN_ID); | |
| IPreferenceStore store = plugin.getPreferenceStore(); | |
| String pref = store.getString(IWorkbenchPreferenceConstants.OPEN_NEW_PERSPECTIVE); | |
| | |
| // Implement open behavior. | |
| try { | |
| if (pref.equals(IWorkbenchPreferenceConstants.OPEN_PERSPECTIVE_WINDOW)) | |
| workbench.openWorkbenchWindow(perspId, input); | |
| else if (pref.equals(IWorkbenchPreferenceConstants.OPEN_PERSPECTIVE_PAGE)) | |
| window.openPage(perspId, input); | |
| else if (pref.equals(IWorkbenchPreferenceConstants.OPEN_PERSPECTIVE_REPLACE)) { | |
| IPerspectiveRegistry reg = workbench.getPerspectiveRegistry(); | |
| window.getActivePage().setPerspective(reg.findPerspectiveWithId(perspId)); | |
| } | |
| } catch (WorkbenchException e) { | |
| e.printStackTrace(); | |
| } | |
| }</pre> | |
| <h3> | |
| <a NAME="Extend an Existing Perspective"></a>Extending an Existing Perspective</h3> | |
| In many scenarios the extension of an existing perspective is a good way | |
| to introduce new action sets, wizards, or views into the workbench. | |
| For instance, as an ISV you may create a new Java centric view to the workbench. | |
| Rather than defining a new perspective to show off your view, you can extend | |
| the standard Java perspective. This strategy provides better integration | |
| with the existing platform. In this section the details of perspective | |
| extension will be covered. | |
| <p>The extension of an existing perspective is a three step process. | |
| <br> | |
| <ol> | |
| <li> | |
| Create a plug-in for your extensions.</li> | |
| <li> | |
| Define an action set or view extension in the plugin.xml file.</li> | |
| <li> | |
| Add a perspectiveExtension extension to the plug-in registry.</li> | |
| </ol> | |
| <p><br>This process will be illustrated using the Test Perspective which | |
| was defined in a <a href="#Adding a New Perspective">Adding a New Perspective</a>. | |
| <p>The first step is to create a plug-in with an action set or view extension. | |
| In this example I chose to reuse a few extensions which already exist within | |
| <tt>org.eclipse.jdt.ui</tt> | |
| (the Java plug-in). This plug-in defines a Java Action Set, a New | |
| Java Project Wizard, a Packages View and a Hierarchy View. | |
| <p>The <tt>org.eclipse.ui</tt> plug-in defines an extension point for perspective | |
| extension: <tt>org.eclipse.ui.perspectiveExtensions</tt>. This extension | |
| point can be used to contribute any of the following objects to an existing | |
| extension perspective. | |
| <br> | |
| <ul> | |
| <li> | |
| Action Sets</li> | |
| <li> | |
| File New Items</li> | |
| <li> | |
| Show View Items</li> | |
| <li> | |
| Open Perspective Items</li> | |
| <li> | |
| Views</li> | |
| </ul> | |
| <p><br>In the following example the extension point is used to add the | |
| Java extensions discussed above to the Test perspective. In the first | |
| two lines of XML the target perspective extension is declared: <tt>org.eclipse.ui.articles.perspective.TestPerspective</tt>. | |
| Following this the specific extensions for this perspective are declared. | |
| An action set is added. Then menu items for Show View, File > New, | |
| and Open Perspective are added. And then the Packages view is stacked | |
| on top of the Navigator. | |
| <pre><extension point="org.eclipse.ui.perspectiveExtensions"> | |
| <perspectiveExtension targetID="org.eclipse.ui.articles.perspective.Test"> | |
| <actionSet id="org.eclipse.jdt.ui.JavaActionSet"/> | |
| <viewShortcut id="org.eclipse.jdt.ui.PackageExplorer"/> | |
| <newWizardShortcut | |
| id="org.eclipse.jdt.ui.wizards.NewProjectCreationWizard"/> | |
| <perspectiveShortcut id="org.eclipse.jdt.ui.JavaPerspective"/> | |
| <view id="org.eclipse.jdt.ui.PackageExplorer" | |
| relative="org.eclipse.ui.views.ResourceNavigator" | |
| relationship="stack"/> | |
| </perspectiveExtension> | |
| </extension></pre> | |
| In the next few paragraphs a brief description of each element within the | |
| perspectiveExtensions extension point is provided. A complete description | |
| of the extension point and the syntax are available in the developer documentation | |
| for org.eclipse.ui. | |
| <p>In the example an <tt>actionSet</tt>, <tt>viewShortcut</tt>, <tt>newWizardShortcut</tt> | |
| and <tt>perspectiveShortcut</tt> extension are demonstrated. The | |
| format of these elements is very simple. There is one attribute, | |
| <tt>id</tt>, which identifies an existing extension which should be added | |
| to the perspective. It must identify an action set, view, wizard, | |
| or perspective which has been registered using the standard extension point | |
| for each. | |
| <p>The XML for view extension is a little more complicated. A new | |
| view may be stacked on or placed relative to an existing view. Minimally, | |
| you must define an <tt>id</tt> (of the view being added), <tt>relative</tt> | |
| id, and <tt>relationship</tt> ( <tt>left, right, bottom, top, stack</tt> | |
| ). If the relationship is not <tt>stack</tt> a <tt>ratio</tt> must | |
| also be supplied. This will be interpreted using the same heuristics | |
| as <tt>IPageLayout.addView(id, relationship, ratio, refID)</tt>. | |
| <p>In the current implementation of perspective extension there is one | |
| limitation. Perspective extension is only possible when the user | |
| has not modified the default layout for a perspective. If modification | |
| has occurred perspective extensions will be ignored. However, given the | |
| customizable nature of the workbench the user can always introduce an action | |
| set or view into the perspective by invoking the Perspective > Customize | |
| action or by opening a view from the Perspective > Show View menu. | |
| <h3> | |
| Conclusion</h3> | |
| In this article we have examined the role of perspectives within the workbench | |
| and their implementation. Perspectives are complex and will certainly | |
| evolve over time. Hopefully this article will get you started. | |
| Further information is available in the Platform Plug-in Developer Guide | |
| and in the javadoc for <tt>org.eclipse.ui</tt>. | |
| <p><small>Java and all Java-based trademarks and logos are trademarks or registered | |
| trademarks of Sun Microsystems, Inc. in the United States, other countries, or | |
| both.</small></p> | |
| </body> | |
| </html> |