首页 A guide to the workbench internals

A guide to the workbench internals

举报
开通vip

A guide to the workbench internals http://www.eclipse.org/articles/Article-UI-Workbench/workbench.html#mozTocId91 7303 Inside the Workbench A guide to the workbench internals Summary This article describes how the Eclipse 3.1 workbench works, in particular the infrastructure for views ...

A guide to the workbench internals
http://www.eclipse.org/articles/Article-UI-Workbench/workbench.html#mozTocId91 7303 Inside the Workbench A guide to the workbench internals Summary 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. Stefan Xenos, IBM October 20, 2005 Table of Contents • 1 Introduction • 2 Inside a part o 2.1 Part Lifecycle o 2.2 Part Construction • 3 Workbench Layout o 3.1 An example layout o 3.2 Zoom / Unzoom protocol o 3.3 Layout protocol o 3.4 PartStack: Communicating with the Presentation API o 3.5 PartSashContainer: The main workbench layout o 3.6 Drag / Drop • 4 Action Bars o 4.1 Editor Action Bars o 4.2 Action Sets o 4.3 View Actions • 5 General Conventions o 5.1 Objects must not be returned through API until they are fully initialized o 5.2 No method may open a modal dialog unless its JavaDoc says so o 5.3 Lazy creation should happen as late as possible o 5.4 getters should not modify the thing they are supposed to measure 1 Introduction 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 UI development resources page . Figure 1: Ownership of views and editors Figure 1 shows how views and editors are owned by the workbench. 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. 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. 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. 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. Figure 2: Workbench objects and what they look like 2 Inside a part Figure 3: Anatomy of a part 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. 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. 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. 2.1 Part Lifecycle Figure 4: WorkbenchPartReference states Figure 4 shows the part lifecycle as a state machine. The part reference stores its current state in the integer state field. Notes: • 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. • The part implementation cannot be recreated once the reference has been disposed. • 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. • 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). 2.2 Part Construction Figure 5: Message sequence for creating a part 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. 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. 3 Workbench Layout Figure 6: LayoutPart hierarchy 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. 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. • 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. • 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. • LayoutParts know about higher-level concepts like zoom, and can specify constraints about their own size. 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. 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. 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. 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. 3.1 An example layout 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. Figure 7: Example Java Perspective Figure 8: Example Java Browsing perspective 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: Figure 9: LayoutPart instances when two perspectives are open 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. 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. 3.2 Zoom / Unzoom protocol 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. Anything that can contain LayoutParts must implement the following methods, to support zooming: /** * Called by child parts to request a zoom in, given an immediate child * * @param toZoom part to zoom in on */ public void childRequestZoomIn(LayoutPart toZoom); /** * Called by child parts to request a zoom out */ public void childRequestZoomOut(); /** * Returns true iff the given child is obscured due to the fact that the container is zoomed into * another part. * * @param toTest part to test * @return true iff the part is currently obscured */ public boolean childObscuredByZoom(LayoutPart toTest); /** * Returns true iff we are zoomed into the given part, given an immediate child of this container. * * @param toTest part to test * @return true iff this contianer is currently zooming in on the given part */ public boolean childIsZoomed(LayoutPart toTest); 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.) a Editor tPane) PartStack editor area (EditorSashContainer) ViewSashContainer requestZoomIn childRequestZoomIn(java editor) childRequestZoomIn(java editor's part stack) if there were other editor stacks in the layout, we would call setVisible(false) on them here remember the partStack as the zoomed part setZoomed(true) setZoomed(true) childRequestZoomIn(editor area) call setVisible(false) on all PartStacks for views in the perspective remember the editor area as the zoomed part setZoomed(true) trigger a layout setBounds(zoomed bounds) setBounds(zoomed bounds) setBounds(zoomed bounds) trigger a layout (nothing to do) 3.3 Layout protocol 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: Constraint type Meaning Minimum size 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. Maximum size 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. Preferred size 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. Although there are three kinds of constraints, they are all returned using a single method. See the JavaDoc on ISizeProvider for more information. 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). 3.4 PartStack: Communicating with the Presentation API 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. Figure 10: Anatomy of PartStack Suggestion: it would be useful to update this document with a state diagram for PartStack, and message sequence charts for initializaiton and part activation. 3.5 PartSashContainer: The main workbench layout Figure 11: PartSashContainer 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. 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. 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. 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 LayoutPar
本文档为【A guide to the workbench internals】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_677394
暂无简介~
格式:pdf
大小:280KB
软件:PDF阅读器
页数:0
分类:互联网
上传时间:2010-08-18
浏览量:19