Difference between revisions of "Framework/Article/Tool Panels Internals"

From Apache OpenOffice Wiki
Jump to: navigation, search
(OpenOffice.org Tool Panels Internals)
(Replaced content with "= OpenOffice.org Tool Panels Internals = Category:Framework:Article")
Line 1: Line 1:
 
= OpenOffice.org Tool Panels Internals =
 
= OpenOffice.org Tool Panels Internals =
  
=User interface controllers in the mixed sfx2/uno environment=
 
  
==How user interface controllers work in a pure UNO based environment?==
 
 
[[Image:EnvironmentPureUnoUserInterfaceController.png]]
 
 
==How user interface controllers work in our mixed sfx2/UNO based environment?==
 
 
[[Image:EnvironmentUserInterfaceController.png]]
 
 
 
Let's see what happens in more detail, especially when we switch from one layer to another one.
 
 
# A shell wants to invalidate a slot and calls SfxShell::Invalidate( SlotID ).
 
# The bindings updates the SfxStateCache for the provided slot ID normally through a update timer or directly.
 
# The SfxStateCache calls StateChanged with the new state on a SfxDispatchController_Impl object.
 
# The SfxDispatchController_Impl now maps the sfx2 state information based on SfxPoolItem to UNO information and sends them to UNO based toolbar controller.
 
 
<source lang="cpp">
 
...
 
 
::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();
 
    }
 
  }
 
}
 
 
...
 
</source>
 
 
How does QueryValue work and convert an item to UNO com::sun::star::uno::any?
 
 
<br />
 
 
You can find the base class of any pool item in ''svtools/inc/poolitem.hxx''
 
 
<source lang="cpp">
 
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.!!
 
};
 
</source>
 
 
A example how to implement QueryValue can be found in the implementation of the SvxULSpaceItem (located in svx/source/items/frmitems.cxx).
 
 
<source lang="cpp">
 
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;
 
}
 
</source>
 
 
# 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).
 
 
<source lang="cpp">
 
// 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;
 
        }
 
    }
 
}
 
</source>
 
 
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:
 
 
<source lang="cpp">
 
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;
 
}
 
</source>
 
 
'''''We should now see some very important rules that this conversion can work correctly.'''''
 
 
<br />
 
 
* 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.
 
  
 
[[Category:Framework:Article]]
 
[[Category:Framework:Article]]

Revision as of 07:14, 2 May 2012

OpenOffice.org Tool Panels Internals

Personal tools