1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "pcrservices.hxx"
21 #include "propcontroller.hxx"
22 #include "pcrstrings.hxx"
23 #include "standardcontrol.hxx"
24 #include "linedescriptor.hxx"
25 #include <strings.hrc>
26 #include "propertyeditor.hxx"
27 #include "modulepcr.hxx"
28 #include "formstrings.hxx"
29 #include "formmetadata.hxx"
30 #include "formbrowsertools.hxx"
31 #include "propertycomposer.hxx"
33 #include <com/sun/star/awt/XWindow.hpp>
34 #include <com/sun/star/lang/NoSupportException.hpp>
35 #include <com/sun/star/util/XCloseable.hpp>
36 #include <com/sun/star/inspection/PropertyControlType.hpp>
37 #include <com/sun/star/ucb/AlreadyInitializedException.hpp>
38 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
39 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
40 #include <com/sun/star/util/VetoException.hpp>
41 #include <tools/debug.hxx>
42 #include <tools/diagnose_ex.h>
43 #include <comphelper/types.hxx>
44 #include <toolkit/awt/vclxwindow.hxx>
45 #include <toolkit/helper/vclunohelper.hxx>
46 #include <comphelper/property.hxx>
47 #include <vcl/weld.hxx>
48 #include <vcl/svapp.hxx>
49 #include <osl/mutex.hxx>
50 #include <cppuhelper/queryinterface.hxx>
51 #include <cppuhelper/component_context.hxx>
52 #include <cppuhelper/exc_hlp.hxx>
53 #include <cppuhelper/supportsservice.hxx>
57 #include <sal/macros.h>
58 #include <sal/log.hxx>
61 // !!! outside the namespace !!!
62 extern "C" void createRegistryInfo_OPropertyBrowserController()
64 ::pcr::OAutoRegistration
< ::pcr::OPropertyBrowserController
> aAutoRegistration
;
72 using namespace ::com::sun::star
;
73 using namespace ::com::sun::star::uno
;
74 using namespace ::com::sun::star::awt
;
75 using namespace ::com::sun::star::form
;
76 using namespace ::com::sun::star::beans
;
77 using namespace ::com::sun::star::script
;
78 using namespace ::com::sun::star::lang
;
79 using namespace ::com::sun::star::container
;
80 using namespace ::com::sun::star::frame
;
81 using namespace ::com::sun::star::util
;
82 using namespace ::com::sun::star::inspection
;
83 using namespace ::com::sun::star::ucb
;
84 using namespace ::comphelper
;
87 //= OPropertyBrowserController
90 OPropertyBrowserController::OPropertyBrowserController( const Reference
< XComponentContext
>& _rxContext
)
91 :m_xContext(_rxContext
)
92 ,m_aDisposeListeners( m_aMutex
)
93 ,m_aControlObservers( m_aMutex
)
95 ,m_bContainerFocusListening( false )
96 ,m_bSuspendingPropertyHandlers( false )
97 ,m_bConstructed( false )
98 ,m_bBindingIntrospectee( false )
103 OPropertyBrowserController::~OPropertyBrowserController()
105 // stop listening for property changes
107 stopInspection( true );
111 IMPLEMENT_FORWARD_REFCOUNT( OPropertyBrowserController
, OPropertyBrowserController_Base
)
114 Any SAL_CALL
OPropertyBrowserController::queryInterface( const Type
& _rType
)
116 Any aReturn
= OPropertyBrowserController_Base::queryInterface( _rType
);
117 if ( !aReturn
.hasValue() )
118 aReturn
= ::cppu::queryInterface(
120 static_cast< XObjectInspectorUI
* >( this )
126 void OPropertyBrowserController::startContainerWindowListening()
128 if (m_bContainerFocusListening
)
133 Reference
< XWindow
> xContainerWindow
= m_xFrame
->getContainerWindow();
134 if (xContainerWindow
.is())
136 xContainerWindow
->addFocusListener(this);
137 m_bContainerFocusListening
= true;
141 DBG_ASSERT(m_bContainerFocusListening
, "OPropertyBrowserController::startContainerWindowListening: unable to start listening (inconsistence)!");
145 void OPropertyBrowserController::stopContainerWindowListening()
147 if (!m_bContainerFocusListening
)
152 Reference
< XWindow
> xContainerWindow
= m_xFrame
->getContainerWindow();
153 if (xContainerWindow
.is())
155 xContainerWindow
->removeFocusListener(this);
156 m_bContainerFocusListening
= false;
160 DBG_ASSERT(!m_bContainerFocusListening
, "OPropertyBrowserController::stopContainerWindowListening: unable to stop listening (inconsistence)!");
164 Reference
< XObjectInspectorModel
> SAL_CALL
OPropertyBrowserController::getInspectorModel()
170 void OPropertyBrowserController::impl_initializeView_nothrow()
172 OSL_PRECOND( haveView(), "OPropertyBrowserController::impl_initializeView_nothrow: not to be called when we have no view!" );
176 if ( !m_xModel
.is() )
182 getPropertyBox().EnableHelpSection( m_xModel
->getHasHelpSection() );
183 getPropertyBox().SetHelpLineLimites( m_xModel
->getMinHelpTextLines(), m_xModel
->getMaxHelpTextLines() );
185 catch( const Exception
& )
187 DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
192 bool OPropertyBrowserController::impl_isReadOnlyModel_throw() const
194 if ( !m_xModel
.is() )
197 return m_xModel
->getIsReadOnly();
201 void OPropertyBrowserController::impl_startOrStopModelListening_nothrow( bool _bDoListen
) const
205 Reference
< XPropertySet
> xModelProperties( m_xModel
, UNO_QUERY
);
206 if ( !xModelProperties
.is() )
207 // okay, so the model doesn't want to change its properties
208 // dynamically - fine with us
211 void (SAL_CALL
XPropertySet::*pListenerOperation
)( const OUString
&, const Reference
< XPropertyChangeListener
>& )
212 = _bDoListen
? &XPropertySet::addPropertyChangeListener
: &XPropertySet::removePropertyChangeListener
;
214 (xModelProperties
.get()->*pListenerOperation
)(
215 OUString( "IsReadOnly" ),
216 const_cast< OPropertyBrowserController
* >( this )
219 catch( const Exception
& )
221 DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
226 void OPropertyBrowserController::impl_bindToNewModel_nothrow( const Reference
< XObjectInspectorModel
>& _rxInspectorModel
)
228 impl_startOrStopModelListening_nothrow( false );
229 m_xModel
= _rxInspectorModel
;
230 impl_startOrStopModelListening_nothrow( true );
232 // initialize the view, if we already have one
234 impl_initializeView_nothrow();
236 // inspect again, if we already have inspectees
237 if ( !m_aInspectedObjects
.empty() )
238 impl_rebindToInspectee_nothrow( m_aInspectedObjects
);
242 void SAL_CALL
OPropertyBrowserController::setInspectorModel( const Reference
< XObjectInspectorModel
>& _inspectorModel
)
244 ::osl::MutexGuard
aGuard( m_aMutex
);
246 if ( m_xModel
== _inspectorModel
)
249 impl_bindToNewModel_nothrow( _inspectorModel
);
253 Reference
< XObjectInspectorUI
> SAL_CALL
OPropertyBrowserController::getInspectorUI()
255 // we're derived from this interface, though we do not expose it in queryInterface and getTypes.
260 void SAL_CALL
OPropertyBrowserController::inspect( const Sequence
< Reference
< XInterface
> >& _rObjects
)
262 SolarMutexGuard aSolarGuard
;
263 ::osl::MutexGuard
aGuard( m_aMutex
);
265 if ( m_bSuspendingPropertyHandlers
|| !suspendAll_nothrow() )
266 { // we already are trying to suspend the component (this is somewhere up the stack)
267 // OR one of our property handlers raised a veto against closing. Well, we *need* to close
268 // it in order to inspect another object.
269 throw VetoException();
271 if ( m_bBindingIntrospectee
)
272 throw VetoException();
274 m_bBindingIntrospectee
= true;
275 impl_rebindToInspectee_nothrow( InterfaceArray( _rObjects
.begin(), _rObjects
.end() ) );
276 m_bBindingIntrospectee
= false;
281 Reference
< XDispatch
> SAL_CALL
OPropertyBrowserController::queryDispatch( const URL
& /*URL*/, const OUString
& /*TargetFrameName*/, ::sal_Int32
/*SearchFlags*/ )
283 // we don't have any dispatches at all, right now
284 return Reference
< XDispatch
>();
288 Sequence
< Reference
< XDispatch
> > SAL_CALL
OPropertyBrowserController::queryDispatches( const Sequence
< DispatchDescriptor
>& Requests
)
290 Sequence
< Reference
< XDispatch
> > aReturn
;
291 sal_Int32 nLen
= Requests
.getLength();
292 aReturn
.realloc( nLen
);
294 Reference
< XDispatch
>* pReturn
= aReturn
.getArray();
295 const Reference
< XDispatch
>* pReturnEnd
= aReturn
.getArray() + nLen
;
296 const DispatchDescriptor
* pDescripts
= Requests
.getConstArray();
298 for ( ; pReturn
!= pReturnEnd
; ++ pReturn
, ++pDescripts
)
299 *pReturn
= queryDispatch( pDescripts
->FeatureURL
, pDescripts
->FrameName
, pDescripts
->SearchFlags
);
305 void SAL_CALL
OPropertyBrowserController::initialize( const Sequence
< Any
>& _arguments
)
307 if ( m_bConstructed
)
308 throw AlreadyInitializedException();
310 StlSyntaxSequence
< Any
> arguments( _arguments
);
311 if ( arguments
.empty() )
312 { // constructor: "createDefault()"
313 m_bConstructed
= true;
317 Reference
< XObjectInspectorModel
> xModel
;
318 if ( arguments
.size() == 1 )
319 { // constructor: "createWithModel( XObjectInspectorModel )"
320 if ( !( arguments
[0] >>= xModel
) )
321 throw IllegalArgumentException( OUString(), *this, 0 );
322 createWithModel( xModel
);
326 throw IllegalArgumentException( OUString(), *this, 0 );
330 void OPropertyBrowserController::createWithModel( const Reference
< XObjectInspectorModel
>& _rxModel
)
332 osl_atomic_increment( &m_refCount
);
334 setInspectorModel( _rxModel
);
336 osl_atomic_decrement( &m_refCount
);
338 m_bConstructed
= true;
342 void SAL_CALL
OPropertyBrowserController::attachFrame( const Reference
< XFrame
>& _rxFrame
)
344 SolarMutexGuard aSolarGuard
;
345 ::osl::MutexGuard
aGuard( m_aMutex
);
347 if (_rxFrame
.is() && haveView())
348 throw RuntimeException("Unable to attach to a second frame.",*this);
350 // revoke as focus listener from the old container window
351 stopContainerWindowListening();
357 // TODO: this construction perhaps should be done outside. Don't know the exact meaning of attachFrame.
358 // Maybe it is intended to only announce the frame to the controller, and the instance doing this
359 // announcement is responsible for calling setComponent, too.
360 Reference
< XWindow
> xContainerWindow
= m_xFrame
->getContainerWindow();
361 VCLXWindow
* pContainerWindow
= comphelper::getUnoTunnelImplementation
<VCLXWindow
>(xContainerWindow
);
362 VclPtr
<vcl::Window
> pParentWin
= pContainerWindow
? pContainerWindow
->GetWindow() : VclPtr
<vcl::Window
>();
364 throw RuntimeException("The frame is invalid. Unable to extract the container window.",*this);
366 Construct( pParentWin
);
369 m_xFrame
->setComponent( VCLUnoHelper::GetInterface( m_pView
), this );
371 catch( const Exception
& )
373 OSL_FAIL( "OPropertyBrowserController::attachFrame: caught an exception!" );
376 startContainerWindowListening();
382 sal_Bool SAL_CALL
OPropertyBrowserController::attachModel( const Reference
< XModel
>& _rxModel
)
384 Reference
< XObjectInspectorModel
> xModel( _rxModel
, UNO_QUERY
);
388 setInspectorModel( xModel
);
389 return getInspectorModel() == _rxModel
;
393 bool OPropertyBrowserController::suspendAll_nothrow()
395 // if there is a handle inside its "onInteractivePropertySelection" method,
397 // Normally, we could expect every handler to do this itself, but being
398 // realistic, it's safer to handle this here in general.
399 if ( m_xInteractiveHandler
.is() )
402 m_bSuspendingPropertyHandlers
= true;
403 bool bHandlerVeto
= !suspendPropertyHandlers_nothrow( true );
404 m_bSuspendingPropertyHandlers
= false;
405 return !bHandlerVeto
;
409 bool OPropertyBrowserController::suspendPropertyHandlers_nothrow( bool _bSuspend
)
411 PropertyHandlerArray aAllHandlers
; // will contain every handler exactly once
412 for (auto const& propertyHandler
: m_aPropertyHandlers
)
414 if ( std::find( aAllHandlers
.begin(), aAllHandlers
.end(), propertyHandler
.second
) != aAllHandlers
.end() )
415 // already visited this particular handler (m_aPropertyHandlers usually contains
416 // the same handler more than once)
418 aAllHandlers
.push_back(propertyHandler
.second
);
421 for (auto const& handler
: aAllHandlers
)
425 if ( !handler
->suspend( _bSuspend
) )
427 // if we're not suspending, but reactivating, ignore the error
430 catch( const Exception
& )
432 OSL_FAIL( "OPropertyBrowserController::suspendPropertyHandlers_nothrow: caught an exception!" );
439 sal_Bool SAL_CALL
OPropertyBrowserController::suspend( sal_Bool _bSuspend
)
441 ::osl::MutexGuard
aGuard( m_aMutex
);
442 OSL_ENSURE( haveView(), "OPropertyBrowserController::suspend: don't have a view anymore!" );
445 { // this means a "suspend" is to be "revoked"
446 suspendPropertyHandlers_nothrow( false );
447 // we ourself cannot revoke our suspend
451 if ( !suspendAll_nothrow() )
454 // commit the editor's content
456 getPropertyBox().CommitModified();
459 stopContainerWindowListening();
466 Any SAL_CALL
OPropertyBrowserController::getViewData( )
468 return makeAny( m_sPageSelection
);
472 void SAL_CALL
OPropertyBrowserController::restoreViewData( const Any
& Data
)
474 OUString sPageSelection
;
475 if ( ( Data
>>= sPageSelection
) && !sPageSelection
.isEmpty() )
477 m_sPageSelection
= sPageSelection
;
478 selectPageFromViewData();
483 Reference
< XModel
> SAL_CALL
OPropertyBrowserController::getModel( )
486 return Reference
< XModel
>();
490 Reference
< XFrame
> SAL_CALL
OPropertyBrowserController::getFrame( )
496 void SAL_CALL
OPropertyBrowserController::dispose( )
498 SolarMutexGuard aSolarGuard
;
500 // stop inspecting the current object
501 stopInspection( false );
503 // say our dispose listeners goodbye
504 css::lang::EventObject aEvt
;
505 aEvt
.Source
= static_cast< ::cppu::OWeakObject
* >(this);
506 m_aDisposeListeners
.disposeAndClear(aEvt
);
507 m_aControlObservers
.disposeAndClear(aEvt
);
509 // don't delete explicitly (this is done by the frame we reside in)
513 m_xView
->removeEventListener( static_cast< XPropertyChangeListener
* >( this ) );
516 m_aInspectedObjects
.clear();
517 impl_bindToNewModel_nothrow( nullptr );
521 void SAL_CALL
OPropertyBrowserController::addEventListener( const Reference
< XEventListener
>& _rxListener
)
523 m_aDisposeListeners
.addInterface(_rxListener
);
527 void SAL_CALL
OPropertyBrowserController::removeEventListener( const Reference
< XEventListener
>& _rxListener
)
529 m_aDisposeListeners
.removeInterface(_rxListener
);
533 OUString SAL_CALL
OPropertyBrowserController::getImplementationName( )
535 return getImplementationName_static();
538 sal_Bool SAL_CALL
OPropertyBrowserController::supportsService( const OUString
& ServiceName
)
540 return cppu::supportsService(this, ServiceName
);
544 Sequence
< OUString
> SAL_CALL
OPropertyBrowserController::getSupportedServiceNames( )
546 return getSupportedServiceNames_static();
550 OUString
OPropertyBrowserController::getImplementationName_static( )
552 return "org.openoffice.comp.extensions.ObjectInspector";
556 Sequence
< OUString
> OPropertyBrowserController::getSupportedServiceNames_static( )
558 Sequence
< OUString
> aSupported
{ "com.sun.star.inspection.ObjectInspector" };
563 Reference
< XInterface
> OPropertyBrowserController::Create(const Reference
< XComponentContext
>& _rxContext
)
565 return *(new OPropertyBrowserController( _rxContext
) );
569 void SAL_CALL
OPropertyBrowserController::focusGained( const FocusEvent
& _rSource
)
571 Reference
< XWindow
> xSourceWindow(_rSource
.Source
, UNO_QUERY
);
572 Reference
< XWindow
> xContainerWindow
;
574 xContainerWindow
= m_xFrame
->getContainerWindow();
576 if ( xContainerWindow
.get() == xSourceWindow
.get() )
577 { // our container window got the focus
579 getPropertyBox().GrabFocus();
584 void SAL_CALL
OPropertyBrowserController::focusLost( const FocusEvent
& /*_rSource*/ )
590 void SAL_CALL
OPropertyBrowserController::disposing( const EventObject
& _rSource
)
592 if ( m_xView
.is() && ( m_xView
== _rSource
.Source
) )
598 auto it
= std::find_if(m_aInspectedObjects
.begin(), m_aInspectedObjects
.end(),
599 [&_rSource
](const InterfaceArray::value_type
& rxObj
) { return rxObj
== _rSource
.Source
; });
600 if (it
!= m_aInspectedObjects
.end())
601 m_aInspectedObjects
.erase(it
);
605 IMPL_LINK_NOARG(OPropertyBrowserController
, OnPageActivation
, LinkParamNone
*, void)
607 updateViewDataFromActivePage();
611 void OPropertyBrowserController::updateViewDataFromActivePage()
616 OUString sOldSelection
= m_sPageSelection
;
617 m_sPageSelection
.clear();
619 const sal_uInt16 nCurrentPage
= m_pView
->getActivaPage();
620 if ( sal_uInt16(-1) != nCurrentPage
)
622 for (auto const& pageId
: m_aPageIds
)
624 if ( nCurrentPage
== pageId
.second
)
626 m_sPageSelection
= pageId
.first
;
632 if ( !m_sPageSelection
.isEmpty() )
633 m_sLastValidPageSelection
= m_sPageSelection
;
634 else if ( !sOldSelection
.isEmpty() )
635 m_sLastValidPageSelection
= sOldSelection
;
639 sal_uInt16
OPropertyBrowserController::impl_getPageIdForCategory_nothrow( const OUString
& _rCategoryName
) const
641 sal_uInt16 nPageId
= sal_uInt16(-1);
642 HashString2Int16::const_iterator pagePos
= m_aPageIds
.find( _rCategoryName
);
643 if ( pagePos
!= m_aPageIds
.end() )
644 nPageId
= pagePos
->second
;
649 void OPropertyBrowserController::selectPageFromViewData()
651 sal_uInt16 nNewPage
= impl_getPageIdForCategory_nothrow( m_sPageSelection
);
653 if ( haveView() && ( nNewPage
!= sal_uInt16(-1) ) )
654 m_pView
->activatePage( nNewPage
);
657 updateViewDataFromActivePage();
661 void OPropertyBrowserController::Construct(vcl::Window
* _pParentWin
)
663 DBG_ASSERT(!haveView(), "OPropertyBrowserController::Construct: already have a view!");
664 DBG_ASSERT(_pParentWin
, "OPropertyBrowserController::Construct: invalid parent window!");
666 m_pView
= VclPtr
<OPropertyBrowserView
>::Create(_pParentWin
);
667 m_pView
->setPageActivationHandler(LINK(this, OPropertyBrowserController
, OnPageActivation
));
669 // add as dispose listener for our view. The view is disposed by the frame we're plugged into,
670 // and this disposal _deletes_ the view, so it would be deadly if we use our m_pView member
672 m_xView
= VCLUnoHelper::GetInterface(m_pView
);
674 m_xView
->addEventListener( static_cast< XPropertyChangeListener
* >( this ) );
676 getPropertyBox().SetLineListener(this);
677 getPropertyBox().SetControlObserver(this);
678 impl_initializeView_nothrow();
684 void SAL_CALL
OPropertyBrowserController::propertyChange( const PropertyChangeEvent
& _rEvent
)
686 if ( _rEvent
.Source
== m_xModel
)
688 if ( _rEvent
.PropertyName
== "IsReadOnly" )
689 // this is a huge cudgel, admitted.
690 // The problem is that in case we were previously read-only, all our controls
691 // were created read-only, too. We cannot simply switch them to not-read-only.
692 // Even if they had an API for this, we do not know whether they were
693 // originally created read-only, or if they are read-only just because
695 impl_rebindToInspectee_nothrow( m_aInspectedObjects
);
699 if ( m_sCommittingProperty
== _rEvent
.PropertyName
)
705 Any
aNewValue( _rEvent
.NewValue
);
706 if ( impl_hasPropertyHandlerFor_nothrow( _rEvent
.PropertyName
) )
708 // forward the new value to the property box, to reflect the change in the UI
709 aNewValue
= impl_getPropertyValue_throw( _rEvent
.PropertyName
);
711 // check whether the state is ambiguous. This is interesting in case we display the properties
712 // for multiple objects at once: In this case, we'll get a notification from one of the objects,
713 // but need to care for the "composed" value, which can be "ambiguous".
714 PropertyHandlerRef
xHandler( impl_getHandlerForProperty_throw( _rEvent
.PropertyName
), UNO_SET_THROW
);
715 PropertyState
ePropertyState( xHandler
->getPropertyState( _rEvent
.PropertyName
) );
716 bool bAmbiguousValue
= ( PropertyState_AMBIGUOUS_VALUE
== ePropertyState
);
718 getPropertyBox().SetPropertyValue( _rEvent
.PropertyName
, aNewValue
, bAmbiguousValue
);
721 // if it's an actuating property, then update the UI for any dependent
723 if ( impl_isActuatingProperty_nothrow( _rEvent
.PropertyName
) )
724 impl_broadcastPropertyChange_nothrow( _rEvent
.PropertyName
, aNewValue
, _rEvent
.OldValue
, false );
728 Reference
< XPropertyControl
> SAL_CALL
OPropertyBrowserController::createPropertyControl( ::sal_Int16 ControlType
, sal_Bool CreateReadOnly
)
730 ::osl::MutexGuard
aGuard( m_aMutex
);
732 Reference
< XPropertyControl
> xControl
;
734 // default winbits: a border only
735 WinBits nWinBits
= WB_BORDER
;
738 CreateReadOnly
|= impl_isReadOnlyModel_throw() ? 1 : 0;
739 if ( CreateReadOnly
)
740 nWinBits
|= WB_READONLY
;
742 switch ( ControlType
)
744 case PropertyControlType::StringListField
:
745 xControl
= new OMultilineEditControl( &getPropertyBox(), eStringList
, nWinBits
| WB_DROPDOWN
| WB_TABSTOP
);
748 case PropertyControlType::MultiLineTextField
:
749 xControl
= new OMultilineEditControl( &getPropertyBox(), eMultiLineText
, nWinBits
| WB_DROPDOWN
| WB_TABSTOP
);
752 case PropertyControlType::ListBox
:
753 xControl
= new OListboxControl( &getPropertyBox(), nWinBits
| WB_TABSTOP
| WB_DROPDOWN
);
756 case PropertyControlType::ComboBox
:
757 xControl
= new OComboboxControl( &getPropertyBox(), nWinBits
| WB_TABSTOP
| WB_DROPDOWN
);
760 case PropertyControlType::TextField
:
761 xControl
= new OEditControl( &getPropertyBox(), false, nWinBits
| WB_TABSTOP
);
764 case PropertyControlType::CharacterField
:
765 xControl
= new OEditControl( &getPropertyBox(), true, nWinBits
| WB_TABSTOP
);
768 case PropertyControlType::NumericField
:
769 xControl
= new ONumericControl( &getPropertyBox(), nWinBits
| WB_TABSTOP
| WB_SPIN
| WB_REPEAT
);
772 case PropertyControlType::DateTimeField
:
773 xControl
= new ODateTimeControl( &getPropertyBox(), nWinBits
| WB_TABSTOP
);
776 case PropertyControlType::DateField
:
777 xControl
= new ODateControl( &getPropertyBox(), nWinBits
| WB_TABSTOP
| WB_SPIN
| WB_REPEAT
);
780 case PropertyControlType::TimeField
:
781 xControl
= new OTimeControl( &getPropertyBox(), nWinBits
| WB_TABSTOP
| WB_SPIN
| WB_REPEAT
);
784 case PropertyControlType::ColorListBox
:
785 xControl
= new OColorControl( &getPropertyBox(), nWinBits
| WB_TABSTOP
| WB_DROPDOWN
);
788 case PropertyControlType::HyperlinkField
:
789 xControl
= new OHyperlinkControl( &getPropertyBox(), nWinBits
| WB_TABSTOP
| WB_DROPDOWN
);
793 throw IllegalArgumentException( OUString(), *this, 1 );
800 void OPropertyBrowserController::impl_toggleInspecteeListening_nothrow( bool _bOn
)
802 for (auto const& inspectedObject
: m_aInspectedObjects
)
806 Reference
< XComponent
> xComp( inspectedObject
, UNO_QUERY
);
810 xComp
->addEventListener( static_cast< XPropertyChangeListener
* >( this ) );
812 xComp
->removeEventListener( static_cast< XPropertyChangeListener
* >( this ) );
815 catch( const Exception
& )
817 DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
823 void OPropertyBrowserController::stopInspection( bool _bCommitModified
)
827 if ( _bCommitModified
)
828 // commit the editor's content
829 getPropertyBox().CommitModified();
831 // hide the property box so that it does not flicker
832 getPropertyBox().Hide();
834 // clear the property box
835 getPropertyBox().ClearAll();
838 // destroy the view first
842 for (auto const& pageId
: m_aPageIds
)
843 getPropertyBox().RemovePage( pageId
.second
);
844 clearContainer( m_aPageIds
);
847 clearContainer( m_aProperties
);
849 // de-register as dispose-listener from our inspected objects
850 impl_toggleInspecteeListening_nothrow( false );
852 // handlers are obsolete, so is our "composer" for their UI requests
853 if (m_pUIRequestComposer
)
854 m_pUIRequestComposer
->dispose();
855 m_pUIRequestComposer
.reset();
857 // clean up the property handlers
858 PropertyHandlerArray aAllHandlers
; // will contain every handler exactly once
859 for (auto const& propertyHandler
: m_aPropertyHandlers
)
860 if ( std::find( aAllHandlers
.begin(), aAllHandlers
.end(), propertyHandler
.second
) == aAllHandlers
.end() )
861 aAllHandlers
.push_back( propertyHandler
.second
);
863 for (auto const& handler
: aAllHandlers
)
867 handler
->removePropertyChangeListener( this );
870 catch( const DisposedException
& )
873 catch( const Exception
& )
875 DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
879 clearContainer( m_aPropertyHandlers
);
880 clearContainer( m_aDependencyHandlers
);
884 bool OPropertyBrowserController::impl_hasPropertyHandlerFor_nothrow( const OUString
& _rPropertyName
) const
886 PropertyHandlerRepository::const_iterator handlerPos
= m_aPropertyHandlers
.find( _rPropertyName
);
887 return ( handlerPos
!= m_aPropertyHandlers
.end() );
891 OPropertyBrowserController::PropertyHandlerRef
const & OPropertyBrowserController::impl_getHandlerForProperty_throw( const OUString
& _rPropertyName
) const
893 PropertyHandlerRepository::const_iterator handlerPos
= m_aPropertyHandlers
.find( _rPropertyName
);
894 if ( handlerPos
== m_aPropertyHandlers
.end() )
895 throw RuntimeException();
896 return handlerPos
->second
;
900 Any
OPropertyBrowserController::impl_getPropertyValue_throw( const OUString
& _rPropertyName
)
902 PropertyHandlerRef handler
= impl_getHandlerForProperty_throw( _rPropertyName
);
903 return handler
->getPropertyValue( _rPropertyName
);
907 void OPropertyBrowserController::impl_rebindToInspectee_nothrow( const InterfaceArray
& _rObjects
)
911 // stop inspecting the old object(s)
912 stopInspection( true );
914 // inspect the new object(s)
915 m_aInspectedObjects
= _rObjects
;
918 // update the user interface
922 catch(const Exception
&)
924 OSL_FAIL("OPropertyBrowserController::impl_rebindToInspectee_nothrow: caught an exception !");
929 void OPropertyBrowserController::doInspection()
934 // obtain the properties of the object
935 std::vector
< Property
> aProperties
;
937 PropertyHandlerArray aPropertyHandlers
;
938 getPropertyHandlers( m_aInspectedObjects
, aPropertyHandlers
);
940 PropertyHandlerArray::iterator
aHandler( aPropertyHandlers
.begin() );
941 while ( aHandler
!= aPropertyHandlers
.end() )
943 DBG_ASSERT( aHandler
->get(), "OPropertyBrowserController::doInspection: invalid handler!" );
945 StlSyntaxSequence
< Property
> aThisHandlersProperties( (*aHandler
)->getSupportedProperties() );
947 if ( aThisHandlersProperties
.empty() )
949 // this handler doesn't know anything about the current inspectee -> ignore it
950 (*aHandler
)->dispose();
951 aHandler
= aPropertyHandlers
.erase( aHandler
);
955 // append these properties to our "all properties" array
956 aProperties
.reserve( aProperties
.size() + aThisHandlersProperties
.size() );
957 for (const auto & aThisHandlersPropertie
: aThisHandlersProperties
)
959 auto noPrevious
= std::none_of(
962 FindPropertyByName( aThisHandlersPropertie
.Name
)
966 aProperties
.push_back( aThisHandlersPropertie
);
970 // there already was another (previous) handler which supported this property.
971 // Don't add it to aProperties, again.
973 // Also, ensure that handlers which previously expressed interest in *changes*
974 // of this property are not notified.
975 // This is 'cause we have a new handler which is responsible for this property,
976 // which means it can give it a completely different meaning than the previous
977 // handler for this property is prepared for.
978 std::pair
< PropertyHandlerMultiRepository::iterator
, PropertyHandlerMultiRepository::iterator
>
979 aDepHandlers
= m_aDependencyHandlers
.equal_range( aThisHandlersPropertie
.Name
);
980 m_aDependencyHandlers
.erase( aDepHandlers
.first
, aDepHandlers
.second
);
983 // determine the superseded properties
984 StlSyntaxSequence
< OUString
> aSupersededByThisHandler( (*aHandler
)->getSupersededProperties() );
985 for (const auto & superseded
: aSupersededByThisHandler
)
987 std::vector
< Property
>::iterator existent
= std::find_if(
990 FindPropertyByName( superseded
)
992 if ( existent
!= aProperties
.end() )
993 // one of the properties superseded by this handler was supported by a previous
995 aProperties
.erase( existent
);
998 // be notified of changes which this handler is responsible for
999 (*aHandler
)->addPropertyChangeListener( this );
1001 // remember this handler for every of the properties which it is responsible
1003 for (const auto & aThisHandlersPropertie
: aThisHandlersProperties
)
1005 m_aPropertyHandlers
[ aThisHandlersPropertie
.Name
] = *aHandler
;
1006 // note that this implies that if two handlers support the same property,
1010 // see if the handler expresses interest in any actuating properties
1011 StlSyntaxSequence
< OUString
> aInterestingActuations( (*aHandler
)->getActuatingProperties() );
1012 for (const auto & aInterestingActuation
: aInterestingActuations
)
1014 m_aDependencyHandlers
.emplace( aInterestingActuation
, *aHandler
);
1020 // create a new composer for UI requests coming from the handlers
1021 m_pUIRequestComposer
.reset( new ComposedPropertyUIUpdate( getInspectorUI(), this ) );
1023 // sort the properties by relative position, as indicated by the model
1025 for (auto const& sourceProps
: aProperties
)
1027 sal_Int32 nRelativePropertyOrder
= nPos
;
1028 if ( m_xModel
.is() )
1029 nRelativePropertyOrder
= m_xModel
->getPropertyOrderIndex( sourceProps
.Name
);
1030 m_aProperties
.emplace(nRelativePropertyOrder
, sourceProps
);
1034 // be notified when one of our inspectees dies
1035 impl_toggleInspecteeListening_nothrow( true );
1037 catch(const Exception
&)
1039 OSL_FAIL("OPropertyBrowserController::doInspection : caught an exception !");
1044 css::awt::Size SAL_CALL
OPropertyBrowserController::getMinimumSize()
1046 css::awt::Size aSize
;
1048 return m_pView
->getMinimumSize();
1054 css::awt::Size SAL_CALL
OPropertyBrowserController::getPreferredSize()
1056 return getMinimumSize();
1060 css::awt::Size SAL_CALL
OPropertyBrowserController::calcAdjustedSize( const css::awt::Size
& _rNewSize
)
1062 awt::Size aMinSize
= getMinimumSize( );
1063 awt::Size
aAdjustedSize( _rNewSize
);
1064 if ( aAdjustedSize
.Width
< aMinSize
.Width
)
1065 aAdjustedSize
.Width
= aMinSize
.Width
;
1066 if ( aAdjustedSize
.Height
< aMinSize
.Height
)
1067 aAdjustedSize
.Height
= aMinSize
.Height
;
1068 return aAdjustedSize
;
1072 void OPropertyBrowserController::describePropertyLine( const Property
& _rProperty
, OLineDescriptor
& _rDescriptor
)
1076 PropertyHandlerRepository::const_iterator handler
= m_aPropertyHandlers
.find( _rProperty
.Name
);
1077 if ( handler
== m_aPropertyHandlers
.end() )
1078 throw RuntimeException(); // caught below
1080 _rDescriptor
.assignFrom( handler
->second
->describePropertyLine( _rProperty
.Name
, this ) );
1083 _rDescriptor
.xPropertyHandler
= handler
->second
;
1084 _rDescriptor
.sName
= _rProperty
.Name
;
1085 _rDescriptor
.aValue
= _rDescriptor
.xPropertyHandler
->getPropertyValue( _rProperty
.Name
);
1087 if ( _rDescriptor
.DisplayName
.isEmpty() )
1090 SAL_WARN( "extensions.propctrlr", "OPropertyBrowserController::describePropertyLine: handler did not provide a display name for '"
1091 <<_rProperty
.Name
<< "'!" );
1093 _rDescriptor
.DisplayName
= _rProperty
.Name
;
1096 PropertyState
ePropertyState( _rDescriptor
.xPropertyHandler
->getPropertyState( _rProperty
.Name
) );
1097 if ( PropertyState_AMBIGUOUS_VALUE
== ePropertyState
)
1099 _rDescriptor
.bUnknownValue
= true;
1100 _rDescriptor
.aValue
.clear();
1103 _rDescriptor
.bReadOnly
= impl_isReadOnlyModel_throw();
1105 catch( const Exception
& )
1107 OSL_FAIL( "OPropertyBrowserController::describePropertyLine: caught an exception!" );
1112 void OPropertyBrowserController::impl_buildCategories_throw()
1114 OSL_PRECOND( m_aPageIds
.empty(), "OPropertyBrowserController::impl_buildCategories_throw: duplicate call!" );
1116 StlSyntaxSequence
< PropertyCategoryDescriptor
> aCategories
;
1117 if ( m_xModel
.is() )
1118 aCategories
= StlSyntaxSequence
< PropertyCategoryDescriptor
>(m_xModel
->describeCategories());
1120 for (auto const& category
: aCategories
)
1122 OSL_ENSURE( m_aPageIds
.find( category
.ProgrammaticName
) == m_aPageIds
.end(),
1123 "OPropertyBrowserController::impl_buildCategories_throw: duplicate programmatic name!" );
1125 m_aPageIds
[ category
.ProgrammaticName
] =
1126 getPropertyBox().AppendPage( category
.UIName
, HelpIdUrl::getHelpId( category
.HelpURL
) );
1131 void OPropertyBrowserController::UpdateUI()
1136 // too early, will return later
1139 getPropertyBox().DisableUpdate();
1141 bool bHaveFocus
= getPropertyBox().HasChildPathFocus();
1143 // create our tab pages
1144 impl_buildCategories_throw();
1145 // (and allow for pages to be actually unused)
1146 std::set
< sal_uInt16
> aUsedPages
;
1148 // when building the UI below, remember which properties are actuating,
1149 // to allow for an initial actuatingPropertyChanged call
1150 std::vector
< OUString
> aActuatingProperties
;
1151 std::vector
< Any
> aActuatingPropertyValues
;
1153 // ask the handlers to describe the property UI, and insert the resulting
1154 // entries into our list boxes
1155 for (auto const& property
: m_aProperties
)
1157 OLineDescriptor aDescriptor
;
1158 describePropertyLine( property
.second
, aDescriptor
);
1160 bool bIsActuatingProperty
= impl_isActuatingProperty_nothrow( property
.second
.Name
);
1162 SAL_WARN_IF( aDescriptor
.Category
.isEmpty(), "extensions.propctrlr",
1163 "OPropertyBrowserController::UpdateUI: empty category provided for property '"
1164 << property
.second
.Name
<< "'!");
1165 // finally insert this property control
1166 sal_uInt16 nTargetPageId
= impl_getPageIdForCategory_nothrow( aDescriptor
.Category
);
1167 if ( nTargetPageId
== sal_uInt16(-1) )
1169 // this category does not yet exist. This is allowed, as an inspector model might be lazy, and not provide
1170 // any category information of its own. In this case, we have a fallback ...
1171 m_aPageIds
[ aDescriptor
.Category
] =
1172 getPropertyBox().AppendPage( aDescriptor
.Category
, OString() );
1173 nTargetPageId
= impl_getPageIdForCategory_nothrow( aDescriptor
.Category
);
1176 getPropertyBox().InsertEntry( aDescriptor
, nTargetPageId
);
1177 aUsedPages
.insert( nTargetPageId
);
1179 // if it's an actuating property, remember it
1180 if ( bIsActuatingProperty
)
1182 aActuatingProperties
.push_back( property
.second
.Name
);
1183 aActuatingPropertyValues
.push_back( impl_getPropertyValue_throw( property
.second
.Name
) );
1187 // update any dependencies for the actuating properties which we encountered
1189 std::vector
< Any
>::const_iterator aPropertyValue
= aActuatingPropertyValues
.begin();
1190 for (auto const& actuatingProperty
: aActuatingProperties
)
1192 impl_broadcastPropertyChange_nothrow( actuatingProperty
, *aPropertyValue
, *aPropertyValue
, true );
1197 // remove any unused pages (which we did not encounter properties for)
1198 HashString2Int16 aSurvivingPageIds
;
1199 for (auto const& pageId
: m_aPageIds
)
1201 if ( aUsedPages
.find( pageId
.second
) == aUsedPages
.end() )
1202 getPropertyBox().RemovePage( pageId
.second
);
1204 aSurvivingPageIds
.insert(pageId
);
1206 m_aPageIds
.swap( aSurvivingPageIds
);
1209 getPropertyBox().Show();
1210 getPropertyBox().EnableUpdate();
1212 getPropertyBox().GrabFocus();
1214 // activate the first page
1215 if ( !m_aPageIds
.empty() )
1217 Sequence
< PropertyCategoryDescriptor
> aCategories( m_xModel
->describeCategories() );
1218 if ( aCategories
.hasElements() )
1219 m_pView
->activatePage( m_aPageIds
[ aCategories
[0].ProgrammaticName
] );
1221 // allowed: if we default-created the pages ...
1222 m_pView
->activatePage( m_aPageIds
.begin()->second
);
1225 // activate the previously active page (if possible)
1226 if ( !m_sLastValidPageSelection
.isEmpty() )
1227 m_sPageSelection
= m_sLastValidPageSelection
;
1228 selectPageFromViewData();
1230 catch( const Exception
& )
1232 DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
1237 void OPropertyBrowserController::Clicked( const OUString
& _rName
, bool _bPrimary
)
1241 // since the browse buttons do not get the focus when clicked with the mouse,
1242 // we need to commit the changes in the current property field
1243 getPropertyBox().CommitModified();
1245 PropertyHandlerRepository::const_iterator handler
= m_aPropertyHandlers
.find( _rName
);
1246 DBG_ASSERT( handler
!= m_aPropertyHandlers
.end(), "OPropertyBrowserController::Clicked: a property without handler? This will crash!" );
1248 ComposedUIAutoFireGuard
aAutoFireGuard( *m_pUIRequestComposer
);
1251 m_xInteractiveHandler
= handler
->second
;
1252 InteractiveSelectionResult eResult
=
1253 handler
->second
->onInteractivePropertySelection( _rName
, _bPrimary
, aData
,
1254 m_pUIRequestComposer
->getUIForPropertyHandler( handler
->second
) );
1258 case InteractiveSelectionResult_Cancelled
:
1259 case InteractiveSelectionResult_Success
:
1260 // okay, nothing to do
1262 case InteractiveSelectionResult_ObtainedValue
:
1263 handler
->second
->setPropertyValue( _rName
, aData
);
1265 case InteractiveSelectionResult_Pending
:
1266 // also okay, we expect that the handler has disabled the UI as necessary
1269 OSL_FAIL( "OPropertyBrowserController::Clicked: unknown result value!" );
1273 catch (const Exception
&)
1275 DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
1277 m_xInteractiveHandler
= nullptr;
1281 bool OPropertyBrowserController::hasPropertyByName( const OUString
& _rName
)
1283 for (auto const& property
: m_aProperties
)
1284 if ( property
.second
.Name
== _rName
)
1290 void OPropertyBrowserController::Commit( const OUString
& rName
, const Any
& _rValue
)
1294 OUString sPlcHolder
= PcrRes(RID_EMBED_IMAGE_PLACEHOLDER
);
1295 bool bIsPlaceHolderValue
= false;
1297 if ( rName
== PROPERTY_IMAGE_URL
)
1299 // if the prop value is the PlaceHolder
1303 if ( sVal
== sPlcHolder
)
1304 bIsPlaceHolderValue
= true;
1306 m_sCommittingProperty
= rName
;
1308 bool bIsActuatingProperty
= impl_isActuatingProperty_nothrow( rName
);
1311 if ( bIsActuatingProperty
)
1312 aOldValue
= impl_getPropertyValue_throw( rName
);
1314 // do we have a dedicated handler for this property, which we can delegate some tasks to?
1315 PropertyHandlerRef handler
= impl_getHandlerForProperty_throw( rName
);
1318 // set the value ( only if it's not a placeholder )
1319 if ( !bIsPlaceHolderValue
)
1320 handler
->setPropertyValue( rName
, _rValue
);
1323 // re-retrieve the value
1324 Any aNormalizedValue
= handler
->getPropertyValue( rName
);
1326 // care for any inter-property dependencies
1327 if ( bIsActuatingProperty
)
1328 impl_broadcastPropertyChange_nothrow( rName
, aNormalizedValue
, aOldValue
, false );
1330 // and display it again. This ensures proper formatting
1331 getPropertyBox().SetPropertyValue( rName
, aNormalizedValue
, false );
1333 catch(const PropertyVetoException
& eVetoException
)
1335 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(m_pView
? m_pView
->GetFrameWeld() : nullptr,
1336 VclMessageType::Info
, VclButtonsType::Ok
,
1337 eVetoException
.Message
));
1339 PropertyHandlerRef handler
= impl_getHandlerForProperty_throw( rName
);
1340 Any aNormalizedValue
= handler
->getPropertyValue( rName
);
1341 getPropertyBox().SetPropertyValue( rName
, aNormalizedValue
, false );
1343 catch(const Exception
&)
1345 OSL_FAIL("OPropertyBrowserController::Commit : caught an exception !");
1348 m_sCommittingProperty
.clear();
1352 void OPropertyBrowserController::focusGained( const Reference
< XPropertyControl
>& Control
)
1354 m_aControlObservers
.notifyEach( &XPropertyControlObserver::focusGained
, Control
);
1358 void OPropertyBrowserController::valueChanged( const Reference
< XPropertyControl
>& Control
)
1360 m_aControlObservers
.notifyEach( &XPropertyControlObserver::valueChanged
, Control
);
1366 Reference
< XPropertyHandler
> lcl_createHandler( const Reference
<XComponentContext
>& _rContext
, const Any
& _rFactoryDescriptor
)
1368 Reference
< XPropertyHandler
> xHandler
;
1370 OUString sServiceName
;
1371 Reference
< XSingleServiceFactory
> xServiceFac
;
1372 Reference
< XSingleComponentFactory
> xComponentFac
;
1374 if ( _rFactoryDescriptor
>>= sServiceName
)
1375 xHandler
.set( _rContext
->getServiceManager()->createInstanceWithContext( sServiceName
, _rContext
), UNO_QUERY
);
1376 else if ( _rFactoryDescriptor
>>= xServiceFac
)
1377 xHandler
.set(xServiceFac
->createInstance(), css::uno::UNO_QUERY
);
1378 else if ( _rFactoryDescriptor
>>= xComponentFac
)
1379 xHandler
.set(xComponentFac
->createInstanceWithContext( _rContext
), css::uno::UNO_QUERY
);
1380 OSL_ENSURE(xHandler
.is(),"lcl_createHandler: Can not create handler");
1386 void OPropertyBrowserController::getPropertyHandlers( const InterfaceArray
& _rObjects
, PropertyHandlerArray
& _rHandlers
)
1388 _rHandlers
.resize( 0 );
1389 if ( _rObjects
.empty() )
1392 // create a component context for the handlers, containing some information about where
1394 Reference
< XComponentContext
> xHandlerContext( m_xContext
);
1396 // if our own creator did not pass a dialog parent window, use our own view for this
1397 Reference
< XWindow
> xParentWindow
;
1398 Any any
= m_xContext
->getValueByName( "DialogParentWindow" );
1399 any
>>= xParentWindow
;
1400 if ( !xParentWindow
.is() )
1402 ::cppu::ContextEntry_Init aHandlerContextInfo
[] =
1404 ::cppu::ContextEntry_Init( "DialogParentWindow", makeAny( VCLUnoHelper::GetInterface( m_pView
) ) )
1406 xHandlerContext
= ::cppu::createComponentContext(
1407 aHandlerContextInfo
, SAL_N_ELEMENTS( aHandlerContextInfo
),
1411 Sequence
< Any
> aHandlerFactories
;
1412 if ( m_xModel
.is() )
1413 aHandlerFactories
= m_xModel
->getHandlerFactories();
1415 for ( auto const & handlerFactory
: std::as_const(aHandlerFactories
) )
1417 if ( _rObjects
.size() == 1 )
1418 { // we're inspecting only one object -> one handler
1419 Reference
< XPropertyHandler
> xHandler( lcl_createHandler( m_xContext
, handlerFactory
) );
1420 if ( xHandler
.is() )
1422 xHandler
->inspect( _rObjects
[0] );
1423 _rHandlers
.push_back( xHandler
);
1428 // create a single handler for every single object
1429 std::vector
< Reference
< XPropertyHandler
> > aSingleHandlers( _rObjects
.size() );
1430 std::vector
< Reference
< XPropertyHandler
> >::iterator pHandler
= aSingleHandlers
.begin();
1432 for (auto const& elem
: _rObjects
)
1434 *pHandler
= lcl_createHandler( m_xContext
, handlerFactory
);
1435 if ( pHandler
->is() )
1437 (*pHandler
)->inspect(elem
);
1441 aSingleHandlers
.resize( pHandler
- aSingleHandlers
.begin() );
1443 // then create a handler which composes information out of those single handlers
1444 if ( !aSingleHandlers
.empty() )
1445 _rHandlers
.push_back( new PropertyComposer( aSingleHandlers
) );
1449 // note that the handlers will not be used by our caller, if they indicate that there are no
1450 // properties they feel responsible for
1454 bool OPropertyBrowserController::impl_findObjectProperty_nothrow( const OUString
& _rName
, OrderedPropertyMap::const_iterator
* _pProperty
)
1456 OrderedPropertyMap::const_iterator search
= std::find_if(m_aProperties
.begin(), m_aProperties
.end(),
1457 [&_rName
](const OrderedPropertyMap::value_type
& rEntry
) { return rEntry
.second
.Name
== _rName
; });
1459 *_pProperty
= search
;
1460 return ( search
!= m_aProperties
.end() );
1464 void OPropertyBrowserController::rebuildPropertyUI( const OUString
& _rPropertyName
)
1466 ::osl::MutexGuard
aGuard( m_aMutex
);
1468 throw RuntimeException();
1470 OrderedPropertyMap::const_iterator propertyPos
;
1471 if ( !impl_findObjectProperty_nothrow( _rPropertyName
, &propertyPos
) )
1474 OLineDescriptor aDescriptor
;
1477 describePropertyLine( propertyPos
->second
, aDescriptor
);
1479 catch( const Exception
& )
1481 OSL_FAIL( "OPropertyBrowserController::rebuildPropertyUI: caught an exception!" );
1484 getPropertyBox().ChangeEntry( aDescriptor
);
1488 void OPropertyBrowserController::enablePropertyUI( const OUString
& _rPropertyName
, sal_Bool _bEnable
)
1490 ::osl::MutexGuard
aGuard( m_aMutex
);
1492 throw RuntimeException();
1494 if ( !impl_findObjectProperty_nothrow( _rPropertyName
) )
1497 getPropertyBox().EnablePropertyLine( _rPropertyName
, _bEnable
);
1501 void OPropertyBrowserController::enablePropertyUIElements( const OUString
& _rPropertyName
, sal_Int16 _nElements
, sal_Bool _bEnable
)
1503 ::osl::MutexGuard
aGuard( m_aMutex
);
1505 throw RuntimeException();
1507 if ( !impl_findObjectProperty_nothrow( _rPropertyName
) )
1510 getPropertyBox().EnablePropertyControls( _rPropertyName
, _nElements
, _bEnable
);
1514 void OPropertyBrowserController::showPropertyUI( const OUString
& _rPropertyName
)
1516 ::osl::MutexGuard
aGuard( m_aMutex
);
1518 throw RuntimeException();
1520 // look up the property in our object properties
1521 OrderedPropertyMap::const_iterator propertyPos
;
1522 if ( !impl_findObjectProperty_nothrow( _rPropertyName
, &propertyPos
) )
1525 if ( getPropertyBox().GetPropertyPos( _rPropertyName
) != EDITOR_LIST_ENTRY_NOTFOUND
)
1527 rebuildPropertyUI( _rPropertyName
);
1531 OLineDescriptor aDescriptor
;
1532 describePropertyLine( propertyPos
->second
, aDescriptor
);
1534 // look for the position to insert the property
1536 // side note: The methods GetPropertyPos and InsertEntry of the OPropertyEditor work
1537 // only on the current page. This implies that it's impossible to use this method here
1538 // to show property lines which are *not* on the current page.
1539 // This is sufficient for now, but should be changed in the future.
1541 // by definition, the properties in m_aProperties are in the order in which they appear in the UI
1542 // So all we need is a predecessor of pProperty in m_aProperties
1543 sal_uInt16 nUIPos
= EDITOR_LIST_ENTRY_NOTFOUND
;
1546 if ( propertyPos
!= m_aProperties
.begin() )
1548 nUIPos
= getPropertyBox().GetPropertyPos( propertyPos
->second
.Name
);
1550 while ( ( nUIPos
== EDITOR_LIST_ENTRY_NOTFOUND
) && ( propertyPos
!= m_aProperties
.begin() ) );
1552 if ( nUIPos
== EDITOR_LIST_ENTRY_NOTFOUND
)
1553 // insert at the very top
1556 // insert right after the predecessor we found
1559 getPropertyBox().InsertEntry(
1560 aDescriptor
, impl_getPageIdForCategory_nothrow( aDescriptor
.Category
), nUIPos
);
1564 void OPropertyBrowserController::hidePropertyUI( const OUString
& _rPropertyName
)
1566 ::osl::MutexGuard
aGuard( m_aMutex
);
1568 throw RuntimeException();
1570 if ( !impl_findObjectProperty_nothrow( _rPropertyName
) )
1573 getPropertyBox().RemoveEntry( _rPropertyName
);
1577 void OPropertyBrowserController::showCategory( const OUString
& _rCategory
, sal_Bool _bShow
)
1579 ::osl::MutexGuard
aGuard( m_aMutex
);
1581 throw RuntimeException();
1583 sal_uInt16 nPageId
= impl_getPageIdForCategory_nothrow( _rCategory
);
1584 OSL_ENSURE( nPageId
!= sal_uInt16(-1), "OPropertyBrowserController::showCategory: invalid category!" );
1586 getPropertyBox().ShowPropertyPage( nPageId
, _bShow
);
1590 Reference
< XPropertyControl
> SAL_CALL
OPropertyBrowserController::getPropertyControl( const OUString
& _rPropertyName
)
1592 ::osl::MutexGuard
aGuard( m_aMutex
);
1594 throw RuntimeException();
1596 Reference
< XPropertyControl
> xControl( getPropertyBox().GetPropertyControl( _rPropertyName
) );
1601 void SAL_CALL
OPropertyBrowserController::registerControlObserver( const Reference
< XPropertyControlObserver
>& Observer
)
1603 m_aControlObservers
.addInterface( Observer
);
1607 void SAL_CALL
OPropertyBrowserController::revokeControlObserver( const Reference
< XPropertyControlObserver
>& Observer
)
1609 m_aControlObservers
.removeInterface( Observer
);
1613 void SAL_CALL
OPropertyBrowserController::setHelpSectionText( const OUString
& _rHelpText
)
1615 SolarMutexGuard aSolarGuard
;
1616 ::osl::MutexGuard
aGuard( m_aMutex
);
1619 throw DisposedException();
1621 if ( !getPropertyBox().HasHelpSection() )
1622 throw NoSupportException();
1624 getPropertyBox().SetHelpText( _rHelpText
);
1628 void OPropertyBrowserController::impl_broadcastPropertyChange_nothrow( const OUString
& _rPropertyName
, const Any
& _rNewValue
, const Any
& _rOldValue
, bool _bFirstTimeInit
) const
1630 // are there one or more handlers which are interested in the actuation?
1631 std::pair
< PropertyHandlerMultiRepository::const_iterator
, PropertyHandlerMultiRepository::const_iterator
> aInterestedHandlers
=
1632 m_aDependencyHandlers
.equal_range( _rPropertyName
);
1633 if ( aInterestedHandlers
.first
== aInterestedHandlers
.second
)
1634 // none of our handlers is interested in this
1637 ComposedUIAutoFireGuard
aAutoFireGuard( *m_pUIRequestComposer
);
1640 // collect the responses from all interested handlers
1641 PropertyHandlerMultiRepository::const_iterator handler
= aInterestedHandlers
.first
;
1642 while ( handler
!= aInterestedHandlers
.second
)
1644 handler
->second
->actuatingPropertyChanged( _rPropertyName
, _rNewValue
, _rOldValue
,
1645 m_pUIRequestComposer
->getUIForPropertyHandler( handler
->second
),
1650 catch( const Exception
& )
1652 DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
1660 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */