/* -*- 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 using namespace css; namespace { uno::Reference TypeToIdlClass(const uno::Type& rType, const uno::Reference& xContext) { auto xReflection = reflection::theCoreReflection::get(xContext); uno::Reference 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) { uno::Type aValType = aValue.getValueType(); uno::TypeClass eType = aValType.getTypeClass(); OUString aRetStr; switch (eType) { 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; } default: break; } return aRetStr; } OUString getAnyType(const uno::Any& aValue, const uno::Reference& xContext) { uno::Type aValType = aValue.getValueType(); auto xIdlClass = TypeToIdlClass(aValType, xContext); return xIdlClass->getName(); } // Object inspector nodes class ObjectInspectorNodeInterface { public: ObjectInspectorNodeInterface() = default; virtual ~ObjectInspectorNodeInterface() {} virtual OUString getObjectName() = 0; virtual void fillChildren(std::unique_ptr& rTree, weld::TreeIter const& rParent) = 0; }; class ObjectInspectorNode : public ObjectInspectorNodeInterface { public: css::uno::Reference mxObject; ObjectInspectorNode() = default; ObjectInspectorNode(css::uno::Reference const& xObject) : mxObject(xObject) { } }; OUString lclAppendNode(std::unique_ptr& pTree, ObjectInspectorNodeInterface* pEntry, bool bChildrenOnDemand = false) { 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, bChildrenOnDemand, pCurrent.get()); pTree->set_text_emphasis(*pCurrent, true, 0); return sId; } OUString lclAppendNodeToParent(std::unique_ptr& pTree, weld::TreeIter const& rParent, ObjectInspectorNodeInterface* pEntry, bool bChildrenOnDemand = false) { OUString sName = pEntry->getObjectName(); OUString sId(OUString::number(reinterpret_cast(pEntry))); std::unique_ptr pCurrent = pTree->make_iterator(); pTree->insert(&rParent, -1, &sName, &sId, nullptr, nullptr, bChildrenOnDemand, pCurrent.get()); pTree->set_text_emphasis(*pCurrent, true, 0); return sId; } OUString lclAppendNodeWithIterToParent(std::unique_ptr& pTree, weld::TreeIter const& rParent, weld::TreeIter& rCurrent, ObjectInspectorNodeInterface* pEntry, bool bChildrenOnDemand = false) { OUString sName = pEntry->getObjectName(); OUString sId(OUString::number(reinterpret_cast(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 const& xObject) : ObjectInspectorNode(xObject) , msName(rName) { } OUString getObjectName() override { return msName; } void fillChildren(std::unique_ptr& /*rTree*/, weld::TreeIter const& /*rParent*/) override { } }; class ServicesNode : public ObjectInspectorNamedNode { public: ServicesNode(css::uno::Reference const& xObject) : ObjectInspectorNamedNode("Services", xObject) { } void fillChildren(std::unique_ptr& pTree, weld::TreeIter const& rParent) override { auto xServiceInfo = uno::Reference(mxObject, uno::UNO_QUERY); const uno::Sequence aServiceNames(xServiceInfo->getSupportedServiceNames()); for (auto const& aServiceName : aServiceNames) { lclAppendNodeToParent(pTree, rParent, new ObjectInspectorNamedNode(aServiceName, mxObject)); } } }; class GenericPropertiesNode : public ObjectInspectorNamedNode { public: uno::Reference mxContext; GenericPropertiesNode(OUString const& rName, uno::Reference const& xObject, uno::Reference const& xContext) : ObjectInspectorNamedNode(rName, xObject) , mxContext(xContext) { } void fillChildren(std::unique_ptr& pTree, weld::TreeIter const& rParent) override; }; class PropertiesNode : public GenericPropertiesNode { public: PropertiesNode(uno::Reference const& xObject, uno::Reference const& xContext) : GenericPropertiesNode("Properties", xObject, xContext) { } }; class InterfacesNode : public ObjectInspectorNamedNode { public: InterfacesNode(css::uno::Reference const& xObject) : ObjectInspectorNamedNode("Interfaces", xObject) { } void fillChildren(std::unique_ptr& pTree, weld::TreeIter const& rParent) override { uno::Reference 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 mxContext; MethodsNode(css::uno::Reference const& xObject, uno::Reference const& xContext) : ObjectInspectorNamedNode("Methods", xObject) , mxContext(xContext) { } void fillChildren(std::unique_ptr& pTree, weld::TreeIter const& rParent) override { uno::Reference 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)); } } }; void GenericPropertiesNode::fillChildren(std::unique_ptr& pTree, weld::TreeIter const& rParent) { uno::Reference xIntrospection = beans::theIntrospection::get(mxContext); auto xIntrospectionAccess = xIntrospection->inspect(uno::makeAny(mxObject)); auto xInvocationFactory = css::script::Invocation::create(mxContext); uno::Sequence aParameters = { uno::Any(mxObject) }; auto xInvocationInterface = xInvocationFactory->createInstanceWithArguments(aParameters); uno::Reference xInvocation(xInvocationInterface, uno::UNO_QUERY); const auto xProperties = xIntrospectionAccess->getProperties( beans::PropertyConcept::ALL - beans::PropertyConcept::DANGEROUS); for (auto const& xProperty : xProperties) { OUString aValue; OUString aType; uno::Any aAny; uno::Reference xCurrent = mxObject; try { if (xInvocation->hasProperty(xProperty.Name)) { aAny = xInvocation->getValue(xProperty.Name); aValue = AnyToString(aAny); aType = getAnyType(aAny, mxContext); } } catch (...) { aValue = ""; aType = "?"; } bool bComplex = false; if (aAny.hasValue()) { auto xInterface = uno::Reference(aAny, uno::UNO_QUERY); if (xInterface.is()) { xCurrent = xInterface; bComplex = true; } } std::unique_ptr 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); } if (!aType.isEmpty()) { pTree->set_text(*pCurrent, aType, 2); } } } } // end anonymous namespace ObjectInspectorTreeHandler::ObjectInspectorTreeHandler( std::unique_ptr& pObjectInspectorTree, std::unique_ptr& pClassNameLabel) : mpObjectInspectorTree(pObjectInspectorTree) , mpClassNameLabel(pClassNameLabel) { mpObjectInspectorTree->connect_expanding( LINK(this, ObjectInspectorTreeHandler, ExpandingHandler)); } 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(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 pChild = mpObjectInspectorTree->make_iterator(&rParent); bChild = mpObjectInspectorTree->iter_children(*pChild); if (bChild) { clearObjectInspectorChildren(*pChild); OUString sID = mpObjectInspectorTree->get_id(*pChild); auto* pEntry = reinterpret_cast(sID.toInt64()); delete pEntry; mpObjectInspectorTree->remove(*pChild); } } } while (bChild); } void ObjectInspectorTreeHandler::introspect(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); // 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(sID.toInt64()); delete pEntry; return false; }); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */