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"
37 #ifndef _EXTENSIONS_FORMCTRLR_PROPRESID_HRC_
38 #include "formresid.hrc"
40 #include "propertyeditor.hxx"
41 #ifndef _EXTENSIONS_PROPCTRLR_MODULEPRC_HXX_
42 #include "modulepcr.hxx"
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>
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>
73 //------------------------------------------------------------------------
74 // !!! outside the namespace !!!
75 extern "C" void SAL_CALL
createRegistryInfo_OPropertyBrowserController()
77 ::pcr::OAutoRegistration
< ::pcr::OPropertyBrowserController
> aAutoRegistration
;
80 //............................................................................
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
)
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
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(
138 static_cast< XObjectInspectorUI
* >( this )
143 //------------------------------------------------------------------------
144 void OPropertyBrowserController::startContainerWindowListening()
146 if (m_bContainerFocusListening
)
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
)
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
)
187 //--------------------------------------------------------------------
188 void OPropertyBrowserController::impl_initializeView_nothrow()
190 OSL_PRECOND( haveView(), "OPropertyBrowserController::impl_initializeView_nothrow: not to be called when we have no view!" );
194 if ( !m_xModel
.is() )
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
218 impl_rebindToInspectee_nothrow( m_aInspectedObjects
);
221 //--------------------------------------------------------------------
222 bool OPropertyBrowserController::impl_isReadOnlyModel_throw() const
224 if ( !m_xModel
.is() )
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
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
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
)
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.
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
);
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()"
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
);
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();
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
;
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();
419 //------------------------------------------------------------------------
420 sal_Bool SAL_CALL
OPropertyBrowserController::attachModel( const Reference
< XModel
>& _rxModel
) throw(RuntimeException
)
422 Reference
< XObjectInspectorModel
> xModel( _rxModel
, UNO_QUERY
);
426 setInspectorModel( xModel
);
427 return getInspectorModel() == _rxModel
;
430 //------------------------------------------------------------------------
431 sal_Bool
OPropertyBrowserController::suspendAll_nothrow()
433 // if there is a handle inside its "onInteractivePropertySelection" method,
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() )
440 m_bSuspendingPropertyHandlers
= true;
441 sal_Bool bHandlerVeto
= !suspendPropertyHandlers_nothrow( sal_True
);
442 m_bSuspendingPropertyHandlers
= false;
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();
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)
462 aAllHandlers
.push_back( handler
->second
);
465 for ( PropertyHandlerArray::iterator loop
= aAllHandlers
.begin();
466 loop
!= aAllHandlers
.end();
472 if ( !(*loop
)->suspend( _bSuspend
) )
474 // if we're not suspending, but reactivating, ignore the error
477 catch( const Exception
& )
479 OSL_ENSURE( sal_False
, "OPropertyBrowserController::suspendPropertyHandlers_nothrow: caught an exception!" );
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!" );
492 { // this means a "suspend" is to be "revoked"
493 suspendPropertyHandlers_nothrow( sal_False
);
494 // we ourself cannot revoke our suspend
498 if ( !suspendAll_nothrow() )
501 // commit the editor's content
503 getPropertyBox().CommitModified();
506 stopContainerWindowListening();
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
)
533 return Reference
< XModel
>();
536 //------------------------------------------------------------------------
537 Reference
< XFrame
> SAL_CALL
OPropertyBrowserController::getFrame( ) throw(RuntimeException
)
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)
559 Reference
< XComponent
> xViewAsComp( m_xView
, UNO_QUERY
);
560 if ( xViewAsComp
.is() )
561 xViewAsComp
->removeEventListener( static_cast< XPropertyChangeListener
* >( this ) );
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
))
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" );
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
;
629 xContainerWindow
= m_xFrame
->getContainerWindow();
631 if ( xContainerWindow
.get() == xSourceWindow
.get() )
632 { // our container window got the focus
634 getPropertyBox().GrabFocus();
638 //------------------------------------------------------------------------
639 void SAL_CALL
OPropertyBrowserController::focusLost( const FocusEvent
& /*_rSource*/ ) throw (RuntimeException
)
644 //------------------------------------------------------------------------
645 void SAL_CALL
OPropertyBrowserController::disposing( const EventObject
& _rSource
) throw(RuntimeException
)
647 if ( m_xView
.is() && ( m_xView
== _rSource
.Source
) )
653 for ( InterfaceArray::iterator loop
= m_aInspectedObjects
.begin();
654 loop
!= m_aInspectedObjects
.end();
658 if ( *loop
== _rSource
.Source
)
660 m_aInspectedObjects
.erase( loop
);
666 //------------------------------------------------------------------------
667 IMPL_LINK(OPropertyBrowserController
, OnPageActivation
, void*, EMPTYARG
)
669 updateViewDataFromActivePage();
673 //------------------------------------------------------------------------
674 void OPropertyBrowserController::updateViewDataFromActivePage()
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();
690 if ( nCurrentPage
== pageId
->second
)
692 m_sPageSelection
= pageId
->first
;
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
;
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
);
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
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();
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();
762 if ( m_sCommittingProperty
== _rEvent
.PropertyName
)
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
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
;
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
);
811 case PropertyControlType::MultiLineTextField
:
812 xControl
= new OMultilineEditControl( &getPropertyBox(), eMultiLineText
, nWinBits
| WB_DROPDOWN
| WB_TABSTOP
);
815 case PropertyControlType::ListBox
:
816 xControl
= new OListboxControl( &getPropertyBox(), nWinBits
| WB_TABSTOP
| WB_DROPDOWN
);
819 case PropertyControlType::ComboBox
:
820 xControl
= new OComboboxControl( &getPropertyBox(), nWinBits
| WB_TABSTOP
| WB_DROPDOWN
);
823 case PropertyControlType::TextField
:
824 xControl
= new OEditControl( &getPropertyBox(), sal_False
, nWinBits
| WB_TABSTOP
);
827 case PropertyControlType::CharacterField
:
828 xControl
= new OEditControl( &getPropertyBox(), sal_True
, nWinBits
| WB_TABSTOP
);
831 case PropertyControlType::NumericField
:
832 xControl
= new ONumericControl( &getPropertyBox(), nWinBits
| WB_TABSTOP
| WB_SPIN
| WB_REPEAT
);
835 case PropertyControlType::DateTimeField
:
836 xControl
= new ODateTimeControl( &getPropertyBox(), nWinBits
| WB_TABSTOP
);
839 case PropertyControlType::DateField
:
840 xControl
= new ODateControl( &getPropertyBox(), nWinBits
| WB_TABSTOP
| WB_SPIN
| WB_REPEAT
);
843 case PropertyControlType::TimeField
:
844 xControl
= new OTimeControl( &getPropertyBox(), nWinBits
| WB_TABSTOP
| WB_SPIN
| WB_REPEAT
);
847 case PropertyControlType::ColorListBox
:
848 xControl
= new OColorControl( &getPropertyBox(), nWinBits
| WB_TABSTOP
| WB_DROPDOWN
);
851 case PropertyControlType::HyperlinkField
:
852 xControl
= new OHyperlinkControl( &getPropertyBox(), nWinBits
| WB_TABSTOP
| WB_DROPDOWN
);
856 throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
862 //------------------------------------------------------------------------
863 void OPropertyBrowserController::impl_toggleInspecteeListening_nothrow( bool _bOn
)
865 for ( InterfaceArray::const_iterator loop
= m_aInspectedObjects
.begin();
866 loop
!= m_aInspectedObjects
.end();
872 Reference
< XComponent
> xComp( *loop
, UNO_QUERY
);
876 xComp
->addEventListener( static_cast< XPropertyChangeListener
* >( this ) );
878 xComp
->removeEventListener( static_cast< XPropertyChangeListener
* >( this ) );
881 catch( const Exception
& )
883 DBG_UNHANDLED_EXCEPTION();
888 //------------------------------------------------------------------------
889 void OPropertyBrowserController::stopInspection( bool _bCommitModified
)
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
908 for ( HashString2Int16::const_iterator erase
= m_aPageIds
.begin();
909 erase
!= m_aPageIds
.end();
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();
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();
942 (*loop
)->removePropertyChangeListener( this );
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
;
993 // update the user interface
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
);
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();
1037 ::std::vector
< Property
>::const_iterator previous
= ::std::find_if(
1038 aProperties
.begin(),
1040 FindPropertyByName( copyProperty
->Name
)
1042 if ( previous
== aProperties
.end() )
1044 aProperties
.push_back( *copyProperty
);
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();
1068 ::std::vector
< Property
>::iterator existent
= ::std::find_if(
1069 aProperties
.begin(),
1071 FindPropertyByName( *superseded
)
1073 if ( existent
!= aProperties
.end() )
1074 // one of the properties superseded by this handler was supported by a previous
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
1084 for ( StlSyntaxSequence
< Property
>::const_iterator remember
= aThisHandlersProperties
.begin();
1085 remember
!= aThisHandlersProperties
.end();
1089 m_aPropertyHandlers
[ remember
->Name
] = *aHandler
;
1090 // note that this implies that if two handlers support the same property,
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();
1101 m_aDependencyHandlers
.insert( PropertyHandlerMultiRepository::value_type(
1102 *aLoop
, *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();
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 );
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
;
1139 return m_pView
->getMinimumSize();
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() )
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
);
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();
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()
1233 // too early, will return later
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() );
1266 OSL_ENSURE( false, sMessage
);
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();
1306 if ( aUsedPages
.find( pageId
->second
) == aUsedPages
.end() )
1307 getPropertyBox().RemovePage( pageId
->second
);
1309 aSurvivingPageIds
.insert( *pageId
);
1311 m_aPageIds
.swap( aSurvivingPageIds
);
1314 getPropertyBox().Show();
1315 getPropertyBox().EnableUpdate();
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
] );
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
);
1356 m_xInteractiveHandler
= handler
->second
;
1357 InteractiveSelectionResult eResult
=
1358 handler
->second
->onInteractivePropertySelection( _rName
, _bPrimary
, aData
,
1359 m_pUIRequestComposer
->getUIForPropertyHandler( handler
->second
) );
1363 case InteractiveSelectionResult_Cancelled
:
1364 case InteractiveSelectionResult_Success
:
1365 // okay, nothing to do
1367 case InteractiveSelectionResult_ObtainedValue
:
1368 handler
->second
->setPropertyValue( _rName
, aData
);
1370 case InteractiveSelectionResult_Pending
:
1371 // also okay, we expect that the handler has disabled the UI as necessary
1374 OSL_ENSURE( false, "OPropertyBrowserController::Clicked: unknown result value!" );
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();
1392 if ( search
->second
.Name
== _rName
)
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
1411 if ( sVal
.equals( sPlcHolder
) )
1412 bIsPlaceHolderValue
= true;
1414 m_sCommittingProperty
= rName
;
1416 bool bIsActuatingProperty
= impl_isActuatingProperty_nothrow( rName
);
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 );
1450 DBG_ERROR("OPropertyBrowserController::Commit : caught an exception !");
1453 m_sCommittingProperty
= ::rtl::OUString();
1456 //--------------------------------------------------------------------
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 //------------------------------------------------------------------------
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");
1495 //------------------------------------------------------------------------
1496 void OPropertyBrowserController::getPropertyHandlers( const InterfaceArray
& _rObjects
, PropertyHandlerArray
& _rHandlers
)
1498 _rHandlers
.resize( 0 );
1499 if ( _rObjects
.empty() )
1502 // create a component context for the handlers, containing some information about where
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
);
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
);
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
) );
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
)
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
);
1586 throw RuntimeException();
1588 OrderedPropertyMap::const_iterator propertyPos
;
1589 if ( !impl_findObjectProperty_nothrow( _rPropertyName
, &propertyPos
) )
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
);
1610 throw RuntimeException();
1612 if ( !impl_findObjectProperty_nothrow( _rPropertyName
) )
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
);
1623 throw RuntimeException();
1625 if ( !impl_findObjectProperty_nothrow( _rPropertyName
) )
1628 getPropertyBox().EnablePropertyControls( _rPropertyName
, _nElements
, _bEnable
);
1631 //------------------------------------------------------------------------
1632 void OPropertyBrowserController::showPropertyUI( const ::rtl::OUString
& _rPropertyName
) throw (RuntimeException
)
1634 ::osl::MutexGuard
aGuard( m_aMutex
);
1636 throw RuntimeException();
1638 // look up the property in our object properties
1639 OrderedPropertyMap::const_iterator propertyPos
;
1640 if ( !impl_findObjectProperty_nothrow( _rPropertyName
, &propertyPos
) )
1643 if ( getPropertyBox().GetPropertyPos( _rPropertyName
) != LISTBOX_ENTRY_NOTFOUND
)
1645 rebuildPropertyUI( _rPropertyName
);
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() )
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
1674 // insert right after the predecessor we found
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
);
1686 throw RuntimeException();
1688 if ( !impl_findObjectProperty_nothrow( _rPropertyName
) )
1691 getPropertyBox().RemoveEntry( _rPropertyName
);
1694 //------------------------------------------------------------------------
1695 void OPropertyBrowserController::showCategory( const ::rtl::OUString
& _rCategory
, sal_Bool _bShow
) throw (RuntimeException
)
1697 ::osl::MutexGuard
aGuard( m_aMutex
);
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
);
1712 throw RuntimeException();
1714 Reference
< XPropertyControl
> xControl( getPropertyBox().GetPropertyControl( _rPropertyName
) );
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
);
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
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
),
1768 catch( const Exception
& )
1770 DBG_UNHANDLED_EXCEPTION();
1774 //............................................................................
1776 //............................................................................