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