| <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
| <html> |
| <head> |
| |
| |
| <meta http-equiv="Content-Type" |
| content="text/html; charset=windows-1252"> |
| <title>Inside the Workbench: A guide to the workbench internals</title> |
| |
| <link rel="stylesheet" href="../default_style.css"> |
| </head> |
| <body link="#0000ff" vlink="#800080"> |
| <div align="right"> <font face="Times New Roman, Times, serif" |
| size="2">Copyright © 2005 International Business Machines Corp.</font> |
| <table border="0" cellpadding="2" cellspacing="0" width="100%"> |
| <tbody> |
| <tr> |
| <td colspan="2" align="left" bgcolor="#0080c0" valign="top"><b><font |
| face="Arial,Helvetica"><font color="#ffffff"> Eclipse Corner |
| Article</font></font></b></td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| <div align="left"> |
| <h1><a class="mozTocH1" name="mozTocId282580"></a><img |
| src="../images/Idea.jpg" align="middle" height="86" width="120" alt=""></h1> |
| </div> |
| <p> </p> |
| <h1 align="center"><a class="mozTocH1" name="mozTocId119947"></a>Inside |
| the Workbench<br> |
| A guide to the workbench internals<br> |
| </h1> |
| <blockquote><b>Summary</b> <br> |
| This article describes how the Eclipse 3.1 workbench works, in |
| particular the infrastructure for views and editors. The goal is to |
| teach you about important classes in the workbench, and how they |
| interact. A familiarity with the basic workbench APIs for views, |
| editors, action sets, and so forth is assumed. |
| <p><b>Stefan Xenos, IBM</b> <br> |
| <font size="-1">October 20, 2005</font></p> |
| </blockquote> |
| <br> |
| <hr style="width: 100%; height: 2px;"> |
| <h1><a class="mozTocH1" name="mozTocId744856"></a>Table of Contents</h1> |
| <ul id="mozToc"> |
| <!--mozToc h2 1 h3 2 h4 3 h5 4 h6 5--> |
| <li><a href="#mozTocId917303">1 Introduction </a></li> |
| <li><a href="#mozTocId270357">2 Inside a part </a> |
| <ul> |
| <li><a href="#mozTocId713423">2.1 Part Lifecycle </a></li> |
| <li><a href="#mozTocId789670">2.2 Part Construction</a></li> |
| </ul> |
| </li> |
| <li><a href="#mozTocId409413">3 Workbench Layout </a> |
| <ul> |
| <li><a href="#mozTocId95893">3.1 An example layout</a></li> |
| <li><a href="#mozTocId114962">3.2 Zoom / Unzoom protocol </a></li> |
| <li><a href="#mozTocId977378">3.3 Layout protocol </a></li> |
| <li><a href="#mozTocId162591">3.4 PartStack: Communicating with the |
| Presentation API </a></li> |
| <li><a href="#mozTocId479574">3.5 PartSashContainer: The main |
| workbench layout </a></li> |
| <li><a href="#mozTocId887241">3.6 Drag / Drop</a></li> |
| </ul> |
| </li> |
| <li><a href="#mozTocId443855">4 Action Bars</a> |
| <ul> |
| <li><a href="#mozTocId652269">4.1 Editor Action Bars </a></li> |
| <li><a href="#mozTocId340925">4.2 Action Sets </a></li> |
| <li><a href="#mozTocId277128">4.3 View Actions</a></li> |
| </ul> |
| </li> |
| <li><a href="#mozTocId642161">5 General Conventions</a> |
| <ul> |
| <li><a href="#mozTocId892615">5.1 Objects must not be returned through |
| API until they are fully initialized</a></li> |
| <li><a href="#mozTocId308622">5.2 No method may open a modal dialog |
| unless its JavaDoc says so</a></li> |
| <li><a href="#mozTocId753192">5.3 Lazy creation should happen as late |
| as possible </a></li> |
| <li><a href="#mozTocId921869">5.4 getters should not modify the thing |
| they are supposed to measure </a></li> |
| </ul> |
| </li> |
| </ul> |
| <br> |
| <div style="margin-left: 40px;"><span style="font-weight: bold;"></span></div> |
| <h2><a class="mozTocH2" name="mozTocId917303"></a><span |
| style="font-weight: bold;"></span><span style="font-weight: bold;">1 |
| Introduction</span> <br> |
| </h2> |
| <span style="font-weight: bold;"></span> |
| This document describes workbench internals and not API. The design of |
| internals changes frequently. For information on newer Eclipse versions, |
| the latest version of this document can be found on the |
| <a |
| href="http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-ui-home/dev.html">UI |
| development resources page</a> |
| . |
| <br> |
| <br> |
| <br> |
| <div style="text-align: center;"><span style="font-weight: bold;">Figure |
| 1: Ownership of views and editors<br> |
| <br> |
| </span></div> |
| <div style="text-align: center;"><img alt="" |
| src="images/workbench_high_level.png" |
| style="width: 600px; height: 340px;"><br> |
| </div> |
| <br> |
| Figure 1 shows how views and editors are owned by the workbench. |
| <br> |
| <br> |
| The Workbench contains one or more WorkbenchWindows, each of which |
| contain zero or more WorkbenchPages. The WorkbenchWindow supplies the |
| trim widgets, and the WorkbenchPage supplies the window contents. In |
| theory, a WorkbenchWindow can contain any number of pages, but in |
| practice there is never more than 1 page in a window. |
| <br> |
| <br> |
| Views and editors are owned by the page, through a ViewFactory and |
| EditorManager respectively. EditorManager stores the list of editors and |
| their shared resources, and ViewFactory stores a reference counted list |
| of views. The workbench works in terms of EditorReferences and |
| ViewReferences, and in this article the terms "editor" or "view" will |
| refer to these classes specifically. In situations where the distinction |
| between editors and views is not important, we will simply use the term |
| "part". The implementation of the part (typically an IEditorPart or |
| IViewPart) is created lazily when it is first needed. As shown in Figure |
| 2, a part reference exists for every tab but the implementation is only |
| created the first time it becomes visible. |
| <br> |
| <br> |
| The page owns a set of perspectives. Perspectives contain a layout and |
| information about what action sets to enable. Although perspectives |
| appear to contain views and the editor area, they only own a layout. The |
| page itself maintains a reference count for how many perspectives are |
| using each view, and has complete ownership of the parts and editor |
| area. |
| <br> |
| <br> |
| Not shown in figure 1 are the classes PerspectiveHelper and |
| EditorAreaHelper. These classes exist largely for historic purposes, and |
| in this article we will treat the former as though it were part of the |
| Perspective class and the latter as part of the WorkbenchPage class. |
| <br> |
| <br> |
| <br> |
| <div style="text-align: center;"><span style="font-weight: bold;">Figure |
| 2: Workbench objects and what they look like<br> |
| <br> |
| </span></div> |
| <div style="text-align: center;"><img alt="" |
| src="images/what_you_see.png" style="width: 892px; height: 700px;"><br> |
| </div> |
| <br> |
| <h2><a class="mozTocH2" name="mozTocId270357"></a>2 Inside a part<br> |
| </h2> |
| <div style="text-align: center;"><span style="font-weight: bold;"> |
| Figure 3: Anatomy of a part</span><br> |
| </div> |
| <div style="text-align: center;"><img alt="" |
| src="images/anatomy_of_a_part.png" style="width: 420px; height: 280px;"><br> |
| </div> |
| Internally, a part consists of several objects (Figure 3). |
| WorkbenchPartReference is the topmost representation of the part. |
| Depending on where it is used, the part reference is often exposed as |
| IWorkbenchPartReference, IViewReference, IEditorRefenece, or |
| IPresentablePart, or PartPane. These are essentially different |
| interfaces to the same object. The I*Reference interfaces are |
| implemented directly by WorkbenchPartReference and its subclasses. |
| IPresentablePart is a simple adapter that redirects its methods directly |
| to the part. PartPane implements the LayoutPart protocol which is needed |
| to insert the part into the workbench layout. PartPane also manages the |
| SWT resources (such as a top-level control) that are needed to include |
| the control in the workbench layout. |
| <br> |
| <br> |
| The part implementation (the IEditorPart or IViewPart) is owned by the |
| reference. When the implementation is created, it is given a PartSite. |
| The PartSite (seen by client code as an IWorkbenchPartSite, IEditorSite, |
| or IViewSite) allows the client code to communicate with the reference |
| and manages services created for the implementation. |
| <br> |
| <br> |
| WorkbenchPartReferences allocates SWT resources lazily as needed. Once |
| created, the part reference must be explicitly disposed. Disposing the |
| reference cleans up all of its resources (including the part |
| implementation itself) and guarantees that the reference will never |
| allocate additional resources. The workbench page disposes the part |
| reference once it is certain that it will never need to use that part |
| again. Unlike SWT controls, it is valid to continue using the reference |
| after it has been disposed. A disposed part reference is unlikely to do |
| anything interesting besides returning its name and cannot be used with |
| any methods in the workbench page. Since it is hard (or impossible) for |
| clients to track the lifecycle of the reference, they are permitted to |
| continue using its public interface after disposal. |
| <br> |
| <br> |
| <h3><a class="mozTocH3" name="mozTocId713423"></a>2.1 Part Lifecycle<br> |
| </h3> |
| <div style="text-align: center;"><span style="font-weight: bold;">Figure |
| 4: WorkbenchPartReference states<br> |
| <br> |
| </span></div> |
| <div style="text-align: center;"><img alt="" |
| src="images/part_states.png" style="width: 445px; height: 590px;"><br> |
| </div> |
| Figure 4 shows the part lifecycle as a state machine. The part reference |
| stores its current state in the integer state field. |
| <br> |
| <br> |
| Notes: |
| <br> |
| <ul> |
| <li>The part is in a distinct state while it is in the process of |
| creating the implementation. It cannot be recursively re-created or |
| disposed while it is in this state.</li> |
| <li>The part implementation cannot be recreated once the reference has |
| been disposed.</li> |
| <li>Parts cannot return to the lazy state once they have been created. |
| This is a limitation in the 3.1 implementation, not a functional |
| requirement.</li> |
| <li>It is valid to continue using the public interface of |
| WorkbenchPartReference once it has been disposed, however a disposed |
| reference cannot be passed to methods in workbench page (since it is, |
| by definition, no longer part of any page).</li> |
| </ul> |
| <h3><a class="mozTocH3" name="mozTocId789670"></a>2.2 Part Construction</h3> |
| <div style="text-align: center;"><span style="font-weight: bold;">Figure |
| 5: Message sequence for creating a part<br> |
| <br> |
| </span></div> |
| <div style="text-align: center;"><img alt="" |
| src="images/part_creation_msc.png" style="width: 892px; height: 700px;"><br> |
| </div> |
| <br> |
| Figure 5 shows the process for creating a part. The horizontal line |
| separates the two phases of creating a part. First the part is added to |
| the layout, and then a real implementation is attached. These are two |
| distinct operations, and the part can exist as a tab in the page with no |
| implementation for some time before it becomes visible. This diagram |
| focuses on the interactions with the part reference, and skips the |
| details of adding the part to the presentation and creating the part |
| site. |
| <br> |
| <br> |
| Suggestion: there are situations where it would be useful to only add |
| the part to the layout if it can be created successfully (this would be |
| necessary to pass a PartInitException thrown in the implementation's |
| init method up through IWorkbenchPage.openEditor). In these situations, |
| it would be possible to merge both operations into one atomic operation |
| by creating the part before adding it to the layout. It is unknown if |
| this would create event ordering bugs in client code. |
| <br> |
| <br> |
| <span style="font-weight: bold;"></span> |
| <h2><a class="mozTocH2" name="mozTocId409413"></a>3 Workbench Layout<br> |
| </h2> |
| <br> |
| <div style="text-align: center;"><span style="font-weight: bold;">Figure |
| 6: LayoutPart hierarchy</span><br> |
| <img alt="" src="images/LayoutPart_hierarchy.png" |
| style="width: 302px; height: 412px;"><br> |
| </div> |
| <br> |
| The workbench layout provides supports arranging parts using drag & |
| drop, resizing and detaching parts, fast views, etc. This section gives |
| a quick overview of the layout mechanism. |
| <br> |
| <br> |
| Anything in the workbench layout is a LayoutPart. A LayoutPart manages a |
| set of widgets in a rectangular region of the screen, can contain or |
| arrange other layout parts, returns size constraints, responds to drag |
| events, etc. To this extent, a LayoutPart is very similar to a custom |
| SWT Control. However, LayoutPart differs from Control in several |
| important ways. |
| <br> |
| <ul> |
| <li>The LayoutPart hierarchy is not the same as the widget hierarchy. |
| Even though one LayoutPart may contain another, their widgets may be |
| peers. This allows drag and drop to work on platforms where SWT doesn't |
| support reparenting, since a LayoutPart can be reparented without |
| reparenting its widgets.<br> |
| </li> |
| <li>LayoutParts mainly perform layout-related tasks, unlike Controls |
| which also supply behavior and appearance. The behavior of a LayoutPart |
| is supplied by the widgets it arranges.<br> |
| </li> |
| <li>LayoutParts know about higher-level concepts like zoom, and can |
| specify constraints about their own size.<br> |
| </li> |
| </ul> |
| Figure 6 shows the LayoutPart hierarchy. Notice the symmetry between the |
| View* classes and the Editor* classes. These classes exist largely for |
| historical reasons, and it should be possible to move all of the |
| functionality into the Part* base classes or other objects in the |
| system. Since all of the interesting behavior comes from the Part* |
| classes, the remainder of this section will focus on them without |
| describing the minor differences between views and editors. |
| <br> |
| <br> |
| PartSashContainer arranges a set of child parts separated by a bunch of |
| sashes. This is the object that implements the most visible aspects of |
| the workbench layout. It arranges rectangular regions separated by |
| sashes, and allows new regions to be created by splitting old ones. It |
| also supports the size constraints that make minimized views possible, |
| and determines what it means for one of these regions to be maximized. |
| Typically, a PartSashContainer contains a bunch of PartStacks, although |
| it is also possible for it to contain another PartSashContainer. The |
| latter case occurs since the editor area and the perspective both use a |
| PartSashContainer for their layout and one is embedded inside the other. |
| PartSashContainer owns its stacks but does not own an embedded |
| PartSashContainer. In a workbench window, there is one PartSashContainer |
| for each perspective and one for the editor area itself. |
| <br> |
| <br> |
| PartStack arranges a stack of PartPanes. PartStack allows the |
| presentation API to participate in the workbench layout. The code for |
| creating the tabs and arranging parts is supplied by the active |
| presentation. |
| <br> |
| <br> |
| PartPane allows views and editors to participate in the workbench |
| layout. Although PartPanes are arranged by PartStacks they belong to |
| part reference, not the stack. The same PartPane can exist in more than |
| one PartStack at a time if that part appears in more that one |
| perspective. |
| <span style="font-weight: bold;"><br> |
| <br> |
| </span> |
| <h3><a class="mozTocH3" name="mozTocId95893"></a>3.1 An example layout</h3> |
| LayoutParts are best explained through example. Imagine a |
| WorkbenchWindow that contains custom Java and Java Browsing perspectives |
| that look like Figure 7 and Figure 8 respectively. |
| <br> |
| <br> |
| <br> |
| <div style="text-align: center;"><span style="font-weight: bold;">Figure |
| 7: Example Java Perspective</span><br> |
| <img alt="" src="images/perspective1.png" |
| style="width: 571px; height: 495px;"><br> |
| <br> |
| <span style="font-weight: bold;">Figure 8: Example Java Browsing |
| perspective</span><br> |
| <img alt="" src="images/perspective2.png" |
| style="width: 571px; height: 495px;"><br> |
| </div> |
| <br> |
| <br> |
| Assume that the window resembles Figure 7. In this case, the Java |
| perspective is active, the Java Browsing perspective is hidden, and the |
| objects are connected as shown in Figure 9: |
| <br> |
| <br> |
| <br> |
| <div style="text-align: center;"><span style="font-weight: bold;">Figure |
| 9: LayoutPart instances when two perspectives are open</span><br> |
| <img alt="" src="images/perspective1_2_instances.png" |
| style="width: 555px; height: 670px;"><br> |
| <div style="text-align: left;"><br> |
| </div> |
| </div> |
| <br> |
| <br> |
| All LayoutParts have a container pointer that points to the object that |
| is currently managing their position. Since the same LayoutPart instance |
| may exist in more than one perspective at once, this pointer points to |
| the part's container in the currently-active perspective. In the case of |
| the projects view, above, the part is not in the current perspective so |
| its container pointer is null. When another perspective becomes active, |
| all the container pointers move to the new perspective. For historical |
| reasons, this is accomplished by setting and clearing the contianer |
| pointer when the container becomes visible or invisible. This works |
| since only one perspective is visible at a time, but it also means that |
| perspectives cannot be manipulated when they are invisible. |
| <br> |
| <br> |
| The diagram shows the internal objects that make up the only editor. |
| Although this detail has been omitted for the views, they would look |
| similar. Each view's PartPane is owned by a part reference which may |
| have an associated part implementation. |
| <br> |
| <br> |
| <h3><a class="mozTocH3" name="mozTocId114962"></a>3.2 Zoom / Unzoom |
| protocol<br> |
| </h3> |
| The notion of "zoom" is defined locally between a part and its immediate |
| container. Zoom changes are triggered bottom-up. A part asks its parent |
| to "zoom me", and the parent either does something with the request or |
| forwards the request up to its parent. Each container determines what it |
| means for a child to be zoomed. Once a part's zoom state changes, its |
| parent notifies it by calling setZoomed. The part may in turn zoom or |
| unzoom one or more of its children. |
| <br> |
| <br> |
| Anything that can contain LayoutParts must implement the following |
| methods, to support zooming: |
| <br> |
| <span style="font-family: monospace;"><br> |
| </span> |
| <code> /**<br> |
| * Called by child parts to request a zoom in, |
| given an immediate child <br> |
| * <br> |
| * @param toZoom part to zoom in on<br> |
| */<br> |
| public void childRequestZoomIn(LayoutPart toZoom);<br> |
| <br> |
| /**<br> |
| * Called by child parts to request a zoom out<br> |
| */<br> |
| public void childRequestZoomOut();<br> |
| <br> |
| /**<br> |
| * Returns true iff the given child is obscured |
| due to the fact that the container is zoomed into<br> |
| * another part. <br> |
| * <br> |
| * @param toTest part to test<br> |
| * @return true iff the part is currently |
| obscured <br> |
| */<br> |
| public boolean childObscuredByZoom(LayoutPart |
| toTest);<br> |
| <br> |
| /**<br> |
| * Returns true iff we are zoomed into the given |
| part, given an immediate child of this container.<br> |
| * <br> |
| * @param toTest part to test<br> |
| * @return true iff this contianer is currently |
| zooming in on the given part<br> |
| */<br> |
| public boolean childIsZoomed(LayoutPart toTest);<br> |
| <br> |
| </code> |
| <br> |
| Consider again Figure 7. If we were to double-click on the java editor |
| to zoom it, the LayoutParts would send messages to one another in the |
| following sequence. (In this diagram, each cell represents a method |
| call. Each column is an object. The reciever's column shows the method |
| name and the caller contains an arrow. Rows are in ascending order of |
| time.) |
| <br> |
| <br> |
| <table style="width: 100%; text-align: left;" border="1" cellpadding="2" |
| cellspacing="2"> |
| <tbody> |
| <tr> |
| <td style="vertical-align: top; font-weight: bold;">Java Editor |
| (PartPane)<br> |
| </td> |
| <td style="vertical-align: top; font-weight: bold;">PartStack<br> |
| </td> |
| <td style="vertical-align: top; font-weight: bold;">editor area |
| (EditorSashContainer)<br> |
| </td> |
| <td style="vertical-align: top; font-weight: bold;">ViewSashContainer<br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;">requestZoomIn<br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;"><img alt="" |
| src="images/right_arrow.png" style="width: 42px; height: 17px;"><br> |
| </td> |
| <td style="vertical-align: top;">childRequestZoomIn(java editor)<br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><img alt="" |
| src="images/right_arrow.png" style="width: 42px; height: 17px;"><br> |
| </td> |
| <td style="vertical-align: top;">childRequestZoomIn(java editor's |
| part stack)<br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;">if there were other editor stacks in |
| the layout, we would call setVisible(false) on them here</td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;">remember the partStack as the zoomed |
| part<br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;">setZoomed(true)<br> |
| </td> |
| <td style="vertical-align: top;"><img alt="" |
| src="images/left_arrow.png" style="width: 42px; height: 17px;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;">setZoomed(true)<br> |
| </td> |
| <td style="vertical-align: top;"><img alt="" |
| src="images/left_arrow.png" style="width: 42px; height: 17px;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><img alt="" |
| src="images/right_arrow.png" style="width: 42px; height: 17px;"><br> |
| </td> |
| <td style="vertical-align: top;">childRequestZoomIn(editor area)<br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;">call setVisible(false) on all |
| PartStacks for views in the perspective<br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;">remember the editor area as the |
| zoomed part<br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;">setZoomed(true)<br> |
| </td> |
| <td style="vertical-align: top;"><img alt="" |
| src="images/left_arrow.png" style="width: 42px; height: 17px;"></td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;">trigger a layout<br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;">setBounds(zoomed bounds)<br> |
| </td> |
| <td style="vertical-align: top;"><img alt="" |
| src="images/left_arrow.png" style="width: 42px; height: 17px;"></td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;">setBounds(zoomed bounds)</td> |
| <td style="vertical-align: top;"><img alt="" |
| src="images/left_arrow.png" style="width: 42px; height: 17px;"></td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;">setBounds(zoomed bounds)</td> |
| <td style="vertical-align: top;"><img alt="" |
| src="images/left_arrow.png" style="width: 42px; height: 17px;"></td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| <td style="vertical-align: top;">trigger a layout (nothing to do)<br> |
| </td> |
| <td style="vertical-align: top;"><br> |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| <br> |
| <h3><a class="mozTocH3" name="mozTocId977378"></a>3.3 Layout protocol<br> |
| </h3> |
| Every LayoutPart can specify constraints on their size. Parts specify |
| constraints by implementing the ISizeProvider interface. ISizeProvider |
| serves a similar function as the computeSize method on an SWT control, |
| in that the parent layout uses it to consult with the part when |
| computing the part's size. ISizeProvider can provide a variety of |
| constraints: |
| <br> |
| <br> |
| <table style="width: 100%; text-align: left;" border="1" cellpadding="2" |
| cellspacing="2"> |
| <tbody> |
| <tr> |
| <td style="vertical-align: top; font-weight: bold;">Constraint type<br> |
| </td> |
| <td style="vertical-align: top; font-weight: bold;">Meaning<br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;">Minimum size<br> |
| </td> |
| <td style="vertical-align: top;">Given the available space along one |
| dimension, the part returns the minimum size that it can be |
| compressed to along the other dimension. For example, a stack would |
| typically set its minimum size to be large enough to fit its tabs. |
| The information about available perpendicular space could allow a |
| stack to have wrapping tabs and still reserve enough vertical space |
| for the tabs once they are wrapped to fill the available horizontal |
| space.<br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;">Maximum size<br> |
| </td> |
| <td style="vertical-align: top;">Given the available space along one |
| dimension, the part returns the maximum size that it can utilize |
| along the other dimension. For example, minimized stacks are |
| implemented by setting their maximum size to the minimized size. |
| Non-minimized stacks typically have an unbounded maximum size.<br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;">Preferred size<br> |
| </td> |
| <td style="vertical-align: top;">Given the availble space along one |
| dimension and a preferred size, this returns the size closest to the |
| preferred size at which the part would look best. Parts can use this |
| to quantize their size. For example, a part can ensure that its size |
| is always chosen such that it can be completely filled with toolbar |
| icons leaving no space left over.<br> |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| <br> |
| Although there are three kinds of constraints, they are all returned |
| using a single method. See the JavaDoc on ISizeProvider for more |
| information. |
| <br> |
| <br> |
| Whenever a size constraint changes, the part notifies its contianer by |
| calling resizeChild(part). This tells the container to respond to the |
| new constraints, and to resize the child if necessary (suggestion: if |
| this is ever exposed as API, it would be better to separate the concerns |
| of notifying the parent of changes and triggering a layout. In general, |
| it may be possible for more than one part to change without requiring a |
| layout between each change). |
| <br> |
| <br> |
| <h3><a class="mozTocH3" name="mozTocId162591"></a>3.4 PartStack: |
| Communicating with the Presentation API<br> |
| </h3> |
| PartStack allows presentation to participate in the workbench layout. As |
| shown in Figure 10, it wraps a single instance of StackPresentation, and |
| allows it the presentation to manipulate parts by converting each |
| visible part into an IPresentablePart. The part stack outlives the |
| StackPresentation. Whenever the part stack needs widgets, it creates the |
| StackPresentation. If the widgets are no longer needed, it disposes the |
| StackPresentation and remembers its persisted form. Whenever the |
| PartStack persists its StackPresenation, it remembers the presentation |
| ID so that it will not try to restore one StackPresentation from state |
| saved by an incompatible presentation. |
| <br> |
| <br> |
| <div style="text-align: center;"><span style="font-weight: bold;">Figure |
| 10: Anatomy of PartStack</span><br> |
| <img alt="" src="images/PartStack.png" |
| style="width: 430px; height: 225px;"><br> |
| <div style="text-align: left;"><br> |
| Suggestion: it would be useful to update this document with a state |
| diagram for PartStack, and message sequence charts for initializaiton |
| and part activation.<br> |
| <br> |
| </div> |
| </div> |
| <h3><a class="mozTocH3" name="mozTocId479574"></a>3.5 PartSashContainer: |
| The main workbench layout <br> |
| </h3> |
| <div style="text-align: center;"><span style="font-weight: bold;">Figure |
| 11: PartSashContainer</span><br> |
| <img alt="" src="images/PartSashContainer.png" |
| style="width: 428px; height: 305px;"><br> |
| </div> |
| <br> |
| PartSashContainer implements the main layout for a perspective and the |
| editor area. As shown in Figure 11, PartSashContainer contains a list of |
| children, a (possibly null) zoomed part, and a LayoutTree that manages |
| the actual layout. |
| <br> |
| <br> |
| LayoutTree is a binary tree (technically, a KD tree). Each internal node |
| is an instance of LayoutTreeNode. It contains a draggable sash |
| (LayoutPartSash) that divides its area among its left and right |
| children. LayoutTreeNodes can be horizontal or vertical based on the |
| orientation of the sash. For horizontal nodes, the "left" child is on |
| top and the "right" child is on the bottom. Leaf nodes are instances of |
| LayoutTree (the base class), and they point to a LayoutPart that |
| occupies that region of the screen. Normally, this is a PartStack, but |
| in general it can be any LayoutPart. |
| <br> |
| <br> |
| Each LayoutTree occupies a recangular region of the screen that |
| encompasses its children. Internal nodes keep track of an integer size |
| for each child (implementation note: the sizes are stored in the |
| associated LayoutPartSash, not the LayoutTreeNode itself). Normally, the |
| left and right sizes are used as a ratio for dividing up the available |
| space. However, when one child contains the editor area, the other |
| becomes "non-compressible". If one side in non-compressible, the size |
| value is interpreted as a fixed pixel size rather than a ratio. When the |
| sash is moved, the size values are set to the current pixel sizes of the |
| left and right children. |
| <br> |
| <br> |
| Figure 12 shows an example LayoutTree. If this tree were rendered in a |
| workbench window, it would resemble Figure 3.5.3. The tall vertical sash |
| separating the package explorer from the editor area is the root node. |
| The left child is the leaf node holding the package explorer's stack. |
| The right node is the horizontal sash separating the problems view from |
| the editor area. The editor area itself is a PartSashContainer, which |
| has its own LayoutTree. Note that the rounded rectangles in Figure 3.5.2 |
| are LayoutParts. The upper portion of the rectangle is the part type and |
| the lower portion is some text to help locate the part in the |
| screenshot. In this example, every internal node has the editor area on |
| one side of it, so all sizes are interpreted as pixel sizes and not |
| ratios. |
| <br> |
| <div style="text-align: center;"><span style="font-weight: bold;"></span><br> |
| <span style="font-weight: bold;">Figure 12: Example LayoutTree</span><br |
| style="font-weight: bold;"> |
| <img alt="" src="images/example_LayoutTree.png" |
| style="width: 480px; height: 462px; font-weight: bold;"><br> |
| <span style="font-weight: bold;"><br> |
| Figure 13: Example perspective</span><br style="font-weight: bold;"> |
| <img alt="" src="images/perspective1.png" |
| style="width: 571px; height: 495px; font-weight: bold;"><br> |
| </div> |
| <br> |
| Like LayoutParts, LayoutTrees also implement ISizeProvider and support |
| size constraints. For external nodes, the size constraints come directly |
| from the LayoutPart. For internal nodes, the size constraints are |
| computed from the child nodes as follows: |
| <br> |
| <ol> |
| <li>When computing a constraint perpendicular to the sash, the result |
| is the sum of the constraints of the children plus the width of the |
| sash.</li> |
| <li>When computing a constraint parallel to the sash, the result is the |
| maximum of the constraints of the children<br> |
| </li> |
| </ol> |
| An example can help make this a little less abstract. Imagine we're |
| computing the minimum width for the root node in Figure 12, which is a |
| tall vertical sash. Width measurements are perpendicular to the sash, so |
| we end up with case 1. The minimum width is the minimum width of the |
| left stack plus the sash width plus the minimum width of the right |
| child. This makes sense because if we made the root node any smaller, |
| one of the three would need to be truncated or made smaller than their |
| minimum size. |
| <br> |
| <br> |
| The "right child" mentioned above is the horizontal sash separating the |
| problems view from the editor area. When computing its minimum width, we |
| hit case 2: the minimum width of a horizantal sash is the maximum of the |
| minimum widths of each child. Intuitively, this means that the child |
| with the larger minimum size will be the first to reach its minimum when |
| the layout gets small. |
| <br> |
| <br> |
| <h3><a class="mozTocH3" name="mozTocId887241"></a>3.6 Drag / Drop</h3> |
| <div style="text-align: center;"><span style="font-weight: bold;">Figure |
| 14: LayoutPart drop regions</span><br> |
| </div> |
| <div style="text-align: center;"><img alt="" |
| src="images/drag_regions.png" style="width: 571px; height: 495px;"><br> |
| <div style="text-align: left;"><br> |
| Dragging a workbench part is triggered by calling DragUtil.performDrag. |
| SWT controls can respond to drag / drop by registering an |
| IDragOverListener with DragUtil .addDragTarget. If multiple drag |
| listeners are registered for the same screen position, the one |
| associated with the most specific control gets precidence.<br> |
| <br> |
| Rather than register drag listeners directly, LayoutParts implement a |
| getDropTarget method. When the window recieves a drag event, it |
| delegates to the top-level LayoutPart's getDropTarget. Each part either |
| delegates to one of its children or handles the drag event directly. If |
| the part returns null from getDropTarget, this means that the part has |
| no special preference for the drop event, and the parent may provide a |
| default behavior. Unlike IDragOverListener, getDropTarget works |
| top-down. The parent may overload any drag regions that are recognized |
| by the child, or provide default behaviors for drag regions not |
| recognized by the child.<br> |
| <br> |
| Figure 14 shows regions of the workbench where LayoutParts can be |
| dropped. The workbench checks these regions in the following order:<br> |
| <br> |
| <table style="width: 100%; text-align: left;" border="1" cellpadding="2" |
| cellspacing="2"> |
| <tbody> |
| <tr> |
| <td style="vertical-align: top;"><span style="color: rgb(0, 51, 0);">1. |
| green region</span><br> |
| </td> |
| <td style="vertical-align: top;">The fast view bar registers a |
| IDragOverListener that responds to views being dragged.<br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;"><span |
| style="background-color: rgb(0, 0, 0);"><span |
| style="background-color: rgb(255, 255, 255);">2. black regions</span></span><br> |
| </td> |
| <td style="vertical-align: top;">These areas are reserved by |
| PartSashContainer.getDropTarget. When the user drags a part over this |
| region, the PartSashContainer interprets this as a split and does not |
| ask its child to participate in the drag. This ensures that it is |
| never possible for the child to prevent splitting by reserving its |
| entire area as a drop region. The region outside the |
| PartSashContainer's client area is handled by an IDragOverListener |
| registered with the shell. This allows parts to be attached to the |
| edge of the layout by dragging over the window trim.<br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;"><span style="color: rgb(255, 0, 0);">3. |
| red regions</span><br> |
| </td> |
| <td style="vertical-align: top;">For most of the screen area, |
| PartSashContainer delegates to its child (PartStack.getDropTarget). |
| PartStack filters out objects that don't belong in the stack (no |
| editors in view stacks, etc) and delegates to the presentation |
| (StackPresentation.dragOver). The default presentation recognizes the |
| tabs and title area as drop targets, but returns null everywhere |
| else. This is the best practice for presentations and PartStack since |
| it permits PartSashContainer to extend the split regions where |
| possible.<br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;"><span style="color: rgb(0, 0, 153);">4. |
| blue regions</span><br> |
| </td> |
| <td style="vertical-align: top;">If the child doesn't have any |
| particular use for the drop location, the PartSashContainer extends |
| the split regions. If the child allows objects of this type to be |
| added (determined by calling LayoutPart.allowsAdd), it uses the |
| center of the rectangle for stacking. Otherwise, the entire region is |
| used for splitting. The latter case occurs when dragging views over |
| the editor area or when dragging over a standalone view.<br> |
| </td> |
| </tr> |
| <tr> |
| <td style="vertical-align: top;">5. outside the window (not shown)<br> |
| </td> |
| <td style="vertical-align: top;">The workbench page registers an |
| IDragOverListener that responds to views being dragged outside the |
| workbench window, and interprets this as a detach operation.<br> |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| <br> |
| By convention, all methods used for drag / drop work in display |
| coordinates.<br> |
| <br> |
| </div> |
| </div> |
| <h2><a class="mozTocH2" name="mozTocId443855"></a>4 Action Bars</h2> |
| Parts contribute to menus, toolbars, coolbars, popup menus, etc. using |
| action bars. Each action bar implements IActionBars. It is possible to |
| create one action bar as a child of another. In this situation, the |
| parent and child share the same widgets, but the child may be disabled |
| independently of the parent. Figure 15 shows how the workbench action |
| bars are constructed. The rectangles indicate instances of IActionBars, |
| and the ovals indicate other entities that create or modify action bars. |
| <br> |
| <br> |
| <div style="text-align: center;"><span style="font-weight: bold;">Figure |
| 15: Action bar information flow</span><br> |
| <img alt="" src="images/action_bar_flow.png" |
| style="width: 800px; height: 600px;"><br> |
| <div style="text-align: left;"> |
| <p |
| colors="#FFFFFF,#000000,#808080,#000000,#00CC99,#3333CC,#CCCCFF,#B2B2B2"></p> |
| <div class="O"> |
| <div style=""><span style="font-size: 50%;"><br> |
| </span><span style="font-family: Symbol; font-size: 50%;"></span><span |
| style="font-size: 50%;"></span><span |
| style="font-family: Symbol; font-size: 50%;"></span><span |
| style="font-size: 50%;"></span><span |
| style="font-family: Symbol; font-size: 50%;"></span><span |
| style="font-size: 50%;"></span></div> |
| <div style=""><span style="display: none;"> </span></div> |
| </div> |
| </div> |
| </div> |
| <br> |
| The workbench window has a top level IActionBars instance that |
| contributes to the main menubar, coolbar, etc. (this top-level object is |
| returned by WorkbenchWindow.getActionBars()). |
| <br> |
| <br> |
| <h3><a class="mozTocH3" name="mozTocId652269"></a>4.1 Editor Action Bars<br> |
| </h3> |
| Each type of editor gets a reference-counted IActionBars instance that |
| is a child of the window's action bars. For example, if the workbench |
| contains 10 java editors and 10 text editors, it will create one |
| IActionBars to be shared among the Java editors and another IActionBars |
| to be shared among the text editors. Editors can access this shared |
| instance by calling getSite().getActionBars(). Editor action bars are |
| initialized by an instance of IEditorActionBarContributor, and |
| additional actions are added by the editorActions extension point. |
| <br> |
| <br> |
| The reference counted IEditorActionBars are managed by the |
| EditorManager, along with the IActionBarContributor. |
| <br> |
| <br> |
| <h3><a class="mozTocH3" name="mozTocId340925"></a>4.2 Action Sets<br> |
| </h3> |
| An action set is an action bar that is identified by ID. Action sets are |
| contributed by the actionSets extension point, and their action bars are |
| a child of the workbench window's root action bars. Visibility of action |
| sets is controlled by the following function: |
| <br> |
| <br> |
| <div style="margin-left: 40px;"><img alt="" |
| src="images/action_set_formula.png" style="width: 208px; height: 29px;"><br> |
| </div> |
| <br> |
| Where: |
| <br> |
| <br> |
| <div style="margin-left: 40px;">P = set of actions enabled in the |
| perspective. Returned by Perspective.getAlwaysOnActionSets(). |
| Initialized by the perspective factory, perspective extensions extension |
| point, and IWonkbenchPage.showActionSet.<br> |
| A = action sets associated with the active part (associated by the |
| actionSetPartAssociations extension point).<br> |
| E = action sets associated with the active editor (associated by the |
| actionSetPartAssociations extension point).<br> |
| D = action sets that are enabled by default (a property of the |
| actionSets extension markup).<br> |
| N = action sets that are explicitly disabled in the current perspective. |
| Initialized by IWorkbenchPage.hideActionSet.<br> |
| </div> |
| <br> |
| The sets P and N are persisted with the current perspective between |
| sessions. The sets A and E can change every time the active part or |
| editor changes. |
| <br> |
| <br> |
| The workbench page uses the class ActionSetManager to compute action set |
| enablement. This class keeps two reference counts for each action set: |
| <br> |
| <ul> |
| <li>a "showCount" indicates how many of P, A, E, and D the action set |
| appears in</li> |
| <li>a "hideCount" indicates whether the action set appears in N</li> |
| </ul> |
| The action set is visible iff showCount is nonzero and hideCount is |
| zero. |
| <br> |
| <br> |
| <h3><a class="mozTocH3" name="mozTocId277128"></a>4.3 View Actions</h3> |
| Each view instance is given its own IActionBars instance. Unlike editor |
| action bars, these are not shared and are not a child of the workbench |
| window's root action bars. This means that view instances can |
| programmatically add actions to their action bar. Additional actions are |
| also added to a view's action bars through the viewActions extension |
| point. |
| <br> |
| <br> |
| <h2><a class="mozTocH2" name="mozTocId642161"></a>5 General Conventions</h2> |
| This section describes coding conventions that apply to the entire |
| workbench. |
| <br> |
| <br> |
| <h3><a class="mozTocH3" name="mozTocId892615"></a>5.1 Objects must not |
| be returned through API until they are fully initialized</h3> |
| Some objects require several public methods to be called in a specific |
| order before they are considered fully initialized. For example, to |
| initialize an IViewPart, it is necessary to call the constructor, |
| setInitializationData, init, and createPartControl before the part is |
| considered initialized. Until |
| <span style="font-style: italic;">all</span> |
| of the above have happened successfully, it must not be possible to |
| reach the object through any API method. |
| <br> |
| <br> |
| Keep in mind that the object may trigger other client code during its |
| own initialization, so it should not even be possible for an object to |
| find itself during construction. |
| <br> |
| <br> |
| <h3><a class="mozTocH3" name="mozTocId308622"></a>5.2 No method may open |
| a modal dialog unless its JavaDoc says so</h3> |
| Any method that has the possibility of opening a modal (or of calling |
| Display.readAndDispatch through any other means) needs to be clearly |
| documented. All callers of that method must be prepared to handle |
| background threads running arbitrary code in *syncExecs during the |
| method call. It is always a bug to open a modal dialog when extending or |
| overloading a method unless the JavaDoc in the base class says |
| otherwise. Permitting opening of dialogs in a method that did not |
| previously do so is a breaking change for all callers of that method. |
| <br> |
| <br> |
| Some common bugs: |
| <br> |
| <ul> |
| <li>Views are never allowed to call MessageDialog.openError from their |
| createPartControls method, especially when handling an exception.</li> |
| <li>Parts can be closed in a *syncExec. If a part calls a method that |
| opens dialogs, it might not still exist when the method returns. After |
| calling the method, the part must check that it hasn't been disposed |
| before using their widgets or accessing any members that would have |
| been deallocated by the disposal.</li> |
| </ul> |
| <br> |
| <h3><a class="mozTocH3" name="mozTocId753192"></a>5.3 Lazy creation |
| should happen as late as possible<br> |
| </h3> |
| Part implementations should be created at the latest possible moment. |
| The workbench's internal state should be restored as much as possible |
| before the first object is created from an extension point. Parts should |
| not be materialized until they are needed. |
| <br> |
| <br> |
| <h3><a class="mozTocH3" name="mozTocId921869"></a>5.4 getters should not |
| modify the thing they are supposed to measure<br> |
| </h3> |
| This applies to any situation where there is a getter and an associated |
| listener that monitors changes in the getter's value. The getter should |
| never cause such a property change to be fired while computing its |
| return value. |
| <br> |
| <br> |
| For example, IWorkbenchPage.getActivePart() should never create the |
| active part. Unless the active part already exists and a property change |
| was fired to all IPartListeners, getActivePart must return null. |
| <br> |
| <br> |
| <hr> |
| <p>To discuss or report problems in this article see <a |
| href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=103958">bug 103958</a>.</p> |
| |
| <p><small>IBM is trademark of International Business Machines |
| Corporation in the United States, other countries, or both.</small></p> |
| <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> |
| <p><small>Microsoft and Windows are trademarks of Microsoft Corporation |
| in the United States, other countries, or both.</small></p> |
| <p><small>Other company, product, and service names may be trademarks or |
| service marks of others.</small></p> |
| |
| |
| </body> |
| </html> |