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 "propcontroller.hxx"
21 #include "handlerhelper.hxx"
22 #include "standardcontrol.hxx"
23 #include "linedescriptor.hxx"
24 #include <strings.hrc>
25 #include "propertyeditor.hxx"
26 #include "modulepcr.hxx"
27 #include "formstrings.hxx"
28 #include "formbrowsertools.hxx"
29 #include "propertycomposer.hxx"
31 #include <com/sun/star/awt/XWindow.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/lang/NoSupportException.hpp>
34 #include <com/sun/star/inspection/PropertyControlType.hpp>
35 #include <com/sun/star/ucb/AlreadyInitializedException.hpp>
36 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
37 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
38 #include <com/sun/star/util/VetoException.hpp>
39 #include <tools/debug.hxx>
40 #include <comphelper/diagnose_ex.hxx>
41 #include <toolkit/helper/vclunohelper.hxx>
42 #include <vcl/svapp.hxx>
43 #include <vcl/weld.hxx>
44 #include <vcl/weldutils.hxx>
45 #include <osl/mutex.hxx>
46 #include <cppuhelper/queryinterface.hxx>
47 #include <cppuhelper/supportsservice.hxx>
50 #include <sal/log.hxx>
54 using namespace ::com::sun::star
;
55 using namespace ::com::sun::star::uno
;
56 using namespace ::com::sun::star::awt
;
57 using namespace ::com::sun::star::beans
;
58 using namespace ::com::sun::star::lang
;
59 using namespace ::com::sun::star::frame
;
60 using namespace ::com::sun::star::util
;
61 using namespace ::com::sun::star::inspection
;
62 using namespace ::com::sun::star::ucb
;
63 using namespace ::comphelper
;
65 //= OPropertyBrowserController
66 OPropertyBrowserController::OPropertyBrowserController( const Reference
< XComponentContext
>& _rxContext
)
67 :m_xContext(_rxContext
)
68 ,m_aDisposeListeners( m_aMutex
)
69 ,m_aControlObservers( m_aMutex
)
70 ,m_bContainerFocusListening( false )
71 ,m_bSuspendingPropertyHandlers( false )
72 ,m_bConstructed( false )
73 ,m_bBindingIntrospectee( false )
77 OPropertyBrowserController::~OPropertyBrowserController()
79 // stop listening for property changes
81 stopInspection( true );
84 IMPLEMENT_FORWARD_REFCOUNT( OPropertyBrowserController
, OPropertyBrowserController_Base
)
86 Any SAL_CALL
OPropertyBrowserController::queryInterface( const Type
& _rType
)
88 Any aReturn
= OPropertyBrowserController_Base::queryInterface( _rType
);
89 if ( !aReturn
.hasValue() )
90 aReturn
= ::cppu::queryInterface(
92 static_cast< XObjectInspectorUI
* >( this )
98 void OPropertyBrowserController::startContainerWindowListening()
100 if (m_bContainerFocusListening
)
105 Reference
< XWindow
> xContainerWindow
= m_xFrame
->getContainerWindow();
106 if (xContainerWindow
.is())
108 xContainerWindow
->addFocusListener(this);
109 m_bContainerFocusListening
= true;
113 DBG_ASSERT(m_bContainerFocusListening
, "OPropertyBrowserController::startContainerWindowListening: unable to start listening (inconsistence)!");
117 void OPropertyBrowserController::stopContainerWindowListening()
119 if (!m_bContainerFocusListening
)
124 Reference
< XWindow
> xContainerWindow
= m_xFrame
->getContainerWindow();
125 if (xContainerWindow
.is())
127 xContainerWindow
->removeFocusListener(this);
128 m_bContainerFocusListening
= false;
132 DBG_ASSERT(!m_bContainerFocusListening
, "OPropertyBrowserController::stopContainerWindowListening: unable to stop listening (inconsistence)!");
136 Reference
< XObjectInspectorModel
> SAL_CALL
OPropertyBrowserController::getInspectorModel()
142 void OPropertyBrowserController::impl_initializeView_nothrow()
144 OSL_PRECOND( haveView(), "OPropertyBrowserController::impl_initializeView_nothrow: not to be called when we have no view!" );
148 if ( !m_xModel
.is() )
154 getPropertyBox().EnableHelpSection( m_xModel
->getHasHelpSection() );
156 catch( const Exception
& )
158 DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
163 bool OPropertyBrowserController::impl_isReadOnlyModel_throw() const
165 if ( !m_xModel
.is() )
168 return m_xModel
->getIsReadOnly();
172 void OPropertyBrowserController::impl_startOrStopModelListening_nothrow( bool _bDoListen
) const
176 Reference
< XPropertySet
> xModelProperties( m_xModel
, UNO_QUERY
);
177 if ( !xModelProperties
.is() )
178 // okay, so the model doesn't want to change its properties
179 // dynamically - fine with us
182 void (SAL_CALL
XPropertySet::*pListenerOperation
)( const OUString
&, const Reference
< XPropertyChangeListener
>& )
183 = _bDoListen
? &XPropertySet::addPropertyChangeListener
: &XPropertySet::removePropertyChangeListener
;
185 (xModelProperties
.get()->*pListenerOperation
)(
187 const_cast< OPropertyBrowserController
* >( this )
190 catch( const Exception
& )
192 DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
197 void OPropertyBrowserController::impl_bindToNewModel_nothrow( const Reference
< XObjectInspectorModel
>& _rxInspectorModel
)
199 impl_startOrStopModelListening_nothrow( false );
200 m_xModel
= _rxInspectorModel
;
201 impl_startOrStopModelListening_nothrow( true );
203 // initialize the view, if we already have one
205 impl_initializeView_nothrow();
207 // inspect again, if we already have inspectees
208 if ( !m_aInspectedObjects
.empty() )
209 impl_rebindToInspectee_nothrow( std::vector(m_aInspectedObjects
) );
213 void SAL_CALL
OPropertyBrowserController::setInspectorModel( const Reference
< XObjectInspectorModel
>& _inspectorModel
)
215 ::osl::MutexGuard
aGuard( m_aMutex
);
217 if ( m_xModel
== _inspectorModel
)
220 impl_bindToNewModel_nothrow( _inspectorModel
);
224 Reference
< XObjectInspectorUI
> SAL_CALL
OPropertyBrowserController::getInspectorUI()
226 // we're derived from this interface, though we do not expose it in queryInterface and getTypes.
231 void SAL_CALL
OPropertyBrowserController::inspect( const Sequence
< Reference
< XInterface
> >& _rObjects
)
233 SolarMutexGuard aSolarGuard
;
234 ::osl::MutexGuard
aGuard( m_aMutex
);
236 if ( m_bSuspendingPropertyHandlers
|| !suspendAll_nothrow() )
237 { // we already are trying to suspend the component (this is somewhere up the stack)
238 // OR one of our property handlers raised a veto against closing. Well, we *need* to close
239 // it in order to inspect another object.
240 throw VetoException();
242 if ( m_bBindingIntrospectee
)
243 throw VetoException();
245 m_bBindingIntrospectee
= true;
246 impl_rebindToInspectee_nothrow( InterfaceArray( _rObjects
.begin(), _rObjects
.end() ) );
247 m_bBindingIntrospectee
= false;
252 Reference
< XDispatch
> SAL_CALL
OPropertyBrowserController::queryDispatch( const URL
& /*URL*/, const OUString
& /*TargetFrameName*/, ::sal_Int32
/*SearchFlags*/ )
254 // we don't have any dispatches at all, right now
255 return Reference
< XDispatch
>();
259 Sequence
< Reference
< XDispatch
> > SAL_CALL
OPropertyBrowserController::queryDispatches( const Sequence
< DispatchDescriptor
>& Requests
)
261 Sequence
< Reference
< XDispatch
> > aReturn
;
262 sal_Int32 nLen
= Requests
.getLength();
263 aReturn
.realloc( nLen
);
265 Reference
< XDispatch
>* pReturn
= aReturn
.getArray();
266 const Reference
< XDispatch
>* pReturnEnd
= aReturn
.getArray() + nLen
;
267 const DispatchDescriptor
* pDescripts
= Requests
.getConstArray();
269 for ( ; pReturn
!= pReturnEnd
; ++ pReturn
, ++pDescripts
)
270 *pReturn
= queryDispatch( pDescripts
->FeatureURL
, pDescripts
->FrameName
, pDescripts
->SearchFlags
);
276 void SAL_CALL
OPropertyBrowserController::initialize( const Sequence
< Any
>& _arguments
)
278 if ( m_bConstructed
)
279 throw AlreadyInitializedException();
281 StlSyntaxSequence
< Any
> arguments( _arguments
);
282 if ( arguments
.empty() )
283 { // constructor: "createDefault()"
284 m_bConstructed
= true;
288 Reference
< XObjectInspectorModel
> xModel
;
289 if ( arguments
.size() == 1 )
290 { // constructor: "createWithModel( XObjectInspectorModel )"
291 if ( !( arguments
[0] >>= xModel
) )
292 throw IllegalArgumentException( OUString(), *this, 0 );
293 createWithModel( xModel
);
297 throw IllegalArgumentException( OUString(), *this, 0 );
301 void OPropertyBrowserController::createWithModel( const Reference
< XObjectInspectorModel
>& _rxModel
)
303 osl_atomic_increment( &m_refCount
);
305 setInspectorModel( _rxModel
);
307 osl_atomic_decrement( &m_refCount
);
309 m_bConstructed
= true;
313 void SAL_CALL
OPropertyBrowserController::attachFrame( const Reference
< XFrame
>& _rxFrame
)
315 SolarMutexGuard aSolarGuard
;
316 ::osl::MutexGuard
aGuard( m_aMutex
);
318 if (_rxFrame
.is() && haveView())
319 throw RuntimeException(u
"Unable to attach to a second frame."_ustr
,*this);
321 // revoke as focus listener from the old container window
322 stopContainerWindowListening();
331 // TODO: this construction perhaps should be done outside. Don't know the exact meaning of attachFrame.
332 // Maybe it is intended to only announce the frame to the controller, and the instance doing this
333 // announcement is responsible for calling setComponent, too.
334 Reference
<XWindow
> xContainerWindow
= m_xFrame
->getContainerWindow();
336 OUString
sUIFile(u
"modules/spropctrlr/ui/formproperties.ui"_ustr
);
337 std::unique_ptr
<weld::Builder
> xBuilder
;
339 if (weld::TransportAsXWindow
* pTunnel
= dynamic_cast<weld::TransportAsXWindow
*>(xContainerWindow
.get()))
341 xBuilder
= Application::CreateBuilder(pTunnel
->getWidget(), sUIFile
);
345 VclPtr
<vcl::Window
> pParentWin
= VCLUnoHelper::GetWindow(xContainerWindow
);
347 throw RuntimeException(u
"The frame is invalid. Unable to extract the container window."_ustr
,*this);
348 xBuilder
= Application::CreateInterimBuilder(pParentWin
, sUIFile
, true);
351 Construct(xContainerWindow
, std::move(xBuilder
));
353 startContainerWindowListening();
358 sal_Bool SAL_CALL
OPropertyBrowserController::attachModel( const Reference
< XModel
>& _rxModel
)
360 Reference
< XObjectInspectorModel
> xModel( _rxModel
, UNO_QUERY
);
364 setInspectorModel( xModel
);
365 return getInspectorModel() == _rxModel
;
369 bool OPropertyBrowserController::suspendAll_nothrow()
371 // if there is a handle inside its "onInteractivePropertySelection" method,
373 // Normally, we could expect every handler to do this itself, but being
374 // realistic, it's safer to handle this here in general.
375 if ( m_xInteractiveHandler
.is() )
378 m_bSuspendingPropertyHandlers
= true;
379 bool bHandlerVeto
= !suspendPropertyHandlers_nothrow( true );
380 m_bSuspendingPropertyHandlers
= false;
381 return !bHandlerVeto
;
385 bool OPropertyBrowserController::suspendPropertyHandlers_nothrow( bool _bSuspend
)
387 PropertyHandlerArray aAllHandlers
; // will contain every handler exactly once
388 for (auto const& propertyHandler
: m_aPropertyHandlers
)
390 if ( std::find( aAllHandlers
.begin(), aAllHandlers
.end(), propertyHandler
.second
) != aAllHandlers
.end() )
391 // already visited this particular handler (m_aPropertyHandlers usually contains
392 // the same handler more than once)
394 aAllHandlers
.push_back(propertyHandler
.second
);
397 for (auto const& handler
: aAllHandlers
)
401 if ( !handler
->suspend( _bSuspend
) )
403 // if we're not suspending, but reactivating, ignore the error
406 catch( const Exception
& )
408 TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "OPropertyBrowserController::suspendPropertyHandlers_nothrow" );
415 sal_Bool SAL_CALL
OPropertyBrowserController::suspend( sal_Bool _bSuspend
)
417 ::osl::MutexGuard
aGuard( m_aMutex
);
418 OSL_ENSURE( haveView(), "OPropertyBrowserController::suspend: don't have a view anymore!" );
421 { // this means a "suspend" is to be "revoked"
422 suspendPropertyHandlers_nothrow( false );
423 // we ourself cannot revoke our suspend
427 if ( !suspendAll_nothrow() )
430 // commit the editor's content
432 getPropertyBox().CommitModified();
435 stopContainerWindowListening();
442 Any SAL_CALL
OPropertyBrowserController::getViewData( )
444 return Any( m_sPageSelection
);
448 void SAL_CALL
OPropertyBrowserController::restoreViewData( const Any
& Data
)
450 OUString sPageSelection
;
451 if ( ( Data
>>= sPageSelection
) && !sPageSelection
.isEmpty() )
453 m_sPageSelection
= sPageSelection
;
454 selectPageFromViewData();
458 Reference
< XModel
> SAL_CALL
OPropertyBrowserController::getModel( )
461 return Reference
< XModel
>();
464 Reference
< XFrame
> SAL_CALL
OPropertyBrowserController::getFrame( )
469 void SAL_CALL
OPropertyBrowserController::dispose()
471 SolarMutexGuard aSolarGuard
;
473 // stop inspecting the current object
474 stopInspection( false );
476 // say our dispose listeners goodbye
477 css::lang::EventObject aEvt
;
478 aEvt
.Source
= static_cast< ::cppu::OWeakObject
* >(this);
479 m_aDisposeListeners
.disposeAndClear(aEvt
);
480 m_aControlObservers
.disposeAndClear(aEvt
);
486 m_xView
->removeEventListener( static_cast< XPropertyChangeListener
* >( this ) );
489 m_aInspectedObjects
.clear();
490 impl_bindToNewModel_nothrow( nullptr );
492 m_xInteractiveHandler
.clear();
496 void SAL_CALL
OPropertyBrowserController::addEventListener( const Reference
< XEventListener
>& _rxListener
)
498 m_aDisposeListeners
.addInterface(_rxListener
);
501 void SAL_CALL
OPropertyBrowserController::removeEventListener( const Reference
< XEventListener
>& _rxListener
)
503 m_aDisposeListeners
.removeInterface(_rxListener
);
506 OUString SAL_CALL
OPropertyBrowserController::getImplementationName( )
508 return u
"org.openoffice.comp.extensions.ObjectInspector"_ustr
;
511 sal_Bool SAL_CALL
OPropertyBrowserController::supportsService( const OUString
& ServiceName
)
513 return cppu::supportsService(this, ServiceName
);
517 Sequence
< OUString
> SAL_CALL
OPropertyBrowserController::getSupportedServiceNames( )
519 return { u
"com.sun.star.inspection.ObjectInspector"_ustr
};
523 void SAL_CALL
OPropertyBrowserController::focusGained( const FocusEvent
& _rSource
)
525 Reference
< XWindow
> xSourceWindow(_rSource
.Source
, UNO_QUERY
);
526 Reference
< XWindow
> xContainerWindow
;
528 xContainerWindow
= m_xFrame
->getContainerWindow();
530 if ( xContainerWindow
.get() == xSourceWindow
.get() )
531 { // our container window got the focus
533 getPropertyBox().GrabFocus();
538 void SAL_CALL
OPropertyBrowserController::focusLost( const FocusEvent
& /*_rSource*/ )
544 void SAL_CALL
OPropertyBrowserController::disposing( const EventObject
& _rSource
)
546 if ( m_xView
.is() && ( m_xView
== _rSource
.Source
) )
553 auto it
= std::find_if(m_aInspectedObjects
.begin(), m_aInspectedObjects
.end(),
554 [&_rSource
](const InterfaceArray::value_type
& rxObj
) { return rxObj
== _rSource
.Source
; });
555 if (it
!= m_aInspectedObjects
.end())
556 m_aInspectedObjects
.erase(it
);
560 IMPL_LINK_NOARG(OPropertyBrowserController
, OnPageActivation
, LinkParamNone
*, void)
562 updateViewDataFromActivePage();
566 void OPropertyBrowserController::updateViewDataFromActivePage()
571 OUString sOldSelection
= m_sPageSelection
;
572 m_sPageSelection
.clear();
574 const sal_uInt16 nCurrentPage
= m_xPropView
->getActivePage();
575 if ( sal_uInt16(-1) != nCurrentPage
)
577 for (auto const& pageId
: m_aPageIds
)
579 if ( nCurrentPage
== pageId
.second
)
581 m_sPageSelection
= pageId
.first
;
587 if ( !m_sPageSelection
.isEmpty() )
588 m_sLastValidPageSelection
= m_sPageSelection
;
589 else if ( !sOldSelection
.isEmpty() )
590 m_sLastValidPageSelection
= sOldSelection
;
594 sal_uInt16
OPropertyBrowserController::impl_getPageIdForCategory_nothrow( const OUString
& _rCategoryName
) const
596 sal_uInt16 nPageId
= sal_uInt16(-1);
597 HashString2Int16::const_iterator pagePos
= m_aPageIds
.find( _rCategoryName
);
598 if ( pagePos
!= m_aPageIds
.end() )
599 nPageId
= pagePos
->second
;
603 void OPropertyBrowserController::selectPageFromViewData()
605 sal_uInt16 nNewPage
= impl_getPageIdForCategory_nothrow( m_sPageSelection
);
607 if ( haveView() && ( nNewPage
!= sal_uInt16(-1) ) )
608 m_xPropView
->activatePage( nNewPage
);
611 updateViewDataFromActivePage();
614 void OPropertyBrowserController::Construct(const Reference
<XWindow
>& rContainerWindow
, std::unique_ptr
<weld::Builder
> xBuilder
)
616 DBG_ASSERT(!haveView(), "OPropertyBrowserController::Construct: already have a view!");
617 assert(xBuilder
&& "OPropertyBrowserController::Construct: invalid parent window!");
619 m_xBuilder
= std::move(xBuilder
);
621 m_xPropView
.reset(new OPropertyBrowserView(m_xContext
, *m_xBuilder
));
622 m_xPropView
->setPageActivationHandler(LINK(this, OPropertyBrowserController
, OnPageActivation
));
624 // add as dispose listener for our view. The view is disposed by the frame we're plugged into,
625 // and this disposal _deletes_ the view, so it would be deadly if we use our m_xPropView member
627 m_xView
= rContainerWindow
;
629 m_xView
->addEventListener( static_cast< XPropertyChangeListener
* >( this ) );
631 getPropertyBox().SetLineListener(this);
632 getPropertyBox().SetControlObserver(this);
633 impl_initializeView_nothrow();
636 void SAL_CALL
OPropertyBrowserController::propertyChange( const PropertyChangeEvent
& _rEvent
)
638 if ( _rEvent
.Source
== m_xModel
)
640 if ( _rEvent
.PropertyName
== "IsReadOnly" )
641 // this is a huge cudgel, admitted.
642 // The problem is that in case we were previously read-only, all our controls
643 // were created read-only, too. We cannot simply switch them to not-read-only.
644 // Even if they had an API for this, we do not know whether they were
645 // originally created read-only, or if they are read-only just because
647 impl_rebindToInspectee_nothrow( std::vector(m_aInspectedObjects
) );
651 if ( m_sCommittingProperty
== _rEvent
.PropertyName
)
657 Any
aNewValue( _rEvent
.NewValue
);
658 if ( impl_hasPropertyHandlerFor_nothrow( _rEvent
.PropertyName
) )
660 // forward the new value to the property box, to reflect the change in the UI
661 aNewValue
= impl_getPropertyValue_throw( _rEvent
.PropertyName
);
663 // check whether the state is ambiguous. This is interesting in case we display the properties
664 // for multiple objects at once: In this case, we'll get a notification from one of the objects,
665 // but need to care for the "composed" value, which can be "ambiguous".
666 PropertyHandlerRef
xHandler( impl_getHandlerForProperty_throw( _rEvent
.PropertyName
), UNO_SET_THROW
);
667 PropertyState
ePropertyState( xHandler
->getPropertyState( _rEvent
.PropertyName
) );
668 bool bAmbiguousValue
= ( PropertyState_AMBIGUOUS_VALUE
== ePropertyState
);
670 getPropertyBox().SetPropertyValue( _rEvent
.PropertyName
, aNewValue
, bAmbiguousValue
);
673 // if it's an actuating property, then update the UI for any dependent
675 if ( impl_isActuatingProperty_nothrow( _rEvent
.PropertyName
) )
676 impl_broadcastPropertyChange_nothrow( _rEvent
.PropertyName
, aNewValue
, _rEvent
.OldValue
, false );
679 Reference
< XPropertyControl
> SAL_CALL
OPropertyBrowserController::createPropertyControl( ::sal_Int16 ControlType
, sal_Bool bCreateReadOnly
)
681 ::osl::MutexGuard
aGuard( m_aMutex
);
683 Reference
< XPropertyControl
> xControl
;
686 bCreateReadOnly
|= impl_isReadOnlyModel_throw() ? 1 : 0;
688 switch ( ControlType
)
690 case PropertyControlType::MultiLineTextField
:
691 case PropertyControlType::StringListField
:
693 bool bMultiLineTextField
= ControlType
== PropertyControlType::MultiLineTextField
;
694 std::unique_ptr
<weld::Builder
> xBuilder(PropertyHandlerHelper::makeBuilder(u
"modules/spropctrlr/ui/multiline.ui"_ustr
, m_xContext
));
695 auto pContainer
= xBuilder
->weld_container(u
"multiline"_ustr
);
696 rtl::Reference
<OMultilineEditControl
> pControl
= new OMultilineEditControl(std::move(pContainer
), std::move(xBuilder
),
697 bMultiLineTextField
? eMultiLineText
: eStringList
, bCreateReadOnly
);
698 pControl
->SetModifyHandler();
703 case PropertyControlType::ListBox
:
705 std::unique_ptr
<weld::Builder
> xBuilder(PropertyHandlerHelper::makeBuilder(u
"modules/spropctrlr/ui/listbox.ui"_ustr
, m_xContext
));
706 auto pComboBox
= xBuilder
->weld_combo_box(u
"listbox"_ustr
);
707 rtl::Reference
<OListboxControl
> pControl
= new OListboxControl(std::move(pComboBox
), std::move(xBuilder
), bCreateReadOnly
);
708 pControl
->SetModifyHandler();
713 case PropertyControlType::ComboBox
:
715 std::unique_ptr
<weld::Builder
> xBuilder(PropertyHandlerHelper::makeBuilder(u
"modules/spropctrlr/ui/combobox.ui"_ustr
, m_xContext
));
716 auto pComboBox
= xBuilder
->weld_combo_box(u
"combobox"_ustr
);
717 rtl::Reference
<OComboboxControl
> pControl
= new OComboboxControl(std::move(pComboBox
), std::move(xBuilder
), bCreateReadOnly
);
718 pControl
->SetModifyHandler();
723 case PropertyControlType::TextField
:
724 case PropertyControlType::CharacterField
:
726 bool bCharacterField
= ControlType
== PropertyControlType::CharacterField
;
727 std::unique_ptr
<weld::Builder
> xBuilder(PropertyHandlerHelper::makeBuilder(u
"modules/spropctrlr/ui/textfield.ui"_ustr
, m_xContext
));
728 auto pEntry
= xBuilder
->weld_entry(u
"textfield"_ustr
);
729 rtl::Reference
<OEditControl
> pControl
= new OEditControl(std::move(pEntry
), std::move(xBuilder
), bCharacterField
, bCreateReadOnly
);
730 pControl
->SetModifyHandler();
735 case PropertyControlType::NumericField
:
737 std::unique_ptr
<weld::Builder
> xBuilder(PropertyHandlerHelper::makeBuilder(u
"modules/spropctrlr/ui/numericfield.ui"_ustr
, m_xContext
));
738 auto pSpinButton
= xBuilder
->weld_metric_spin_button(u
"numericfield"_ustr
, FieldUnit::NONE
);
739 rtl::Reference
<ONumericControl
> pControl
= new ONumericControl(std::move(pSpinButton
), std::move(xBuilder
), bCreateReadOnly
);
740 pControl
->SetModifyHandler();
745 case PropertyControlType::DateTimeField
:
747 std::unique_ptr
<weld::Builder
> xBuilder(PropertyHandlerHelper::makeBuilder(u
"modules/spropctrlr/ui/datetimefield.ui"_ustr
, m_xContext
));
748 auto pContainer
= xBuilder
->weld_container(u
"datetimefield"_ustr
);
749 rtl::Reference
<ODateTimeControl
> pControl
= new ODateTimeControl(std::move(pContainer
), std::move(xBuilder
), bCreateReadOnly
);
750 pControl
->SetModifyHandler();
755 case PropertyControlType::DateField
:
757 std::unique_ptr
<weld::Builder
> xBuilder(PropertyHandlerHelper::makeBuilder(u
"modules/spropctrlr/ui/datefield.ui"_ustr
, m_xContext
));
758 auto pContainer
= xBuilder
->weld_container(u
"datefield"_ustr
);
759 rtl::Reference
<ODateControl
> pControl
= new ODateControl(std::move(pContainer
), std::move(xBuilder
), bCreateReadOnly
);
760 pControl
->SetModifyHandler();
765 case PropertyControlType::TimeField
:
767 std::unique_ptr
<weld::Builder
> xBuilder(PropertyHandlerHelper::makeBuilder(u
"modules/spropctrlr/ui/timefield.ui"_ustr
, m_xContext
));
768 auto pTimeSpinButton
= xBuilder
->weld_formatted_spin_button(u
"timefield"_ustr
);
769 rtl::Reference
<OTimeControl
> pControl
= new OTimeControl(std::move(pTimeSpinButton
), std::move(xBuilder
), bCreateReadOnly
);
770 pControl
->SetModifyHandler();
775 case PropertyControlType::ColorListBox
:
777 auto lambda
= [this]{ return PropertyHandlerHelper::getDialogParentFrame(m_xContext
); };
778 std::unique_ptr
<weld::Builder
> xBuilder(PropertyHandlerHelper::makeBuilder(u
"modules/spropctrlr/ui/colorlistbox.ui"_ustr
, m_xContext
));
779 auto pMenuButton
= xBuilder
->weld_menu_button(u
"colorlistbox"_ustr
);
780 rtl::Reference
<OColorControl
> pControl
= new OColorControl(std::make_unique
<ColorListBox
>(std::move(pMenuButton
), lambda
), std::move(xBuilder
), bCreateReadOnly
);
781 pControl
->SetModifyHandler();
786 case PropertyControlType::HyperlinkField
:
788 std::unique_ptr
<weld::Builder
> xBuilder(PropertyHandlerHelper::makeBuilder(u
"modules/spropctrlr/ui/hyperlinkfield.ui"_ustr
, m_xContext
));
789 auto pContainer
= xBuilder
->weld_container(u
"hyperlinkfield"_ustr
);
790 rtl::Reference
<OHyperlinkControl
> pControl
= new OHyperlinkControl(std::move(pContainer
), std::move(xBuilder
), bCreateReadOnly
);
791 pControl
->SetModifyHandler();
797 throw IllegalArgumentException( OUString(), *this, 1 );
804 void OPropertyBrowserController::impl_toggleInspecteeListening_nothrow( bool _bOn
)
806 for (auto const& inspectedObject
: m_aInspectedObjects
)
810 Reference
< XComponent
> xComp( inspectedObject
, UNO_QUERY
);
814 xComp
->addEventListener( static_cast< XPropertyChangeListener
* >( this ) );
816 xComp
->removeEventListener( static_cast< XPropertyChangeListener
* >( this ) );
819 catch( const Exception
& )
821 DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
827 void OPropertyBrowserController::stopInspection( bool _bCommitModified
)
831 if ( _bCommitModified
)
832 // commit the editor's content
833 getPropertyBox().CommitModified();
835 // hide the property box so that it does not flicker
836 getPropertyBox().Hide();
838 // clear the property box
839 getPropertyBox().ClearAll();
842 // destroy the view first
846 for (auto const& pageId
: m_aPageIds
)
847 getPropertyBox().RemovePage( pageId
.second
);
848 clearContainer( m_aPageIds
);
851 clearContainer( m_aProperties
);
853 // de-register as dispose-listener from our inspected objects
854 impl_toggleInspecteeListening_nothrow( false );
856 // handlers are obsolete, so is our "composer" for their UI requests
857 if (m_pUIRequestComposer
)
858 m_pUIRequestComposer
->dispose();
859 m_pUIRequestComposer
.reset();
861 // clean up the property handlers
862 PropertyHandlerArray aAllHandlers
; // will contain every handler exactly once
863 for (auto const& propertyHandler
: m_aPropertyHandlers
)
864 if ( std::find( aAllHandlers
.begin(), aAllHandlers
.end(), propertyHandler
.second
) == aAllHandlers
.end() )
865 aAllHandlers
.push_back( propertyHandler
.second
);
867 for (auto const& handler
: aAllHandlers
)
871 handler
->removePropertyChangeListener( this );
874 catch( const DisposedException
& )
877 catch( const Exception
& )
879 DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
883 clearContainer( m_aPropertyHandlers
);
884 clearContainer( m_aDependencyHandlers
);
888 bool OPropertyBrowserController::impl_hasPropertyHandlerFor_nothrow( const OUString
& _rPropertyName
) const
890 PropertyHandlerRepository::const_iterator handlerPos
= m_aPropertyHandlers
.find( _rPropertyName
);
891 return ( handlerPos
!= m_aPropertyHandlers
.end() );
895 OPropertyBrowserController::PropertyHandlerRef
const & OPropertyBrowserController::impl_getHandlerForProperty_throw( const OUString
& _rPropertyName
) const
897 PropertyHandlerRepository::const_iterator handlerPos
= m_aPropertyHandlers
.find( _rPropertyName
);
898 if ( handlerPos
== m_aPropertyHandlers
.end() )
899 throw RuntimeException();
900 return handlerPos
->second
;
904 Any
OPropertyBrowserController::impl_getPropertyValue_throw( const OUString
& _rPropertyName
)
906 PropertyHandlerRef handler
= impl_getHandlerForProperty_throw( _rPropertyName
);
907 return handler
->getPropertyValue( _rPropertyName
);
911 void OPropertyBrowserController::impl_rebindToInspectee_nothrow( InterfaceArray
&& _rObjects
)
915 // stop inspecting the old object(s)
916 stopInspection( true );
918 // inspect the new object(s)
919 m_aInspectedObjects
= std::move(_rObjects
);
922 // update the user interface
926 catch(const Exception
&)
928 TOOLS_WARN_EXCEPTION("extensions.propctrlr", "");
933 void OPropertyBrowserController::doInspection()
938 // obtain the properties of the object
939 std::vector
< Property
> aProperties
;
941 PropertyHandlerArray aPropertyHandlers
;
942 getPropertyHandlers( m_aInspectedObjects
, aPropertyHandlers
);
944 PropertyHandlerArray::iterator
aHandler( aPropertyHandlers
.begin() );
945 while ( aHandler
!= aPropertyHandlers
.end() )
947 DBG_ASSERT( aHandler
->get(), "OPropertyBrowserController::doInspection: invalid handler!" );
949 StlSyntaxSequence
< Property
> aThisHandlersProperties( (*aHandler
)->getSupportedProperties() );
951 if ( aThisHandlersProperties
.empty() )
953 // this handler doesn't know anything about the current inspectee -> ignore it
954 (*aHandler
)->dispose();
955 aHandler
= aPropertyHandlers
.erase( aHandler
);
959 // append these properties to our "all properties" array
960 aProperties
.reserve( std::max
<size_t>(aProperties
.size() + aThisHandlersProperties
.size(), aProperties
.size() * 2) );
961 for (const auto & aThisHandlersProperty
: aThisHandlersProperties
)
963 auto noPrevious
= std::none_of(
966 FindPropertyByName( aThisHandlersProperty
.Name
)
970 aProperties
.push_back( aThisHandlersProperty
);
974 // there already was another (previous) handler which supported this property.
975 // Don't add it to aProperties, again.
977 // Also, ensure that handlers which previously expressed interest in *changes*
978 // of this property are not notified.
979 // This is 'cause we have a new handler which is responsible for this property,
980 // which means it can give it a completely different meaning than the previous
981 // handler for this property is prepared for.
982 std::pair
< PropertyHandlerMultiRepository::iterator
, PropertyHandlerMultiRepository::iterator
>
983 aDepHandlers
= m_aDependencyHandlers
.equal_range( aThisHandlersProperty
.Name
);
984 m_aDependencyHandlers
.erase( aDepHandlers
.first
, aDepHandlers
.second
);
987 // determine the superseded properties
988 StlSyntaxSequence
< OUString
> aSupersededByThisHandler( (*aHandler
)->getSupersededProperties() );
989 for (const auto & superseded
: aSupersededByThisHandler
)
991 std::vector
< Property
>::iterator existent
= std::find_if(
994 FindPropertyByName( superseded
)
996 if ( existent
!= aProperties
.end() )
997 // one of the properties superseded by this handler was supported by a previous
999 aProperties
.erase( existent
);
1002 // be notified of changes which this handler is responsible for
1003 (*aHandler
)->addPropertyChangeListener( this );
1005 // remember this handler for every of the properties which it is responsible
1007 for (const auto & aThisHandlersProperty
: aThisHandlersProperties
)
1009 m_aPropertyHandlers
[ aThisHandlersProperty
.Name
] = *aHandler
;
1010 // note that this implies that if two handlers support the same property,
1014 // see if the handler expresses interest in any actuating properties
1015 StlSyntaxSequence
< OUString
> aInterestingActuations( (*aHandler
)->getActuatingProperties() );
1016 for (const auto & aInterestingActuation
: aInterestingActuations
)
1018 m_aDependencyHandlers
.emplace( aInterestingActuation
, *aHandler
);
1024 // create a new composer for UI requests coming from the handlers
1025 m_pUIRequestComposer
.reset( new ComposedPropertyUIUpdate( getInspectorUI(), this ) );
1027 // sort the properties by relative position, as indicated by the model
1029 for (auto const& sourceProps
: aProperties
)
1031 sal_Int32 nRelativePropertyOrder
= nPos
;
1032 if ( m_xModel
.is() )
1033 nRelativePropertyOrder
= m_xModel
->getPropertyOrderIndex( sourceProps
.Name
);
1034 m_aProperties
.emplace(nRelativePropertyOrder
, sourceProps
);
1038 // be notified when one of our inspectees dies
1039 impl_toggleInspecteeListening_nothrow( true );
1041 catch(const Exception
&)
1043 TOOLS_WARN_EXCEPTION("extensions.propctrlr", "");
1048 css::awt::Size SAL_CALL
OPropertyBrowserController::getMinimumSize()
1050 css::awt::Size aSize
;
1052 return m_xPropView
->getMinimumSize();
1058 css::awt::Size SAL_CALL
OPropertyBrowserController::getPreferredSize()
1060 return getMinimumSize();
1064 css::awt::Size SAL_CALL
OPropertyBrowserController::calcAdjustedSize( const css::awt::Size
& _rNewSize
)
1066 awt::Size aMinSize
= getMinimumSize( );
1067 awt::Size
aAdjustedSize( _rNewSize
);
1068 if ( aAdjustedSize
.Width
< aMinSize
.Width
)
1069 aAdjustedSize
.Width
= aMinSize
.Width
;
1070 if ( aAdjustedSize
.Height
< aMinSize
.Height
)
1071 aAdjustedSize
.Height
= aMinSize
.Height
;
1072 return aAdjustedSize
;
1076 void OPropertyBrowserController::describePropertyLine( const Property
& _rProperty
, OLineDescriptor
& _rDescriptor
)
1080 PropertyHandlerRepository::const_iterator handler
= m_aPropertyHandlers
.find( _rProperty
.Name
);
1081 if ( handler
== m_aPropertyHandlers
.end() )
1082 throw RuntimeException(); // caught below
1084 _rDescriptor
.assignFrom( handler
->second
->describePropertyLine( _rProperty
.Name
, this ) );
1087 _rDescriptor
.xPropertyHandler
= handler
->second
;
1088 _rDescriptor
.sName
= _rProperty
.Name
;
1089 _rDescriptor
.aValue
= _rDescriptor
.xPropertyHandler
->getPropertyValue( _rProperty
.Name
);
1091 if ( _rDescriptor
.DisplayName
.isEmpty() )
1094 SAL_WARN( "extensions.propctrlr", "OPropertyBrowserController::describePropertyLine: handler did not provide a display name for '"
1095 <<_rProperty
.Name
<< "'!" );
1097 _rDescriptor
.DisplayName
= _rProperty
.Name
;
1100 PropertyState
ePropertyState( _rDescriptor
.xPropertyHandler
->getPropertyState( _rProperty
.Name
) );
1101 if ( PropertyState_AMBIGUOUS_VALUE
== ePropertyState
)
1103 _rDescriptor
.bUnknownValue
= true;
1104 _rDescriptor
.aValue
.clear();
1107 _rDescriptor
.bReadOnly
= impl_isReadOnlyModel_throw();
1109 // for ui-testing try and distinguish different instances of the controls
1110 auto xWindow
= _rDescriptor
.Control
->getControlWindow();
1111 if (weld::TransportAsXWindow
* pTunnel
= dynamic_cast<weld::TransportAsXWindow
*>(xWindow
.get()))
1113 weld::Widget
* m_pControlWindow
= pTunnel
->getWidget();
1114 if (m_pControlWindow
)
1115 m_pControlWindow
->set_buildable_name(m_pControlWindow
->get_buildable_name() + "-" + _rDescriptor
.DisplayName
);
1119 catch( const Exception
& )
1121 TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "OPropertyBrowserController::describePropertyLine" );
1126 void OPropertyBrowserController::impl_buildCategories_throw()
1128 OSL_PRECOND( m_aPageIds
.empty(), "OPropertyBrowserController::impl_buildCategories_throw: duplicate call!" );
1130 StlSyntaxSequence
< PropertyCategoryDescriptor
> aCategories
;
1131 if ( m_xModel
.is() )
1132 aCategories
= StlSyntaxSequence
< PropertyCategoryDescriptor
>(m_xModel
->describeCategories());
1134 for (auto const& category
: aCategories
)
1136 OSL_ENSURE( m_aPageIds
.find( category
.ProgrammaticName
) == m_aPageIds
.end(),
1137 "OPropertyBrowserController::impl_buildCategories_throw: duplicate programmatic name!" );
1139 m_aPageIds
[ category
.ProgrammaticName
] =
1140 getPropertyBox().AppendPage( category
.UIName
, HelpIdUrl::getHelpId( category
.HelpURL
) );
1145 void OPropertyBrowserController::UpdateUI()
1150 // too early, will return later
1153 // create our tab pages
1154 impl_buildCategories_throw();
1155 // (and allow for pages to be actually unused)
1156 std::set
< sal_uInt16
> aUsedPages
;
1158 // when building the UI below, remember which properties are actuating,
1159 // to allow for an initial actuatingPropertyChanged call
1160 std::vector
< OUString
> aActuatingProperties
;
1161 std::vector
< Any
> aActuatingPropertyValues
;
1163 // ask the handlers to describe the property UI, and insert the resulting
1164 // entries into our list boxes
1165 for (auto const& property
: m_aProperties
)
1167 OLineDescriptor aDescriptor
;
1168 describePropertyLine( property
.second
, aDescriptor
);
1170 bool bIsActuatingProperty
= impl_isActuatingProperty_nothrow( property
.second
.Name
);
1172 SAL_WARN_IF( aDescriptor
.Category
.isEmpty(), "extensions.propctrlr",
1173 "OPropertyBrowserController::UpdateUI: empty category provided for property '"
1174 << property
.second
.Name
<< "'!");
1175 // finally insert this property control
1176 sal_uInt16 nTargetPageId
= impl_getPageIdForCategory_nothrow( aDescriptor
.Category
);
1177 if ( nTargetPageId
== sal_uInt16(-1) )
1179 // this category does not yet exist. This is allowed, as an inspector model might be lazy, and not provide
1180 // any category information of its own. In this case, we have a fallback ...
1181 m_aPageIds
[ aDescriptor
.Category
] =
1182 getPropertyBox().AppendPage(aDescriptor
.Category
, {});
1183 nTargetPageId
= impl_getPageIdForCategory_nothrow( aDescriptor
.Category
);
1186 getPropertyBox().InsertEntry( aDescriptor
, nTargetPageId
);
1187 aUsedPages
.insert( nTargetPageId
);
1189 // if it's an actuating property, remember it
1190 if ( bIsActuatingProperty
)
1192 aActuatingProperties
.push_back( property
.second
.Name
);
1193 aActuatingPropertyValues
.push_back( impl_getPropertyValue_throw( property
.second
.Name
) );
1197 // update any dependencies for the actuating properties which we encountered
1199 std::vector
< Any
>::const_iterator aPropertyValue
= aActuatingPropertyValues
.begin();
1200 for (auto const& actuatingProperty
: aActuatingProperties
)
1202 impl_broadcastPropertyChange_nothrow( actuatingProperty
, *aPropertyValue
, *aPropertyValue
, true );
1207 // remove any unused pages (which we did not encounter properties for)
1208 HashString2Int16 aSurvivingPageIds
;
1209 for (auto const& pageId
: m_aPageIds
)
1211 if ( aUsedPages
.find( pageId
.second
) == aUsedPages
.end() )
1212 getPropertyBox().RemovePage( pageId
.second
);
1214 aSurvivingPageIds
.insert(pageId
);
1216 m_aPageIds
.swap( aSurvivingPageIds
);
1218 getPropertyBox().Show();
1220 // activate the first page
1221 if ( !m_aPageIds
.empty() )
1223 Sequence
< PropertyCategoryDescriptor
> aCategories( m_xModel
->describeCategories() );
1224 if ( aCategories
.hasElements() )
1225 m_xPropView
->activatePage( m_aPageIds
[ aCategories
[0].ProgrammaticName
] );
1227 // allowed: if we default-created the pages ...
1228 m_xPropView
->activatePage( m_aPageIds
.begin()->second
);
1231 // activate the previously active page (if possible)
1232 if ( !m_sLastValidPageSelection
.isEmpty() )
1233 m_sPageSelection
= m_sLastValidPageSelection
;
1234 selectPageFromViewData();
1236 catch( const Exception
& )
1238 DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
1243 void OPropertyBrowserController::Clicked( const OUString
& _rName
, bool _bPrimary
)
1247 // since the browse buttons do not get the focus when clicked with the mouse,
1248 // we need to commit the changes in the current property field
1249 getPropertyBox().CommitModified();
1251 PropertyHandlerRepository::const_iterator handler
= m_aPropertyHandlers
.find( _rName
);
1252 DBG_ASSERT( handler
!= m_aPropertyHandlers
.end(), "OPropertyBrowserController::Clicked: a property without handler? This will crash!" );
1254 ComposedUIAutoFireGuard
aAutoFireGuard( *m_pUIRequestComposer
);
1257 m_xInteractiveHandler
= handler
->second
;
1258 InteractiveSelectionResult eResult
=
1259 handler
->second
->onInteractivePropertySelection( _rName
, _bPrimary
, aData
,
1260 m_pUIRequestComposer
->getUIForPropertyHandler( handler
->second
) );
1264 case InteractiveSelectionResult_Cancelled
:
1265 case InteractiveSelectionResult_Success
:
1266 // okay, nothing to do
1268 case InteractiveSelectionResult_ObtainedValue
:
1269 handler
->second
->setPropertyValue( _rName
, aData
);
1271 case InteractiveSelectionResult_Pending
:
1272 // also okay, we expect that the handler has disabled the UI as necessary
1275 OSL_FAIL( "OPropertyBrowserController::Clicked: unknown result value!" );
1279 catch (const Exception
&)
1281 DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
1283 m_xInteractiveHandler
= nullptr;
1287 bool OPropertyBrowserController::hasPropertyByName( const OUString
& _rName
)
1289 for (auto const& property
: m_aProperties
)
1290 if ( property
.second
.Name
== _rName
)
1296 void OPropertyBrowserController::Commit( const OUString
& rName
, const Any
& _rValue
)
1300 OUString sPlcHolder
= PcrRes(RID_EMBED_IMAGE_PLACEHOLDER
);
1301 bool bIsPlaceHolderValue
= false;
1303 if ( rName
== PROPERTY_IMAGE_URL
)
1305 // if the prop value is the PlaceHolder
1309 if ( sVal
== sPlcHolder
)
1310 bIsPlaceHolderValue
= true;
1312 m_sCommittingProperty
= rName
;
1314 bool bIsActuatingProperty
= impl_isActuatingProperty_nothrow( rName
);
1317 if ( bIsActuatingProperty
)
1318 aOldValue
= impl_getPropertyValue_throw( rName
);
1320 // do we have a dedicated handler for this property, which we can delegate some tasks to?
1321 PropertyHandlerRef handler
= impl_getHandlerForProperty_throw( rName
);
1324 // set the value ( only if it's not a placeholder )
1325 if ( !bIsPlaceHolderValue
)
1326 handler
->setPropertyValue( rName
, _rValue
);
1329 // re-retrieve the value
1330 Any aNormalizedValue
= handler
->getPropertyValue( rName
);
1332 // care for any inter-property dependencies
1333 if ( bIsActuatingProperty
)
1334 impl_broadcastPropertyChange_nothrow( rName
, aNormalizedValue
, aOldValue
, false );
1336 // and display it again. This ensures proper formatting
1337 getPropertyBox().SetPropertyValue( rName
, aNormalizedValue
, false );
1339 catch(const PropertyVetoException
& eVetoException
)
1341 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(m_xPropView
->getPropertyBox().getWidget(),
1342 VclMessageType::Info
, VclButtonsType::Ok
,
1343 eVetoException
.Message
));
1345 PropertyHandlerRef handler
= impl_getHandlerForProperty_throw( rName
);
1346 Any aNormalizedValue
= handler
->getPropertyValue( rName
);
1347 getPropertyBox().SetPropertyValue( rName
, aNormalizedValue
, false );
1349 catch(const Exception
&)
1351 TOOLS_WARN_EXCEPTION("extensions.propctrlr", "");
1354 m_sCommittingProperty
.clear();
1358 void OPropertyBrowserController::focusGained( const Reference
< XPropertyControl
>& Control
)
1360 m_aControlObservers
.notifyEach( &XPropertyControlObserver::focusGained
, Control
);
1364 void OPropertyBrowserController::valueChanged( const Reference
< XPropertyControl
>& Control
)
1366 m_aControlObservers
.notifyEach( &XPropertyControlObserver::valueChanged
, Control
);
1372 Reference
< XPropertyHandler
> lcl_createHandler( const Reference
<XComponentContext
>& _rContext
, const Any
& _rFactoryDescriptor
)
1374 Reference
< XPropertyHandler
> xHandler
;
1376 OUString sServiceName
;
1377 Reference
< XSingleServiceFactory
> xServiceFac
;
1378 Reference
< XSingleComponentFactory
> xComponentFac
;
1380 if ( _rFactoryDescriptor
>>= sServiceName
)
1381 xHandler
.set( _rContext
->getServiceManager()->createInstanceWithContext( sServiceName
, _rContext
), UNO_QUERY
);
1382 else if ( _rFactoryDescriptor
>>= xServiceFac
)
1383 xHandler
.set(xServiceFac
->createInstance(), css::uno::UNO_QUERY
);
1384 else if ( _rFactoryDescriptor
>>= xComponentFac
)
1385 xHandler
.set(xComponentFac
->createInstanceWithContext( _rContext
), css::uno::UNO_QUERY
);
1386 OSL_ENSURE(xHandler
.is(),"lcl_createHandler: Can not create handler");
1392 void OPropertyBrowserController::getPropertyHandlers( const InterfaceArray
& _rObjects
, PropertyHandlerArray
& _rHandlers
)
1394 _rHandlers
.resize( 0 );
1395 if ( _rObjects
.empty() )
1398 Sequence
< Any
> aHandlerFactories
;
1399 if ( m_xModel
.is() )
1400 aHandlerFactories
= m_xModel
->getHandlerFactories();
1402 for (auto const& handlerFactory
: aHandlerFactories
)
1404 if ( _rObjects
.size() == 1 )
1405 { // we're inspecting only one object -> one handler
1406 Reference
< XPropertyHandler
> xHandler( lcl_createHandler( m_xContext
, handlerFactory
) );
1407 if ( xHandler
.is() )
1409 xHandler
->inspect( _rObjects
[0] );
1410 _rHandlers
.push_back( xHandler
);
1415 // create a single handler for every single object
1416 std::vector
< Reference
< XPropertyHandler
> > aSingleHandlers( _rObjects
.size() );
1417 std::vector
< Reference
< XPropertyHandler
> >::iterator pHandler
= aSingleHandlers
.begin();
1419 for (auto const& elem
: _rObjects
)
1421 *pHandler
= lcl_createHandler( m_xContext
, handlerFactory
);
1422 if ( pHandler
->is() )
1424 (*pHandler
)->inspect(elem
);
1428 aSingleHandlers
.resize( pHandler
- aSingleHandlers
.begin() );
1430 // then create a handler which composes information out of those single handlers
1431 if ( !aSingleHandlers
.empty() )
1432 _rHandlers
.push_back( new PropertyComposer( std::move(aSingleHandlers
) ) );
1436 // note that the handlers will not be used by our caller, if they indicate that there are no
1437 // properties they feel responsible for
1441 bool OPropertyBrowserController::impl_findObjectProperty_nothrow( const OUString
& _rName
, OrderedPropertyMap::const_iterator
* _pProperty
)
1443 OrderedPropertyMap::const_iterator search
= std::find_if(m_aProperties
.begin(), m_aProperties
.end(),
1444 [&_rName
](const OrderedPropertyMap::value_type
& rEntry
) { return rEntry
.second
.Name
== _rName
; });
1446 *_pProperty
= search
;
1447 return ( search
!= m_aProperties
.end() );
1451 void OPropertyBrowserController::rebuildPropertyUI( const OUString
& _rPropertyName
)
1453 ::osl::MutexGuard
aGuard( m_aMutex
);
1455 throw RuntimeException();
1457 OrderedPropertyMap::const_iterator propertyPos
;
1458 if ( !impl_findObjectProperty_nothrow( _rPropertyName
, &propertyPos
) )
1461 OLineDescriptor aDescriptor
;
1464 describePropertyLine( propertyPos
->second
, aDescriptor
);
1466 catch( const Exception
& )
1468 TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "OPropertyBrowserController::rebuildPropertyUI" );
1471 getPropertyBox().ChangeEntry( aDescriptor
);
1475 void OPropertyBrowserController::enablePropertyUI( const OUString
& _rPropertyName
, sal_Bool _bEnable
)
1477 ::osl::MutexGuard
aGuard( m_aMutex
);
1479 throw RuntimeException();
1481 if ( !impl_findObjectProperty_nothrow( _rPropertyName
) )
1484 getPropertyBox().EnablePropertyLine( _rPropertyName
, _bEnable
);
1488 void OPropertyBrowserController::enablePropertyUIElements( const OUString
& _rPropertyName
, sal_Int16 _nElements
, sal_Bool _bEnable
)
1490 ::osl::MutexGuard
aGuard( m_aMutex
);
1492 throw RuntimeException();
1494 if ( !impl_findObjectProperty_nothrow( _rPropertyName
) )
1497 getPropertyBox().EnablePropertyControls( _rPropertyName
, _nElements
, _bEnable
);
1501 void OPropertyBrowserController::showPropertyUI( const OUString
& _rPropertyName
)
1503 ::osl::MutexGuard
aGuard( m_aMutex
);
1505 throw RuntimeException();
1507 // look up the property in our object properties
1508 OrderedPropertyMap::const_iterator propertyPos
;
1509 if ( !impl_findObjectProperty_nothrow( _rPropertyName
, &propertyPos
) )
1512 if ( getPropertyBox().GetPropertyPos( _rPropertyName
) != EDITOR_LIST_ENTRY_NOTFOUND
)
1514 rebuildPropertyUI( _rPropertyName
);
1518 OLineDescriptor aDescriptor
;
1519 describePropertyLine( propertyPos
->second
, aDescriptor
);
1521 // look for the position to insert the property
1523 // side note: The methods GetPropertyPos and InsertEntry of the OPropertyEditor work
1524 // only on the current page. This implies that it's impossible to use this method here
1525 // to show property lines which are *not* on the current page.
1526 // This is sufficient for now, but should be changed in the future.
1528 // by definition, the properties in m_aProperties are in the order in which they appear in the UI
1529 // So all we need is a predecessor of pProperty in m_aProperties
1530 sal_uInt16 nUIPos
= EDITOR_LIST_ENTRY_NOTFOUND
;
1533 if ( propertyPos
!= m_aProperties
.begin() )
1535 nUIPos
= getPropertyBox().GetPropertyPos( propertyPos
->second
.Name
);
1537 while ( ( nUIPos
== EDITOR_LIST_ENTRY_NOTFOUND
) && ( propertyPos
!= m_aProperties
.begin() ) );
1539 if ( nUIPos
== EDITOR_LIST_ENTRY_NOTFOUND
)
1540 // insert at the very top
1543 // insert right after the predecessor we found
1546 getPropertyBox().InsertEntry(
1547 aDescriptor
, impl_getPageIdForCategory_nothrow( aDescriptor
.Category
), nUIPos
);
1551 void OPropertyBrowserController::hidePropertyUI( const OUString
& _rPropertyName
)
1553 ::osl::MutexGuard
aGuard( m_aMutex
);
1555 throw RuntimeException();
1557 if ( !impl_findObjectProperty_nothrow( _rPropertyName
) )
1560 getPropertyBox().RemoveEntry( _rPropertyName
);
1564 void OPropertyBrowserController::showCategory( const OUString
& rCategory
, sal_Bool bShow
)
1566 ::osl::MutexGuard
aGuard( m_aMutex
);
1568 throw RuntimeException();
1570 sal_uInt16 nPageId
= impl_getPageIdForCategory_nothrow( rCategory
);
1571 OSL_ENSURE( nPageId
!= sal_uInt16(-1), "OPropertyBrowserController::showCategory: invalid category!" );
1573 getPropertyBox().ShowPropertyPage( nPageId
, bShow
);
1577 Reference
< XPropertyControl
> SAL_CALL
OPropertyBrowserController::getPropertyControl( const OUString
& _rPropertyName
)
1579 ::osl::MutexGuard
aGuard( m_aMutex
);
1581 throw RuntimeException();
1583 Reference
< XPropertyControl
> xControl( getPropertyBox().GetPropertyControl( _rPropertyName
) );
1588 void SAL_CALL
OPropertyBrowserController::registerControlObserver( const Reference
< XPropertyControlObserver
>& Observer
)
1590 m_aControlObservers
.addInterface( Observer
);
1594 void SAL_CALL
OPropertyBrowserController::revokeControlObserver( const Reference
< XPropertyControlObserver
>& Observer
)
1596 m_aControlObservers
.removeInterface( Observer
);
1600 void SAL_CALL
OPropertyBrowserController::setHelpSectionText( const OUString
& _rHelpText
)
1602 SolarMutexGuard aSolarGuard
;
1603 ::osl::MutexGuard
aGuard( m_aMutex
);
1606 throw DisposedException();
1608 if ( !getPropertyBox().HasHelpSection() )
1609 throw NoSupportException();
1611 getPropertyBox().SetHelpText( _rHelpText
);
1615 void OPropertyBrowserController::impl_broadcastPropertyChange_nothrow( const OUString
& _rPropertyName
, const Any
& _rNewValue
, const Any
& _rOldValue
, bool _bFirstTimeInit
) const
1617 // are there one or more handlers which are interested in the actuation?
1618 std::pair
< PropertyHandlerMultiRepository::const_iterator
, PropertyHandlerMultiRepository::const_iterator
> aInterestedHandlers
=
1619 m_aDependencyHandlers
.equal_range( _rPropertyName
);
1620 if ( aInterestedHandlers
.first
== aInterestedHandlers
.second
)
1621 // none of our handlers is interested in this
1624 ComposedUIAutoFireGuard
aAutoFireGuard( *m_pUIRequestComposer
);
1627 // collect the responses from all interested handlers
1628 PropertyHandlerMultiRepository::const_iterator handler
= aInterestedHandlers
.first
;
1629 while ( handler
!= aInterestedHandlers
.second
)
1631 handler
->second
->actuatingPropertyChanged( _rPropertyName
, _rNewValue
, _rOldValue
,
1632 m_pUIRequestComposer
->getUIForPropertyHandler( handler
->second
),
1637 catch( const Exception
& )
1639 DBG_UNHANDLED_EXCEPTION("extensions.propctrlr");
1646 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
1647 extensions_propctrlr_OPropertyBrowserController_get_implementation(
1648 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
1650 return cppu::acquire(new pcr::OPropertyBrowserController(context
));
1653 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */