Framework/Article/OpenOffice.org 2.0 User Interface Controller Internals

From Apache OpenOffice Wiki
Jump to: navigation, search

OpenOffice.org 2.0 User Interface Controller Internals

A typical OOo 2.0 document contains different user interface elements. They have to provide their functions to the user and display the current state of the document view.

If you want to know about the different controller type then you should read the controller tutorials available in the articles&tutorials chapter.

How and in which infrastructure do they work?

OpenOffice2UserInterfaceElements.png

The user interface elements are using controllers for each of their elements to bind them to the dynamic state of the application module. It's the responsibility of every user interface controller to call and to display the current state of its bound function.

OOo 2.0 uses the following user interface controllers:

  • Menubar
    • Popup menu controller
    • Generic menu item controller
    • Internal menu controller
  • Toolbar
    • Generic toolbar item controller
    • Specific toolbar item controller
  • Statusbar
    • Specific statusbar item controller

Menubar

Generic menu item controller

A normal menu item is controlled by a generic menu item controller. A menu bar of an application module uses for about 90% of its menu items generic item controllers. For example the Edit - Undo, Redo and Edit - Cut, Copy and Paste menu items are implemented using generic menu item controllers.

A generic menu item controller supports the following interfaces:

module com { module sun { module star { module frame {
published interface XStatusListener: com::sun::star::lang::XEventListener
{
  /** is called when the status of the feature changes.
    @param State
  provides information about changes of the requested feature */
 [oneway] void statusChanged( [in] FeatureStateEvent State );
};
}; }; }; };
module com { module sun { module star { module frame {
published struct FeatureStateEvent: com::sun::star::lang::EventObject
{
  //-------------------------------------------------------------------------
  /** contains the URL of the feature. */
  com::sun::star::util::URL FeatureURL;
 
  //-------------------------------------------------------------------------
  /** contains a descriptor of the feature for the user interface.*/
  string FeatureDescriptor;
 
  //-------------------------------------------------------------------------
  /** specifies whether the feature is currently enabled or disabled. */
  boolean IsEnabled;
 
  //-------------------------------------------------------------------------
  /** specifies whether the <type>XDispatch</type> has to be requeried. */
  boolean Requery;
 
  //-------------------------------------------------------------------------
  /** contains the state of the feature in this dispatch.*/
  any State;
};
}; }; }; };

It supports the following generic functions by listing to status updates provided by function statusChanged.

Variable

UNO Type/Poolitem

Action

State

String / SfxStringItem

Menu item changes its label to the content of the provided string.

State

Boolean / SfxBoolItem

Menu item checks or unchecks its menu item, according to the boolean value.

State

com.sun.star.frame.status.VisibilityItem / SfxVisibilityItem

Menu item will be made visible or invisible, according to the provided state.

IsEnabled

Boolean

Menu item is enabled or disabled according to the value of IsEnabled.


Internal menu controller

An Internal menu controllers is used for special menu items, like the window list (accessible via the Window popup menu). Internal menu controllers are completely responsible for their menu items. Currently there is no special menu controller which is implemented outside the framework library. There exists no UNO API to implement internal menu controllers.

Popup menu controller

A popup menu controller is a special menu controller which is responsible for a whole popup menu inside a menu bar. A popup menu controller must be a UNO service and registered in the configuration controller set, which can be found at org.openoffice.Office.UI.Controller/Registered/PopupMenu. The configuration set associates UNO service names implementing a popup menu controller with a command URL. The command URL is used by our XML based menu bar description. A popup menu controller is created by a popup menu controller factory which uses the configuration set to retrieve the correct service name and to initialize it.
An abstract from the org.openoffice.Office.UI.Controller/Registered/PopupMenu:

<!DOCTYPE oor:component-data SYSTEM "../../../../../component-update.dtd">
<oor:component-data oor:name="Controller" oor:package="org.openoffice.Office.UI" xmlns:oor="http://openoffice.org/2001/registry" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <node oor:name="Registered">
  <node oor:name="PopupMenu">
   <node oor:name="c1" oor:op="replace">
    <prop oor:name="Command">
     <value>.uno:CharFontName</value>
    </prop>
    <prop oor:name="Module">
     <value/>
    </prop>
    <prop oor:name="Controller">
     <value>com.sun.star.comp.framework.FontMenuController</value>
    </prop>
   </node>
   ...

A popup menu controller must support the following services / interfaces:

module com { module sun { module star { module frame {
 
service PopupMenuController
{
//-------------------------------------------------------------------------
/** supports functions to initialize and update a popup menu controller
    implementation.
 
    A popup menu controller implementation gets initialized with a
    com::sun::star::awt::XPopupMenu object. This assures
    that a popup menu controller can be implemented with any UNO based
    language.
*/
interface com::sun::star::frame::XPopupMenuController;
 
//-------------------------------------------------------------------------
/** provides functions to initialize a popup menu controller with
    specific data which are needed.
 
    This interface should not directly used. A factory service is responsible to
    initialize every controller correctly.
    popup menu controller needs at least two additional arguments
    provided as com::sun::star::beans::PropertyValue.
 
    Frame
    specifies the com::sun::star::frame::XFrame instance to which the 
    popup menu controller belongs to.
 
    CommandURL
    specifies which popup menu controller should be created.
 
    @see PopupMenuControllerFactory
*/
interface com::sun::star::lang::XInitialization;
 
//-------------------------------------------------------------------------
/** used to brief the popup menu controller with new status information.
    A popup menu controller makes special functions available to users which 
    normally depend on the state of other data. This interface is used to 
    send this data to a controller implementation.
*/
interface com::sun::star::frame::XStatusListener;
};
}; }; }; };
module com { module sun { module star { module frame {
 
interface XPopupMenuController : com::sun::star::uno::XInterface
{
    /** provides a com::sun::star::awt::XPopupMenu to a popup menu 
        controller implementation. The controller must fill this popup 
        menu with its functions.
 
        @param PopupMenu
        An empty popup menu that must be filled by the popup menu controller.
    */
    void setPopupMenu( [in] com::sun::star::awt::XPopupMenu PopupMenu );
 
    /** briefs the popup menu controller to update the contents of 
        the provided popup menu to reflect the current state. A 
        controller should never update the popup menu structure 
        on its own to prevent performance problems. A better way 
        would be that a controller registers itself as status listener 
        for a command URL and immediately deregister after that. 
        Therefore status updates will not be send regularly for a 
        non visible popup menu.
    */
    void updatePopupMenu();
};
 
}; }; }; };
module com { module sun { module star { module lang {
 
published interface XInitialization: com::sun::star::uno::XInterface
{
    // DocMerge from xml: method com::sun::star::lang::XInitialization::initialize
    /** initializes the object. 
        It should be called directly after the object has been created. 
     */
    void initialize( [in] sequence< any > aArguments ) raises( com::sun::star::uno::Exception );
};
 
}; }; }; };
module com { module sun { module star { module frame {
 
published interface XStatusListener: com::sun::star::lang::XEventListener
{
    /** is called when the status of the feature changes.
 
        @param State
        provides information about changes of the requested feature
     */
    [oneway] void statusChanged( [in] FeatureStateEvent State );
};
 
}; }; }; };
module com { module sun { module star { module frame {
 
published struct FeatureStateEvent: com::sun::star::lang::EventObject
{
    //-------------------------------------------------------------------------
    /** contains the URL of the feature.                                     */
    com::sun::star::util::URL FeatureURL;
 
    //-------------------------------------------------------------------------
    /** contains a descriptor of the feature for the user interface.         */
    string FeatureDescriptor;
 
    //-------------------------------------------------------------------------
    /** specifies whether the feature is currently enabled or disabled.      */
    boolean IsEnabled;
 
    //-------------------------------------------------------------------------
    /** specifies whether the XDispatch object has to be re-queried.         */
    boolean Requery;
 
    //-------------------------------------------------------------------------
    /** contains the state of the feature in this dispatch.                  */
    any State;
};
 
}; }; }; };

The framework project provides a base class to implement popup menu controller easier. It can be found in framework/inc/helper/popupmenucontrollerbase.hxx. There are several implementations for popup menu controller in framework/source/uielement which uses the base class and can be used as templates.

Currently OOo 2.0 provides the following popup menu controllers:

Command

Modules

Service

Purpose

.uno:CharFontName

all

com.sun.star.comp.framework.FontMenuController

Provides a popup menu with all supported fonts.

.uno:FontHeight

all

com.sun.star.comp.framework.FontSizeMenuController

Provides a popup menu with all supported font sizes.

.uno:ObjectMenue

all

com.sun.star.comp.framework.ObjectMenuController

Provides a popup menu with all supported commands of an embedded object.

.uno:InsertPageHeader

all

com.sun.star.comp.framework.HeaderMenuController

Provides a popup menu to insert pages headers.

.uno:InsertPageFooter

all

com.sun.star.comp.framework.FooterMenuController

Provides a popup menu to insert page footers.

.uno:ChangeControlType

all

com.sun.star.comp.framework.ControlMenuController

Provides a popup menu to change the control type of a selected form control.

.uno:AvailableToolbars

all

com.sun.star.comp.framework.ToolBarsMenuController

Provides a popup menu to show/hide toolbars.

.uno:ScriptOrganizer

all

com.sun.star.comp.framework.MacrosMenuController

Provides a popup menu with all available scripting languages.

.uno:RecentFileList

all

com.sun.star.comp.framework.RecentFilesMenuController

Provides a popup menu with recently opened files.

.uno:AddDirect

all

com.sun.star.comp.framework.NewMenuController

Provides a popup menu to create document for all available application modules.

.uno:AutoPilotMenu

all

com.sun.star.comp.framework.NewMenuController

Provides a popup menu with all available wizards.

The menu bar is completely controlled by an UNO implementations and is not based on any old sfx2 code. Therefor old sfx2 based and new non-sfx2 application modules are equally supported.

Toolbar

Toolbar item controller

Toolbar item controllers are responsible for a single toolbar button or toolbar item window (like a combobox, dropdown-box or an edit field). A toolbar item controller must support the following services and interfaces.



module com { module sun { module star { module frame {
 
service ToolbarController
{
    //-------------------------------------------------------------------------
    /** with this interface a component can receive events if a feature has 
        changed. 
 
        The toolbar controller implementation should register itself as a
        listener when its com::sun::star::util::XUpdatable interface has been called.
    */
    interface com::sun::star::frame::XStatusListener;
 
    //-------------------------------------------------------------------------
    /** used to initialize a component with required arguments.
 
        A toolbar controller needs at least three additional arguments provided as 
        com::sun::star::beans::PropertyValue 
 
        Frame 
        a com::sun::star::frame::XFrame instance to which the toolbar controller belongs.
 
        CommandURL
        a string which specifies the command a toolbar controller is bound.
 
        ServiceManager
        a com::sun::star::lang::XMultiServiceFactory instance which can be used to 
        create additional UNO services.
    */
    interface com::sun::star::lang::XInitialization;
 
    //-------------------------------------------------------------------------
    /** used to notify an implementation that it needs to add its listener or remove 
        and add them again.
 
        A toolbar controller instance is ready for use after this call has been made 
        the first time. The toolbar implementation guarantees that the controller's 
        item window has been added to the toolbar and its reference is held by it.
    */
    interface com::sun::star::util::XUpdatable;
 
    //-------------------------------------------------------------------------
    /** used to notify changed features and requests for additional user interface 
        items.
 
        Mostly used by a toolbar implementation to forward information to and request
        services from a toolbar controller component. This interface must be useable 
        after com::sun::star::lang::XInitialitation::initialize has been called. The 
        behavior of the interface is undefined if the controller component hasn't been 
        initialized.
    */
    interface com::sun::star::frame::XToolbarController;
 
    //-------------------------------------------------------------------------
    /** used to notify and retrieve information that are specific for sub-toolbar 
        controllers.
 
        Used by implementations that want to provide the toolbar button sub-toolbar 
        function feature. A controller supporting this interface exchanges the 
        function of its own toolbar button, that opened the sub-toolbar, with the 
        one that has been selected on the sub-toolbar.
    */
    [optional] interface ::com::sun::star::frame::XSubToolbarController;
};
 
}; }; }; };
module com { module sun { module star { module frame { 
 
published interface XStatusListener: com::sun::star::lang::XEventListener
{
 /** is called when the status of the feature changes.
 
 @param State
 provides information about changes of the requested feature
 */
 [oneway] void statusChanged( [in] FeatureStateEvent State );
 
};
 
}; }; }; };
module com { module sun { module star { module frame { 
 
published struct FeatureStateEvent: com::sun::star::lang::EventObject
 
{
 //-------------------------------------------------------------------------
 
 /** contains the URL of the feature. */
 com::sun::star::util::URL FeatureURL;
 
 //-------------------------------------------------------------------------
 
 /** contains a descriptor of the feature for the user interface.*/
 string FeatureDescriptor;
 
 //-------------------------------------------------------------------------
 
 /** specifies whether the feature is currently enabled or disabled. */
 boolean IsEnabled;
 
 //-------------------------------------------------------------------------
 
 /** specifies whether the <type>XDispatch</type> has to be requeried. */
 boolean Requery;
 
 //-------------------------------------------------------------------------
 
 /** contains the state of the feature in this dispatch.*/
 any State;
}; 
 
}; }; }; };
module com { module sun { module star { module lang { 
 
published interface XInitialization: com::sun::star::uno::XInterface
{ 
 // DocMerge from xml: method com::sun::star::lang::XInitialization::initialize
 /** initializes the object. 
 
 <p>It should be called directly after the object is created.
 */
 void initialize( [in] sequence<any> aArguments ) 
 raises( com::sun::star::uno::Exception );
}; 
 
//============================================================================= 
 
}; }; }; };
module com { module sun { module star { module util {
 
published interface XUpdatable: com::sun::star::uno::XInterface
{
 //-------------------------------------------------------------------------
 /** refreshes the data of the object from the connected data source. */
 void update();
};
 
//=============================================================================
 
}; }; }; };
module com { module sun { module star { module frame {
 
interface XToolbarController : com::sun::star::uno::XInterface
{
 //=============================================================================
 /** provides a function to execute the command which is bound to the toolbar controller.
 
 @param 
 a combination of <type scope="com::sun::star::awt">KeyModifier</type> value that represent the current state of the modifier keys.
 
 <p>
 This function is usally called by a toolbar implementation when a user clicked on a toolbar button or pressed enter on the keyboard when the item has the input focus.
 </p>
 */
 void execute( [in] short KeyModifier );
 
 //=============================================================================
 /** notifies a component that a single click has been made on the toolbar item.
 */
 void click();
 
 //=============================================================================
 /** notifies a component that a double click has been made on the toolbar item.
 */
 void doubleClick();
 
 //=============================================================================
 /** requests to create a popup window for additional functions.
 
 @return
 a <type scope="com::sun::star::awt">XWindow</type> which provides additional functions to the user. The reference must be empty if component does not want to provide a separate window.
 */
 com::sun::star::awt::XWindow createPopupWindow();
 
 //=============================================================================
 /** requests to create an item window which can be added to the toolbar.
 
 @param Parent
 a <type scope="com::sun::star::awt">XWindow</type> which must be used as a parent for the requested item window.
 
 @return
 a <type scope="com::sun::star::awt">XWindow</type> which can be added to a toolbar. The reference must be empty if a component does not want to provide an item window.
 */
 com::sun::star::awt::XWindow createItemWindow( [in] com::sun::star::awt::XWindow Parent );
};
 
}; }; }; };
module com { module sun { module star { module frame {
 
interface XSubToolbarController : com::sun::star::uno::XInterface
{
 //=============================================================================
 /** if the controller features a sub-toolbar. 
 
 @return
 <TRUE/> if the controller offers a sub toolbar, otherwise <FALSE/>.
 
 <p>
 Enables implementations to dynamically decide to support sub-toolbars
 or not.
 </p>
 */
 boolean opensSubToolbar();
 
 //=============================================================================
 /** provides the resource URL of the sub-toolbar this controller opens.
 
 @return
 name of the sub-toolbar this controller offers. A empty string 
 will be interpreted as if this controller offers no sub-toolbar.
 */
 string getSubToolbarName();
 
 //=============================================================================
 /** gets called to notify a controller that a sub-toolbar function has been 
 selected.
 
 @param aCommand
 a string which identifies the function that has been selected by
 a user.
 */
 void functionSelected( [in] string aCommand );
 
 //=============================================================================
 /** gets called to notify a controller that it should set an image which
 represents the current selected function.
 
 <p>
 Only the controller instance is able to set the correct image for the
 current function. A toolbar implementation will ask sub-toolbar 
 controllers to update their image whenever it has to update the images
 of all its buttons.
 </p>
 */
 void updateImage();
};
 
}; }; }; };

Generic toolbar item controller

A generic toolbar item controller is used by toolbar implementation for simple toolbar buttons. Normally most items of a toolbar consists of generic toolbar item controllers. They support the following generic functions by listening to status updates provided by the application module controller.


Variable

UNO Type/Poolitem

Action

State

String / SfxStringItem

Toolbar item changes its quick help and its label to the content of the provided string.

State

Boolean / SfxBoolItem

Toolbar item checks or unchecks its item, according to the boolean value.

State

com.sun.star.frame.status.VisibilityItem / SfxVisibilityItem

Toolbar item will be made visible or invisible according to the provided state.

State

com.sun.star.frame.status.ItemStatus ( Will be directly retrieved with Dispatcher->QueryState(...) or transported by SfxItemState ).

Toolbar item is set to normal or tri-state according to the provided member ItemStatus.State (see dont_care value in com.sun.star.frame.status.ItemState)

IsEnabled

Boolean

Toolbar item is enabled or disabled according to the value of IsEnabled.


Generic toolbar item controllers are not able to support the creation of sub-toolbars or floating windows.


Specific toolbar item controllers

Specific toolbar item controllers are much more flexible and can support the creation of sub-toolbars or floating windows. As they are much more powerful they have sole responsibility to react correctly on status updates received by the application module controller.

Variable

UNO Type/Poolitem

Action required

State

Boolean / SfxBoolItem

Toolbar item checks or unchecks its item according to the boolean value, if this makes sense in the context.

State

com.sun.star.frame.status.VisibilityItem / SfxVisibilityItem

Toolbar item should make itself visible or invisible according to the provided state.

State

com.sun.star.frame.status.ItemStatus ( Will be directly retrieved with Dispatcher->QueryState(...) or transported by SfxItemState ).

Toolbar item should set itself to normal or tri-state according to the provided member ItemStatus.State. It depends on the specific toolbar item if this makes sense.

IsEnabled

Boolean

Toolbar item must enabled or disabled itself according to the value of IsEnabled.



Specific toolbar item controllers must be registered in the configuration set org.openoffice.Office.UI.Controller/Registered/Toolbar when they are implemented via an UNO service.

An abstract from the Controller.xcu with registered specific toolbar item controllers:

 ...
 
<node oor:name="ToolBar">
 <node oor:name="c1" oor:op="replace">
  <prop oor:name="Command">
   <value>.uno:DBNewForm</value>
  </prop>
  <prop oor:name="Module">
   <value>com.sun.star.sdb.OfficeDatabaseDocument</value>
  </prop>
  <prop oor:name="Controller">
   <value>com.sun.star.sdb.ApplicationToolboxController</value>
  </prop>
 </node>
 <node oor:name="c2" oor:op="replace">
  <prop oor:name="Command">
   <value>.uno:Refresh</value>
  </prop>
  <prop oor:name="Module">
   <value>com.sun.star.sdb.OfficeDatabaseDocument</value>
  </prop>
  <prop oor:name="Controller">
   <value>com.sun.star.sdb.ApplicationToolboxController</value>
  </prop>
 </node>
</node>
 
 ...

The framework provides a base class which makes it much easier to implement UNO based specific toolbar item controllers. It can be found in svtools/inc/toolboxcontroller.hxx.

The sfx2 based specific toolbar item controllers are registered by calling ToolbarControllerClass::RegisterControl(SlotID, SfxModule* ). The framework implementation uses a special toolbar controller factory to create instances of sfx2 based specific toolbar item controllers. Sfx2 based specific toolbar controllers can use the known base class sfx2/inc/tbxctrl.hxx. It's a special wrapper which converts calls to the its UNO interfaces to the needs of sfx2 based toolbar controllers.

class SFX2_DLLPUBLIC SfxToolBoxControl:
    public ::com::sun::star::awt::XDockableWindowListener,
    public ::com::sun::star::frame::XSubToolbarController,
    public svt::ToolboxController 
{
    friend class SfxToolbox;
    friend class SfxToolBox_Impl;
    friend class SfxToolboxCustomizer;
    friend class SfxPopupWindow;
    friend struct SfxTbxCtrlFactory;
 
    SfxToolBoxControl_Impl* pImpl;
 
protected:
    DECL_LINK( PopupModeEndHdl, void * );
    DECL_LINK( ClosePopupWindow, SfxPopupWindow * );
 
    // old SfxToolBoxControl methods
    virtual void StateChanged( USHORT nSID, SfxItemState eState, const SfxPoolItem* pState );
    virtual void Select( BOOL bMod1 = FALSE );
    virtual void Select( USHORT nModifier );
 
    virtual void DoubleClick();
    virtual void Click();
    virtual SfxPopupWindowType GetPopupWindowType() const;
    virtual SfxPopupWindow* CreatePopupWindow();
    virtual SfxPopupWindow* CreatePopupWindowCascading();
    virtual Window* CreateItemWindow( Window *pParent );
 
    // Must be called by subclass to set a new popup window instance
    void SetPopupWindow( SfxPopupWindow* pWindow );
 
    // XInterface
    virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL acquire() throw();
    virtual void SAL_CALL release() throw();
 
    // XEventListener
    virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& aEvent ) throw( ::com::sun::star::uno::RuntimeException );
 
    // XComponent
    virtual void SAL_CALL dispose() throw (::com::sun::star::uno::RuntimeException);
 
    // new controller API
    // XStatusListener
    virtual void SAL_CALL statusChanged( const ::com::sun::star::frame::FeatureStateEvent& Event ) throw ( ::com::sun::star::uno::RuntimeException );
 
    // XToolbarController
    virtual void SAL_CALL execute( sal_Int16 KeyModifier ) 
    throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL click() 
    throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL doubleClick() 
    throw (::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindow > SAL_CALL createPopupWindow() 
    throw (::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindow > SAL_CALL createItemWindow( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindow >& rParent ) 
    throw (::com::sun::star::uno::RuntimeException);
 
    // XSubToolbarController
    virtual ::sal_Bool SAL_CALL opensSubToolbar( ) throw (::com::sun::star::uno::RuntimeException);
    virtual ::rtl::OUString SAL_CALL getSubToolbarName( ) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL functionSelected( const ::rtl::OUString& aCommand ) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL updateImage( ) throw (::com::sun::star::uno::RuntimeException);
 
    // XDockableWindowListener
    virtual void SAL_CALL startDocking( const ::com::sun::star::awt::DockingEvent& e ) throw (::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::awt::DockingData SAL_CALL docking( const ::com::sun::star::awt::DockingEvent& e ) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL endDocking( const ::com::sun::star::awt::EndDockingEvent& e ) throw (::com::sun::star::uno::RuntimeException);
    virtual sal_Bool SAL_CALL prepareToggleFloatingMode( const ::com::sun::star::lang::EventObject& e ) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL toggleFloatingMode( const ::com::sun::star::lang::EventObject& e ) throw (::com::sun::star::uno::RuntimeException); 
    virtual void SAL_CALL closed( const ::com::sun::star::lang::EventObject& e ) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL endPopupMode( const ::com::sun::star::awt::EndPopupModeEvent& e ) throw (::com::sun::star::uno::RuntimeException);
 
    // helper methods
    void createAndPositionSubToolBar( const ::rtl::OUString& rSubToolBarResName );
    ::Size getPersistentFloatingSize( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame >& xFrame, const ::rtl::OUString& rSubToolBarResName );
 
public:
    SFX_DECL_TOOLBOX_CONTROL();
 
    SfxToolBoxControl( USHORT nSlotID, USHORT nId, ToolBox& rBox, BOOL bShowStrings = FALSE );
    virtual ~SfxToolBoxControl();
 
    ToolBox& GetToolBox() const;
    unsigned short GetId() const;
    unsigned short GetSlotId() const;
 
    void Dispatch( 
    const ::rtl::OUString& aCommand, 
    ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs );
    static void Dispatch( 
    const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider >& rDispatchProvider, const rtl::OUString& rCommand, ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs );
 
    static SfxItemState GetItemState( const SfxPoolItem* pState );
    static SfxToolBoxControl* CreateControl( USHORT nSlotId, USHORT nTbxId, ToolBox *pBox, SfxModule *pMod );
};

Statusbar

Specific statusbar item controller

The statusbar implementation only supports specific statusbar item controllers. There are no generic statusbar item controllers which could provide generic functions.

A statusbar item controller must support the following services and interfaces.

module com { module sun { module star { module frame {
 
service StatusbarController
{
 //-------------------------------------------------------------------------
 /** with this interface a component can receive events if a feature has 
 changed.
 
 <p>
 The statusbar controller implementation should register itself as a 
 listener when its <member scope="com::sun::star::util">XUpdatable</member> 
 interface has been called.
 </p>
 */
 interface com::sun::star::frame::XStatusListener;
 
 /** used to initialize a component with required arguments.
 
 <b>A statusbar controller needs at least three additional arguments 
 provided as <type scope="com::sun::star::beans">PropertyValue</type>:
 <ul>
 <li><b>Frame</b><br>a 
 <type scope="com::sun::star::frame">XFrame</type> instance
 to which the toolbar controller belongs.</li>
 <li><b>CommandURL</b><br>a string which specifies the command a 
 statusbar controller is bound.</li>
 <li><b>ServiceManager</b><br>a <type scope="com::sun::star::lang">
 XMultiServiceFactory</type> instance which can be used to 
 create additional UNO services.</li>
 </ul>
 */
 interface com::sun::star::lang::XInitialization;
 
 /** used to notify an implementation that it needs to add its listener or 
 remove and add them again.
 
 <p>
 A status bar controller instance is ready for use after this call has 
 been made the first time. The status bar implementation guarentees that 
 the controller's item window has been added to the status bar and its 
 reference is held by it.
 </p>
 */
 interface com::sun::star::util::XUpdatable;
 
 //-------------------------------------------------------------------------
 /** used to notify changed features and requests for additional user 
 interface items.
 
 <p>
 Mostly used by a status bar implementation to forward information to 
 and request services from a status bar controller component. This 
 interface must be useable after 
 <member scope="com::sun::star::lang">XInitialitation::initialize</member> 
 has been called. The behavior of the interface is undefined if the 
 controller component hasn't been initialized.
 </p>
 */
 interface com::sun::star::frame::XStatusbarController;
};
 
}; }; }; };
module com { module sun { module star { module frame {
 
published interface XStatusListener: com::sun::star::lang::XEventListener
{
    /** is called when the status of the feature changes.
 
        @param State
         provides information about changes of the requested feature
    */
    [oneway] void statusChanged( [in] FeatureStateEvent State );
 
};
 
}; }; }; };
module com { module sun { module star { module frame {
 
published struct FeatureStateEvent: com::sun::star::lang::EventObject
{
    //-------------------------------------------------------------------------
    /** contains the URL of the feature. 
     */
    com::sun::star::util::URL FeatureURL;
 
    //-------------------------------------------------------------------------
    /** contains a descriptor of the feature for the user interface.
     */
    string FeatureDescriptor;
 
    //-------------------------------------------------------------------------
    /** specifies whether the feature is currently enabled or disabled.
    */
    boolean IsEnabled;
 
    //-------------------------------------------------------------------------
    /** specifies whether the XDispatch object has to be requeried.
     */
    boolean Requery;
 
    //-------------------------------------------------------------------------
    /** contains the state of the feature in this dispatch.
     */
    any State;
 
};
}; }; }; };
module com { module sun { module star { module lang { 
 
published interface XInitialization: com::sun::star::uno::XInterface
{ 
 // DocMerge from xml: method com::sun::star::lang::XInitialization::initialize
 /** initializes the object. 
 
 <p>It should be called directly after the object is created.
 */
 void initialize( [in] sequence<any> aArguments ) 
 raises( com::sun::star::uno::Exception );
}; 
 
//============================================================================= 
 
}; }; }; };
module com { module sun { module star { module util {
 
published interface XUpdatable: com::sun::star::uno::XInterface
{
 //-------------------------------------------------------------------------
 /** refreshes the data of the object from the connected data source. */
 void update();
};
 
//=============================================================================
 
}; }; }; };
module com { module sun { module star { module frame {
 
interface XStatusbarController : ::com::sun::star::uno::XInterface
{
 //=============================================================================
 /** is called by a status bar if the mouse position is within the controller 
 and a mouse button has been pressed. If the controller has captured the 
 mouse input this function is also called when the mouse position is not 
 within the controller.
 
 @param aMouseEvent
 current information about the mouse pointer.
 
 @return
 return <TRUE/> if the event should not be processed and <FALSE/> 
 if the event should be processed by the status bar.
 */
 boolean mouseButtonDown( [in] ::com::sun::star::awt::MouseEvent aMouseEvent );
 
 //=============================================================================
 /** is called by a status bar if the mouse position is within the controller 
 and a mouse has been moved. If the controller has captured the 
 mouse input this function is also called when the mouse position is not 
 within the controller.
 
 @param aMouseEvent
 current information about the mouse pointer.
 
 @return
 return <TRUE/> if the event should not be processed and <FALSE/> 
 if the event should be processed by the status bar.
 */
 boolean mouseMove( [in] ::com::sun::star::awt::MouseEvent aMouseEvent );
 
 //=============================================================================
 /** is called by a status bar if the mouse position is within the controller 
 and a mouse button has been released. If the controller has captured the 
 mouse input this function is also called when the mouse position is not 
 within the controller.
 
 @param aMouseEvent
 current information about the mouse pointer.
 
 @return
 return <TRUE/> if the event should not be processed and <FALSE/> 
 if the event should be processed by the status bar.
 */
 boolean mouseButtonUp( [in] ::com::sun::star::awt::MouseEvent aMouseEvent );
 
 //=============================================================================
 /** is called by a status bar if a command event is available for a controller.
 
 @param aPos
 the current mouse position in pixel.
 
 @param nCommand
 describes which command has been invoked.
 
 @param bMouseEvent
 <TRUE/> if the command is based on a mouse event, otherwise <FALSE/>.
 
 @param aData
 for future use only.
 */
 void command( [in] ::com::sun::star::awt::Point aPos,
 [in] long nCommand,
 [in] boolean bMouseEvent,
 [in] any aData );
 
 //=============================================================================
 /** is called by a status bar if a command event is available for a controller.
 
 @param xGraphics
 the current graphics which should be used for painting.
 
 @param rOutputRectangle
 the output rectangle for graphic operations.
 
 @param nItemId
 the item id of the controller.
 
 @param nStyle
 the style of the statusbar item. The controller should respect the provided
 
style when paints.
 */
 void paint( [in] ::com::sun::star::awt::XGraphics xGraphics,
 [in] ::com::sun::star::awt::Rectangle rOutputRectangle,
 [in] long nItemId,
 [in] long nStyle );
 
 //=============================================================================
 /** is called by a status bar if the user clicked with mouse into the 
 field of the corresponding control.
 */
 void click();
 
 //=============================================================================
 /** is called by a status bar if the user double-clicked with mouse 
 into the field of the corresponding control.
 */
 void doubleClick();
}; 
 
}; }; }; };

OOo 2.0 supports two kind of specific statusbar item controllers. UNO based specific statusbar item controllers must be registered in the configuration set org.openoffice.Office.UI.Controller/Registered/Statusbar.

An abstract from the Controller.xcu with registered specific statusbar item controllers:

 ...
 
<node oor:name="StatusBar">
 <node oor:name="c1" oor:op="replace">
  <prop oor:name="Command">
   <value>.uno:DBStatusType</value>
  </prop>
  <prop oor:name="Module">
   <value>com.sun.star.sdb.OfficeDatabaseDocument</value>
  </prop>
  <prop oor:name="Controller">
   <value>com.sun.star.sdb.ApplicationStatusbarController</value>
  </prop>
 </node>
 <node oor:name="c2" oor:op="replace">
  <prop oor:name="Command">
   <value>.uno:DBStatusDBName</value>
  </prop>
  <prop oor:name="Module">
   <value>com.sun.star.sdb.OfficeDatabaseDocument</value>
  </prop>
  <prop oor:name="Controller">
   <value>com.sun.star.sdb.ApplicationStatusbarController</value>
  </prop>
 </node>
 
 ...
 <node oor:name="c5" oor:op="replace">
  <prop oor:name="Command">
   <value>.uno:StatusbarLogo</value>
  </prop>
  <prop oor:name="Module">
   <value/>
  </prop>
  <prop oor:name="Controller">
   <value>com.sun.star.comp.framework.LogoImageStatusbarController</value>
  </prop>
 </node>
 
 ...
</node>

The framework library provides a base class in svtools/inc/statusbarcontroller.hxx which makes it simpler to implement a UNO based specific status bar controller.

The sfx2 based specific statusbar item controllers are registered by calling StatusbarControllerClass::RegisterControl(SlotID, SfxModule* ). The framework implementation uses a special statusbar controller factory to create instances of sfx2 based specific statusbar item controllers. Sfx2 based specific statusbar controllers can use the known base class sfx2/inc/stbitem.hxx. It's a special wrapper which converts calls to the its UNO interfaces to the needs of sfx2 based statusbar controllers.

class SFX2_DLLPUBLIC SfxStatusBarControl: public svt::StatusbarController
{
 USHORT nSlotId;
 USHORT nId;
 StatusBar* pBar;
 
protected:
 // new controller API
 // XInterface
 virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException);
 virtual void SAL_CALL acquire() throw();
 virtual void SAL_CALL release() throw();
 
 // XEventListener
 virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& aEvent ) throw( ::com::sun::star::uno::RuntimeException );
 
 // XComponent
 virtual void SAL_CALL dispose() throw (::com::sun::star::uno::RuntimeException);
 
 // XStatusListener
 virtual void SAL_CALL statusChanged( const ::com::sun::star::frame::FeatureStateEvent& Event ) throw ( ::com::sun::star::uno::RuntimeException );
 
 // XStatusbarController
 virtual ::sal_Bool SAL_CALL mouseButtonDown( const ::com::sun::star::awt::MouseEvent& aMouseEvent ) throw (::com::sun::star::uno::RuntimeException);
 virtual ::sal_Bool SAL_CALL mouseMove( const ::com::sun::star::awt::MouseEvent& aMouseEvent ) throw (::com::sun::star::uno::RuntimeException);
 virtual ::sal_Bool SAL_CALL mouseButtonUp( const ::com::sun::star::awt::MouseEvent& aMouseEvent ) throw (::com::sun::star::uno::RuntimeException);
 virtual void SAL_CALL command( const ::com::sun::star::awt::Point& aPos, 
 ::sal_Int32 nCommand, 
 ::sal_Bool bMouseEvent, 
 const ::com::sun::star::uno::Any& aData ) 
 
throw (::com::sun::star::uno::RuntimeException);
 virtual void SAL_CALL paint( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XGraphics >& xGraphics, 
 const ::com::sun::star::awt::Rectangle& rOutputRectangle, 
 ::sal_Int32 nItemId, 
 ::sal_Int32 nStyle )
 
throw (::com::sun::star::uno::RuntimeException);
 virtual void SAL_CALL click() throw (::com::sun::star::uno::RuntimeException);
 virtual void SAL_CALL doubleClick() throw (::com::sun::star::uno::RuntimeException);
 
 // Old sfx2 interface
 virtual void StateChanged( USHORT nSID, SfxItemState eState,
 const SfxPoolItem* pState );
 virtual void Click();
 virtual void DoubleClick();
 virtual void Command( const CommandEvent& rCEvt );
 virtual BOOL MouseButtonDown( const MouseEvent & );
 virtual BOOL MouseMove( const MouseEvent & );
 virtual BOOL MouseButtonUp( const MouseEvent & );
 virtual void Paint( const UserDrawEvent &rUDEvt );
 
 static USHORT convertAwtToVCLMouseButtons( sal_Int16 nAwtMouseButtons ); 
 
public:
 SfxStatusBarControl( USHORT nSlotID, USHORT nId, StatusBar& rBar );
 virtual ~SfxStatusBarControl();
 
 USHORT GetSlotId() const { return nSlotId; }
 USHORT GetId() const { return nId; }
 StatusBar& GetStatusBar() const { return *pBar; }
 void CaptureMouse();
 void ReleaseMouse();
 
 static SfxStatusBarControl* CreateControl( USHORT nSlotID, USHORT nId, StatusBar *pBar, SfxModule* );
};

User interface controllers in the mixed sfx2/uno environment

How user interface controllers work in a pure UNO based environment?

EnvironmentPureUnoUserInterfaceController.png

How user interface controllers work in our mixed sfx2/UNO based environment?

EnvironmentUserInterfaceController.png


Let's see what happens in more detail, especially when we switch from one layer to another one.

  1. A shell wants to invalidate a slot and calls SfxShell::Invalidate( SlotID ).
  2. The bindings updates the SfxStateCache for the provided slot ID normally through a update timer or directly.
  3. The SfxStateCache calls StateChanged with the new state on a SfxDispatchController_Impl object.
  4. The SfxDispatchController_Impl now maps the sfx2 state information based on SfxPoolItem to UNO information and sends them to UNO based toolbar controller.
...
 
::cppu::OInterfaceContainerHelper* pContnr = pDispatch->GetListeners().getContainer( aDispatchURL.Complete );
if ( bNotify && pContnr )
{
  ::com::sun::star::uno::Any aState;
  if ( ( eState >= SFX_ITEM_AVAILABLE ) && pState && !IsInvalidItem( pState ) && !pState->ISA(SfxVoidItem) )
  {
    // Retrieve metric from pool to have correct sub ID when calling QueryValue
    USHORT nSubId( 0 );
    SfxMapUnit eMapUnit( SFX_MAPUNIT_100TH_MM );
 
    // retrieve the core metric
    // it's enough to check the objectshell, the only shell that does not 
    // use the pool of the document is SfxViewFrame, but it hasn't any metric parameters
    if ( pSlotServ && pDispatcher )
    {
      SfxShell* pShell = pDispatcher->GetShell( pSlotServ->GetShellLevel() );
      DBG_ASSERT( pShell, "Can't get core metric without shell!" );
      if ( pShell )
        eMapUnit = GetCoreMetric( pShell->GetPool(), nSID );
    }
 
    if ( eMapUnit == SFX_MAPUNIT_TWIP )
      nSubId |= CONVERT_TWIPS;
    pState->QueryValue( aState, (BYTE)nSubId );
  }
  else if ( eState == SFX_ITEM_DONTCARE )
  {
    // Use special uno struct to transport don't care state
    ::com::sun::star::frame::status::ItemStatus aItemStatus;
    aItemStatus.State = ::com::sun::star::frame::status::ItemState::dont_care;
    aState = makeAny( aItemStatus );
  }
 
  ::com::sun::star::frame::FeatureStateEvent aEvent;
  aEvent.FeatureURL = aDispatchURL;
  aEvent.Source = (::com::sun::star::frame::XDispatch*) pDispatch;
  aEvent.IsEnabled = eState != SFX_ITEM_DISABLED;
  aEvent.Requery = sal_False;
  aEvent.State = aState;
 
  ::cppu::OInterfaceIteratorHelper aIt( *pContnr );
  while( aIt.hasMoreElements() )
  {
    try
    {
      ((::com::sun::star::frame::XStatusListener *)aIt.next())->statusChanged( aEvent );
    }
    catch( ::com::sun::star::uno::RuntimeException& )
    {
      aIt.remove();
    }
  }
}
 
...

How does QueryValue work and convert an item to UNO com::sun::star::uno::any?


You can find the base class of any pool item in svtools/inc/poolitem.hxx

class SVL_DLLPUBLIC SfxPoolItem
{
friend class SfxItemPool;
friend class SfxItemDesruptor_Impl;
friend class SfxItemPoolCache;
friend class SfxItemSet;
friend class SfxVoidItem;
 
 ULONG nRefCount; // Referenzzaehler
 USHORT nWhich;
 USHORT nKind;
 
private:
 inline void SetRefCount( ULONG n );
 inline void SetKind( USHORT n );
public:
 inline ULONG AddRef( ULONG n = 1 ) const;
private:
 inline ULONG ReleaseRef( ULONG n = 1 ) const;
 SVL_DLLPRIVATE long Delete_Impl(void*);
 
protected:
 SfxPoolItem( USHORT nWhich = 0 );
 SfxPoolItem( const SfxPoolItem& );
 
public:
 TYPEINFO();
 
 virtual ~SfxPoolItem();
 void SetWhich( USHORT nId ) 
 { DBG_CHKTHIS(SfxPoolItem, 0); nWhich = nId; }
 USHORT Which() const { DBG_CHKTHIS(SfxPoolItem, 0); return nWhich; }
 virtual int operator==( const SfxPoolItem& ) const = 0;
 int operator!=( const SfxPoolItem& rItem ) const
 { return !(*this == rItem); }
 virtual int Compare( const SfxPoolItem &rWith ) const;
 virtual int Compare( const SfxPoolItem &rWith, const IntlWrapper& rIntlWrapper ) const;
 
