Difference between revisions of "Drawing framework"

From Apache OpenOffice Wiki
Jump to: navigation, search
m (Added link to sdext module)
(Providing a New Resource)
 
(12 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
==Introduction==
 
==Introduction==
The drawing framework is a framework employed by the [[Impress]] and [[Draw]] applications for the synchronized activation and deactivation of resources.
+
The drawing framework is a framework used by [[Impress]] and [[Draw]] for the coordinated activation and deactivation of resources like views, panes, and tool bars.
  
The primary goal in designing the drawing framework is to turn Impress and Draw into modular applications that can easily be extended by additional features.
+
The primary goal in designing the drawing framework was to turn Impress and Draw into modular applications that can easily be extended by additional features.
This should be possible not only statically at compile time.  The drawing framework will be accessible to extensions that are deployed via the extension manager (menu entry Tools->ExtensionManager...).  This allows an extension to provide for instance a new view and to control when to show this view and in which pane to display it.  This can be done in any programming language for which there is UNO API support.  Extensions can be located in the [[sdext]] module.
+
This should be possible dynamically through extensions, not only statically at compile time.  The drawing framework is accessible to extensions that are deployed via the extension manager (menu entry Tools->ExtensionManager...).  This allows an extension to provide for instance a new view and to control when to show this view and in which pane to display it.  This can be done in any programming language for which there is UNO API support.  The [Presenter Screen|Presenter Screen extension] is one example for this.
  
 
The design of the drawing framework addresses the following goals:
 
The design of the drawing framework addresses the following goals:
Line 15: Line 15:
 
*abstraction from underlying frameworks
 
*abstraction from underlying frameworks
  
The drawing framework can be seen as a resource management system, where the resources are panes, views, tool bars, commands (slots).  Different types of resources are managed by individual resource controllers.  The resource controllers are synchronized by the configuration controller.  Its name comes from the configuration, which describes the set of active resources, i.e. the set of visible panes, views, and tool bars.  Synchronization means that activation or deactivation of resources of different types are made in a fashion that minimizes the overall time and reduces visual artifacts, i.e. flickering.
+
The drawing framework can be seen as a resource management system, where the resources are panes, views, tool bars, commands (slots).  The configuration controller synchronizes activation and deactivation of resourcesIt has its name from the configuration, which describes the set of active resources, i.e. the set of visible panes, views, and tool bars.  Synchronization means that when two or more resources are to be activated or deactivated at the same time then the configuration controller
 +
*orders activations and deactivations according to dependencies between resources (e.g. when a viewand a pane are to be activated then the pane is activated before the view so that the view has access to the pane),
 +
*tries to minimize the overall time and
 +
*reduces visual artifacts, i.e. flickering.
  
The drawing framework is implemented on top of and abstracts from existing framework functionality provides mostly by the SFX2 and Framework projects.
+
The drawing framework is implemented on top of and abstracts from existing framework functionality provides mostly by the SFX2 and [[Framework]] projects.
  
There is a [[Drawing Framework Glossary|glossary]] for the drawing framework.
+
There is a [[Drawing Framework Glossary|glossary]] for the drawing framework.  The API of the drawing framework is documented [http://api.openoffice.org/docs/common/ref/com/sun/star/drawing/framework/module-ix.html here].
  
 
==Current State==
 
==Current State==
The first part of the drawing framework is implemented in child work space ''components1''. It covers panes and views. Tool bars and commands will be addressed soon in following child work spaces.
+
With the experience from the implementation of the [[Presenter_Screen|Presenter Screen extension]] the first incarnation of the drawing framework (that is described by older versions of this page, see history for [http://wiki.services.openoffice.org/w/index.php?title=Drawing_framework&oldid=45696 this] or older versions) has been cleaned up and simplified into its current form.
 
+
TODO: Add proper links to the interfaces of the API when the components1 child work space is integrated.
+
  
 +
The drawing framework is used by [[Impress]] and [[Draw]] for managing views, panes, and one or two toolbars.
  
  
Line 31: Line 33:
  
 
The following sections describe the inner structure of the drawing framework in more detail.
 
The following sections describe the inner structure of the drawing framework in more detail.
It starts with the set of supported resources, the ResourceIds to identify resources, and configurations to describe the set of active or requested resources.
+
It starts with the set of supported resources, the ResourceIds that identify resources, and configurations that describe the set of active or requested resources.
This is followed by the layout of the controllers that operate on the resources.
+
Last comes a description of the update process that involves the actual activation and deactivation of resources.
Last comes a description of the update process that starts when the application requests the activation or deactivation of a resource.
+
  
 
===Resources===
 
===Resources===
  
The drawing framework supports four types of resources:
+
The drawing framework has been desinged for four types of resources:
  
 
* Panes
 
* Panes
Line 49: Line 50:
 
While the first three need little explanation (the little explanation is done in the API documentation) the concept of [[Drawing Framework Glossary#Command Groups|command groups]] is not used (yet) anywhere else.  A command group is a collection of commands realized by a module that implements at least the com::sun::star::frame::XDispatch interface and implements one or more commands (that to some are known as slots).
 
While the first three need little explanation (the little explanation is done in the API documentation) the concept of [[Drawing Framework Glossary#Command Groups|command groups]] is not used (yet) anywhere else.  A command group is a collection of commands realized by a module that implements at least the com::sun::star::frame::XDispatch interface and implements one or more commands (that to some are known as slots).
  
A resource is identified by a non-empty set of URLs.  One is called the resource URL and defines the type of the resource.  A possibly empty set of anchor URLs specifies a set of resources to which the one in question is anchored.  An example will hopefully make this clear:
+
A resource is identified by a non-empty set of URLs that describe the actual resource and its dependency on other resources.  One URL is called the resource URL and defines the type of the resource.  A possibly empty set of anchor URLs specifies a set of resources to which the one in question is anchored.  Panes for example act as containers for views and thus are their anchors: the resource URL of the left slide sorter in the left pane is <pre>private:resource/view/SlideSorter</pre>.  Its anchor is the left pane with the URL being <pre>private:resource/floater/LeftImpressPane</pre>.
 
+
The resource URL of the left slide sorter in the left pane is <pre>private:resource/view/SlideSorter</pre>.  The left pane is the anchor, its URL is <pre>private:resource/floater/LeftImpressPane</pre>.
+
  
 
Here, the first part after private:resource/ specifies the type of resource:
 
Here, the first part after private:resource/ specifies the type of resource:
* '''floater''' for panes
+
* '''pane''' for panes
 
* '''view''' for views
 
* '''view''' for views
 
* '''toolbar''' for tool bars
 
* '''toolbar''' for tool bars
Line 61: Line 60:
  
 
===ResourceId===
 
===ResourceId===
Each resource is identified by an object that implements the com::sun::star::drawing::framework::ResourceId service with its com::sun::star::drawing::framework::XResourceId interface.  The XResourceId interface gives access to a set of URLs which specify the resource.  There is one URL returned by the getResourceURL() function that defines the type of the resource.  A possibly empty set of URLs returned by getAnchorURLs() specifies the anchor resource.
+
Each resource is identified by an object that implements the
 +
[http://api.openoffice.org/docs/common/ref/com/sun/star/drawing/framework/ResourceId.html com::sun::star::drawing::framework::ResourceId] service with its [http://api.openoffice.org/docs/common/ref/com/sun/star/drawing/framework/XResourceId.html com::sun::star::drawing::framework::XResourceId] interface.  The XResourceId interface gives access to a set of URLs which specify the resource.  There is one URL returned by the getResourceURL() function that defines the type of the resource.  A possibly empty set of URLs returned by getAnchorURLs() specifies the anchor resource.
  
 
Each resource in a configuration has to have a unique resource id.  Two resource ids may have the same resource URLs but then their anchors must not be the same.  An example for this would be the slide sorter being shown in two different panes.  Alternatively two resource may have the same anchor but then must not have the same resource URL.  An example for this is the view tab bar and the view in the center pane.  The anchor of both is the center pane.
 
Each resource in a configuration has to have a unique resource id.  Two resource ids may have the same resource URLs but then their anchors must not be the same.  An example for this would be the slide sorter being shown in two different panes.  Alternatively two resource may have the same anchor but then must not have the same resource URL.  An example for this is the view tab bar and the view in the center pane.  The anchor of both is the center pane.
Line 68: Line 68:
 
<pre>private:resource/floater/LeftImpressPane, private:resource/view/SlideSorter</pre>
 
<pre>private:resource/floater/LeftImpressPane, private:resource/view/SlideSorter</pre>
 
The slide sorter view in the center pane id described by the ResourceId
 
The slide sorter view in the center pane id described by the ResourceId
<pre>private:resource/floater/CenterPane, private:resource/view/SlideSorter</pre>
+
<pre>private:resource/pane/CenterPane, private:resource/view/SlideSorter</pre>
  
 
Panes are the typical anchor resources.  They do not have an anchor, therefore getAnchorURLs() returns an empty list for them.  An example for an anchor that is not a pane is the view tab bar.  It is linked to the center pane.  It is the anchor for its tabs that each represent one view that may by displayed in the center pane.  The resource ids of the two left most tabs are for example
 
Panes are the typical anchor resources.  They do not have an anchor, therefore getAnchorURLs() returns an empty list for them.  An example for an anchor that is not a pane is the view tab bar.  It is linked to the center pane.  It is the anchor for its tabs that each represent one view that may by displayed in the center pane.  The resource ids of the two left most tabs are for example
<pre>private:resource/floater/CenterPane, private:resource/toolbar/ViewTabBar, private:resource/view/ImpressView
+
<pre>private:resource/pane/CenterPane, private:resource/toolbar/ViewTabBar, private:resource/view/ImpressView
private:resource/floater/CenterPane, private:resource/toolbar/ViewTabBar, private:resource/view/OutlineView</pre>
+
private:resource/pane/CenterPane, private:resource/toolbar/ViewTabBar, private:resource/view/OutlineView</pre>
  
 
The ResourceId service provides four functions for creating ResourceId objects.  These are createEmpty() and create() for creating an empty resource id and one that has no anchor.  The createWithAnchor() variant creates a resource whose anchor is given as ResourceId object.  When the later is empty then the resulting resource could have been created with create().  Finally createWithAnchorURL takes two URLs, one for the actual resource and one for its anchor.  These four variants cover the most common usages but it may be extended in the future (note drawing framework API is not yet marked as published and may be modified.)
 
The ResourceId service provides four functions for creating ResourceId objects.  These are createEmpty() and create() for creating an empty resource id and one that has no anchor.  The createWithAnchor() variant creates a resource whose anchor is given as ResourceId object.  When the later is empty then the resulting resource could have been created with create().  Finally createWithAnchorURL takes two URLs, one for the actual resource and one for its anchor.  These four variants cover the most common usages but it may be extended in the future (note drawing framework API is not yet marked as published and may be modified.)
  
 +
===Known Resources===
 +
A list of known resources can be found [[Drawing Framework Resources|here]].
  
 
===Configuration===
 
===Configuration===
Line 106: Line 108:
 
===Three layer design===
 
===Three layer design===
  
The drawing framework consists of a couple of controllers (not of the
+
The drawing framework consists of controllers, factories, and application
com::sun::star::frame::XController variety), factories, and application
+
 
logic modules.  These  are located on three layers.  The assignment to the
 
logic modules.  These  are located on three layers.  The assignment to the
 
different layers depends on the knowledge about different aspects of the
 
different layers depends on the knowledge about different aspects of the
Line 116: Line 117:
 
;Synchronization Layer:The [[Drawing Framework Glossary#Synchronization Layer|synchronization layer]] uses the XConfigurationController to '''synchronize''' the requests from the application layer with the resource controllers in the resource layer. It has no detailed knowledge about individual resources nor about the application logic.
 
;Synchronization Layer:The [[Drawing Framework Glossary#Synchronization Layer|synchronization layer]] uses the XConfigurationController to '''synchronize''' the requests from the application layer with the resource controllers in the resource layer. It has no detailed knowledge about individual resources nor about the application logic.
  
;Resource Layer:The resource controllers and factories in the [[Drawing Framework Glossary#Resource Layer|resource layer]] know '''how''' to activate or deactivate resources.  The XResourceControllers are called by the XConfigurationController to update the the current configuration so that it looks like the requested configuration.
+
;Resource Layer:The resource factories in the [[Drawing Framework Glossary#Resource Layer|resource layer]] know '''how''' to activate or deactivate resources.  The XResourceControllers are called by the XConfigurationController to update the the current configuration so that it looks like the requested configuration.
  
 
[[image:DrawingFrameworkDesign.png|The different parts of the drawing framework are organized in three layers]]
 
[[image:DrawingFrameworkDesign.png|The different parts of the drawing framework are organized in three layers]]
  
The image illustrates the three layer design for the Impress application.  The ImpressModule is created by the ImpressViewShell when the user creates a new Impress document.  The ImpressModule creates the other modules in the application layer.  They watch for user input and are responsible for switching views in ther center pane and for showing or hiding the side panes and the views therein.
+
The image illustrates the three layer design for the Impress application.  The ImpressModule is created by the ImpressViewShell when the user creates a new Impress document.  The ImpressModule creates the other modules in the application layer that control different aspect of the applicationFor example they watch for user input and switch to different views in ther center pane accordingly.
  
 
The modules in the application layer communicate with the XConfgurationController in the synchronization layer to make requests for the activation or deactivation of panes and views.  The XConfigurationController modifies the RequestedConfiguration accordingly.  
 
The modules in the application layer communicate with the XConfgurationController in the synchronization layer to make requests for the activation or deactivation of panes and views.  The XConfigurationController modifies the RequestedConfiguration accordingly.  
  
Eventually the CurrentConfiguration is updated.  The XConfigurationController asks the resource controllers in the resource layer to activate or deactivate the resources that are controlled by themWhen for instance the slide sorter bar is to be hidden then first the ViewController is asked to deactivate the SlideSorterView and then the PaneController is asked to deactivate the left pane.   
+
Eventually the CurrentConfiguration is updated.  The XConfigurationController then determines the order in which to activate and deactivate resources and calls the resource factories in that order to create resources that are activated or to release resources that are deactivated.
The resource controllers use their resource factories for the actual activation or deactivation.
+
 
 +
Resource factories can implement a cache to store deactivated resourcesSome resources like the slide sorter bar are activated and deactivated frequentlyCaching it may speed this up.
  
Resource factories can implement a cache to store deactivated resources.  For example it is quite likely that the slide sorter bar will later be activated again.  This can be done faster when it is not deleted but only hidden.
 
  
 
===Two phase updates===
 
===Two phase updates===
  
 
The drawing framework negotiates between modules implementing application
 
The drawing framework negotiates between modules implementing application
logic that wants to show or hide a resource on one side and the resource
+
logic that want to show or hide a resource on one side and the resource
providers on the other side.  The negotiation process is iterative: the
+
factories on the other side.  The negotiation process is iterative: the
 
activation request of a resource made by one application logic module may
 
activation request of a resource made by one application logic module may
 
cause the activation request of another resource made by a second module.
 
cause the activation request of another resource made by a second module.
Line 140: Line 141:
  
 
The negation process is split into two phases, one
 
The negation process is split into two phases, one
for the actual negotiation of the requested changes and the other for
+
for collecting a list of all the necessary changes and the second for
 
updating the GUI to reflect these changes.
 
updating the GUI to reflect these changes.
  
;Negotiation Phase: The negotiation phase is triggered by the initial request, for example the switch of the view in the center pane.  In this phase only the the requested configuration is modified.  The requested change is stored in the requested configuration and then is broadcasted.  Listeners may react by making further requests for the activation or deactivation of other resources.  These are again broadcasted and may lead to even more requests.  All requests are put into a queue which is processed until there are no more pending requests.
+
;Negotiation Phase: The negotiation phase is triggered by the initial request, for example the switch of the view in the center pane.  In this phase only the requested configuration is modified.  The requested change is stored in the requested configuration and then is broadcasted.  Listeners may react by making further requests for activation or deactivation of other resources.  These are again stored in the requested configuration and broadcasted and may lead to even more requests.  All requests are put into a queue which is processed until there are no more pending requests.
  
;Update Phase:When all requests have been processed and the the requested configuration describes a new consistent state of the GUI then the second, the '''update phase''' is started.  In this phase only the current configuration is modified.
+
;Update Phase:When all requests have been processed and the requested configuration describes a new consistent state of the GUI then the second, the '''update phase''' is started.  In this phase only the current configuration is modified.
 
:That is, the requested configuration is not modified directly in this phase.  The application can of course request the activation or deactivation of resources.  Therefore, in the update phase a copy of the requested configuration is used which remains unchanged during the update.
 
:That is, the requested configuration is not modified directly in this phase.  The application can of course request the activation or deactivation of resources.  Therefore, in the update phase a copy of the requested configuration is used which remains unchanged during the update.
:The different resource controllers are asked to activate or deactivate resources so that eventually the current configuration looks like the requested configuration.  Every activation and deactivation is broadcasted like the requests for the activations and deactivations where.
+
:The different resource factories are asked to create or relase resources so that eventually the current configuration looks like the requested configuration.  Every activation and deactivation is broadcasted like the requests for the activations and deactivations were.
 
+
It is the task of the configuration controller to optimize the the update
+
phase with respect to time and visual artifacts, flickering.  It does that
+
by acquiring the relevant locks and by calling the resource controllers in
+
the right order.
+
 
+
  
 +
It is the task of the configuration controller to order the activations and deactivations according to dependencies between affected resources and to optimize the update
 +
phase with respect to time and visual artifacts/flickering.
  
 
==Extensibility==
 
==Extensibility==
The drawing framework is designed to be extensible with regard to both the set of known resources as well as the set of supported ''types'' of resources.
+
The drawing framework is designed to be extensible with regard to the set of known resources and to the application logic.
  
For a new resource you have to provide a factory and register it at the responsible resource manager.  An example could be a new view or a new tool bar.
+
For a new resource you have to provide a factory and register it at the configuration manager.  An example could be a new view or a new tool bar.
 
+
For a new type of resource you have to provide a resource controller and register it at the controller manager.  An exmaple for a new type of resource could be the entries of the view tab bar.
+
 
+
The drawing framework uses the ModuleController to handle different modules of the core implementation and of extensions.  However, the drawing framework is not in its final form with respect to extensions.
+
  
 +
For a new piece of application logic add a listener to the configuration controller and react to activations or deactivations of relevant resources.
  
  
 
==Implementation and Examples==
 
==Implementation and Examples==
Examples for the use of the drawing framework have their own page: the [[Drawing Framework Examples]].
+
The examples in the following sections show how to use the drawing framework to request and access resources and how to react to changes of the current configuration.  Note that the code is C++ like pseudo code that can not be compiled as is.
  
 
===FrameworkHelper===
 
===FrameworkHelper===
 
The ::sd::framework::FrameworkHelper class provides two things
 
The ::sd::framework::FrameworkHelper class provides two things
* the most frequently used resource URLs so that you do not have to remember them or have trouble with resource allocation,
+
* the most frequently used resource URLs so that you do not have to remember them, have trouble with resource allocation, or be able to misspell resource names, and
* and some helper functions to work with the UNO based drawing framework from inside core code.
+
* some helper functions that simplify the work with the UNO based drawing framework from inside core code.
 
The FrameworkHelper is a multi singleton.  Its Instance() method returns for a ViewShellBase object the associated FrameworkHelper object.  The functions provided cover
 
The FrameworkHelper is a multi singleton.  Its Instance() method returns for a ViewShellBase object the associated FrameworkHelper object.  The functions provided cover
 
* mapping between sd::ViewShell::ShellType and view resource URL,
 
* mapping between sd::ViewShell::ShellType and view resource URL,
Line 182: Line 176:
  
 
One example for that is a request for the activation of the slide sorter bar:
 
One example for that is a request for the activation of the slide sorter bar:
<pre>
+
<source lang="cpp">
 
FrameworkHelper::Instance(GetViewShellBase()).RequestView(
 
FrameworkHelper::Instance(GetViewShellBase()).RequestView(
 
     ResourceId::createWithAnchorURL(
 
     ResourceId::createWithAnchorURL(
Line 188: Line 182:
 
         FrameworkHelper::msSlideSorterURL,
 
         FrameworkHelper::msSlideSorterURL,
 
         FrameworkHelper::msLeftImpressPaneURL));
 
         FrameworkHelper::msLeftImpressPaneURL));
</pre>
+
</source>
 
+
  
 
===Drawing Framework API===
 
===Drawing Framework API===
Line 195: Line 188:
  
 
====Getting Access to the Drawing Framework====
 
====Getting Access to the Drawing Framework====
Using the UNO API of the drawing framework to access active resources or to request the activation or deactivation of resources starts with the [http://api.openoffice.org/docs/common/ref/com/sun/star/frame/XController.html XController].  From this you can obtain the XControllerManager and from this the XConfigurationController.  The XControllerManager is the hub from where you have access to all sub controllers of the drawing framework, the XConfigurationController is ususally the main access point for making requests and for accessing resources.  
+
Using the UNO API of the drawing framework to access active resources or to request the activation or deactivation of resources starts with the [http://api.openoffice.org/docs/common/ref/com/sun/star/frame/XController.html XController] of an [[Impress]] or a [[Draw]] document.  From this you can obtain the [http://api.openoffice.org/docs/common/ref/com/sun/star/drawing/framework/XControllerManager.html XControllerManager] and from that the [http://api.openoffice.org/docs/common/ref/com/sun/star/drawing/framework/XConfigurationController.html XConfigurationController].  The XConfigurationController is the main access point for making requests and for accessing resources.  
<pre>
+
<source lang="cpp">
 
using ::com::sun::star::uno;
 
using ::com::sun::star::uno;
 
using ::com::sun::star::frame;
 
using ::com::sun::star::frame;
 
using ::com::sun::star::drawing::framework;
 
using ::com::sun::star::drawing::framework;
  
Reference<XController> xController;  // This is regarded as given.
+
Reference<XController> xController;              // This is regarded as given.
 +
Reference<XComponentContext> xComponentContext;  // This also is regarded as given.
  
 
Reference<XControllerManager> xCM (xController, UNO_QUERY_THROW);
 
Reference<XControllerManager> xCM (xController, UNO_QUERY_THROW);
 
Reference<XConfigurationController> xCC (xCM->getConfigurationController());
 
Reference<XConfigurationController> xCC (xCM->getConfigurationController());
</pre>
+
</source>
  
 
====Requesting a Resource Activation====
 
====Requesting a Resource Activation====
The XConfigurationController is the
+
Once you have obtained access to the XConfigurationController, making requests to activate or deactivate resources is simple.  The following code requests the activation of the slide sorter bar:
center piece of the drawing framework.  For the most common tasks you will
+
<source lang="cpp">
not need to go deeper into the framework.  The following code requests the
+
activation of the slide sorter bar:
+
<pre>
+
 
xCC->requestResourceActivation(
 
xCC->requestResourceActivation(
 
     ResourceId::createWithAnchorURL(
 
     ResourceId::createWithAnchorURL(
         aComponentContext,
+
         xComponentContext,
 
         FrameworkHelper::msSlideSorterURL,
 
         FrameworkHelper::msSlideSorterURL,
 
         FrameworkHelper::msLeftImpressPaneURL));
 
         FrameworkHelper::msLeftImpressPaneURL));
</pre>
+
</source>
 
If you compare this to the code bove that uses the FrameworkHelper to accomplish
 
If you compare this to the code bove that uses the FrameworkHelper to accomplish
 
the same thing then you see, that the FrameworkHelper only hides the
 
the same thing then you see, that the FrameworkHelper only hides the
Line 227: Line 218:
 
layer (that is the task of the modules in the application layer) so the pane
 
layer (that is the task of the modules in the application layer) so the pane
 
in which to show the slide sorter has to be requested as well.
 
in which to show the slide sorter has to be requested as well.
<pre>
+
<source lang="cpp">
 
xCC->requestResourceActivation(
 
xCC->requestResourceActivation(
 
     ResourceId::create(
 
     ResourceId::create(
         aComponentContext,
+
         xComponentContext,
 
         FrameworkHelper::msLeftImpressPaneURL));
 
         FrameworkHelper::msLeftImpressPaneURL));
</pre>
+
</source>
Note the use of OUString(). This is because a pane, in contrast to the view that was requested earlier, is not bound to any other resource.  Therefore the AnchorURL remains empty.
+
Note the use of ResourceId::create() instead of ResourceId::createWithAnchorURL(). This is because a pane, in contrast to the view that was requested earlier, is not bound to any other resource.
  
 
The two requests should be executed together.  An intermediate update of the
 
The two requests should be executed together.  An intermediate update of the
Line 244: Line 235:
 
inner class to do that.  Adding this and bringing the two requests into the
 
inner class to do that.  Adding this and bringing the two requests into the
 
logical order you get
 
logical order you get
<pre>
+
<source lang="cpp">
 
{
 
{
 
     ::sd::framework::ConfigurationController::Lock(xCC);
 
     ::sd::framework::ConfigurationController::Lock(xCC);
Line 257: Line 248:
 
             FrameworkHelper::msLeftImpressPaneURL));
 
             FrameworkHelper::msLeftImpressPaneURL));
 
}
 
}
</pre>
+
</source>
  
 
====Accessing a Resource====
 
====Accessing a Resource====
 
If you want to access an active resource directly then you have to ask the
 
If you want to access an active resource directly then you have to ask the
responsible resource controller for it (this may be simplified in the
+
XConfigurationController for it.  Suppose you are interested in accessing the window of the left
future.) Suppose you are interested in accessing the window of the left
+
 
pane that shows the slide sorter bar:
 
pane that shows the slide sorter bar:
<pre>
+
<source lang="cpp">
Reference<XPaneController> xPM (xCM->getPaneController());
+
Reference<XPane> xPane (xCC->getResource(
Reference<XPane> xPane (xPM->getPane(
+
 
     ResourceId::create(
 
     ResourceId::create(
 
         aComponentContext,
 
         aComponentContext,
         FrameworkHelper::msLeftImpressPaneURL));
+
         FrameworkHelper::msLeftImpressPaneURL),
 +
    UNO_QUERY);
 
if (xPane.is())
 
if (xPane.is())
 
{
 
{
Line 278: Line 268:
 
     }
 
     }
 
}
 
}
</pre>
+
</source>
 
+
  
 
====Reacting to Modifications of the Configuration====
 
====Reacting to Modifications of the Configuration====
The following code turns on the slide sorter bar when the center pane shows
+
When you want to implement application logic then you have to react to user input by requesting changes to the current configuration.  User input can come in many ways.  Here we cover only the indirect way of (requested) changes of the current configuration made by others.
the edit view, outline view, or notes view and turns it off when the handout
+
 
view or the slide sorter view is shown.  The drawing framework contains a
+
The following code turns on the slide sorter bar when the center pane is switched to
module in the application layer that does essentially the same.
+
the edit view, outline view, or notes view and turns it off for all other views.  The drawing framework contains a module in the application layer that does essentially the same.
<pre>
+
<source lang="cpp">
class SlideSorterBarManager : public XConfigurationChangeListener {
+
class SlideSorterBarManager : public XConfigurationChangeListener
 +
{
 
public:
 
public:
 
Reference<XConfigurationController> mxCC;
 
Reference<XConfigurationController> mxCC;
Line 337: Line 327:
 
         }
 
         }
 
     }
 
     }
 +
}
 +
 
};
 
};
</pre>
+
</source>
 
There are three things to note in this code:
 
There are three things to note in this code:
 
# The first '''if''' statement in the notifyConfigurationChange() method is not really necessary because the listener is registered only for this one event type and thus will not be called for other event types.
 
# The first '''if''' statement in the notifyConfigurationChange() method is not really necessary because the listener is registered only for this one event type and thus will not be called for other event types.
 
# There is no update lock surrounding the activation requests for the slide sorter bar.  This is not necessary  here, because the listener is only called during the negotiation phase.  During this whole phase the update is locked.
 
# There is no update lock surrounding the activation requests for the slide sorter bar.  This is not necessary  here, because the listener is only called during the negotiation phase.  During this whole phase the update is locked.
# There is only one deactivation requests, the one for the view.  The request for the pane is missing.  This is because there might be other resources bound to the pane.  However, this is one of a few places where an automatism is active: when there are not resources bound to a pane when the negotiation phase ends, then the pane is deactivated.
+
# There is only one deactivation request, the one for the view.  The request for the pane is missing.  This is because there might be other resources bound to the pane.  However, this is one of a few places where an automatism is active: when there are no resources bound to a pane when the negotiation phase ends, then the pane is deactivated.
 
+
  
 
====Providing a New Resource====
 
====Providing a New Resource====
To provide a new resource, say a SingleColorView that paints a window with a
+
To provide a new resource, say a SingleColorView that fills a window with a
 
single color, you have to
 
single color, you have to
 
*Provide the actual view
 
*Provide the actual view
Line 353: Line 344:
 
*Request the new view
 
*Request the new view
  
A view has to support the css::drawing::framework::XView interface which is
+
A view has to support the [http://api.openoffice.org/docs/common/ref/com/sun/star/drawing/framework/XView.html css::drawing::framework::XView] interface which is
 
derived from the XResource interface.  Both interfaces are extremely simple
 
derived from the XResource interface.  Both interfaces are extremely simple
 
because the drawing framework does not need to know much about its
 
because the drawing framework does not need to know much about its
resources.  The XResource interface has just one method, the XView interface
+
resources.
is even simpler; it has no method at all.
+
  
 
The knowledge is concentrated only in the factory and of course in the
 
The knowledge is concentrated only in the factory and of course in the
implementation of the resource.  Both the resource and its factory are
+
implementation of the new view.  Both a new resource and its factory are
 
typically deployed together so they can use private and implementation
 
typically deployed together so they can use private and implementation
language dependent means to communicate and share information.
+
language dependent means to communicate with each other and share information.
  
 
The factory is given a ResourceId when asked for a new resource object.  For
 
The factory is given a ResourceId when asked for a new resource object.  For
Line 370: Line 360:
 
to the VCL Window pointer, but that is not used here.
 
to the VCL Window pointer, but that is not used here.
  
<pre>
+
<source lang="cpp">
class SingleColorViewFactory : XViewFactory
+
class SingleColorViewFactory : XResourceFactory
 
{
 
{
 
public:
 
public:
     virtual Reference<XView> createView (
+
     virtual Reference<XView> createResource (
         const Reference<XResourceId>& rxViewId,
+
         const Reference<XResourceId>& rxViewId)
        const Reference<frame::XController>& rxController)
+
 
     {
 
     {
         Reference<XView> xView;
+
         Reference<XResource> xView;
  
 
         // Get the XWindow object fort the AnchorURL of the given ResourceId.
 
         // Get the XWindow object fort the AnchorURL of the given ResourceId.
 
         Reference<XControllerManager> xCM (xController, UNO_QUERY_THROW);
 
         Reference<XControllerManager> xCM (xController, UNO_QUERY_THROW);
         Reference<XPaneController> xPM (xCM->getPaneController());
+
         Reference<XConfigurationController> xCC (xCM->getConfigurationController());
         Reference<XPane> xPane (xPM->getPane(rxViewId->getAnchor()));
+
         Reference<XPane> xPane (xCC->getResource(rxViewId->getAnchor()), UNO_QUERY);
 
         if (xPane.is())
 
         if (xPane.is())
 
         {
 
         {
             // Create the view for the XWIndow object.
+
             // Create the view for the XWindow object.
 
             Reference<XWindow> xWindow (xPane->getWindow());
 
             Reference<XWindow> xWindow (xPane->getWindow());
 
             if (xWindow.is())
 
             if (xWindow.is())
Line 396: Line 385:
  
 
     virtual void releaseView (
 
     virtual void releaseView (
         const Reference<XView>& rxView)
+
         const Reference<XResource>& rxView)
 
     {
 
     {
 
         // Do nothing.  When the caller releases its reference to the view,
 
         // Do nothing.  When the caller releases its reference to the view,
Line 402: Line 391:
 
     }
 
     }
 
};
 
};
</pre>
+
</source>
<pre>
+
<source lang="cpp">
 
class SingleColorView : drawing::framework::XView, awt::XPaintListener
 
class SingleColorView : drawing::framework::XView, awt::XPaintListener
 
{
 
{
Line 428: Line 417:
 
     Reference<XResourceId> mxViewId;
 
     Reference<XResourceId> mxViewId;
 
};
 
};
</pre>
+
</source>
 
The factory can be registered in two ways.
 
The factory can be registered in two ways.
 
#Dynamically by calling XViewController::addViewFactory()
 
#Dynamically by calling XViewController::addViewFactory()
Line 435: Line 424:
 
For the latter you have to provide a UNO service for the view factory, say com.sun.star.drawing.framework.SingleColorViewFactory.  With
 
For the latter you have to provide a UNO service for the view factory, say com.sun.star.drawing.framework.SingleColorViewFactory.  With
 
this, merge the following entry into the Impress.xcu file.
 
this, merge the following entry into the Impress.xcu file.
<pre>
+
<source lang="xml">
 
<node oor:name="MultiPaneGUI">
 
<node oor:name="MultiPaneGUI">
 
   <node oor:name="Framework">
 
   <node oor:name="Framework">
 
     <node oor:name="ResourceFactories">
 
     <node oor:name="ResourceFactories">
       <node oor:name="F0" oor:op="replace">
+
       <node oor:name="org.openoffice.drawing.framework.ExampleFactory" oor:op="replace">
 
         <prop oor:name="ServiceName">
 
         <prop oor:name="ServiceName">
 
           <value>com.sun.star.drawing.framework.SingleColorViewFactory</value>
 
           <value>com.sun.star.drawing.framework.SingleColorViewFactory</value>
Line 454: Line 443:
 
   </node>
 
   </node>
 
</node>
 
</node>
</pre>
+
</source>
 +
 
 +
Note: It is recommended to use a name for the resource factory configuration which is likely to be unique, for instance by employing the usual "org.*" or "vnd.*" scheme. If you choose a name too generic, it might conflict with existing node names, overriding other factories, causing them to be completely unavailable. In the worst case, this will result in Draw/Impress being unusable.
 +
 
 
All what remains to be done is to request the view.  To show it in the right
 
All what remains to be done is to request the view.  To show it in the right
 
pane, instead of the task panel, make this call:
 
pane, instead of the task panel, make this call:
<pre>
+
<source lang="cpp">
 
xCC->requestResourceActivation(
 
xCC->requestResourceActivation(
 
     ResourceId::createWithAnchorURL(
 
     ResourceId::createWithAnchorURL(
         aComponentContext,
+
         xComponentContext,
 
         ::rtl::OUString::createFromAscii("private:resource/view/SingleColorView"),
 
         ::rtl::OUString::createFromAscii("private:resource/view/SingleColorView"),
         FameworkHelper::msRightPaneURL));
+
         FrameworkHelper::msRightPaneURL));
</pre>
+
</source>
  
 
[[Category:Impress]]
 
[[Category:Impress]]

Latest revision as of 13:50, 18 March 2010

Introduction

The drawing framework is a framework used by Impress and Draw for the coordinated activation and deactivation of resources like views, panes, and tool bars.

The primary goal in designing the drawing framework was to turn Impress and Draw into modular applications that can easily be extended by additional features. This should be possible dynamically through extensions, not only statically at compile time. The drawing framework is accessible to extensions that are deployed via the extension manager (menu entry Tools->ExtensionManager...). This allows an extension to provide for instance a new view and to control when to show this view and in which pane to display it. This can be done in any programming language for which there is UNO API support. The [Presenter Screen|Presenter Screen extension] is one example for this.

The design of the drawing framework addresses the following goals:

  • ease of use
  • flexibility
  • extensibility
  • abstraction from underlying frameworks

The drawing framework can be seen as a resource management system, where the resources are panes, views, tool bars, commands (slots). The configuration controller synchronizes activation and deactivation of resources. It has its name from the configuration, which describes the set of active resources, i.e. the set of visible panes, views, and tool bars. Synchronization means that when two or more resources are to be activated or deactivated at the same time then the configuration controller

  • orders activations and deactivations according to dependencies between resources (e.g. when a viewand a pane are to be activated then the pane is activated before the view so that the view has access to the pane),
  • tries to minimize the overall time and
  • reduces visual artifacts, i.e. flickering.

The drawing framework is implemented on top of and abstracts from existing framework functionality provides mostly by the SFX2 and Framework projects.

There is a glossary for the drawing framework. The API of the drawing framework is documented here.

Current State

With the experience from the implementation of the Presenter Screen extension the first incarnation of the drawing framework (that is described by older versions of this page, see history for this or older versions) has been cleaned up and simplified into its current form.

The drawing framework is used by Impress and Draw for managing views, panes, and one or two toolbars.


Framework Design

The following sections describe the inner structure of the drawing framework in more detail. It starts with the set of supported resources, the ResourceIds that identify resources, and configurations that describe the set of active or requested resources. Last comes a description of the update process that involves the actual activation and deactivation of resources.

Resources

The drawing framework has been desinged for four types of resources:

  • Panes
  • Views
  • Tool Bars
  • Command groups

While the first three need little explanation (the little explanation is done in the API documentation) the concept of command groups is not used (yet) anywhere else. A command group is a collection of commands realized by a module that implements at least the com::sun::star::frame::XDispatch interface and implements one or more commands (that to some are known as slots).

A resource is identified by a non-empty set of URLs that describe the actual resource and its dependency on other resources. One URL is called the resource URL and defines the type of the resource. A possibly empty set of anchor URLs specifies a set of resources to which the one in question is anchored. Panes for example act as containers for views and thus are their anchors: the resource URL of the left slide sorter in the left pane is
private:resource/view/SlideSorter
. Its anchor is the left pane with the URL being
private:resource/floater/LeftImpressPane
.

Here, the first part after private:resource/ specifies the type of resource:

  • pane for panes
  • view for views
  • toolbar for tool bars
  • command for command groups

The final part of the URL defines the actual resource.

ResourceId

Each resource is identified by an object that implements the com::sun::star::drawing::framework::ResourceId service with its com::sun::star::drawing::framework::XResourceId interface. The XResourceId interface gives access to a set of URLs which specify the resource. There is one URL returned by the getResourceURL() function that defines the type of the resource. A possibly empty set of URLs returned by getAnchorURLs() specifies the anchor resource.

Each resource in a configuration has to have a unique resource id. Two resource ids may have the same resource URLs but then their anchors must not be the same. An example for this would be the slide sorter being shown in two different panes. Alternatively two resource may have the same anchor but then must not have the same resource URL. An example for this is the view tab bar and the view in the center pane. The anchor of both is the center pane.

Lets take the slide sorter as an example for this. In the left pane, the slide sorter bar is described by the ResourceId

private:resource/floater/LeftImpressPane, private:resource/view/SlideSorter

The slide sorter view in the center pane id described by the ResourceId

private:resource/pane/CenterPane, private:resource/view/SlideSorter

Panes are the typical anchor resources. They do not have an anchor, therefore getAnchorURLs() returns an empty list for them. An example for an anchor that is not a pane is the view tab bar. It is linked to the center pane. It is the anchor for its tabs that each represent one view that may by displayed in the center pane. The resource ids of the two left most tabs are for example

private:resource/pane/CenterPane, private:resource/toolbar/ViewTabBar, private:resource/view/ImpressView
private:resource/pane/CenterPane, private:resource/toolbar/ViewTabBar, private:resource/view/OutlineView

The ResourceId service provides four functions for creating ResourceId objects. These are createEmpty() and create() for creating an empty resource id and one that has no anchor. The createWithAnchor() variant creates a resource whose anchor is given as ResourceId object. When the later is empty then the resulting resource could have been created with create(). Finally createWithAnchorURL takes two URLs, one for the actual resource and one for its anchor. These four variants cover the most common usages but it may be extended in the future (note drawing framework API is not yet marked as published and may be modified.)

Known Resources

A list of known resources can be found here.

Configuration

A configuration describes a set of resources. There are two important configurations, which ideally are identical:

  • The current configuration describes the set of currently active resources. The term active can mean different things for different types of resources. For panes, views, and tool bars it means that they are visible. For a command group it means that that group is ready to process incoming slot calls.
  • The requested configuration describes the set of resources that have been requested to be active either directly by the user or by the application in response to some user input.

Usually the two configurations differ only temporarily after a new request for the activation or deactivation of a resource has been made but not yet been processed. Eventually the current configuration is updated to reflect the requested configuration. There may, however, be circumstances, that do not allow a resource to be activated or (less likely) to be deactivated. One reason for this is that some resources are created asynchronously and become available only after a little time.

See the configuration glossary entry for examples.

It is possible obtain a copy of the requested configuration and restore it later. This allows to undo temporary changes. For example, the in-place slide show uses this feature to temporarily hide the side panes and to restore them when the show ends.


Three layer design

The drawing framework consists of controllers, factories, and application logic modules. These are located on three layers. The assignment to the different layers depends on the knowledge about different aspects of the resource management:

Application Layer
The application layer controls when to activate or deactivate a resource. This layer contains the application logic. For example the Impress application uses a module that is responsible for activating or deactivating the slide sorter bar depending on the view that is displayed in the center pane.
Synchronization Layer
The synchronization layer uses the XConfigurationController to synchronize the requests from the application layer with the resource controllers in the resource layer. It has no detailed knowledge about individual resources nor about the application logic.
Resource Layer
The resource factories in the resource layer know how to activate or deactivate resources. The XResourceControllers are called by the XConfigurationController to update the the current configuration so that it looks like the requested configuration.

The different parts of the drawing framework are organized in three layers

The image illustrates the three layer design for the Impress application. The ImpressModule is created by the ImpressViewShell when the user creates a new Impress document. The ImpressModule creates the other modules in the application layer that control different aspect of the application. For example they watch for user input and switch to different views in ther center pane accordingly.

The modules in the application layer communicate with the XConfgurationController in the synchronization layer to make requests for the activation or deactivation of panes and views. The XConfigurationController modifies the RequestedConfiguration accordingly.

Eventually the CurrentConfiguration is updated. The XConfigurationController then determines the order in which to activate and deactivate resources and calls the resource factories in that order to create resources that are activated or to release resources that are deactivated.

Resource factories can implement a cache to store deactivated resources. Some resources like the slide sorter bar are activated and deactivated frequently. Caching it may speed this up.


Two phase updates

The drawing framework negotiates between modules implementing application logic that want to show or hide a resource on one side and the resource factories on the other side. The negotiation process is iterative: the activation request of a resource made by one application logic module may cause the activation request of another resource made by a second module. For example, when the user switches the view in the center pane to the outline view, then the task pane is deactivated.

The negation process is split into two phases, one for collecting a list of all the necessary changes and the second for updating the GUI to reflect these changes.

Negotiation Phase
The negotiation phase is triggered by the initial request, for example the switch of the view in the center pane. In this phase only the requested configuration is modified. The requested change is stored in the requested configuration and then is broadcasted. Listeners may react by making further requests for activation or deactivation of other resources. These are again stored in the requested configuration and broadcasted and may lead to even more requests. All requests are put into a queue which is processed until there are no more pending requests.
Update Phase
When all requests have been processed and the requested configuration describes a new consistent state of the GUI then the second, the update phase is started. In this phase only the current configuration is modified.
That is, the requested configuration is not modified directly in this phase. The application can of course request the activation or deactivation of resources. Therefore, in the update phase a copy of the requested configuration is used which remains unchanged during the update.
The different resource factories are asked to create or relase resources so that eventually the current configuration looks like the requested configuration. Every activation and deactivation is broadcasted like the requests for the activations and deactivations were.

It is the task of the configuration controller to order the activations and deactivations according to dependencies between affected resources and to optimize the update phase with respect to time and visual artifacts/flickering.

Extensibility

The drawing framework is designed to be extensible with regard to the set of known resources and to the application logic.

For a new resource you have to provide a factory and register it at the configuration manager. An example could be a new view or a new tool bar.

For a new piece of application logic add a listener to the configuration controller and react to activations or deactivations of relevant resources.


Implementation and Examples

The examples in the following sections show how to use the drawing framework to request and access resources and how to react to changes of the current configuration. Note that the code is C++ like pseudo code that can not be compiled as is.

FrameworkHelper

The ::sd::framework::FrameworkHelper class provides two things

  • the most frequently used resource URLs so that you do not have to remember them, have trouble with resource allocation, or be able to misspell resource names, and
  • some helper functions that simplify the work with the UNO based drawing framework from inside core code.

The FrameworkHelper is a multi singleton. Its Instance() method returns for a ViewShellBase object the associated FrameworkHelper object. The functions provided cover

  • mapping between sd::ViewShell::ShellType and view resource URL,
  • obtain view objects for their URLs or ResourceIds,
  • making requests for the activation or deactivation of resources,
  • locking configuration updates,
  • waiting for certain events to make asynchronous requests synchronous.

One example for that is a request for the activation of the slide sorter bar:

FrameworkHelper::Instance(GetViewShellBase()).RequestView(
    ResourceId::createWithAnchorURL(
        aComponentContext,
        FrameworkHelper::msSlideSorterURL,
        FrameworkHelper::msLeftImpressPaneURL));

Drawing Framework API

The following subsections provide a short introduction of the UNO API of the drawing framework. For details please refer to the API documentation (not yet available.)

Getting Access to the Drawing Framework

Using the UNO API of the drawing framework to access active resources or to request the activation or deactivation of resources starts with the XController of an Impress or a Draw document. From this you can obtain the XControllerManager and from that the XConfigurationController. The XConfigurationController is the main access point for making requests and for accessing resources.

using ::com::sun::star::uno;
using ::com::sun::star::frame;
using ::com::sun::star::drawing::framework;
 
Reference<XController> xController;              // This is regarded as given.
Reference<XComponentContext> xComponentContext;  // This also is regarded as given.
 
Reference<XControllerManager> xCM (xController, UNO_QUERY_THROW);
Reference<XConfigurationController> xCC (xCM->getConfigurationController());

Requesting a Resource Activation

Once you have obtained access to the XConfigurationController, making requests to activate or deactivate resources is simple. The following code requests the activation of the slide sorter bar:

xCC->requestResourceActivation(
    ResourceId::createWithAnchorURL(
        xComponentContext,
        FrameworkHelper::msSlideSorterURL,
        FrameworkHelper::msLeftImpressPaneURL));

If you compare this to the code bove that uses the FrameworkHelper to accomplish the same thing then you see, that the FrameworkHelper only hides the connection from the ViewShellBase to the XConfigurationController. The rest of the call is basically the same.

However, the drawing framework does not provide too many automatisms on this layer (that is the task of the modules in the application layer) so the pane in which to show the slide sorter has to be requested as well.

xCC->requestResourceActivation(
    ResourceId::create(
        xComponentContext,
        FrameworkHelper::msLeftImpressPaneURL));

Note the use of ResourceId::create() instead of ResourceId::createWithAnchorURL(). This is because a pane, in contrast to the view that was requested earlier, is not bound to any other resource.

The two requests should be executed together. An intermediate update of the current configuration is not necessary and would lead to an annoying display of an empty window before the slide sorter bar is properly shown. The probability that this happens is low but not zero. Therefore it is good practice to lock the XConfigurationController while the two requests are made. This prevents unwanted updates. You can call the lock() and unlock() methods directly but it is safer to use the ConfigurationController::Lock inner class to do that. Adding this and bringing the two requests into the logical order you get

{
    ::sd::framework::ConfigurationController::Lock(xCC);
    xCC->requestResourceActivation(
        ResourceId::create(
            aComponentContext,
            FrameworkHelper::msLeftImpressPaneURL));
    xCC->requestResourceActivation(
        ResourceId::createWithAnchorURL(
            aComponentContext,
            FrameworkHelper::msSlideSorterURL,
            FrameworkHelper::msLeftImpressPaneURL));
}

Accessing a Resource

If you want to access an active resource directly then you have to ask the XConfigurationController for it. Suppose you are interested in accessing the window of the left pane that shows the slide sorter bar:

Reference<XPane> xPane (xCC->getResource(
    ResourceId::create(
        aComponentContext,
        FrameworkHelper::msLeftImpressPaneURL),
    UNO_QUERY);
if (xPane.is())
{
    Reference<XWindow> xWindow (xPane->getWindow());
    if (xWindow->is())
    {
        // Do something with the window.
    }
}

Reacting to Modifications of the Configuration

When you want to implement application logic then you have to react to user input by requesting changes to the current configuration. User input can come in many ways. Here we cover only the indirect way of (requested) changes of the current configuration made by others.

The following code turns on the slide sorter bar when the center pane is switched to the edit view, outline view, or notes view and turns it off for all other views. The drawing framework contains a module in the application layer that does essentially the same.

class SlideSorterBarManager : public XConfigurationChangeListener
{
public:
Reference<XConfigurationController> mxCC;
 
void SlideSorterBarManager (const Reference<XConfigurationController>& rxCC)
    : mxCC(rxCC)
{
    Reference<XConfigurationControllerBroadcaster> xCCB (mxCC, UNO_QUERY);
    xCCB->addConfigurationChangeListener(
        this,
        FramworkHelper::msResourceActivationRequestEvent,
        Any());
}
 
virtual void notifyConfigurationChange (const ConfigurationChangeEvent& rEvent)
{
    if (rEvent.Type.equals(FrameworkHelper::msResourceActivationRequestEvent))
    {
        if (rEvent.ResourceId.is())
         && rEvent.ResourceId->isBoundToURL(FrameworkHelper::msCenterPaneURL,DIRECT))
        {
            // A resource has been requested for the center pane.
            ::rtl::OUString sResourceURL (rEvent.ResourceId->getResourceURL());
            if (sResourceURL.equals(FrameworkHelper::msImpressViewURL)
             || sResourceURL.equals(FrameworkHelper::msOutlineViewURL)
             || sResourceURL.equals(FrameworkHelper::msNotesViewURL))
            {
                // Show the slide sorter bar.
                xCC->requestResourceActivation(
                    ResourceId::create(
                        aComponentContext,
                        FrameworkHelper::msLeftImpressPaneURL));
                xCC->requestResourceActivation(
                    ResourceId::createWithAnchorURL(
                        aComponentContext,
                        FrameworkHelper::msSlideSorterURL,
                        FrameworkHelper::msLeftImpressPaneURL));
            }
            else
            {
                // Hide the slide sorter bar for the handout view, the slide
                // sorter view, and all views that where not handled above.
                mxCC->requestResourceDeactivation(
                    ResourceId::createWithAnchorURL(
                        aComponentContext,
                        FrameworkHelper::msSlideSorterURL,
                        FrameworkHelper::msLeftImpressPaneURL));
            }
        }
    }
}
 
};

There are three things to note in this code:

  1. The first if statement in the notifyConfigurationChange() method is not really necessary because the listener is registered only for this one event type and thus will not be called for other event types.
  2. There is no update lock surrounding the activation requests for the slide sorter bar. This is not necessary here, because the listener is only called during the negotiation phase. During this whole phase the update is locked.
  3. There is only one deactivation request, the one for the view. The request for the pane is missing. This is because there might be other resources bound to the pane. However, this is one of a few places where an automatism is active: when there are no resources bound to a pane when the negotiation phase ends, then the pane is deactivated.

Providing a New Resource

To provide a new resource, say a SingleColorView that fills a window with a single color, you have to

  • Provide the actual view
  • Provide a factory that creates a view object for a given XPane object
  • Register the factory
  • Request the new view

A view has to support the css::drawing::framework::XView interface which is derived from the XResource interface. Both interfaces are extremely simple because the drawing framework does not need to know much about its resources.

The knowledge is concentrated only in the factory and of course in the implementation of the new view. Both a new resource and its factory are typically deployed together so they can use private and implementation language dependent means to communicate with each other and share information.

The factory is given a ResourceId when asked for a new resource object. For the SingleColorView the ResourceId is used to look up the corresponding XPane object from which the XWindow reference is obtained. For the standard panes the XPane object supports the XUnoTunnel interface which gives access to the VCL Window pointer, but that is not used here.

class SingleColorViewFactory : XResourceFactory
{
public:
    virtual Reference<XView> createResource (
        const Reference<XResourceId>& rxViewId)
    {
        Reference<XResource> xView;
 
        // Get the XWindow object fort the AnchorURL of the given ResourceId.
        Reference<XControllerManager> xCM (xController, UNO_QUERY_THROW);
        Reference<XConfigurationController> xCC (xCM->getConfigurationController());
        Reference<XPane> xPane (xCC->getResource(rxViewId->getAnchor()), UNO_QUERY);
        if (xPane.is())
        {
            // Create the view for the XWindow object.
            Reference<XWindow> xWindow (xPane->getWindow());
            if (xWindow.is())
                xView = new SingleColorView(rxViewId, xWindow);
        }
 
        return xView;
    }
 
    virtual void releaseView (
        const Reference<XResource>& rxView)
    {
        // Do nothing.  When the caller releases its reference to the view,
        // then the view will be destroyed.
    }
};
class SingleColorView : drawing::framework::XView, awt::XPaintListener
{
public:
    SingleColorView(
        const Reference<XResourceId>& rxViewId,
        const Reference<XWindow>& rxWindow)
        : mxViewId(rxViewId)
    {
        rxWindow->addPaintListener(this);
    }
 
    virtual ResourceId getResourceId (void)
    {
        return maId;
    }
 
    virtual void windowPaint (const awt::PaintEvent& rEvent)
    {
        // Paint the area specified by the event.
    }
 
private:
    Reference<XResourceId> mxViewId;
};

The factory can be registered in two ways.

  1. Dynamically by calling XViewController::addViewFactory()
  2. Statically by adding an entry to the configuration.

For the latter you have to provide a UNO service for the view factory, say com.sun.star.drawing.framework.SingleColorViewFactory. With this, merge the following entry into the Impress.xcu file.

<node oor:name="MultiPaneGUI">
  <node oor:name="Framework">
    <node oor:name="ResourceFactories">
      <node oor:name="org.openoffice.drawing.framework.ExampleFactory" oor:op="replace">
        <prop oor:name="ServiceName">
          <value>com.sun.star.drawing.framework.SingleColorViewFactory</value>
        </prop>
        <node oor:name="ResourceList">
          <node oor:name="R0" oor:op="replace">
            <prop oor:name="URL">
              <value>private:resource/view/SingleColorView</value>
            </prop>
          </node>
        </node>
      </node>
    </node>
  </node>
</node>

Note: It is recommended to use a name for the resource factory configuration which is likely to be unique, for instance by employing the usual "org.*" or "vnd.*" scheme. If you choose a name too generic, it might conflict with existing node names, overriding other factories, causing them to be completely unavailable. In the worst case, this will result in Draw/Impress being unusable.

All what remains to be done is to request the view. To show it in the right pane, instead of the task panel, make this call:

xCC->requestResourceActivation(
    ResourceId::createWithAnchorURL(
        xComponentContext,
        ::rtl::OUString::createFromAscii("private:resource/view/SingleColorView"),
        FrameworkHelper::msRightPaneURL));
Personal tools