diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2021-02-08 22:41:36 +0900 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2021-02-11 12:54:47 +0100 |
commit | e44639f50056b843913573b4635517019e00431c (patch) | |
tree | fc1b161e07919e20693526676f24ece05eff887d | |
parent | a1ca311061b617b2e4731f6e4c8a5466e8a080f5 (diff) |
devtools: move handling of object inspector tree to own class/files
To make handling of object inspector tree view easier, move the
functionality to its own class and file.
Change-Id: I47ae1bc06b582d0d146e7e97bc08a3b5f82ce794
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/110734
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
-rw-r--r-- | include/sfx2/devtools/DevelopmentToolDockingWindow.hxx | 6 | ||||
-rw-r--r-- | include/sfx2/devtools/ObjectInspectorTreeHandler.hxx | 44 | ||||
-rw-r--r-- | sfx2/Library_sfx.mk | 1 | ||||
-rw-r--r-- | sfx2/source/devtools/DevelopmentToolDockingWindow.cxx | 501 | ||||
-rw-r--r-- | sfx2/source/devtools/ObjectInspectorTreeHandler.cxx | 503 |
5 files changed, 557 insertions, 498 deletions
diff --git a/include/sfx2/devtools/DevelopmentToolDockingWindow.hxx b/include/sfx2/devtools/DevelopmentToolDockingWindow.hxx index 1ed166239949..4721a424e66d 100644 --- a/include/sfx2/devtools/DevelopmentToolDockingWindow.hxx +++ b/include/sfx2/devtools/DevelopmentToolDockingWindow.hxx @@ -16,6 +16,7 @@ #include <vcl/weld.hxx> #include <sfx2/devtools/DocumentModelTreeHandler.hxx> +#include <sfx2/devtools/ObjectInspectorTreeHandler.hxx> #include <com/sun/star/uno/XInterface.hpp> #include <com/sun/star/uno/Reference.hxx> @@ -37,18 +38,15 @@ private: css::uno::Reference<css::view::XSelectionChangeListener> mxSelectionListener; DocumentModelTreeHandler maDocumentModelTreeHandler; + ObjectInspectorTreeHandler maObjectInspectorTreeHandler; DECL_LINK(DocumentModelTreeViewSelectionHandler, weld::TreeView&, void); DECL_LINK(SelectionToggled, weld::ToggleButton&, void); - DECL_LINK(ObjectInspectorExpandingHandler, const weld::TreeIter&, bool); - void inspectDocument(); void updateSelection(); void inspectSelectionOrRoot(css::uno::Reference<css::frame::XController> const& xController); - void clearObjectInspectorChildren(weld::TreeIter const& rParent); - public: DevelopmentToolDockingWindow(SfxBindings* pBindings, SfxChildWindow* pChildWindow, vcl::Window* pParent); diff --git a/include/sfx2/devtools/ObjectInspectorTreeHandler.hxx b/include/sfx2/devtools/ObjectInspectorTreeHandler.hxx new file mode 100644 index 000000000000..aa6e353e6549 --- /dev/null +++ b/include/sfx2/devtools/ObjectInspectorTreeHandler.hxx @@ -0,0 +1,44 @@ +/* -*- 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/. + * + */ + +#pragma once + +#include <sfx2/dllapi.h> +#include <vcl/weld.hxx> + +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/uno/Reference.hxx> + +class ObjectInspectorTreeHandler +{ +private: + std::unique_ptr<weld::TreeView>& mpObjectInspectorTree; + std::unique_ptr<weld::Label>& mpClassNameLabel; + + void clearObjectInspectorChildren(weld::TreeIter const& rParent); + +public: + ObjectInspectorTreeHandler(std::unique_ptr<weld::TreeView>& pObjectInspectorTree, + std::unique_ptr<weld::Label>& pClassNameLabel) + : mpObjectInspectorTree(pObjectInspectorTree) + , mpClassNameLabel(pClassNameLabel) + { + mpObjectInspectorTree->connect_expanding( + LINK(this, ObjectInspectorTreeHandler, ExpandingHandler)); + } + + DECL_LINK(ExpandingHandler, const weld::TreeIter&, bool); + + void introspect(css::uno::Reference<css::uno::XInterface> const& xInterface); + + void dispose(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sfx2/Library_sfx.mk b/sfx2/Library_sfx.mk index 52ace3c503fe..b5126ca87893 100644 --- a/sfx2/Library_sfx.mk +++ b/sfx2/Library_sfx.mk @@ -165,6 +165,7 @@ $(eval $(call gb_Library_add_exception_objects,sfx,\ sfx2/source/devtools/DevelopmentToolChildWindow \ sfx2/source/devtools/DevelopmentToolDockingWindow \ sfx2/source/devtools/DocumentModelTreeHandler \ + sfx2/source/devtools/ObjectInspectorTreeHandler \ sfx2/source/dialog/alienwarn \ sfx2/source/dialog/backingcomp \ sfx2/source/dialog/backingwindow \ diff --git a/sfx2/source/devtools/DevelopmentToolDockingWindow.cxx b/sfx2/source/devtools/DevelopmentToolDockingWindow.cxx index 89f9e878d69b..0d335b5118cc 100644 --- a/sfx2/source/devtools/DevelopmentToolDockingWindow.cxx +++ b/sfx2/source/devtools/DevelopmentToolDockingWindow.cxx @@ -12,433 +12,16 @@ #include <sfx2/devtools/DevelopmentToolDockingWindow.hxx> -#include <com/sun/star/uno/XComponentContext.hpp> -#include <com/sun/star/lang/XServiceInfo.hpp> - -#include <com/sun/star/beans/theIntrospection.hpp> -#include <com/sun/star/beans/XIntrospection.hpp> -#include <com/sun/star/beans/XIntrospectionAccess.hpp> -#include <com/sun/star/beans/Property.hpp> -#include <com/sun/star/beans/PropertyConcept.hpp> -#include <com/sun/star/beans/MethodConcept.hpp> -#include <com/sun/star/beans/XPropertySet.hpp> - -#include <com/sun/star/reflection/theCoreReflection.hpp> -#include <com/sun/star/reflection/XIdlReflection.hpp> -#include <com/sun/star/reflection/XIdlMethod.hpp> - -#include <com/sun/star/script/XInvocation.hpp> -#include <com/sun/star/script/Invocation.hpp> - #include <com/sun/star/view/XSelectionSupplier.hpp> -#include <comphelper/processfactory.hxx> - #include <sfx2/dispatch.hxx> -#include <sfx2/sfxmodelfactory.hxx> - #include <sfx2/objsh.hxx> - #include <sfx2/viewfrm.hxx> -#include <cppuhelper/compbase.hxx> -#include <cppuhelper/basemutex.hxx> - #include "SelectionChangeHandler.hxx" using namespace css; -namespace -{ -uno::Reference<reflection::XIdlClass> -TypeToIdlClass(const uno::Type& rType, const uno::Reference<uno::XComponentContext>& xContext) -{ - auto xReflection = reflection::theCoreReflection::get(xContext); - - uno::Reference<reflection::XIdlClass> xRetClass; - typelib_TypeDescription* pTD = nullptr; - rType.getDescription(&pTD); - if (pTD) - { - OUString sOWName(pTD->pTypeName); - xRetClass = xReflection->forName(sOWName); - } - return xRetClass; -} - -OUString AnyToString(const uno::Any& aValue, const uno::Reference<uno::XComponentContext>& xContext) -{ - uno::Type aValType = aValue.getValueType(); - uno::TypeClass eType = aValType.getTypeClass(); - - OUString aRetStr; - switch (eType) - { - case uno::TypeClass_TYPE: - { - auto xIdlClass = TypeToIdlClass(aValType, xContext); - aRetStr = xIdlClass->getName() + " <TYPE>"; - break; - } - case uno::TypeClass_INTERFACE: - { - auto xIdlClass = TypeToIdlClass(aValType, xContext); - aRetStr = xIdlClass->getName() + " <INTERFACE>"; - break; - } - case uno::TypeClass_SERVICE: - { - auto xIdlClass = TypeToIdlClass(aValType, xContext); - aRetStr = xIdlClass->getName() + " <SERVICE>"; - break; - } - case uno::TypeClass_STRUCT: - { - auto xIdlClass = TypeToIdlClass(aValType, xContext); - aRetStr = xIdlClass->getName() + " <STRUCT>"; - break; - } - case uno::TypeClass_TYPEDEF: - { - auto xIdlClass = TypeToIdlClass(aValType, xContext); - aRetStr = xIdlClass->getName() + " <TYPEDEF>"; - break; - } - case uno::TypeClass_ENUM: - { - auto xIdlClass = TypeToIdlClass(aValType, xContext); - aRetStr = xIdlClass->getName() + " <ENUM>"; - break; - } - case uno::TypeClass_EXCEPTION: - { - auto xIdlClass = TypeToIdlClass(aValType, xContext); - aRetStr = xIdlClass->getName() + " <EXCEPTION>"; - break; - } - case uno::TypeClass_SEQUENCE: - { - auto xIdlClass = TypeToIdlClass(aValType, xContext); - aRetStr = xIdlClass->getName() + " <SEQUENCE>"; - break; - } - case uno::TypeClass_VOID: - { - auto xIdlClass = TypeToIdlClass(aValType, xContext); - aRetStr = xIdlClass->getName() + " <VOID>"; - break; - } - case uno::TypeClass_ANY: - { - auto xIdlClass = TypeToIdlClass(aValType, xContext); - aRetStr = xIdlClass->getName() + " <ANY>"; - break; - } - case uno::TypeClass_UNKNOWN: - aRetStr = "<Unknown>"; - break; - case uno::TypeClass_BOOLEAN: - { - bool bBool = aValue.get<bool>(); - aRetStr = bBool ? u"True" : u"False"; - break; - } - case uno::TypeClass_CHAR: - { - sal_Unicode aChar = aValue.get<sal_Unicode>(); - aRetStr = OUString::number(aChar); - break; - } - case uno::TypeClass_STRING: - { - aRetStr = "\"" + aValue.get<OUString>() + "\""; - break; - } - case uno::TypeClass_FLOAT: - { - auto aNumber = aValue.get<float>(); - aRetStr = OUString::number(aNumber); - break; - } - case uno::TypeClass_DOUBLE: - { - auto aNumber = aValue.get<double>(); - aRetStr = OUString::number(aNumber); - break; - } - case uno::TypeClass_BYTE: - { - auto aNumber = aValue.get<sal_Int8>(); - aRetStr = OUString::number(aNumber); - break; - } - case uno::TypeClass_SHORT: - { - auto aNumber = aValue.get<sal_Int16>(); - aRetStr = OUString::number(aNumber); - break; - } - case uno::TypeClass_LONG: - { - auto aNumber = aValue.get<sal_Int32>(); - aRetStr = OUString::number(aNumber); - break; - } - case uno::TypeClass_HYPER: - { - auto aNumber = aValue.get<sal_Int64>(); - aRetStr = OUString::number(aNumber); - break; - } - - default: - break; - } - return aRetStr; -} - -// Object inspector nodes - -class ObjectInspectorNode -{ -public: - css::uno::Reference<css::uno::XInterface> mxObject; - - ObjectInspectorNode() = default; - - ObjectInspectorNode(css::uno::Reference<css::uno::XInterface> const& xObject) - : mxObject(xObject) - { - } - - virtual ~ObjectInspectorNode() {} - - virtual OUString getObjectName() = 0; - - virtual void fillChildren(std::unique_ptr<weld::TreeView>& rTree, weld::TreeIter const& rParent) - = 0; -}; - -OUString lclAppendNode(std::unique_ptr<weld::TreeView>& pTree, ObjectInspectorNode* pEntry, - bool bChildrenOnDemand = false) -{ - OUString sName = pEntry->getObjectName(); - OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pEntry))); - std::unique_ptr<weld::TreeIter> pCurrent = pTree->make_iterator(); - pTree->insert(nullptr, -1, &sName, &sId, nullptr, nullptr, bChildrenOnDemand, pCurrent.get()); - pTree->set_text_emphasis(*pCurrent, true, 0); - return sId; -} - -OUString lclAppendNodeToParent(std::unique_ptr<weld::TreeView>& pTree, - weld::TreeIter const& rParent, ObjectInspectorNode* pEntry, - bool bChildrenOnDemand = false) -{ - OUString sName = pEntry->getObjectName(); - OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pEntry))); - std::unique_ptr<weld::TreeIter> pCurrent = pTree->make_iterator(); - pTree->insert(&rParent, -1, &sName, &sId, nullptr, nullptr, bChildrenOnDemand, nullptr); - pTree->set_text_emphasis(*pCurrent, true, 0); - return sId; -} - -OUString lclAppendNodeWithIterToParent(std::unique_ptr<weld::TreeView>& pTree, - weld::TreeIter const& rParent, weld::TreeIter& rCurrent, - ObjectInspectorNode* pEntry, bool bChildrenOnDemand = false) -{ - OUString sName = pEntry->getObjectName(); - OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pEntry))); - pTree->insert(&rParent, -1, &sName, &sId, nullptr, nullptr, bChildrenOnDemand, &rCurrent); - pTree->set_text_emphasis(rCurrent, true, 0); - return sId; -} - -class ObjectInspectorNamedNode : public ObjectInspectorNode -{ -public: - OUString msName; - - ObjectInspectorNamedNode(OUString const& rName, - css::uno::Reference<css::uno::XInterface> const& xObject) - : ObjectInspectorNode(xObject) - , msName(rName) - { - } - - OUString getObjectName() override { return msName; } - - void fillChildren(std::unique_ptr<weld::TreeView>& /*rTree*/, - weld::TreeIter const& /*rParent*/) override - { - } -}; - -class ServicesNode : public ObjectInspectorNamedNode -{ -public: - ServicesNode(css::uno::Reference<css::uno::XInterface> const& xObject) - : ObjectInspectorNamedNode("Services", xObject) - { - } - - void fillChildren(std::unique_ptr<weld::TreeView>& pTree, - weld::TreeIter const& rParent) override - { - auto xServiceInfo = uno::Reference<lang::XServiceInfo>(mxObject, uno::UNO_QUERY); - const uno::Sequence<OUString> aServiceNames(xServiceInfo->getSupportedServiceNames()); - for (auto const& aServiceName : aServiceNames) - { - lclAppendNodeToParent(pTree, rParent, - new ObjectInspectorNamedNode(aServiceName, mxObject)); - } - } -}; - -class GenericPropertiesNode : public ObjectInspectorNamedNode -{ -public: - uno::Reference<uno::XComponentContext> mxContext; - - GenericPropertiesNode(OUString const& rName, uno::Reference<uno::XInterface> const& xObject, - uno::Reference<uno::XComponentContext> const& xContext) - : ObjectInspectorNamedNode(rName, xObject) - , mxContext(xContext) - { - } - - void fillChildren(std::unique_ptr<weld::TreeView>& pTree, - weld::TreeIter const& rParent) override - { - uno::Reference<beans::XIntrospection> xIntrospection - = beans::theIntrospection::get(mxContext); - auto xIntrospectionAccess = xIntrospection->inspect(uno::makeAny(mxObject)); - auto xInvocationFactory = css::script::Invocation::create(mxContext); - uno::Sequence<uno::Any> aParameters = { uno::Any(mxObject) }; - auto xInvocationInterface = xInvocationFactory->createInstanceWithArguments(aParameters); - uno::Reference<script::XInvocation> xInvocation(xInvocationInterface, uno::UNO_QUERY); - - const auto xProperties = xIntrospectionAccess->getProperties( - beans::PropertyConcept::ALL - beans::PropertyConcept::DANGEROUS); - - for (auto const& xProperty : xProperties) - { - OUString aValue; - uno::Any aAny; - uno::Reference<uno::XInterface> xCurrent = mxObject; - - try - { - if (xInvocation->hasProperty(xProperty.Name)) - { - aAny = xInvocation->getValue(xProperty.Name); - aValue = AnyToString(aAny, mxContext); - } - } - catch (...) - { - aValue = "<?>"; - } - - bool bComplex = false; - if (aAny.hasValue()) - { - auto xInterface = uno::Reference<uno::XInterface>(aAny, uno::UNO_QUERY); - if (xInterface.is()) - { - xCurrent = xInterface; - bComplex = true; - } - } - - std::unique_ptr<weld::TreeIter> pCurrent = pTree->make_iterator(); - if (bComplex) - { - lclAppendNodeWithIterToParent( - pTree, rParent, *pCurrent, - new GenericPropertiesNode(xProperty.Name, xCurrent, mxContext), true); - } - else - { - lclAppendNodeWithIterToParent( - pTree, rParent, *pCurrent, - new ObjectInspectorNamedNode(xProperty.Name, xCurrent), false); - } - - if (!aValue.isEmpty()) - { - pTree->set_text(*pCurrent, aValue, 1); - } - } - } -}; - -class PropertiesNode : public GenericPropertiesNode -{ -public: - PropertiesNode(uno::Reference<uno::XInterface> const& xObject, - uno::Reference<uno::XComponentContext> const& xContext) - : GenericPropertiesNode("Properties", xObject, xContext) - { - } -}; - -class InterfacesNode : public ObjectInspectorNamedNode -{ -public: - InterfacesNode(css::uno::Reference<css::uno::XInterface> const& xObject) - : ObjectInspectorNamedNode("Interfaces", xObject) - { - } - - void fillChildren(std::unique_ptr<weld::TreeView>& pTree, - weld::TreeIter const& rParent) override - { - uno::Reference<lang::XTypeProvider> xTypeProvider(mxObject, uno::UNO_QUERY); - if (xTypeProvider.is()) - { - const auto xSequenceTypes = xTypeProvider->getTypes(); - for (auto const& xType : xSequenceTypes) - { - OUString aName = xType.getTypeName(); - lclAppendNodeToParent(pTree, rParent, - new ObjectInspectorNamedNode(aName, mxObject)); - } - } - } -}; - -class MethodsNode : public ObjectInspectorNamedNode -{ -public: - uno::Reference<uno::XComponentContext> mxContext; - - MethodsNode(css::uno::Reference<css::uno::XInterface> const& xObject, - uno::Reference<uno::XComponentContext> const& xContext) - : ObjectInspectorNamedNode("Methods", xObject) - , mxContext(xContext) - { - } - - void fillChildren(std::unique_ptr<weld::TreeView>& pTree, - weld::TreeIter const& rParent) override - { - uno::Reference<beans::XIntrospection> xIntrospection - = beans::theIntrospection::get(mxContext); - auto xIntrospectionAccess = xIntrospection->inspect(uno::makeAny(mxObject)); - - const auto xMethods = xIntrospectionAccess->getMethods(beans::MethodConcept::ALL); - for (auto const& xMethod : xMethods) - { - OUString aMethodName = xMethod->getName(); - - lclAppendNodeToParent(pTree, rParent, - new ObjectInspectorNamedNode(aMethodName, mxObject)); - } - } -}; - -} // end anonymous namespace - DevelopmentToolDockingWindow::DevelopmentToolDockingWindow(SfxBindings* pInputBindings, SfxChildWindow* pChildWindow, vcl::Window* pParent) @@ -451,12 +34,11 @@ DevelopmentToolDockingWindow::DevelopmentToolDockingWindow(SfxBindings* pInputBi , maDocumentModelTreeHandler( mpDocumentModelTreeView, pInputBindings->GetDispatcher()->GetFrame()->GetObjectShell()->GetBaseModel()) + , maObjectInspectorTreeHandler(mpClassListBox, mpClassNameLabel) { mpDocumentModelTreeView->connect_changed( LINK(this, DevelopmentToolDockingWindow, DocumentModelTreeViewSelectionHandler)); mpSelectionToggle->connect_toggled(LINK(this, DevelopmentToolDockingWindow, SelectionToggled)); - mpClassListBox->connect_expanding( - LINK(this, DevelopmentToolDockingWindow, ObjectInspectorExpandingHandler)); auto* pViewFrame = pInputBindings->GetDispatcher()->GetFrame(); @@ -482,14 +64,14 @@ void DevelopmentToolDockingWindow::inspectSelectionOrRoot( auto xInterface = aAny.get<css::uno::Reference<css::uno::XInterface>>(); if (xInterface.is()) { - introspect(xInterface); + maObjectInspectorTreeHandler.introspect(xInterface); mpSelectionToggle->set_state(TRISTATE_TRUE); return; } } } mpSelectionToggle->set_state(TRISTATE_FALSE); - introspect(mxRoot); + maObjectInspectorTreeHandler.introspect(mxRoot); } IMPL_LINK(DevelopmentToolDockingWindow, DocumentModelTreeViewSelectionHandler, weld::TreeView&, @@ -501,7 +83,7 @@ IMPL_LINK(DevelopmentToolDockingWindow, DocumentModelTreeViewSelectionHandler, w OUString sID = rView.get_selected_id(); auto xObject = DocumentModelTreeHandler::getObjectByID(sID); if (xObject.is()) - introspect(xObject); + maObjectInspectorTreeHandler.introspect(xObject); } IMPL_LINK_NOARG(DevelopmentToolDockingWindow, SelectionToggled, weld::ToggleButton&, void) @@ -509,28 +91,6 @@ IMPL_LINK_NOARG(DevelopmentToolDockingWindow, SelectionToggled, weld::ToggleButt updateSelection(); } -void DevelopmentToolDockingWindow::clearObjectInspectorChildren(weld::TreeIter const& rParent) -{ - bool bChild = false; - do - { - bChild = mpClassListBox->iter_has_child(rParent); - if (bChild) - { - std::unique_ptr<weld::TreeIter> pChild = mpClassListBox->make_iterator(&rParent); - bChild = mpClassListBox->iter_children(*pChild); - if (bChild) - { - clearObjectInspectorChildren(*pChild); - OUString sID = mpClassListBox->get_id(*pChild); - auto* pEntry = reinterpret_cast<ObjectInspectorNode*>(sID.toInt64()); - delete pEntry; - mpClassListBox->remove(*pChild); - } - } - } while (bChild); -} - DevelopmentToolDockingWindow::~DevelopmentToolDockingWindow() { disposeOnce(); } void DevelopmentToolDockingWindow::dispose() @@ -541,15 +101,9 @@ void DevelopmentToolDockingWindow::dispose() pSelectionChangeHandler->stopListening(); mxSelectionListener = uno::Reference<view::XSelectionChangeListener>(); - maDocumentModelTreeHandler.dispose(); - // destroy all ObjectInspectorNodes from the tree - mpClassListBox->all_foreach([this](weld::TreeIter& rEntry) { - OUString sID = mpClassListBox->get_id(rEntry); - auto* pEntry = reinterpret_cast<ObjectInspectorNode*>(sID.toInt64()); - delete pEntry; - return false; - }); + maDocumentModelTreeHandler.dispose(); + maObjectInspectorTreeHandler.dispose(); // dispose welded objects mpClassNameLabel.reset(); @@ -565,7 +119,7 @@ void DevelopmentToolDockingWindow::updateSelection() TriState eTriState = mpSelectionToggle->get_state(); if (eTriState == TRISTATE_TRUE) { - introspect(mxCurrentSelection); + maObjectInspectorTreeHandler.introspect(mxCurrentSelection); maDocumentModelTreeHandler.selectObject(mxCurrentSelection); } else @@ -584,20 +138,6 @@ void DevelopmentToolDockingWindow::ToggleFloatingMode() Invalidate(); } -IMPL_LINK(DevelopmentToolDockingWindow, ObjectInspectorExpandingHandler, weld::TreeIter const&, - rParent, bool) -{ - OUString sID = mpClassListBox->get_id(rParent); - if (sID.isEmpty()) - return true; - - clearObjectInspectorChildren(rParent); - auto* pNode = reinterpret_cast<ObjectInspectorNode*>(sID.toInt64()); - pNode->fillChildren(mpClassListBox, rParent); - - return true; -} - void DevelopmentToolDockingWindow::selectionChanged( uno::Reference<uno::XInterface> const& xInterface) { @@ -605,31 +145,4 @@ void DevelopmentToolDockingWindow::selectionChanged( updateSelection(); } -void DevelopmentToolDockingWindow::introspect(uno::Reference<uno::XInterface> const& xInterface) -{ - if (!xInterface.is()) - return; - - uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext(); - if (!xContext.is()) - return; - - // Set implementation name - auto xServiceInfo = uno::Reference<lang::XServiceInfo>(xInterface, uno::UNO_QUERY); - OUString aImplementationName = xServiceInfo->getImplementationName(); - mpClassNameLabel->set_label(aImplementationName); - - // fill object inspector - - mpClassListBox->freeze(); - mpClassListBox->clear(); - - lclAppendNode(mpClassListBox, new ServicesNode(xInterface), true); - lclAppendNode(mpClassListBox, new InterfacesNode(xInterface), true); - lclAppendNode(mpClassListBox, new PropertiesNode(xInterface, xContext), true); - lclAppendNode(mpClassListBox, new MethodsNode(xInterface, xContext), true); - - mpClassListBox->thaw(); -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sfx2/source/devtools/ObjectInspectorTreeHandler.cxx b/sfx2/source/devtools/ObjectInspectorTreeHandler.cxx new file mode 100644 index 000000000000..d69f8130f82b --- /dev/null +++ b/sfx2/source/devtools/ObjectInspectorTreeHandler.cxx @@ -0,0 +1,503 @@ +/* -*- 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/. + * + */ + +#include <memory> + +#include <sfx2/devtools/ObjectInspectorTreeHandler.hxx> + +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/uno/Reference.hxx> + +#include <com/sun/star/beans/theIntrospection.hpp> +#include <com/sun/star/beans/XIntrospection.hpp> +#include <com/sun/star/beans/XIntrospectionAccess.hpp> +#include <com/sun/star/beans/Property.hpp> +#include <com/sun/star/beans/PropertyConcept.hpp> +#include <com/sun/star/beans/MethodConcept.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <com/sun/star/reflection/theCoreReflection.hpp> +#include <com/sun/star/reflection/XIdlReflection.hpp> +#include <com/sun/star/reflection/XIdlMethod.hpp> + +#include <com/sun/star/script/XInvocation.hpp> +#include <com/sun/star/script/Invocation.hpp> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XTypeProvider.hpp> + +#include <comphelper/processfactory.hxx> + +using namespace css; + +namespace +{ +uno::Reference<reflection::XIdlClass> +TypeToIdlClass(const uno::Type& rType, const uno::Reference<uno::XComponentContext>& xContext) +{ + auto xReflection = reflection::theCoreReflection::get(xContext); + + uno::Reference<reflection::XIdlClass> xRetClass; + typelib_TypeDescription* pTD = nullptr; + rType.getDescription(&pTD); + if (pTD) + { + OUString sOWName(pTD->pTypeName); + xRetClass = xReflection->forName(sOWName); + } + return xRetClass; +} + +OUString AnyToString(const uno::Any& aValue, const uno::Reference<uno::XComponentContext>& xContext) +{ + uno::Type aValType = aValue.getValueType(); + uno::TypeClass eType = aValType.getTypeClass(); + + OUString aRetStr; + switch (eType) + { + case uno::TypeClass_TYPE: + { + auto xIdlClass = TypeToIdlClass(aValType, xContext); + aRetStr = xIdlClass->getName() + " <TYPE>"; + break; + } + case uno::TypeClass_INTERFACE: + { + auto xIdlClass = TypeToIdlClass(aValType, xContext); + aRetStr = xIdlClass->getName() + " <INTERFACE>"; + break; + } + case uno::TypeClass_SERVICE: + { + auto xIdlClass = TypeToIdlClass(aValType, xContext); + aRetStr = xIdlClass->getName() + " <SERVICE>"; + break; + } + case uno::TypeClass_STRUCT: + { + auto xIdlClass = TypeToIdlClass(aValType, xContext); + aRetStr = xIdlClass->getName() + " <STRUCT>"; + break; + } + case uno::TypeClass_TYPEDEF: + { + auto xIdlClass = TypeToIdlClass(aValType, xContext); + aRetStr = xIdlClass->getName() + " <TYPEDEF>"; + break; + } + case uno::TypeClass_ENUM: + { + auto xIdlClass = TypeToIdlClass(aValType, xContext); + aRetStr = xIdlClass->getName() + " <ENUM>"; + break; + } + case uno::TypeClass_EXCEPTION: + { + auto xIdlClass = TypeToIdlClass(aValType, xContext); + aRetStr = xIdlClass->getName() + " <EXCEPTION>"; + break; + } + case uno::TypeClass_SEQUENCE: + { + auto xIdlClass = TypeToIdlClass(aValType, xContext); + aRetStr = xIdlClass->getName() + " <SEQUENCE>"; + break; + } + case uno::TypeClass_VOID: + { + auto xIdlClass = TypeToIdlClass(aValType, xContext); + aRetStr = xIdlClass->getName() + " <VOID>"; + break; + } + case uno::TypeClass_ANY: + { + auto xIdlClass = TypeToIdlClass(aValType, xContext); + aRetStr = xIdlClass->getName() + " <ANY>"; + break; + } + case uno::TypeClass_UNKNOWN: + aRetStr = "<Unknown>"; + break; + case uno::TypeClass_BOOLEAN: + { + bool bBool = aValue.get<bool>(); + aRetStr = bBool ? u"True" : u"False"; + break; + } + case uno::TypeClass_CHAR: + { + sal_Unicode aChar = aValue.get<sal_Unicode>(); + aRetStr = OUString::number(aChar); + break; + } + case uno::TypeClass_STRING: + { + aRetStr = "\"" + aValue.get<OUString>() + "\""; + break; + } + case uno::TypeClass_FLOAT: + { + auto aNumber = aValue.get<float>(); + aRetStr = OUString::number(aNumber); + break; + } + case uno::TypeClass_DOUBLE: + { + auto aNumber = aValue.get<double>(); + aRetStr = OUString::number(aNumber); + break; + } + case uno::TypeClass_BYTE: + { + auto aNumber = aValue.get<sal_Int8>(); + aRetStr = OUString::number(aNumber); + break; + } + case uno::TypeClass_SHORT: + { + auto aNumber = aValue.get<sal_Int16>(); + aRetStr = OUString::number(aNumber); + break; + } + case uno::TypeClass_LONG: + { + auto aNumber = aValue.get<sal_Int32>(); + aRetStr = OUString::number(aNumber); + break; + } + case uno::TypeClass_HYPER: + { + auto aNumber = aValue.get<sal_Int64>(); + aRetStr = OUString::number(aNumber); + break; + } + + default: + break; + } + return aRetStr; +} + +// Object inspector nodes + +class ObjectInspectorNode +{ +public: + css::uno::Reference<css::uno::XInterface> mxObject; + + ObjectInspectorNode() = default; + + ObjectInspectorNode(css::uno::Reference<css::uno::XInterface> const& xObject) + : mxObject(xObject) + { + } + + virtual ~ObjectInspectorNode() {} + + virtual OUString getObjectName() = 0; + + virtual void fillChildren(std::unique_ptr<weld::TreeView>& rTree, weld::TreeIter const& rParent) + = 0; +}; + +OUString lclAppendNode(std::unique_ptr<weld::TreeView>& pTree, ObjectInspectorNode* pEntry, + bool bChildrenOnDemand = false) +{ + OUString sName = pEntry->getObjectName(); + OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pEntry))); + std::unique_ptr<weld::TreeIter> pCurrent = pTree->make_iterator(); + pTree->insert(nullptr, -1, &sName, &sId, nullptr, nullptr, bChildrenOnDemand, pCurrent.get()); + pTree->set_text_emphasis(*pCurrent, true, 0); + return sId; +} + +OUString lclAppendNodeToParent(std::unique_ptr<weld::TreeView>& pTree, + weld::TreeIter const& rParent, ObjectInspectorNode* pEntry, + bool bChildrenOnDemand = false) +{ + OUString sName = pEntry->getObjectName(); + OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pEntry))); + std::unique_ptr<weld::TreeIter> pCurrent = pTree->make_iterator(); + pTree->insert(&rParent, -1, &sName, &sId, nullptr, nullptr, bChildrenOnDemand, nullptr); + pTree->set_text_emphasis(*pCurrent, true, 0); + return sId; +} + +OUString lclAppendNodeWithIterToParent(std::unique_ptr<weld::TreeView>& pTree, + weld::TreeIter const& rParent, weld::TreeIter& rCurrent, + ObjectInspectorNode* pEntry, bool bChildrenOnDemand = false) +{ + OUString sName = pEntry->getObjectName(); + OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pEntry))); + pTree->insert(&rParent, -1, &sName, &sId, nullptr, nullptr, bChildrenOnDemand, &rCurrent); + pTree->set_text_emphasis(rCurrent, true, 0); + return sId; +} + +class ObjectInspectorNamedNode : public ObjectInspectorNode +{ +public: + OUString msName; + + ObjectInspectorNamedNode(OUString const& rName, + css::uno::Reference<css::uno::XInterface> const& xObject) + : ObjectInspectorNode(xObject) + , msName(rName) + { + } + + OUString getObjectName() override { return msName; } + + void fillChildren(std::unique_ptr<weld::TreeView>& /*rTree*/, + weld::TreeIter const& /*rParent*/) override + { + } +}; + +class ServicesNode : public ObjectInspectorNamedNode +{ +public: + ServicesNode(css::uno::Reference<css::uno::XInterface> const& xObject) + : ObjectInspectorNamedNode("Services", xObject) + { + } + + void fillChildren(std::unique_ptr<weld::TreeView>& pTree, + weld::TreeIter const& rParent) override + { + auto xServiceInfo = uno::Reference<lang::XServiceInfo>(mxObject, uno::UNO_QUERY); + const uno::Sequence<OUString> aServiceNames(xServiceInfo->getSupportedServiceNames()); + for (auto const& aServiceName : aServiceNames) + { + lclAppendNodeToParent(pTree, rParent, + new ObjectInspectorNamedNode(aServiceName, mxObject)); + } + } +}; + +class GenericPropertiesNode : public ObjectInspectorNamedNode +{ +public: + uno::Reference<uno::XComponentContext> mxContext; + + GenericPropertiesNode(OUString const& rName, uno::Reference<uno::XInterface> const& xObject, + uno::Reference<uno::XComponentContext> const& xContext) + : ObjectInspectorNamedNode(rName, xObject) + , mxContext(xContext) + { + } + + void fillChildren(std::unique_ptr<weld::TreeView>& pTree, + weld::TreeIter const& rParent) override + { + uno::Reference<beans::XIntrospection> xIntrospection + = beans::theIntrospection::get(mxContext); + auto xIntrospectionAccess = xIntrospection->inspect(uno::makeAny(mxObject)); + auto xInvocationFactory = css::script::Invocation::create(mxContext); + uno::Sequence<uno::Any> aParameters = { uno::Any(mxObject) }; + auto xInvocationInterface = xInvocationFactory->createInstanceWithArguments(aParameters); + uno::Reference<script::XInvocation> xInvocation(xInvocationInterface, uno::UNO_QUERY); + + const auto xProperties = xIntrospectionAccess->getProperties( + beans::PropertyConcept::ALL - beans::PropertyConcept::DANGEROUS); + + for (auto const& xProperty : xProperties) + { + OUString aValue; + uno::Any aAny; + uno::Reference<uno::XInterface> xCurrent = mxObject; + + try + { + if (xInvocation->hasProperty(xProperty.Name)) + { + aAny = xInvocation->getValue(xProperty.Name); + aValue = AnyToString(aAny, mxContext); + } + } + catch (...) + { + aValue = "<?>"; + } + + bool bComplex = false; + if (aAny.hasValue()) + { + auto xInterface = uno::Reference<uno::XInterface>(aAny, uno::UNO_QUERY); + if (xInterface.is()) + { + xCurrent = xInterface; + bComplex = true; + } + } + + std::unique_ptr<weld::TreeIter> pCurrent = pTree->make_iterator(); + if (bComplex) + { + lclAppendNodeWithIterToParent( + pTree, rParent, *pCurrent, + new GenericPropertiesNode(xProperty.Name, xCurrent, mxContext), true); + } + else + { + lclAppendNodeWithIterToParent( + pTree, rParent, *pCurrent, + new ObjectInspectorNamedNode(xProperty.Name, xCurrent), false); + } + + if (!aValue.isEmpty()) + { + pTree->set_text(*pCurrent, aValue, 1); + } + } + } +}; + +class PropertiesNode : public GenericPropertiesNode +{ +public: + PropertiesNode(uno::Reference<uno::XInterface> const& xObject, + uno::Reference<uno::XComponentContext> const& xContext) + : GenericPropertiesNode("Properties", xObject, xContext) + { + } +}; + +class InterfacesNode : public ObjectInspectorNamedNode +{ +public: + InterfacesNode(css::uno::Reference<css::uno::XInterface> const& xObject) + : ObjectInspectorNamedNode("Interfaces", xObject) + { + } + + void fillChildren(std::unique_ptr<weld::TreeView>& pTree, + weld::TreeIter const& rParent) override + { + uno::Reference<lang::XTypeProvider> xTypeProvider(mxObject, uno::UNO_QUERY); + if (xTypeProvider.is()) + { + const auto xSequenceTypes = xTypeProvider->getTypes(); + for (auto const& xType : xSequenceTypes) + { + OUString aName = xType.getTypeName(); + lclAppendNodeToParent(pTree, rParent, + new ObjectInspectorNamedNode(aName, mxObject)); + } + } + } +}; + +class MethodsNode : public ObjectInspectorNamedNode +{ +public: + uno::Reference<uno::XComponentContext> mxContext; + + MethodsNode(css::uno::Reference<css::uno::XInterface> const& xObject, + uno::Reference<uno::XComponentContext> const& xContext) + : ObjectInspectorNamedNode("Methods", xObject) + , mxContext(xContext) + { + } + + void fillChildren(std::unique_ptr<weld::TreeView>& pTree, + weld::TreeIter const& rParent) override + { + uno::Reference<beans::XIntrospection> xIntrospection + = beans::theIntrospection::get(mxContext); + auto xIntrospectionAccess = xIntrospection->inspect(uno::makeAny(mxObject)); + + const auto xMethods = xIntrospectionAccess->getMethods(beans::MethodConcept::ALL); + for (auto const& xMethod : xMethods) + { + OUString aMethodName = xMethod->getName(); + + lclAppendNodeToParent(pTree, rParent, + new ObjectInspectorNamedNode(aMethodName, mxObject)); + } + } +}; + +} // end anonymous namespace + +IMPL_LINK(ObjectInspectorTreeHandler, ExpandingHandler, weld::TreeIter const&, rParent, bool) +{ + OUString sID = mpObjectInspectorTree->get_id(rParent); + if (sID.isEmpty()) + return true; + + clearObjectInspectorChildren(rParent); + auto* pNode = reinterpret_cast<ObjectInspectorNode*>(sID.toInt64()); + pNode->fillChildren(mpObjectInspectorTree, rParent); + + return true; +} + +void ObjectInspectorTreeHandler::clearObjectInspectorChildren(weld::TreeIter const& rParent) +{ + bool bChild = false; + do + { + bChild = mpObjectInspectorTree->iter_has_child(rParent); + if (bChild) + { + std::unique_ptr<weld::TreeIter> pChild = mpObjectInspectorTree->make_iterator(&rParent); + bChild = mpObjectInspectorTree->iter_children(*pChild); + if (bChild) + { + clearObjectInspectorChildren(*pChild); + OUString sID = mpObjectInspectorTree->get_id(*pChild); + auto* pEntry = reinterpret_cast<ObjectInspectorNode*>(sID.toInt64()); + delete pEntry; + mpObjectInspectorTree->remove(*pChild); + } + } + } while (bChild); +} + +void ObjectInspectorTreeHandler::introspect(uno::Reference<uno::XInterface> const& xInterface) +{ + if (!xInterface.is()) + return; + + uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext(); + if (!xContext.is()) + return; + + // Set implementation name + auto xServiceInfo = uno::Reference<lang::XServiceInfo>(xInterface, uno::UNO_QUERY); + OUString aImplementationName = xServiceInfo->getImplementationName(); + mpClassNameLabel->set_label(aImplementationName); + + // fill object inspector + mpObjectInspectorTree->freeze(); + mpObjectInspectorTree->clear(); + + lclAppendNode(mpObjectInspectorTree, new ServicesNode(xInterface), true); + lclAppendNode(mpObjectInspectorTree, new InterfacesNode(xInterface), true); + lclAppendNode(mpObjectInspectorTree, new PropertiesNode(xInterface, xContext), true); + lclAppendNode(mpObjectInspectorTree, new MethodsNode(xInterface, xContext), true); + + mpObjectInspectorTree->thaw(); +} + +void ObjectInspectorTreeHandler::dispose() +{ + // destroy all ObjectInspectorNodes from the tree + mpObjectInspectorTree->all_foreach([this](weld::TreeIter& rEntry) { + OUString sID = mpObjectInspectorTree->get_id(rEntry); + auto* pEntry = reinterpret_cast<ObjectInspectorNode*>(sID.toInt64()); + delete pEntry; + return false; + }); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |