Files
libreoffice/svx/source/form/fmtextcontrolshell.cxx
Kurt Zenker 99efc0ba1f CWS-TOOLING: integrate CWS dba32h
2009-10-12 12:21:44 +0200 msc  r276827 : remove warning for issue 102712 because the issue is fixed
2009-10-05 07:14:20 +0200 oj  r276658 : #105585# add missing dependency for OOO_UI
2009-10-02 12:50:19 +0200 fs  r276632 : #i105505#
If a model is created, and is a revenant of a previous incarnation, then ensure it is properly initialized.
In particular, in its ctor, set the state to "Initializing", not "Initialized", and then let the ModelImpl
call attachResource. This ensures that the model is initialized completely, including firing the necessary
events.
2009-10-02 12:46:12 +0200 fs  r276631 : #i105505# always do an attachResource at the newly loaded model, even if it (internally) was not really loaded, but only a revenant of a previous incarnation of this document
2009-10-01 13:09:07 +0200 fs  r276596 : do not rely on the name 'Standard' for the one and only form in a document
2009-10-01 12:35:56 +0200 fs  r276589 : #i105509# don't rely on default form component names, use indexes
2009-10-01 11:19:18 +0200 fs  r276584 : copying the fix for #i105082# into this CWS
2009-10-01 11:13:22 +0200 fs  r276583 : improved logs
2009-10-01 11:10:44 +0200 fs  r276581 : #i105505#
2009-10-01 08:07:57 +0200 fs  r276575 : manual merge of trunk, to allow cwslocalize to run
2009-09-30 22:48:30 +0200 fs  r276574 : removed that strange ONLOAD definition
2009-09-30 12:58:18 +0200 fs  r276553 : copy fix for #i105387# into this CWS, as the issue prevents us from finalizing the CWS
2009-09-30 12:56:45 +0200 fs  r276552 : copy fix for #i105387# into this CWS, as the issue prevents us from finalizing the CWS
2009-09-30 11:47:45 +0200 fs  r276549 : #i105235#
2009-09-29 12:27:40 +0200 fs  r276521 : #i105367#
2009-09-28 12:08:17 +0200 oj  r276485 : #i105371# export version in manifest.xml as well
2009-09-28 12:07:02 +0200 oj  r276484 : #i105371# export version in manifest.xml as well
2009-09-28 09:48:01 +0200 oj  r276481 : #i105366# init drivers when not empty
2009-09-25 14:31:27 +0200 fs  r276466 : CWS-TOOLING: rebase CWS dba32h to trunk@276429 (milestone: DEV300:m60)
2009-09-24 13:52:54 +0200 fs  r276422 : #i105234# do not zoom the control when they view information is still uninitialized (happens at least in Writer when opening a form document)
2009-09-24 11:42:03 +0200 fs  r276413 : #i105234# proper zoom handling for the nav bar
2009-09-24 11:41:40 +0200 fs  r276412 : #i105234# setZoom: care for precision errors caused by implicit conversion float->double
2009-09-23 12:21:22 +0200 oj  r276377 : remove dos lineends
2009-09-23 11:44:52 +0200 oj  r276376 : #i105216# load config on demand
2009-09-23 11:44:19 +0200 oj  r276375 : #i105216# load config on demand
2009-09-23 11:43:35 +0200 oj  r276374 : #i105216# load config on demand
2009-09-21 09:13:03 +0200 oj  r276307 : #i105158# use Thread support
2009-09-18 13:06:50 +0200 fs  r276277 : #i105147#
2009-09-18 11:48:23 +0200 oj  r276271 : #i105158# new method for thread safety
2009-09-18 10:42:56 +0200 fs  r276266 : CWS-TOOLING: rebase CWS dba32h to trunk@276192 (milestone: DEV300:m59)
2009-09-18 08:30:03 +0200 oj  r276263 : #i105016# load correct ldap so
2009-09-17 13:42:31 +0200 oj  r276240 : change count of check boxes
2009-09-17 13:32:59 +0200 oj  r276239 : revert false to true for currency
2009-09-17 09:14:46 +0200 oj  r276220 : #i104901# add patch for every issue
2009-09-17 09:10:29 +0200 oj  r276219 : #i104901# add patch for every issue
2009-09-11 13:47:49 +0200 oj  r276060 : #i104901# fix for indentity
2009-09-11 12:14:14 +0200 fs  r276056 : #i104594# allow to render controls without an SdrPageView
2009-09-11 11:49:31 +0200 fs  r276055 : CWS-TOOLING: rebase CWS dba32h to trunk@276043 (milestone: DEV300:m58)
2009-09-10 08:41:40 +0200 oj  r276021 : #i104911# export variable-set not for repeating sections
2009-10-14 18:48:09 +00:00

1401 lines
56 KiB
C++

/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2008 by Sun Microsystems, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: fmtextcontrolshell.cxx,v $
* $Revision: 1.16.86.1 $
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"
#include "fmprop.hrc"
#include "fmresids.hrc"
#include "fmtextcontroldialogs.hxx"
#include "fmtextcontrolfeature.hxx"
#include "fmtextcontrolshell.hxx"
#include "svx/crsditem.hxx"
#include "svx/dialmgr.hxx"
#include "svx/editeng.hxx"
#include "svx/eeitem.hxx"
#include "svx/fmglob.hxx"
#include "svx/scriptspaceitem.hxx"
#include "svx/svxids.hrc"
#include "svx/udlnitem.hxx"
/** === begin UNO includes === **/
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/awt/FontDescriptor.hpp>
#include <com/sun/star/frame/XDispatchProvider.hpp>
#include <com/sun/star/form/XForm.hpp>
#include <com/sun/star/container/XChild.hpp>
#include <com/sun/star/awt/XFocusListener.hpp>
#include <com/sun/star/awt/XMouseListener.hpp>
/** === end UNO includes === **/
#include <comphelper/componentcontext.hxx>
#include <comphelper/processfactory.hxx>
#include <cppuhelper/implbase1.hxx>
#include <sfx2/app.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/msgpool.hxx>
#include <sfx2/objsh.hxx>
#include <sfx2/request.hxx>
#include <sfx2/sfxuno.hxx>
#include <sfx2/viewfrm.hxx>
#include <svtools/eitem.hxx>
#include <svtools/intitem.hxx>
#include <svtools/itempool.hxx>
#include <svtools/languageoptions.hxx>
#include <svtools/stringtransfer.hxx>
#include <svtools/whiter.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <tools/diagnose_ex.h>
#include <vcl/msgbox.hxx>
#include <vcl/outdev.hxx>
#include <vos/mutex.hxx>
#include <memory>
//........................................................................
namespace svx
{
//........................................................................
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::awt;
using namespace ::com::sun::star::form;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::frame;
using namespace ::com::sun::star::util;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::container;
//====================================================================
typedef USHORT WhichId;
//====================================================================
static SfxSlotId pTextControlSlots[] =
{
SID_CLIPBOARD_FORMAT_ITEMS,
SID_CUT,
SID_COPY,
SID_PASTE,
SID_SELECTALL,
// SID_ATTR_TABSTOP, /* 2 */
SID_ATTR_CHAR_FONT,
SID_ATTR_CHAR_POSTURE,
SID_ATTR_CHAR_WEIGHT,
SID_ATTR_CHAR_SHADOWED,
SID_ATTR_CHAR_WORDLINEMODE,
SID_ATTR_CHAR_CONTOUR,
SID_ATTR_CHAR_STRIKEOUT,
SID_ATTR_CHAR_UNDERLINE,
SID_ATTR_CHAR_FONTHEIGHT,
SID_ATTR_CHAR_COLOR,
SID_ATTR_CHAR_KERNING,
SID_ATTR_CHAR_LANGUAGE, /* 20 */
SID_ATTR_CHAR_ESCAPEMENT,
SID_ATTR_PARA_ADJUST, /* 28 */
SID_ATTR_PARA_ADJUST_LEFT,
SID_ATTR_PARA_ADJUST_RIGHT,
SID_ATTR_PARA_ADJUST_CENTER,
SID_ATTR_PARA_ADJUST_BLOCK,
SID_ATTR_PARA_LINESPACE, /* 33 */
SID_ATTR_PARA_LINESPACE_10,
SID_ATTR_PARA_LINESPACE_15,
SID_ATTR_PARA_LINESPACE_20,
SID_ATTR_LRSPACE, /* 48 */
SID_ATTR_ULSPACE, /* 49 */
SID_ATTR_CHAR_AUTOKERN,
SID_ATTR_CHAR_OVERLINE,
SID_SET_SUPER_SCRIPT,
SID_SET_SUB_SCRIPT,
SID_CHAR_DLG,
SID_PARA_DLG,
// SID_TEXTDIRECTION_LEFT_TO_RIGHT, /* 907 */
// SID_TEXTDIRECTION_TOP_TO_BOTTOM,
SID_ATTR_CHAR_SCALEWIDTH, /* 911 */
SID_ATTR_CHAR_RELIEF,
SID_ATTR_PARA_LEFT_TO_RIGHT, /* 950 */
SID_ATTR_PARA_RIGHT_TO_LEFT,
0
};
// slots which we are not responsible for on the SfxShell level, but
// need to handle during the "paragraph attributes" and/or "character
// attributes" dialogs
static SfxSlotId pDialogSlots[] =
{
SID_ATTR_TABSTOP,
SID_ATTR_PARA_HANGPUNCTUATION,
SID_ATTR_PARA_FORBIDDEN_RULES,
SID_ATTR_PARA_SCRIPTSPACE,
SID_ATTR_CHAR_LATIN_LANGUAGE,
SID_ATTR_CHAR_CJK_LANGUAGE,
SID_ATTR_CHAR_CTL_LANGUAGE,
SID_ATTR_CHAR_LATIN_FONT,
SID_ATTR_CHAR_CJK_FONT,
SID_ATTR_CHAR_CTL_FONT,
SID_ATTR_CHAR_LATIN_FONTHEIGHT,
SID_ATTR_CHAR_CJK_FONTHEIGHT,
SID_ATTR_CHAR_CTL_FONTHEIGHT,
SID_ATTR_CHAR_LATIN_WEIGHT,
SID_ATTR_CHAR_CJK_WEIGHT,
SID_ATTR_CHAR_CTL_WEIGHT,
SID_ATTR_CHAR_LATIN_POSTURE,
SID_ATTR_CHAR_CJK_POSTURE,
SID_ATTR_CHAR_CTL_POSTURE,
SID_ATTR_CHAR_EMPHASISMARK,
0
};
//====================================================================
//= FmFocusListenerAdapter
//====================================================================
typedef ::cppu::WeakImplHelper1 < XFocusListener
> FmFocusListenerAdapter_Base;
class FmFocusListenerAdapter : public FmFocusListenerAdapter_Base
{
private:
IFocusObserver* m_pObserver;
Reference< XWindow > m_xWindow;
public:
FmFocusListenerAdapter( const Reference< XControl >& _rxControl, IFocusObserver* _pObserver );
// clean up the instance
void dispose();
protected:
~FmFocusListenerAdapter();
protected:
virtual void SAL_CALL focusGained( const FocusEvent& e ) throw (RuntimeException);
virtual void SAL_CALL focusLost( const FocusEvent& e ) throw (RuntimeException);
virtual void SAL_CALL disposing( const EventObject& Source ) throw (RuntimeException);
};
//--------------------------------------------------------------------
DBG_NAME( FmFocusListenerAdapter )
//--------------------------------------------------------------------
FmFocusListenerAdapter::FmFocusListenerAdapter( const Reference< XControl >& _rxControl, IFocusObserver* _pObserver )
:m_pObserver( _pObserver )
,m_xWindow( _rxControl, UNO_QUERY )
{
DBG_CTOR( FmFocusListenerAdapter, NULL );
DBG_ASSERT( m_xWindow.is(), "FmFocusListenerAdapter::FmFocusListenerAdapter: invalid control!" );
osl_incrementInterlockedCount( &m_refCount );
{
try
{
if ( m_xWindow.is() )
m_xWindow->addFocusListener( this );
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION();
}
}
osl_decrementInterlockedCount( &m_refCount );
}
//--------------------------------------------------------------------
FmFocusListenerAdapter::~FmFocusListenerAdapter()
{
acquire();
dispose();
DBG_DTOR( FmFocusListenerAdapter, NULL );
}
//--------------------------------------------------------------------
void FmFocusListenerAdapter::dispose()
{
if ( m_xWindow.is() )
{
m_xWindow->removeFocusListener( this );
m_xWindow.clear();
}
}
//--------------------------------------------------------------------
void SAL_CALL FmFocusListenerAdapter::focusGained( const FocusEvent& e ) throw (RuntimeException)
{
if ( m_pObserver )
m_pObserver->focusGained( e );
}
//--------------------------------------------------------------------
void SAL_CALL FmFocusListenerAdapter::focusLost( const FocusEvent& e ) throw (RuntimeException)
{
if ( m_pObserver )
m_pObserver->focusLost( e );
}
//--------------------------------------------------------------------
void SAL_CALL FmFocusListenerAdapter::disposing( const EventObject& Source ) throw (RuntimeException)
{
(void)Source;
DBG_ASSERT( Source.Source == m_xWindow, "FmFocusListenerAdapter::disposing: where did this come from?" );
m_xWindow.clear();
}
//====================================================================
//= FmMouseListenerAdapter
//====================================================================
typedef ::cppu::WeakImplHelper1 < XMouseListener
> FmMouseListenerAdapter_Base;
class FmMouseListenerAdapter : public FmMouseListenerAdapter_Base
{
private:
IContextRequestObserver* m_pObserver;
Reference< XWindow > m_xWindow;
public:
FmMouseListenerAdapter( const Reference< XControl >& _rxControl, IContextRequestObserver* _pObserver );
// clean up the instance
void dispose();
protected:
~FmMouseListenerAdapter();
protected:
virtual void SAL_CALL mousePressed( const awt::MouseEvent& e ) throw (RuntimeException);
virtual void SAL_CALL mouseReleased( const awt::MouseEvent& e ) throw (RuntimeException);
virtual void SAL_CALL mouseEntered( const awt::MouseEvent& e ) throw (RuntimeException);
virtual void SAL_CALL mouseExited( const awt::MouseEvent& e ) throw (RuntimeException);
virtual void SAL_CALL disposing( const EventObject& Source ) throw (RuntimeException);
};
//====================================================================
//= FmMouseListenerAdapter
//====================================================================
//--------------------------------------------------------------------
DBG_NAME( FmMouseListenerAdapter )
//--------------------------------------------------------------------
FmMouseListenerAdapter::FmMouseListenerAdapter( const Reference< XControl >& _rxControl, IContextRequestObserver* _pObserver )
:m_pObserver( _pObserver )
,m_xWindow( _rxControl, UNO_QUERY )
{
DBG_CTOR( FmMouseListenerAdapter, NULL );
DBG_ASSERT( m_xWindow.is(), "FmMouseListenerAdapter::FmMouseListenerAdapter: invalid control!" );
osl_incrementInterlockedCount( &m_refCount );
{
try
{
if ( m_xWindow.is() )
m_xWindow->addMouseListener( this );
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION();
}
}
osl_decrementInterlockedCount( &m_refCount );
}
//--------------------------------------------------------------------
FmMouseListenerAdapter::~FmMouseListenerAdapter()
{
acquire();
dispose();
DBG_DTOR( FmMouseListenerAdapter, NULL );
}
//--------------------------------------------------------------------
void FmMouseListenerAdapter::dispose()
{
if ( m_xWindow.is() )
{
m_xWindow->removeMouseListener( this );
m_xWindow.clear();
}
}
//--------------------------------------------------------------------
void SAL_CALL FmMouseListenerAdapter::mousePressed( const awt::MouseEvent& _rEvent ) throw (::com::sun::star::uno::RuntimeException)
{
::vos::OGuard aGuard( Application::GetSolarMutex() );
// is this a request for a context menu?
if ( _rEvent.PopupTrigger )
{
if ( m_pObserver )
m_pObserver->contextMenuRequested( _rEvent );
}
}
//--------------------------------------------------------------------
void SAL_CALL FmMouseListenerAdapter::mouseReleased( const awt::MouseEvent& /*e*/ ) throw (::com::sun::star::uno::RuntimeException)
{
// not interested in
}
//--------------------------------------------------------------------
void SAL_CALL FmMouseListenerAdapter::mouseEntered( const awt::MouseEvent& /*e*/ ) throw (::com::sun::star::uno::RuntimeException)
{
// not interested in
}
//--------------------------------------------------------------------
void SAL_CALL FmMouseListenerAdapter::mouseExited( const awt::MouseEvent& /*e*/ ) throw (::com::sun::star::uno::RuntimeException)
{
// not interested in
}
//--------------------------------------------------------------------
void SAL_CALL FmMouseListenerAdapter::disposing( const EventObject& Source ) throw (RuntimeException)
{
(void)Source;
DBG_ASSERT( Source.Source == m_xWindow, "FmMouseListenerAdapter::disposing: where did this come from?" );
m_xWindow.clear();
}
//====================================================================
//= FmTextControlShell
//====================================================================
//------------------------------------------------------------------------
namespace
{
//....................................................................
void lcl_translateUnoStateToItem( SfxSlotId _nSlot, const Any& _rUnoState, SfxItemSet& _rSet )
{
WhichId nWhich = _rSet.GetPool()->GetWhich( _nSlot );
if ( !_rUnoState.hasValue() )
{
if ( ( _nSlot != SID_CUT )
&& ( _nSlot != SID_COPY )
&& ( _nSlot != SID_PASTE )
)
{
_rSet.InvalidateItem( nWhich );
}
}
else
{
switch ( _rUnoState.getValueType().getTypeClass() )
{
case TypeClass_BOOLEAN:
{
sal_Bool bState = sal_False;
_rUnoState >>= bState;
if ( _nSlot == SID_ATTR_PARA_SCRIPTSPACE )
_rSet.Put( SvxScriptSpaceItem( bState, nWhich ) );
else
_rSet.Put( SfxBoolItem( nWhich, bState ) );
}
break;
default:
{
Sequence< PropertyValue > aComplexState;
if ( _rUnoState >>= aComplexState )
{
if ( !aComplexState.getLength() )
_rSet.InvalidateItem( nWhich );
else
{
SfxAllItemSet aAllItems( _rSet );
TransformParameters( _nSlot, aComplexState, aAllItems );
const SfxPoolItem* pTransformed = aAllItems.GetItem( nWhich );
OSL_ENSURE( pTransformed, "lcl_translateUnoStateToItem: non-empty parameter sequence leading to empty item?" );
if ( pTransformed )
_rSet.Put( *pTransformed );
else
_rSet.InvalidateItem( nWhich );
}
}
else
{
DBG_ERROR( "lcl_translateUnoStateToItem: invalid state!" );
}
}
}
}
}
//....................................................................
::rtl::OUString lcl_getUnoSlotName( SfxApplication&, SfxSlotId _nSlotId )
{
::rtl::OUString sSlotUnoName;
SfxSlotPool& rSlotPool = SfxSlotPool::GetSlotPool( NULL );
const SfxSlot* pSlot = rSlotPool.GetSlot( _nSlotId );
const sal_Char* pAsciiUnoName = NULL;
if ( pSlot )
{
pAsciiUnoName = pSlot->GetUnoName();
}
else
{
// some hard-coded slots, which do not have a UNO name at SFX level, but which
// we nevertheless need to transport via UNO mechanisms, so we need a name
switch ( _nSlotId )
{
case SID_ATTR_PARA_HANGPUNCTUATION: pAsciiUnoName = "AllowHangingPunctuation"; break;
case SID_ATTR_PARA_FORBIDDEN_RULES: pAsciiUnoName = "ApplyForbiddenCharacterRules"; break;
case SID_ATTR_PARA_SCRIPTSPACE: pAsciiUnoName = "UseScriptSpacing"; break;
}
}
if ( pAsciiUnoName )
{
sSlotUnoName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:" ) );
sSlotUnoName += ::rtl::OUString::createFromAscii( pAsciiUnoName );
}
#if OSL_DEBUG_LEVEL > 0
else
{
::rtl::OString sMessage( "lcl_getUnoSlotName: invalid slot id, or invalid slot, or no UNO name!\n" );
sMessage += "(slot id: ";
sMessage += ::rtl::OString::valueOf( (sal_Int32)_nSlotId );
sMessage += ")";
DBG_ERROR( sMessage );
}
#endif
return sSlotUnoName;
}
//....................................................................
bool lcl_determineReadOnly( const Reference< XControl >& _rxControl )
{
bool bIsReadOnlyModel = true;
try
{
Reference< XPropertySet > xModelProps;
if ( _rxControl.is() )
xModelProps = xModelProps.query( _rxControl->getModel() );
Reference< XPropertySetInfo > xModelPropInfo;
if ( xModelProps.is() )
xModelPropInfo = xModelProps->getPropertySetInfo();
if ( !xModelPropInfo.is() || !xModelPropInfo->hasPropertyByName( FM_PROP_READONLY ) )
bIsReadOnlyModel = true;
else
{
sal_Bool bReadOnly = sal_True;
xModelProps->getPropertyValue( FM_PROP_READONLY ) >>= bReadOnly;
bIsReadOnlyModel = bReadOnly;
}
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION();
}
return bIsReadOnlyModel;
}
//....................................................................
static Window* lcl_getWindow( const Reference< XControl >& _rxControl )
{
Window* pWindow = NULL;
try
{
Reference< XWindowPeer > xControlPeer;
if ( _rxControl.is() )
xControlPeer = _rxControl->getPeer();
if ( xControlPeer.is() )
pWindow = VCLUnoHelper::GetWindow( xControlPeer );
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION();
}
return pWindow;
}
//....................................................................
bool lcl_isRichText( const Reference< XControl >& _rxControl )
{
if ( !_rxControl.is() )
return false;
bool bIsRichText = false;
try
{
Reference< XPropertySet > xModelProps( _rxControl->getModel(), UNO_QUERY );
Reference< XPropertySetInfo > xPSI;
if ( xModelProps.is() )
xPSI = xModelProps->getPropertySetInfo();
::rtl::OUString sRichTextPropertyName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "RichText" ) );
if ( xPSI.is() && xPSI->hasPropertyByName( sRichTextPropertyName ) )
{
OSL_VERIFY( xModelProps->getPropertyValue( sRichTextPropertyName ) >>= bIsRichText );
}
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION();
}
return bIsRichText;
}
}
//------------------------------------------------------------------------
FmTextControlShell::FmTextControlShell( SfxViewFrame* _pFrame )
:m_bActiveControl( false )
,m_bActiveControlIsReadOnly( true )
,m_bActiveControlIsRichText( false )
,m_pViewFrame( _pFrame )
,m_rBindings( _pFrame->GetBindings() )
,m_bNeedClipboardInvalidation( true )
{
m_aClipboardInvalidation.SetTimeoutHdl( LINK( this, FmTextControlShell, OnInvalidateClipboard ) );
m_aClipboardInvalidation.SetTimeout( 200 );
}
//------------------------------------------------------------------------
FmTextControlShell::~FmTextControlShell()
{
dispose();
}
//------------------------------------------------------------------------
IMPL_LINK( FmTextControlShell, OnInvalidateClipboard, void*, /*_pNotInterestedIn*/ )
{
if ( m_bNeedClipboardInvalidation )
{
DBG_TRACE( "FmTextControlShell::ClipBoard: invalidating clipboard slots" );
m_rBindings.Invalidate( SID_CUT );
m_rBindings.Invalidate( SID_COPY );
m_rBindings.Invalidate( SID_PASTE );
m_bNeedClipboardInvalidation = false;
}
return 0L;
}
//------------------------------------------------------------------------
void FmTextControlShell::transferFeatureStatesToItemSet( ControlFeatures& _rDispatchers, SfxAllItemSet& _rSet, bool _bTranslateLatin )
{
SfxItemPool& rPool = *_rSet.GetPool();
for ( ControlFeatures::const_iterator aFeature = _rDispatchers.begin();
aFeature != _rDispatchers.end();
++aFeature
)
{
SfxSlotId nSlotId( aFeature->first );
#if OSL_DEBUG_LEVEL > 0
::rtl::OUString sUnoSlotName;
if ( SFX_APP() )
sUnoSlotName = lcl_getUnoSlotName( *SFX_APP(), nSlotId );
else
sUnoSlotName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "<unknown>" ) );
::rtl::OString sUnoSlotNameAscii( "\"" );
sUnoSlotNameAscii += ::rtl::OString( sUnoSlotName.getStr(), sUnoSlotName.getLength(), RTL_TEXTENCODING_ASCII_US );
sUnoSlotNameAscii += "\"";
#endif
if ( _bTranslateLatin )
{
// A rich text control offers a dispatcher for the "Font" slot/feature.
// Sadly, the semantics of the dispatches is that the feature "Font" depends
// on the current cursor position: If it's on latin text, it's the "latin font"
// which is set up at the control. If it's on CJK text, it's the "CJK font", and
// aequivalent for "CTL font".
// The same holds for some other font related features/slots.
// Thus, we have separate dispatches for "Latin Font", "Latin Font Size", etc,
// which are only "virtual", in a sense that there exist no item with this id.
// So when we encounter such a dispatcher for, say, "Latin Font", we need to
// put an item into the set which has the "Font" id.
switch ( nSlotId )
{
case SID_ATTR_CHAR_LATIN_FONT: nSlotId = SID_ATTR_CHAR_FONT; break;
case SID_ATTR_CHAR_LATIN_FONTHEIGHT:nSlotId = SID_ATTR_CHAR_FONTHEIGHT; break;
case SID_ATTR_CHAR_LATIN_LANGUAGE: nSlotId = SID_ATTR_CHAR_LANGUAGE; break;
case SID_ATTR_CHAR_LATIN_POSTURE: nSlotId = SID_ATTR_CHAR_POSTURE; break;
case SID_ATTR_CHAR_LATIN_WEIGHT: nSlotId = SID_ATTR_CHAR_WEIGHT; break;
}
}
WhichId nWhich = rPool.GetWhich( nSlotId );
bool bIsInPool = rPool.IsInRange( nWhich );
if ( bIsInPool )
{
#if OSL_DEBUG_LEVEL > 0
bool bFeatureIsEnabled = aFeature->second->isFeatureEnabled();
::rtl::OString sMessage( "FmTextControlShell::transferFeatureStatesToItemSet: found a feature state for " );
sMessage += sUnoSlotNameAscii;
if ( !bFeatureIsEnabled )
sMessage += " (disabled)";
DBG_TRACE( sMessage );
#endif
lcl_translateUnoStateToItem( nSlotId, aFeature->second->getFeatureState(), _rSet );
}
#if OSL_DEBUG_LEVEL > 0
else
{
::rtl::OString sMessage( "FmTextControlShell::transferFeatureStatesToItemSet: found a feature state for " );
sMessage += sUnoSlotNameAscii;
sMessage += ", but could not translate it into an item!";
DBG_TRACE( sMessage );
}
#endif
}
}
//------------------------------------------------------------------------
void FmTextControlShell::executeAttributeDialog( AttributeSet _eSet, SfxRequest& _rReq )
{
const SvxFontListItem* pFontList = PTR_CAST( SvxFontListItem, m_pViewFrame->GetObjectShell()->GetItem( SID_ATTR_CHAR_FONTLIST ) );
DBG_ASSERT( pFontList, "FmTextControlShell::executeAttributeDialog: no font list item!" );
if ( !pFontList )
return;
SfxItemPool* pPool = EditEngine::CreatePool();
pPool->FreezeIdRanges();
::std::auto_ptr< SfxItemSet > pPureItems( new SfxItemSet( *pPool ) );
// put the current states of the items into the set
::std::auto_ptr< SfxAllItemSet > pCurrentItems( new SfxAllItemSet( *pPureItems ) );
transferFeatureStatesToItemSet( m_aControlFeatures, *pCurrentItems );
// additional items, which we are not responsible for at the SfxShell level,
// but which need to be forwarded to the dialog, anyway
ControlFeatures aAdditionalFestures;
fillFeatureDispatchers( m_xActiveControl, pDialogSlots, aAdditionalFestures );
transferFeatureStatesToItemSet( aAdditionalFestures, *pCurrentItems, true );
::std::auto_ptr< SfxTabDialog > pDialog ( _eSet == eCharAttribs
? static_cast< SfxTabDialog* >( new TextControlCharAttribDialog( NULL, *pCurrentItems, *pFontList ) )
: static_cast< SfxTabDialog* >( new TextControlParaAttribDialog( NULL, *pCurrentItems ) ) );
if ( RET_OK == pDialog->Execute() )
{
const SfxItemSet& rModifiedItems = *pDialog->GetOutputItemSet();
for ( WhichId nWhich = pPool->GetFirstWhich(); nWhich <= pPool->GetLastWhich(); ++nWhich )
{
if ( rModifiedItems.GetItemState( nWhich ) == SFX_ITEM_SET )
{
SfxSlotId nSlotForItemSet = pPool->GetSlotId( nWhich );
const SfxPoolItem* pModifiedItem = rModifiedItems.GetItem( nWhich );
SfxSlotId nSlotForDispatcher = nSlotForItemSet;
switch ( nSlotForDispatcher )
{
case SID_ATTR_CHAR_FONT: nSlotForDispatcher = SID_ATTR_CHAR_LATIN_FONT; break;
case SID_ATTR_CHAR_FONTHEIGHT:nSlotForDispatcher = SID_ATTR_CHAR_LATIN_FONTHEIGHT; break;
case SID_ATTR_CHAR_LANGUAGE: nSlotForDispatcher = SID_ATTR_CHAR_LATIN_LANGUAGE; break;
case SID_ATTR_CHAR_POSTURE: nSlotForDispatcher = SID_ATTR_CHAR_LATIN_POSTURE; break;
case SID_ATTR_CHAR_WEIGHT: nSlotForDispatcher = SID_ATTR_CHAR_LATIN_WEIGHT; break;
}
// do we already have a dispatcher for this slot/feature?
ControlFeatures::const_iterator aFeaturePos = m_aControlFeatures.find( nSlotForDispatcher );
bool bFound = aFeaturePos != m_aControlFeatures.end( );
if ( !bFound )
{
aFeaturePos = aAdditionalFestures.find( nSlotForDispatcher );
bFound = aFeaturePos != aAdditionalFestures.end( );
}
if ( bFound )
{
Sequence< PropertyValue > aArgs;
// temporarily put the modified item into a "clean" set,
// and let TransformItems calc the respective UNO parameters
pPureItems->Put( *pModifiedItem );
TransformItems( nSlotForItemSet, *pPureItems, aArgs );
pPureItems->ClearItem( nWhich );
if ( ( nSlotForItemSet == SID_ATTR_PARA_HANGPUNCTUATION )
|| ( nSlotForItemSet == SID_ATTR_PARA_FORBIDDEN_RULES )
|| ( nSlotForItemSet == SID_ATTR_PARA_SCRIPTSPACE )
)
{
// these are no UNO slots, they need special handling since TransformItems cannot
// handle them
DBG_ASSERT( aArgs.getLength() == 0, "FmTextControlShell::executeAttributeDialog: these are no UNO slots - are they?" );
const SfxBoolItem* pBoolItem = PTR_CAST( SfxBoolItem, pModifiedItem );
DBG_ASSERT( pBoolItem, "FmTextControlShell::executeAttributeDialog: no bool item?!" );
if ( pBoolItem )
{
aArgs.realloc( 1 );
aArgs[ 0 ].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Enable" ) );
aArgs[ 0 ].Value <<= (sal_Bool)pBoolItem->GetValue();
}
}
// dispatch this
aFeaturePos->second->dispatch( aArgs );
}
#if OSL_DEBUG_LEVEL > 0
else
{
::rtl::OString sError( "FmTextControShell::executeAttributeDialog: Could not handle the following item:" );
sError += "\n SlotID: "; sError += ::rtl::OString::valueOf( (sal_Int32)nSlotForItemSet );
sError += "\n WhichID: "; sError += ::rtl::OString::valueOf( (sal_Int32)nWhich );
sError += "\n UNO name: ";
::rtl::OUString sUnoSlotName = lcl_getUnoSlotName( *SFX_APP(), nSlotForItemSet );
if ( sUnoSlotName.getLength() )
sError += ::rtl::OString( sUnoSlotName.getStr(), sUnoSlotName.getLength(), RTL_TEXTENCODING_ASCII_US );
else
sError += "unknown (no SfxSlot)";
DBG_ERROR( sError.getStr() );
}
#endif
}
}
_rReq.Done( rModifiedItems );
}
pDialog.reset();
pCurrentItems.reset();
pPureItems.reset();
SfxItemPool::Free(pPool);
}
//------------------------------------------------------------------------
bool FmTextControlShell::executeSelectAll( )
{
try
{
if ( m_xActiveTextComponent.is() )
{
sal_Int32 nTextLen = m_xActiveTextComponent->getText().getLength();
m_xActiveTextComponent->setSelection( awt::Selection( 0, nTextLen ) );
return true;
}
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION();
}
return false; // not handled
}
//------------------------------------------------------------------------
bool FmTextControlShell::executeClipboardSlot( SfxSlotId _nSlot )
{
try
{
if ( m_xActiveTextComponent.is() )
{
switch ( _nSlot )
{
case SID_COPY:
case SID_CUT:
{
::rtl::OUString sSelectedText( m_xActiveTextComponent->getSelectedText() );
::svt::OStringTransfer::CopyString( sSelectedText, lcl_getWindow( m_xActiveControl ) );
if ( SID_CUT == _nSlot )
{
awt::Selection aSelection( m_xActiveTextComponent->getSelection() );
m_xActiveTextComponent->insertText( aSelection, ::rtl::OUString() );
}
}
break;
case SID_PASTE:
{
::rtl::OUString sClipboardContent;
OSL_VERIFY( ::svt::OStringTransfer::PasteString( sClipboardContent, lcl_getWindow( m_xActiveControl ) ) );
awt::Selection aSelection( m_xActiveTextComponent->getSelection() );
m_xActiveTextComponent->insertText( aSelection, sClipboardContent );
}
break;
default:
OSL_ENSURE( sal_False, "FmTextControlShell::executeClipboardSlot: invalid slot!" );
}
return true;
}
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION();
}
return false; // not handled
}
//------------------------------------------------------------------------
void FmTextControlShell::ExecuteTextAttribute( SfxRequest& _rReq )
{
SfxSlotId nSlot = _rReq.GetSlot();
ControlFeatures::const_iterator aFeaturePos = m_aControlFeatures.find( nSlot );
if ( aFeaturePos == m_aControlFeatures.end() )
{
// special slots
switch ( nSlot )
{
case SID_CHAR_DLG:
executeAttributeDialog( eCharAttribs, _rReq );
break;
case SID_PARA_DLG:
executeAttributeDialog( eParaAttribs, _rReq );
break;
case SID_SELECTALL:
executeSelectAll();
break;
case SID_CUT:
case SID_COPY:
case SID_PASTE:
executeClipboardSlot( nSlot );
break;
default:
DBG_ASSERT( aFeaturePos != m_aControlFeatures.end(), "FmTextControShell::ExecuteTextAttribute: I have no such dispatcher, and cannot handle it at all!" );
return;
}
}
else
{
// slots which are dispatched to the control
switch ( nSlot )
{
case SID_ATTR_CHAR_STRIKEOUT:
case SID_ATTR_CHAR_UNDERLINE:
case SID_ATTR_CHAR_OVERLINE:
{
SfxItemSet aToggled( *_rReq.GetArgs() );
lcl_translateUnoStateToItem( nSlot, aFeaturePos->second->getFeatureState(), aToggled );
WhichId nWhich = aToggled.GetPool()->GetWhich( nSlot );
const SfxPoolItem* pItem = aToggled.GetItem( nWhich );
if ( ( SID_ATTR_CHAR_UNDERLINE == nSlot ) || ( SID_ATTR_CHAR_OVERLINE == nSlot ) )
{
const SvxOverlineItem* pTextLine = PTR_CAST( SvxOverlineItem, pItem );
DBG_ASSERT( pTextLine, "FmTextControlShell::ExecuteTextAttribute: ooops - no underline/overline item!" );
if ( pTextLine )
{
FontUnderline eTL = pTextLine->GetLineStyle();
if ( SID_ATTR_CHAR_UNDERLINE == nSlot ) {
aToggled.Put( SvxUnderlineItem( eTL == UNDERLINE_SINGLE ? UNDERLINE_NONE : UNDERLINE_SINGLE, nWhich ) );
} else {
aToggled.Put( SvxOverlineItem( eTL == UNDERLINE_SINGLE ? UNDERLINE_NONE : UNDERLINE_SINGLE, nWhich ) );
}
}
}
else
{
const SvxCrossedOutItem* pCrossedOut = PTR_CAST( SvxCrossedOutItem, pItem );
DBG_ASSERT( pCrossedOut, "FmTextControlShell::ExecuteTextAttribute: ooops - no CrossedOut item!" );
if ( pCrossedOut )
{
FontStrikeout eFS = pCrossedOut->GetStrikeout();
aToggled.Put( SvxCrossedOutItem( eFS == STRIKEOUT_SINGLE ? STRIKEOUT_NONE : STRIKEOUT_SINGLE, nWhich ) );
}
}
Sequence< PropertyValue > aArguments;
TransformItems( nSlot, aToggled, aArguments );
aFeaturePos->second->dispatch( aArguments );
}
break;
case SID_ATTR_CHAR_FONTHEIGHT:
case SID_ATTR_CHAR_FONT:
case SID_ATTR_CHAR_POSTURE:
case SID_ATTR_CHAR_WEIGHT:
case SID_ATTR_CHAR_SHADOWED:
case SID_ATTR_CHAR_CONTOUR:
case SID_SET_SUPER_SCRIPT:
case SID_SET_SUB_SCRIPT:
{
const SfxItemSet* pArgs = _rReq.GetArgs();
Sequence< PropertyValue > aArgs;
if ( pArgs )
TransformItems( nSlot, *pArgs, aArgs );
aFeaturePos->second->dispatch( aArgs );
}
break;
default:
if ( aFeaturePos->second->isFeatureEnabled() )
aFeaturePos->second->dispatch();
break;
}
}
_rReq.Done();
}
//------------------------------------------------------------------------
void FmTextControlShell::GetTextAttributeState( SfxItemSet& _rSet )
{
SfxWhichIter aIter( _rSet );
sal_uInt16 nSlot = aIter.FirstWhich();
while ( nSlot )
{
if ( ( nSlot == SID_ATTR_PARA_LEFT_TO_RIGHT )
|| ( nSlot == SID_ATTR_PARA_RIGHT_TO_LEFT )
)
{
if ( !SvtLanguageOptions().IsCTLFontEnabled() )
{
_rSet.DisableItem( nSlot );
nSlot = aIter.NextWhich();
continue;
}
}
ControlFeatures::const_iterator aFeaturePos = m_aControlFeatures.find( nSlot );
if ( aFeaturePos != m_aControlFeatures.end() )
{
if ( aFeaturePos->second->isFeatureEnabled() )
lcl_translateUnoStateToItem( nSlot, aFeaturePos->second->getFeatureState(), _rSet );
else
_rSet.DisableItem( nSlot );
}
else
{
bool bDisable = false;
bool bNeedWriteableControl = false;
bool bNeedTextComponent = false;
bool bNeedSelection = false;
switch ( nSlot )
{
case SID_CHAR_DLG:
case SID_PARA_DLG:
bDisable |= m_aControlFeatures.empty();
bNeedWriteableControl = true;
break;
case SID_CUT:
bNeedSelection = true;
bNeedTextComponent = true;
bNeedWriteableControl = true;
DBG_TRACE( "FmTextControlShell::ClipBoard: need to invalidate again" );
m_bNeedClipboardInvalidation = true;
break;
case SID_PASTE:
{
Window* pActiveControlVCLWindow = lcl_getWindow( m_xActiveControl );
if ( pActiveControlVCLWindow )
{
TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pActiveControlVCLWindow) );
bDisable |= !aDataHelper.HasFormat( SOT_FORMAT_STRING );
}
else
bDisable |= true;
bNeedTextComponent = true;
bNeedWriteableControl = true;
}
break;
case SID_COPY:
bNeedTextComponent = true;
bNeedSelection = true;
break;
case SID_SELECTALL:
bNeedTextComponent = true;
break;
default:
// slot is unknown at all
bDisable |= true;
break;
}
OSL_POSTCOND( !bNeedSelection || bNeedTextComponent, "FmTextControlShell::GetTextAttributeState: bNeedSelection should imply bNeedTextComponent!" );
if ( !bDisable && bNeedWriteableControl )
bDisable |= !IsActiveControl( ) || m_bActiveControlIsReadOnly;
if ( !bDisable && bNeedTextComponent )
bDisable |= !m_xActiveTextComponent.is();
if ( !bDisable && bNeedSelection )
{
awt::Selection aSelection = m_xActiveTextComponent->getSelection();
bDisable |= aSelection.Min == aSelection.Max;
}
if ( bDisable )
_rSet.DisableItem( nSlot );
}
nSlot = aIter.NextWhich();
}
}
//------------------------------------------------------------------------
bool FmTextControlShell::IsActiveControl( bool _bCountRichTextOnly ) const
{
if ( _bCountRichTextOnly && !m_bActiveControlIsRichText )
return false;
return m_bActiveControl;
}
//------------------------------------------------------------------------
void FmTextControlShell::dispose()
{
if ( IsActiveControl() )
controlDeactivated();
if ( isControllerListening() )
stopControllerListening();
}
//------------------------------------------------------------------------
void FmTextControlShell::designModeChanged( bool /*_bNewDesignMode*/ )
{
m_rBindings.Invalidate( pTextControlSlots );
}
//------------------------------------------------------------------------
void FmTextControlShell::formActivated( const Reference< XFormController >& _rxController )
{
#if OSL_DEBUG_LEVEL > 0
::rtl::OString sTrace( "FmTextControlShell::formActivated: 0x" );
sTrace += ::rtl::OString::valueOf( (sal_IntPtr)_rxController.get(), 16 );
DBG_TRACE( sTrace );
#endif
DBG_ASSERT( _rxController.is(), "FmTextControlShell::formActivated: invalid controller!" );
if ( !_rxController.is() )
return;
// sometimes, a form controller notifies activations, even if it's already activated
if ( m_xActiveController == _rxController )
return;
try
{
startControllerListening( _rxController );
controlActivated( _rxController->getCurrentControl() );
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION();
}
}
//------------------------------------------------------------------------
void FmTextControlShell::formDeactivated( const Reference< XFormController >& _rxController )
{
#if OSL_DEBUG_LEVEL > 0
::rtl::OString sTrace( "FmTextControlShell::formDeactivated: 0x" );
sTrace += ::rtl::OString::valueOf( (sal_IntPtr)_rxController.get(), 16 );
DBG_TRACE( sTrace );
#endif
(void)_rxController;
if ( IsActiveControl() )
controlDeactivated();
if ( isControllerListening() )
stopControllerListening();
}
//------------------------------------------------------------------------
void FmTextControlShell::startControllerListening( const Reference< XFormController >& _rxController )
{
OSL_PRECOND( _rxController.is(), "FmTextControlShell::startControllerListening: invalid controller!" );
if ( !_rxController.is() )
return;
OSL_PRECOND( !isControllerListening(), "FmTextControlShell::startControllerListening: already listening!" );
if ( isControllerListening() )
stopControllerListening( );
DBG_ASSERT( !isControllerListening(), "FmTextControlShell::startControllerListening: inconsistence!" );
try
{
Sequence< Reference< XControl > > aControls( _rxController->getControls() );
m_aControlObservers.resize( 0 );
m_aControlObservers.reserve( aControls.getLength() );
const Reference< XControl >* pControls = aControls.getConstArray();
const Reference< XControl >* pControlsEnd = pControls + aControls.getLength();
for ( ; pControls != pControlsEnd; ++pControls )
{
m_aControlObservers.push_back( FocusListenerAdapter( new FmFocusListenerAdapter( *pControls, this ) ) );
}
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION();
}
m_xActiveController = _rxController;
}
//------------------------------------------------------------------------
void FmTextControlShell::stopControllerListening( )
{
OSL_PRECOND( isControllerListening(), "FmTextControlShell::stopControllerListening: inconsistence!" );
// dispose all listeners associated with the controls of the active controller
for ( FocusListenerAdapters::iterator aLoop = m_aControlObservers.begin();
aLoop != m_aControlObservers.end();
++aLoop
)
{
(*aLoop)->dispose();
}
FocusListenerAdapters aEmpty;
m_aControlObservers.swap( aEmpty );
m_xActiveController.clear();
}
//------------------------------------------------------------------------
void FmTextControlShell::implClearActiveControlRef()
{
// no more features for this control
for ( ControlFeatures::iterator aLoop = m_aControlFeatures.begin();
aLoop != m_aControlFeatures.end();
++aLoop
)
{
aLoop->second->dispose();
}
ControlFeatures aEmpty;
m_aControlFeatures.swap( aEmpty );
if ( m_aContextMenuObserver.get() )
{
m_aContextMenuObserver->dispose();
m_aContextMenuObserver = MouseListenerAdapter();
}
if ( m_xActiveTextComponent.is() )
{
DBG_TRACE( "FmTextControlShell::ClipBoard: stopping timer for clipboard invalidation" );
m_aClipboardInvalidation.Stop();
}
// no more active control
m_xActiveControl.clear();
m_xActiveTextComponent.clear();
m_bActiveControlIsReadOnly = true;
m_bActiveControlIsRichText = false;
m_bActiveControl = false;
}
//------------------------------------------------------------------------
void FmTextControlShell::controlDeactivated( )
{
DBG_ASSERT( IsActiveControl(), "FmTextControlShell::controlDeactivated: no active control!" );
m_bActiveControl = false;
m_rBindings.Invalidate( pTextControlSlots );
}
//------------------------------------------------------------------------
void FmTextControlShell::controlActivated( const Reference< XControl >& _rxControl )
{
// ensure that all knittings with the previously active control are lost
if ( m_xActiveControl.is() )
implClearActiveControlRef();
DBG_ASSERT( m_aControlFeatures.empty(), "FmTextControlShell::controlActivated: should have no dispatchers when I'm here!" );
#if OSL_DEBUG_LEVEL > 0
{
Sequence< Reference< XControl > > aActiveControls;
if ( m_xActiveController.is() )
aActiveControls = m_xActiveController->getControls();
bool bFoundThisControl = false;
const Reference< XControl >* pControls = aActiveControls.getConstArray();
const Reference< XControl >* pControlsEnd = pControls + aActiveControls.getLength();
for ( ; ( pControls != pControlsEnd ) && !bFoundThisControl; ++pControls )
{
if ( *pControls == _rxControl )
bFoundThisControl = true;
}
DBG_ASSERT( bFoundThisControl, "FmTextControlShell::controlActivated: only controls which belong to the active controller can be activated!" );
}
#endif
// ask the control for dispatchers for our text-related slots
fillFeatureDispatchers( _rxControl, pTextControlSlots, m_aControlFeatures );
// remember this control
m_xActiveControl = _rxControl;
m_xActiveTextComponent = m_xActiveTextComponent.query( _rxControl );
m_bActiveControlIsReadOnly = lcl_determineReadOnly( m_xActiveControl );
m_bActiveControlIsRichText = lcl_isRichText( m_xActiveControl );
// if we found a rich text control, we need context menu support
if ( m_bActiveControlIsRichText )
{
DBG_ASSERT( NULL == m_aContextMenuObserver.get(), "FmTextControlShell::controlActivated: already have an observer!" );
m_aContextMenuObserver = MouseListenerAdapter( new FmMouseListenerAdapter( _rxControl, this ) );
}
if ( m_xActiveTextComponent.is() )
{
DBG_TRACE( "FmTextControlShell::ClipBoard: starting timer for clipboard invalidation" );
m_aClipboardInvalidation.Start();
}
m_bActiveControl = true;
m_rBindings.Invalidate( pTextControlSlots );
if ( m_pViewFrame )
m_pViewFrame->UIFeatureChanged();
// don't call the activation handler if we don't have any slots we can serve
// The activation handler is used to put the shell on the top of the dispatcher stack,
// so it's preferred when slots are distributed.
// Note that this is a slight hack, to prevent that we grab slots from the SfxDispatcher
// which should be served by other shells (e.g. Cut/Copy/Paste).
// A real solution would be a forwarding-mechanism for slots: We should be on the top
// if we're active, but if we cannot handle the slot, then we need to tell the dispatcher
// to skip our shell, and pass the slot to the next one. However, this mechanism is not
// not in place in SFX.
// Another possibility would be to have dedicated shells for the slots which we might
// or might not be able to serve. However, this could probably increase the number of
// shells too much (In theory, nearly every slot could have an own shell then).
//
// #i51621# / 2005-08-19 / frank.schoenheit@sun.com
bool bHaveAnyServeableSlots = m_xActiveTextComponent.is() || !m_aControlFeatures.empty();
if ( m_aControlActivationHandler.IsSet() && bHaveAnyServeableSlots )
m_aControlActivationHandler.Call( NULL );
m_bNeedClipboardInvalidation = true;
}
//------------------------------------------------------------------------
void FmTextControlShell::fillFeatureDispatchers( const Reference< XControl > _rxControl, SfxSlotId* _pZeroTerminatedSlots,
ControlFeatures& _rDispatchers )
{
Reference< XDispatchProvider > xProvider( _rxControl, UNO_QUERY );
SfxApplication* pApplication = SFX_APP();
DBG_ASSERT( pApplication, "FmTextControlShell::fillFeatureDispatchers: no SfxApplication!" );
if ( xProvider.is() && pApplication )
{
SfxSlotId* pSlots = _pZeroTerminatedSlots;
while ( *pSlots )
{
FmTextControlFeature* pDispatcher = implGetFeatureDispatcher( xProvider, pApplication, *pSlots );
if ( pDispatcher )
_rDispatchers.insert( ControlFeatures::value_type( *pSlots, ControlFeature( pDispatcher ) ) );
++pSlots;
}
}
}
//------------------------------------------------------------------------
void FmTextControlShell::impl_parseURL_nothrow( URL& _rURL )
{
try
{
if ( !m_xURLTransformer.is() )
{
::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() );
aContext.createComponent( "com.sun.star.util.URLTransformer", m_xURLTransformer );
}
if ( m_xURLTransformer.is() )
m_xURLTransformer->parseStrict( _rURL );
}
catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION();
}
}
//------------------------------------------------------------------------
FmTextControlFeature* FmTextControlShell::implGetFeatureDispatcher( const Reference< XDispatchProvider >& _rxProvider, SfxApplication* _pApplication, SfxSlotId _nSlot )
{
OSL_PRECOND( _rxProvider.is() && _pApplication, "FmTextControlShell::implGetFeatureDispatcher: invalid arg(s)!" );
URL aFeatureURL;
aFeatureURL.Complete = lcl_getUnoSlotName( *_pApplication, _nSlot );
impl_parseURL_nothrow( aFeatureURL );
Reference< XDispatch > xDispatcher = _rxProvider->queryDispatch( aFeatureURL, ::rtl::OUString(), 0xFF );
if ( xDispatcher.is() )
return new FmTextControlFeature( xDispatcher, aFeatureURL, _nSlot, this );
return NULL;
}
//------------------------------------------------------------------------
void FmTextControlShell::Invalidate( SfxSlotId _nSlot )
{
m_rBindings.Invalidate( _nSlot );
// despite this method being called "Invalidate", we also update here - this gives more immediate
// feedback in the UI
m_rBindings.Update( _nSlot );
}
//------------------------------------------------------------------------
void FmTextControlShell::focusGained( const ::com::sun::star::awt::FocusEvent& _rEvent )
{
Reference< XControl > xControl( _rEvent.Source, UNO_QUERY );
#if OSL_DEBUG_LEVEL > 0
::rtl::OString sTrace( "FmTextControlShell::focusGained: 0x" );
sTrace += ::rtl::OString::valueOf( (sal_IntPtr)xControl.get(), 16 );
DBG_TRACE( sTrace );
#endif
DBG_ASSERT( xControl.is(), "FmTextControlShell::focusGained: suspicious focus event!" );
if ( xControl.is() )
controlActivated( xControl );
}
//------------------------------------------------------------------------
void FmTextControlShell::focusLost( const ::com::sun::star::awt::FocusEvent& _rEvent )
{
Reference< XControl > xControl( _rEvent.Source, UNO_QUERY );
#if OSL_DEBUG_LEVEL > 0
::rtl::OString sTrace( "FmTextControlShell::focusLost: 0x" );
sTrace += ::rtl::OString::valueOf( (sal_IntPtr)xControl.get(), 16 );
DBG_TRACE( sTrace );
#endif
m_bActiveControl = false;
}
//------------------------------------------------------------------------
void FmTextControlShell::ForgetActiveControl()
{
implClearActiveControlRef();
}
//------------------------------------------------------------------------
void FmTextControlShell::contextMenuRequested( const awt::MouseEvent& /*_rEvent*/ )
{
m_rBindings.GetDispatcher()->ExecutePopup( SVX_RES( RID_FM_TEXTATTRIBUTE_MENU ) );
}
//........................................................................
} // namespace svx
//........................................................................