extensions/source/propctrlr/browserline.cxx | 6 extensions/source/propctrlr/browserline.hxx | 14 extensions/source/propctrlr/browserlistbox.cxx | 4 extensions/source/propctrlr/browserlistbox.hxx | 13 extensions/source/propctrlr/propcontroller.cxx | 2482 +++++++++++------------ extensions/source/propctrlr/propcontroller.hxx | 468 ++-- extensions/source/propctrlr/propertyeditor.cxx | 2 extensions/source/propctrlr/propertyeditor.hxx | 6 extensions/source/propctrlr/proplinelistener.hxx | 43 solenv/clang-format/excludelist | 3 10 files changed, 1500 insertions(+), 1541 deletions(-)
New commits: commit d6062c6b9810b50c78ccd054011b76f40cb79b10 Author: Michael Weghorn <[email protected]> AuthorDate: Wed Feb 25 01:11:01 2026 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Wed Feb 25 09:04:09 2026 +0100 propctrlr: Drop abstract IButtonClickListener It's only implemented/subclassed by OBrowserListBox. Use that one directly instead. Change-Id: I7c8e3d7fe80eb3cc3165163c1eabf409610ea5c3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200280 Tested-by: Jenkins Reviewed-by: Michael Weghorn <[email protected]> diff --git a/extensions/source/propctrlr/browserline.cxx b/extensions/source/propctrlr/browserline.cxx index 55778dd2ae13..2471337b095a 100644 --- a/extensions/source/propctrlr/browserline.cxx +++ b/extensions/source/propctrlr/browserline.cxx @@ -18,6 +18,7 @@ */ #include "browserline.hxx" +#include "browserlistbox.hxx" #include <com/sun/star/uno/XComponentContext.hpp> #include <com/sun/star/inspection/PropertyLineElement.hpp> @@ -379,10 +380,7 @@ void OBrowserLine::SetTitleWidth(sal_uInt16 nWidth) FullFillTitleString(); } -void OBrowserLine::SetClickListener(IButtonClickListener* _pListener) -{ - m_pClickListener = _pListener; -} +void OBrowserLine::SetClickListener(OBrowserListBox* _pListener) { m_pClickListener = _pListener; } IMPL_LINK(OBrowserLine, OnButtonClicked, weld::Button&, rButton, void) { diff --git a/extensions/source/propctrlr/browserline.hxx b/extensions/source/propctrlr/browserline.hxx index 0fd8f88f8d71..d591262b69f6 100644 --- a/extensions/source/propctrlr/browserline.hxx +++ b/extensions/source/propctrlr/browserline.hxx @@ -31,15 +31,7 @@ const sal_Int16 CompleteLine = 0x4000; namespace pcr { class OBrowserLine; - -class IButtonClickListener -{ -public: - virtual void buttonClicked(OBrowserLine* pLine, bool bPrimary) = 0; - -protected: - ~IButtonClickListener() {} -}; +class OBrowserListBox; class OBrowserLine { @@ -56,7 +48,7 @@ private: weld::Widget* m_pControlWindow; weld::Button* m_pBrowseButton; weld::Button* m_pAdditionalBrowseButton; - IButtonClickListener* m_pClickListener; + OBrowserListBox* m_pClickListener; sal_uInt16 m_nNameWidth; sal_uInt16 m_nEnableFlags; bool m_bIndentTitle; @@ -100,7 +92,7 @@ public: void SetReadOnly(bool bReadOnly); - void SetClickListener(IButtonClickListener* pListener); + void SetClickListener(OBrowserListBox* pListener); void IndentTitle(bool bIndent); diff --git a/extensions/source/propctrlr/browserlistbox.hxx b/extensions/source/propctrlr/browserlistbox.hxx index 577fd772a0cd..b4d38e449bcf 100644 --- a/extensions/source/propctrlr/browserlistbox.hxx +++ b/extensions/source/propctrlr/browserlistbox.hxx @@ -61,7 +61,7 @@ struct ListBoxLine }; typedef std::vector<ListBoxLine> ListBoxLines; -class OBrowserListBox final : public IButtonClickListener +class OBrowserListBox final { std::unique_ptr<weld::ScrolledWindow> m_xScrolledWindow; std::unique_ptr<weld::Grid> m_xLinesPlayground; @@ -116,10 +116,9 @@ public: void activateNextControl( const css::uno::Reference<css::inspection::XPropertyControl>& CurrentControl); -private: - // IButtonClickListener - void buttonClicked(OBrowserLine* _pLine, bool _bPrimary) override; + void buttonClicked(OBrowserLine* _pLine, bool _bPrimary); +private: /** retrieves the index of a given control in our line list @param _rxControl The control to lookup. Must denote a control of one of the lines in ->m_aLines commit d7f16caf6add7bcae4c1479baac8c7e95110c2d9 Author: Michael Weghorn <[email protected]> AuthorDate: Wed Feb 25 00:59:02 2026 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Wed Feb 25 09:04:03 2026 +0100 propctrlr: Drop abstract IPropertyLineListener It's only implemented/subclassed by OPropertyBrowserController. Use that one directly instead. Change-Id: I2a686230273d5138a9af2018d1b7e49ee3dedfaa Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200279 Reviewed-by: Michael Weghorn <[email protected]> Tested-by: Jenkins diff --git a/extensions/source/propctrlr/browserlistbox.cxx b/extensions/source/propctrlr/browserlistbox.cxx index 420faeb663c8..3a60d53dc451 100644 --- a/extensions/source/propctrlr/browserlistbox.cxx +++ b/extensions/source/propctrlr/browserlistbox.cxx @@ -19,7 +19,7 @@ #include "browserlistbox.hxx" #include "pcrcommon.hxx" -#include "proplinelistener.hxx" +#include "propcontroller.hxx" #include "propcontrolobserver.hxx" #include "linedescriptor.hxx" #include "inspectorhelpwindow.hxx" @@ -354,7 +354,7 @@ void OBrowserListBox::CommitModified() m_pControlContextImpl->setNotificationMode(PropertyControlContext_Impl::eAsynchronously); } -void OBrowserListBox::SetListener(IPropertyLineListener* _pListener) +void OBrowserListBox::SetListener(OPropertyBrowserController* _pListener) { m_pLineListener = _pListener; } diff --git a/extensions/source/propctrlr/browserlistbox.hxx b/extensions/source/propctrlr/browserlistbox.hxx index a4bfc225002c..577fd772a0cd 100644 --- a/extensions/source/propctrlr/browserlistbox.hxx +++ b/extensions/source/propctrlr/browserlistbox.hxx @@ -36,9 +36,9 @@ namespace pcr { -class IPropertyLineListener; class IPropertyControlObserver; struct OLineDescriptor; +class OPropertyBrowserController; class InspectorHelpWindow; class PropertyControlContext_Impl; @@ -68,7 +68,7 @@ class OBrowserListBox final : public IButtonClickListener std::unique_ptr<InspectorHelpWindow> m_xHelpWindow; weld::Container* m_pInitialControlParent; ListBoxLines m_aLines; - IPropertyLineListener* m_pLineListener; + OPropertyBrowserController* m_pLineListener; IPropertyControlObserver* m_pControlObserver; css::uno::Reference<css::inspection::XPropertyControl> m_xActiveControl; sal_uInt16 m_nTheNameSize; @@ -84,7 +84,7 @@ public: explicit OBrowserListBox(weld::Builder& rBuilder, weld::Container* pContainer); ~OBrowserListBox(); - void SetListener(IPropertyLineListener* _pListener); + void SetListener(OPropertyBrowserController* _pListener); void SetObserver(IPropertyControlObserver* _pObserver); void EnableHelpSection(bool _bEnable); diff --git a/extensions/source/propctrlr/propcontroller.hxx b/extensions/source/propctrlr/propcontroller.hxx index 1fb562353e0d..baaa7aca1674 100644 --- a/extensions/source/propctrlr/propcontroller.hxx +++ b/extensions/source/propctrlr/propcontroller.hxx @@ -20,7 +20,6 @@ #pragma once #include "composeduiupdate.hxx" -#include "proplinelistener.hxx" #include "propcontrolobserver.hxx" #include "browserview.hxx" @@ -57,15 +56,14 @@ typedef ::cppu::WeakImplHelper<css::lang::XServiceInfo, css::awt::XFocusListener css::inspection::XObjectInspector, css::lang::XInitialization> OPropertyBrowserController_Base; -class OPropertyBrowserController : public ::comphelper::OMutexAndBroadcastHelper, - public OPropertyBrowserController_Base, - public css::inspection::XObjectInspectorUI - // that's intentionally *not* part of the OPropertyBrowserController_Base - // We do not want this to be available in queryInterface, getTypes, and the like. - , - public IPropertyLineListener, - public IPropertyControlObserver, - public IPropertyExistenceCheck +class OPropertyBrowserController + : public ::comphelper::OMutexAndBroadcastHelper, + public OPropertyBrowserController_Base, + public css::inspection::XObjectInspectorUI, + // that's intentionally *not* part of the OPropertyBrowserController_Base + // We do not want this to be available in queryInterface, getTypes, and the like. + public IPropertyControlObserver, + public IPropertyExistenceCheck { private: typedef std::multimap<sal_Int32, css::beans::Property> OrderedPropertyMap; @@ -161,13 +159,12 @@ public: explicit OPropertyBrowserController( const css::uno::Reference<css::uno::XComponentContext>& _rxContext); + void Clicked(const OUString& _rName, bool _bPrimary); + void Commit(const OUString& _rName, const css::uno::Any& _rVal); + protected: virtual ~OPropertyBrowserController() override; - // IPropertyLineListener - virtual void Clicked(const OUString& _rName, bool _bPrimary) override; - virtual void Commit(const OUString& _rName, const css::uno::Any& _rVal) override; - // IPropertyControlObserver virtual void focusGained(const css::uno::Reference<css::inspection::XPropertyControl>& Control) override; diff --git a/extensions/source/propctrlr/propertyeditor.cxx b/extensions/source/propctrlr/propertyeditor.cxx index f6f1c1fe5f29..14a03bdc3a59 100644 --- a/extensions/source/propctrlr/propertyeditor.cxx +++ b/extensions/source/propctrlr/propertyeditor.cxx @@ -184,7 +184,7 @@ namespace pcr rPage.getListBox().SetListener( m_pListener ); } - void OPropertyEditor::SetLineListener(IPropertyLineListener* pListener) + void OPropertyEditor::SetLineListener(OPropertyBrowserController* pListener) { m_pListener = pListener; forEachPage( &OPropertyEditor::setPageLineListener ); diff --git a/extensions/source/propctrlr/propertyeditor.hxx b/extensions/source/propctrlr/propertyeditor.hxx index 07e232a8e88c..2562665cfe31 100644 --- a/extensions/source/propctrlr/propertyeditor.hxx +++ b/extensions/source/propctrlr/propertyeditor.hxx @@ -30,9 +30,9 @@ namespace pcr { - class IPropertyLineListener; class IPropertyControlObserver; struct OLineDescriptor; + class OPropertyBrowserController; //= OPropertyEditor class OPropertyEditor final @@ -53,7 +53,7 @@ namespace pcr // controls initially have this parent before they are moved std::unique_ptr<weld::Container> m_xControlHoldingParent; css::uno::Reference<css::uno::XComponentContext> m_xContext; - IPropertyLineListener* m_pListener; + OPropertyBrowserController* m_pListener; IPropertyControlObserver* m_pObserver; sal_uInt16 m_nNextId; Link<const OUString&,void> m_aPageActivationHandler; @@ -67,7 +67,7 @@ namespace pcr explicit OPropertyEditor(const css::uno::Reference<css::uno::XComponentContext>& rContext, weld::Builder& rBuilder); ~OPropertyEditor(); - void SetLineListener( IPropertyLineListener* ); + void SetLineListener(OPropertyBrowserController*); void SetControlObserver( IPropertyControlObserver* ); void EnableHelpSection( bool _bEnable ); diff --git a/extensions/source/propctrlr/proplinelistener.hxx b/extensions/source/propctrlr/proplinelistener.hxx deleted file mode 100644 index 6931a1f33b17..000000000000 --- a/extensions/source/propctrlr/proplinelistener.hxx +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#pragma once - -#include <rtl/ustring.hxx> -#include <com/sun/star/uno/Any.hxx> - -namespace pcr -{ - - - class IPropertyLineListener - { - public: - virtual void Clicked( const OUString& _rName, bool _bPrimary ) = 0; - virtual void Commit( const OUString& _rName, const css::uno::Any& _rVal ) = 0; - - protected: - ~IPropertyLineListener() {} - }; - - -} // namespace pcr - - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/solenv/clang-format/excludelist b/solenv/clang-format/excludelist index 6709ce404322..146b70619c59 100644 --- a/solenv/clang-format/excludelist +++ b/solenv/clang-format/excludelist @@ -3547,7 +3547,6 @@ extensions/source/propctrlr/propertyhandler.hxx extensions/source/propctrlr/propertyinfo.hxx extensions/source/propctrlr/propeventtranslation.cxx extensions/source/propctrlr/propeventtranslation.hxx -extensions/source/propctrlr/proplinelistener.hxx extensions/source/propctrlr/pushbuttonnavigation.cxx extensions/source/propctrlr/pushbuttonnavigation.hxx extensions/source/propctrlr/sqlcommanddesign.cxx commit daa4a853227460ec74e4d5a6d388ccec90453cd3 Author: Michael Weghorn <[email protected]> AuthorDate: Wed Feb 25 00:49:39 2026 +0100 Commit: Michael Weghorn <[email protected]> CommitDate: Wed Feb 25 09:03:56 2026 +0100 propctrlr: clang-format OPropertyBrowserController code This in particular gets rid of an extra level of indentation. Change-Id: I0712f395ba599a39cc80c5fcd0dc59a669e2ee36 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200278 Reviewed-by: Michael Weghorn <[email protected]> Tested-by: Jenkins diff --git a/extensions/source/propctrlr/propcontroller.cxx b/extensions/source/propctrlr/propcontroller.cxx index 4293b553a03d..f97ac4208e41 100644 --- a/extensions/source/propctrlr/propcontroller.cxx +++ b/extensions/source/propctrlr/propcontroller.cxx @@ -53,1593 +53,1597 @@ namespace pcr { - using namespace ::com::sun::star; - using namespace ::com::sun::star::uno; - using namespace ::com::sun::star::awt; - using namespace ::com::sun::star::beans; - using namespace ::com::sun::star::lang; - using namespace ::com::sun::star::frame; - using namespace ::com::sun::star::util; - using namespace ::com::sun::star::inspection; - using namespace ::com::sun::star::ucb; - using namespace ::comphelper; - - //= OPropertyBrowserController - OPropertyBrowserController::OPropertyBrowserController( const Reference< XComponentContext >& _rxContext ) - :m_xContext(_rxContext) - ,m_aDisposeListeners( m_aMutex ) - ,m_aControlObservers( m_aMutex ) - ,m_bContainerFocusListening( false ) - ,m_bSuspendingPropertyHandlers( false ) - ,m_bConstructed( false ) - ,m_bBindingIntrospectee( false ) - { - } +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::inspection; +using namespace ::com::sun::star::ucb; +using namespace ::comphelper; + +//= OPropertyBrowserController +OPropertyBrowserController::OPropertyBrowserController( + const Reference<XComponentContext>& _rxContext) + : m_xContext(_rxContext) + , m_aDisposeListeners(m_aMutex) + , m_aControlObservers(m_aMutex) + , m_bContainerFocusListening(false) + , m_bSuspendingPropertyHandlers(false) + , m_bConstructed(false) + , m_bBindingIntrospectee(false) +{ +} - OPropertyBrowserController::~OPropertyBrowserController() - { - // stop listening for property changes - acquire(); - stopInspection( true ); - } +OPropertyBrowserController::~OPropertyBrowserController() +{ + // stop listening for property changes + acquire(); + stopInspection(true); +} - IMPLEMENT_FORWARD_REFCOUNT( OPropertyBrowserController, OPropertyBrowserController_Base ) +IMPLEMENT_FORWARD_REFCOUNT(OPropertyBrowserController, OPropertyBrowserController_Base) - Any SAL_CALL OPropertyBrowserController::queryInterface( const Type& _rType ) - { - Any aReturn = OPropertyBrowserController_Base::queryInterface( _rType ); - if ( !aReturn.hasValue() ) - aReturn = ::cppu::queryInterface( - _rType, - static_cast< XObjectInspectorUI* >( this ) - ); - return aReturn; - } +Any SAL_CALL OPropertyBrowserController::queryInterface(const Type& _rType) +{ + Any aReturn = OPropertyBrowserController_Base::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = ::cppu::queryInterface(_rType, static_cast<XObjectInspectorUI*>(this)); + return aReturn; +} +void OPropertyBrowserController::startContainerWindowListening() +{ + if (m_bContainerFocusListening) + return; - void OPropertyBrowserController::startContainerWindowListening() + if (m_xFrame.is()) { - if (m_bContainerFocusListening) - return; - - if (m_xFrame.is()) + Reference<XWindow> xContainerWindow = m_xFrame->getContainerWindow(); + if (xContainerWindow.is()) { - Reference< XWindow > xContainerWindow = m_xFrame->getContainerWindow(); - if (xContainerWindow.is()) - { - xContainerWindow->addFocusListener(this); - m_bContainerFocusListening = true; - } + xContainerWindow->addFocusListener(this); + m_bContainerFocusListening = true; } - - DBG_ASSERT(m_bContainerFocusListening, "OPropertyBrowserController::startContainerWindowListening: unable to start listening (inconsistence)!"); } + DBG_ASSERT(m_bContainerFocusListening, "OPropertyBrowserController::" + "startContainerWindowListening: unable to start " + "listening (inconsistence)!"); +} - void OPropertyBrowserController::stopContainerWindowListening() - { - if (!m_bContainerFocusListening) - return; +void OPropertyBrowserController::stopContainerWindowListening() +{ + if (!m_bContainerFocusListening) + return; - if (m_xFrame.is()) + if (m_xFrame.is()) + { + Reference<XWindow> xContainerWindow = m_xFrame->getContainerWindow(); + if (xContainerWindow.is()) { - Reference< XWindow > xContainerWindow = m_xFrame->getContainerWindow(); - if (xContainerWindow.is()) - { - xContainerWindow->removeFocusListener(this); - m_bContainerFocusListening = false; - } + xContainerWindow->removeFocusListener(this); + m_bContainerFocusListening = false; } - - DBG_ASSERT(!m_bContainerFocusListening, "OPropertyBrowserController::stopContainerWindowListening: unable to stop listening (inconsistence)!"); } + DBG_ASSERT(!m_bContainerFocusListening, "OPropertyBrowserController::" + "stopContainerWindowListening: unable to stop " + "listening (inconsistence)!"); +} - Reference< XObjectInspectorModel > SAL_CALL OPropertyBrowserController::getInspectorModel() - { - return m_xModel; - } - +Reference<XObjectInspectorModel> SAL_CALL OPropertyBrowserController::getInspectorModel() +{ + return m_xModel; +} - void OPropertyBrowserController::impl_initializeView_nothrow() - { - OSL_PRECOND( haveView(), "OPropertyBrowserController::impl_initializeView_nothrow: not to be called when we have no view!" ); - if ( !haveView() ) - return; +void OPropertyBrowserController::impl_initializeView_nothrow() +{ + OSL_PRECOND(haveView(), "OPropertyBrowserController::impl_initializeView_nothrow: not to be " + "called when we have no view!"); + if (!haveView()) + return; - if ( !m_xModel.is() ) - // allowed - return; + if (!m_xModel.is()) + // allowed + return; - try - { - getPropertyBox().EnableHelpSection( m_xModel->getHasHelpSection() ); - } - catch( const Exception& ) - { - DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); - } + try + { + getPropertyBox().EnableHelpSection(m_xModel->getHasHelpSection()); } - - - bool OPropertyBrowserController::impl_isReadOnlyModel_throw() const + catch (const Exception&) { - if ( !m_xModel.is() ) - return false; - - return m_xModel->getIsReadOnly(); + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); } +} + +bool OPropertyBrowserController::impl_isReadOnlyModel_throw() const +{ + if (!m_xModel.is()) + return false; + return m_xModel->getIsReadOnly(); +} - void OPropertyBrowserController::impl_startOrStopModelListening_nothrow( bool _bDoListen ) const +void OPropertyBrowserController::impl_startOrStopModelListening_nothrow(bool _bDoListen) const +{ + try { - try - { - Reference< XPropertySet > xModelProperties( m_xModel, UNO_QUERY ); - if ( !xModelProperties.is() ) - // okay, so the model doesn't want to change its properties - // dynamically - fine with us - return; - - void (SAL_CALL XPropertySet::*pListenerOperation)( const OUString&, const Reference< XPropertyChangeListener >& ) - = _bDoListen ? &XPropertySet::addPropertyChangeListener : &XPropertySet::removePropertyChangeListener; - - (xModelProperties.get()->*pListenerOperation)( - u"IsReadOnly"_ustr, - const_cast< OPropertyBrowserController* >( this ) - ); - } - catch( const Exception& ) - { - DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); - } - } + Reference<XPropertySet> xModelProperties(m_xModel, UNO_QUERY); + if (!xModelProperties.is()) + // okay, so the model doesn't want to change its properties + // dynamically - fine with us + return; + void (SAL_CALL XPropertySet::*pListenerOperation)(const OUString&, + const Reference<XPropertyChangeListener>&) + = _bDoListen ? &XPropertySet::addPropertyChangeListener + : &XPropertySet::removePropertyChangeListener; - void OPropertyBrowserController::impl_bindToNewModel_nothrow( const Reference< XObjectInspectorModel >& _rxInspectorModel ) + (xModelProperties.get()->*pListenerOperation)( + u"IsReadOnly"_ustr, const_cast<OPropertyBrowserController*>(this)); + } + catch (const Exception&) { - impl_startOrStopModelListening_nothrow( false ); - m_xModel = _rxInspectorModel; - impl_startOrStopModelListening_nothrow( true ); + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } +} - // initialize the view, if we already have one - if ( haveView() ) - impl_initializeView_nothrow(); +void OPropertyBrowserController::impl_bindToNewModel_nothrow( + const Reference<XObjectInspectorModel>& _rxInspectorModel) +{ + impl_startOrStopModelListening_nothrow(false); + m_xModel = _rxInspectorModel; + impl_startOrStopModelListening_nothrow(true); - // inspect again, if we already have inspectees - if ( !m_aInspectedObjects.empty() ) - impl_rebindToInspectee_nothrow( std::vector(m_aInspectedObjects) ); - } + // initialize the view, if we already have one + if (haveView()) + impl_initializeView_nothrow(); + + // inspect again, if we already have inspectees + if (!m_aInspectedObjects.empty()) + impl_rebindToInspectee_nothrow(std::vector(m_aInspectedObjects)); +} +void SAL_CALL OPropertyBrowserController::setInspectorModel( + const Reference<XObjectInspectorModel>& _inspectorModel) +{ + ::osl::MutexGuard aGuard(m_aMutex); - void SAL_CALL OPropertyBrowserController::setInspectorModel( const Reference< XObjectInspectorModel >& _inspectorModel ) - { - ::osl::MutexGuard aGuard( m_aMutex ); + if (m_xModel == _inspectorModel) + return; - if ( m_xModel == _inspectorModel ) - return; + impl_bindToNewModel_nothrow(_inspectorModel); +} - impl_bindToNewModel_nothrow( _inspectorModel ); - } +Reference<XObjectInspectorUI> SAL_CALL OPropertyBrowserController::getInspectorUI() +{ + // we're derived from this interface, though we do not expose it in queryInterface and getTypes. + return this; +} +void SAL_CALL OPropertyBrowserController::inspect(const Sequence<Reference<XInterface>>& _rObjects) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard(m_aMutex); - Reference< XObjectInspectorUI > SAL_CALL OPropertyBrowserController::getInspectorUI() + if (m_bSuspendingPropertyHandlers || !suspendAll_nothrow()) { - // we're derived from this interface, though we do not expose it in queryInterface and getTypes. - return this; + // we already are trying to suspend the component (this is somewhere up the stack) + // OR one of our property handlers raised a veto against closing. Well, we *need* to close + // it in order to inspect another object. + throw VetoException(); } + if (m_bBindingIntrospectee) + throw VetoException(); + m_bBindingIntrospectee = true; + impl_rebindToInspectee_nothrow(InterfaceArray(_rObjects.begin(), _rObjects.end())); + m_bBindingIntrospectee = false; +} - void SAL_CALL OPropertyBrowserController::inspect( const Sequence< Reference< XInterface > >& _rObjects ) - { - SolarMutexGuard aSolarGuard; - ::osl::MutexGuard aGuard( m_aMutex ); - - if ( m_bSuspendingPropertyHandlers || !suspendAll_nothrow() ) - { // we already are trying to suspend the component (this is somewhere up the stack) - // OR one of our property handlers raised a veto against closing. Well, we *need* to close - // it in order to inspect another object. - throw VetoException(); - } - if ( m_bBindingIntrospectee ) - throw VetoException(); - - m_bBindingIntrospectee = true; - impl_rebindToInspectee_nothrow( InterfaceArray( _rObjects.begin(), _rObjects.end() ) ); - m_bBindingIntrospectee = false; +Reference<XDispatch> SAL_CALL OPropertyBrowserController::queryDispatch( + const URL& /*URL*/, const OUString& /*TargetFrameName*/, ::sal_Int32 /*SearchFlags*/) +{ + // we don't have any dispatches at all, right now + return Reference<XDispatch>(); +} - } +Sequence<Reference<XDispatch>> SAL_CALL +OPropertyBrowserController::queryDispatches(const Sequence<DispatchDescriptor>& Requests) +{ + Sequence<Reference<XDispatch>> aReturn(Requests.getLength()); + std::transform(Requests.begin(), Requests.end(), aReturn.getArray(), + [this](const DispatchDescriptor& d) { + return queryDispatch(d.FeatureURL, d.FrameName, d.SearchFlags); + }); + return aReturn; +} +void SAL_CALL OPropertyBrowserController::initialize(const Sequence<Any>& _arguments) +{ + if (m_bConstructed) + throw AlreadyInitializedException(); - Reference< XDispatch > SAL_CALL OPropertyBrowserController::queryDispatch( const URL& /*URL*/, const OUString& /*TargetFrameName*/, ::sal_Int32 /*SearchFlags*/ ) + if (!_arguments.hasElements()) { - // we don't have any dispatches at all, right now - return Reference< XDispatch >(); + // constructor: "createDefault()" + m_bConstructed = true; + return; } - - Sequence< Reference< XDispatch > > SAL_CALL OPropertyBrowserController::queryDispatches( const Sequence< DispatchDescriptor >& Requests ) + Reference<XObjectInspectorModel> xModel; + if (_arguments.size() == 1) { - Sequence<Reference<XDispatch>> aReturn(Requests.getLength()); - std::transform(Requests.begin(), Requests.end(), aReturn.getArray(), - [this](const DispatchDescriptor& d) - { return queryDispatch(d.FeatureURL, d.FrameName, d.SearchFlags); }); - return aReturn; + // constructor: "createWithModel( XObjectInspectorModel )" + if (!(_arguments[0] >>= xModel)) + throw IllegalArgumentException(OUString(), *this, 0); + createWithModel(xModel); + return; } + throw IllegalArgumentException(OUString(), *this, 0); +} - void SAL_CALL OPropertyBrowserController::initialize( const Sequence< Any >& _arguments ) +void OPropertyBrowserController::createWithModel(const Reference<XObjectInspectorModel>& _rxModel) +{ + osl_atomic_increment(&m_refCount); { - if ( m_bConstructed ) - throw AlreadyInitializedException(); - - if (!_arguments.hasElements()) - { // constructor: "createDefault()" - m_bConstructed = true; - return; - } - - Reference< XObjectInspectorModel > xModel; - if (_arguments.size() == 1) - { // constructor: "createWithModel( XObjectInspectorModel )" - if (!(_arguments[0] >>= xModel)) - throw IllegalArgumentException( OUString(), *this, 0 ); - createWithModel( xModel ); - return; - } - - throw IllegalArgumentException( OUString(), *this, 0 ); + setInspectorModel(_rxModel); } + osl_atomic_decrement(&m_refCount); + m_bConstructed = true; +} - void OPropertyBrowserController::createWithModel( const Reference< XObjectInspectorModel >& _rxModel ) - { - osl_atomic_increment( &m_refCount ); - { - setInspectorModel( _rxModel ); - } - osl_atomic_decrement( &m_refCount ); - - m_bConstructed = true; - } - +void SAL_CALL OPropertyBrowserController::attachFrame(const Reference<XFrame>& _rxFrame) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard(m_aMutex); - void SAL_CALL OPropertyBrowserController::attachFrame( const Reference< XFrame >& _rxFrame ) - { - SolarMutexGuard aSolarGuard; - ::osl::MutexGuard aGuard( m_aMutex ); + if (_rxFrame.is() && haveView()) + throw RuntimeException(u"Unable to attach to a second frame."_ustr, *this); - if (_rxFrame.is() && haveView()) - throw RuntimeException(u"Unable to attach to a second frame."_ustr,*this); + // revoke as focus listener from the old container window + stopContainerWindowListening(); - // revoke as focus listener from the old container window - stopContainerWindowListening(); + m_xPropView.reset(); + m_xBuilder.reset(); - m_xPropView.reset(); - m_xBuilder.reset(); + m_xFrame = _rxFrame; + if (!m_xFrame.is()) + return; - m_xFrame = _rxFrame; - if (!m_xFrame.is()) - return; + // TODO: this construction perhaps should be done outside. Don't know the exact meaning of attachFrame. + // Maybe it is intended to only announce the frame to the controller, and the instance doing this + // announcement is responsible for calling setComponent, too. + Reference<XWindow> xContainerWindow = m_xFrame->getContainerWindow(); - // TODO: this construction perhaps should be done outside. Don't know the exact meaning of attachFrame. - // Maybe it is intended to only announce the frame to the controller, and the instance doing this - // announcement is responsible for calling setComponent, too. - Reference<XWindow> xContainerWindow = m_xFrame->getContainerWindow(); + OUString sUIFile(u"modules/spropctrlr/ui/formproperties.ui"_ustr); + std::unique_ptr<weld::Builder> xBuilder; - OUString sUIFile(u"modules/spropctrlr/ui/formproperties.ui"_ustr); - std::unique_ptr<weld::Builder> xBuilder; + if (weld::TransportAsXWindow* pTunnel + = dynamic_cast<weld::TransportAsXWindow*>(xContainerWindow.get())) + { + xBuilder = Application::CreateBuilder(pTunnel->getWidget(), sUIFile); + } + else + { + VclPtr<vcl::Window> pParentWin = VCLUnoHelper::GetWindow(xContainerWindow); + if (!pParentWin) + throw RuntimeException( + u"The frame is invalid. Unable to extract the container window."_ustr, *this); + xBuilder = Application::CreateInterimBuilder(pParentWin, sUIFile, true); + } - if (weld::TransportAsXWindow* pTunnel = dynamic_cast<weld::TransportAsXWindow*>(xContainerWindow.get())) - { - xBuilder = Application::CreateBuilder(pTunnel->getWidget(), sUIFile); - } - else - { - VclPtr<vcl::Window> pParentWin = VCLUnoHelper::GetWindow(xContainerWindow); - if (!pParentWin) - throw RuntimeException(u"The frame is invalid. Unable to extract the container window."_ustr,*this); - xBuilder = Application::CreateInterimBuilder(pParentWin, sUIFile, true); - } + Construct(xContainerWindow, std::move(xBuilder)); - Construct(xContainerWindow, std::move(xBuilder)); + startContainerWindowListening(); - startContainerWindowListening(); + UpdateUI(); +} - UpdateUI(); - } +sal_Bool SAL_CALL OPropertyBrowserController::attachModel(const Reference<XModel>& _rxModel) +{ + Reference<XObjectInspectorModel> xModel(_rxModel, UNO_QUERY); + if (!xModel.is()) + return false; - sal_Bool SAL_CALL OPropertyBrowserController::attachModel( const Reference< XModel >& _rxModel ) - { - Reference< XObjectInspectorModel > xModel( _rxModel, UNO_QUERY ); - if ( !xModel.is() ) - return false; + setInspectorModel(xModel); + return getInspectorModel() == _rxModel; +} - setInspectorModel( xModel ); - return getInspectorModel() == _rxModel; - } +bool OPropertyBrowserController::suspendAll_nothrow() +{ + // if there is a handle inside its "onInteractivePropertySelection" method, + // then veto + // Normally, we could expect every handler to do this itself, but being + // realistic, it's safer to handle this here in general. + if (m_xInteractiveHandler.is()) + return false; + m_bSuspendingPropertyHandlers = true; + bool bHandlerVeto = !suspendPropertyHandlers_nothrow(true); + m_bSuspendingPropertyHandlers = false; + return !bHandlerVeto; +} - bool OPropertyBrowserController::suspendAll_nothrow() +bool OPropertyBrowserController::suspendPropertyHandlers_nothrow(bool _bSuspend) +{ + PropertyHandlerArray aAllHandlers; // will contain every handler exactly once + for (auto const& propertyHandler : m_aPropertyHandlers) { - // if there is a handle inside its "onInteractivePropertySelection" method, - // then veto - // Normally, we could expect every handler to do this itself, but being - // realistic, it's safer to handle this here in general. - if ( m_xInteractiveHandler.is() ) - return false; - - m_bSuspendingPropertyHandlers = true; - bool bHandlerVeto = !suspendPropertyHandlers_nothrow( true ); - m_bSuspendingPropertyHandlers = false; - return !bHandlerVeto; + if (std::find(aAllHandlers.begin(), aAllHandlers.end(), propertyHandler.second) + != aAllHandlers.end()) + // already visited this particular handler (m_aPropertyHandlers usually contains + // the same handler more than once) + continue; + aAllHandlers.push_back(propertyHandler.second); } - - bool OPropertyBrowserController::suspendPropertyHandlers_nothrow( bool _bSuspend ) + for (auto const& handler : aAllHandlers) { - PropertyHandlerArray aAllHandlers; // will contain every handler exactly once - for (auto const& propertyHandler : m_aPropertyHandlers) + try { - if ( std::find( aAllHandlers.begin(), aAllHandlers.end(), propertyHandler.second ) != aAllHandlers.end() ) - // already visited this particular handler (m_aPropertyHandlers usually contains - // the same handler more than once) - continue; - aAllHandlers.push_back(propertyHandler.second); + if (!handler->suspend(_bSuspend)) + if (_bSuspend) + // if we're not suspending, but reactivating, ignore the error + return false; } - - for (auto const& handler : aAllHandlers) + catch (const Exception&) { - try - { - if ( !handler->suspend( _bSuspend ) ) - if ( _bSuspend ) - // if we're not suspending, but reactivating, ignore the error - return false; - } - catch( const Exception& ) - { - TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "OPropertyBrowserController::suspendPropertyHandlers_nothrow" ); - } + TOOLS_WARN_EXCEPTION("extensions.propctrlr", + "OPropertyBrowserController::suspendPropertyHandlers_nothrow"); } - return true; } + return true; +} +sal_Bool SAL_CALL OPropertyBrowserController::suspend(sal_Bool _bSuspend) +{ + ::osl::MutexGuard aGuard(m_aMutex); + OSL_ENSURE(haveView(), "OPropertyBrowserController::suspend: don't have a view anymore!"); - sal_Bool SAL_CALL OPropertyBrowserController::suspend( sal_Bool _bSuspend ) + if (!_bSuspend) { - ::osl::MutexGuard aGuard( m_aMutex ); - OSL_ENSURE( haveView(), "OPropertyBrowserController::suspend: don't have a view anymore!" ); - - if ( !_bSuspend ) - { // this means a "suspend" is to be "revoked" - suspendPropertyHandlers_nothrow( false ); - // we ourself cannot revoke our suspend - return false; - } + // this means a "suspend" is to be "revoked" + suspendPropertyHandlers_nothrow(false); + // we ourself cannot revoke our suspend + return false; + } - if ( !suspendAll_nothrow() ) - return false; + if (!suspendAll_nothrow()) + return false; - // commit the editor's content - if ( haveView() ) - getPropertyBox().CommitModified(); + // commit the editor's content + if (haveView()) + getPropertyBox().CommitModified(); - // stop listening - stopContainerWindowListening(); + // stop listening + stopContainerWindowListening(); - // outta here - return true; - } + // outta here + return true; +} +Any SAL_CALL OPropertyBrowserController::getViewData() { return Any(m_sPageSelection); } - Any SAL_CALL OPropertyBrowserController::getViewData( ) +void SAL_CALL OPropertyBrowserController::restoreViewData(const Any& Data) +{ + OUString sPageSelection; + if ((Data >>= sPageSelection) && !sPageSelection.isEmpty()) { - return Any( m_sPageSelection ); + m_sPageSelection = sPageSelection; + selectPageFromViewData(); } +} +Reference<XModel> SAL_CALL OPropertyBrowserController::getModel() +{ + // have no model + return Reference<XModel>(); +} - void SAL_CALL OPropertyBrowserController::restoreViewData( const Any& Data ) - { - OUString sPageSelection; - if ( ( Data >>= sPageSelection ) && !sPageSelection.isEmpty() ) - { - m_sPageSelection = sPageSelection; - selectPageFromViewData(); - } - } - - Reference< XModel > SAL_CALL OPropertyBrowserController::getModel( ) - { - // have no model - return Reference< XModel >(); - } +Reference<XFrame> SAL_CALL OPropertyBrowserController::getFrame() { return m_xFrame; } - Reference< XFrame > SAL_CALL OPropertyBrowserController::getFrame( ) - { - return m_xFrame; - } +void SAL_CALL OPropertyBrowserController::dispose() +{ + SolarMutexGuard aSolarGuard; - void SAL_CALL OPropertyBrowserController::dispose() - { - SolarMutexGuard aSolarGuard; + // stop inspecting the current object + stopInspection(false); - // stop inspecting the current object - stopInspection( false ); + // say our dispose listeners goodbye + css::lang::EventObject aEvt; + aEvt.Source = static_cast<::cppu::OWeakObject*>(this); + m_aDisposeListeners.disposeAndClear(aEvt); + m_aControlObservers.disposeAndClear(aEvt); - // say our dispose listeners goodbye - css::lang::EventObject aEvt; - aEvt.Source = static_cast< ::cppu::OWeakObject* >(this); - m_aDisposeListeners.disposeAndClear(aEvt); - m_aControlObservers.disposeAndClear(aEvt); + m_xPropView.reset(); + m_xBuilder.reset(); - m_xPropView.reset(); - m_xBuilder.reset(); + if (m_xView.is()) + m_xView->removeEventListener(static_cast<XPropertyChangeListener*>(this)); + m_xView.clear(); - if ( m_xView.is() ) - m_xView->removeEventListener( static_cast< XPropertyChangeListener* >( this ) ); - m_xView.clear( ); + m_aInspectedObjects.clear(); + impl_bindToNewModel_nothrow(nullptr); + m_xModel.clear(); + m_xInteractiveHandler.clear(); + m_xFrame.clear(); +} - m_aInspectedObjects.clear(); - impl_bindToNewModel_nothrow( nullptr ); - m_xModel.clear(); - m_xInteractiveHandler.clear(); - m_xFrame.clear(); - } +void SAL_CALL +OPropertyBrowserController::addEventListener(const Reference<XEventListener>& _rxListener) +{ + m_aDisposeListeners.addInterface(_rxListener); +} - void SAL_CALL OPropertyBrowserController::addEventListener( const Reference< XEventListener >& _rxListener ) - { - m_aDisposeListeners.addInterface(_rxListener); - } +void SAL_CALL +OPropertyBrowserController::removeEventListener(const Reference<XEventListener>& _rxListener) +{ + m_aDisposeListeners.removeInterface(_rxListener); +} - void SAL_CALL OPropertyBrowserController::removeEventListener( const Reference< XEventListener >& _rxListener ) - { - m_aDisposeListeners.removeInterface(_rxListener); - } +OUString SAL_CALL OPropertyBrowserController::getImplementationName() +{ + return u"org.openoffice.comp.extensions.ObjectInspector"_ustr; +} - OUString SAL_CALL OPropertyBrowserController::getImplementationName( ) - { - return u"org.openoffice.comp.extensions.ObjectInspector"_ustr; - } +sal_Bool SAL_CALL OPropertyBrowserController::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} - sal_Bool SAL_CALL OPropertyBrowserController::supportsService( const OUString& ServiceName ) - { - return cppu::supportsService(this, ServiceName); - } +Sequence<OUString> SAL_CALL OPropertyBrowserController::getSupportedServiceNames() +{ + return { u"com.sun.star.inspection.ObjectInspector"_ustr }; +} +void SAL_CALL OPropertyBrowserController::focusGained(const FocusEvent& _rSource) +{ + Reference<XWindow> xSourceWindow(_rSource.Source, UNO_QUERY); + Reference<XWindow> xContainerWindow; + if (m_xFrame.is()) + xContainerWindow = m_xFrame->getContainerWindow(); - Sequence< OUString > SAL_CALL OPropertyBrowserController::getSupportedServiceNames( ) + if (xContainerWindow.get() == xSourceWindow.get()) { - return { u"com.sun.star.inspection.ObjectInspector"_ustr }; + // our container window got the focus + if (haveView()) + getPropertyBox().GrabFocus(); } +} +void SAL_CALL OPropertyBrowserController::focusLost(const FocusEvent& /*_rSource*/) +{ + // not interested in +} - void SAL_CALL OPropertyBrowserController::focusGained( const FocusEvent& _rSource ) +void SAL_CALL OPropertyBrowserController::disposing(const EventObject& _rSource) +{ + if (m_xView.is() && (m_xView == _rSource.Source)) { - Reference< XWindow > xSourceWindow(_rSource.Source, UNO_QUERY); - Reference< XWindow > xContainerWindow; - if (m_xFrame.is()) - xContainerWindow = m_xFrame->getContainerWindow(); - - if ( xContainerWindow.get() == xSourceWindow.get() ) - { // our container window got the focus - if ( haveView() ) - getPropertyBox().GrabFocus(); - } + m_xView = nullptr; + m_xPropView.reset(); + m_xBuilder.reset(); } + auto it = std::find_if( + m_aInspectedObjects.begin(), m_aInspectedObjects.end(), + [&_rSource](const InterfaceArray::value_type& rxObj) { return rxObj == _rSource.Source; }); + if (it != m_aInspectedObjects.end()) + m_aInspectedObjects.erase(it); +} - void SAL_CALL OPropertyBrowserController::focusLost( const FocusEvent& /*_rSource*/ ) - { - // not interested in - } +IMPL_LINK_NOARG(OPropertyBrowserController, OnPageActivation, LinkParamNone*, void) +{ + updateViewDataFromActivePage(); +} + +void OPropertyBrowserController::updateViewDataFromActivePage() +{ + if (!haveView()) + return; + OUString sOldSelection = m_sPageSelection; + m_sPageSelection.clear(); - void SAL_CALL OPropertyBrowserController::disposing( const EventObject& _rSource ) + const sal_uInt16 nCurrentPage = m_xPropView->getActivePage(); + if (sal_uInt16(-1) != nCurrentPage) { - if ( m_xView.is() && ( m_xView == _rSource.Source ) ) + for (auto const& pageId : m_aPageIds) { - m_xView = nullptr; - m_xPropView.reset(); - m_xBuilder.reset(); + if (nCurrentPage == pageId.second) + { + m_sPageSelection = pageId.first; + break; + } } - - auto it = std::find_if(m_aInspectedObjects.begin(), m_aInspectedObjects.end(), - [&_rSource](const InterfaceArray::value_type& rxObj) { return rxObj == _rSource.Source; }); - if (it != m_aInspectedObjects.end()) - m_aInspectedObjects.erase(it); } + if (!m_sPageSelection.isEmpty()) + m_sLastValidPageSelection = m_sPageSelection; + else if (!sOldSelection.isEmpty()) + m_sLastValidPageSelection = sOldSelection; +} - IMPL_LINK_NOARG(OPropertyBrowserController, OnPageActivation, LinkParamNone*, void) - { - updateViewDataFromActivePage(); - } +sal_uInt16 +OPropertyBrowserController::impl_getPageIdForCategory_nothrow(const OUString& _rCategoryName) const +{ + sal_uInt16 nPageId = sal_uInt16(-1); + HashString2Int16::const_iterator pagePos = m_aPageIds.find(_rCategoryName); + if (pagePos != m_aPageIds.end()) + nPageId = pagePos->second; + return nPageId; +} +void OPropertyBrowserController::selectPageFromViewData() +{ + sal_uInt16 nNewPage = impl_getPageIdForCategory_nothrow(m_sPageSelection); - void OPropertyBrowserController::updateViewDataFromActivePage() - { - if (!haveView()) - return; + if (haveView() && (nNewPage != sal_uInt16(-1))) + m_xPropView->activatePage(nNewPage); - OUString sOldSelection = m_sPageSelection; - m_sPageSelection.clear(); + // just in case ... + updateViewDataFromActivePage(); +} - const sal_uInt16 nCurrentPage = m_xPropView->getActivePage(); - if ( sal_uInt16(-1) != nCurrentPage ) - { - for (auto const& pageId : m_aPageIds) - { - if ( nCurrentPage == pageId.second ) - { - m_sPageSelection = pageId.first; - break; - } - } - } +void OPropertyBrowserController::Construct(const Reference<XWindow>& rContainerWindow, + std::unique_ptr<weld::Builder> xBuilder) +{ + DBG_ASSERT(!haveView(), "OPropertyBrowserController::Construct: already have a view!"); + assert(xBuilder && "OPropertyBrowserController::Construct: invalid parent window!"); - if ( !m_sPageSelection.isEmpty() ) - m_sLastValidPageSelection = m_sPageSelection; - else if ( !sOldSelection.isEmpty() ) - m_sLastValidPageSelection = sOldSelection; - } + m_xBuilder = std::move(xBuilder); + + m_xPropView.reset(new OPropertyBrowserView(m_xContext, *m_xBuilder)); + m_xPropView->setPageActivationHandler(LINK(this, OPropertyBrowserController, OnPageActivation)); + // add as dispose listener for our view. The view is disposed by the frame we're plugged into, + // and this disposal _deletes_ the view, so it would be deadly if we use our m_xPropView member + // after that + m_xView = rContainerWindow; + if (m_xView.is()) + m_xView->addEventListener(static_cast<XPropertyChangeListener*>(this)); + + getPropertyBox().SetLineListener(this); + getPropertyBox().SetControlObserver(this); + impl_initializeView_nothrow(); +} - sal_uInt16 OPropertyBrowserController::impl_getPageIdForCategory_nothrow( const OUString& _rCategoryName ) const +void SAL_CALL OPropertyBrowserController::propertyChange(const PropertyChangeEvent& _rEvent) +{ + if (_rEvent.Source == m_xModel) { - sal_uInt16 nPageId = sal_uInt16(-1); - HashString2Int16::const_iterator pagePos = m_aPageIds.find( _rCategoryName ); - if ( pagePos != m_aPageIds.end() ) - nPageId = pagePos->second; - return nPageId; + if (_rEvent.PropertyName == "IsReadOnly") + // this is a huge cudgel, admitted. + // The problem is that in case we were previously read-only, all our controls + // were created read-only, too. We cannot simply switch them to not-read-only. + // Even if they had an API for this, we do not know whether they were + // originally created read-only, or if they are read-only just because + // the model was. + impl_rebindToInspectee_nothrow(std::vector(m_aInspectedObjects)); + return; } - void OPropertyBrowserController::selectPageFromViewData() + if (m_sCommittingProperty == _rEvent.PropertyName) + return; + + if (!haveView()) + return; + + Any aNewValue(_rEvent.NewValue); + if (impl_hasPropertyHandlerFor_nothrow(_rEvent.PropertyName)) { - sal_uInt16 nNewPage = impl_getPageIdForCategory_nothrow( m_sPageSelection ); + // forward the new value to the property box, to reflect the change in the UI + aNewValue = impl_getPropertyValue_throw(_rEvent.PropertyName); - if ( haveView() && ( nNewPage != sal_uInt16(-1) ) ) - m_xPropView->activatePage( nNewPage ); + // check whether the state is ambiguous. This is interesting in case we display the properties + // for multiple objects at once: In this case, we'll get a notification from one of the objects, + // but need to care for the "composed" value, which can be "ambiguous". + PropertyHandlerRef xHandler(impl_getHandlerForProperty_throw(_rEvent.PropertyName), + UNO_SET_THROW); + PropertyState ePropertyState(xHandler->getPropertyState(_rEvent.PropertyName)); + bool bAmbiguousValue = (PropertyState_AMBIGUOUS_VALUE == ePropertyState); - // just in case ... - updateViewDataFromActivePage(); + getPropertyBox().SetPropertyValue(_rEvent.PropertyName, aNewValue, bAmbiguousValue); } - void OPropertyBrowserController::Construct(const Reference<XWindow>& rContainerWindow, std::unique_ptr<weld::Builder> xBuilder) - { - DBG_ASSERT(!haveView(), "OPropertyBrowserController::Construct: already have a view!"); - assert(xBuilder && "OPropertyBrowserController::Construct: invalid parent window!"); - - m_xBuilder = std::move(xBuilder); + // if it's an actuating property, then update the UI for any dependent + // properties + if (impl_isActuatingProperty_nothrow(_rEvent.PropertyName)) + impl_broadcastPropertyChange_nothrow(_rEvent.PropertyName, aNewValue, _rEvent.OldValue, + false); +} - m_xPropView.reset(new OPropertyBrowserView(m_xContext, *m_xBuilder)); - m_xPropView->setPageActivationHandler(LINK(this, OPropertyBrowserController, OnPageActivation)); +Reference<XPropertyControl> SAL_CALL +OPropertyBrowserController::createPropertyControl(::sal_Int16 ControlType, sal_Bool bCreateReadOnly) +{ + ::osl::MutexGuard aGuard(m_aMutex); - // add as dispose listener for our view. The view is disposed by the frame we're plugged into, - // and this disposal _deletes_ the view, so it would be deadly if we use our m_xPropView member - // after that - m_xView = rContainerWindow; - if (m_xView.is()) - m_xView->addEventListener( static_cast< XPropertyChangeListener* >( this ) ); + Reference<XPropertyControl> xControl; - getPropertyBox().SetLineListener(this); - getPropertyBox().SetControlObserver(this); - impl_initializeView_nothrow(); - } + // read-only-ness + bCreateReadOnly |= impl_isReadOnlyModel_throw() ? 1 : 0; - void SAL_CALL OPropertyBrowserController::propertyChange( const PropertyChangeEvent& _rEvent ) + switch (ControlType) { - if ( _rEvent.Source == m_xModel ) + case PropertyControlType::MultiLineTextField: + case PropertyControlType::StringListField: { - if ( _rEvent.PropertyName == "IsReadOnly" ) - // this is a huge cudgel, admitted. - // The problem is that in case we were previously read-only, all our controls - // were created read-only, too. We cannot simply switch them to not-read-only. - // Even if they had an API for this, we do not know whether they were - // originally created read-only, or if they are read-only just because - // the model was. - impl_rebindToInspectee_nothrow( std::vector(m_aInspectedObjects) ); - return; + bool bMultiLineTextField = ControlType == PropertyControlType::MultiLineTextField; + std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder( + u"modules/spropctrlr/ui/multiline.ui"_ustr, m_xContext)); + auto pContainer = xBuilder->weld_container(u"multiline"_ustr); + rtl::Reference<OMultilineEditControl> pControl = new OMultilineEditControl( + std::move(pContainer), std::move(xBuilder), + bMultiLineTextField ? eMultiLineText : eStringList, bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; } - if ( m_sCommittingProperty == _rEvent.PropertyName ) - return; - - if ( !haveView() ) - return; - - Any aNewValue( _rEvent.NewValue ); - if ( impl_hasPropertyHandlerFor_nothrow( _rEvent.PropertyName ) ) + case PropertyControlType::ListBox: { - // forward the new value to the property box, to reflect the change in the UI - aNewValue = impl_getPropertyValue_throw( _rEvent.PropertyName ); - - // check whether the state is ambiguous. This is interesting in case we display the properties - // for multiple objects at once: In this case, we'll get a notification from one of the objects, - // but need to care for the "composed" value, which can be "ambiguous". - PropertyHandlerRef xHandler( impl_getHandlerForProperty_throw( _rEvent.PropertyName ), UNO_SET_THROW ); - PropertyState ePropertyState( xHandler->getPropertyState( _rEvent.PropertyName ) ); - bool bAmbiguousValue = ( PropertyState_AMBIGUOUS_VALUE == ePropertyState ); - - getPropertyBox().SetPropertyValue( _rEvent.PropertyName, aNewValue, bAmbiguousValue ); + std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder( + u"modules/spropctrlr/ui/listbox.ui"_ustr, m_xContext)); + auto pComboBox = xBuilder->weld_combo_box(u"listbox"_ustr); + rtl::Reference<OListboxControl> pControl + = new OListboxControl(std::move(pComboBox), std::move(xBuilder), bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; } - // if it's an actuating property, then update the UI for any dependent - // properties - if ( impl_isActuatingProperty_nothrow( _rEvent.PropertyName ) ) - impl_broadcastPropertyChange_nothrow( _rEvent.PropertyName, aNewValue, _rEvent.OldValue, false ); - } - - Reference< XPropertyControl > SAL_CALL OPropertyBrowserController::createPropertyControl( ::sal_Int16 ControlType, sal_Bool bCreateReadOnly ) - { - ::osl::MutexGuard aGuard( m_aMutex ); - - Reference< XPropertyControl > xControl; - - // read-only-ness - bCreateReadOnly |= impl_isReadOnlyModel_throw() ? 1 : 0; - - switch ( ControlType ) + case PropertyControlType::ComboBox: { - case PropertyControlType::MultiLineTextField: - case PropertyControlType::StringListField: - { - bool bMultiLineTextField = ControlType == PropertyControlType::MultiLineTextField; - std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder(u"modules/spropctrlr/ui/multiline.ui"_ustr, m_xContext)); - auto pContainer = xBuilder->weld_container(u"multiline"_ustr); - rtl::Reference<OMultilineEditControl> pControl = new OMultilineEditControl(std::move(pContainer), std::move(xBuilder), - bMultiLineTextField ? eMultiLineText : eStringList, bCreateReadOnly); - pControl->SetModifyHandler(); - xControl = pControl; - break; - } - - case PropertyControlType::ListBox: - { - std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder(u"modules/spropctrlr/ui/listbox.ui"_ustr, m_xContext)); - auto pComboBox = xBuilder->weld_combo_box(u"listbox"_ustr); - rtl::Reference<OListboxControl> pControl = new OListboxControl(std::move(pComboBox), std::move(xBuilder), bCreateReadOnly); - pControl->SetModifyHandler(); - xControl = pControl; - break; - } - - case PropertyControlType::ComboBox: - { - std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder(u"modules/spropctrlr/ui/combobox.ui"_ustr, m_xContext)); - auto pComboBox = xBuilder->weld_combo_box(u"combobox"_ustr); - rtl::Reference<OComboboxControl> pControl = new OComboboxControl(std::move(pComboBox), std::move(xBuilder), bCreateReadOnly); - pControl->SetModifyHandler(); - xControl = pControl; - break; - } - - case PropertyControlType::TextField: - case PropertyControlType::CharacterField: - { - bool bCharacterField = ControlType == PropertyControlType::CharacterField; - std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder(u"modules/spropctrlr/ui/textfield.ui"_ustr, m_xContext)); - auto pEntry = xBuilder->weld_entry(u"textfield"_ustr); - rtl::Reference<OEditControl> pControl = new OEditControl(std::move(pEntry), std::move(xBuilder), bCharacterField, bCreateReadOnly); - pControl->SetModifyHandler(); - xControl = pControl; - break; - } - - case PropertyControlType::NumericField: - { - std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder(u"modules/spropctrlr/ui/numericfield.ui"_ustr, m_xContext)); - auto pSpinButton = xBuilder->weld_metric_spin_button(u"numericfield"_ustr, FieldUnit::NONE); - rtl::Reference<ONumericControl> pControl = new ONumericControl(std::move(pSpinButton), std::move(xBuilder), bCreateReadOnly); - pControl->SetModifyHandler(); - xControl = pControl; - break; - } - - case PropertyControlType::DateTimeField: - { - std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder(u"modules/spropctrlr/ui/datetimefield.ui"_ustr, m_xContext)); - auto pContainer = xBuilder->weld_container(u"datetimefield"_ustr); - rtl::Reference<ODateTimeControl> pControl = new ODateTimeControl(std::move(pContainer), std::move(xBuilder), bCreateReadOnly); - pControl->SetModifyHandler(); - xControl = pControl; - break; - } - - case PropertyControlType::DateField: - { - std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder(u"modules/spropctrlr/ui/datefield.ui"_ustr, m_xContext)); - auto pContainer = xBuilder->weld_container(u"datefield"_ustr); - rtl::Reference<ODateControl> pControl = new ODateControl(std::move(pContainer), std::move(xBuilder), bCreateReadOnly); - pControl->SetModifyHandler(); - xControl = pControl; - break; - } - - case PropertyControlType::TimeField: - { - std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder(u"modules/spropctrlr/ui/timefield.ui"_ustr, m_xContext)); - auto pTimeSpinButton = xBuilder->weld_formatted_spin_button(u"timefield"_ustr); - rtl::Reference<OTimeControl> pControl = new OTimeControl(std::move(pTimeSpinButton), std::move(xBuilder), bCreateReadOnly); - pControl->SetModifyHandler(); - xControl = pControl; - break; - } - - case PropertyControlType::ColorListBox: - { - auto lambda = [this]{ return PropertyHandlerHelper::getDialogParentFrame(m_xContext); }; - std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder(u"modules/spropctrlr/ui/colorlistbox.ui"_ustr, m_xContext)); - auto pMenuButton = xBuilder->weld_menu_button(u"colorlistbox"_ustr); - rtl::Reference<OColorControl> pControl = new OColorControl(std::make_unique<ColorListBox>(std::move(pMenuButton), lambda), std::move(xBuilder), bCreateReadOnly); - pControl->SetModifyHandler(); - xControl = pControl; - break; - } - - case PropertyControlType::HyperlinkField: - { - std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder(u"modules/spropctrlr/ui/hyperlinkfield.ui"_ustr, m_xContext)); - auto pContainer = xBuilder->weld_container(u"hyperlinkfield"_ustr); - rtl::Reference<OHyperlinkControl> pControl = new OHyperlinkControl(std::move(pContainer), std::move(xBuilder), bCreateReadOnly); - pControl->SetModifyHandler(); - xControl = pControl; - break; - } - - default: - throw IllegalArgumentException( OUString(), *this, 1 ); + std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder( + u"modules/spropctrlr/ui/combobox.ui"_ustr, m_xContext)); + auto pComboBox = xBuilder->weld_combo_box(u"combobox"_ustr); + rtl::Reference<OComboboxControl> pControl + = new OComboboxControl(std::move(pComboBox), std::move(xBuilder), bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; } - return xControl; - } - - - void OPropertyBrowserController::impl_toggleInspecteeListening_nothrow( bool _bOn ) - { - for (auto const& inspectedObject : m_aInspectedObjects) + case PropertyControlType::TextField: + case PropertyControlType::CharacterField: { - try - { - Reference< XComponent > xComp( inspectedObject, UNO_QUERY ); - if ( xComp.is() ) - { - if ( _bOn ) - xComp->addEventListener( static_cast< XPropertyChangeListener* >( this ) ); - else - xComp->removeEventListener( static_cast< XPropertyChangeListener* >( this ) ); - } - } - catch( const Exception& ) - { - DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); - } + bool bCharacterField = ControlType == PropertyControlType::CharacterField; + std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder( + u"modules/spropctrlr/ui/textfield.ui"_ustr, m_xContext)); + auto pEntry = xBuilder->weld_entry(u"textfield"_ustr); + rtl::Reference<OEditControl> pControl = new OEditControl( + std::move(pEntry), std::move(xBuilder), bCharacterField, bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; } - } - - void OPropertyBrowserController::stopInspection( bool _bCommitModified ) - { - if ( haveView() ) + case PropertyControlType::NumericField: { - if ( _bCommitModified ) - // commit the editor's content - getPropertyBox().CommitModified(); - - // hide the property box so that it does not flicker - getPropertyBox().Hide(); - - // clear the property box - getPropertyBox().ClearAll(); + std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder( + u"modules/spropctrlr/ui/numericfield.ui"_ustr, m_xContext)); + auto pSpinButton + = xBuilder->weld_metric_spin_button(u"numericfield"_ustr, FieldUnit::NONE); + rtl::Reference<ONumericControl> pControl + = new ONumericControl(std::move(pSpinButton), std::move(xBuilder), bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; } - // destroy the view first - if ( haveView() ) + case PropertyControlType::DateTimeField: { - // remove the pages - for (auto const& pageId : m_aPageIds) - getPropertyBox().RemovePage( pageId.second ); - clearContainer( m_aPageIds ); + std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder( + u"modules/spropctrlr/ui/datetimefield.ui"_ustr, m_xContext)); + auto pContainer = xBuilder->weld_container(u"datetimefield"_ustr); + rtl::Reference<ODateTimeControl> pControl + = new ODateTimeControl(std::move(pContainer), std::move(xBuilder), bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; } - clearContainer( m_aProperties ); - - // de-register as dispose-listener from our inspected objects - impl_toggleInspecteeListening_nothrow( false ); - - // handlers are obsolete, so is our "composer" for their UI requests - if (m_pUIRequestComposer) - m_pUIRequestComposer->dispose(); - m_pUIRequestComposer.reset(); - - // clean up the property handlers - PropertyHandlerArray aAllHandlers; // will contain every handler exactly once - for (auto const& propertyHandler : m_aPropertyHandlers) - if ( std::find( aAllHandlers.begin(), aAllHandlers.end(), propertyHandler.second ) == aAllHandlers.end() ) - aAllHandlers.push_back( propertyHandler.second ); - - for (auto const& handler : aAllHandlers) + case PropertyControlType::DateField: { - try - { - handler->removePropertyChangeListener( this ); - handler->dispose(); - } - catch( const DisposedException& ) - { - } - catch( const Exception& ) - { - DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); - } + std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder( + u"modules/spropctrlr/ui/datefield.ui"_ustr, m_xContext)); + auto pContainer = xBuilder->weld_container(u"datefield"_ustr); + rtl::Reference<ODateControl> pControl + = new ODateControl(std::move(pContainer), std::move(xBuilder), bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; } - clearContainer( m_aPropertyHandlers ); - clearContainer( m_aDependencyHandlers ); - } - - - bool OPropertyBrowserController::impl_hasPropertyHandlerFor_nothrow( const OUString& _rPropertyName ) const - { - PropertyHandlerRepository::const_iterator handlerPos = m_aPropertyHandlers.find( _rPropertyName ); - return ( handlerPos != m_aPropertyHandlers.end() ); - } - + case PropertyControlType::TimeField: + { + std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder( + u"modules/spropctrlr/ui/timefield.ui"_ustr, m_xContext)); + auto pTimeSpinButton = xBuilder->weld_formatted_spin_button(u"timefield"_ustr); + rtl::Reference<OTimeControl> pControl = new OTimeControl( + std::move(pTimeSpinButton), std::move(xBuilder), bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; + } - OPropertyBrowserController::PropertyHandlerRef const & OPropertyBrowserController::impl_getHandlerForProperty_throw( const OUString& _rPropertyName ) const - { - PropertyHandlerRepository::const_iterator handlerPos = m_aPropertyHandlers.find( _rPropertyName ); - if ( handlerPos == m_aPropertyHandlers.end() ) - throw RuntimeException(); - return handlerPos->second; - } + case PropertyControlType::ColorListBox: + { + auto lambda + = [this] { return PropertyHandlerHelper::getDialogParentFrame(m_xContext); }; + std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder( + u"modules/spropctrlr/ui/colorlistbox.ui"_ustr, m_xContext)); + auto pMenuButton = xBuilder->weld_menu_button(u"colorlistbox"_ustr); + rtl::Reference<OColorControl> pControl + = new OColorControl(std::make_unique<ColorListBox>(std::move(pMenuButton), lambda), + std::move(xBuilder), bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; + } + case PropertyControlType::HyperlinkField: + { + std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder( + u"modules/spropctrlr/ui/hyperlinkfield.ui"_ustr, m_xContext)); + auto pContainer = xBuilder->weld_container(u"hyperlinkfield"_ustr); + rtl::Reference<OHyperlinkControl> pControl = new OHyperlinkControl( + std::move(pContainer), std::move(xBuilder), bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; + } - Any OPropertyBrowserController::impl_getPropertyValue_throw( const OUString& _rPropertyName ) - { - PropertyHandlerRef handler = impl_getHandlerForProperty_throw( _rPropertyName ); - return handler->getPropertyValue( _rPropertyName ); + default: + throw IllegalArgumentException(OUString(), *this, 1); } + return xControl; +} - void OPropertyBrowserController::impl_rebindToInspectee_nothrow( InterfaceArray&& _rObjects ) +void OPropertyBrowserController::impl_toggleInspecteeListening_nothrow(bool _bOn) +{ + for (auto const& inspectedObject : m_aInspectedObjects) { try { - // stop inspecting the old object(s) - stopInspection( true ); - - // inspect the new object(s) - m_aInspectedObjects = std::move(_rObjects); - doInspection(); - - // update the user interface - UpdateUI(); + Reference<XComponent> xComp(inspectedObject, UNO_QUERY); + if (xComp.is()) + { + if (_bOn) + xComp->addEventListener(static_cast<XPropertyChangeListener*>(this)); + else + xComp->removeEventListener(static_cast<XPropertyChangeListener*>(this)); + } } - - catch(const Exception&) + catch (const Exception&) { - TOOLS_WARN_EXCEPTION("extensions.propctrlr", ""); + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); } } +} - - void OPropertyBrowserController::doInspection() +void OPropertyBrowserController::stopInspection(bool _bCommitModified) +{ + if (haveView()) { - try - { - - // obtain the properties of the object - std::vector< Property > aProperties; - - PropertyHandlerArray aPropertyHandlers; - getPropertyHandlers( m_aInspectedObjects, aPropertyHandlers ); - - PropertyHandlerArray::iterator aHandler( aPropertyHandlers.begin() ); - while ( aHandler != aPropertyHandlers.end() ) - { - DBG_ASSERT( aHandler->get(), "OPropertyBrowserController::doInspection: invalid handler!" ); - - Sequence<Property> aThisHandlersProperties((*aHandler)->getSupportedProperties()); - - if (!aThisHandlersProperties.hasElements()) - { - // this handler doesn't know anything about the current inspectee -> ignore it - (*aHandler)->dispose(); - aHandler = aPropertyHandlers.erase( aHandler ); - continue; - } + if (_bCommitModified) + // commit the editor's content + getPropertyBox().CommitModified(); - // append these properties to our "all properties" array - aProperties.reserve( std::max<size_t>(aProperties.size() + aThisHandlersProperties.size(), aProperties.size() * 2) ); - for (const auto & aThisHandlersProperty : aThisHandlersProperties) - { - auto noPrevious = std::none_of( - aProperties.begin(), - aProperties.end(), - FindPropertyByName( aThisHandlersProperty.Name ) - ); - if ( noPrevious ) - { - aProperties.push_back( aThisHandlersProperty ); - continue; - } - - // there already was another (previous) handler which supported this property. - // Don't add it to aProperties, again. - - // Also, ensure that handlers which previously expressed interest in *changes* - // of this property are not notified. - // This is 'cause we have a new handler which is responsible for this property, - // which means it can give it a completely different meaning than the previous - // handler for this property is prepared for. - std::pair< PropertyHandlerMultiRepository::iterator, PropertyHandlerMultiRepository::iterator > - aDepHandlers = m_aDependencyHandlers.equal_range( aThisHandlersProperty.Name ); - m_aDependencyHandlers.erase( aDepHandlers.first, aDepHandlers.second ); - } + // hide the property box so that it does not flicker + getPropertyBox().Hide(); - // determine the superseded properties - Sequence<OUString> aSupersededByThisHandler((*aHandler)->getSupersededProperties()); - for (const auto & superseded : aSupersededByThisHandler) - { - std::vector< Property >::iterator existent = std::find_if( - aProperties.begin(), - aProperties.end(), - FindPropertyByName( superseded ) - ); - if ( existent != aProperties.end() ) - // one of the properties superseded by this handler was supported by a previous - // one -> erase - aProperties.erase( existent ); - } - - // be notified of changes which this handler is responsible for - (*aHandler)->addPropertyChangeListener( this ); + // clear the property box + getPropertyBox().ClearAll(); + } - // remember this handler for every of the properties which it is responsible - // for - for (const auto & aThisHandlersProperty : aThisHandlersProperties) - { - m_aPropertyHandlers[ aThisHandlersProperty.Name ] = *aHandler; - // note that this implies that if two handlers support the same property, - // the latter wins - } + // destroy the view first + if (haveView()) + { + // remove the pages + for (auto const& pageId : m_aPageIds) + getPropertyBox().RemovePage(pageId.second); + clearContainer(m_aPageIds); + } - // see if the handler expresses interest in any actuating properties - Sequence<OUString> aInterestingActuations((*aHandler)->getActuatingProperties()); - for (const auto & aInterestingActuation : aInterestingActuations) - { - m_aDependencyHandlers.emplace( aInterestingActuation, *aHandler ); - } + clearContainer(m_aProperties); - ++aHandler; - } + // de-register as dispose-listener from our inspected objects + impl_toggleInspecteeListening_nothrow(false); - // create a new composer for UI requests coming from the handlers - m_pUIRequestComposer.reset( new ComposedPropertyUIUpdate( getInspectorUI(), this ) ); + // handlers are obsolete, so is our "composer" for their UI requests + if (m_pUIRequestComposer) + m_pUIRequestComposer->dispose(); + m_pUIRequestComposer.reset(); - // sort the properties by relative position, as indicated by the model - sal_Int32 nPos = 0; - for (auto const& sourceProps : aProperties) - { - sal_Int32 nRelativePropertyOrder = nPos; - if ( m_xModel.is() ) - nRelativePropertyOrder = m_xModel->getPropertyOrderIndex( sourceProps.Name ); - m_aProperties.emplace(nRelativePropertyOrder, sourceProps); - ++nPos; - } + // clean up the property handlers + PropertyHandlerArray aAllHandlers; // will contain every handler exactly once + for (auto const& propertyHandler : m_aPropertyHandlers) + if (std::find(aAllHandlers.begin(), aAllHandlers.end(), propertyHandler.second) + == aAllHandlers.end()) + aAllHandlers.push_back(propertyHandler.second); - // be notified when one of our inspectees dies - impl_toggleInspecteeListening_nothrow( true ); + for (auto const& handler : aAllHandlers) + { + try + { + handler->removePropertyChangeListener(this); + handler->dispose(); + } + catch (const DisposedException&) + { } - catch(const Exception&) + catch (const Exception&) { - TOOLS_WARN_EXCEPTION("extensions.propctrlr", ""); + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); } } + clearContainer(m_aPropertyHandlers); + clearContainer(m_aDependencyHandlers); +} - css::awt::Size SAL_CALL OPropertyBrowserController::getMinimumSize() - { - css::awt::Size aSize; - if( m_xPropView ) - return m_xPropView->getMinimumSize(); - else - return aSize; - } +bool OPropertyBrowserController::impl_hasPropertyHandlerFor_nothrow( + const OUString& _rPropertyName) const +{ + PropertyHandlerRepository::const_iterator handlerPos = m_aPropertyHandlers.find(_rPropertyName); + return (handlerPos != m_aPropertyHandlers.end()); +} +OPropertyBrowserController::PropertyHandlerRef const& +OPropertyBrowserController::impl_getHandlerForProperty_throw(const OUString& _rPropertyName) const +{ + PropertyHandlerRepository::const_iterator handlerPos = m_aPropertyHandlers.find(_rPropertyName); + if (handlerPos == m_aPropertyHandlers.end()) + throw RuntimeException(); + return handlerPos->second; +} + +Any OPropertyBrowserController::impl_getPropertyValue_throw(const OUString& _rPropertyName) +{ + PropertyHandlerRef handler = impl_getHandlerForProperty_throw(_rPropertyName); + return handler->getPropertyValue(_rPropertyName); +} - css::awt::Size SAL_CALL OPropertyBrowserController::getPreferredSize() +void OPropertyBrowserController::impl_rebindToInspectee_nothrow(InterfaceArray&& _rObjects) +{ + try { - return getMinimumSize(); - } + // stop inspecting the old object(s) + stopInspection(true); + // inspect the new object(s) + m_aInspectedObjects = std::move(_rObjects); + doInspection(); - css::awt::Size SAL_CALL OPropertyBrowserController::calcAdjustedSize( const css::awt::Size& _rNewSize ) - { - awt::Size aMinSize = getMinimumSize( ); - awt::Size aAdjustedSize( _rNewSize ); - if ( aAdjustedSize.Width < aMinSize.Width ) - aAdjustedSize.Width = aMinSize.Width; - if ( aAdjustedSize.Height < aMinSize.Height ) - aAdjustedSize.Height = aMinSize.Height; - return aAdjustedSize; + // update the user interface + UpdateUI(); } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.propctrlr", ""); + } +} - void OPropertyBrowserController::describePropertyLine( const Property& _rProperty, OLineDescriptor& _rDescriptor ) +void OPropertyBrowserController::doInspection() +{ + try { - try - { - PropertyHandlerRepository::const_iterator handler = m_aPropertyHandlers.find( _rProperty.Name ); - if ( handler == m_aPropertyHandlers.end() ) - throw RuntimeException(); // caught below + // obtain the properties of the object + std::vector<Property> aProperties; + + PropertyHandlerArray aPropertyHandlers; + getPropertyHandlers(m_aInspectedObjects, aPropertyHandlers); - _rDescriptor.assignFrom( handler->second->describePropertyLine( _rProperty.Name, this ) ); + PropertyHandlerArray::iterator aHandler(aPropertyHandlers.begin()); + while (aHandler != aPropertyHandlers.end()) + { + DBG_ASSERT(aHandler->get(), + "OPropertyBrowserController::doInspection: invalid handler!"); + Sequence<Property> aThisHandlersProperties((*aHandler)->getSupportedProperties()); - _rDescriptor.xPropertyHandler = handler->second; - _rDescriptor.sName = _rProperty.Name; - _rDescriptor.aValue = _rDescriptor.xPropertyHandler->getPropertyValue( _rProperty.Name ); + if (!aThisHandlersProperties.hasElements()) + { + // this handler doesn't know anything about the current inspectee -> ignore it + (*aHandler)->dispose(); + aHandler = aPropertyHandlers.erase(aHandler); + continue; + } - if ( _rDescriptor.DisplayName.isEmpty() ) + // append these properties to our "all properties" array + aProperties.reserve(std::max<size_t>( + aProperties.size() + aThisHandlersProperties.size(), aProperties.size() * 2)); + for (const auto& aThisHandlersProperty : aThisHandlersProperties) { - #ifdef DBG_UTIL - SAL_WARN( "extensions.propctrlr", "OPropertyBrowserController::describePropertyLine: handler did not provide a display name for '" - <<_rProperty.Name << "'!" ); - #endif - _rDescriptor.DisplayName = _rProperty.Name; + auto noPrevious = std::none_of(aProperties.begin(), aProperties.end(), + FindPropertyByName(aThisHandlersProperty.Name)); + if (noPrevious) + { + aProperties.push_back(aThisHandlersProperty); + continue; + } + + // there already was another (previous) handler which supported this property. + // Don't add it to aProperties, again. + + // Also, ensure that handlers which previously expressed interest in *changes* + // of this property are not notified. + // This is 'cause we have a new handler which is responsible for this property, + // which means it can give it a completely different meaning than the previous + // handler for this property is prepared for. + std::pair<PropertyHandlerMultiRepository::iterator, + PropertyHandlerMultiRepository::iterator> + aDepHandlers = m_aDependencyHandlers.equal_range(aThisHandlersProperty.Name); + m_aDependencyHandlers.erase(aDepHandlers.first, aDepHandlers.second); } - PropertyState ePropertyState( _rDescriptor.xPropertyHandler->getPropertyState( _rProperty.Name ) ); - if ( PropertyState_AMBIGUOUS_VALUE == ePropertyState ) + // determine the superseded properties + Sequence<OUString> aSupersededByThisHandler((*aHandler)->getSupersededProperties()); + for (const auto& superseded : aSupersededByThisHandler) { - _rDescriptor.bUnknownValue = true; - _rDescriptor.aValue.clear(); + std::vector<Property>::iterator existent = std::find_if( + aProperties.begin(), aProperties.end(), FindPropertyByName(superseded)); + if (existent != aProperties.end()) + // one of the properties superseded by this handler was supported by a previous + // one -> erase + aProperties.erase(existent); } - _rDescriptor.bReadOnly = impl_isReadOnlyModel_throw(); + // be notified of changes which this handler is responsible for + (*aHandler)->addPropertyChangeListener(this); - // for ui-testing try and distinguish different instances of the controls - auto xWindow = _rDescriptor.Control->getControlWindow(); - if (weld::TransportAsXWindow* pTunnel = dynamic_cast<weld::TransportAsXWindow*>(xWindow.get())) + // remember this handler for every of the properties which it is responsible + // for + for (const auto& aThisHandlersProperty : aThisHandlersProperties) { - weld::Widget* m_pControlWindow = pTunnel->getWidget(); - if (m_pControlWindow) - m_pControlWindow->set_buildable_name(m_pControlWindow->get_buildable_name() + "-" + _rDescriptor.DisplayName); + m_aPropertyHandlers[aThisHandlersProperty.Name] = *aHandler; + // note that this implies that if two handlers support the same property, + // the latter wins } + // see if the handler expresses interest in any actuating properties + Sequence<OUString> aInterestingActuations((*aHandler)->getActuatingProperties()); + for (const auto& aInterestingActuation : aInterestingActuations) + { + m_aDependencyHandlers.emplace(aInterestingActuation, *aHandler); + } + + ++aHandler; } - catch( const Exception& ) + + // create a new composer for UI requests coming from the handlers + m_pUIRequestComposer.reset(new ComposedPropertyUIUpdate(getInspectorUI(), this)); + + // sort the properties by relative position, as indicated by the model + sal_Int32 nPos = 0; + for (auto const& sourceProps : aProperties) { - TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "OPropertyBrowserController::describePropertyLine" ); + sal_Int32 nRelativePropertyOrder = nPos; + if (m_xModel.is()) + nRelativePropertyOrder = m_xModel->getPropertyOrderIndex(sourceProps.Name); + m_aProperties.emplace(nRelativePropertyOrder, sourceProps); + ++nPos; } + + // be notified when one of our inspectees dies + impl_toggleInspecteeListening_nothrow(true); + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.propctrlr", ""); } +} + +css::awt::Size SAL_CALL OPropertyBrowserController::getMinimumSize() +{ + css::awt::Size aSize; + if (m_xPropView) + return m_xPropView->getMinimumSize(); + else + return aSize; +} +css::awt::Size SAL_CALL OPropertyBrowserController::getPreferredSize() { return getMinimumSize(); } - void OPropertyBrowserController::impl_buildCategories_throw() +css::awt::Size SAL_CALL +OPropertyBrowserController::calcAdjustedSize(const css::awt::Size& _rNewSize) +{ + awt::Size aMinSize = getMinimumSize(); + awt::Size aAdjustedSize(_rNewSize); + if (aAdjustedSize.Width < aMinSize.Width) + aAdjustedSize.Width = aMinSize.Width; + if (aAdjustedSize.Height < aMinSize.Height) + aAdjustedSize.Height = aMinSize.Height; + return aAdjustedSize; +} + +void OPropertyBrowserController::describePropertyLine(const Property& _rProperty, + OLineDescriptor& _rDescriptor) +{ + try { - OSL_PRECOND( m_aPageIds.empty(), "OPropertyBrowserController::impl_buildCategories_throw: duplicate call!" ); + PropertyHandlerRepository::const_iterator handler + = m_aPropertyHandlers.find(_rProperty.Name); + if (handler == m_aPropertyHandlers.end()) + throw RuntimeException(); // caught below - Sequence<PropertyCategoryDescriptor> aCategories; - if ( m_xModel.is() ) - aCategories = m_xModel->describeCategories(); + _rDescriptor.assignFrom(handler->second->describePropertyLine(_rProperty.Name, this)); + + _rDescriptor.xPropertyHandler = handler->second; + _rDescriptor.sName = _rProperty.Name; + _rDescriptor.aValue = _rDescriptor.xPropertyHandler->getPropertyValue(_rProperty.Name); + + if (_rDescriptor.DisplayName.isEmpty()) + { +#ifdef DBG_UTIL + SAL_WARN("extensions.propctrlr", "OPropertyBrowserController::describePropertyLine: " + "handler did not provide a display name for '" + << _rProperty.Name << "'!"); +#endif + _rDescriptor.DisplayName = _rProperty.Name; + } - for (auto const& category : aCategories) + PropertyState ePropertyState( + _rDescriptor.xPropertyHandler->getPropertyState(_rProperty.Name)); + if (PropertyState_AMBIGUOUS_VALUE == ePropertyState) { - OSL_ENSURE( m_aPageIds.find( category.ProgrammaticName ) == m_aPageIds.end(), - "OPropertyBrowserController::impl_buildCategories_throw: duplicate programmatic name!" ); + _rDescriptor.bUnknownValue = true; + _rDescriptor.aValue.clear(); + } + + _rDescriptor.bReadOnly = impl_isReadOnlyModel_throw(); - m_aPageIds[ category.ProgrammaticName ] = - getPropertyBox().AppendPage( category.UIName, HelpIdUrl::getHelpId( category.HelpURL ) ); + // for ui-testing try and distinguish different instances of the controls + auto xWindow = _rDescriptor.Control->getControlWindow(); + if (weld::TransportAsXWindow* pTunnel + = dynamic_cast<weld::TransportAsXWindow*>(xWindow.get())) + { + weld::Widget* m_pControlWindow = pTunnel->getWidget(); + if (m_pControlWindow) + m_pControlWindow->set_buildable_name(m_pControlWindow->get_buildable_name() + "-" + + _rDescriptor.DisplayName); } } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.propctrlr", + "OPropertyBrowserController::describePropertyLine"); + } +} + +void OPropertyBrowserController::impl_buildCategories_throw() +{ + OSL_PRECOND(m_aPageIds.empty(), + "OPropertyBrowserController::impl_buildCategories_throw: duplicate call!"); + Sequence<PropertyCategoryDescriptor> aCategories; + if (m_xModel.is()) + aCategories = m_xModel->describeCategories(); - void OPropertyBrowserController::UpdateUI() + for (auto const& category : aCategories) { - try - { - if ( !haveView() ) - // too early, will return later - return; - - // create our tab pages - impl_buildCategories_throw(); - // (and allow for pages to be actually unused) - std::set< sal_uInt16 > aUsedPages; - - // when building the UI below, remember which properties are actuating, - // to allow for an initial actuatingPropertyChanged call - std::vector< OUString > aActuatingProperties; - std::vector< Any > aActuatingPropertyValues; - - // ask the handlers to describe the property UI, and insert the resulting - // entries into our list boxes - for (auto const& property : m_aProperties) - { - OLineDescriptor aDescriptor; - describePropertyLine( property.second, aDescriptor ); + OSL_ENSURE( + m_aPageIds.find(category.ProgrammaticName) == m_aPageIds.end(), + "OPropertyBrowserController::impl_buildCategories_throw: duplicate programmatic name!"); - bool bIsActuatingProperty = impl_isActuatingProperty_nothrow( property.second.Name ); + m_aPageIds[category.ProgrammaticName] + = getPropertyBox().AppendPage(category.UIName, HelpIdUrl::getHelpId(category.HelpURL)); + } +} - SAL_WARN_IF( aDescriptor.Category.isEmpty(), "extensions.propctrlr", - "OPropertyBrowserController::UpdateUI: empty category provided for property '" - << property.second.Name << "'!"); - // finally insert this property control - sal_uInt16 nTargetPageId = impl_getPageIdForCategory_nothrow( aDescriptor.Category ); - if ( nTargetPageId == sal_uInt16(-1) ) - { - // this category does not yet exist. This is allowed, as an inspector model might be lazy, and not provide - // any category information of its own. In this case, we have a fallback ... - m_aPageIds[ aDescriptor.Category ] = - getPropertyBox().AppendPage(aDescriptor.Category, {}); - nTargetPageId = impl_getPageIdForCategory_nothrow( aDescriptor.Category ); - } +void OPropertyBrowserController::UpdateUI() +{ + try + { + if (!haveView()) + // too early, will return later + return; - getPropertyBox().InsertEntry( aDescriptor, nTargetPageId ); - aUsedPages.insert( nTargetPageId ); + // create our tab pages + impl_buildCategories_throw(); + // (and allow for pages to be actually unused) + std::set<sal_uInt16> aUsedPages; - // if it's an actuating property, remember it - if ( bIsActuatingProperty ) - { - aActuatingProperties.push_back( property.second.Name ); - aActuatingPropertyValues.push_back( impl_getPropertyValue_throw( property.second.Name ) ); - } - } + // when building the UI below, remember which properties are actuating, + // to allow for an initial actuatingPropertyChanged call + std::vector<OUString> aActuatingProperties; + std::vector<Any> aActuatingPropertyValues; - // update any dependencies for the actuating properties which we encountered + // ask the handlers to describe the property UI, and insert the resulting + // entries into our list boxes + for (auto const& property : m_aProperties) + { + OLineDescriptor aDescriptor; + describePropertyLine(property.second, aDescriptor); + + bool bIsActuatingProperty = impl_isActuatingProperty_nothrow(property.second.Name); + + SAL_WARN_IF( + aDescriptor.Category.isEmpty(), "extensions.propctrlr", + "OPropertyBrowserController::UpdateUI: empty category provided for property '" + << property.second.Name << "'!"); + // finally insert this property control + sal_uInt16 nTargetPageId = impl_getPageIdForCategory_nothrow(aDescriptor.Category); + if (nTargetPageId == sal_uInt16(-1)) { - std::vector< Any >::const_iterator aPropertyValue = aActuatingPropertyValues.begin(); - for (auto const& actuatingProperty : aActuatingProperties) - { - impl_broadcastPropertyChange_nothrow( actuatingProperty, *aPropertyValue, *aPropertyValue, true ); - ++aPropertyValue; - } + // this category does not yet exist. This is allowed, as an inspector model might be lazy, and not provide + // any category information of its own. In this case, we have a fallback ... -e ... etc. - the rest is truncated
