Windows are platform-specific data structures through which documents display themselves. This section discusses how to use OpenDoc window objects (which are basically wrappers for those structures) regardless of which platform you are developing for.
The OpenDoc class ODWindow is a wrapper for a pointer to a platform-specific window structure. For some operations, your part editor must retrieve the window pointer from the ODWindow object and use the platform's facilities. In most cases, however, the interface to ODWindow provides the capability you need for interacting with your windows.
There is a single instantiated window state object (class ODWindowState) for each OpenDoc session. The window state consists of a list of the currently existing window objects. You can access all open windows in a session through the window state.
The document shell and dispatcher use the window state to pass events to parts so that they can activate themselves, handle user input, and adjust their menus as necessary. A part may be displayed in any number of frames, in any window of a document. The dispatcher uses the window state to make sure that it passes events to the correct part, no matter what window encloses the active frame and how many other frames the part has.
Normally, your part editor calls the window state only when it creates new windows, when it needs access to a particular window, and when it needs access to the base menu bar object.
If for some reason your part needs access to all windows, you can create an ODWindowIterator object, which gives you access to all windows referenced by the window state.
In order to receive events in a window, you generally must create an OpenDoc window object for it. (You may not be able to create an OpenDoc window for a modal dialog box, but you can pass an event filter routine to it and therefore receive events.) Windows in OpenDoc are created and maintained through the window-state object, which you access through the session object.
You first create a window with platform-specific calls; you then call the window state object to create an OpenDoc window object describing the platform-specific window. You call either of two methods:
A window has an is-root property. If the property is true, the window is a root window, which is the same as a document window. The root part of a root window is the root part of its document, and the document cannot close as long as the root window is open. If a window's is-root property is false, the window may be either a part window that has been opened from a source frame within a root window, or it may be a dialog box, palette, or other utility window. OpenDoc permits multiple document windows for a single document, as long as the root part provides a user interface to support this feature. The document shell closes a document when the document's last document window (root window) is closed.
Windows also have a should-save property that, if true, specifies that the state of the window is saved persistently after the window closes. Usually, only document windows should be marked as should-save.
The creator of a window can specify the view type and presentation of the root frame, the frame that displays the root part. The view type specifies whether the root part should draw itself as an icon, and the presentation specifies what kind of appearance the part content should have if not drawn as an icon. View type and presentation are suggestions to the part editor that draws within that frame. View type and presentation are described in more detail in "Defining General Display Characteristics".
On the OpenDoc platform, the root frame in the window has the same shape as the window's content region.
Your part should create windows as invisible and then make them visible as described in "Opening a Window".
After creating a window, your part editor typically makes calls to these three methods, in this order:
Your part editor should not maintain references to ODWindow objects for accessing OpenDoc windows, because the document shell or the window state object can close a window and invalidate the reference. Instead, the window state assigns window IDs that are valid for the length of a session. Use the window's GetID method to get the ID of a window when you create it, and then pass that ID to the window state's AcquireWindow method for subsequent access to the window.
If your part editor needs to close a window programmatically, it calls the window's CloseAndRemove method. That method closes the window, releases the window object and disposes of the platform-specific window structure, deletes the root facet and canvas, and removes the root frame from the document. It also makes any necessary platform-specific calls to dispose of the window itself.
Whenever a document is saved, OpenDoc writes certain information into a storage unit of the window's root frame. The window's bounding rectangle, title, and other characteristics are saved in a property of type kODPropWindowProperties in the frame's storage unit.
When you create a root window, you retrieve that information from the stored frame, and use it to specify the platform-specific window's characteristics. You can use functions of the WinUtils utility library (provided with OpenDoc) to extract that information, or you can access the frame's storage unit directly. The kODPropWindowProperties property contains a persistent reference to another storage unit, which contains the following properties:
If your part is a root part that recreates a previously stored document window, you must make sure that the window is visible onscreen. Your document may have been moved from one system to another with a different monitor configuration or size. You may need to move or resize the window to fit its new environment.
Opening your part means creating a window for it and displaying it in the window.
Your part itself initiates the opening of a window when the user selects the Open as window command from the View menu (see "View Menu"), and when it creates its own dialog boxes. Otherwise, your part opens a window only when your part's Open method is called. This is the interface to the Open method:
ODID Open(in ODFrame frame); |
The Open method is called in these circumstances.
In your implementation of Open, you can take steps similar to the following, depending on the circumstances under which it was called.
Note:
You are not absolutely required to open a window when your Open method is called. Your part does whatever is appropriate, given its nature and the conditions under which the method is called. For example, if your part is a very simple sound player, it might simply play its sound and never create a window.
To receive events in its windows that it creates, your part must create an ODWindow object for each platform-specific window it uses, including dialog boxes (except for modal dialog boxes; see "Modal Dialog Boxes").
The document shell handles most window events outside of the content region, for example, events in the title bar or resize box.
If your part handles a window event, its HandleEvent method must return true. If it does not handle an event, its HandleEvent method must return false so that the document shell can handle the event.
The document shell usually resizes windows. When a window is resized, the active part does not change, but the part editor for the root frame is informed of the resizing through calls by OpenDoc to its FrameShapeChanged and GeometryChanged methods. The root part can then do any necessary invalidation and subsequent redrawing, including creation of new facets if embedded parts have become visible due to the resizing.
The document shell handles a mouse click in the Close icon of a window or user action of Close or its keyboard equivalent. The document shell closes the window, after which the window cannot be reopened.
If the window is a document window and is the only one open for that document, the document shell closes the document.
If your part editor needs to close a window programmatically, it can call the window's CloseAndRemove method. The window is closed and the window object is released.
The document shell handles some platform-specific window-moving actions, such as dragging of a window by its title bar. No event-handling is required of the window's root part.
Parts in other windows may need to be updated because of the window's move; they receive update events as appropriate.
When your part editor displays a modal dialog box, it does not need to create an ODWindow object, as with a regular window. However, it should still request the modal focus (using its own display frame as the modal-focus owner), and it can still receive events by providing an event filter
Your part can create and register its own dialog window, request the modal focus for the window's root frame, and handle the dialog box.
A frame displaying a modal dialog box should own the modal focus, a focus type that exists to constrain certain events.
For example, a mouse click outside the frame that has the modal focus still goes to that frame. If your part's frame has the modal focus and you click outside the frame, your part's HandleEvent method is called and passed a facet of kODNULL. The method should check for a null facet in this situation and either alert the user with a beep or dismiss the dialog box, as appropriate.
A click in a frame embedded within the frame that has the modal focus goes to the embedded frame. This behavior facilitates the construction of dialog boxes and other controls from multiple parts.
Your part obtains and relinquishes the modal focus as it does any focus, as described in "Requesting Focuses" and "Relinquishing Focuses".
In general, your part should not be willing to relinquish the modal focus on request. If your part is displaying a modal dialog, you probably do not want any other modal dialog to be displayed at the same time. To make sure that your part holds on to the modal focus, your part editor's BeginRelinquishFocus method should return kODFalse if the requested focus is kODModalFocus and the proposed new owner of the focus is not one of your own display frames.
When you have finished displaying a modal dialog box, you can directly transfer it to its previous owner by calling the arbitrator's TransferFocus method, as noted in "Handling a Simple Modal Dialog Box".
With modal dialog boxes, your part editor's dialog-box event filter controls which events you receive while a dialog box or alert box is being displayed. To pass received null events, update events, and activate events on to OpenDoc or other windows for handling, your event filter can send them to the OpenDoc dispatcher by calling its Dispatch method.
Your event filter should not pass other events, such as mouse events, to the dispatcher.
To display a simple modal dialog box or Alert box, you can take these steps:
By always saving and restoring the owner of the modal focus, your part can use this approach for nested modal dialog boxes, such as a dialog box that is built from several embedded parts.
In OpenDoc, to implement a full-featured movable modal dialog box, one that allows process switching, you must create a window object (ODWindow) to contain it. To display a movable modal dialog box, you can take these steps:
To make sure you dismiss the modal dialog box at the right time, you can take actions such as these when you receive a mouse-down event in the dialog box:
Note:
It is also possible to create a modal dialog box that is movable, but does not support process switching. To do so, use a filter function and other functions in a utility library (DlogUtil) provided with OpenDoc.
Modeless dialog boxes are more like regular windows than modal dialogs are. They can be activated and deactivated, and they need not be dismissed for your part to become active and editable.
To display a modeless dialog box in OpenDoc, you must create a window object (ODWindow) to contain it. To display the dialog box, you can take steps such as these:
When you click in the close box of a modeless dialog, you can hide the dialog window, rather than close it, so that it is not destroyed. This is an optimization that allows you to quickly display the dialog box again.
In your part's HandleEvent method, you can respond in this general way to a mouse click within a window's close box:
When your part is deactivated, it should hide any of its modeless dialog boxes.
When your part relinquishes the selection focus, it can get a reference to the dialog window (by passing its ID to the window state's AcquireWindow method), call the window's IsShown method to see if it is currently being shown, and then save that shown state and hide the window.
When your part reacquires the selection focus, it can retrieve a reference to the dialog window by passing its ID to the window state's AcquireWindow method. Then, if the dialog window had been visible at deactivation, your part can once again show it.