Difference between revisions of "Framework/Article/Implementation of the Dispatch API In SFX2"

From Apache OpenOffice Wiki
Jump to: navigation, search
(Implementation of the Dispatch API in SFX2)
(Slot Processing)
Line 33: Line 33:
  
 
== Slot Processing ==
 
== Slot Processing ==
 +
 +
In former (Pre-UNO) time the slots where not only used for command dispatching but also for the implementation of our Basic API (up to StarOffice 5.2), so the slot arrays where "real" ''interfaces''. There are a lot residues of the in the sdi files (see below), but they aren't used anymore.<br/>
 +
 +
The use case explains why there are two different kinds of slots, property slots and method slots, and the difference between them can be spotted easily from the definition of a slot in the sdi file. Here are two examples, the first one describing a method slot and the second one describing a property slot:
 +
 +
<code>[cpp]
 +
SfxVoidItem About SID_ABOUT
 +
()
 +
[
 +
    /* flags: */
 +
    AutoUpdate = FALSE,
 +
    Cachable = Cachable,
 +
    FastCall = FALSE,
 +
    HasCoreId = FALSE,
 +
    HasDialog = TRUE,
 +
    ReadyOnlyDoc = TRUE,
 +
    Toggle = FALSE,
 +
    Container = FALSE,
 +
    RecordAbsolute = FALSE,
 +
    RecordPerSet;
 +
    Synchron;
 +
 +
    /* config */
 +
    AccelConfig = TRUE,
 +
    MenuConfig = TRUE,
 +
    StatusBarConfig = FALSE,
 +
    ToolBoxConfig = TRUE,
 +
    GroupId = GID_APPLICATION;
 +
]
 +
 +
SfxBoolItem DesignerDialog SID_STYLE_DESIGNER
 +
 +
[
 +
    /* flags: */
 +
    AutoUpdate = TRUE,
 +
    Cachable = Cachable,
 +
    FastCall = TRUE,
 +
    HasCoreId = FALSE,
 +
    HasDialog = FALSE,
 +
    ReadyOnlyDoc = FALSE,
 +
    Toggle = FALSE,
 +
    Container = FALSE,
 +
    RecordAbsolute = FALSE,
 +
    RecordPerSet;
 +
    Synchron;
 +
 +
    Readyonly = FALSE,
 +
 +
    /* config */
 +
    AccelConfig = TRUE,
 +
    MenuConfig = TRUE,
 +
    StatusBarConfig = FALSE,
 +
    ToolBoxConfig = TRUE,
 +
    GroupId = GID_FORMAT;
 +
]
 +
</code>
  
 
== Items and UNO structs ==
 
== Items and UNO structs ==

Revision as of 09:33, 22 December 2006

Implementation of the Dispatch API in SFX2

The Dispatch API as described in chapter 6.1.6 of the Developer's Guide is the backbone of our communication between "generic" UI elements and the document core implementations.

Traditionally SFX based components implemented this communication with a much older framework based on the so called slots and their organization into shells. While up to OpenOffice.org 1.1 our generic UI elements (menus, toolbars, etc.) still used the SFX based API directly to a large degree in OpenOffice.org 2.0 we changed this to using the Dispatch API exclusively, thus enabling us to share the UI components with other, not SFX based components. This paper describes how the old SFX implementation is matched to the DispatchProvider implementation that the component provides to the outside to make this happen.

The basic entity in the dispatch API is a command, and it's represented by a CommandURL. For simplifications we suppose that this CommandURL is a string (though the API transport it as a pre-parsed struct). All commands supported by our components have the form .uno:xxxxx for historical reasons, where xxxxx represents an internal command name.

The basic idea is that the Controller (the component used by a document to participate in the dispatch process) is able to take any CommandURL it receives in a request for a Dispatch Object and compares it with the CommandURLs in the set of commands it supports. If a match can be achieved a Dispatch Object is returned. The SFX based components charge their common Controller base class (SfxBaseController) implementation with the task of implementing this job based on the old SFX framework.

This old framework organized functionality in context that can be merged together and exposed to the outside world by a single point of contact. This contact point is an SfxDispatcher object that every SfxBaseController owns. The SfxDispatcher internally maitains a stack of objects, each representing a context. Examples for the contexts are "document, "view", "text", "table", "cell" etc. The complete stack of all contextual objects (all deriving from the common base class SfxShell) available in a particular situation represents the function set applicable to the current selection or cursor position in a document. Context changes inside the documents editing window causes pushing and poping of shell objects to and from the stack.

This is how a typical stack in Writer looks:

  • Text
  • View
  • Document
  • Frame
  • Module
  • Application

The Frame and Application contexts are there for historical reasons, we are still in the process of moving their functionality to the framework where other DispatchProviders outside of the component take over. I omitted the "Form" context here because it's somewhat confusing.

Each SfxShell owns an interface, an array of SfxSlot structs. Each slot represents a command supported by the context it's assigned to and the struct contains all necessary information that the SfxDispatcher needs to work together with the Shell object containing the slot without knowing its particular implementation. The most important part of information are the "name" of the slot that is identical with the internal command name of the dispatch command it represents and two pointers to functions inside the shell that the SFX can call to retrieve status information for the command or execute it. More about slots can be found below.

When the SfxDispatcher is asked for support of a particular command it searches for a slot with the given internal command name string with the topmost shell on the stack and the proceeding with the next one until success. This way "higher prioritized" contexts can overrule functionality from "lower prioritized" contexts. As an example, the "document" context has a generic implementation of the "Print" command, but each particular "view" context can overrule the generic behavior and define a specific way of printing.

The slot array aka interfaces are static to each shell class and so each interface is part of the data segment of the library that contains the shell code assigned to this interface. The data for these arrays needs to be predefined in soure files. Writing huge arrays into C++ source files is a very tedious work and so we use a different kind of source file that is easier to edit and have a compiler svidl that takes these files and compiles them into a generated header file containing the definition of the arrays. These idl files are located in the sdi sub folders of each SFX based project and have the extension "sdi". The generated header file contains the definitions (not only declarations) of all interfaces of the library and some "#define" magic allows to have each interface generated only once. More about this process follows below.

In OpenOffice.org 1.1 the SfxBaseController utilized its SfxDispatcher and its stack to provide a generic Dispatch object for every supported command. It gets the CommandURL in the queryDispatch call, looks for a slot on the dispatcher stack with a suitable internal command name and in case of success creates a dispatch object and returns it. There is a drawback in this approach: if the context changes (means: shell are pushed of popped) slot might appear of disappear from the stack so commands that had been supported aren't any longer or the other way around. This forces the DispatchProvider to request a complete refetching of all dispatch objects and so can be time consuming.

In OpenOffice.org 2.0 we utilize the "slot pool" of the SFX based modules. This in the entirety of all interfaces (slot arrays) the module supports. On startup all interfaces register at the module class (SfxModule base class) so it's easy to iterate through its interfaces. Now a dispatch object is returned when the slot is found anywhere in the slot pool, even if the interface is not on the stack, but in this case the dispatch object reports its slot as disabled everytime it's used. This can be determined dynamically so context changes don't need external updates, it's enough to update the internal status of the already created dispatch objects. This approach also enables some future optimizations for the representation of slot arrays that will be discussed later.

Slot Processing

In former (Pre-UNO) time the slots where not only used for command dispatching but also for the implementation of our Basic API (up to StarOffice 5.2), so the slot arrays where "real" interfaces. There are a lot residues of the in the sdi files (see below), but they aren't used anymore.

The use case explains why there are two different kinds of slots, property slots and method slots, and the difference between them can be spotted easily from the definition of a slot in the sdi file. Here are two examples, the first one describing a method slot and the second one describing a property slot:

[cpp] SfxVoidItem About SID_ABOUT () [

   /* flags: */
   AutoUpdate = FALSE,
   Cachable = Cachable,
   FastCall = FALSE,
   HasCoreId = FALSE,
   HasDialog = TRUE,
   ReadyOnlyDoc = TRUE,
   Toggle = FALSE,
   Container = FALSE,
   RecordAbsolute = FALSE,
   RecordPerSet;
   Synchron;
   /* config */
   AccelConfig = TRUE,
   MenuConfig = TRUE,
   StatusBarConfig = FALSE,
   ToolBoxConfig = TRUE,
   GroupId = GID_APPLICATION;

]

SfxBoolItem DesignerDialog SID_STYLE_DESIGNER

[

   /* flags: */
   AutoUpdate = TRUE,
   Cachable = Cachable,
   FastCall = TRUE,
   HasCoreId = FALSE,
   HasDialog = FALSE,
   ReadyOnlyDoc = FALSE,
   Toggle = FALSE,
   Container = FALSE,
   RecordAbsolute = FALSE,
   RecordPerSet;
   Synchron;
   Readyonly = FALSE,
   /* config */
   AccelConfig = TRUE,
   MenuConfig = TRUE,
   StatusBarConfig = FALSE,
   ToolBoxConfig = TRUE,
   GroupId = GID_FORMAT;

]

Items and UNO structs

Personal tools