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_extensions.hxx" 26 #include "propcontroller.hxx" 27 #include "pcrstrings.hxx" 28 #include "standardcontrol.hxx" 29 #include "linedescriptor.hxx" 30 #ifndef EXTENSIONS_PROPRESID_HRC 31 #include "propresid.hrc" 32 #endif 33 #ifndef _EXTENSIONS_FORMCTRLR_PROPRESID_HRC_ 34 #include "formresid.hrc" 35 #endif 36 #include "propertyeditor.hxx" 37 #ifndef _EXTENSIONS_PROPCTRLR_MODULEPRC_HXX_ 38 #include "modulepcr.hxx" 39 #endif 40 #include "formstrings.hxx" 41 #include "formmetadata.hxx" 42 #include "formbrowsertools.hxx" 43 #include "propertycomposer.hxx" 44 45 /** === begin UNO includes === **/ 46 #include <com/sun/star/awt/XWindow.hpp> 47 #include <com/sun/star/util/XCloseable.hpp> 48 #include <com/sun/star/inspection/PropertyControlType.hpp> 49 #include <com/sun/star/ucb/AlreadyInitializedException.hpp> 50 /** === end UNO includes === **/ 51 #include <tools/debug.hxx> 52 #include <tools/diagnose_ex.h> 53 #include <comphelper/types.hxx> 54 #include <comphelper/extract.hxx> 55 #include <toolkit/awt/vclxwindow.hxx> 56 #ifndef _TOOLKIT_HELPER_VCLUNOHELPER_HXX_ 57 #include <toolkit/unohlp.hxx> 58 #endif 59 #include <comphelper/property.hxx> 60 #include <vcl/msgbox.hxx> 61 #include <vcl/svapp.hxx> 62 #include <vos/mutex.hxx> 63 #include <cppuhelper/component_context.hxx> 64 #include <cppuhelper/exc_hlp.hxx> 65 66 #include <algorithm> 67 #include <functional> 68 69 //------------------------------------------------------------------------ 70 // !!! outside the namespace !!! 71 extern "C" void SAL_CALL createRegistryInfo_OPropertyBrowserController() 72 { 73 ::pcr::OAutoRegistration< ::pcr::OPropertyBrowserController > aAutoRegistration; 74 } 75 76 //............................................................................ 77 namespace pcr 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::beans; 86 using namespace ::com::sun::star::script; 87 using namespace ::com::sun::star::lang; 88 using namespace ::com::sun::star::container; 89 using namespace ::com::sun::star::frame; 90 using namespace ::com::sun::star::util; 91 using namespace ::com::sun::star::inspection; 92 using namespace ::com::sun::star::ucb; 93 using namespace ::comphelper; 94 95 #define THISREF() static_cast< XController* >(this) 96 97 //======================================================================== 98 //= OPropertyBrowserController 99 //======================================================================== 100 DBG_NAME(OPropertyBrowserController) 101 //------------------------------------------------------------------------ 102 OPropertyBrowserController::OPropertyBrowserController( const Reference< XComponentContext >& _rxContext ) 103 :m_aContext(_rxContext) 104 ,m_aDisposeListeners( m_aMutex ) 105 ,m_aControlObservers( m_aMutex ) 106 ,m_pView(NULL) 107 ,m_bContainerFocusListening( false ) 108 ,m_bSuspendingPropertyHandlers( false ) 109 ,m_bConstructed( false ) 110 ,m_bBindingIntrospectee( false ) 111 { 112 DBG_CTOR(OPropertyBrowserController,NULL); 113 } 114 115 //------------------------------------------------------------------------ 116 OPropertyBrowserController::~OPropertyBrowserController() 117 { 118 // stop listening for property changes 119 acquire(); 120 stopInspection( true ); 121 DBG_DTOR(OPropertyBrowserController,NULL); 122 } 123 124 //------------------------------------------------------------------------ 125 IMPLEMENT_FORWARD_REFCOUNT( OPropertyBrowserController, OPropertyBrowserController_Base ) 126 127 //------------------------------------------------------------------------ 128 Any SAL_CALL OPropertyBrowserController::queryInterface( const Type& _rType ) throw (RuntimeException) 129 { 130 Any aReturn = OPropertyBrowserController_Base::queryInterface( _rType ); 131 if ( !aReturn.hasValue() ) 132 aReturn = ::cppu::queryInterface( 133 _rType, 134 static_cast< XObjectInspectorUI* >( this ) 135 ); 136 return aReturn; 137 } 138 139 //------------------------------------------------------------------------ 140 void OPropertyBrowserController::startContainerWindowListening() 141 { 142 if (m_bContainerFocusListening) 143 return; 144 145 if (m_xFrame.is()) 146 { 147 Reference< XWindow > xContainerWindow = m_xFrame->getContainerWindow(); 148 if (xContainerWindow.is()) 149 { 150 xContainerWindow->addFocusListener(this); 151 m_bContainerFocusListening = sal_True; 152 } 153 } 154 155 DBG_ASSERT(m_bContainerFocusListening, "OPropertyBrowserController::startContainerWindowListening: unable to start listening (inconsistence)!"); 156 } 157 158 //------------------------------------------------------------------------ 159 void OPropertyBrowserController::stopContainerWindowListening() 160 { 161 if (!m_bContainerFocusListening) 162 return; 163 164 if (m_xFrame.is()) 165 { 166 Reference< XWindow > xContainerWindow = m_xFrame->getContainerWindow(); 167 if (xContainerWindow.is()) 168 { 169 xContainerWindow->removeFocusListener(this); 170 m_bContainerFocusListening = sal_False; 171 } 172 } 173 174 DBG_ASSERT(!m_bContainerFocusListening, "OPropertyBrowserController::stopContainerWindowListening: unable to stop listening (inconsistence)!"); 175 } 176 177 //-------------------------------------------------------------------- 178 Reference< XObjectInspectorModel > SAL_CALL OPropertyBrowserController::getInspectorModel() throw (RuntimeException) 179 { 180 return m_xModel; 181 } 182 183 //-------------------------------------------------------------------- 184 void OPropertyBrowserController::impl_initializeView_nothrow() 185 { 186 OSL_PRECOND( haveView(), "OPropertyBrowserController::impl_initializeView_nothrow: not to be called when we have no view!" ); 187 if ( !haveView() ) 188 return; 189 190 if ( !m_xModel.is() ) 191 // allowed 192 return; 193 194 try 195 { 196 getPropertyBox().EnableHelpSection( m_xModel->getHasHelpSection() ); 197 getPropertyBox().SetHelpLineLimites( m_xModel->getMinHelpTextLines(), m_xModel->getMaxHelpTextLines() ); 198 } 199 catch( const Exception& ) 200 { 201 DBG_UNHANDLED_EXCEPTION(); 202 } 203 } 204 205 //-------------------------------------------------------------------- 206 void OPropertyBrowserController::impl_updateReadOnlyView_nothrow() 207 { 208 // this is a huge cudgel, admitted. 209 // The problem is that in case we were previously read-only, all our controls 210 // were created read-only, too. We cannot simply switch them to not-read-only. 211 // Even if they had an API for this, we do not know whether they were 212 // originally created read-only, or if they are read-only just because 213 // the model was. 214 impl_rebindToInspectee_nothrow( m_aInspectedObjects ); 215 } 216 217 //-------------------------------------------------------------------- 218 bool OPropertyBrowserController::impl_isReadOnlyModel_throw() const 219 { 220 if ( !m_xModel.is() ) 221 return false; 222 223 return m_xModel->getIsReadOnly(); 224 } 225 226 //-------------------------------------------------------------------- 227 void OPropertyBrowserController::impl_startOrStopModelListening_nothrow( bool _bDoListen ) const 228 { 229 try 230 { 231 Reference< XPropertySet > xModelProperties( m_xModel, UNO_QUERY ); 232 if ( !xModelProperties.is() ) 233 // okay, so the model doesn't want to change its properties 234 // dynamically - fine with us 235 return; 236 237 void (SAL_CALL XPropertySet::*pListenerOperation)( const ::rtl::OUString&, const Reference< XPropertyChangeListener >& ) 238 = _bDoListen ? &XPropertySet::addPropertyChangeListener : &XPropertySet::removePropertyChangeListener; 239 240 (xModelProperties.get()->*pListenerOperation)( 241 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsReadOnly" ) ), 242 const_cast< OPropertyBrowserController* >( this ) 243 ); 244 } 245 catch( const Exception& ) 246 { 247 DBG_UNHANDLED_EXCEPTION(); 248 } 249 } 250 251 //-------------------------------------------------------------------- 252 void OPropertyBrowserController::impl_bindToNewModel_nothrow( const Reference< XObjectInspectorModel >& _rxInspectorModel ) 253 { 254 impl_startOrStopModelListening_nothrow( false ); 255 m_xModel = _rxInspectorModel; 256 impl_startOrStopModelListening_nothrow( true ); 257 258 // initialize the view, if we already have one 259 if ( haveView() ) 260 impl_initializeView_nothrow(); 261 262 // inspect again, if we already have inspectees 263 if ( !m_aInspectedObjects.empty() ) 264 impl_rebindToInspectee_nothrow( m_aInspectedObjects ); 265 } 266 267 //-------------------------------------------------------------------- 268 void SAL_CALL OPropertyBrowserController::setInspectorModel( const Reference< XObjectInspectorModel >& _inspectorModel ) throw (RuntimeException) 269 { 270 ::osl::MutexGuard aGuard( m_aMutex ); 271 272 if ( m_xModel == _inspectorModel ) 273 return; 274 275 impl_bindToNewModel_nothrow( _inspectorModel ); 276 } 277 278 //-------------------------------------------------------------------- 279 Reference< XObjectInspectorUI > SAL_CALL OPropertyBrowserController::getInspectorUI() throw (RuntimeException) 280 { 281 // we're derived from this interface, though we do not expose it in queryInterface and getTypes. 282 return this; 283 } 284 285 //-------------------------------------------------------------------- 286 void SAL_CALL OPropertyBrowserController::inspect( const Sequence< Reference< XInterface > >& _rObjects ) throw (com::sun::star::util::VetoException, RuntimeException) 287 { 288 ::vos::OGuard aSolarGuard( Application::GetSolarMutex() ); 289 ::osl::MutexGuard aGuard( m_aMutex ); 290 291 if ( m_bSuspendingPropertyHandlers || !suspendAll_nothrow() ) 292 { // we already are trying to suspend the component (this is somewhere up the stack) 293 // OR one of our property handlers raised a veto against closing. Well, we *need* to close 294 // it in order to inspect another object. 295 throw VetoException(); 296 } 297 if ( m_bBindingIntrospectee ) 298 throw VetoException(); 299 300 m_bBindingIntrospectee = true; 301 impl_rebindToInspectee_nothrow( InterfaceArray( _rObjects.getConstArray(), _rObjects.getConstArray() + _rObjects.getLength() ) ); 302 m_bBindingIntrospectee = false; 303 304 } 305 306 //-------------------------------------------------------------------- 307 Reference< XDispatch > SAL_CALL OPropertyBrowserController::queryDispatch( const URL& /*URL*/, const ::rtl::OUString& /*TargetFrameName*/, ::sal_Int32 /*SearchFlags*/ ) throw (RuntimeException) 308 { 309 // we don't have any dispatches at all, right now 310 return Reference< XDispatch >(); 311 } 312 313 //-------------------------------------------------------------------- 314 Sequence< Reference< XDispatch > > SAL_CALL OPropertyBrowserController::queryDispatches( const Sequence< DispatchDescriptor >& Requests ) throw (RuntimeException) 315 { 316 Sequence< Reference< XDispatch > > aReturn; 317 sal_Int32 nLen = Requests.getLength(); 318 aReturn.realloc( nLen ); 319 320 Reference< XDispatch >* pReturn = aReturn.getArray(); 321 const Reference< XDispatch >* pReturnEnd = aReturn.getArray() + nLen; 322 const DispatchDescriptor* pDescripts = Requests.getConstArray(); 323 324 for ( ; pReturn != pReturnEnd; ++ pReturn, ++pDescripts ) 325 *pReturn = queryDispatch( pDescripts->FeatureURL, pDescripts->FrameName, pDescripts->SearchFlags ); 326 327 return aReturn; 328 } 329 330 //------------------------------------------------------------------------ 331 void SAL_CALL OPropertyBrowserController::initialize( const Sequence< Any >& _arguments ) throw (Exception, RuntimeException) 332 { 333 if ( m_bConstructed ) 334 throw AlreadyInitializedException(); 335 336 StlSyntaxSequence< Any > arguments( _arguments ); 337 if ( arguments.empty() ) 338 { // constructor: "createDefault()" 339 createDefault(); 340 return; 341 } 342 343 Reference< XObjectInspectorModel > xModel; 344 if ( arguments.size() == 1 ) 345 { // constructor: "createWithModel( XObjectInspectorModel )" 346 if ( !( arguments[0] >>= xModel ) ) 347 throw IllegalArgumentException( ::rtl::OUString(), *this, 0 ); 348 createWithModel( xModel ); 349 return; 350 } 351 352 throw IllegalArgumentException( ::rtl::OUString(), *this, 0 ); 353 } 354 355 //------------------------------------------------------------------------ 356 void OPropertyBrowserController::createDefault() 357 { 358 m_bConstructed = true; 359 } 360 361 //------------------------------------------------------------------------ 362 void OPropertyBrowserController::createWithModel( const Reference< XObjectInspectorModel >& _rxModel ) 363 { 364 osl_incrementInterlockedCount( &m_refCount ); 365 { 366 setInspectorModel( _rxModel ); 367 } 368 osl_decrementInterlockedCount( &m_refCount ); 369 370 m_bConstructed = true; 371 } 372 373 //------------------------------------------------------------------------ 374 void SAL_CALL OPropertyBrowserController::attachFrame( const Reference< XFrame >& _rxFrame ) throw(RuntimeException) 375 { 376 ::vos::OGuard aSolarGuard( Application::GetSolarMutex() ); 377 ::osl::MutexGuard aGuard( m_aMutex ); 378 379 if (_rxFrame.is() && haveView()) 380 throw RuntimeException(::rtl::OUString::createFromAscii("Unable to attach to a second frame."),*this); 381 382 // revoke as focus listener from the old container window 383 stopContainerWindowListening(); 384 385 m_xFrame = _rxFrame; 386 if (!m_xFrame.is()) 387 return; 388 389 // TODO: this construction perhaps should be done outside. Don't know the exact meaning of attachFrame. 390 // Maybe it is intended to only announce the frame to the controller, and the instance doing this 391 // announcement is responsible for calling setComponent, too. 392 Reference< XWindow > xContainerWindow = m_xFrame->getContainerWindow(); 393 VCLXWindow* pContainerWindow = VCLXWindow::GetImplementation(xContainerWindow); 394 Window* pParentWin = pContainerWindow ? pContainerWindow->GetWindow() : NULL; 395 if (!pParentWin) 396 throw RuntimeException(::rtl::OUString::createFromAscii("The frame is invalid. Unable to extract the container window."),*this); 397 398 if ( Construct( pParentWin ) ) 399 { 400 try 401 { 402 m_xFrame->setComponent( VCLUnoHelper::GetInterface( m_pView ), this ); 403 } 404 catch( const Exception& ) 405 { 406 OSL_ENSURE( sal_False, "OPropertyBrowserController::attachFrame: caught an exception!" ); 407 } 408 } 409 410 startContainerWindowListening(); 411 412 UpdateUI(); 413 } 414 415 //------------------------------------------------------------------------ 416 sal_Bool SAL_CALL OPropertyBrowserController::attachModel( const Reference< XModel >& _rxModel ) throw(RuntimeException) 417 { 418 Reference< XObjectInspectorModel > xModel( _rxModel, UNO_QUERY ); 419 if ( !xModel.is() ) 420 return false; 421 422 setInspectorModel( xModel ); 423 return getInspectorModel() == _rxModel; 424 } 425 426 //------------------------------------------------------------------------ 427 sal_Bool OPropertyBrowserController::suspendAll_nothrow() 428 { 429 // if there is a handle inside its "onInteractivePropertySelection" method, 430 // then veto 431 // Normally, we could expect every handler to do this itself, but being 432 // realistic, it's safer to handle this here in general. 433 if ( m_xInteractiveHandler.is() ) 434 return sal_False; 435 436 m_bSuspendingPropertyHandlers = true; 437 sal_Bool bHandlerVeto = !suspendPropertyHandlers_nothrow( sal_True ); 438 m_bSuspendingPropertyHandlers = false; 439 if ( bHandlerVeto ) 440 return sal_False; 441 442 return sal_True; 443 } 444 445 //------------------------------------------------------------------------ 446 sal_Bool OPropertyBrowserController::suspendPropertyHandlers_nothrow( sal_Bool _bSuspend ) 447 { 448 PropertyHandlerArray aAllHandlers; // will contain every handler exactly once 449 for ( PropertyHandlerRepository::const_iterator handler = m_aPropertyHandlers.begin(); 450 handler != m_aPropertyHandlers.end(); 451 ++handler 452 ) 453 { 454 if ( ::std::find( aAllHandlers.begin(), aAllHandlers.end(), handler->second ) != aAllHandlers.end() ) 455 // already visited this particular handler (m_aPropertyHandlers usually contains 456 // the same handler more than once) 457 continue; 458 aAllHandlers.push_back( handler->second ); 459 } 460 461 for ( PropertyHandlerArray::iterator loop = aAllHandlers.begin(); 462 loop != aAllHandlers.end(); 463 ++loop 464 ) 465 { 466 try 467 { 468 if ( !(*loop)->suspend( _bSuspend ) ) 469 if ( _bSuspend ) 470 // if we're not suspending, but reactivating, ignore the error 471 return sal_False; 472 } 473 catch( const Exception& ) 474 { 475 OSL_ENSURE( sal_False, "OPropertyBrowserController::suspendPropertyHandlers_nothrow: caught an exception!" ); 476 } 477 } 478 return sal_True; 479 } 480 481 //------------------------------------------------------------------------ 482 sal_Bool SAL_CALL OPropertyBrowserController::suspend( sal_Bool _bSuspend ) throw(RuntimeException) 483 { 484 ::osl::MutexGuard aGuard( m_aMutex ); 485 OSL_ENSURE( haveView(), "OPropertyBrowserController::suspend: don't have a view anymore!" ); 486 487 if ( !_bSuspend ) 488 { // this means a "suspend" is to be "revoked" 489 suspendPropertyHandlers_nothrow( sal_False ); 490 // we ourself cannot revoke our suspend 491 return sal_False; 492 } 493 494 if ( !suspendAll_nothrow() ) 495 return sal_False; 496 497 // commit the editor's content 498 if ( haveView() ) 499 getPropertyBox().CommitModified(); 500 501 // stop listening 502 stopContainerWindowListening(); 503 504 // outtahere 505 return sal_True; 506 } 507 508 //------------------------------------------------------------------------ 509 Any SAL_CALL OPropertyBrowserController::getViewData( ) throw(RuntimeException) 510 { 511 return makeAny( m_sPageSelection ); 512 } 513 514 //------------------------------------------------------------------------ 515 void SAL_CALL OPropertyBrowserController::restoreViewData( const Any& Data ) throw(RuntimeException) 516 { 517 ::rtl::OUString sPageSelection; 518 if ( ( Data >>= sPageSelection ) && sPageSelection.getLength() ) 519 { 520 m_sPageSelection = sPageSelection; 521 selectPageFromViewData(); 522 } 523 } 524 525 //------------------------------------------------------------------------ 526 Reference< XModel > SAL_CALL OPropertyBrowserController::getModel( ) throw(RuntimeException) 527 { 528 // have no model 529 return Reference< XModel >(); 530 } 531 532 //------------------------------------------------------------------------ 533 Reference< XFrame > SAL_CALL OPropertyBrowserController::getFrame( ) throw(RuntimeException) 534 { 535 return m_xFrame; 536 } 537 538 //------------------------------------------------------------------------ 539 void SAL_CALL OPropertyBrowserController::dispose( ) throw(RuntimeException) 540 { 541 ::vos::OGuard aSolarGuard( Application::GetSolarMutex() ); 542 543 // stop inspecting the current object 544 stopInspection( false ); 545 546 // say our dispose listeners goodbye 547 ::com::sun::star::lang::EventObject aEvt; 548 aEvt.Source = static_cast< ::cppu::OWeakObject* >(this); 549 m_aDisposeListeners.disposeAndClear(aEvt); 550 m_aControlObservers.disposeAndClear(aEvt); 551 552 // don't delete explicitly (this is done by the frame we reside in) 553 m_pView = NULL; 554 555 Reference< XComponent > xViewAsComp( m_xView, UNO_QUERY ); 556 if ( xViewAsComp.is() ) 557 xViewAsComp->removeEventListener( static_cast< XPropertyChangeListener* >( this ) ); 558 m_xView.clear( ); 559 560 m_aInspectedObjects.clear(); 561 impl_bindToNewModel_nothrow( NULL ); 562 } 563 564 //------------------------------------------------------------------------ 565 void SAL_CALL OPropertyBrowserController::addEventListener( const Reference< XEventListener >& _rxListener ) throw(RuntimeException) 566 { 567 m_aDisposeListeners.addInterface(_rxListener); 568 } 569 570 //------------------------------------------------------------------------ 571 void SAL_CALL OPropertyBrowserController::removeEventListener( const Reference< XEventListener >& _rxListener ) throw(RuntimeException) 572 { 573 m_aDisposeListeners.removeInterface(_rxListener); 574 } 575 576 //------------------------------------------------------------------------ 577 ::rtl::OUString SAL_CALL OPropertyBrowserController::getImplementationName( ) throw(RuntimeException) 578 { 579 return getImplementationName_static(); 580 } 581 582 //------------------------------------------------------------------------ 583 sal_Bool SAL_CALL OPropertyBrowserController::supportsService( const ::rtl::OUString& ServiceName ) throw(RuntimeException) 584 { 585 Sequence< ::rtl::OUString > aSupported(getSupportedServiceNames()); 586 const ::rtl::OUString* pArray = aSupported.getConstArray(); 587 for (sal_Int32 i = 0; i < aSupported.getLength(); ++i, ++pArray) 588 if (pArray->equals(ServiceName)) 589 return sal_True; 590 return sal_False; 591 } 592 593 //------------------------------------------------------------------------ 594 Sequence< ::rtl::OUString > SAL_CALL OPropertyBrowserController::getSupportedServiceNames( ) throw(RuntimeException) 595 { 596 return getSupportedServiceNames_static(); 597 } 598 599 //------------------------------------------------------------------------ 600 ::rtl::OUString OPropertyBrowserController::getImplementationName_static( ) throw(RuntimeException) 601 { 602 return ::rtl::OUString::createFromAscii("org.openoffice.comp.extensions.ObjectInspector"); 603 } 604 605 //------------------------------------------------------------------------ 606 Sequence< ::rtl::OUString > OPropertyBrowserController::getSupportedServiceNames_static( ) throw(RuntimeException) 607 { 608 Sequence< ::rtl::OUString > aSupported(1); 609 aSupported[0] = ::rtl::OUString::createFromAscii( "com.sun.star.inspection.ObjectInspector" ); 610 return aSupported; 611 } 612 613 //------------------------------------------------------------------------ 614 Reference< XInterface > SAL_CALL OPropertyBrowserController::Create(const Reference< XComponentContext >& _rxContext) 615 { 616 return *(new OPropertyBrowserController( _rxContext ) ); 617 } 618 619 //------------------------------------------------------------------------ 620 void SAL_CALL OPropertyBrowserController::focusGained( const FocusEvent& _rSource ) throw (RuntimeException) 621 { 622 Reference< XWindow > xSourceWindow(_rSource.Source, UNO_QUERY); 623 Reference< XWindow > xContainerWindow; 624 if (m_xFrame.is()) 625 xContainerWindow = m_xFrame->getContainerWindow(); 626 627 if ( xContainerWindow.get() == xSourceWindow.get() ) 628 { // our container window got the focus 629 if ( haveView() ) 630 getPropertyBox().GrabFocus(); 631 } 632 } 633 634 //------------------------------------------------------------------------ 635 void SAL_CALL OPropertyBrowserController::focusLost( const FocusEvent& /*_rSource*/ ) throw (RuntimeException) 636 { 637 // not interested in 638 } 639 640 //------------------------------------------------------------------------ 641 void SAL_CALL OPropertyBrowserController::disposing( const EventObject& _rSource ) throw(RuntimeException) 642 { 643 if ( m_xView.is() && ( m_xView == _rSource.Source ) ) 644 { 645 m_xView = NULL; 646 m_pView = NULL; 647 } 648 649 for ( InterfaceArray::iterator loop = m_aInspectedObjects.begin(); 650 loop != m_aInspectedObjects.end(); 651 ++loop 652 ) 653 { 654 if ( *loop == _rSource.Source ) 655 { 656 m_aInspectedObjects.erase( loop ); 657 break; 658 } 659 } 660 } 661 662 //------------------------------------------------------------------------ 663 IMPL_LINK(OPropertyBrowserController, OnPageActivation, void*, EMPTYARG) 664 { 665 updateViewDataFromActivePage(); 666 return 0L; 667 } 668 669 //------------------------------------------------------------------------ 670 void OPropertyBrowserController::updateViewDataFromActivePage() 671 { 672 if (!haveView()) 673 return; 674 675 ::rtl::OUString sOldSelection = m_sPageSelection; 676 m_sPageSelection = ::rtl::OUString(); 677 678 const sal_uInt16 nCurrentPage = m_pView->getActivaPage(); 679 if ( (sal_uInt16)-1 != nCurrentPage ) 680 { 681 for ( HashString2Int16::const_iterator pageId = m_aPageIds.begin(); 682 pageId != m_aPageIds.end(); 683 ++pageId 684 ) 685 { 686 if ( nCurrentPage == pageId->second ) 687 { 688 m_sPageSelection = pageId->first; 689 break; 690 } 691 } 692 } 693 694 if ( m_sPageSelection.getLength() ) 695 m_sLastValidPageSelection = m_sPageSelection; 696 else if ( sOldSelection.getLength() ) 697 m_sLastValidPageSelection = sOldSelection; 698 } 699 700 //------------------------------------------------------------------------ 701 sal_uInt16 OPropertyBrowserController::impl_getPageIdForCategory_nothrow( const ::rtl::OUString& _rCategoryName ) const 702 { 703 sal_uInt16 nPageId = (sal_uInt16)-1; 704 HashString2Int16::const_iterator pagePos = m_aPageIds.find( _rCategoryName ); 705 if ( pagePos != m_aPageIds.end() ) 706 nPageId = pagePos->second; 707 return nPageId; 708 } 709 710 //------------------------------------------------------------------------ 711 void OPropertyBrowserController::selectPageFromViewData() 712 { 713 sal_uInt16 nNewPage = impl_getPageIdForCategory_nothrow( m_sPageSelection ); 714 715 if ( haveView() && ( nNewPage != (sal_uInt16)-1 ) ) 716 m_pView->activatePage( nNewPage ); 717 718 // just in case ... 719 updateViewDataFromActivePage(); 720 } 721 722 //------------------------------------------------------------------------ 723 sal_Bool OPropertyBrowserController::Construct(Window* _pParentWin) 724 { 725 DBG_ASSERT(!haveView(), "OPropertyBrowserController::Construct: already have a view!"); 726 DBG_ASSERT(_pParentWin, "OPropertyBrowserController::Construct: invalid parent window!"); 727 728 m_pView = new OPropertyBrowserView(m_aContext.getLegacyServiceFactory(), _pParentWin); 729 m_pView->setPageActivationHandler(LINK(this, OPropertyBrowserController, OnPageActivation)); 730 731 // add as dispose listener for our view. The view is disposed by the frame we're plugged into, 732 // and this disposal _deletes_ the view, so it would be deadly if we use our m_pView member 733 // after that 734 m_xView = VCLUnoHelper::GetInterface(m_pView); 735 Reference< XComponent > xViewAsComp(m_xView, UNO_QUERY); 736 if (xViewAsComp.is()) 737 xViewAsComp->addEventListener( static_cast< XPropertyChangeListener* >( this ) ); 738 739 getPropertyBox().SetLineListener(this); 740 getPropertyBox().SetControlObserver(this); 741 impl_initializeView_nothrow(); 742 743 m_pView->Show(); 744 745 return sal_True; 746 } 747 748 //------------------------------------------------------------------------ 749 void SAL_CALL OPropertyBrowserController::propertyChange( const PropertyChangeEvent& _rEvent ) throw (RuntimeException) 750 { 751 if ( _rEvent.Source == m_xModel ) 752 { 753 if ( _rEvent.PropertyName.equalsAscii( "IsReadOnly" ) ) 754 impl_updateReadOnlyView_nothrow(); 755 return; 756 } 757 758 if ( m_sCommittingProperty == _rEvent.PropertyName ) 759 return; 760 761 if ( !haveView() ) 762 return; 763 764 Any aNewValue( _rEvent.NewValue ); 765 if ( impl_hasPropertyHandlerFor_nothrow( _rEvent.PropertyName ) ) 766 { 767 // forward the new value to the property box, to reflect the change in the UI 768 aNewValue = impl_getPropertyValue_throw( _rEvent.PropertyName ); 769 770 // check whether the state is ambiguous. This is interesting in case we display the properties 771 // for multiple objects at once: In this case, we'll get a notification from one of the objects, 772 // but need to care for the "composed" value, which can be "ambiguous". 773 PropertyHandlerRef xHandler( impl_getHandlerForProperty_throw( _rEvent.PropertyName ), UNO_SET_THROW ); 774 PropertyState ePropertyState( xHandler->getPropertyState( _rEvent.PropertyName ) ); 775 bool bAmbiguousValue = ( PropertyState_AMBIGUOUS_VALUE == ePropertyState ); 776 777 getPropertyBox().SetPropertyValue( _rEvent.PropertyName, aNewValue, bAmbiguousValue ); 778 } 779 780 // if it's a actuating property, then update the UI for any dependent 781 // properties 782 if ( impl_isActuatingProperty_nothrow( _rEvent.PropertyName ) ) 783 impl_broadcastPropertyChange_nothrow( _rEvent.PropertyName, aNewValue, _rEvent.OldValue, false ); 784 } 785 786 //------------------------------------------------------------------------ 787 Reference< XPropertyControl > SAL_CALL OPropertyBrowserController::createPropertyControl( ::sal_Int16 ControlType, ::sal_Bool _CreateReadOnly ) throw (IllegalArgumentException, RuntimeException) 788 { 789 ::osl::MutexGuard aGuard( m_aMutex ); 790 791 Reference< XPropertyControl > xControl; 792 793 // default winbits: a border only 794 WinBits nWinBits = WB_BORDER; 795 796 // read-only-ness 797 _CreateReadOnly |= (sal_Bool)impl_isReadOnlyModel_throw(); 798 if ( _CreateReadOnly ) 799 nWinBits |= WB_READONLY; 800 801 switch ( ControlType ) 802 { 803 case PropertyControlType::StringListField: 804 xControl = new OMultilineEditControl( &getPropertyBox(), eStringList, nWinBits | WB_DROPDOWN | WB_TABSTOP ); 805 break; 806 807 case PropertyControlType::MultiLineTextField: 808 xControl = new OMultilineEditControl( &getPropertyBox(), eMultiLineText, nWinBits | WB_DROPDOWN | WB_TABSTOP ); 809 break; 810 811 case PropertyControlType::ListBox: 812 xControl = new OListboxControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_DROPDOWN); 813 break; 814 815 case PropertyControlType::ComboBox: 816 xControl = new OComboboxControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_DROPDOWN); 817 break; 818 819 case PropertyControlType::TextField: 820 xControl = new OEditControl( &getPropertyBox(), sal_False, nWinBits | WB_TABSTOP ); 821 break; 822 823 case PropertyControlType::CharacterField: 824 xControl = new OEditControl( &getPropertyBox(), sal_True, nWinBits | WB_TABSTOP ); 825 break; 826 827 case PropertyControlType::NumericField: 828 xControl = new ONumericControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_SPIN | WB_REPEAT ); 829 break; 830 831 case PropertyControlType::DateTimeField: 832 xControl = new ODateTimeControl( &getPropertyBox(), nWinBits | WB_TABSTOP ); 833 break; 834 835 case PropertyControlType::DateField: 836 xControl = new ODateControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_SPIN | WB_REPEAT ); 837 break; 838 839 case PropertyControlType::TimeField: 840 xControl = new OTimeControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_SPIN | WB_REPEAT ); 841 break; 842 843 case PropertyControlType::ColorListBox: 844 xControl = new OColorControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_DROPDOWN ); 845 break; 846 847 case PropertyControlType::HyperlinkField: 848 xControl = new OHyperlinkControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_DROPDOWN ); 849 break; 850 851 default: 852 throw IllegalArgumentException( ::rtl::OUString(), *this, 1 ); 853 } 854 855 return xControl; 856 } 857 858 //------------------------------------------------------------------------ 859 void OPropertyBrowserController::impl_toggleInspecteeListening_nothrow( bool _bOn ) 860 { 861 for ( InterfaceArray::const_iterator loop = m_aInspectedObjects.begin(); 862 loop != m_aInspectedObjects.end(); 863 ++loop 864 ) 865 { 866 try 867 { 868 Reference< XComponent > xComp( *loop, UNO_QUERY ); 869 if ( xComp.is() ) 870 { 871 if ( _bOn ) 872 xComp->addEventListener( static_cast< XPropertyChangeListener* >( this ) ); 873 else 874 xComp->removeEventListener( static_cast< XPropertyChangeListener* >( this ) ); 875 } 876 } 877 catch( const Exception& ) 878 { 879 DBG_UNHANDLED_EXCEPTION(); 880 } 881 } 882 } 883 884 //------------------------------------------------------------------------ 885 void OPropertyBrowserController::stopInspection( bool _bCommitModified ) 886 { 887 if ( haveView() ) 888 { 889 if ( _bCommitModified ) 890 // commit the editor's content 891 getPropertyBox().CommitModified(); 892 893 // hide the property box so that it does not flicker 894 getPropertyBox().Hide(); 895 896 // clear the property box 897 getPropertyBox().ClearAll(); 898 } 899 900 // destroy the view first 901 if ( haveView() ) 902 { 903 // remove the pages 904 for ( HashString2Int16::const_iterator erase = m_aPageIds.begin(); 905 erase != m_aPageIds.end(); 906 ++erase 907 ) 908 getPropertyBox().RemovePage( erase->second ); 909 clearContainer( m_aPageIds ); 910 } 911 912 clearContainer( m_aProperties ); 913 914 // de-register as dispose-listener from our inspected objects 915 impl_toggleInspecteeListening_nothrow( false ); 916 917 // handlers are obsolete, so is our "composer" for their UI requests 918 if ( m_pUIRequestComposer.get() ) 919 m_pUIRequestComposer->dispose(); 920 m_pUIRequestComposer.reset(); 921 922 // clean up the property handlers 923 PropertyHandlerArray aAllHandlers; // will contain every handler exactly once 924 for ( PropertyHandlerRepository::const_iterator aHandler = m_aPropertyHandlers.begin(); 925 aHandler != m_aPropertyHandlers.end(); 926 ++aHandler 927 ) 928 if ( ::std::find( aAllHandlers.begin(), aAllHandlers.end(), aHandler->second ) == aAllHandlers.end() ) 929 aAllHandlers.push_back( aHandler->second ); 930 931 for ( PropertyHandlerArray::iterator loop = aAllHandlers.begin(); 932 loop != aAllHandlers.end(); 933 ++loop 934 ) 935 { 936 try 937 { 938 (*loop)->removePropertyChangeListener( this ); 939 (*loop)->dispose(); 940 } 941 catch( const DisposedException& ) 942 { 943 } 944 catch( const Exception& ) 945 { 946 DBG_UNHANDLED_EXCEPTION(); 947 } 948 } 949 950 clearContainer( m_aPropertyHandlers ); 951 clearContainer( m_aDependencyHandlers ); 952 } 953 954 //------------------------------------------------------------------------ 955 bool OPropertyBrowserController::impl_hasPropertyHandlerFor_nothrow( const ::rtl::OUString& _rPropertyName ) const 956 { 957 PropertyHandlerRepository::const_iterator handlerPos = m_aPropertyHandlers.find( _rPropertyName ); 958 return ( handlerPos != m_aPropertyHandlers.end() ); 959 } 960 961 //------------------------------------------------------------------------ 962 OPropertyBrowserController::PropertyHandlerRef OPropertyBrowserController::impl_getHandlerForProperty_throw( const ::rtl::OUString& _rPropertyName ) const 963 { 964 PropertyHandlerRepository::const_iterator handlerPos = m_aPropertyHandlers.find( _rPropertyName ); 965 if ( handlerPos == m_aPropertyHandlers.end() ) 966 throw RuntimeException(); 967 return handlerPos->second; 968 } 969 970 //------------------------------------------------------------------------ 971 Any OPropertyBrowserController::impl_getPropertyValue_throw( const ::rtl::OUString& _rPropertyName ) 972 { 973 PropertyHandlerRef handler = impl_getHandlerForProperty_throw( _rPropertyName ); 974 return handler->getPropertyValue( _rPropertyName ); 975 } 976 977 //------------------------------------------------------------------------ 978 void OPropertyBrowserController::impl_rebindToInspectee_nothrow( const InterfaceArray& _rObjects ) 979 { 980 try 981 { 982 // stop inspecting the old object(s) 983 stopInspection( true ); 984 985 // inspect the new object(s) 986 m_aInspectedObjects = _rObjects; 987 doInspection(); 988 989 // update the user interface 990 UpdateUI(); 991 } 992 993 catch(Exception&) 994 { 995 DBG_ERROR("OPropertyBrowserController::impl_rebindToInspectee_nothrow: caught an exception !"); 996 } 997 } 998 999 //------------------------------------------------------------------------ 1000 void OPropertyBrowserController::doInspection() 1001 { 1002 try 1003 { 1004 ////////////////////////////////////////////////////////////////////// 1005 // obtain the properties of the object 1006 ::std::vector< Property > aProperties; 1007 1008 PropertyHandlerArray aPropertyHandlers; 1009 getPropertyHandlers( m_aInspectedObjects, aPropertyHandlers ); 1010 1011 PropertyHandlerArray::iterator aHandler( aPropertyHandlers.begin() ); 1012 while ( aHandler != aPropertyHandlers.end() ) 1013 { 1014 DBG_ASSERT( aHandler->get(), "OPropertyBrowserController::doInspection: invalid handler!" ); 1015 1016 StlSyntaxSequence< Property > aThisHandlersProperties = (*aHandler)->getSupportedProperties(); 1017 1018 if ( aThisHandlersProperties.empty() ) 1019 { 1020 // this handler doesn't know anything about the current inspectee -> ignore it 1021 (*aHandler)->dispose(); 1022 aHandler = aPropertyHandlers.erase( aHandler ); 1023 continue; 1024 } 1025 1026 // append these properties to our "all properties" array 1027 aProperties.reserve( aProperties.size() + aThisHandlersProperties.size() ); 1028 for ( StlSyntaxSequence< Property >::const_iterator copyProperty = aThisHandlersProperties.begin(); 1029 copyProperty != aThisHandlersProperties.end(); 1030 ++copyProperty 1031 ) 1032 { 1033 ::std::vector< Property >::const_iterator previous = ::std::find_if( 1034 aProperties.begin(), 1035 aProperties.end(), 1036 FindPropertyByName( copyProperty->Name ) 1037 ); 1038 if ( previous == aProperties.end() ) 1039 { 1040 aProperties.push_back( *copyProperty ); 1041 continue; 1042 } 1043 1044 // there already was another (previous) handler which supported this property. 1045 // Don't add it to aProperties, again. 1046 1047 // Also, ensure that handlers which previously expressed interest in *changes* 1048 // of this property are not notified. 1049 // This is 'cause we have a new handler which is responsible for this property, 1050 // which means it can give it a completely different meaning than the previous 1051 // handler for this property is prepared for. 1052 ::std::pair< PropertyHandlerMultiRepository::iterator, PropertyHandlerMultiRepository::iterator > 1053 aDepHandlers = m_aDependencyHandlers.equal_range( copyProperty->Name ); 1054 m_aDependencyHandlers.erase( aDepHandlers.first, aDepHandlers.second ); 1055 } 1056 1057 // determine the superseded properties 1058 StlSyntaxSequence< ::rtl::OUString > aSupersededByThisHandler = (*aHandler)->getSupersededProperties(); 1059 for ( StlSyntaxSequence< ::rtl::OUString >::const_iterator superseded = aSupersededByThisHandler.begin(); 1060 superseded != aSupersededByThisHandler.end(); 1061 ++superseded 1062 ) 1063 { 1064 ::std::vector< Property >::iterator existent = ::std::find_if( 1065 aProperties.begin(), 1066 aProperties.end(), 1067 FindPropertyByName( *superseded ) 1068 ); 1069 if ( existent != aProperties.end() ) 1070 // one of the properties superseded by this handler was supported by a previous 1071 // one -> erase 1072 aProperties.erase( existent ); 1073 } 1074 1075 // be notified of changes which this handler is responsible for 1076 (*aHandler)->addPropertyChangeListener( this ); 1077 1078 // remember this handler for every of the properties which it is responsible 1079 // for 1080 for ( StlSyntaxSequence< Property >::const_iterator remember = aThisHandlersProperties.begin(); 1081 remember != aThisHandlersProperties.end(); 1082 ++remember 1083 ) 1084 { 1085 m_aPropertyHandlers[ remember->Name ] = *aHandler; 1086 // note that this implies that if two handlers support the same property, 1087 // the latter wins 1088 } 1089 1090 // see if the handler expresses interest in any actuating properties 1091 StlSyntaxSequence< ::rtl::OUString > aInterestingActuations = (*aHandler)->getActuatingProperties(); 1092 for ( StlSyntaxSequence< ::rtl::OUString >::const_iterator aLoop = aInterestingActuations.begin(); 1093 aLoop != aInterestingActuations.end(); 1094 ++aLoop 1095 ) 1096 { 1097 m_aDependencyHandlers.insert( PropertyHandlerMultiRepository::value_type( 1098 *aLoop, *aHandler ) ); 1099 } 1100 1101 ++aHandler; 1102 } 1103 1104 // create a new composer for UI requests coming from the handlers 1105 m_pUIRequestComposer.reset( new ComposedPropertyUIUpdate( getInspectorUI(), this ) ); 1106 1107 // sort the properties by relative position, as indicated by the model 1108 for ( ::std::vector< Property >::const_iterator sourceProps = aProperties.begin(); 1109 sourceProps != aProperties.end(); 1110 ++sourceProps 1111 ) 1112 { 1113 sal_Int32 nRelativePropertyOrder = sourceProps - aProperties.begin(); 1114 if ( m_xModel.is() ) 1115 nRelativePropertyOrder = m_xModel->getPropertyOrderIndex( sourceProps->Name ); 1116 while ( m_aProperties.find( nRelativePropertyOrder ) != m_aProperties.end() ) 1117 ++nRelativePropertyOrder; 1118 m_aProperties[ nRelativePropertyOrder ] = *sourceProps; 1119 } 1120 1121 // be notified when one of our inspectees dies 1122 impl_toggleInspecteeListening_nothrow( true ); 1123 } 1124 catch(Exception&) 1125 { 1126 DBG_ERROR("OPropertyBrowserController::doInspection : caught an exception !"); 1127 } 1128 } 1129 1130 //------------------------------------------------------------------------ 1131 ::com::sun::star::awt::Size SAL_CALL OPropertyBrowserController::getMinimumSize() throw (::com::sun::star::uno::RuntimeException) 1132 { 1133 ::com::sun::star::awt::Size aSize; 1134 if( m_pView ) 1135 return m_pView->getMinimumSize(); 1136 else 1137 return aSize; 1138 } 1139 1140 //------------------------------------------------------------------------ 1141 ::com::sun::star::awt::Size SAL_CALL OPropertyBrowserController::getPreferredSize() throw (::com::sun::star::uno::RuntimeException) 1142 { 1143 return getMinimumSize(); 1144 } 1145 1146 //------------------------------------------------------------------------ 1147 ::com::sun::star::awt::Size SAL_CALL OPropertyBrowserController::calcAdjustedSize( const ::com::sun::star::awt::Size& _rNewSize ) throw (::com::sun::star::uno::RuntimeException) 1148 { 1149 awt::Size aMinSize = getMinimumSize( ); 1150 awt::Size aAdjustedSize( _rNewSize ); 1151 if ( aAdjustedSize.Width < aMinSize.Width ) 1152 aAdjustedSize.Width = aMinSize.Width; 1153 if ( aAdjustedSize.Height < aMinSize.Height ) 1154 aAdjustedSize.Height = aMinSize.Height; 1155 return aAdjustedSize; 1156 } 1157 1158 //------------------------------------------------------------------------ 1159 void OPropertyBrowserController::describePropertyLine( const Property& _rProperty, OLineDescriptor& _rDescriptor ) SAL_THROW((Exception)) 1160 { 1161 try 1162 { 1163 PropertyHandlerRepository::const_iterator handler = m_aPropertyHandlers.find( _rProperty.Name ); 1164 if ( handler == m_aPropertyHandlers.end() ) 1165 throw RuntimeException(); // caught below 1166 1167 _rDescriptor.assignFrom( handler->second->describePropertyLine( _rProperty.Name, this ) ); 1168 1169 ////////////////////////////////////////////////////////////////////// 1170 1171 _rDescriptor.xPropertyHandler = handler->second; 1172 _rDescriptor.sName = _rProperty.Name; 1173 _rDescriptor.aValue = _rDescriptor.xPropertyHandler->getPropertyValue( _rProperty.Name ); 1174 1175 if ( !_rDescriptor.DisplayName.getLength() ) 1176 { 1177 #ifdef DBG_UTIL 1178 ::rtl::OString sMessage( "OPropertyBrowserController::describePropertyLine: handler did not provide a display name for '" ); 1179 sMessage += ::rtl::OString( _rProperty.Name.getStr(), _rProperty.Name.getLength(), RTL_TEXTENCODING_ASCII_US ); 1180 sMessage += ::rtl::OString( "'!" ); 1181 DBG_ASSERT( _rDescriptor.DisplayName.getLength(), sMessage ); 1182 #endif 1183 _rDescriptor.DisplayName = _rProperty.Name; 1184 } 1185 1186 PropertyState ePropertyState( _rDescriptor.xPropertyHandler->getPropertyState( _rProperty.Name ) ); 1187 if ( PropertyState_AMBIGUOUS_VALUE == ePropertyState ) 1188 { 1189 _rDescriptor.bUnknownValue = true; 1190 _rDescriptor.aValue.clear(); 1191 } 1192 1193 _rDescriptor.bReadOnly = impl_isReadOnlyModel_throw(); 1194 } 1195 catch( const Exception& ) 1196 { 1197 OSL_ENSURE( sal_False, "OPropertyBrowserController::describePropertyLine: caught an exception!" ); 1198 } 1199 } 1200 1201 //------------------------------------------------------------------------ 1202 void OPropertyBrowserController::impl_buildCategories_throw() 1203 { 1204 OSL_PRECOND( m_aPageIds.empty(), "OPropertyBrowserController::impl_buildCategories_throw: duplicate call!" ); 1205 1206 StlSyntaxSequence< PropertyCategoryDescriptor > aCategories; 1207 if ( m_xModel.is() ) 1208 aCategories = m_xModel->describeCategories(); 1209 1210 for ( StlSyntaxSequence< PropertyCategoryDescriptor >::const_iterator category = aCategories.begin(); 1211 category != aCategories.end(); 1212 ++category 1213 ) 1214 { 1215 OSL_ENSURE( m_aPageIds.find( category->ProgrammaticName ) == m_aPageIds.end(), 1216 "OPropertyBrowserController::impl_buildCategories_throw: duplicate programmatic name!" ); 1217 1218 m_aPageIds[ category->ProgrammaticName ] = 1219 getPropertyBox().AppendPage( category->UIName, HelpIdUrl::getHelpId( category->HelpURL ) ); 1220 } 1221 } 1222 1223 //------------------------------------------------------------------------ 1224 void OPropertyBrowserController::UpdateUI() 1225 { 1226 try 1227 { 1228 if ( !haveView() ) 1229 // too early, will return later 1230 return; 1231 1232 getPropertyBox().DisableUpdate(); 1233 1234 sal_Bool bHaveFocus = getPropertyBox().HasChildPathFocus(); 1235 1236 // create our tab pages 1237 impl_buildCategories_throw(); 1238 // (and allow for pages to be actually unused) 1239 ::std::set< sal_uInt16 > aUsedPages; 1240 1241 // when building the UI below, remember which properties are actuating, 1242 // to allow for a initial actuatinPropertyChanged call 1243 ::std::vector< ::rtl::OUString > aActuatingProperties; 1244 ::std::vector< Any > aActuatingPropertyValues; 1245 1246 // ask the handlers to describe the property UI, and insert the resulting 1247 // entries into our list boxes 1248 OrderedPropertyMap::const_iterator property( m_aProperties.begin() ); 1249 for ( ; property != m_aProperties.end(); ++property ) 1250 { 1251 OLineDescriptor aDescriptor; 1252 describePropertyLine( property->second, aDescriptor ); 1253 1254 bool bIsActuatingProperty = impl_isActuatingProperty_nothrow( property->second.Name ); 1255 1256 #if OSL_DEBUG_LEVEL > 0 1257 if ( !aDescriptor.Category.getLength() ) 1258 { 1259 ::rtl::OString sMessage( "OPropertyBrowserController::UpdateUI: empty category provided for property '" ); 1260 sMessage += ::rtl::OString( property->second.Name.getStr(), property->second.Name.getLength(), osl_getThreadTextEncoding() ); 1261 sMessage += "'!"; 1262 OSL_ENSURE( false, sMessage ); 1263 } 1264 #endif 1265 // finally insert this property control 1266 sal_uInt16 nTargetPageId = impl_getPageIdForCategory_nothrow( aDescriptor.Category ); 1267 if ( nTargetPageId == (sal_uInt16)-1 ) 1268 { 1269 // this category does not yet exist. This is allowed, as an inspector model might be lazy, and not provide 1270 // any category information of its own. In this case, we have a fallback ... 1271 m_aPageIds[ aDescriptor.Category ] = 1272 getPropertyBox().AppendPage( aDescriptor.Category, rtl::OString() ); 1273 nTargetPageId = impl_getPageIdForCategory_nothrow( aDescriptor.Category ); 1274 } 1275 1276 getPropertyBox().InsertEntry( aDescriptor, nTargetPageId ); 1277 aUsedPages.insert( nTargetPageId ); 1278 1279 // if it's an actuating property, remember it 1280 if ( bIsActuatingProperty ) 1281 { 1282 aActuatingProperties.push_back( property->second.Name ); 1283 aActuatingPropertyValues.push_back( impl_getPropertyValue_throw( property->second.Name ) ); 1284 } 1285 } 1286 1287 // update any dependencies for the actuating properties which we encountered 1288 { 1289 ::std::vector< ::rtl::OUString >::const_iterator aProperty = aActuatingProperties.begin(); 1290 ::std::vector< Any >::const_iterator aPropertyValue = aActuatingPropertyValues.begin(); 1291 for ( ; aProperty != aActuatingProperties.end(); ++aProperty, ++aPropertyValue ) 1292 impl_broadcastPropertyChange_nothrow( *aProperty, *aPropertyValue, *aPropertyValue, true ); 1293 } 1294 1295 // remove any unused pages (which we did not encounter properties for) 1296 HashString2Int16 aSurvivingPageIds; 1297 for ( HashString2Int16::iterator pageId = m_aPageIds.begin(); 1298 pageId != m_aPageIds.end(); 1299 ++pageId 1300 ) 1301 { 1302 if ( aUsedPages.find( pageId->second ) == aUsedPages.end() ) 1303 getPropertyBox().RemovePage( pageId->second ); 1304 else 1305 aSurvivingPageIds.insert( *pageId ); 1306 } 1307 m_aPageIds.swap( aSurvivingPageIds ); 1308 1309 1310 getPropertyBox().Show(); 1311 getPropertyBox().EnableUpdate(); 1312 if ( bHaveFocus ) 1313 getPropertyBox().GrabFocus(); 1314 1315 // activate the first page 1316 if ( !m_aPageIds.empty() ) 1317 { 1318 Sequence< PropertyCategoryDescriptor > aCategories( m_xModel->describeCategories() ); 1319 if ( aCategories.getLength() ) 1320 m_pView->activatePage( m_aPageIds[ aCategories[0].ProgrammaticName ] ); 1321 else 1322 // allowed: if we default-created the pages ... 1323 m_pView->activatePage( m_aPageIds.begin()->second ); 1324 } 1325 1326 // activate the previously active page (if possible) 1327 if ( m_sLastValidPageSelection.getLength() ) 1328 m_sPageSelection = m_sLastValidPageSelection; 1329 selectPageFromViewData(); 1330 } 1331 catch( const Exception& ) 1332 { 1333 DBG_UNHANDLED_EXCEPTION(); 1334 } 1335 } 1336 1337 //------------------------------------------------------------------------ 1338 void OPropertyBrowserController::Clicked( const ::rtl::OUString& _rName, sal_Bool _bPrimary ) 1339 { 1340 try 1341 { 1342 // since the browse buttons do not get the focus when clicked with the mouse, 1343 // we need to commit the changes in the current property field 1344 getPropertyBox().CommitModified(); 1345 1346 PropertyHandlerRepository::const_iterator handler = m_aPropertyHandlers.find( _rName ); 1347 DBG_ASSERT( handler != m_aPropertyHandlers.end(), "OPropertyBrowserController::Clicked: a property without handler? This will crash!" ); 1348 1349 ComposedUIAutoFireGuard aAutoFireGuard( *m_pUIRequestComposer ); 1350 1351 Any aData; 1352 m_xInteractiveHandler = handler->second; 1353 InteractiveSelectionResult eResult = 1354 handler->second->onInteractivePropertySelection( _rName, _bPrimary, aData, 1355 m_pUIRequestComposer->getUIForPropertyHandler( handler->second ) ); 1356 1357 switch ( eResult ) 1358 { 1359 case InteractiveSelectionResult_Cancelled: 1360 case InteractiveSelectionResult_Success: 1361 // okay, nothing to do 1362 break; 1363 case InteractiveSelectionResult_ObtainedValue: 1364 handler->second->setPropertyValue( _rName, aData ); 1365 break; 1366 case InteractiveSelectionResult_Pending: 1367 // also okay, we expect that the handler has disabled the UI as necessary 1368 break; 1369 default: 1370 OSL_ENSURE( false, "OPropertyBrowserController::Clicked: unknown result value!" ); 1371 break; 1372 } 1373 } 1374 catch (Exception&) 1375 { 1376 DBG_UNHANDLED_EXCEPTION(); 1377 } 1378 m_xInteractiveHandler = NULL; 1379 } 1380 1381 //------------------------------------------------------------------------ 1382 sal_Bool SAL_CALL OPropertyBrowserController::hasPropertyByName( const ::rtl::OUString& _rName ) throw (RuntimeException) 1383 { 1384 for ( OrderedPropertyMap::const_iterator search = m_aProperties.begin(); 1385 search != m_aProperties.end(); 1386 ++search 1387 ) 1388 if ( search->second.Name == _rName ) 1389 return true; 1390 return false; 1391 } 1392 1393 //------------------------------------------------------------------------ 1394 void OPropertyBrowserController::Commit( const ::rtl::OUString& rName, const Any& _rValue ) 1395 { 1396 try 1397 { 1398 rtl::OUString sPlcHolder = String( PcrRes( RID_EMBED_IMAGE_PLACEHOLDER ) ); 1399 bool bIsPlaceHolderValue = false; 1400 1401 if ( rName.equals( PROPERTY_IMAGE_URL ) ) 1402 { 1403 // if the prop value is the PlaceHolder 1404 // can ignore it 1405 rtl::OUString sVal; 1406 _rValue >>= sVal; 1407 if ( sVal.equals( sPlcHolder ) ) 1408 bIsPlaceHolderValue = true; 1409 } 1410 m_sCommittingProperty = rName; 1411 1412 bool bIsActuatingProperty = impl_isActuatingProperty_nothrow( rName ); 1413 1414 Any aOldValue; 1415 if ( bIsActuatingProperty ) 1416 aOldValue = impl_getPropertyValue_throw( rName ); 1417 1418 // do we have a dedicated handler for this property, which we can delegate some tasks to? 1419 PropertyHandlerRef handler = impl_getHandlerForProperty_throw( rName ); 1420 1421 ////////////////////////////////////////////////////////////////////// 1422 // set the value ( only if it's not a placeholder ) 1423 if ( !bIsPlaceHolderValue ) 1424 handler->setPropertyValue( rName, _rValue ); 1425 1426 ////////////////////////////////////////////////////////////////////// 1427 // re-retrieve the value 1428 Any aNormalizedValue = handler->getPropertyValue( rName ); 1429 1430 // care for any inter-property dependencies 1431 if ( bIsActuatingProperty ) 1432 impl_broadcastPropertyChange_nothrow( rName, aNormalizedValue, aOldValue, false ); 1433 1434 // and display it again. This ensures proper formatting 1435 getPropertyBox().SetPropertyValue( rName, aNormalizedValue, false ); 1436 } 1437 catch(PropertyVetoException& eVetoException) 1438 { 1439 InfoBox(m_pView, eVetoException.Message).Execute(); 1440 PropertyHandlerRef handler = impl_getHandlerForProperty_throw( rName ); 1441 Any aNormalizedValue = handler->getPropertyValue( rName ); 1442 getPropertyBox().SetPropertyValue( rName, aNormalizedValue, false ); 1443 } 1444 catch(Exception&) 1445 { 1446 DBG_ERROR("OPropertyBrowserController::Commit : caught an exception !"); 1447 } 1448 1449 m_sCommittingProperty = ::rtl::OUString(); 1450 } 1451 1452 //-------------------------------------------------------------------- 1453 namespace 1454 { 1455 } 1456 1457 //-------------------------------------------------------------------- 1458 void OPropertyBrowserController::focusGained( const Reference< XPropertyControl >& _Control ) 1459 { 1460 m_aControlObservers.notifyEach( &XPropertyControlObserver::focusGained, _Control ); 1461 } 1462 1463 //-------------------------------------------------------------------- 1464 void OPropertyBrowserController::valueChanged( const Reference< XPropertyControl >& _Control ) 1465 { 1466 m_aControlObservers.notifyEach( &XPropertyControlObserver::valueChanged, _Control ); 1467 } 1468 1469 //------------------------------------------------------------------------ 1470 namespace 1471 { 1472 Reference< XPropertyHandler > lcl_createHandler( const ComponentContext& _rContext, const Any& _rFactoryDescriptor ) 1473 { 1474 Reference< XPropertyHandler > xHandler; 1475 1476 ::rtl::OUString sServiceName; 1477 Reference< XSingleServiceFactory > xServiceFac; 1478 Reference< XSingleComponentFactory > xComponentFac; 1479 1480 if ( _rFactoryDescriptor >>= sServiceName ) 1481 _rContext.createComponent( sServiceName, xHandler ); 1482 else if ( _rFactoryDescriptor >>= xServiceFac ) 1483 xHandler = xHandler.query( xServiceFac->createInstance() ); 1484 else if ( _rFactoryDescriptor >>= xComponentFac ) 1485 xHandler = xHandler.query( xComponentFac->createInstanceWithContext( _rContext.getUNOContext() ) ); 1486 OSL_ENSURE(xHandler.is(),"lcl_createHandler: Can not create handler"); 1487 return xHandler; 1488 } 1489 } 1490 1491 //------------------------------------------------------------------------ 1492 void OPropertyBrowserController::getPropertyHandlers( const InterfaceArray& _rObjects, PropertyHandlerArray& _rHandlers ) 1493 { 1494 _rHandlers.resize( 0 ); 1495 if ( _rObjects.empty() ) 1496 return; 1497 1498 // create a component context for the handlers, containing some information about where 1499 // they live 1500 Reference< XComponentContext > xHandlerContext( m_aContext.getUNOContext() ); 1501 1502 // if our own creator did not pass a dialog parent window, use our own view for this 1503 Reference< XWindow > xParentWindow( m_aContext.getContextValueByAsciiName( "DialogParentWindow" ), UNO_QUERY ); 1504 if ( !xParentWindow.is() ) 1505 { 1506 ::cppu::ContextEntry_Init aHandlerContextInfo[] = 1507 { 1508 ::cppu::ContextEntry_Init( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DialogParentWindow" ) ), makeAny( VCLUnoHelper::GetInterface( m_pView ) ) ) 1509 }; 1510 xHandlerContext = ::cppu::createComponentContext( 1511 aHandlerContextInfo, sizeof( aHandlerContextInfo ) / sizeof( aHandlerContextInfo[0] ), 1512 m_aContext.getUNOContext() ); 1513 } 1514 1515 Sequence< Any > aHandlerFactories; 1516 if ( m_xModel.is() ) 1517 aHandlerFactories = m_xModel->getHandlerFactories(); 1518 1519 const Any* pHandlerFactory = aHandlerFactories.getConstArray(); 1520 const Any* pHandlerFactoryEnd = aHandlerFactories.getConstArray() + aHandlerFactories.getLength(); 1521 1522 while ( pHandlerFactory != pHandlerFactoryEnd ) 1523 { 1524 if ( _rObjects.size() == 1 ) 1525 { // we're inspecting only one object -> one handler 1526 Reference< XPropertyHandler > xHandler( lcl_createHandler( m_aContext, *pHandlerFactory ) ); 1527 if ( xHandler.is() ) 1528 { 1529 xHandler->inspect( _rObjects[0] ); 1530 _rHandlers.push_back( xHandler ); 1531 } 1532 } 1533 else 1534 { 1535 // create a single handler for every single object 1536 ::std::vector< Reference< XPropertyHandler > > aSingleHandlers( _rObjects.size() ); 1537 ::std::vector< Reference< XPropertyHandler > >::iterator pHandler = aSingleHandlers.begin(); 1538 1539 InterfaceArray::const_iterator pObject = _rObjects.begin(); 1540 InterfaceArray::const_iterator pObjectEnd = _rObjects.end(); 1541 1542 for ( ; pObject != pObjectEnd; ++pObject ) 1543 { 1544 *pHandler = lcl_createHandler( m_aContext, *pHandlerFactory ); 1545 if ( pHandler->is() ) 1546 { 1547 (*pHandler)->inspect( *pObject ); 1548 ++pHandler; 1549 } 1550 } 1551 aSingleHandlers.resize( pHandler - aSingleHandlers.begin() ); 1552 1553 // then create a handler which composes information out of those single handlers 1554 if ( !aSingleHandlers.empty() ) 1555 _rHandlers.push_back( new PropertyComposer( aSingleHandlers ) ); 1556 } 1557 1558 ++pHandlerFactory; 1559 } 1560 1561 // note that the handlers will not be used by our caller, if they indicate that there are no 1562 // properties they feel responsible for 1563 } 1564 1565 //------------------------------------------------------------------------ 1566 bool OPropertyBrowserController::impl_findObjectProperty_nothrow( const ::rtl::OUString& _rName, OrderedPropertyMap::const_iterator* _pProperty ) 1567 { 1568 OrderedPropertyMap::const_iterator search = m_aProperties.begin(); 1569 for ( ; search != m_aProperties.end(); ++search ) 1570 if ( search->second.Name == _rName ) 1571 break; 1572 if ( _pProperty ) 1573 *_pProperty = search; 1574 return ( search != m_aProperties.end() ); 1575 } 1576 1577 //------------------------------------------------------------------------ 1578 void OPropertyBrowserController::rebuildPropertyUI( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException) 1579 { 1580 ::osl::MutexGuard aGuard( m_aMutex ); 1581 if ( !haveView() ) 1582 throw RuntimeException(); 1583 1584 OrderedPropertyMap::const_iterator propertyPos; 1585 if ( !impl_findObjectProperty_nothrow( _rPropertyName, &propertyPos ) ) 1586 return; 1587 1588 OLineDescriptor aDescriptor; 1589 try 1590 { 1591 describePropertyLine( propertyPos->second, aDescriptor ); 1592 } 1593 catch( const Exception& ) 1594 { 1595 OSL_ENSURE( sal_False, "OPropertyBrowserController::rebuildPropertyUI: caught an exception!" ); 1596 } 1597 1598 getPropertyBox().ChangeEntry( aDescriptor ); 1599 } 1600 1601 //------------------------------------------------------------------------ 1602 void OPropertyBrowserController::enablePropertyUI( const ::rtl::OUString& _rPropertyName, sal_Bool _bEnable ) throw (RuntimeException) 1603 { 1604 ::osl::MutexGuard aGuard( m_aMutex ); 1605 if ( !haveView() ) 1606 throw RuntimeException(); 1607 1608 if ( !impl_findObjectProperty_nothrow( _rPropertyName ) ) 1609 return; 1610 1611 getPropertyBox().EnablePropertyLine( _rPropertyName, _bEnable ); 1612 } 1613 1614 //------------------------------------------------------------------------ 1615 void OPropertyBrowserController::enablePropertyUIElements( const ::rtl::OUString& _rPropertyName, sal_Int16 _nElements, sal_Bool _bEnable ) throw (RuntimeException) 1616 { 1617 ::osl::MutexGuard aGuard( m_aMutex ); 1618 if ( !haveView() ) 1619 throw RuntimeException(); 1620 1621 if ( !impl_findObjectProperty_nothrow( _rPropertyName ) ) 1622 return; 1623 1624 getPropertyBox().EnablePropertyControls( _rPropertyName, _nElements, _bEnable ); 1625 } 1626 1627 //------------------------------------------------------------------------ 1628 void OPropertyBrowserController::showPropertyUI( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException) 1629 { 1630 ::osl::MutexGuard aGuard( m_aMutex ); 1631 if ( !haveView() ) 1632 throw RuntimeException(); 1633 1634 // look up the property in our object properties 1635 OrderedPropertyMap::const_iterator propertyPos; 1636 if ( !impl_findObjectProperty_nothrow( _rPropertyName, &propertyPos ) ) 1637 return; 1638 1639 if ( getPropertyBox().GetPropertyPos( _rPropertyName ) != LISTBOX_ENTRY_NOTFOUND ) 1640 { 1641 rebuildPropertyUI( _rPropertyName ); 1642 return; 1643 } 1644 1645 OLineDescriptor aDescriptor; 1646 describePropertyLine( propertyPos->second, aDescriptor ); 1647 1648 // look for the position to insert the property 1649 1650 // side note: The methods GetPropertyPos and InsertEntry of the OPropertyEditor work 1651 // only on the current page. This implies that it's impossible to use this method here 1652 // to show property lines which are *not* on the current page. 1653 // This is sufficient for now, but should be changed in the future. 1654 1655 // by definition, the properties in m_aProperties are in the order in which they appear in the UI 1656 // So all we need is a predecessor of pProperty in m_aProperties 1657 sal_uInt16 nUIPos = LISTBOX_ENTRY_NOTFOUND; 1658 do 1659 { 1660 if ( propertyPos != m_aProperties.begin() ) 1661 --propertyPos; 1662 nUIPos = getPropertyBox().GetPropertyPos( propertyPos->second.Name ); 1663 } 1664 while ( ( nUIPos == LISTBOX_ENTRY_NOTFOUND ) && ( propertyPos != m_aProperties.begin() ) ); 1665 1666 if ( nUIPos == LISTBOX_ENTRY_NOTFOUND ) 1667 // insert at the very top 1668 nUIPos = 0; 1669 else 1670 // insert right after the predecessor we found 1671 ++nUIPos; 1672 1673 getPropertyBox().InsertEntry( 1674 aDescriptor, impl_getPageIdForCategory_nothrow( aDescriptor.Category ), nUIPos ); 1675 } 1676 1677 //------------------------------------------------------------------------ 1678 void OPropertyBrowserController::hidePropertyUI( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException) 1679 { 1680 ::osl::MutexGuard aGuard( m_aMutex ); 1681 if ( !haveView() ) 1682 throw RuntimeException(); 1683 1684 if ( !impl_findObjectProperty_nothrow( _rPropertyName ) ) 1685 return; 1686 1687 getPropertyBox().RemoveEntry( _rPropertyName ); 1688 } 1689 1690 //------------------------------------------------------------------------ 1691 void OPropertyBrowserController::showCategory( const ::rtl::OUString& _rCategory, sal_Bool _bShow ) throw (RuntimeException) 1692 { 1693 ::osl::MutexGuard aGuard( m_aMutex ); 1694 if ( !haveView() ) 1695 throw RuntimeException(); 1696 1697 sal_uInt16 nPageId = impl_getPageIdForCategory_nothrow( _rCategory ); 1698 OSL_ENSURE( nPageId != (sal_uInt16)-1, "OPropertyBrowserController::showCategory: invalid category!" ); 1699 1700 getPropertyBox().ShowPropertyPage( nPageId, _bShow ); 1701 } 1702 1703 //------------------------------------------------------------------------ 1704 Reference< XPropertyControl > SAL_CALL OPropertyBrowserController::getPropertyControl( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException) 1705 { 1706 ::osl::MutexGuard aGuard( m_aMutex ); 1707 if ( !haveView() ) 1708 throw RuntimeException(); 1709 1710 Reference< XPropertyControl > xControl( getPropertyBox().GetPropertyControl( _rPropertyName ) ); 1711 return xControl; 1712 } 1713 1714 //-------------------------------------------------------------------- 1715 void SAL_CALL OPropertyBrowserController::registerControlObserver( const Reference< XPropertyControlObserver >& _Observer ) throw (RuntimeException) 1716 { 1717 m_aControlObservers.addInterface( _Observer ); 1718 } 1719 1720 //-------------------------------------------------------------------- 1721 void SAL_CALL OPropertyBrowserController::revokeControlObserver( const Reference< XPropertyControlObserver >& _Observer ) throw (RuntimeException) 1722 { 1723 m_aControlObservers.removeInterface( _Observer ); 1724 } 1725 1726 //------------------------------------------------------------------------ 1727 void SAL_CALL OPropertyBrowserController::setHelpSectionText( const ::rtl::OUString& _rHelpText ) throw (NoSupportException, RuntimeException) 1728 { 1729 ::vos::OGuard aSolarGuard( Application::GetSolarMutex() ); 1730 ::osl::MutexGuard aGuard( m_aMutex ); 1731 1732 if ( !haveView() ) 1733 throw DisposedException(); 1734 1735 if ( !getPropertyBox().HasHelpSection() ) 1736 throw NoSupportException(); 1737 1738 getPropertyBox().SetHelpText( _rHelpText ); 1739 } 1740 1741 //------------------------------------------------------------------------ 1742 void OPropertyBrowserController::impl_broadcastPropertyChange_nothrow( const ::rtl::OUString& _rPropertyName, const Any& _rNewValue, const Any& _rOldValue, bool _bFirstTimeInit ) const 1743 { 1744 // are there one or more handlers which are interested in the actuation? 1745 ::std::pair< PropertyHandlerMultiRepository::const_iterator, PropertyHandlerMultiRepository::const_iterator > aInterestedHandlers = 1746 m_aDependencyHandlers.equal_range( _rPropertyName ); 1747 if ( aInterestedHandlers.first == aInterestedHandlers.second ) 1748 // none of our handlers is interested in this 1749 return; 1750 1751 ComposedUIAutoFireGuard aAutoFireGuard( *m_pUIRequestComposer ); 1752 try 1753 { 1754 // collect the responses from all interested handlers 1755 PropertyHandlerMultiRepository::const_iterator handler = aInterestedHandlers.first; 1756 while ( handler != aInterestedHandlers.second ) 1757 { 1758 handler->second->actuatingPropertyChanged( _rPropertyName, _rNewValue, _rOldValue, 1759 m_pUIRequestComposer->getUIForPropertyHandler( handler->second ), 1760 _bFirstTimeInit ); 1761 ++handler; 1762 } 1763 } 1764 catch( const Exception& ) 1765 { 1766 DBG_UNHANDLED_EXCEPTION(); 1767 } 1768 } 1769 1770 //............................................................................ 1771 } // namespace pcr 1772 //............................................................................ 1773 1774 1775