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