merged tag ooo/OOO330_m14
[LibreOffice.git] / extensions / source / propctrlr / propcontroller.cxx
blobcf14f3778682e6e826a3fac0585fdee404308bc7
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
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.
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).
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.
26 ************************************************************************/
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"
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>
70 #include <algorithm>
71 #include <functional>
73 //------------------------------------------------------------------------
74 // !!! outside the namespace !!!
75 extern "C" void SAL_CALL createRegistryInfo_OPropertyBrowserController()
77 ::pcr::OAutoRegistration< ::pcr::OPropertyBrowserController > aAutoRegistration;
80 //............................................................................
81 namespace pcr
83 //............................................................................
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;
99 #define THISREF() static_cast< XController* >(this)
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 )
116 DBG_CTOR(OPropertyBrowserController,NULL);
119 //------------------------------------------------------------------------
120 OPropertyBrowserController::~OPropertyBrowserController()
122 // stop listening for property changes
123 acquire();
124 stopInspection( true );
125 DBG_DTOR(OPropertyBrowserController,NULL);
128 //------------------------------------------------------------------------
129 IMPLEMENT_FORWARD_REFCOUNT( OPropertyBrowserController, OPropertyBrowserController_Base )
131 //------------------------------------------------------------------------
132 Any SAL_CALL OPropertyBrowserController::queryInterface( const Type& _rType ) throw (RuntimeException)
134 Any aReturn = OPropertyBrowserController_Base::queryInterface( _rType );
135 if ( !aReturn.hasValue() )
136 aReturn = ::cppu::queryInterface(
137 _rType,
138 static_cast< XObjectInspectorUI* >( this )
140 return aReturn;
143 //------------------------------------------------------------------------
144 void OPropertyBrowserController::startContainerWindowListening()
146 if (m_bContainerFocusListening)
147 return;
149 if (m_xFrame.is())
151 Reference< XWindow > xContainerWindow = m_xFrame->getContainerWindow();
152 if (xContainerWindow.is())
154 xContainerWindow->addFocusListener(this);
155 m_bContainerFocusListening = sal_True;
159 DBG_ASSERT(m_bContainerFocusListening, "OPropertyBrowserController::startContainerWindowListening: unable to start listening (inconsistence)!");
162 //------------------------------------------------------------------------
163 void OPropertyBrowserController::stopContainerWindowListening()
165 if (!m_bContainerFocusListening)
166 return;
168 if (m_xFrame.is())
170 Reference< XWindow > xContainerWindow = m_xFrame->getContainerWindow();
171 if (xContainerWindow.is())
173 xContainerWindow->removeFocusListener(this);
174 m_bContainerFocusListening = sal_False;
178 DBG_ASSERT(!m_bContainerFocusListening, "OPropertyBrowserController::stopContainerWindowListening: unable to stop listening (inconsistence)!");
181 //--------------------------------------------------------------------
182 Reference< XObjectInspectorModel > SAL_CALL OPropertyBrowserController::getInspectorModel() throw (RuntimeException)
184 return m_xModel;
187 //--------------------------------------------------------------------
188 void OPropertyBrowserController::impl_initializeView_nothrow()
190 OSL_PRECOND( haveView(), "OPropertyBrowserController::impl_initializeView_nothrow: not to be called when we have no view!" );
191 if ( !haveView() )
192 return;
194 if ( !m_xModel.is() )
195 // allowed
196 return;
200 getPropertyBox().EnableHelpSection( m_xModel->getHasHelpSection() );
201 getPropertyBox().SetHelpLineLimites( m_xModel->getMinHelpTextLines(), m_xModel->getMaxHelpTextLines() );
203 catch( const Exception& )
205 DBG_UNHANDLED_EXCEPTION();
209 //--------------------------------------------------------------------
210 void OPropertyBrowserController::impl_updateReadOnlyView_nothrow()
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 );
221 //--------------------------------------------------------------------
222 bool OPropertyBrowserController::impl_isReadOnlyModel_throw() const
224 if ( !m_xModel.is() )
225 return false;
227 return m_xModel->getIsReadOnly();
230 //--------------------------------------------------------------------
231 void OPropertyBrowserController::impl_startOrStopModelListening_nothrow( bool _bDoListen ) const
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;
241 void (SAL_CALL XPropertySet::*pListenerOperation)( const ::rtl::OUString&, const Reference< XPropertyChangeListener >& )
242 = _bDoListen ? &XPropertySet::addPropertyChangeListener : &XPropertySet::removePropertyChangeListener;
244 (xModelProperties.get()->*pListenerOperation)(
245 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsReadOnly" ) ),
246 const_cast< OPropertyBrowserController* >( this )
249 catch( const Exception& )
251 DBG_UNHANDLED_EXCEPTION();
255 //--------------------------------------------------------------------
256 void OPropertyBrowserController::impl_bindToNewModel_nothrow( const Reference< XObjectInspectorModel >& _rxInspectorModel )
258 impl_startOrStopModelListening_nothrow( false );
259 m_xModel = _rxInspectorModel;
260 impl_startOrStopModelListening_nothrow( true );
262 // initialize the view, if we already have one
263 if ( haveView() )
264 impl_initializeView_nothrow();
266 // inspect again, if we already have inspectees
267 if ( !m_aInspectedObjects.empty() )
268 impl_rebindToInspectee_nothrow( m_aInspectedObjects );
271 //--------------------------------------------------------------------
272 void SAL_CALL OPropertyBrowserController::setInspectorModel( const Reference< XObjectInspectorModel >& _inspectorModel ) throw (RuntimeException)
274 ::osl::MutexGuard aGuard( m_aMutex );
276 if ( m_xModel == _inspectorModel )
277 return;
279 impl_bindToNewModel_nothrow( _inspectorModel );
282 //--------------------------------------------------------------------
283 Reference< XObjectInspectorUI > SAL_CALL OPropertyBrowserController::getInspectorUI() throw (RuntimeException)
285 // we're derived from this interface, though we do not expose it in queryInterface and getTypes.
286 return this;
289 //--------------------------------------------------------------------
290 void SAL_CALL OPropertyBrowserController::inspect( const Sequence< Reference< XInterface > >& _rObjects ) throw (com::sun::star::util::VetoException, RuntimeException)
292 ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
293 ::osl::MutexGuard aGuard( m_aMutex );
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();
301 if ( m_bBindingIntrospectee )
302 throw VetoException();
304 m_bBindingIntrospectee = true;
305 impl_rebindToInspectee_nothrow( InterfaceArray( _rObjects.getConstArray(), _rObjects.getConstArray() + _rObjects.getLength() ) );
306 m_bBindingIntrospectee = false;
310 //--------------------------------------------------------------------
311 Reference< XDispatch > SAL_CALL OPropertyBrowserController::queryDispatch( const URL& /*URL*/, const ::rtl::OUString& /*TargetFrameName*/, ::sal_Int32 /*SearchFlags*/ ) throw (RuntimeException)
313 // we don't have any dispatches at all, right now
314 return Reference< XDispatch >();
317 //--------------------------------------------------------------------
318 Sequence< Reference< XDispatch > > SAL_CALL OPropertyBrowserController::queryDispatches( const Sequence< DispatchDescriptor >& Requests ) throw (RuntimeException)
320 Sequence< Reference< XDispatch > > aReturn;
321 sal_Int32 nLen = Requests.getLength();
322 aReturn.realloc( nLen );
324 Reference< XDispatch >* pReturn = aReturn.getArray();
325 const Reference< XDispatch >* pReturnEnd = aReturn.getArray() + nLen;
326 const DispatchDescriptor* pDescripts = Requests.getConstArray();
328 for ( ; pReturn != pReturnEnd; ++ pReturn, ++pDescripts )
329 *pReturn = queryDispatch( pDescripts->FeatureURL, pDescripts->FrameName, pDescripts->SearchFlags );
331 return aReturn;
334 //------------------------------------------------------------------------
335 void SAL_CALL OPropertyBrowserController::initialize( const Sequence< Any >& _arguments ) throw (Exception, RuntimeException)
337 if ( m_bConstructed )
338 throw AlreadyInitializedException();
340 StlSyntaxSequence< Any > arguments( _arguments );
341 if ( arguments.empty() )
342 { // constructor: "createDefault()"
343 createDefault();
344 return;
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;
356 throw IllegalArgumentException( ::rtl::OUString(), *this, 0 );
359 //------------------------------------------------------------------------
360 void OPropertyBrowserController::createDefault()
362 m_bConstructed = true;
365 //------------------------------------------------------------------------
366 void OPropertyBrowserController::createWithModel( const Reference< XObjectInspectorModel >& _rxModel )
368 osl_incrementInterlockedCount( &m_refCount );
370 setInspectorModel( _rxModel );
372 osl_decrementInterlockedCount( &m_refCount );
374 m_bConstructed = true;
377 //------------------------------------------------------------------------
378 void SAL_CALL OPropertyBrowserController::attachFrame( const Reference< XFrame >& _rxFrame ) throw(RuntimeException)
380 ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
381 ::osl::MutexGuard aGuard( m_aMutex );
383 if (_rxFrame.is() && haveView())
384 throw RuntimeException(::rtl::OUString::createFromAscii("Unable to attach to a second frame."),*this);
386 // revoke as focus listener from the old container window
387 stopContainerWindowListening();
389 m_xFrame = _rxFrame;
390 if (!m_xFrame.is())
391 return;
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);
402 if ( Construct( pParentWin ) )
406 m_xFrame->setComponent( VCLUnoHelper::GetInterface( m_pView ), this );
408 catch( const Exception& )
410 OSL_ENSURE( sal_False, "OPropertyBrowserController::attachFrame: caught an exception!" );
414 startContainerWindowListening();
416 UpdateUI();
419 //------------------------------------------------------------------------
420 sal_Bool SAL_CALL OPropertyBrowserController::attachModel( const Reference< XModel >& _rxModel ) throw(RuntimeException)
422 Reference< XObjectInspectorModel > xModel( _rxModel, UNO_QUERY );
423 if ( !xModel.is() )
424 return false;
426 setInspectorModel( xModel );
427 return getInspectorModel() == _rxModel;
430 //------------------------------------------------------------------------
431 sal_Bool OPropertyBrowserController::suspendAll_nothrow()
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;
440 m_bSuspendingPropertyHandlers = true;
441 sal_Bool bHandlerVeto = !suspendPropertyHandlers_nothrow( sal_True );
442 m_bSuspendingPropertyHandlers = false;
443 if ( bHandlerVeto )
444 return sal_False;
446 return sal_True;
449 //------------------------------------------------------------------------
450 sal_Bool OPropertyBrowserController::suspendPropertyHandlers_nothrow( sal_Bool _bSuspend )
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
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 );
465 for ( PropertyHandlerArray::iterator loop = aAllHandlers.begin();
466 loop != aAllHandlers.end();
467 ++loop
472 if ( !(*loop)->suspend( _bSuspend ) )
473 if ( _bSuspend )
474 // if we're not suspending, but reactivating, ignore the error
475 return sal_False;
477 catch( const Exception& )
479 OSL_ENSURE( sal_False, "OPropertyBrowserController::suspendPropertyHandlers_nothrow: caught an exception!" );
482 return sal_True;
485 //------------------------------------------------------------------------
486 sal_Bool SAL_CALL OPropertyBrowserController::suspend( sal_Bool _bSuspend ) throw(RuntimeException)
488 ::osl::MutexGuard aGuard( m_aMutex );
489 OSL_ENSURE( haveView(), "OPropertyBrowserController::suspend: don't have a view anymore!" );
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;
498 if ( !suspendAll_nothrow() )
499 return sal_False;
501 // commit the editor's content
502 if ( haveView() )
503 getPropertyBox().CommitModified();
505 // stop listening
506 stopContainerWindowListening();
508 // outtahere
509 return sal_True;
512 //------------------------------------------------------------------------
513 Any SAL_CALL OPropertyBrowserController::getViewData( ) throw(RuntimeException)
515 return makeAny( m_sPageSelection );
518 //------------------------------------------------------------------------
519 void SAL_CALL OPropertyBrowserController::restoreViewData( const Any& Data ) throw(RuntimeException)
521 ::rtl::OUString sPageSelection;
522 if ( ( Data >>= sPageSelection ) && sPageSelection.getLength() )
524 m_sPageSelection = sPageSelection;
525 selectPageFromViewData();
529 //------------------------------------------------------------------------
530 Reference< XModel > SAL_CALL OPropertyBrowserController::getModel( ) throw(RuntimeException)
532 // have no model
533 return Reference< XModel >();
536 //------------------------------------------------------------------------
537 Reference< XFrame > SAL_CALL OPropertyBrowserController::getFrame( ) throw(RuntimeException)
539 return m_xFrame;
542 //------------------------------------------------------------------------
543 void SAL_CALL OPropertyBrowserController::dispose( ) throw(RuntimeException)
545 ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
547 // stop inspecting the current object
548 stopInspection( false );
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);
556 // don't delete explicitly (this is done by the frame we reside in)
557 m_pView = NULL;
559 Reference< XComponent > xViewAsComp( m_xView, UNO_QUERY );
560 if ( xViewAsComp.is() )
561 xViewAsComp->removeEventListener( static_cast< XPropertyChangeListener* >( this ) );
562 m_xView.clear( );
564 m_aInspectedObjects.clear();
565 impl_bindToNewModel_nothrow( NULL );
568 //------------------------------------------------------------------------
569 void SAL_CALL OPropertyBrowserController::addEventListener( const Reference< XEventListener >& _rxListener ) throw(RuntimeException)
571 m_aDisposeListeners.addInterface(_rxListener);
574 //------------------------------------------------------------------------
575 void SAL_CALL OPropertyBrowserController::removeEventListener( const Reference< XEventListener >& _rxListener ) throw(RuntimeException)
577 m_aDisposeListeners.removeInterface(_rxListener);
580 //------------------------------------------------------------------------
581 ::rtl::OUString SAL_CALL OPropertyBrowserController::getImplementationName( ) throw(RuntimeException)
583 return getImplementationName_static();
586 //------------------------------------------------------------------------
587 sal_Bool SAL_CALL OPropertyBrowserController::supportsService( const ::rtl::OUString& ServiceName ) throw(RuntimeException)
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;
597 //------------------------------------------------------------------------
598 Sequence< ::rtl::OUString > SAL_CALL OPropertyBrowserController::getSupportedServiceNames( ) throw(RuntimeException)
600 return getSupportedServiceNames_static();
603 //------------------------------------------------------------------------
604 ::rtl::OUString OPropertyBrowserController::getImplementationName_static( ) throw(RuntimeException)
606 return ::rtl::OUString::createFromAscii("org.openoffice.comp.extensions.ObjectInspector");
609 //------------------------------------------------------------------------
610 Sequence< ::rtl::OUString > OPropertyBrowserController::getSupportedServiceNames_static( ) throw(RuntimeException)
612 Sequence< ::rtl::OUString > aSupported(1);
613 aSupported[0] = ::rtl::OUString::createFromAscii( "com.sun.star.inspection.ObjectInspector" );
614 return aSupported;
617 //------------------------------------------------------------------------
618 Reference< XInterface > SAL_CALL OPropertyBrowserController::Create(const Reference< XComponentContext >& _rxContext)
620 return *(new OPropertyBrowserController( _rxContext ) );
623 //------------------------------------------------------------------------
624 void SAL_CALL OPropertyBrowserController::focusGained( const FocusEvent& _rSource ) throw (RuntimeException)
626 Reference< XWindow > xSourceWindow(_rSource.Source, UNO_QUERY);
627 Reference< XWindow > xContainerWindow;
628 if (m_xFrame.is())
629 xContainerWindow = m_xFrame->getContainerWindow();
631 if ( xContainerWindow.get() == xSourceWindow.get() )
632 { // our container window got the focus
633 if ( haveView() )
634 getPropertyBox().GrabFocus();
638 //------------------------------------------------------------------------
639 void SAL_CALL OPropertyBrowserController::focusLost( const FocusEvent& /*_rSource*/ ) throw (RuntimeException)
641 // not interested in
644 //------------------------------------------------------------------------
645 void SAL_CALL OPropertyBrowserController::disposing( const EventObject& _rSource ) throw(RuntimeException)
647 if ( m_xView.is() && ( m_xView == _rSource.Source ) )
649 m_xView = NULL;
650 m_pView = NULL;
653 for ( InterfaceArray::iterator loop = m_aInspectedObjects.begin();
654 loop != m_aInspectedObjects.end();
655 ++loop
658 if ( *loop == _rSource.Source )
660 m_aInspectedObjects.erase( loop );
661 break;
666 //------------------------------------------------------------------------
667 IMPL_LINK(OPropertyBrowserController, OnPageActivation, void*, EMPTYARG)
669 updateViewDataFromActivePage();
670 return 0L;
673 //------------------------------------------------------------------------
674 void OPropertyBrowserController::updateViewDataFromActivePage()
676 if (!haveView())
677 return;
679 ::rtl::OUString sOldSelection = m_sPageSelection;
680 m_sPageSelection = ::rtl::OUString();
682 const sal_uInt16 nCurrentPage = m_pView->getActivaPage();
683 if ( (sal_uInt16)-1 != nCurrentPage )
685 for ( HashString2Int16::const_iterator pageId = m_aPageIds.begin();
686 pageId != m_aPageIds.end();
687 ++pageId
690 if ( nCurrentPage == pageId->second )
692 m_sPageSelection = pageId->first;
693 break;
698 if ( m_sPageSelection.getLength() )
699 m_sLastValidPageSelection = m_sPageSelection;
700 else if ( sOldSelection.getLength() )
701 m_sLastValidPageSelection = sOldSelection;
704 //------------------------------------------------------------------------
705 sal_uInt16 OPropertyBrowserController::impl_getPageIdForCategory_nothrow( const ::rtl::OUString& _rCategoryName ) const
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;
714 //------------------------------------------------------------------------
715 void OPropertyBrowserController::selectPageFromViewData()
717 sal_uInt16 nNewPage = impl_getPageIdForCategory_nothrow( m_sPageSelection );
719 if ( haveView() && ( nNewPage != (sal_uInt16)-1 ) )
720 m_pView->activatePage( nNewPage );
722 // just in case ...
723 updateViewDataFromActivePage();
726 //------------------------------------------------------------------------
727 sal_Bool OPropertyBrowserController::Construct(Window* _pParentWin)
729 DBG_ASSERT(!haveView(), "OPropertyBrowserController::Construct: already have a view!");
730 DBG_ASSERT(_pParentWin, "OPropertyBrowserController::Construct: invalid parent window!");
732 m_pView = new OPropertyBrowserView(m_aContext.getLegacyServiceFactory(), _pParentWin);
733 m_pView->setPageActivationHandler(LINK(this, OPropertyBrowserController, OnPageActivation));
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 ) );
743 getPropertyBox().SetLineListener(this);
744 getPropertyBox().SetControlObserver(this);
745 impl_initializeView_nothrow();
747 m_pView->Show();
749 return sal_True;
752 //------------------------------------------------------------------------
753 void SAL_CALL OPropertyBrowserController::propertyChange( const PropertyChangeEvent& _rEvent ) throw (RuntimeException)
755 if ( _rEvent.Source == m_xModel )
757 if ( _rEvent.PropertyName.equalsAscii( "IsReadOnly" ) )
758 impl_updateReadOnlyView_nothrow();
759 return;
762 if ( m_sCommittingProperty == _rEvent.PropertyName )
763 return;
765 if ( !haveView() )
766 return;
768 Any aNewValue( _rEvent.NewValue );
769 if ( impl_hasPropertyHandlerFor_nothrow( _rEvent.PropertyName ) )
771 // forward the new value to the property box, to reflect the change in the UI
772 aNewValue = impl_getPropertyValue_throw( _rEvent.PropertyName );
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 );
781 getPropertyBox().SetPropertyValue( _rEvent.PropertyName, aNewValue, bAmbiguousValue );
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 );
790 //------------------------------------------------------------------------
791 Reference< XPropertyControl > SAL_CALL OPropertyBrowserController::createPropertyControl( ::sal_Int16 ControlType, ::sal_Bool _CreateReadOnly ) throw (IllegalArgumentException, RuntimeException)
793 ::osl::MutexGuard aGuard( m_aMutex );
795 Reference< XPropertyControl > xControl;
797 // default winbits: a border only
798 WinBits nWinBits = WB_BORDER;
800 // read-only-ness
801 _CreateReadOnly |= (sal_Bool)impl_isReadOnlyModel_throw();
802 if ( _CreateReadOnly )
803 nWinBits |= WB_READONLY;
805 switch ( ControlType )
807 case PropertyControlType::StringListField:
808 xControl = new OMultilineEditControl( &getPropertyBox(), eStringList, nWinBits | WB_DROPDOWN | WB_TABSTOP );
809 break;
811 case PropertyControlType::MultiLineTextField:
812 xControl = new OMultilineEditControl( &getPropertyBox(), eMultiLineText, nWinBits | WB_DROPDOWN | WB_TABSTOP );
813 break;
815 case PropertyControlType::ListBox:
816 xControl = new OListboxControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_DROPDOWN);
817 break;
819 case PropertyControlType::ComboBox:
820 xControl = new OComboboxControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_DROPDOWN);
821 break;
823 case PropertyControlType::TextField:
824 xControl = new OEditControl( &getPropertyBox(), sal_False, nWinBits | WB_TABSTOP );
825 break;
827 case PropertyControlType::CharacterField:
828 xControl = new OEditControl( &getPropertyBox(), sal_True, nWinBits | WB_TABSTOP );
829 break;
831 case PropertyControlType::NumericField:
832 xControl = new ONumericControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_SPIN | WB_REPEAT );
833 break;
835 case PropertyControlType::DateTimeField:
836 xControl = new ODateTimeControl( &getPropertyBox(), nWinBits | WB_TABSTOP );
837 break;
839 case PropertyControlType::DateField:
840 xControl = new ODateControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_SPIN | WB_REPEAT );
841 break;
843 case PropertyControlType::TimeField:
844 xControl = new OTimeControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_SPIN | WB_REPEAT );
845 break;
847 case PropertyControlType::ColorListBox:
848 xControl = new OColorControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_DROPDOWN );
849 break;
851 case PropertyControlType::HyperlinkField:
852 xControl = new OHyperlinkControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_DROPDOWN );
853 break;
855 default:
856 throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
859 return xControl;
862 //------------------------------------------------------------------------
863 void OPropertyBrowserController::impl_toggleInspecteeListening_nothrow( bool _bOn )
865 for ( InterfaceArray::const_iterator loop = m_aInspectedObjects.begin();
866 loop != m_aInspectedObjects.end();
867 ++loop
872 Reference< XComponent > xComp( *loop, UNO_QUERY );
873 if ( xComp.is() )
875 if ( _bOn )
876 xComp->addEventListener( static_cast< XPropertyChangeListener* >( this ) );
877 else
878 xComp->removeEventListener( static_cast< XPropertyChangeListener* >( this ) );
881 catch( const Exception& )
883 DBG_UNHANDLED_EXCEPTION();
888 //------------------------------------------------------------------------
889 void OPropertyBrowserController::stopInspection( bool _bCommitModified )
891 if ( haveView() )
893 if ( _bCommitModified )
894 // commit the editor's content
895 getPropertyBox().CommitModified();
897 // hide the property box so that it does not flicker
898 getPropertyBox().Hide();
900 // clear the property box
901 getPropertyBox().ClearAll();
904 // destroy the view first
905 if ( haveView() )
907 // remove the pages
908 for ( HashString2Int16::const_iterator erase = m_aPageIds.begin();
909 erase != m_aPageIds.end();
910 ++erase
912 getPropertyBox().RemovePage( erase->second );
913 clearContainer( m_aPageIds );
916 clearContainer( m_aProperties );
918 // de-register as dispose-listener from our inspected objects
919 impl_toggleInspecteeListening_nothrow( false );
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 );
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
932 if ( ::std::find( aAllHandlers.begin(), aAllHandlers.end(), aHandler->second ) == aAllHandlers.end() )
933 aAllHandlers.push_back( aHandler->second );
935 for ( PropertyHandlerArray::iterator loop = aAllHandlers.begin();
936 loop != aAllHandlers.end();
937 ++loop
942 (*loop)->removePropertyChangeListener( this );
943 (*loop)->dispose();
945 catch( const DisposedException& )
948 catch( const Exception& )
950 DBG_UNHANDLED_EXCEPTION();
954 clearContainer( m_aPropertyHandlers );
955 clearContainer( m_aDependencyHandlers );
958 //------------------------------------------------------------------------
959 bool OPropertyBrowserController::impl_hasPropertyHandlerFor_nothrow( const ::rtl::OUString& _rPropertyName ) const
961 PropertyHandlerRepository::const_iterator handlerPos = m_aPropertyHandlers.find( _rPropertyName );
962 return ( handlerPos != m_aPropertyHandlers.end() );
965 //------------------------------------------------------------------------
966 OPropertyBrowserController::PropertyHandlerRef OPropertyBrowserController::impl_getHandlerForProperty_throw( const ::rtl::OUString& _rPropertyName ) const
968 PropertyHandlerRepository::const_iterator handlerPos = m_aPropertyHandlers.find( _rPropertyName );
969 if ( handlerPos == m_aPropertyHandlers.end() )
970 throw RuntimeException();
971 return handlerPos->second;
974 //------------------------------------------------------------------------
975 Any OPropertyBrowserController::impl_getPropertyValue_throw( const ::rtl::OUString& _rPropertyName )
977 PropertyHandlerRef handler = impl_getHandlerForProperty_throw( _rPropertyName );
978 return handler->getPropertyValue( _rPropertyName );
981 //------------------------------------------------------------------------
982 void OPropertyBrowserController::impl_rebindToInspectee_nothrow( const InterfaceArray& _rObjects )
986 // stop inspecting the old object(s)
987 stopInspection( true );
989 // inspect the new object(s)
990 m_aInspectedObjects = _rObjects;
991 doInspection();
993 // update the user interface
994 UpdateUI();
997 catch(Exception&)
999 DBG_ERROR("OPropertyBrowserController::impl_rebindToInspectee_nothrow: caught an exception !");
1003 //------------------------------------------------------------------------
1004 void OPropertyBrowserController::doInspection()
1008 //////////////////////////////////////////////////////////////////////
1009 // obtain the properties of the object
1010 ::std::vector< Property > aProperties;
1012 PropertyHandlerArray aPropertyHandlers;
1013 getPropertyHandlers( m_aInspectedObjects, aPropertyHandlers );
1015 PropertyHandlerArray::iterator aHandler( aPropertyHandlers.begin() );
1016 while ( aHandler != aPropertyHandlers.end() )
1018 DBG_ASSERT( aHandler->get(), "OPropertyBrowserController::doInspection: invalid handler!" );
1020 StlSyntaxSequence< Property > aThisHandlersProperties = (*aHandler)->getSupportedProperties();
1022 if ( aThisHandlersProperties.empty() )
1024 // this handler doesn't know anything about the current inspectee -> ignore it
1025 (*aHandler)->dispose();
1026 aHandler = aPropertyHandlers.erase( aHandler );
1027 continue;
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
1037 ::std::vector< Property >::const_iterator previous = ::std::find_if(
1038 aProperties.begin(),
1039 aProperties.end(),
1040 FindPropertyByName( copyProperty->Name )
1042 if ( previous == aProperties.end() )
1044 aProperties.push_back( *copyProperty );
1045 continue;
1048 // there already was another (previous) handler which supported this property.
1049 // Don't add it to aProperties, again.
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 );
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
1068 ::std::vector< Property >::iterator existent = ::std::find_if(
1069 aProperties.begin(),
1070 aProperties.end(),
1071 FindPropertyByName( *superseded )
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 );
1079 // be notified of changes which this handler is responsible for
1080 (*aHandler)->addPropertyChangeListener( this );
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
1089 m_aPropertyHandlers[ remember->Name ] = *aHandler;
1090 // note that this implies that if two handlers support the same property,
1091 // the latter wins
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
1101 m_aDependencyHandlers.insert( PropertyHandlerMultiRepository::value_type(
1102 *aLoop, *aHandler ) );
1105 ++aHandler;
1108 // create a new composer for UI requests coming from the handlers
1109 m_pUIRequestComposer.reset( new ComposedPropertyUIUpdate( getInspectorUI(), this ) );
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
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;
1125 // be notified when one of our inspectees dies
1126 impl_toggleInspecteeListening_nothrow( true );
1128 catch(Exception&)
1130 DBG_ERROR("OPropertyBrowserController::doInspection : caught an exception !");
1134 //------------------------------------------------------------------------
1135 ::com::sun::star::awt::Size SAL_CALL OPropertyBrowserController::getMinimumSize() throw (::com::sun::star::uno::RuntimeException)
1137 ::com::sun::star::awt::Size aSize;
1138 if( m_pView )
1139 return m_pView->getMinimumSize();
1140 else
1141 return aSize;
1144 //------------------------------------------------------------------------
1145 ::com::sun::star::awt::Size SAL_CALL OPropertyBrowserController::getPreferredSize() throw (::com::sun::star::uno::RuntimeException)
1147 return getMinimumSize();
1150 //------------------------------------------------------------------------
1151 ::com::sun::star::awt::Size SAL_CALL OPropertyBrowserController::calcAdjustedSize( const ::com::sun::star::awt::Size& _rNewSize ) throw (::com::sun::star::uno::RuntimeException)
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;
1162 //------------------------------------------------------------------------
1163 void OPropertyBrowserController::describePropertyLine( const Property& _rProperty, OLineDescriptor& _rDescriptor ) SAL_THROW((Exception))
1167 PropertyHandlerRepository::const_iterator handler = m_aPropertyHandlers.find( _rProperty.Name );
1168 if ( handler == m_aPropertyHandlers.end() )
1169 throw RuntimeException(); // caught below
1171 _rDescriptor.assignFrom( handler->second->describePropertyLine( _rProperty.Name, this ) );
1173 //////////////////////////////////////////////////////////////////////
1175 _rDescriptor.xPropertyHandler = handler->second;
1176 _rDescriptor.sName = _rProperty.Name;
1177 _rDescriptor.aValue = _rDescriptor.xPropertyHandler->getPropertyValue( _rProperty.Name );
1179 if ( !_rDescriptor.DisplayName.getLength() )
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;
1190 PropertyState ePropertyState( _rDescriptor.xPropertyHandler->getPropertyState( _rProperty.Name ) );
1191 if ( PropertyState_AMBIGUOUS_VALUE == ePropertyState )
1193 _rDescriptor.bUnknownValue = true;
1194 _rDescriptor.aValue.clear();
1197 _rDescriptor.bReadOnly = impl_isReadOnlyModel_throw();
1199 catch( const Exception& )
1201 OSL_ENSURE( sal_False, "OPropertyBrowserController::describePropertyLine: caught an exception!" );
1205 //------------------------------------------------------------------------
1206 void OPropertyBrowserController::impl_buildCategories_throw()
1208 OSL_PRECOND( m_aPageIds.empty(), "OPropertyBrowserController::impl_buildCategories_throw: duplicate call!" );
1210 StlSyntaxSequence< PropertyCategoryDescriptor > aCategories;
1211 if ( m_xModel.is() )
1212 aCategories = m_xModel->describeCategories();
1214 for ( StlSyntaxSequence< PropertyCategoryDescriptor >::const_iterator category = aCategories.begin();
1215 category != aCategories.end();
1216 ++category
1219 OSL_ENSURE( m_aPageIds.find( category->ProgrammaticName ) == m_aPageIds.end(),
1220 "OPropertyBrowserController::impl_buildCategories_throw: duplicate programmatic name!" );
1222 m_aPageIds[ category->ProgrammaticName ] =
1223 getPropertyBox().AppendPage( category->UIName, HelpIdUrl::getHelpId( category->HelpURL ) );
1227 //------------------------------------------------------------------------
1228 void OPropertyBrowserController::UpdateUI()
1232 if ( !haveView() )
1233 // too early, will return later
1234 return;
1236 getPropertyBox().DisableUpdate();
1238 sal_Bool bHaveFocus = getPropertyBox().HasChildPathFocus();
1240 // create our tab pages
1241 impl_buildCategories_throw();
1242 // (and allow for pages to be actually unused)
1243 ::std::set< sal_uInt16 > aUsedPages;
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;
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 )
1255 OLineDescriptor aDescriptor;
1256 describePropertyLine( property->second, aDescriptor );
1258 bool bIsActuatingProperty = impl_isActuatingProperty_nothrow( property->second.Name );
1260 #if OSL_DEBUG_LEVEL > 0
1261 if ( !aDescriptor.Category.getLength() )
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 );
1268 #endif
1269 // finally insert this property control
1270 sal_uInt16 nTargetPageId = impl_getPageIdForCategory_nothrow( aDescriptor.Category );
1271 if ( nTargetPageId == (sal_uInt16)-1 )
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, SmartId() );
1277 nTargetPageId = impl_getPageIdForCategory_nothrow( aDescriptor.Category );
1280 getPropertyBox().InsertEntry( aDescriptor, nTargetPageId );
1281 aUsedPages.insert( nTargetPageId );
1283 // if it's an actuating property, remember it
1284 if ( bIsActuatingProperty )
1286 aActuatingProperties.push_back( property->second.Name );
1287 aActuatingPropertyValues.push_back( impl_getPropertyValue_throw( property->second.Name ) );
1291 // update any dependencies for the actuating properties which we encountered
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 );
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
1306 if ( aUsedPages.find( pageId->second ) == aUsedPages.end() )
1307 getPropertyBox().RemovePage( pageId->second );
1308 else
1309 aSurvivingPageIds.insert( *pageId );
1311 m_aPageIds.swap( aSurvivingPageIds );
1314 getPropertyBox().Show();
1315 getPropertyBox().EnableUpdate();
1316 if ( bHaveFocus )
1317 getPropertyBox().GrabFocus();
1319 // activate the first page
1320 if ( !m_aPageIds.empty() )
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 );
1330 // activate the previously active page (if possible)
1331 if ( m_sLastValidPageSelection.getLength() )
1332 m_sPageSelection = m_sLastValidPageSelection;
1333 selectPageFromViewData();
1335 catch( const Exception& )
1337 DBG_UNHANDLED_EXCEPTION();
1341 //------------------------------------------------------------------------
1342 void OPropertyBrowserController::Clicked( const ::rtl::OUString& _rName, sal_Bool _bPrimary )
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();
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!" );
1353 ComposedUIAutoFireGuard aAutoFireGuard( *m_pUIRequestComposer );
1355 Any aData;
1356 m_xInteractiveHandler = handler->second;
1357 InteractiveSelectionResult eResult =
1358 handler->second->onInteractivePropertySelection( _rName, _bPrimary, aData,
1359 m_pUIRequestComposer->getUIForPropertyHandler( handler->second ) );
1361 switch ( eResult )
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;
1378 catch (Exception&)
1380 DBG_UNHANDLED_EXCEPTION();
1382 m_xInteractiveHandler = NULL;
1385 //------------------------------------------------------------------------
1386 sal_Bool SAL_CALL OPropertyBrowserController::hasPropertyByName( const ::rtl::OUString& _rName ) throw (RuntimeException)
1388 for ( OrderedPropertyMap::const_iterator search = m_aProperties.begin();
1389 search != m_aProperties.end();
1390 ++search
1392 if ( search->second.Name == _rName )
1393 return true;
1394 return false;
1397 //------------------------------------------------------------------------
1398 void OPropertyBrowserController::Commit( const ::rtl::OUString& rName, const Any& _rValue )
1402 rtl::OUString sPlcHolder = String( PcrRes( RID_EMBED_IMAGE_PLACEHOLDER ) );
1403 bool bIsPlaceHolderValue = false;
1405 if ( rName.equals( PROPERTY_IMAGE_URL ) )
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;
1414 m_sCommittingProperty = rName;
1416 bool bIsActuatingProperty = impl_isActuatingProperty_nothrow( rName );
1418 Any aOldValue;
1419 if ( bIsActuatingProperty )
1420 aOldValue = impl_getPropertyValue_throw( rName );
1422 // do we have a dedicated handler for this property, which we can delegate some tasks to?
1423 PropertyHandlerRef handler = impl_getHandlerForProperty_throw( rName );
1425 //////////////////////////////////////////////////////////////////////
1426 // set the value ( only if it's not a placeholder )
1427 if ( !bIsPlaceHolderValue )
1428 handler->setPropertyValue( rName, _rValue );
1430 //////////////////////////////////////////////////////////////////////
1431 // re-retrieve the value
1432 Any aNormalizedValue = handler->getPropertyValue( rName );
1434 // care for any inter-property dependencies
1435 if ( bIsActuatingProperty )
1436 impl_broadcastPropertyChange_nothrow( rName, aNormalizedValue, aOldValue, false );
1438 // and display it again. This ensures proper formatting
1439 getPropertyBox().SetPropertyValue( rName, aNormalizedValue, false );
1441 catch(PropertyVetoException& eVetoException)
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 );
1448 catch(Exception&)
1450 DBG_ERROR("OPropertyBrowserController::Commit : caught an exception !");
1453 m_sCommittingProperty = ::rtl::OUString();
1456 //--------------------------------------------------------------------
1457 namespace
1461 //--------------------------------------------------------------------
1462 void OPropertyBrowserController::focusGained( const Reference< XPropertyControl >& _Control )
1464 m_aControlObservers.notifyEach( &XPropertyControlObserver::focusGained, _Control );
1467 //--------------------------------------------------------------------
1468 void OPropertyBrowserController::valueChanged( const Reference< XPropertyControl >& _Control )
1470 m_aControlObservers.notifyEach( &XPropertyControlObserver::valueChanged, _Control );
1473 //------------------------------------------------------------------------
1474 namespace
1476 Reference< XPropertyHandler > lcl_createHandler( const ComponentContext& _rContext, const Any& _rFactoryDescriptor )
1478 Reference< XPropertyHandler > xHandler;
1480 ::rtl::OUString sServiceName;
1481 Reference< XSingleServiceFactory > xServiceFac;
1482 Reference< XSingleComponentFactory > xComponentFac;
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;
1495 //------------------------------------------------------------------------
1496 void OPropertyBrowserController::getPropertyHandlers( const InterfaceArray& _rObjects, PropertyHandlerArray& _rHandlers )
1498 _rHandlers.resize( 0 );
1499 if ( _rObjects.empty() )
1500 return;
1502 // create a component context for the handlers, containing some information about where
1503 // they live
1504 Reference< XComponentContext > xHandlerContext( m_aContext.getUNOContext() );
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() )
1510 ::cppu::ContextEntry_Init aHandlerContextInfo[] =
1512 ::cppu::ContextEntry_Init( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DialogParentWindow" ) ), makeAny( VCLUnoHelper::GetInterface( m_pView ) ) )
1514 xHandlerContext = ::cppu::createComponentContext(
1515 aHandlerContextInfo, sizeof( aHandlerContextInfo ) / sizeof( aHandlerContextInfo[0] ),
1516 m_aContext.getUNOContext() );
1519 Sequence< Any > aHandlerFactories;
1520 if ( m_xModel.is() )
1521 aHandlerFactories = m_xModel->getHandlerFactories();
1523 const Any* pHandlerFactory = aHandlerFactories.getConstArray();
1524 const Any* pHandlerFactoryEnd = aHandlerFactories.getConstArray() + aHandlerFactories.getLength();
1526 while ( pHandlerFactory != pHandlerFactoryEnd )
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() )
1533 xHandler->inspect( _rObjects[0] );
1534 _rHandlers.push_back( xHandler );
1537 else
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();
1543 InterfaceArray::const_iterator pObject = _rObjects.begin();
1544 InterfaceArray::const_iterator pObjectEnd = _rObjects.end();
1546 for ( ; pObject != pObjectEnd; ++pObject )
1548 *pHandler = lcl_createHandler( m_aContext, *pHandlerFactory );
1549 if ( pHandler->is() )
1551 (*pHandler)->inspect( *pObject );
1552 ++pHandler;
1555 aSingleHandlers.resize( pHandler - aSingleHandlers.begin() );
1557 // then create a handler which composes information out of those single handlers
1558 if ( !aSingleHandlers.empty() )
1559 _rHandlers.push_back( new PropertyComposer( aSingleHandlers ) );
1562 ++pHandlerFactory;
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
1569 //------------------------------------------------------------------------
1570 bool OPropertyBrowserController::impl_findObjectProperty_nothrow( const ::rtl::OUString& _rName, OrderedPropertyMap::const_iterator* _pProperty )
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() );
1581 //------------------------------------------------------------------------
1582 void OPropertyBrowserController::rebuildPropertyUI( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException)
1584 ::osl::MutexGuard aGuard( m_aMutex );
1585 if ( !haveView() )
1586 throw RuntimeException();
1588 OrderedPropertyMap::const_iterator propertyPos;
1589 if ( !impl_findObjectProperty_nothrow( _rPropertyName, &propertyPos ) )
1590 return;
1592 OLineDescriptor aDescriptor;
1595 describePropertyLine( propertyPos->second, aDescriptor );
1597 catch( const Exception& )
1599 OSL_ENSURE( sal_False, "OPropertyBrowserController::rebuildPropertyUI: caught an exception!" );
1602 getPropertyBox().ChangeEntry( aDescriptor );
1605 //------------------------------------------------------------------------
1606 void OPropertyBrowserController::enablePropertyUI( const ::rtl::OUString& _rPropertyName, sal_Bool _bEnable ) throw (RuntimeException)
1608 ::osl::MutexGuard aGuard( m_aMutex );
1609 if ( !haveView() )
1610 throw RuntimeException();
1612 if ( !impl_findObjectProperty_nothrow( _rPropertyName ) )
1613 return;
1615 getPropertyBox().EnablePropertyLine( _rPropertyName, _bEnable );
1618 //------------------------------------------------------------------------
1619 void OPropertyBrowserController::enablePropertyUIElements( const ::rtl::OUString& _rPropertyName, sal_Int16 _nElements, sal_Bool _bEnable ) throw (RuntimeException)
1621 ::osl::MutexGuard aGuard( m_aMutex );
1622 if ( !haveView() )
1623 throw RuntimeException();
1625 if ( !impl_findObjectProperty_nothrow( _rPropertyName ) )
1626 return;
1628 getPropertyBox().EnablePropertyControls( _rPropertyName, _nElements, _bEnable );
1631 //------------------------------------------------------------------------
1632 void OPropertyBrowserController::showPropertyUI( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException)
1634 ::osl::MutexGuard aGuard( m_aMutex );
1635 if ( !haveView() )
1636 throw RuntimeException();
1638 // look up the property in our object properties
1639 OrderedPropertyMap::const_iterator propertyPos;
1640 if ( !impl_findObjectProperty_nothrow( _rPropertyName, &propertyPos ) )
1641 return;
1643 if ( getPropertyBox().GetPropertyPos( _rPropertyName ) != LISTBOX_ENTRY_NOTFOUND )
1645 rebuildPropertyUI( _rPropertyName );
1646 return;
1649 OLineDescriptor aDescriptor;
1650 describePropertyLine( propertyPos->second, aDescriptor );
1652 // look for the position to insert the property
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.
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;
1664 if ( propertyPos != m_aProperties.begin() )
1665 --propertyPos;
1666 nUIPos = getPropertyBox().GetPropertyPos( propertyPos->second.Name );
1668 while ( ( nUIPos == LISTBOX_ENTRY_NOTFOUND ) && ( propertyPos != m_aProperties.begin() ) );
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;
1677 getPropertyBox().InsertEntry(
1678 aDescriptor, impl_getPageIdForCategory_nothrow( aDescriptor.Category ), nUIPos );
1681 //------------------------------------------------------------------------
1682 void OPropertyBrowserController::hidePropertyUI( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException)
1684 ::osl::MutexGuard aGuard( m_aMutex );
1685 if ( !haveView() )
1686 throw RuntimeException();
1688 if ( !impl_findObjectProperty_nothrow( _rPropertyName ) )
1689 return;
1691 getPropertyBox().RemoveEntry( _rPropertyName );
1694 //------------------------------------------------------------------------
1695 void OPropertyBrowserController::showCategory( const ::rtl::OUString& _rCategory, sal_Bool _bShow ) throw (RuntimeException)
1697 ::osl::MutexGuard aGuard( m_aMutex );
1698 if ( !haveView() )
1699 throw RuntimeException();
1701 sal_uInt16 nPageId = impl_getPageIdForCategory_nothrow( _rCategory );
1702 OSL_ENSURE( nPageId != (sal_uInt16)-1, "OPropertyBrowserController::showCategory: invalid category!" );
1704 getPropertyBox().ShowPropertyPage( nPageId, _bShow );
1707 //------------------------------------------------------------------------
1708 Reference< XPropertyControl > SAL_CALL OPropertyBrowserController::getPropertyControl( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException)
1710 ::osl::MutexGuard aGuard( m_aMutex );
1711 if ( !haveView() )
1712 throw RuntimeException();
1714 Reference< XPropertyControl > xControl( getPropertyBox().GetPropertyControl( _rPropertyName ) );
1715 return xControl;
1718 //--------------------------------------------------------------------
1719 void SAL_CALL OPropertyBrowserController::registerControlObserver( const Reference< XPropertyControlObserver >& _Observer ) throw (RuntimeException)
1721 m_aControlObservers.addInterface( _Observer );
1724 //--------------------------------------------------------------------
1725 void SAL_CALL OPropertyBrowserController::revokeControlObserver( const Reference< XPropertyControlObserver >& _Observer ) throw (RuntimeException)
1727 m_aControlObservers.removeInterface( _Observer );
1730 //------------------------------------------------------------------------
1731 void SAL_CALL OPropertyBrowserController::setHelpSectionText( const ::rtl::OUString& _rHelpText ) throw (NoSupportException, RuntimeException)
1733 ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
1734 ::osl::MutexGuard aGuard( m_aMutex );
1736 if ( !haveView() )
1737 throw DisposedException();
1739 if ( !getPropertyBox().HasHelpSection() )
1740 throw NoSupportException();
1742 getPropertyBox().SetHelpText( _rHelpText );
1745 //------------------------------------------------------------------------
1746 void OPropertyBrowserController::impl_broadcastPropertyChange_nothrow( const ::rtl::OUString& _rPropertyName, const Any& _rNewValue, const Any& _rOldValue, bool _bFirstTimeInit ) const
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;
1755 ComposedUIAutoFireGuard aAutoFireGuard( *m_pUIRequestComposer );
1758 // collect the responses from all interested handlers
1759 PropertyHandlerMultiRepository::const_iterator handler = aInterestedHandlers.first;
1760 while ( handler != aInterestedHandlers.second )
1762 handler->second->actuatingPropertyChanged( _rPropertyName, _rNewValue, _rOldValue,
1763 m_pUIRequestComposer->getUIForPropertyHandler( handler->second ),
1764 _bFirstTimeInit );
1765 ++handler;
1768 catch( const Exception& )
1770 DBG_UNHANDLED_EXCEPTION();
1774 //............................................................................
1775 } // namespace pcr
1776 //............................................................................