 virtual SfxItemPresentation GetPresentation( SfxItemPresentation ePresentation,
 SfxMapUnit eCoreMetric,
 SfxMapUnit ePresentationMetric,
 XubString &rText,
 const IntlWrapper * pIntlWrapper = 0 ) const;
 
 virtual USHORT GetVersion( USHORT nFileFormatVersion ) const;
 virtual int ScaleMetrics( long lMult, long lDiv );
 virtual int HasMetrics() const;
 
 virtual BOOL QueryValue( com::sun::star::uno::Any& rVal, BYTE nMemberId = 0 ) const;
 virtual BOOL PutValue( const com::sun::star::uno::Any& rVal, BYTE nMemberId = 0 );
 
 virtual SfxPoolItem* Create( SvStream &, USHORT nItemVersion ) const;
 virtual SvStream& Store( SvStream &, USHORT nItemVersion ) const;
 virtual SfxPoolItem* Clone( SfxItemPool *pPool = 0 ) const = 0;
 
 ULONG GetRefCount() const { return nRefCount; }
 inline USHORT GetKind() const { return nKind; }
 
 static bool readByteString(SvStream & rStream, UniString & rString);
 static void writeByteString(SvStream & rStream,UniString const & rString);
 static bool readUnicodeString(SvStream & rStream, UniString & rString, bool bUnicode);
 static void writeUnicodeString(SvStream & rStream, UniString const & rString);
 
private:
 SfxPoolItem& operator=( const SfxPoolItem& ); // n.i.!!
};

A example how to implement QueryValue can be found in the implementation of the SvxULSpaceItem (located in svx/source/items/frmitems.cxx).

sal_Bool SvxULSpaceItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const
{
  sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS);
  nMemberId &= ~CONVERT_TWIPS;
  switch( nMemberId )
  {
    // jetzt alles signed
    case 0:
    {
      ::com::sun::star::frame::status::UpperLowerMarginScale aUpperLowerMarginScale;
      aUpperLowerMarginScale.Upper = (sal_Int32)(bConvert ? TWIP_TO_MM100(nUpper) : nUpper);
      aUpperLowerMarginScale.Lower = (sal_Int32)(bConvert ? TWIP_TO_MM100(nLower) : nPropUpper);
      aUpperLowerMarginScale.ScaleUpper = (sal_Int16)nPropUpper;
      aUpperLowerMarginScale.ScaleLower = (sal_Int16)nPropLower;
      rVal <<= aUpperLowerMarginScale;
      break;
    }
    case MID_UP_MARGIN: rVal <<= (sal_Int32)(bConvert ? TWIP_TO_MM100(nUpper) : nUpper); break;
    case MID_LO_MARGIN: rVal <<= (sal_Int32)(bConvert ? TWIP_TO_MM100(nLower) : nLower); break;
    case MID_UP_REL_MARGIN: rVal <<= (sal_Int16) nPropUpper; break;
    case MID_LO_REL_MARGIN: rVal <<= (sal_Int16) nPropLower; break;
  }
  return sal_True;
}
  1. The UNO based toolbar controller now has to convert the state information (com::sun::star::uno::Any) again to provide it in a format that the sfx2 based toolbar controller implementation knows (SfxPoolItem).
// XStatusListener 
 
void SAL_CALL SfxToolBoxControl::statusChanged( const FeatureStateEvent& rEvent ) 
throw ( ::com::sun::star::uno::RuntimeException ) 
{ 
    SfxViewFrame* pViewFrame = NULL; 
    Reference < XController > xController; 
 
    ::vos::OGuard aGuard( Application::GetSolarMutex() ); 
    if ( getFrameInterface().is() ) 
        xController = getFrameInterface()->getController(); 
 
    Reference < XDispatchProvider > xProvider( xController, UNO_QUERY ); 
    if ( xProvider.is() ) 
    { 
        Reference < XDispatch > xDisp = xProvider->queryDispatch( 
            rEvent.FeatureURL, ::rtl::OUString(), 0 ); 
        if ( xDisp.is() ) 
        { 
            Reference< XUnoTunnel > xTunnel( xDisp, UNO_QUERY ); 
            SfxOfficeDispatch* pDisp = NULL; 
            if ( xTunnel.is() ) 
            { 
                sal_Int64 nImplementation = xTunnel>getSomething 
                SfxOfficeDispatch::impl_getStaticIdentifier() ); 
                pDisp = (SfxOfficeDispatch*)(nImplementation); 
            } 
 
            if ( pDisp ) 
                pViewFrame = pDisp->GetDispatcher_Impl()->GetFrame(); 
        } 
    } 
 
    USHORT nSlotId = 0; 
    SfxSlotPool& rPool = SFX_APP()->GetSlotPool( pViewFrame ); 
    const SfxSlot* pSlot = rPool.GetUnoSlot( rEvent.FeatureURL.Path ); 
    if ( pSlot ) 
        nSlotId = pSlot->GetSlotId(); 
 
    if ( nSlotId > 0 ) 
    { 
        if ( rEvent.Requery ) 
            svt::ToolboxController::statusChanged( rEvent ); 
        else 
        { 
            SfxItemState eState = SFX_ITEM_DISABLED; 
            SfxPoolItem* pItem = NULL; 
 
            if ( rEvent.IsEnabled ) 
            { 
                eState = SFX_ITEM_AVAILABLE; 
                ::com::sun::star::uno::Type pType = rEvent.State.getValueType(); 
 
                if ( pType == ::getVoidCppuType() ) 
                { 
                    pItem = new SfxVoidItem( nSlotId ); 
                    eState = SFX_ITEM_UNKNOWN; 
                } 
                else if ( pType == ::getBooleanCppuType() ) 
                { 
                    sal_Bool bTemp ; 
                    rEvent.State >>= bTemp ; 
                    pItem = new SfxBoolItem( nSlotId, bTemp ); 
                } 
                else if ( pType == ::getCppuType((const sal_uInt16*)0) ) 
                { 
                    sal_uInt16 nTemp ; 
                    rEvent.State >>= nTemp ; 
                    pItem = new SfxUInt16Item( nSlotId, nTemp ); 
                } 
                else if ( pType == ::getCppuType((const sal_uInt32*)0) ) 
                { 
                    sal_uInt32 nTemp ; 
                    rEvent.State >>= nTemp ; 
                    pItem = new SfxUInt32Item( nSlotId, nTemp ); 
                } 
                else if ( pType == ::getCppuType((const ::rtl::OUString*)0) ) 
                { 
                    ::rtl::OUString sTemp ; 
                    rEvent.State >>= sTemp ; 
                    pItem = new SfxStringItem( nSlotId, sTemp ); 
                } 
                else if ( pType == ::getCppuType(( const 
                    ::com::sun::star::frame::status::ItemStatus* )0) ) 
                { 
                    ItemStatus aItemStatus; 
                    rEvent.State >>= aItemStatus; 
                    eState = aItemStatus.State; 
                    pItem = new SfxVoidItem( nSlotId ); 
                } 
                else if ( pType == ::getCppuType(( const 
                    ::com::sun::star::frame::status::Visibility*)0) ) 
                { 
                    Visibility aVisibilityStatus; 
                    rEvent.State >>= aVisibilityStatus; 
                    pItem = new SfxVisibilityItem( nSlotId, aVisibilityStatus.bVisible ); 
                } 
                else 
                { 
                    if ( pSlot ) 
                        pItem = pSlot->GetType()->CreateItem(); 
                    if ( pItem ) 
                    { 
                        pItem->SetWhich( nSlotId ); 
                        pItem->PutValue( rEvent.State ); 
                    } 
                    else 
                        pItem = new SfxVoidItem( nSlotId ); 
                } 
           } 
 
           StateChanged( nSlotId, eState, pItem ); 
           delete pItem; 
        } 
    } 
}

As you can see the implementation retrieves the type of the slot and creates an empty item of that type. Now it has to use PutValue to convert the UNO com::sun::star::uno::Any back to an item. Let's see how the SvxULSpaceItem implements PutValue:

sal_Bool SvxULSpaceItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) 
{ 
    sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); 
    nMemberId &= ~CONVERT_TWIPS; 
 
    sal_Int32 nVal; 
    switch( nMemberId ) 
    { 
        case 0: 
        { 
            ::com::sun::star::frame::status::UpperLowerMarginScale aUpperLowerMarginScale; 
            if ( !(rVal >>= aUpperLowerMarginScale )) 
                return sal_False; 
            else 
            { 
                SetUpper((sal_uInt16)(bConvert ? 
                    MM100_TO_TWIP( aUpperLowerMarginScale.Upper ) : aUpperLowerMarginScale.Upper)); 
                SetLower((sal_uInt16)(bConvert ? 
                    MM100_TO_TWIP( aUpperLowerMarginScale.Lower ) : aUpperLowerMarginScale.Lower)); 
                if( aUpperLowerMarginScale.ScaleUpper > 1 ) 
                    nPropUpper = aUpperLowerMarginScale.ScaleUpper; 
                if( aUpperLowerMarginScale.ScaleLower > 1 ) 
                    nPropUpper = aUpperLowerMarginScale.ScaleLower; 
            } 
        } 
 
        case MID_UP_MARGIN : 
            if(!(rVal >>= nVal) || nVal < 0) 
                return sal_False; 
            SetUpper((sal_uInt16)bConvert ? MM100_TO_TWIP(nVal) : nVal); 
            break; 
 
         case MID_LO_MARGIN : 
            if(!(rVal >>= nVal) || nVal < 0) 
                return sal_False; 
            SetLower((sal_uInt16)bConvert ? MM100_TO_TWIP(nVal) : nVal); 
            break; 
 
         case MID_UP_REL_MARGIN: 
         case MID_LO_REL_MARGIN: 
         { 
             sal_Int32 nRel; 
             if((rVal >>= nRel) && nRel > 1 ) 
             { 
                 if(MID_UP_REL_MARGIN == nMemberId) 
                     nPropUpper = nRel; 
                 else 
                     nPropLower = nRel; 
             } 
             else 
                 return FALSE; 
         } 
         break; 
 
         default: 
             DBG_ERROR("unknown MemberId"); 
             return sal_False; 
   } 
 
   return sal_True; 
}

We should now see some very important rules that this conversion can work correctly.


  • Never use the value 0 of the nMemberID to convert the default part of an item. This will immediately break our user interface updates.
  • If you want to add a new slot that can be used by the user interface, your MUST support Query- and PutValue. At least the default value 0 must be implemented.
  • Never use other arguments to call a slot than the ones that are declared in your SDI file. The conversion methods in sfx2 use the type description of the slot to map UNO types to items and cannot do this for unknown arguments.
Personal tools