1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_svx.hxx" 30 31 #include "fmprop.hrc" 32 #include "svx/fmresids.hrc" 33 #include "fmtextcontroldialogs.hxx" 34 #include "fmtextcontrolfeature.hxx" 35 #include "fmtextcontrolshell.hxx" 36 #include "editeng/crsditem.hxx" 37 #include "svx/dialmgr.hxx" 38 #include "editeng/editeng.hxx" 39 #include "editeng/eeitem.hxx" 40 #include "svx/fmglob.hxx" 41 #include "editeng/scriptspaceitem.hxx" 42 #include "svx/svxids.hrc" 43 #include "editeng/udlnitem.hxx" 44 45 /** === begin UNO includes === **/ 46 #include <com/sun/star/beans/XPropertySet.hpp> 47 #include <com/sun/star/awt/FontDescriptor.hpp> 48 #include <com/sun/star/frame/XDispatchProvider.hpp> 49 #include <com/sun/star/form/XForm.hpp> 50 #include <com/sun/star/container/XChild.hpp> 51 #include <com/sun/star/awt/XFocusListener.hpp> 52 #include <com/sun/star/awt/XMouseListener.hpp> 53 /** === end UNO includes === **/ 54 55 #include <comphelper/componentcontext.hxx> 56 #include <comphelper/processfactory.hxx> 57 #include <cppuhelper/implbase1.hxx> 58 #include <sfx2/app.hxx> 59 #include <sfx2/bindings.hxx> 60 #include <sfx2/dispatch.hxx> 61 #include <sfx2/msgpool.hxx> 62 #include <sfx2/objsh.hxx> 63 #include <sfx2/request.hxx> 64 #include <sfx2/sfxuno.hxx> 65 #include <sfx2/viewfrm.hxx> 66 #include <svl/eitem.hxx> 67 #include <svl/intitem.hxx> 68 #include <svl/itempool.hxx> 69 #include <svl/languageoptions.hxx> 70 #include <svtools/stringtransfer.hxx> 71 #include <svl/whiter.hxx> 72 #include <toolkit/helper/vclunohelper.hxx> 73 #include <tools/diagnose_ex.h> 74 #include <vcl/msgbox.hxx> 75 #include <vcl/outdev.hxx> 76 #include <vos/mutex.hxx> 77 78 #include <memory> 79 80 //........................................................................ 81 namespace svx 82 { 83 //........................................................................ 84 85 using namespace ::com::sun::star; 86 using namespace ::com::sun::star::uno; 87 using namespace ::com::sun::star::awt; 88 using namespace ::com::sun::star::form; 89 using namespace ::com::sun::star::form::runtime; 90 using namespace ::com::sun::star::lang; 91 using namespace ::com::sun::star::frame; 92 using namespace ::com::sun::star::util; 93 using namespace ::com::sun::star::beans; 94 using namespace ::com::sun::star::container; 95 96 //==================================================================== 97 typedef sal_uInt16 WhichId; 98 99 //==================================================================== 100 static SfxSlotId pTextControlSlots[] = 101 { 102 SID_CLIPBOARD_FORMAT_ITEMS, 103 SID_CUT, 104 SID_COPY, 105 SID_PASTE, 106 SID_SELECTALL, 107 // SID_ATTR_TABSTOP, /* 2 */ 108 SID_ATTR_CHAR_FONT, 109 SID_ATTR_CHAR_POSTURE, 110 SID_ATTR_CHAR_WEIGHT, 111 SID_ATTR_CHAR_SHADOWED, 112 SID_ATTR_CHAR_WORDLINEMODE, 113 SID_ATTR_CHAR_CONTOUR, 114 SID_ATTR_CHAR_STRIKEOUT, 115 SID_ATTR_CHAR_UNDERLINE, 116 SID_ATTR_CHAR_FONTHEIGHT, 117 SID_ATTR_CHAR_COLOR, 118 SID_ATTR_CHAR_KERNING, 119 SID_ATTR_CHAR_LANGUAGE, /* 20 */ 120 SID_ATTR_CHAR_ESCAPEMENT, 121 SID_ATTR_PARA_ADJUST, /* 28 */ 122 SID_ATTR_PARA_ADJUST_LEFT, 123 SID_ATTR_PARA_ADJUST_RIGHT, 124 SID_ATTR_PARA_ADJUST_CENTER, 125 SID_ATTR_PARA_ADJUST_BLOCK, 126 SID_ATTR_PARA_LINESPACE, /* 33 */ 127 SID_ATTR_PARA_LINESPACE_10, 128 SID_ATTR_PARA_LINESPACE_15, 129 SID_ATTR_PARA_LINESPACE_20, 130 SID_ATTR_LRSPACE, /* 48 */ 131 SID_ATTR_ULSPACE, /* 49 */ 132 SID_ATTR_CHAR_AUTOKERN, 133 SID_SET_SUPER_SCRIPT, 134 SID_SET_SUB_SCRIPT, 135 SID_CHAR_DLG, 136 SID_PARA_DLG, 137 // SID_TEXTDIRECTION_LEFT_TO_RIGHT, /* 907 */ 138 // SID_TEXTDIRECTION_TOP_TO_BOTTOM, 139 SID_ATTR_CHAR_SCALEWIDTH, /* 911 */ 140 SID_ATTR_CHAR_RELIEF, 141 SID_ATTR_PARA_LEFT_TO_RIGHT, /* 950 */ 142 SID_ATTR_PARA_RIGHT_TO_LEFT, 143 SID_ATTR_CHAR_OVERLINE, 144 0 145 }; 146 147 // slots which we are not responsible for on the SfxShell level, but 148 // need to handle during the "paragraph attributes" and/or "character 149 // attributes" dialogs 150 static SfxSlotId pDialogSlots[] = 151 { 152 SID_ATTR_TABSTOP, 153 SID_ATTR_PARA_HANGPUNCTUATION, 154 SID_ATTR_PARA_FORBIDDEN_RULES, 155 SID_ATTR_PARA_SCRIPTSPACE, 156 SID_ATTR_CHAR_LATIN_LANGUAGE, 157 SID_ATTR_CHAR_CJK_LANGUAGE, 158 SID_ATTR_CHAR_CTL_LANGUAGE, 159 SID_ATTR_CHAR_LATIN_FONT, 160 SID_ATTR_CHAR_CJK_FONT, 161 SID_ATTR_CHAR_CTL_FONT, 162 SID_ATTR_CHAR_LATIN_FONTHEIGHT, 163 SID_ATTR_CHAR_CJK_FONTHEIGHT, 164 SID_ATTR_CHAR_CTL_FONTHEIGHT, 165 SID_ATTR_CHAR_LATIN_WEIGHT, 166 SID_ATTR_CHAR_CJK_WEIGHT, 167 SID_ATTR_CHAR_CTL_WEIGHT, 168 SID_ATTR_CHAR_LATIN_POSTURE, 169 SID_ATTR_CHAR_CJK_POSTURE, 170 SID_ATTR_CHAR_CTL_POSTURE, 171 SID_ATTR_CHAR_EMPHASISMARK, 172 0 173 }; 174 175 //==================================================================== 176 //= FmFocusListenerAdapter 177 //==================================================================== 178 typedef ::cppu::WeakImplHelper1 < XFocusListener 179 > FmFocusListenerAdapter_Base; 180 class FmFocusListenerAdapter : public FmFocusListenerAdapter_Base 181 { 182 private: 183 IFocusObserver* m_pObserver; 184 Reference< XWindow > m_xWindow; 185 186 public: 187 FmFocusListenerAdapter( const Reference< XControl >& _rxControl, IFocusObserver* _pObserver ); 188 189 // clean up the instance 190 void dispose(); 191 192 protected: 193 ~FmFocusListenerAdapter(); 194 195 protected: 196 virtual void SAL_CALL focusGained( const FocusEvent& e ) throw (RuntimeException); 197 virtual void SAL_CALL focusLost( const FocusEvent& e ) throw (RuntimeException); 198 virtual void SAL_CALL disposing( const EventObject& Source ) throw (RuntimeException); 199 }; 200 201 //-------------------------------------------------------------------- 202 DBG_NAME( FmFocusListenerAdapter ) 203 //-------------------------------------------------------------------- 204 FmFocusListenerAdapter::FmFocusListenerAdapter( const Reference< XControl >& _rxControl, IFocusObserver* _pObserver ) 205 :m_pObserver( _pObserver ) 206 ,m_xWindow( _rxControl, UNO_QUERY ) 207 { 208 DBG_CTOR( FmFocusListenerAdapter, NULL ); 209 210 DBG_ASSERT( m_xWindow.is(), "FmFocusListenerAdapter::FmFocusListenerAdapter: invalid control!" ); 211 osl_incrementInterlockedCount( &m_refCount ); 212 { 213 try 214 { 215 if ( m_xWindow.is() ) 216 m_xWindow->addFocusListener( this ); 217 } 218 catch( const Exception& ) 219 { 220 DBG_UNHANDLED_EXCEPTION(); 221 } 222 } 223 osl_decrementInterlockedCount( &m_refCount ); 224 } 225 226 //-------------------------------------------------------------------- 227 FmFocusListenerAdapter::~FmFocusListenerAdapter() 228 { 229 acquire(); 230 dispose(); 231 232 DBG_DTOR( FmFocusListenerAdapter, NULL ); 233 } 234 235 //-------------------------------------------------------------------- 236 void FmFocusListenerAdapter::dispose() 237 { 238 if ( m_xWindow.is() ) 239 { 240 m_xWindow->removeFocusListener( this ); 241 m_xWindow.clear(); 242 } 243 } 244 245 //-------------------------------------------------------------------- 246 void SAL_CALL FmFocusListenerAdapter::focusGained( const FocusEvent& e ) throw (RuntimeException) 247 { 248 if ( m_pObserver ) 249 m_pObserver->focusGained( e ); 250 } 251 252 //-------------------------------------------------------------------- 253 void SAL_CALL FmFocusListenerAdapter::focusLost( const FocusEvent& e ) throw (RuntimeException) 254 { 255 if ( m_pObserver ) 256 m_pObserver->focusLost( e ); 257 } 258 259 //-------------------------------------------------------------------- 260 void SAL_CALL FmFocusListenerAdapter::disposing( const EventObject& Source ) throw (RuntimeException) 261 { 262 (void)Source; 263 DBG_ASSERT( Source.Source == m_xWindow, "FmFocusListenerAdapter::disposing: where did this come from?" ); 264 m_xWindow.clear(); 265 } 266 267 //==================================================================== 268 //= FmMouseListenerAdapter 269 //==================================================================== 270 typedef ::cppu::WeakImplHelper1 < XMouseListener 271 > FmMouseListenerAdapter_Base; 272 class FmMouseListenerAdapter : public FmMouseListenerAdapter_Base 273 { 274 private: 275 IContextRequestObserver* m_pObserver; 276 Reference< XWindow > m_xWindow; 277 278 public: 279 FmMouseListenerAdapter( const Reference< XControl >& _rxControl, IContextRequestObserver* _pObserver ); 280 281 // clean up the instance 282 void dispose(); 283 284 protected: 285 ~FmMouseListenerAdapter(); 286 287 protected: 288 virtual void SAL_CALL mousePressed( const awt::MouseEvent& e ) throw (RuntimeException); 289 virtual void SAL_CALL mouseReleased( const awt::MouseEvent& e ) throw (RuntimeException); 290 virtual void SAL_CALL mouseEntered( const awt::MouseEvent& e ) throw (RuntimeException); 291 virtual void SAL_CALL mouseExited( const awt::MouseEvent& e ) throw (RuntimeException); 292 virtual void SAL_CALL disposing( const EventObject& Source ) throw (RuntimeException); 293 }; 294 295 //==================================================================== 296 //= FmMouseListenerAdapter 297 //==================================================================== 298 //-------------------------------------------------------------------- 299 DBG_NAME( FmMouseListenerAdapter ) 300 //-------------------------------------------------------------------- 301 FmMouseListenerAdapter::FmMouseListenerAdapter( const Reference< XControl >& _rxControl, IContextRequestObserver* _pObserver ) 302 :m_pObserver( _pObserver ) 303 ,m_xWindow( _rxControl, UNO_QUERY ) 304 { 305 DBG_CTOR( FmMouseListenerAdapter, NULL ); 306 307 DBG_ASSERT( m_xWindow.is(), "FmMouseListenerAdapter::FmMouseListenerAdapter: invalid control!" ); 308 osl_incrementInterlockedCount( &m_refCount ); 309 { 310 try 311 { 312 if ( m_xWindow.is() ) 313 m_xWindow->addMouseListener( this ); 314 } 315 catch( const Exception& ) 316 { 317 DBG_UNHANDLED_EXCEPTION(); 318 } 319 } 320 osl_decrementInterlockedCount( &m_refCount ); 321 } 322 323 //-------------------------------------------------------------------- 324 FmMouseListenerAdapter::~FmMouseListenerAdapter() 325 { 326 acquire(); 327 dispose(); 328 329 DBG_DTOR( FmMouseListenerAdapter, NULL ); 330 } 331 332 //-------------------------------------------------------------------- 333 void FmMouseListenerAdapter::dispose() 334 { 335 if ( m_xWindow.is() ) 336 { 337 m_xWindow->removeMouseListener( this ); 338 m_xWindow.clear(); 339 } 340 } 341 342 //-------------------------------------------------------------------- 343 void SAL_CALL FmMouseListenerAdapter::mousePressed( const awt::MouseEvent& _rEvent ) throw (::com::sun::star::uno::RuntimeException) 344 { 345 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 346 // is this a request for a context menu? 347 if ( _rEvent.PopupTrigger ) 348 { 349 if ( m_pObserver ) 350 m_pObserver->contextMenuRequested( _rEvent ); 351 } 352 } 353 354 //-------------------------------------------------------------------- 355 void SAL_CALL FmMouseListenerAdapter::mouseReleased( const awt::MouseEvent& /*e*/ ) throw (::com::sun::star::uno::RuntimeException) 356 { 357 // not interested in 358 } 359 360 //-------------------------------------------------------------------- 361 void SAL_CALL FmMouseListenerAdapter::mouseEntered( const awt::MouseEvent& /*e*/ ) throw (::com::sun::star::uno::RuntimeException) 362 { 363 // not interested in 364 } 365 366 //-------------------------------------------------------------------- 367 void SAL_CALL FmMouseListenerAdapter::mouseExited( const awt::MouseEvent& /*e*/ ) throw (::com::sun::star::uno::RuntimeException) 368 { 369 // not interested in 370 } 371 372 //-------------------------------------------------------------------- 373 void SAL_CALL FmMouseListenerAdapter::disposing( const EventObject& Source ) throw (RuntimeException) 374 { 375 (void)Source; 376 DBG_ASSERT( Source.Source == m_xWindow, "FmMouseListenerAdapter::disposing: where did this come from?" ); 377 m_xWindow.clear(); 378 } 379 380 //==================================================================== 381 //= FmTextControlShell 382 //==================================================================== 383 //------------------------------------------------------------------------ 384 namespace 385 { 386 //.................................................................... 387 void lcl_translateUnoStateToItem( SfxSlotId _nSlot, const Any& _rUnoState, SfxItemSet& _rSet ) 388 { 389 WhichId nWhich = _rSet.GetPool()->GetWhich( _nSlot ); 390 if ( !_rUnoState.hasValue() ) 391 { 392 if ( ( _nSlot != SID_CUT ) 393 && ( _nSlot != SID_COPY ) 394 && ( _nSlot != SID_PASTE ) 395 ) 396 { 397 _rSet.InvalidateItem( nWhich ); 398 } 399 } 400 else 401 { 402 switch ( _rUnoState.getValueType().getTypeClass() ) 403 { 404 case TypeClass_BOOLEAN: 405 { 406 sal_Bool bState = sal_False; 407 _rUnoState >>= bState; 408 if ( _nSlot == SID_ATTR_PARA_SCRIPTSPACE ) 409 _rSet.Put( SvxScriptSpaceItem( bState, nWhich ) ); 410 else 411 _rSet.Put( SfxBoolItem( nWhich, bState ) ); 412 } 413 break; 414 415 default: 416 { 417 Sequence< PropertyValue > aComplexState; 418 if ( _rUnoState >>= aComplexState ) 419 { 420 if ( !aComplexState.getLength() ) 421 _rSet.InvalidateItem( nWhich ); 422 else 423 { 424 SfxAllItemSet aAllItems( _rSet ); 425 TransformParameters( _nSlot, aComplexState, aAllItems ); 426 const SfxPoolItem* pTransformed = aAllItems.GetItem( nWhich ); 427 OSL_ENSURE( pTransformed, "lcl_translateUnoStateToItem: non-empty parameter sequence leading to empty item?" ); 428 if ( pTransformed ) 429 _rSet.Put( *pTransformed ); 430 else 431 _rSet.InvalidateItem( nWhich ); 432 } 433 } 434 else 435 { 436 DBG_ERROR( "lcl_translateUnoStateToItem: invalid state!" ); 437 } 438 } 439 } 440 } 441 } 442 443 //.................................................................... 444 ::rtl::OUString lcl_getUnoSlotName( SfxApplication&, SfxSlotId _nSlotId ) 445 { 446 ::rtl::OUString sSlotUnoName; 447 448 SfxSlotPool& rSlotPool = SfxSlotPool::GetSlotPool( NULL ); 449 const SfxSlot* pSlot = rSlotPool.GetSlot( _nSlotId ); 450 451 const sal_Char* pAsciiUnoName = NULL; 452 if ( pSlot ) 453 { 454 pAsciiUnoName = pSlot->GetUnoName(); 455 } 456 else 457 { 458 // some hard-coded slots, which do not have a UNO name at SFX level, but which 459 // we nevertheless need to transport via UNO mechanisms, so we need a name 460 switch ( _nSlotId ) 461 { 462 case SID_ATTR_PARA_HANGPUNCTUATION: pAsciiUnoName = "AllowHangingPunctuation"; break; 463 case SID_ATTR_PARA_FORBIDDEN_RULES: pAsciiUnoName = "ApplyForbiddenCharacterRules"; break; 464 case SID_ATTR_PARA_SCRIPTSPACE: pAsciiUnoName = "UseScriptSpacing"; break; 465 } 466 } 467 468 if ( pAsciiUnoName ) 469 { 470 sSlotUnoName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:" ) ); 471 sSlotUnoName += ::rtl::OUString::createFromAscii( pAsciiUnoName ); 472 } 473 #if OSL_DEBUG_LEVEL > 0 474 else 475 { 476 ::rtl::OString sMessage( "lcl_getUnoSlotName: invalid slot id, or invalid slot, or no UNO name!\n" ); 477 sMessage += "(slot id: "; 478 sMessage += ::rtl::OString::valueOf( (sal_Int32)_nSlotId ); 479 sMessage += ")"; 480 DBG_ERROR( sMessage ); 481 } 482 #endif 483 return sSlotUnoName; 484 } 485 486 //.................................................................... 487 bool lcl_determineReadOnly( const Reference< XControl >& _rxControl ) 488 { 489 bool bIsReadOnlyModel = true; 490 try 491 { 492 Reference< XPropertySet > xModelProps; 493 if ( _rxControl.is() ) 494 xModelProps = xModelProps.query( _rxControl->getModel() ); 495 Reference< XPropertySetInfo > xModelPropInfo; 496 if ( xModelProps.is() ) 497 xModelPropInfo = xModelProps->getPropertySetInfo(); 498 499 if ( !xModelPropInfo.is() || !xModelPropInfo->hasPropertyByName( FM_PROP_READONLY ) ) 500 bIsReadOnlyModel = true; 501 else 502 { 503 sal_Bool bReadOnly = sal_True; 504 xModelProps->getPropertyValue( FM_PROP_READONLY ) >>= bReadOnly; 505 bIsReadOnlyModel = bReadOnly; 506 } 507 } 508 catch( const Exception& ) 509 { 510 DBG_UNHANDLED_EXCEPTION(); 511 } 512 return bIsReadOnlyModel; 513 } 514 515 //.................................................................... 516 static Window* lcl_getWindow( const Reference< XControl >& _rxControl ) 517 { 518 Window* pWindow = NULL; 519 try 520 { 521 Reference< XWindowPeer > xControlPeer; 522 if ( _rxControl.is() ) 523 xControlPeer = _rxControl->getPeer(); 524 if ( xControlPeer.is() ) 525 pWindow = VCLUnoHelper::GetWindow( xControlPeer ); 526 } 527 catch( const Exception& ) 528 { 529 DBG_UNHANDLED_EXCEPTION(); 530 } 531 532 return pWindow; 533 } 534 535 //.................................................................... 536 bool lcl_isRichText( const Reference< XControl >& _rxControl ) 537 { 538 if ( !_rxControl.is() ) 539 return false; 540 541 bool bIsRichText = false; 542 try 543 { 544 Reference< XPropertySet > xModelProps( _rxControl->getModel(), UNO_QUERY ); 545 Reference< XPropertySetInfo > xPSI; 546 if ( xModelProps.is() ) 547 xPSI = xModelProps->getPropertySetInfo(); 548 ::rtl::OUString sRichTextPropertyName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "RichText" ) ); 549 if ( xPSI.is() && xPSI->hasPropertyByName( sRichTextPropertyName ) ) 550 { 551 OSL_VERIFY( xModelProps->getPropertyValue( sRichTextPropertyName ) >>= bIsRichText ); 552 } 553 } 554 catch( const Exception& ) 555 { 556 DBG_UNHANDLED_EXCEPTION(); 557 } 558 return bIsRichText; 559 } 560 } 561 562 //------------------------------------------------------------------------ 563 FmTextControlShell::FmTextControlShell( SfxViewFrame* _pFrame ) 564 :m_bActiveControl( false ) 565 ,m_bActiveControlIsReadOnly( true ) 566 ,m_bActiveControlIsRichText( false ) 567 ,m_pViewFrame( _pFrame ) 568 ,m_rBindings( _pFrame->GetBindings() ) 569 ,m_bNeedClipboardInvalidation( true ) 570 { 571 m_aClipboardInvalidation.SetTimeoutHdl( LINK( this, FmTextControlShell, OnInvalidateClipboard ) ); 572 m_aClipboardInvalidation.SetTimeout( 200 ); 573 } 574 575 //------------------------------------------------------------------------ 576 FmTextControlShell::~FmTextControlShell() 577 { 578 dispose(); 579 } 580 581 //------------------------------------------------------------------------ 582 IMPL_LINK( FmTextControlShell, OnInvalidateClipboard, void*, /*_pNotInterestedIn*/ ) 583 { 584 if ( m_bNeedClipboardInvalidation ) 585 { 586 DBG_TRACE( "FmTextControlShell::ClipBoard: invalidating clipboard slots" ); 587 m_rBindings.Invalidate( SID_CUT ); 588 m_rBindings.Invalidate( SID_COPY ); 589 m_rBindings.Invalidate( SID_PASTE ); 590 m_bNeedClipboardInvalidation = false; 591 } 592 return 0L; 593 } 594 595 //------------------------------------------------------------------------ 596 void FmTextControlShell::transferFeatureStatesToItemSet( ControlFeatures& _rDispatchers, SfxAllItemSet& _rSet, bool _bTranslateLatin ) 597 { 598 SfxItemPool& rPool = *_rSet.GetPool(); 599 600 for ( ControlFeatures::const_iterator aFeature = _rDispatchers.begin(); 601 aFeature != _rDispatchers.end(); 602 ++aFeature 603 ) 604 { 605 SfxSlotId nSlotId( aFeature->first ); 606 #if OSL_DEBUG_LEVEL > 0 607 ::rtl::OUString sUnoSlotName; 608 if ( SFX_APP() ) 609 sUnoSlotName = lcl_getUnoSlotName( *SFX_APP(), nSlotId ); 610 else 611 sUnoSlotName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "<unknown>" ) ); 612 ::rtl::OString sUnoSlotNameAscii( "\"" ); 613 sUnoSlotNameAscii += ::rtl::OString( sUnoSlotName.getStr(), sUnoSlotName.getLength(), RTL_TEXTENCODING_ASCII_US ); 614 sUnoSlotNameAscii += "\""; 615 #endif 616 617 if ( _bTranslateLatin ) 618 { 619 // A rich text control offers a dispatcher for the "Font" slot/feature. 620 // Sadly, the semantics of the dispatches is that the feature "Font" depends 621 // on the current cursor position: If it's on latin text, it's the "latin font" 622 // which is set up at the control. If it's on CJK text, it's the "CJK font", and 623 // aequivalent for "CTL font". 624 // The same holds for some other font related features/slots. 625 // Thus, we have separate dispatches for "Latin Font", "Latin Font Size", etc, 626 // which are only "virtual", in a sense that there exist no item with this id. 627 // So when we encounter such a dispatcher for, say, "Latin Font", we need to 628 // put an item into the set which has the "Font" id. 629 630 switch ( nSlotId ) 631 { 632 case SID_ATTR_CHAR_LATIN_FONT: nSlotId = SID_ATTR_CHAR_FONT; break; 633 case SID_ATTR_CHAR_LATIN_FONTHEIGHT:nSlotId = SID_ATTR_CHAR_FONTHEIGHT; break; 634 case SID_ATTR_CHAR_LATIN_LANGUAGE: nSlotId = SID_ATTR_CHAR_LANGUAGE; break; 635 case SID_ATTR_CHAR_LATIN_POSTURE: nSlotId = SID_ATTR_CHAR_POSTURE; break; 636 case SID_ATTR_CHAR_LATIN_WEIGHT: nSlotId = SID_ATTR_CHAR_WEIGHT; break; 637 } 638 } 639 640 WhichId nWhich = rPool.GetWhich( nSlotId ); 641 bool bIsInPool = rPool.IsInRange( nWhich ); 642 if ( bIsInPool ) 643 { 644 #if OSL_DEBUG_LEVEL > 0 645 bool bFeatureIsEnabled = aFeature->second->isFeatureEnabled(); 646 ::rtl::OString sMessage( "FmTextControlShell::transferFeatureStatesToItemSet: found a feature state for " ); 647 sMessage += sUnoSlotNameAscii; 648 if ( !bFeatureIsEnabled ) 649 sMessage += " (disabled)"; 650 DBG_TRACE( sMessage ); 651 #endif 652 653 lcl_translateUnoStateToItem( nSlotId, aFeature->second->getFeatureState(), _rSet ); 654 } 655 #if OSL_DEBUG_LEVEL > 0 656 else 657 { 658 ::rtl::OString sMessage( "FmTextControlShell::transferFeatureStatesToItemSet: found a feature state for " ); 659 sMessage += sUnoSlotNameAscii; 660 sMessage += ", but could not translate it into an item!"; 661 DBG_TRACE( sMessage ); 662 } 663 #endif 664 } 665 } 666 667 //------------------------------------------------------------------------ 668 void FmTextControlShell::executeAttributeDialog( AttributeSet _eSet, SfxRequest& _rReq ) 669 { 670 const SvxFontListItem* pFontList = PTR_CAST( SvxFontListItem, m_pViewFrame->GetObjectShell()->GetItem( SID_ATTR_CHAR_FONTLIST ) ); 671 DBG_ASSERT( pFontList, "FmTextControlShell::executeAttributeDialog: no font list item!" ); 672 if ( !pFontList ) 673 return; 674 675 SfxItemPool* pPool = EditEngine::CreatePool(); 676 pPool->FreezeIdRanges(); 677 ::std::auto_ptr< SfxItemSet > pPureItems( new SfxItemSet( *pPool ) ); 678 679 // put the current states of the items into the set 680 ::std::auto_ptr< SfxAllItemSet > pCurrentItems( new SfxAllItemSet( *pPureItems ) ); 681 transferFeatureStatesToItemSet( m_aControlFeatures, *pCurrentItems ); 682 683 // additional items, which we are not responsible for at the SfxShell level, 684 // but which need to be forwarded to the dialog, anyway 685 ControlFeatures aAdditionalFestures; 686 fillFeatureDispatchers( m_xActiveControl, pDialogSlots, aAdditionalFestures ); 687 transferFeatureStatesToItemSet( aAdditionalFestures, *pCurrentItems, true ); 688 689 ::std::auto_ptr< SfxTabDialog > pDialog ( _eSet == eCharAttribs 690 ? static_cast< SfxTabDialog* >( new TextControlCharAttribDialog( NULL, *pCurrentItems, *pFontList ) ) 691 : static_cast< SfxTabDialog* >( new TextControlParaAttribDialog( NULL, *pCurrentItems ) ) ); 692 if ( RET_OK == pDialog->Execute() ) 693 { 694 const SfxItemSet& rModifiedItems = *pDialog->GetOutputItemSet(); 695 for ( WhichId nWhich = pPool->GetFirstWhich(); nWhich <= pPool->GetLastWhich(); ++nWhich ) 696 { 697 if ( rModifiedItems.GetItemState( nWhich ) == SFX_ITEM_SET ) 698 { 699 SfxSlotId nSlotForItemSet = pPool->GetSlotId( nWhich ); 700 const SfxPoolItem* pModifiedItem = rModifiedItems.GetItem( nWhich ); 701 702 703 SfxSlotId nSlotForDispatcher = nSlotForItemSet; 704 switch ( nSlotForDispatcher ) 705 { 706 case SID_ATTR_CHAR_FONT: nSlotForDispatcher = SID_ATTR_CHAR_LATIN_FONT; break; 707 case SID_ATTR_CHAR_FONTHEIGHT:nSlotForDispatcher = SID_ATTR_CHAR_LATIN_FONTHEIGHT; break; 708 case SID_ATTR_CHAR_LANGUAGE: nSlotForDispatcher = SID_ATTR_CHAR_LATIN_LANGUAGE; break; 709 case SID_ATTR_CHAR_POSTURE: nSlotForDispatcher = SID_ATTR_CHAR_LATIN_POSTURE; break; 710 case SID_ATTR_CHAR_WEIGHT: nSlotForDispatcher = SID_ATTR_CHAR_LATIN_WEIGHT; break; 711 } 712 713 // do we already have a dispatcher for this slot/feature? 714 ControlFeatures::const_iterator aFeaturePos = m_aControlFeatures.find( nSlotForDispatcher ); 715 bool bFound = aFeaturePos != m_aControlFeatures.end( ); 716 717 if ( !bFound ) 718 { 719 aFeaturePos = aAdditionalFestures.find( nSlotForDispatcher ); 720 bFound = aFeaturePos != aAdditionalFestures.end( ); 721 } 722 723 if ( bFound ) 724 { 725 Sequence< PropertyValue > aArgs; 726 // temporarily put the modified item into a "clean" set, 727 // and let TransformItems calc the respective UNO parameters 728 pPureItems->Put( *pModifiedItem ); 729 TransformItems( nSlotForItemSet, *pPureItems, aArgs ); 730 pPureItems->ClearItem( nWhich ); 731 732 if ( ( nSlotForItemSet == SID_ATTR_PARA_HANGPUNCTUATION ) 733 || ( nSlotForItemSet == SID_ATTR_PARA_FORBIDDEN_RULES ) 734 || ( nSlotForItemSet == SID_ATTR_PARA_SCRIPTSPACE ) 735 ) 736 { 737 // these are no UNO slots, they need special handling since TransformItems cannot 738 // handle them 739 DBG_ASSERT( aArgs.getLength() == 0, "FmTextControlShell::executeAttributeDialog: these are no UNO slots - are they?" ); 740 741 const SfxBoolItem* pBoolItem = PTR_CAST( SfxBoolItem, pModifiedItem ); 742 DBG_ASSERT( pBoolItem, "FmTextControlShell::executeAttributeDialog: no bool item?!" ); 743 if ( pBoolItem ) 744 { 745 aArgs.realloc( 1 ); 746 aArgs[ 0 ].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Enable" ) ); 747 aArgs[ 0 ].Value <<= (sal_Bool)pBoolItem->GetValue(); 748 } 749 } 750 751 // dispatch this 752 aFeaturePos->second->dispatch( aArgs ); 753 } 754 #if OSL_DEBUG_LEVEL > 0 755 else 756 { 757 ::rtl::OString sError( "FmTextControShell::executeAttributeDialog: Could not handle the following item:" ); 758 sError += "\n SlotID: "; sError += ::rtl::OString::valueOf( (sal_Int32)nSlotForItemSet ); 759 sError += "\n WhichID: "; sError += ::rtl::OString::valueOf( (sal_Int32)nWhich ); 760 sError += "\n UNO name: "; 761 762 ::rtl::OUString sUnoSlotName = lcl_getUnoSlotName( *SFX_APP(), nSlotForItemSet ); 763 if ( sUnoSlotName.getLength() ) 764 sError += ::rtl::OString( sUnoSlotName.getStr(), sUnoSlotName.getLength(), RTL_TEXTENCODING_ASCII_US ); 765 else 766 sError += "unknown (no SfxSlot)"; 767 DBG_ERROR( sError.getStr() ); 768 } 769 #endif 770 } 771 } 772 _rReq.Done( rModifiedItems ); 773 } 774 775 pDialog.reset(); 776 pCurrentItems.reset(); 777 pPureItems.reset(); 778 SfxItemPool::Free(pPool); 779 } 780 781 //------------------------------------------------------------------------ 782 bool FmTextControlShell::executeSelectAll( ) 783 { 784 try 785 { 786 if ( m_xActiveTextComponent.is() ) 787 { 788 sal_Int32 nTextLen = m_xActiveTextComponent->getText().getLength(); 789 m_xActiveTextComponent->setSelection( awt::Selection( 0, nTextLen ) ); 790 return true; 791 } 792 } 793 catch( const Exception& ) 794 { 795 DBG_UNHANDLED_EXCEPTION(); 796 } 797 return false; // not handled 798 } 799 800 //------------------------------------------------------------------------ 801 bool FmTextControlShell::executeClipboardSlot( SfxSlotId _nSlot ) 802 { 803 try 804 { 805 if ( m_xActiveTextComponent.is() ) 806 { 807 switch ( _nSlot ) 808 { 809 case SID_COPY: 810 case SID_CUT: 811 { 812 ::rtl::OUString sSelectedText( m_xActiveTextComponent->getSelectedText() ); 813 ::svt::OStringTransfer::CopyString( sSelectedText, lcl_getWindow( m_xActiveControl ) ); 814 if ( SID_CUT == _nSlot ) 815 { 816 awt::Selection aSelection( m_xActiveTextComponent->getSelection() ); 817 m_xActiveTextComponent->insertText( aSelection, ::rtl::OUString() ); 818 } 819 } 820 break; 821 case SID_PASTE: 822 { 823 ::rtl::OUString sClipboardContent; 824 OSL_VERIFY( ::svt::OStringTransfer::PasteString( sClipboardContent, lcl_getWindow( m_xActiveControl ) ) ); 825 awt::Selection aSelection( m_xActiveTextComponent->getSelection() ); 826 m_xActiveTextComponent->insertText( aSelection, sClipboardContent ); 827 } 828 break; 829 default: 830 OSL_ENSURE( sal_False, "FmTextControlShell::executeClipboardSlot: invalid slot!" ); 831 } 832 return true; 833 } 834 } 835 catch( const Exception& ) 836 { 837 DBG_UNHANDLED_EXCEPTION(); 838 } 839 return false; // not handled 840 } 841 842 //------------------------------------------------------------------------ 843 void FmTextControlShell::ExecuteTextAttribute( SfxRequest& _rReq ) 844 { 845 SfxSlotId nSlot = _rReq.GetSlot(); 846 847 ControlFeatures::const_iterator aFeaturePos = m_aControlFeatures.find( nSlot ); 848 if ( aFeaturePos == m_aControlFeatures.end() ) 849 { 850 // special slots 851 switch ( nSlot ) 852 { 853 case SID_CHAR_DLG: 854 executeAttributeDialog( eCharAttribs, _rReq ); 855 break; 856 857 case SID_PARA_DLG: 858 executeAttributeDialog( eParaAttribs, _rReq ); 859 break; 860 861 case SID_SELECTALL: 862 executeSelectAll(); 863 break; 864 865 case SID_CUT: 866 case SID_COPY: 867 case SID_PASTE: 868 executeClipboardSlot( nSlot ); 869 break; 870 871 default: 872 DBG_ASSERT( aFeaturePos != m_aControlFeatures.end(), "FmTextControShell::ExecuteTextAttribute: I have no such dispatcher, and cannot handle it at all!" ); 873 return; 874 } 875 } 876 else 877 { 878 // slots which are dispatched to the control 879 880 switch ( nSlot ) 881 { 882 case SID_ATTR_CHAR_STRIKEOUT: 883 case SID_ATTR_CHAR_UNDERLINE: 884 case SID_ATTR_CHAR_OVERLINE: 885 { 886 SfxItemSet aToggled( *_rReq.GetArgs() ); 887 888 lcl_translateUnoStateToItem( nSlot, aFeaturePos->second->getFeatureState(), aToggled ); 889 WhichId nWhich = aToggled.GetPool()->GetWhich( nSlot ); 890 const SfxPoolItem* pItem = aToggled.GetItem( nWhich ); 891 if ( ( SID_ATTR_CHAR_UNDERLINE == nSlot ) || ( SID_ATTR_CHAR_OVERLINE == nSlot ) ) 892 { 893 const SvxOverlineItem* pTextLine = PTR_CAST( SvxOverlineItem, pItem ); 894 DBG_ASSERT( pTextLine, "FmTextControlShell::ExecuteTextAttribute: ooops - no underline/overline item!" ); 895 if ( pTextLine ) 896 { 897 FontUnderline eTL = pTextLine->GetLineStyle(); 898 if ( SID_ATTR_CHAR_UNDERLINE == nSlot ) { 899 aToggled.Put( SvxUnderlineItem( eTL == UNDERLINE_SINGLE ? UNDERLINE_NONE : UNDERLINE_SINGLE, nWhich ) ); 900 } else { 901 aToggled.Put( SvxOverlineItem( eTL == UNDERLINE_SINGLE ? UNDERLINE_NONE : UNDERLINE_SINGLE, nWhich ) ); 902 } 903 } 904 } 905 else 906 { 907 const SvxCrossedOutItem* pCrossedOut = PTR_CAST( SvxCrossedOutItem, pItem ); 908 DBG_ASSERT( pCrossedOut, "FmTextControlShell::ExecuteTextAttribute: ooops - no CrossedOut item!" ); 909 if ( pCrossedOut ) 910 { 911 FontStrikeout eFS = pCrossedOut->GetStrikeout(); 912 aToggled.Put( SvxCrossedOutItem( eFS == STRIKEOUT_SINGLE ? STRIKEOUT_NONE : STRIKEOUT_SINGLE, nWhich ) ); 913 } 914 } 915 916 Sequence< PropertyValue > aArguments; 917 TransformItems( nSlot, aToggled, aArguments ); 918 aFeaturePos->second->dispatch( aArguments ); 919 } 920 break; 921 922 case SID_ATTR_CHAR_FONTHEIGHT: 923 case SID_ATTR_CHAR_FONT: 924 case SID_ATTR_CHAR_POSTURE: 925 case SID_ATTR_CHAR_WEIGHT: 926 case SID_ATTR_CHAR_SHADOWED: 927 case SID_ATTR_CHAR_CONTOUR: 928 case SID_SET_SUPER_SCRIPT: 929 case SID_SET_SUB_SCRIPT: 930 { 931 const SfxItemSet* pArgs = _rReq.GetArgs(); 932 Sequence< PropertyValue > aArgs; 933 if ( pArgs ) 934 TransformItems( nSlot, *pArgs, aArgs ); 935 aFeaturePos->second->dispatch( aArgs ); 936 } 937 break; 938 939 default: 940 if ( aFeaturePos->second->isFeatureEnabled() ) 941 aFeaturePos->second->dispatch(); 942 break; 943 } 944 } 945 _rReq.Done(); 946 } 947 948 //------------------------------------------------------------------------ 949 void FmTextControlShell::GetTextAttributeState( SfxItemSet& _rSet ) 950 { 951 SfxWhichIter aIter( _rSet ); 952 sal_uInt16 nSlot = aIter.FirstWhich(); 953 while ( nSlot ) 954 { 955 if ( ( nSlot == SID_ATTR_PARA_LEFT_TO_RIGHT ) 956 || ( nSlot == SID_ATTR_PARA_RIGHT_TO_LEFT ) 957 ) 958 { 959 if ( !SvtLanguageOptions().IsCTLFontEnabled() ) 960 { 961 _rSet.DisableItem( nSlot ); 962 nSlot = aIter.NextWhich(); 963 continue; 964 } 965 } 966 967 ControlFeatures::const_iterator aFeaturePos = m_aControlFeatures.find( nSlot ); 968 if ( aFeaturePos != m_aControlFeatures.end() ) 969 { 970 if ( aFeaturePos->second->isFeatureEnabled() ) 971 lcl_translateUnoStateToItem( nSlot, aFeaturePos->second->getFeatureState(), _rSet ); 972 else 973 _rSet.DisableItem( nSlot ); 974 } 975 else 976 { 977 bool bDisable = false; 978 979 bool bNeedWriteableControl = false; 980 bool bNeedTextComponent = false; 981 bool bNeedSelection = false; 982 983 switch ( nSlot ) 984 { 985 case SID_CHAR_DLG: 986 case SID_PARA_DLG: 987 bDisable |= m_aControlFeatures.empty(); 988 bNeedWriteableControl = true; 989 break; 990 991 case SID_CUT: 992 bNeedSelection = true; 993 bNeedTextComponent = true; 994 bNeedWriteableControl = true; 995 DBG_TRACE( "FmTextControlShell::ClipBoard: need to invalidate again" ); 996 m_bNeedClipboardInvalidation = true; 997 break; 998 999 case SID_PASTE: 1000 { 1001 Window* pActiveControlVCLWindow = lcl_getWindow( m_xActiveControl ); 1002 if ( pActiveControlVCLWindow ) 1003 { 1004 TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pActiveControlVCLWindow) ); 1005 bDisable |= !aDataHelper.HasFormat( SOT_FORMAT_STRING ); 1006 } 1007 else 1008 bDisable |= true; 1009 1010 bNeedTextComponent = true; 1011 bNeedWriteableControl = true; 1012 } 1013 break; 1014 1015 case SID_COPY: 1016 bNeedTextComponent = true; 1017 bNeedSelection = true; 1018 break; 1019 1020 case SID_SELECTALL: 1021 bNeedTextComponent = true; 1022 break; 1023 1024 default: 1025 // slot is unknown at all 1026 bDisable |= true; 1027 break; 1028 } 1029 OSL_POSTCOND( !bNeedSelection || bNeedTextComponent, "FmTextControlShell::GetTextAttributeState: bNeedSelection should imply bNeedTextComponent!" ); 1030 1031 if ( !bDisable && bNeedWriteableControl ) 1032 bDisable |= !IsActiveControl( ) || m_bActiveControlIsReadOnly; 1033 1034 if ( !bDisable && bNeedTextComponent ) 1035 bDisable |= !m_xActiveTextComponent.is(); 1036 1037 if ( !bDisable && bNeedSelection ) 1038 { 1039 awt::Selection aSelection = m_xActiveTextComponent->getSelection(); 1040 bDisable |= aSelection.Min == aSelection.Max; 1041 } 1042 1043 if ( bDisable ) 1044 _rSet.DisableItem( nSlot ); 1045 } 1046 1047 nSlot = aIter.NextWhich(); 1048 } 1049 } 1050 1051 //------------------------------------------------------------------------ 1052 bool FmTextControlShell::IsActiveControl( bool _bCountRichTextOnly ) const 1053 { 1054 if ( _bCountRichTextOnly && !m_bActiveControlIsRichText ) 1055 return false; 1056 1057 return m_bActiveControl; 1058 } 1059 1060 //------------------------------------------------------------------------ 1061 void FmTextControlShell::dispose() 1062 { 1063 if ( IsActiveControl() ) 1064 controlDeactivated(); 1065 if ( isControllerListening() ) 1066 stopControllerListening(); 1067 } 1068 1069 //------------------------------------------------------------------------ 1070 void FmTextControlShell::designModeChanged( bool /*_bNewDesignMode*/ ) 1071 { 1072 m_rBindings.Invalidate( pTextControlSlots ); 1073 } 1074 1075 //------------------------------------------------------------------------ 1076 void FmTextControlShell::formActivated( const Reference< XFormController >& _rxController ) 1077 { 1078 #if OSL_DEBUG_LEVEL > 0 1079 ::rtl::OString sTrace( "FmTextControlShell::formActivated: 0x" ); 1080 sTrace += ::rtl::OString::valueOf( (sal_IntPtr)_rxController.get(), 16 ); 1081 DBG_TRACE( sTrace ); 1082 #endif 1083 1084 DBG_ASSERT( _rxController.is(), "FmTextControlShell::formActivated: invalid controller!" ); 1085 if ( !_rxController.is() ) 1086 return; 1087 1088 // sometimes, a form controller notifies activations, even if it's already activated 1089 if ( m_xActiveController == _rxController ) 1090 return; 1091 1092 try 1093 { 1094 startControllerListening( _rxController ); 1095 controlActivated( _rxController->getCurrentControl() ); 1096 } 1097 catch( const Exception& ) 1098 { 1099 DBG_UNHANDLED_EXCEPTION(); 1100 } 1101 } 1102 1103 //------------------------------------------------------------------------ 1104 void FmTextControlShell::formDeactivated( const Reference< XFormController >& _rxController ) 1105 { 1106 #if OSL_DEBUG_LEVEL > 0 1107 ::rtl::OString sTrace( "FmTextControlShell::formDeactivated: 0x" ); 1108 sTrace += ::rtl::OString::valueOf( (sal_IntPtr)_rxController.get(), 16 ); 1109 DBG_TRACE( sTrace ); 1110 #endif 1111 (void)_rxController; 1112 1113 if ( IsActiveControl() ) 1114 controlDeactivated(); 1115 if ( isControllerListening() ) 1116 stopControllerListening(); 1117 } 1118 1119 //------------------------------------------------------------------------ 1120 void FmTextControlShell::startControllerListening( const Reference< XFormController >& _rxController ) 1121 { 1122 OSL_PRECOND( _rxController.is(), "FmTextControlShell::startControllerListening: invalid controller!" ); 1123 if ( !_rxController.is() ) 1124 return; 1125 1126 OSL_PRECOND( !isControllerListening(), "FmTextControlShell::startControllerListening: already listening!" ); 1127 if ( isControllerListening() ) 1128 stopControllerListening( ); 1129 DBG_ASSERT( !isControllerListening(), "FmTextControlShell::startControllerListening: inconsistence!" ); 1130 1131 try 1132 { 1133 Sequence< Reference< XControl > > aControls( _rxController->getControls() ); 1134 m_aControlObservers.resize( 0 ); 1135 m_aControlObservers.reserve( aControls.getLength() ); 1136 1137 const Reference< XControl >* pControls = aControls.getConstArray(); 1138 const Reference< XControl >* pControlsEnd = pControls + aControls.getLength(); 1139 for ( ; pControls != pControlsEnd; ++pControls ) 1140 { 1141 m_aControlObservers.push_back( FocusListenerAdapter( new FmFocusListenerAdapter( *pControls, this ) ) ); 1142 } 1143 } 1144 catch( const Exception& ) 1145 { 1146 DBG_UNHANDLED_EXCEPTION(); 1147 } 1148 1149 m_xActiveController = _rxController; 1150 } 1151 1152 //------------------------------------------------------------------------ 1153 void FmTextControlShell::stopControllerListening( ) 1154 { 1155 OSL_PRECOND( isControllerListening(), "FmTextControlShell::stopControllerListening: inconsistence!" ); 1156 1157 // dispose all listeners associated with the controls of the active controller 1158 for ( FocusListenerAdapters::iterator aLoop = m_aControlObservers.begin(); 1159 aLoop != m_aControlObservers.end(); 1160 ++aLoop 1161 ) 1162 { 1163 (*aLoop)->dispose(); 1164 } 1165 1166 FocusListenerAdapters aEmpty; 1167 m_aControlObservers.swap( aEmpty ); 1168 1169 m_xActiveController.clear(); 1170 } 1171 1172 //------------------------------------------------------------------------ 1173 void FmTextControlShell::implClearActiveControlRef() 1174 { 1175 // no more features for this control 1176 for ( ControlFeatures::iterator aLoop = m_aControlFeatures.begin(); 1177 aLoop != m_aControlFeatures.end(); 1178 ++aLoop 1179 ) 1180 { 1181 aLoop->second->dispose(); 1182 } 1183 1184 ControlFeatures aEmpty; 1185 m_aControlFeatures.swap( aEmpty ); 1186 1187 if ( m_aContextMenuObserver.get() ) 1188 { 1189 m_aContextMenuObserver->dispose(); 1190 m_aContextMenuObserver = MouseListenerAdapter(); 1191 } 1192 1193 if ( m_xActiveTextComponent.is() ) 1194 { 1195 DBG_TRACE( "FmTextControlShell::ClipBoard: stopping timer for clipboard invalidation" ); 1196 m_aClipboardInvalidation.Stop(); 1197 } 1198 // no more active control 1199 m_xActiveControl.clear(); 1200 m_xActiveTextComponent.clear(); 1201 m_bActiveControlIsReadOnly = true; 1202 m_bActiveControlIsRichText = false; 1203 m_bActiveControl = false; 1204 } 1205 1206 //------------------------------------------------------------------------ 1207 void FmTextControlShell::controlDeactivated( ) 1208 { 1209 DBG_ASSERT( IsActiveControl(), "FmTextControlShell::controlDeactivated: no active control!" ); 1210 1211 m_bActiveControl = false; 1212 1213 m_rBindings.Invalidate( pTextControlSlots ); 1214 } 1215 1216 //------------------------------------------------------------------------ 1217 void FmTextControlShell::controlActivated( const Reference< XControl >& _rxControl ) 1218 { 1219 // ensure that all knittings with the previously active control are lost 1220 if ( m_xActiveControl.is() ) 1221 implClearActiveControlRef(); 1222 DBG_ASSERT( m_aControlFeatures.empty(), "FmTextControlShell::controlActivated: should have no dispatchers when I'm here!" ); 1223 1224 #if OSL_DEBUG_LEVEL > 0 1225 { 1226 Sequence< Reference< XControl > > aActiveControls; 1227 if ( m_xActiveController.is() ) 1228 aActiveControls = m_xActiveController->getControls(); 1229 1230 bool bFoundThisControl = false; 1231 1232 const Reference< XControl >* pControls = aActiveControls.getConstArray(); 1233 const Reference< XControl >* pControlsEnd = pControls + aActiveControls.getLength(); 1234 for ( ; ( pControls != pControlsEnd ) && !bFoundThisControl; ++pControls ) 1235 { 1236 if ( *pControls == _rxControl ) 1237 bFoundThisControl = true; 1238 } 1239 DBG_ASSERT( bFoundThisControl, "FmTextControlShell::controlActivated: only controls which belong to the active controller can be activated!" ); 1240 } 1241 #endif 1242 // ask the control for dispatchers for our text-related slots 1243 fillFeatureDispatchers( _rxControl, pTextControlSlots, m_aControlFeatures ); 1244 1245 // remember this control 1246 m_xActiveControl = _rxControl; 1247 m_xActiveTextComponent = m_xActiveTextComponent.query( _rxControl ); 1248 m_bActiveControlIsReadOnly = lcl_determineReadOnly( m_xActiveControl ); 1249 m_bActiveControlIsRichText = lcl_isRichText( m_xActiveControl ); 1250 1251 // if we found a rich text control, we need context menu support 1252 if ( m_bActiveControlIsRichText ) 1253 { 1254 DBG_ASSERT( NULL == m_aContextMenuObserver.get(), "FmTextControlShell::controlActivated: already have an observer!" ); 1255 m_aContextMenuObserver = MouseListenerAdapter( new FmMouseListenerAdapter( _rxControl, this ) ); 1256 } 1257 1258 if ( m_xActiveTextComponent.is() ) 1259 { 1260 DBG_TRACE( "FmTextControlShell::ClipBoard: starting timer for clipboard invalidation" ); 1261 m_aClipboardInvalidation.Start(); 1262 } 1263 1264 m_bActiveControl = true; 1265 1266 m_rBindings.Invalidate( pTextControlSlots ); 1267 1268 if ( m_pViewFrame ) 1269 m_pViewFrame->UIFeatureChanged(); 1270 1271 // don't call the activation handler if we don't have any slots we can serve 1272 // The activation handler is used to put the shell on the top of the dispatcher stack, 1273 // so it's preferred when slots are distributed. 1274 // Note that this is a slight hack, to prevent that we grab slots from the SfxDispatcher 1275 // which should be served by other shells (e.g. Cut/Copy/Paste). 1276 // A real solution would be a forwarding-mechanism for slots: We should be on the top 1277 // if we're active, but if we cannot handle the slot, then we need to tell the dispatcher 1278 // to skip our shell, and pass the slot to the next one. However, this mechanism is not 1279 // not in place in SFX. 1280 // Another possibility would be to have dedicated shells for the slots which we might 1281 // or might not be able to serve. However, this could probably increase the number of 1282 // shells too much (In theory, nearly every slot could have an own shell then). 1283 // 1284 // #i51621# / 2005-08-19 / frank.schoenheit@sun.com 1285 bool bHaveAnyServeableSlots = m_xActiveTextComponent.is() || !m_aControlFeatures.empty(); 1286 if ( m_aControlActivationHandler.IsSet() && bHaveAnyServeableSlots ) 1287 m_aControlActivationHandler.Call( NULL ); 1288 1289 m_bNeedClipboardInvalidation = true; 1290 } 1291 1292 //------------------------------------------------------------------------ 1293 void FmTextControlShell::fillFeatureDispatchers( const Reference< XControl > _rxControl, SfxSlotId* _pZeroTerminatedSlots, 1294 ControlFeatures& _rDispatchers ) 1295 { 1296 Reference< XDispatchProvider > xProvider( _rxControl, UNO_QUERY ); 1297 SfxApplication* pApplication = SFX_APP(); 1298 DBG_ASSERT( pApplication, "FmTextControlShell::fillFeatureDispatchers: no SfxApplication!" ); 1299 if ( xProvider.is() && pApplication ) 1300 { 1301 SfxSlotId* pSlots = _pZeroTerminatedSlots; 1302 while ( *pSlots ) 1303 { 1304 FmTextControlFeature* pDispatcher = implGetFeatureDispatcher( xProvider, pApplication, *pSlots ); 1305 if ( pDispatcher ) 1306 _rDispatchers.insert( ControlFeatures::value_type( *pSlots, ControlFeature( pDispatcher ) ) ); 1307 1308 ++pSlots; 1309 } 1310 } 1311 } 1312 1313 //------------------------------------------------------------------------ 1314 void FmTextControlShell::impl_parseURL_nothrow( URL& _rURL ) 1315 { 1316 try 1317 { 1318 if ( !m_xURLTransformer.is() ) 1319 { 1320 ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); 1321 aContext.createComponent( "com.sun.star.util.URLTransformer", m_xURLTransformer ); 1322 } 1323 if ( m_xURLTransformer.is() ) 1324 m_xURLTransformer->parseStrict( _rURL ); 1325 } 1326 catch( const Exception& ) 1327 { 1328 DBG_UNHANDLED_EXCEPTION(); 1329 } 1330 } 1331 1332 //------------------------------------------------------------------------ 1333 FmTextControlFeature* FmTextControlShell::implGetFeatureDispatcher( const Reference< XDispatchProvider >& _rxProvider, SfxApplication* _pApplication, SfxSlotId _nSlot ) 1334 { 1335 OSL_PRECOND( _rxProvider.is() && _pApplication, "FmTextControlShell::implGetFeatureDispatcher: invalid arg(s)!" ); 1336 URL aFeatureURL; 1337 aFeatureURL.Complete = lcl_getUnoSlotName( *_pApplication, _nSlot ); 1338 impl_parseURL_nothrow( aFeatureURL ); 1339 Reference< XDispatch > xDispatcher = _rxProvider->queryDispatch( aFeatureURL, ::rtl::OUString(), 0xFF ); 1340 if ( xDispatcher.is() ) 1341 return new FmTextControlFeature( xDispatcher, aFeatureURL, _nSlot, this ); 1342 return NULL; 1343 } 1344 1345 //------------------------------------------------------------------------ 1346 void FmTextControlShell::Invalidate( SfxSlotId _nSlot ) 1347 { 1348 m_rBindings.Invalidate( _nSlot ); 1349 // despite this method being called "Invalidate", we also update here - this gives more immediate 1350 // feedback in the UI 1351 m_rBindings.Update( _nSlot ); 1352 } 1353 1354 //------------------------------------------------------------------------ 1355 void FmTextControlShell::focusGained( const ::com::sun::star::awt::FocusEvent& _rEvent ) 1356 { 1357 Reference< XControl > xControl( _rEvent.Source, UNO_QUERY ); 1358 1359 #if OSL_DEBUG_LEVEL > 0 1360 ::rtl::OString sTrace( "FmTextControlShell::focusGained: 0x" ); 1361 sTrace += ::rtl::OString::valueOf( (sal_IntPtr)xControl.get(), 16 ); 1362 DBG_TRACE( sTrace ); 1363 #endif 1364 1365 DBG_ASSERT( xControl.is(), "FmTextControlShell::focusGained: suspicious focus event!" ); 1366 if ( xControl.is() ) 1367 controlActivated( xControl ); 1368 } 1369 1370 //------------------------------------------------------------------------ 1371 void FmTextControlShell::focusLost( const ::com::sun::star::awt::FocusEvent& _rEvent ) 1372 { 1373 Reference< XControl > xControl( _rEvent.Source, UNO_QUERY ); 1374 1375 #if OSL_DEBUG_LEVEL > 0 1376 ::rtl::OString sTrace( "FmTextControlShell::focusLost: 0x" ); 1377 sTrace += ::rtl::OString::valueOf( (sal_IntPtr)xControl.get(), 16 ); 1378 DBG_TRACE( sTrace ); 1379 #endif 1380 1381 m_bActiveControl = false; 1382 } 1383 1384 //------------------------------------------------------------------------ 1385 void FmTextControlShell::ForgetActiveControl() 1386 { 1387 implClearActiveControlRef(); 1388 } 1389 1390 //------------------------------------------------------------------------ 1391 void FmTextControlShell::contextMenuRequested( const awt::MouseEvent& /*_rEvent*/ ) 1392 { 1393 m_rBindings.GetDispatcher()->ExecutePopup( SVX_RES( RID_FM_TEXTATTRIBUTE_MENU ) ); 1394 } 1395 1396 //........................................................................ 1397 } // namespace svx 1398 //........................................................................ 1399