/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace css; namespace { constexpr OUStringLiteral constTypeDescriptionManagerSingletonName = u"/singletons/com.sun.star.reflection.theTypeDescriptionManager"; OUString AnyToString(const uno::Any& aValue, const uno::Reference& xContext) { OUString aRetStr; // return early if we don't have any value if (!aValue.hasValue()) return "NULL"; uno::Type aValType = aValue.getValueType(); uno::TypeClass eType = aValType.getTypeClass(); switch (eType) { case uno::TypeClass_INTERFACE: { uno::Reference xInterface(aValue, uno::UNO_QUERY); if (!xInterface.is()) aRetStr = "NULL"; else aRetStr = ""; break; } case uno::TypeClass_STRUCT: { aRetStr = ""; break; } case uno::TypeClass_BOOLEAN: { bool bBool = aValue.get(); aRetStr = bBool ? u"True" : u"False"; break; } case uno::TypeClass_CHAR: { sal_Unicode aChar = aValue.get(); aRetStr = OUString::number(aChar); break; } case uno::TypeClass_STRING: { aRetStr = "\"" + aValue.get() + "\""; break; } case uno::TypeClass_FLOAT: { auto aNumber = aValue.get(); aRetStr = OUString::number(aNumber); break; } case uno::TypeClass_DOUBLE: { auto aNumber = aValue.get(); aRetStr = OUString::number(aNumber); break; } case uno::TypeClass_BYTE: { auto aNumber = aValue.get(); aRetStr = OUString::number(aNumber); break; } case uno::TypeClass_SHORT: { auto aNumber = aValue.get(); aRetStr = OUString::number(aNumber); break; } case uno::TypeClass_LONG: { auto aNumber = aValue.get(); aRetStr = OUString::number(aNumber); break; } case uno::TypeClass_HYPER: { auto aNumber = aValue.get(); aRetStr = OUString::number(aNumber); break; } case uno::TypeClass_UNSIGNED_SHORT: { auto aNumber = aValue.get(); aRetStr = OUString::number(aNumber); break; } case uno::TypeClass_UNSIGNED_LONG: { auto aNumber = aValue.get(); aRetStr = OUString::number(aNumber); break; } case uno::TypeClass_UNSIGNED_HYPER: { auto aNumber = aValue.get(); aRetStr = OUString::number(aNumber); break; } case uno::TypeClass_TYPE: { auto aType = aValue.get(); aRetStr = aType.getTypeName(); break; } case uno::TypeClass_ENUM: { sal_Int32 nIntValue = 0; if (cppu::enum2int(nIntValue, aValue)) { uno::Reference xManager; xManager.set(xContext->getValueByName(constTypeDescriptionManagerSingletonName), uno::UNO_QUERY); uno::Reference xTypeDescription; xTypeDescription.set(xManager->getByHierarchicalName(aValType.getTypeName()), uno::UNO_QUERY); uno::Sequence aValues = xTypeDescription->getEnumValues(); sal_Int32 nValuesIndex = std::find(aValues.begin(), aValues.end(), nIntValue) - aValues.begin(); uno::Sequence aNames = xTypeDescription->getEnumNames(); aRetStr = aNames[nValuesIndex]; } break; } default: break; } return aRetStr; } OUString getAnyType(const uno::Any& aValue) { OUString aTypeName = aValue.getValueType().getTypeName(); return aTypeName.replaceAll("com.sun.star", "css"); } // Object inspector nodes class ObjectInspectorNodeInterface { public: ObjectInspectorNodeInterface() = default; virtual ~ObjectInspectorNodeInterface() {} virtual OUString getObjectName() = 0; virtual bool shouldShowExpander() { return false; } virtual void fillChildren(std::unique_ptr& rTree, const weld::TreeIter* pParent) = 0; virtual std::vector> getColumnValues() { return std::vector>(); } }; OUString lclAppendNode(std::unique_ptr& pTree, ObjectInspectorNodeInterface* pEntry) { OUString sName = pEntry->getObjectName(); OUString sId(OUString::number(reinterpret_cast(pEntry))); std::unique_ptr pCurrent = pTree->make_iterator(); pTree->insert(nullptr, -1, &sName, &sId, nullptr, nullptr, pEntry->shouldShowExpander(), pCurrent.get()); pTree->set_text_emphasis(*pCurrent, true, 0); for (auto const& rPair : pEntry->getColumnValues()) { pTree->set_text(*pCurrent, rPair.second, rPair.first); } return sId; } OUString lclAppendNodeToParent(std::unique_ptr& pTree, const weld::TreeIter* pParent, ObjectInspectorNodeInterface* pEntry) { OUString sName = pEntry->getObjectName(); OUString sId(OUString::number(reinterpret_cast(pEntry))); std::unique_ptr pCurrent = pTree->make_iterator(); pTree->insert(pParent, -1, &sName, &sId, nullptr, nullptr, pEntry->shouldShowExpander(), pCurrent.get()); pTree->set_text_emphasis(*pCurrent, true, 0); for (auto const& rPair : pEntry->getColumnValues()) { pTree->set_text(*pCurrent, rPair.second, rPair.first); } return sId; } class SimpleStringNode : public ObjectInspectorNodeInterface { protected: OUString msName; public: SimpleStringNode(OUString const& rName) : msName(rName) { } void fillChildren(std::unique_ptr& /*rTree*/, const weld::TreeIter* /*pParent*/) override { } OUString getObjectName() override { return msName; } }; class MethodNode : public ObjectInspectorNodeInterface { private: uno::Reference mxMethod; public: MethodNode(uno::Reference const& xMethod) : mxMethod(xMethod) { } OUString getObjectName() override { return mxMethod->getName(); } static OUString simpleTypeName(uno::Reference const& xClass) { switch (xClass->getTypeClass()) { case uno::TypeClass_INTERFACE: return "object"; case uno::TypeClass_STRUCT: return "struct"; case uno::TypeClass_ENUM: return "enum"; case uno::TypeClass_SEQUENCE: return "sequence"; default: break; } return xClass->getName(); } std::vector> getColumnValues() override { OUString aOutString; auto xClass = mxMethod->getReturnType(); aOutString = simpleTypeName(xClass); OUString aInString; const auto aParameters = mxMethod->getParameterInfos(); bool bFirst = true; for (auto const& rParameterInfo : aParameters) { if (!bFirst) aInString += ", "; else bFirst = false; switch (rParameterInfo.aMode) { case reflection::ParamMode_IN: aInString += "[in] "; break; case reflection::ParamMode_OUT: aInString += "[out] "; break; case reflection::ParamMode_INOUT: aInString += "[in&out] "; break; default: break; } aInString += rParameterInfo.aName + " : " + simpleTypeName(rParameterInfo.aType); } OUString aImplementationClass = mxMethod->getDeclaringClass()->getName(); return { { 1, aOutString }, { 2, aInString }, { 3, aImplementationClass }, }; } void fillChildren(std::unique_ptr& /*rTree*/, const weld::TreeIter* /*pParent*/) override { } }; class BasicValueNode : public SimpleStringNode { protected: uno::Any maAny; OUString mrInfo; uno::Reference mxContext; ObjectInspectorNodeInterface* createNodeObjectForAny(OUString const& rName, uno::Any& rAny, OUString const& mrInfo); public: BasicValueNode(OUString const& rName, uno::Any const& rAny, OUString const& rInfo, uno::Reference const& xContext) : SimpleStringNode(rName) , maAny(rAny) , mrInfo(rInfo) , mxContext(xContext) { } uno::Any getAny() { return maAny; } bool shouldShowExpander() override { if (maAny.hasValue()) { switch (maAny.getValueType().getTypeClass()) { case uno::TypeClass_INTERFACE: { uno::Reference xInterface(maAny, uno::UNO_QUERY); return xInterface.is(); } case uno::TypeClass_SEQUENCE: return true; default: break; } } return false; } std::vector> getColumnValues() override { OUString aValue = AnyToString(maAny, mxContext); OUString aType = getAnyType(maAny); return { { 1, aValue }, { 2, aType }, { 3, mrInfo } }; } }; class GenericPropertiesNode : public BasicValueNode { public: GenericPropertiesNode(OUString const& rName, uno::Any const& rAny, OUString const& rInfo, uno::Reference const& xContext) : BasicValueNode(rName, rAny, rInfo, xContext) { } void fillChildren(std::unique_ptr& pTree, const weld::TreeIter* pParent) override; }; class StructNode : public BasicValueNode { public: StructNode(OUString const& rName, uno::Any const& rAny, OUString const& rInfo, uno::Reference const& xContext) : BasicValueNode(rName, rAny, rInfo, xContext) { } bool shouldShowExpander() override { return true; } void fillChildren(std::unique_ptr& pTree, const weld::TreeIter* pParent) override; }; class SequenceNode : public BasicValueNode { uno::Reference mxIdlArray; public: SequenceNode(OUString const& rName, uno::Any const& rAny, OUString const& rInfo, uno::Reference const& xContext) : BasicValueNode(rName, rAny, rInfo, xContext) { auto xReflection = reflection::theCoreReflection::get(mxContext); OUString aTypeName = maAny.getValueType().getTypeName(); auto xClass = xReflection->forName(aTypeName); mxIdlArray = xClass->getArray(); } bool shouldShowExpander() override { // Show expnder only if the sequence has elements int nLength = mxIdlArray->getLen(maAny); return nLength > 0; } void fillChildren(std::unique_ptr& pTree, const weld::TreeIter* pParent) override { int nLength = mxIdlArray->getLen(maAny); for (int i = 0; i < nLength; i++) { uno::Any aArrayValue = mxIdlArray->get(maAny, i); uno::Reference xCurrent; auto* pObjectInspectorNode = createNodeObjectForAny(OUString::number(i), aArrayValue, ""); if (pObjectInspectorNode) lclAppendNodeToParent(pTree, pParent, pObjectInspectorNode); } } std::vector> getColumnValues() override { int nLength = mxIdlArray->getLen(maAny); OUString aValue = ""; OUString aType = getAnyType(maAny).replaceAll(u"[]", u""); aType += u"[" + OUString::number(nLength) + u"]"; return { { 1, aValue }, { 2, aType }, }; } }; void GenericPropertiesNode::fillChildren(std::unique_ptr& pTree, const weld::TreeIter* pParent) { if (!maAny.hasValue()) return; const auto xNameAccess = uno::Reference(maAny, uno::UNO_QUERY); if (xNameAccess.is()) { const uno::Sequence aNames = xNameAccess->getElementNames(); for (OUString const& rName : aNames) { uno::Any aAny = xNameAccess->getByName(rName); auto* pObjectInspectorNode = createNodeObjectForAny(u"@" + rName, aAny, u"name container"); lclAppendNodeToParent(pTree, pParent, pObjectInspectorNode); } } const auto xIndexAccess = uno::Reference(maAny, uno::UNO_QUERY); if (xIndexAccess.is()) { for (sal_Int32 nIndex = 0; nIndex < xIndexAccess->getCount(); ++nIndex) { uno::Any aAny = xIndexAccess->getByIndex(nIndex); auto* pObjectInspectorNode = createNodeObjectForAny(u"@" + OUString::number(nIndex), aAny, u"index container"); lclAppendNodeToParent(pTree, pParent, pObjectInspectorNode); } } const auto xEnumAccess = uno::Reference(maAny, uno::UNO_QUERY); if (xEnumAccess.is()) { uno::Reference xEnumeration = xEnumAccess->createEnumeration(); if (xEnumeration.is()) { for (sal_Int32 nIndex = 0; xEnumeration->hasMoreElements(); nIndex++) { uno::Any aAny = xEnumeration->nextElement(); auto* pObjectInspectorNode = createNodeObjectForAny(u"@" + OUString::number(nIndex), aAny, u"enumeration"); lclAppendNodeToParent(pTree, pParent, pObjectInspectorNode); } } } auto xInvocationFactory = css::script::Invocation::create(mxContext); uno::Sequence aParameters = { maAny }; auto xInvocationInterface = xInvocationFactory->createInstanceWithArguments(aParameters); if (!xInvocationInterface.is()) return; uno::Reference xInvocation(xInvocationInterface, uno::UNO_QUERY); if (!xInvocation.is()) return; const auto xInvocationAccess = xInvocation->getIntrospection(); const auto aInvocationInfoSequence = xInvocation->getInfo(); for (auto const& aInvocationInfo : aInvocationInfoSequence) { if (aInvocationInfo.eMemberType == script::MemberType_PROPERTY) { uno::Any aCurrentAny; auto const& aPropertyName = aInvocationInfo.aName; bool bIsAttribute = false; bool bIsGetSetMethod = false; bool bMethodGet = false; bool bMethodSet = false; bool bMethodIs = false; try { aCurrentAny = xInvocation->getValue(aPropertyName); bIsAttribute = xInvocationAccess->hasProperty(aPropertyName, beans::PropertyConcept::ATTRIBUTES); bIsGetSetMethod = xInvocationAccess->hasProperty(aPropertyName, beans::PropertyConcept::METHODS); if (bIsGetSetMethod) { bMethodGet = xInvocationAccess->hasMethod(u"get" + aPropertyName, beans::MethodConcept::PROPERTY); bMethodSet = xInvocationAccess->hasMethod(u"set" + aPropertyName, beans::MethodConcept::PROPERTY); bMethodIs = xInvocationAccess->hasMethod(u"is" + aPropertyName, beans::MethodConcept::PROPERTY); } } catch (...) { } std::vector aInfoCollection; if (bIsAttribute) aInfoCollection.push_back(u"attribute"); if (bIsGetSetMethod) { bool bSet = false; OUString aString; if (bMethodGet || bMethodIs) { aString += u"get"; bSet = true; } if (bMethodSet) { if (bSet) aString += u", "; aString += u"set"; } aInfoCollection.push_back(u"(" + aString + u")"); } if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::MAYBEVOID) aInfoCollection.push_back(u"may be void"); if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::READONLY) aInfoCollection.push_back(u"read-only"); if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::REMOVABLE) aInfoCollection.push_back(u"removeable"); if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::BOUND) aInfoCollection.push_back(u"bound"); if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::CONSTRAINED) aInfoCollection.push_back(u"constrained"); if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::TRANSIENT) aInfoCollection.push_back(u"transient"); if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::MAYBEAMBIGUOUS) aInfoCollection.push_back(u"may be ambiguous"); if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::MAYBEDEFAULT) aInfoCollection.push_back(u"may be default"); bool bSet = false; OUString aInfoString; for (auto const& rString : aInfoCollection) { if (bSet) aInfoString += ", "; else bSet = true; aInfoString += rString; } auto* pObjectInspectorNode = createNodeObjectForAny(aPropertyName, aCurrentAny, aInfoString); if (pObjectInspectorNode) lclAppendNodeToParent(pTree, pParent, pObjectInspectorNode); } } } void StructNode::fillChildren(std::unique_ptr& pTree, const weld::TreeIter* pParent) { auto xReflection = reflection::theCoreReflection::get(mxContext); uno::Reference xClass = xReflection->forName(maAny.getValueType().getTypeName()); const auto xFields = xClass->getFields(); for (auto const& xField : xFields) { OUString aFieldName = xField->getName(); uno::Any aFieldValue = xField->get(maAny); auto* pObjectInspectorNode = createNodeObjectForAny(aFieldName, aFieldValue, ""); if (pObjectInspectorNode) { lclAppendNodeToParent(pTree, pParent, pObjectInspectorNode); } } } ObjectInspectorNodeInterface* BasicValueNode::createNodeObjectForAny(OUString const& rName, uno::Any& rAny, OUString const& rInfo) { switch (rAny.getValueType().getTypeClass()) { case uno::TypeClass_INTERFACE: return new GenericPropertiesNode(rName, rAny, rInfo, mxContext); case uno::TypeClass_SEQUENCE: return new SequenceNode(rName, rAny, rInfo, mxContext); case uno::TypeClass_STRUCT: return new StructNode(rName, rAny, rInfo, mxContext); default: break; } return new BasicValueNode(rName, rAny, rInfo, mxContext); } // helper functions ObjectInspectorNodeInterface* getSelectedNode(weld::TreeView const& rTreeView) { OUString sID = rTreeView.get_selected_id(); if (sID.isEmpty()) return nullptr; if (auto* pNode = reinterpret_cast(sID.toInt64())) return pNode; return nullptr; } uno::Reference getSelectedXInterface(weld::TreeView const& rTreeView) { uno::Reference xInterface; if (auto* pNode = getSelectedNode(rTreeView)) { if (auto* pBasicValueNode = dynamic_cast(pNode)) { uno::Any aAny = pBasicValueNode->getAny(); xInterface.set(aAny, uno::UNO_QUERY); } } return xInterface; } } // end anonymous namespace ObjectInspectorTreeHandler::ObjectInspectorTreeHandler( std::unique_ptr& pInterfacesTreeView, std::unique_ptr& pServicesTreeView, std::unique_ptr& pPropertiesTreeView, std::unique_ptr& pMethodsTreeView, std::unique_ptr& pClassNameLabel, std::unique_ptr& pObjectInspectorToolbar, std::unique_ptr& pObjectInspectorNotebook) : mpInterfacesTreeView(pInterfacesTreeView) , mpServicesTreeView(pServicesTreeView) , mpPropertiesTreeView(pPropertiesTreeView) , mpMethodsTreeView(pMethodsTreeView) , mpClassNameLabel(pClassNameLabel) , mpObjectInspectorToolbar(pObjectInspectorToolbar) , mpObjectInspectorNotebook(pObjectInspectorNotebook) { mpInterfacesTreeView->connect_expanding( LINK(this, ObjectInspectorTreeHandler, ExpandingHandlerInterfaces)); mpServicesTreeView->connect_expanding( LINK(this, ObjectInspectorTreeHandler, ExpandingHandlerServices)); mpPropertiesTreeView->connect_expanding( LINK(this, ObjectInspectorTreeHandler, ExpandingHandlerProperties)); mpMethodsTreeView->connect_expanding( LINK(this, ObjectInspectorTreeHandler, ExpandingHandlerMethods)); mpPropertiesTreeView->connect_popup_menu( LINK(this, ObjectInspectorTreeHandler, PopupMenuHandler)); mpInterfacesTreeView->connect_changed(LINK(this, ObjectInspectorTreeHandler, SelectionChanged)); mpServicesTreeView->connect_changed(LINK(this, ObjectInspectorTreeHandler, SelectionChanged)); mpPropertiesTreeView->connect_changed(LINK(this, ObjectInspectorTreeHandler, SelectionChanged)); mpMethodsTreeView->connect_changed(LINK(this, ObjectInspectorTreeHandler, SelectionChanged)); mpInterfacesTreeView->make_sorted(); mpServicesTreeView->make_sorted(); mpPropertiesTreeView->make_sorted(); mpMethodsTreeView->make_sorted(); mpObjectInspectorToolbar->connect_clicked( LINK(this, ObjectInspectorTreeHandler, ToolbarButtonClicked)); mpObjectInspectorToolbar->set_item_sensitive("inspect", false); mpObjectInspectorToolbar->set_item_sensitive("back", false); mpObjectInspectorNotebook->connect_leave_page( LINK(this, ObjectInspectorTreeHandler, NotebookLeavePage)); mpObjectInspectorNotebook->connect_enter_page( LINK(this, ObjectInspectorTreeHandler, NotebookEnterPage)); } void ObjectInspectorTreeHandler::handleExpanding(std::unique_ptr& pTreeView, weld::TreeIter const& rParent) { OUString sID = pTreeView->get_id(rParent); if (sID.isEmpty()) return; clearObjectInspectorChildren(pTreeView, rParent); auto* pNode = reinterpret_cast(sID.toInt64()); pNode->fillChildren(pTreeView, &rParent); } IMPL_LINK(ObjectInspectorTreeHandler, ExpandingHandlerInterfaces, weld::TreeIter const&, rParent, bool) { handleExpanding(mpInterfacesTreeView, rParent); return true; } IMPL_LINK(ObjectInspectorTreeHandler, ExpandingHandlerServices, weld::TreeIter const&, rParent, bool) { handleExpanding(mpServicesTreeView, rParent); return true; } IMPL_LINK(ObjectInspectorTreeHandler, ExpandingHandlerProperties, weld::TreeIter const&, rParent, bool) { handleExpanding(mpPropertiesTreeView, rParent); return true; } IMPL_LINK(ObjectInspectorTreeHandler, ExpandingHandlerMethods, weld::TreeIter const&, rParent, bool) { handleExpanding(mpMethodsTreeView, rParent); return true; } IMPL_LINK(ObjectInspectorTreeHandler, SelectionChanged, weld::TreeView&, rTreeView, void) { bool bHaveNodeWithObject = false; if (mpPropertiesTreeView.get() == &rTreeView) { auto* pNode = getSelectedNode(rTreeView); if (auto* pBasicValueNode = dynamic_cast(pNode)) { uno::Any aAny = pBasicValueNode->getAny(); uno::Reference xInterface(aAny, uno::UNO_QUERY); bHaveNodeWithObject = xInterface.is(); } } mpObjectInspectorToolbar->set_item_sensitive("inspect", bHaveNodeWithObject); } IMPL_LINK(ObjectInspectorTreeHandler, PopupMenuHandler, const CommandEvent&, rCommandEvent, bool) { if (rCommandEvent.GetCommand() != CommandEventId::ContextMenu) return false; auto xInterface = getSelectedXInterface(*mpPropertiesTreeView); if (xInterface.is()) { std::unique_ptr xBuilder( Application::CreateBuilder(mpPropertiesTreeView.get(), "sfx/ui/devtoolsmenu.ui")); std::unique_ptr xMenu(xBuilder->weld_menu("inspect_menu")); OString sCommand( xMenu->popup_at_rect(mpPropertiesTreeView.get(), tools::Rectangle(rCommandEvent.GetMousePosPixel(), Size(1, 1)))); if (sCommand == "inspect") { addToStack(uno::Any(xInterface)); inspectObject(xInterface); } } return true; } IMPL_LINK(ObjectInspectorTreeHandler, ToolbarButtonClicked, const OString&, rSelectionId, void) { if (rSelectionId == "inspect") { auto xInterface = getSelectedXInterface(*mpPropertiesTreeView); if (xInterface.is()) { addToStack(uno::Any(xInterface)); inspectObject(xInterface); } } else if (rSelectionId == "back") { uno::Any aAny = popFromStack(); if (aAny.hasValue()) { uno::Reference xInterface(aAny, uno::UNO_QUERY); inspectObject(xInterface); } } else if (rSelectionId == "refresh") { auto rPageId = mpObjectInspectorNotebook->get_current_page_ident(); NotebookEnterPage(rPageId); } } IMPL_LINK(ObjectInspectorTreeHandler, NotebookEnterPage, const OString&, rPageId, void) { uno::Any aAny = maInspectionStack.back(); if (aAny.hasValue()) { uno::Reference xInterface(aAny, uno::UNO_QUERY); if (rPageId == "object_inspector_interfaces_tab") { mpInterfacesTreeView->freeze(); clearAll(mpInterfacesTreeView); appendInterfaces(xInterface); mpInterfacesTreeView->thaw(); } else if (rPageId == "object_inspector_services_tab") { mpServicesTreeView->freeze(); clearAll(mpServicesTreeView); appendServices(xInterface); mpServicesTreeView->thaw(); } else if (rPageId == "object_inspector_properties_tab") { mpPropertiesTreeView->freeze(); clearAll(mpPropertiesTreeView); appendProperties(xInterface); mpPropertiesTreeView->thaw(); } else if (rPageId == "object_inspector_methods_tab") { mpMethodsTreeView->freeze(); clearAll(mpMethodsTreeView); appendMethods(xInterface); mpMethodsTreeView->thaw(); } } } IMPL_LINK(ObjectInspectorTreeHandler, NotebookLeavePage, const OString&, rPageId, bool) { if (rPageId == "object_inspector_interfaces_tab") { mpInterfacesTreeView->freeze(); clearAll(mpInterfacesTreeView); mpInterfacesTreeView->thaw(); } else if (rPageId == "object_inspector_services_tab") { mpServicesTreeView->freeze(); clearAll(mpServicesTreeView); mpServicesTreeView->thaw(); } else if (rPageId == "object_inspector_properties_tab") { mpPropertiesTreeView->freeze(); clearAll(mpPropertiesTreeView); mpPropertiesTreeView->thaw(); } else if (rPageId == "object_inspector_methods_tab") { mpMethodsTreeView->freeze(); clearAll(mpMethodsTreeView); mpMethodsTreeView->thaw(); } return true; } void ObjectInspectorTreeHandler::clearObjectInspectorChildren( std::unique_ptr& pTreeView, weld::TreeIter const& rParent) { bool bChild = false; do { bChild = pTreeView->iter_has_child(rParent); if (bChild) { std::unique_ptr pChild = pTreeView->make_iterator(&rParent); bChild = pTreeView->iter_children(*pChild); if (bChild) { clearObjectInspectorChildren(pTreeView, *pChild); OUString sID = pTreeView->get_id(*pChild); auto* pEntry = reinterpret_cast(sID.toInt64()); delete pEntry; pTreeView->remove(*pChild); } } } while (bChild); } void ObjectInspectorTreeHandler::clearAll(std::unique_ptr& pTreeView) { // destroy all ObjectInspectorNodes from the tree pTreeView->all_foreach([&pTreeView](weld::TreeIter& rEntry) { OUString sID = pTreeView->get_id(rEntry); auto* pEntry = reinterpret_cast(sID.toInt64()); delete pEntry; return false; }); pTreeView->clear(); } void ObjectInspectorTreeHandler::appendInterfaces(uno::Reference const& xInterface) { if (!xInterface.is()) return; uno::Reference xTypeProvider(xInterface, uno::UNO_QUERY); if (xTypeProvider.is()) { const auto xSequenceTypes = xTypeProvider->getTypes(); for (auto const& xType : xSequenceTypes) { OUString aName = xType.getTypeName(); lclAppendNode(mpInterfacesTreeView, new SimpleStringNode(aName)); } } } void ObjectInspectorTreeHandler::appendServices(uno::Reference const& xInterface) { if (!xInterface.is()) return; auto xServiceInfo = uno::Reference(xInterface, uno::UNO_QUERY); const uno::Sequence aServiceNames(xServiceInfo->getSupportedServiceNames()); for (auto const& aServiceName : aServiceNames) { lclAppendNode(mpServicesTreeView, new SimpleStringNode(aServiceName)); } } void ObjectInspectorTreeHandler::appendProperties(uno::Reference const& xInterface) { if (!xInterface.is()) return; GenericPropertiesNode aNode("", uno::Any(xInterface), "", comphelper::getProcessComponentContext()); aNode.fillChildren(mpPropertiesTreeView, nullptr); } void ObjectInspectorTreeHandler::appendMethods(uno::Reference const& xInterface) { if (!xInterface.is()) return; uno::Reference xIntrospection = beans::theIntrospection::get(comphelper::getProcessComponentContext()); auto xIntrospectionAccess = xIntrospection->inspect(uno::Any(xInterface)); const auto xMethods = xIntrospectionAccess->getMethods(beans::MethodConcept::ALL); for (auto const& xMethod : xMethods) { lclAppendNode(mpMethodsTreeView, new MethodNode(xMethod)); } } void ObjectInspectorTreeHandler::updateBackButtonState() { mpObjectInspectorToolbar->set_item_sensitive("back", maInspectionStack.size() > 1); } void ObjectInspectorTreeHandler::clearStack() { maInspectionStack.clear(); updateBackButtonState(); } void ObjectInspectorTreeHandler::addToStack(css::uno::Any const& rAny) { maInspectionStack.push_back(rAny); updateBackButtonState(); } css::uno::Any ObjectInspectorTreeHandler::popFromStack() { maInspectionStack.pop_back(); uno::Any aAny = maInspectionStack.back(); updateBackButtonState(); return aAny; } void ObjectInspectorTreeHandler::inspectObject(uno::Reference const& xInterface) { if (!xInterface.is()) return; uno::Reference xContext = comphelper::getProcessComponentContext(); if (!xContext.is()) return; // Set implementation name auto xServiceInfo = uno::Reference(xInterface, uno::UNO_QUERY); OUString aImplementationName = xServiceInfo->getImplementationName(); mpClassNameLabel->set_label(aImplementationName); auto rPageId = mpObjectInspectorNotebook->get_current_page_ident(); NotebookEnterPage(rPageId); } void ObjectInspectorTreeHandler::introspect(uno::Reference const& xInterface) { clearStack(); addToStack(uno::Any(xInterface)); inspectObject(xInterface); } void ObjectInspectorTreeHandler::dispose() { clearAll(mpInterfacesTreeView); clearAll(mpServicesTreeView); clearAll(mpPropertiesTreeView); clearAll(mpMethodsTreeView); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */