blob: 7ef19feee861b8c44337dacc4e48ffb2cb5ef5dc [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"
#include "fmprop.hrc"
#include "svx/fmresids.hrc"
#include "fmtextcontroldialogs.hxx"
#include "fmtextcontrolfeature.hxx"
#include "fmtextcontrolshell.hxx"
#include "editeng/crsditem.hxx"
#include "svx/dialmgr.hxx"
#include "editeng/editeng.hxx"
#include "editeng/eeitem.hxx"
#include "svx/fmglob.hxx"
#include "editeng/scriptspaceitem.hxx"
#include "svx/svxids.hrc"
#include "editeng/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 <svl/eitem.hxx>
#include <svl/intitem.hxx>
#include <svl/itempool.hxx>
#include <svl/languageoptions.hxx>
#include <svtools/stringtransfer.hxx>
#include <svl/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::form::runtime;
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 sal_uInt16 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_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,
SID_ATTR_CHAR_OVERLINE,
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
//........................................................................