Files
core/sfx2/source/devtools/ObjectInspectorTreeHandler.cxx
Michael Weghorn 78461f9db0 tdf#130857 weld: Reuse existing weld::Widget command logic for TreeView
Drop the weld::TreeView-specific logic for signalling
CommandEvent of type ContextMenu and reuse the existing
logic implemented in the weld::Widget base class instead,
which was moved there in previous commit

    Change-Id: I9367bdbb8be7994057667fab539aaf135751e063
    Author: Michael Weghorn <m.weghorn@posteo.de>
    Date:   Wed Dec 10 23:08:21 2025 +0100

        tdf#130857 weld: Move CommandEvent handling to weld::Widget base

Make weld::Widget::connect_command virtual to override
it in GtkInstanceTreeView, as was previously the case
for the now dropped weld::TreeView::connect_popup_menu.

The existing handlers previously connected using
weld::TreeView::connect_popup_menu already check whether the type
of the event is CommandEventId::ContextMenu, so no change in behavior
is expected.

In a quick test, the sample scenario of the template dialog as
described in

    commit 5d28767654
    Author: Michael Weghorn <m.weghorn@posteo.de>
    Date:   Tue Dec 9 20:13:07 2025 +0100

        tdf#130857 qt weld: Forward TreeView context menu event

still worked as expected with gtk3 and gen as well as with
an experimental branch for qt6 where support for using native
Qt widgets for that dialog is declared.

Change-Id: I13baf51eda2c9f0adc9c167ab50e920d23ada07e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195415
Tested-by: Jenkins
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
2025-12-12 13:25:45 +01:00

1385 lines
48 KiB
C++

/* -*- 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 <sfx2/sfxresid.hxx>
#include <utility>
#include <vcl/svapp.hxx>
#include "DevToolsStrings.hrc"
#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/PropertyConcept.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/beans/MethodConcept.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/reflection/XIdlArray.hpp>
#include <com/sun/star/reflection/XEnumTypeDescription.hpp>
#include <com/sun/star/container/XNamed.hpp>
#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
#include <com/sun/star/container/XIndexAccess.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/container/XEnumerationAccess.hpp>
#include <com/sun/star/script/Invocation.hpp>
#include <com/sun/star/script/XInvocation2.hpp>
#include <com/sun/star/script/MemberType.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XTypeProvider.hpp>
#include <comphelper/processfactory.hxx>
#include <comphelper/extract.hxx>
#include <vcl/settings.hxx>
#include <i18nlangtag/languagetag.hxx>
using namespace css;
namespace
{
constexpr OUStringLiteral constTypeDescriptionManagerSingletonName
= u"/singletons/com.sun.star.reflection.theTypeDescriptionManager";
OUString enumValueToEnumName(uno::Any const& aValue,
uno::Reference<uno::XComponentContext> const& xContext)
{
sal_Int32 nIntValue = 0;
if (!cppu::enum2int(nIntValue, aValue))
return OUString();
uno::Reference<container::XHierarchicalNameAccess> xManager;
xManager.set(xContext->getValueByName(constTypeDescriptionManagerSingletonName),
uno::UNO_QUERY);
uno::Reference<reflection::XEnumTypeDescription> xTypeDescription;
xTypeDescription.set(xManager->getByHierarchicalName(aValue.getValueTypeName()),
uno::UNO_QUERY);
const uno::Sequence<sal_Int32> aValues = xTypeDescription->getEnumValues();
sal_Int32 nValuesIndex = std::find(aValues.begin(), aValues.end(), nIntValue) - aValues.begin();
uno::Sequence<OUString> aNames = xTypeDescription->getEnumNames();
return aNames[nValuesIndex];
}
OUString getInterfaceImplementationClass(uno::Reference<uno::XInterface> const& xInterface)
{
auto xServiceInfo = uno::Reference<lang::XServiceInfo>(xInterface, uno::UNO_QUERY);
if (xServiceInfo.is())
return xServiceInfo->getImplementationName();
return OUString();
}
/** converts basic any value to a string */
OUString convertBasicValueToString(const uno::Any& aValue,
const uno::Reference<uno::XComponentContext>& xContext)
{
OUString aRetStr;
// return early if we don't have any value
if (!aValue.hasValue())
return SfxResId(STR_ANY_VALUE_NULL);
uno::TypeClass eType = aValue.getValueTypeClass();
switch (eType)
{
case uno::TypeClass_BOOLEAN:
{
bool bBool = aValue.get<bool>();
aRetStr = bBool ? SfxResId(STR_ANY_VALUE_TRUE) : SfxResId(STR_ANY_VALUE_FALSE);
break;
}
case uno::TypeClass_CHAR:
{
sal_Unicode aChar = aValue.get<sal_Unicode>();
aRetStr = OUString::number(aChar);
break;
}
case uno::TypeClass_STRING:
{
aRetStr = u"\"" + aValue.get<OUString>() + u"\"";
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;
}
case uno::TypeClass_UNSIGNED_SHORT:
{
auto aNumber = aValue.get<sal_uInt16>();
aRetStr = OUString::number(aNumber);
break;
}
case uno::TypeClass_UNSIGNED_LONG:
{
auto aNumber = aValue.get<sal_uInt32>();
aRetStr = OUString::number(aNumber);
break;
}
case uno::TypeClass_UNSIGNED_HYPER:
{
auto aNumber = aValue.get<sal_uInt64>();
aRetStr = OUString::number(aNumber);
break;
}
case uno::TypeClass_TYPE:
{
auto aType = aValue.get<uno::Type>();
aRetStr = aType.getTypeName();
break;
}
case uno::TypeClass_ENUM:
{
aRetStr = enumValueToEnumName(aValue, xContext);
break;
}
default:
break;
}
return aRetStr;
}
// returns a name of the object, if available
OUString getInterfaceName(uno::Reference<uno::XInterface> const& xInterface,
const uno::Reference<uno::XComponentContext>& xContext)
{
uno::Reference<container::XNamed> xNamed(xInterface, uno::UNO_QUERY);
if (xNamed.is())
return xNamed->getName();
auto xInvocationFactory = css::script::Invocation::create(xContext);
uno::Sequence<uno::Any> aParameters = { uno::Any(xInterface) };
auto xInvocationInterface = xInvocationFactory->createInstanceWithArguments(aParameters);
if (xInvocationInterface.is())
{
uno::Reference<script::XInvocation2> xInvocation(xInvocationInterface, uno::UNO_QUERY);
if (xInvocation.is() && xInvocation->hasProperty(u"Name"_ustr))
{
uno::Any aAny = xInvocation->getValue(u"Name"_ustr);
if (aAny.hasValue() && aAny.getValueTypeClass() == uno::TypeClass_STRING)
return aAny.get<OUString>();
}
}
return OUString();
}
OUString convertAnyToString(const uno::Any& aValue,
const uno::Reference<uno::XComponentContext>& xContext)
{
// return early if we don't have any value
if (!aValue.hasValue())
return SfxResId(STR_ANY_VALUE_NULL);
OUString aRetStr;
uno::TypeClass eType = aValue.getValueTypeClass();
switch (eType)
{
case uno::TypeClass_INTERFACE:
{
uno::Reference<uno::XInterface> xInterface(aValue, uno::UNO_QUERY);
if (!xInterface.is())
aRetStr = SfxResId(STR_ANY_VALUE_NULL);
else
{
OUString aImplementationClass = getInterfaceImplementationClass(xInterface);
if (aImplementationClass.isEmpty())
aImplementationClass = SfxResId(STR_CLASS_UNKNOWN);
aRetStr
= SfxResId(STR_PROPERTY_VALUE_OBJECT).replaceFirst("%1", aImplementationClass);
OUString aString = getInterfaceName(xInterface, xContext);
if (!aString.isEmpty())
aRetStr += " {" + aString + "}";
}
break;
}
case uno::TypeClass_STRUCT:
{
aRetStr = SfxResId(STR_PROPERTY_VALUE_STRUCT);
break;
}
default:
{
aRetStr = convertBasicValueToString(aValue, xContext);
break;
}
}
return aRetStr;
}
OUString convertAnyToShortenedString(const uno::Any& aValue,
const uno::Reference<uno::XComponentContext>& xContext)
{
// return early if we don't have any value
if (!aValue.hasValue())
return SfxResId(STR_ANY_VALUE_NULL);
OUString aRetStr;
uno::TypeClass eType = aValue.getValueTypeClass();
constexpr const sal_Int32 constMaxStringLength = 60;
switch (eType)
{
case uno::TypeClass_INTERFACE:
{
aRetStr = convertAnyToString(aValue, xContext);
if (aRetStr.getLength() > constMaxStringLength + 3)
aRetStr = OUString::Concat(aRetStr.subView(0, constMaxStringLength)) + u"...";
break;
}
case uno::TypeClass_STRING:
{
OUString aString = convertAnyToString(aValue, xContext);
if (aString.getLength() > constMaxStringLength + 4)
aString = OUString::Concat(aString.subView(0, constMaxStringLength)) + u"\"...";
aRetStr = aString.replaceAll("\n", " ");
break;
}
default:
{
aRetStr = convertAnyToString(aValue, xContext);
break;
}
}
return aRetStr;
}
/** converts an any's type to a string (in a short form) */
OUString getAnyType(const uno::Any& aValue)
{
OUString aTypeName = aValue.getValueTypeName();
return aTypeName.replaceAll("com.sun.star", "css");
}
/** converts a Type to a XIdlClass */
uno::Reference<reflection::XIdlClass>
convertTypeToIdlClass(const uno::Type& rType,
const uno::Reference<uno::XComponentContext>& xContext)
{
auto xReflection = reflection::theCoreReflection::get(xContext);
return xReflection->forName(rType.getTypeName());
}
// Object inspector nodes
/** Object inspector node's main interface
*
* The interface for the "attached" object to a tree view nodes that
* are added to the tree views of the object inspector part. The node
* can return the main value of the node (object name) and if present
* also the values for additional columns. It signals if a tree needs
* an expander and fills the children of the tree is any exists.
*
*/
class ObjectInspectorNodeInterface
{
public:
ObjectInspectorNodeInterface() = default;
virtual ~ObjectInspectorNodeInterface() {}
// main value (object name) of the tree view node
virtual OUString getObjectName() = 0;
// should show the expander for the tree view node
virtual bool shouldShowExpander() { return false; }
// fill the children for the current tree view node
virtual void fillChildren(std::unique_ptr<weld::TreeView>& rTree, const weld::TreeIter* pParent)
= 0;
// fill any additional column values for the current tree view node
virtual std::vector<std::pair<sal_Int32, OUString>> getColumnValues()
{
return std::vector<std::pair<sal_Int32, OUString>>();
}
};
// appends the node to the root of the tree view
void lclAppendNode(const std::unique_ptr<weld::TreeView>& pTree,
ObjectInspectorNodeInterface* pEntry)
{
OUString sName = pEntry->getObjectName();
OUString sId(weld::toId(pEntry));
std::unique_ptr<weld::TreeIter> 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);
}
}
// appends the node to the parent
void lclAppendNodeToParent(const std::unique_ptr<weld::TreeView>& pTree,
const weld::TreeIter* pParent, ObjectInspectorNodeInterface* pEntry)
{
OUString sName = pEntry->getObjectName();
OUString sId(weld::toId(pEntry));
std::unique_ptr<weld::TreeIter> 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);
}
}
/** Node that represent just a simple string with no children or columns */
class SimpleStringNode : public ObjectInspectorNodeInterface
{
protected:
OUString msName;
public:
SimpleStringNode(OUString sName)
: msName(std::move(sName))
{
}
void fillChildren(std::unique_ptr<weld::TreeView>& /*rTree*/,
const weld::TreeIter* /*pParent*/) override
{
}
OUString getObjectName() override { return msName; }
};
/** Node represents a method of an object */
class MethodNode : public ObjectInspectorNodeInterface
{
private:
uno::Reference<reflection::XIdlMethod> mxMethod;
public:
MethodNode(uno::Reference<reflection::XIdlMethod> xMethod)
: mxMethod(std::move(xMethod))
{
}
OUString getObjectName() override { return mxMethod->getName(); }
static OUString simpleTypeName(uno::Reference<reflection::XIdlClass> const& xClass)
{
switch (xClass->getTypeClass())
{
case uno::TypeClass_INTERFACE:
return SfxResId(STR_METHOD_TYPE_OBJECT);
case uno::TypeClass_STRUCT:
return SfxResId(STR_METHOD_TYPE_STRUCT);
case uno::TypeClass_ENUM:
return SfxResId(STR_METHOD_TYPE_ENUM);
case uno::TypeClass_SEQUENCE:
return SfxResId(STR_METHOD_TYPE_SEQUENCE);
default:
break;
}
return xClass->getName();
}
std::vector<std::pair<sal_Int32, OUString>> getColumnValues() override
{
OUString aOutString;
auto xClass = mxMethod->getReturnType();
aOutString = simpleTypeName(xClass);
OUStringBuffer aInString;
const auto aParameters = mxMethod->getParameterInfos();
bool bFirst = true;
for (auto const& rParameterInfo : aParameters)
{
if (!bFirst)
aInString.append(", ");
else
bFirst = false;
switch (rParameterInfo.aMode)
{
case reflection::ParamMode_IN:
aInString.append(SfxResId(STR_PARMETER_MODE_IN) + " ");
break;
case reflection::ParamMode_OUT:
aInString.append(SfxResId(STR_PARMETER_MODE_OUT) + " ");
break;
case reflection::ParamMode_INOUT:
aInString.append(SfxResId(STR_PARMETER_MODE_IN_AND_OUT) + " ");
break;
default:
break;
}
aInString.append(rParameterInfo.aName + " : " + simpleTypeName(rParameterInfo.aType));
}
OUString aImplementationClass = mxMethod->getDeclaringClass()->getName();
return {
{ 1, aOutString },
{ 2, aInString.toString() },
{ 3, aImplementationClass },
};
}
void fillChildren(std::unique_ptr<weld::TreeView>& /*rTree*/,
const weld::TreeIter* /*pParent*/) override
{
}
};
/** Node represents a class (XIdlClass) of an object.
*
* Children are superclasses of the current class. XInterface superclass
* is ignored.
*
*/
class ClassNode : public ObjectInspectorNodeInterface
{
private:
uno::Reference<reflection::XIdlClass> mxClass;
static bool isXInterface(uno::Reference<reflection::XIdlClass> const& xClass)
{
return xClass->getName() == "com.sun.star.uno.XInterface";
}
public:
ClassNode(uno::Reference<reflection::XIdlClass> xClass)
: mxClass(std::move(xClass))
{
}
bool shouldShowExpander() override
{
auto const xSuperClasses = mxClass->getSuperclasses();
return xSuperClasses.getLength() > 2
|| (xSuperClasses.getLength() == 1 && !isXInterface(xSuperClasses[0]));
}
OUString getObjectName() override { return mxClass->getName(); }
// Fill superclasses
void fillChildren(std::unique_ptr<weld::TreeView>& rTree,
const weld::TreeIter* pParent) override
{
auto const xSuperClasses = mxClass->getSuperclasses();
for (auto const& xSuper : xSuperClasses)
{
if (!isXInterface(xSuper))
lclAppendNodeToParent(rTree, pParent, new ClassNode(xSuper));
}
}
};
/** Node represents a basic value, that can be any object, sequence, struct */
class BasicValueNode : public SimpleStringNode
{
protected:
uno::Any maAny;
OUString mrInfo;
uno::Reference<uno::XComponentContext> mxContext;
ObjectInspectorNodeInterface*
createNodeObjectForAny(OUString const& rName, const uno::Any& rAny, OUString const& mrInfo);
public:
BasicValueNode(OUString const& rName, uno::Any aAny, OUString aInfo,
uno::Reference<uno::XComponentContext> xContext)
: SimpleStringNode(rName)
, maAny(std::move(aAny))
, mrInfo(std::move(aInfo))
, mxContext(std::move(xContext))
{
}
const uno::Any& getAny() const { return maAny; }
bool shouldShowExpander() override
{
if (maAny.hasValue())
{
switch (maAny.getValueTypeClass())
{
case uno::TypeClass_INTERFACE:
{
uno::Reference<uno::XInterface> xInterface(maAny, uno::UNO_QUERY);
return xInterface.is();
}
case uno::TypeClass_SEQUENCE:
return true;
default:
break;
}
}
return false;
}
std::vector<std::pair<sal_Int32, OUString>> getColumnValues() override
{
OUString aValue = convertAnyToShortenedString(maAny, mxContext);
OUString aType = getAnyType(maAny);
return { { 1, aValue }, { 2, aType }, { 3, mrInfo } };
}
};
/** Node represents a property */
class GenericPropertiesNode : public BasicValueNode
{
public:
GenericPropertiesNode(OUString const& rName, uno::Any const& rAny, OUString const& rInfo,
uno::Reference<uno::XComponentContext> const& xContext)
: BasicValueNode(rName, rAny, rInfo, xContext)
{
}
void fillChildren(std::unique_ptr<weld::TreeView>& pTree,
const weld::TreeIter* pParent) override;
};
/** Node represents a struct */
class StructNode : public BasicValueNode
{
public:
StructNode(OUString const& rName, uno::Any const& rAny, OUString const& rInfo,
uno::Reference<uno::XComponentContext> const& xContext)
: BasicValueNode(rName, rAny, rInfo, xContext)
{
}
bool shouldShowExpander() override { return true; }
void fillChildren(std::unique_ptr<weld::TreeView>& pTree,
const weld::TreeIter* pParent) override;
};
/** Node represents a sequence */
class SequenceNode : public BasicValueNode
{
uno::Reference<reflection::XIdlArray> mxIdlArray;
public:
SequenceNode(OUString const& rName, uno::Any const& rAny, OUString const& rInfo,
uno::Reference<uno::XComponentContext> const& xContext)
: BasicValueNode(rName, rAny, rInfo, xContext)
{
auto xClass = convertTypeToIdlClass(maAny.getValueType(), mxContext);
mxIdlArray = xClass->getArray();
}
bool shouldShowExpander() override
{
// Show expander only if the sequence has elements
int nLength = mxIdlArray->getLen(maAny);
return nLength > 0;
}
void fillChildren(std::unique_ptr<weld::TreeView>& 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);
auto* pObjectInspectorNode
= createNodeObjectForAny(OUString::number(i), aArrayValue, u""_ustr);
if (pObjectInspectorNode)
lclAppendNodeToParent(pTree, pParent, pObjectInspectorNode);
}
}
std::vector<std::pair<sal_Int32, OUString>> getColumnValues() override
{
int nLength = mxIdlArray->getLen(maAny);
OUString aType
= getAnyType(maAny).replaceAll(u"[]", u"") + u"[" + OUString::number(nLength) + u"]";
OUString aValue
= SfxResId(STR_PROPERTY_VALUE_SEQUENCE).replaceFirst("%1", OUString::number(nLength));
return {
{ 1, aValue },
{ 2, aType },
};
}
};
void GenericPropertiesNode::fillChildren(std::unique_ptr<weld::TreeView>& pTree,
const weld::TreeIter* pParent)
{
if (!maAny.hasValue())
return;
try
{
const auto xNameAccess = uno::Reference<container::XNameAccess>(maAny, uno::UNO_QUERY);
if (xNameAccess.is())
{
const uno::Sequence<OUString> aNames = xNameAccess->getElementNames();
for (OUString const& rName : aNames)
{
uno::Any aAny = xNameAccess->getByName(rName);
auto* pObjectInspectorNode = createNodeObjectForAny(
u"@" + rName, aAny, SfxResId(STR_PROPERTY_TYPE_IS_NAMED_CONTAINER));
lclAppendNodeToParent(pTree, pParent, pObjectInspectorNode);
}
}
}
catch (...)
{
}
try
{
const auto xIndexAccess = uno::Reference<container::XIndexAccess>(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,
SfxResId(STR_PROPERTY_TYPE_IS_INDEX_CONTAINER));
lclAppendNodeToParent(pTree, pParent, pObjectInspectorNode);
}
}
}
catch (...)
{
}
try
{
const auto xEnumAccess
= uno::Reference<container::XEnumerationAccess>(maAny, uno::UNO_QUERY);
if (xEnumAccess.is())
{
uno::Reference<container::XEnumeration> 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,
SfxResId(STR_PROPERTY_TYPE_IS_ENUMERATION));
lclAppendNodeToParent(pTree, pParent, pObjectInspectorNode);
}
}
}
}
catch (...)
{
}
auto xInvocationFactory = css::script::Invocation::create(mxContext);
uno::Sequence<uno::Any> aParameters = { maAny };
auto xInvocationInterface = xInvocationFactory->createInstanceWithArguments(aParameters);
if (!xInvocationInterface.is())
return;
uno::Reference<script::XInvocation2> xInvocation(xInvocationInterface, uno::UNO_QUERY);
if (!xInvocation.is())
return;
auto const xInvocationAccess = xInvocation->getIntrospection();
if (!xInvocationAccess.is())
return;
uno::Sequence<script::InvocationInfo> aInvocationInfoSequence;
try
{
aInvocationInfoSequence = xInvocation->getInfo();
}
catch (...)
{
}
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<OUString> aInfoCollection;
if (bIsAttribute)
aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_IS_ATTRIBUTE));
if (bIsGetSetMethod)
{
bool bHasGet = false;
OUString aString;
if (bMethodGet || bMethodIs)
{
aString += SfxResId(STR_PROPERTY_ATTRIBUTE_GET);
bHasGet = true;
}
if (bMethodSet)
{
if (bHasGet)
aString += u"+";
aString += SfxResId(STR_PROPERTY_ATTRIBUTE_SET);
}
aInfoCollection.push_back(aString);
if (bMethodSet && !bHasGet)
aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_WRITEONLY));
}
if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::MAYBEVOID)
aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_MAYBEVOID));
if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::READONLY)
aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_READONLY));
if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::REMOVABLE)
aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_REMOVABLE));
if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::BOUND)
aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_BOUND));
if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::CONSTRAINED)
aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_CONSTRAINED));
if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::TRANSIENT)
aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_TRANSIENT));
if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::MAYBEAMBIGUOUS)
aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_MAYBEAMBIGUOUS));
if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::MAYBEDEFAULT)
aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_MAYBEDEFAULT));
bool bSet = false;
OUStringBuffer aInfoString;
for (auto const& rString : aInfoCollection)
{
if (bSet)
aInfoString.append(", ");
else
bSet = true;
aInfoString.append(rString);
}
auto* pObjectInspectorNode
= createNodeObjectForAny(aPropertyName, aCurrentAny, aInfoString.toString());
if (pObjectInspectorNode)
lclAppendNodeToParent(pTree, pParent, pObjectInspectorNode);
}
}
}
void StructNode::fillChildren(std::unique_ptr<weld::TreeView>& pTree, const weld::TreeIter* pParent)
{
auto xReflection = reflection::theCoreReflection::get(mxContext);
uno::Reference<reflection::XIdlClass> xClass = xReflection->forName(maAny.getValueTypeName());
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, u""_ustr);
if (pObjectInspectorNode)
{
lclAppendNodeToParent(pTree, pParent, pObjectInspectorNode);
}
}
}
ObjectInspectorNodeInterface* BasicValueNode::createNodeObjectForAny(OUString const& rName,
const uno::Any& rAny,
OUString const& rInfo)
{
switch (rAny.getValueTypeClass())
{
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);
}
} // end anonymous namespace
// Object inspector tree view helper functions
namespace
{
ObjectInspectorNodeInterface* getSelectedNode(weld::TreeView const& rTreeView)
{
OUString sID = rTreeView.get_selected_id();
if (sID.isEmpty())
return nullptr;
if (auto* pNode = weld::fromId<ObjectInspectorNodeInterface*>(sID))
return pNode;
return nullptr;
}
uno::Reference<uno::XInterface> getSelectedXInterface(weld::TreeView const& rTreeView)
{
uno::Reference<uno::XInterface> xInterface;
if (auto* pNode = getSelectedNode(rTreeView))
{
if (auto* pBasicValueNode = dynamic_cast<BasicValueNode*>(pNode))
{
uno::Any aAny = pBasicValueNode->getAny();
xInterface.set(aAny, uno::UNO_QUERY);
}
}
return xInterface;
}
} // end anonymous namespace
ObjectInspectorTreeHandler::ObjectInspectorTreeHandler(
std::unique_ptr<ObjectInspectorWidgets>& pObjectInspectorWidgets)
: mpObjectInspectorWidgets(pObjectInspectorWidgets)
, mxContext(comphelper::getProcessComponentContext())
, mxSorter(mxContext, Application::GetSettings().GetLanguageTag().getLocale())
{
mpObjectInspectorWidgets->mpInterfacesTreeView->connect_expanding(
LINK(this, ObjectInspectorTreeHandler, ExpandingHandlerInterfaces));
mpObjectInspectorWidgets->mpServicesTreeView->connect_expanding(
LINK(this, ObjectInspectorTreeHandler, ExpandingHandlerServices));
mpObjectInspectorWidgets->mpPropertiesTreeView->connect_expanding(
LINK(this, ObjectInspectorTreeHandler, ExpandingHandlerProperties));
mpObjectInspectorWidgets->mpMethodsTreeView->connect_expanding(
LINK(this, ObjectInspectorTreeHandler, ExpandingHandlerMethods));
mpObjectInspectorWidgets->mpPropertiesTreeView->connect_command(
LINK(this, ObjectInspectorTreeHandler, PopupMenuHandler));
mpObjectInspectorWidgets->mpInterfacesTreeView->connect_selection_changed(
LINK(this, ObjectInspectorTreeHandler, SelectionChanged));
mpObjectInspectorWidgets->mpServicesTreeView->connect_selection_changed(
LINK(this, ObjectInspectorTreeHandler, SelectionChanged));
mpObjectInspectorWidgets->mpPropertiesTreeView->connect_selection_changed(
LINK(this, ObjectInspectorTreeHandler, SelectionChanged));
mpObjectInspectorWidgets->mpMethodsTreeView->connect_selection_changed(
LINK(this, ObjectInspectorTreeHandler, SelectionChanged));
mpObjectInspectorWidgets->mpInterfacesTreeView->make_sorted();
mpObjectInspectorWidgets->mpServicesTreeView->make_sorted();
mpObjectInspectorWidgets->mpPropertiesTreeView->make_sorted();
mpObjectInspectorWidgets->mpMethodsTreeView->make_sorted();
setSortFunction(mpObjectInspectorWidgets->mpInterfacesTreeView);
setSortFunction(mpObjectInspectorWidgets->mpServicesTreeView);
setSortFunction(mpObjectInspectorWidgets->mpPropertiesTreeView);
setSortFunction(mpObjectInspectorWidgets->mpMethodsTreeView);
mpObjectInspectorWidgets->mpInterfacesTreeView->connect_column_clicked(
LINK(this, ObjectInspectorTreeHandler, HeaderBarClick));
mpObjectInspectorWidgets->mpServicesTreeView->connect_column_clicked(
LINK(this, ObjectInspectorTreeHandler, HeaderBarClick));
mpObjectInspectorWidgets->mpPropertiesTreeView->connect_column_clicked(
LINK(this, ObjectInspectorTreeHandler, HeaderBarClick));
mpObjectInspectorWidgets->mpMethodsTreeView->connect_column_clicked(
LINK(this, ObjectInspectorTreeHandler, HeaderBarClick));
mpObjectInspectorWidgets->mpToolbar->connect_clicked(
LINK(this, ObjectInspectorTreeHandler, ToolbarButtonClicked));
mpObjectInspectorWidgets->mpToolbar->set_item_sensitive(u"inspect"_ustr, false);
mpObjectInspectorWidgets->mpToolbar->set_item_sensitive(u"back"_ustr, false);
mpObjectInspectorWidgets->mpNotebook->connect_leave_page(
LINK(this, ObjectInspectorTreeHandler, NotebookLeavePage));
mpObjectInspectorWidgets->mpNotebook->connect_enter_page(
LINK(this, ObjectInspectorTreeHandler, NotebookEnterPage));
auto nPropertiesDigitWidth
= mpObjectInspectorWidgets->mpPropertiesTreeView->get_approximate_digit_width();
std::vector<int> aPropertiesWidths(4, nPropertiesDigitWidth * 30);
mpObjectInspectorWidgets->mpPropertiesTreeView->set_column_fixed_widths(aPropertiesWidths);
auto nMethodsDigitWidth
= mpObjectInspectorWidgets->mpMethodsTreeView->get_approximate_digit_width();
std::vector<int> aMethodsWidths{ static_cast<int>(nMethodsDigitWidth * 30),
static_cast<int>(nMethodsDigitWidth * 15),
static_cast<int>(nMethodsDigitWidth * 30),
static_cast<int>(nMethodsDigitWidth * 50) };
mpObjectInspectorWidgets->mpMethodsTreeView->set_column_fixed_widths(aMethodsWidths);
mpObjectInspectorWidgets->mpPaned->set_position(160);
}
void ObjectInspectorTreeHandler::setSortFunction(std::unique_ptr<weld::TreeView>& pTreeView)
{
pTreeView->set_sort_func(
[this, &pTreeView](const weld::TreeIter& rLeft, const weld::TreeIter& rRight) {
return compare(pTreeView, rLeft, rRight);
});
}
sal_Int32 ObjectInspectorTreeHandler::compare(const std::unique_ptr<weld::TreeView>& pTreeView,
const weld::TreeIter& rLeft,
const weld::TreeIter& rRight)
{
int nSortColumn = pTreeView->get_sort_column();
OUString sLeft = pTreeView->get_text(rLeft, nSortColumn);
OUString sRight = pTreeView->get_text(rRight, nSortColumn);
sal_Int32 nCompare = mxSorter.compare(sLeft, sRight);
return nCompare;
}
void ObjectInspectorTreeHandler::handleExpanding(std::unique_ptr<weld::TreeView>& pTreeView,
weld::TreeIter const& rParent)
{
OUString sID = pTreeView->get_id(rParent);
if (sID.isEmpty())
return;
clearObjectInspectorChildren(pTreeView, rParent);
auto* pNode = weld::fromId<ObjectInspectorNodeInterface*>(sID);
pNode->fillChildren(pTreeView, &rParent);
}
IMPL_LINK(ObjectInspectorTreeHandler, ExpandingHandlerInterfaces, weld::TreeIter const&, rParent,
bool)
{
handleExpanding(mpObjectInspectorWidgets->mpInterfacesTreeView, rParent);
return true;
}
IMPL_LINK(ObjectInspectorTreeHandler, ExpandingHandlerServices, weld::TreeIter const&, rParent,
bool)
{
handleExpanding(mpObjectInspectorWidgets->mpServicesTreeView, rParent);
return true;
}
IMPL_LINK(ObjectInspectorTreeHandler, ExpandingHandlerProperties, weld::TreeIter const&, rParent,
bool)
{
handleExpanding(mpObjectInspectorWidgets->mpPropertiesTreeView, rParent);
return true;
}
IMPL_LINK(ObjectInspectorTreeHandler, ExpandingHandlerMethods, weld::TreeIter const&, rParent, bool)
{
handleExpanding(mpObjectInspectorWidgets->mpMethodsTreeView, rParent);
return true;
}
IMPL_LINK(ObjectInspectorTreeHandler, SelectionChanged, weld::TreeView&, rTreeView, void)
{
bool bHaveNodeWithObject = false;
mpObjectInspectorWidgets->mpTextView->set_text(u""_ustr);
if (mpObjectInspectorWidgets->mpPropertiesTreeView.get() == &rTreeView)
{
auto* pNode = getSelectedNode(rTreeView);
if (auto* pBasicValueNode = dynamic_cast<BasicValueNode*>(pNode))
{
uno::Any aAny = pBasicValueNode->getAny();
uno::Reference<uno::XInterface> xInterface(aAny, uno::UNO_QUERY);
bHaveNodeWithObject = xInterface.is();
mpObjectInspectorWidgets->mpTextView->set_text(convertAnyToString(aAny, mxContext));
}
}
mpObjectInspectorWidgets->mpToolbar->set_item_sensitive(u"inspect"_ustr, bHaveNodeWithObject);
}
static void updateOrder(const std::unique_ptr<weld::TreeView>& pTreeView, sal_Int32 nColumn)
{
pTreeView->set_sort_column(nColumn);
bool bSortAtoZ = pTreeView->get_sort_order();
pTreeView->set_sort_order(!bSortAtoZ);
pTreeView->set_sort_indicator(!bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn);
}
IMPL_LINK(ObjectInspectorTreeHandler, HeaderBarClick, int, nColumn, void)
{
auto rPageId = mpObjectInspectorWidgets->mpNotebook->get_current_page_ident();
if (rPageId == "object_inspector_interfaces_tab")
updateOrder(mpObjectInspectorWidgets->mpInterfacesTreeView, nColumn);
else if (rPageId == "object_inspector_services_tab")
updateOrder(mpObjectInspectorWidgets->mpServicesTreeView, nColumn);
else if (rPageId == "object_inspector_properties_tab")
updateOrder(mpObjectInspectorWidgets->mpPropertiesTreeView, nColumn);
else if (rPageId == "object_inspector_methods_tab")
updateOrder(mpObjectInspectorWidgets->mpMethodsTreeView, nColumn);
}
IMPL_LINK(ObjectInspectorTreeHandler, PopupMenuHandler, const CommandEvent&, rCommandEvent, bool)
{
if (rCommandEvent.GetCommand() != CommandEventId::ContextMenu)
return false;
auto xInterface = getSelectedXInterface(*mpObjectInspectorWidgets->mpPropertiesTreeView);
if (xInterface.is())
{
std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(
mpObjectInspectorWidgets->mpPropertiesTreeView.get(), u"sfx/ui/devtoolsmenu.ui"_ustr));
std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu(u"inspect_menu"_ustr));
OUString sCommand(
xMenu->popup_at_rect(mpObjectInspectorWidgets->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 OUString&, rSelectionId, void)
{
if (rSelectionId == "inspect")
{
auto xInterface = getSelectedXInterface(*mpObjectInspectorWidgets->mpPropertiesTreeView);
if (xInterface.is())
{
addToStack(uno::Any(xInterface));
inspectObject(xInterface);
}
}
else if (rSelectionId == "back")
{
uno::Any aAny = popFromStack();
if (aAny.hasValue())
{
uno::Reference<uno::XInterface> xInterface(aAny, uno::UNO_QUERY);
inspectObject(xInterface);
}
}
else if (rSelectionId == "refresh")
{
auto rPageId = mpObjectInspectorWidgets->mpNotebook->get_current_page_ident();
NotebookEnterPage(rPageId);
}
}
IMPL_LINK(ObjectInspectorTreeHandler, NotebookEnterPage, const OUString&, rPageId, void)
{
uno::Any aAny = maInspectionStack.back();
if (!aAny.hasValue())
return;
uno::Reference<uno::XInterface> xInterface(aAny, uno::UNO_QUERY);
if (rPageId == "object_inspector_interfaces_tab")
{
mpObjectInspectorWidgets->mpInterfacesTreeView->freeze();
clearAll(mpObjectInspectorWidgets->mpInterfacesTreeView);
appendInterfaces(xInterface);
mpObjectInspectorWidgets->mpInterfacesTreeView->thaw();
}
else if (rPageId == "object_inspector_services_tab")
{
mpObjectInspectorWidgets->mpServicesTreeView->freeze();
clearAll(mpObjectInspectorWidgets->mpServicesTreeView);
appendServices(xInterface);
mpObjectInspectorWidgets->mpServicesTreeView->thaw();
}
else if (rPageId == "object_inspector_properties_tab")
{
mpObjectInspectorWidgets->mpPropertiesTreeView->freeze();
clearAll(mpObjectInspectorWidgets->mpPropertiesTreeView);
appendProperties(xInterface);
mpObjectInspectorWidgets->mpPropertiesTreeView->thaw();
}
else if (rPageId == "object_inspector_methods_tab")
{
mpObjectInspectorWidgets->mpMethodsTreeView->freeze();
clearAll(mpObjectInspectorWidgets->mpMethodsTreeView);
appendMethods(xInterface);
mpObjectInspectorWidgets->mpMethodsTreeView->thaw();
}
}
IMPL_LINK(ObjectInspectorTreeHandler, NotebookLeavePage, const OUString&, rPageId, bool)
{
if (rPageId == "object_inspector_interfaces_tab")
{
mpObjectInspectorWidgets->mpInterfacesTreeView->freeze();
clearAll(mpObjectInspectorWidgets->mpInterfacesTreeView);
mpObjectInspectorWidgets->mpInterfacesTreeView->thaw();
}
else if (rPageId == "object_inspector_services_tab")
{
mpObjectInspectorWidgets->mpServicesTreeView->freeze();
clearAll(mpObjectInspectorWidgets->mpServicesTreeView);
mpObjectInspectorWidgets->mpServicesTreeView->thaw();
}
else if (rPageId == "object_inspector_properties_tab")
{
mpObjectInspectorWidgets->mpPropertiesTreeView->freeze();
clearAll(mpObjectInspectorWidgets->mpPropertiesTreeView);
mpObjectInspectorWidgets->mpPropertiesTreeView->thaw();
}
else if (rPageId == "object_inspector_methods_tab")
{
mpObjectInspectorWidgets->mpMethodsTreeView->freeze();
clearAll(mpObjectInspectorWidgets->mpMethodsTreeView);
mpObjectInspectorWidgets->mpMethodsTreeView->thaw();
}
return true;
}
void ObjectInspectorTreeHandler::clearObjectInspectorChildren(
std::unique_ptr<weld::TreeView>& pTreeView, weld::TreeIter const& rParent)
{
bool bChild = false;
do
{
bChild = pTreeView->iter_has_child(rParent);
if (bChild)
{
std::unique_ptr<weld::TreeIter> pChild = pTreeView->make_iterator(&rParent);
bChild = pTreeView->iter_children(*pChild);
if (bChild)
{
clearObjectInspectorChildren(pTreeView, *pChild);
OUString sID = pTreeView->get_id(*pChild);
auto* pEntry = weld::fromId<ObjectInspectorNodeInterface*>(sID);
delete pEntry;
pTreeView->remove(*pChild);
}
}
} while (bChild);
}
/** Deletes all the node objects in a tree view */
void ObjectInspectorTreeHandler::clearAll(std::unique_ptr<weld::TreeView>& pTreeView)
{
// destroy all ObjectInspectorNodes from the tree
pTreeView->all_foreach([&pTreeView](weld::TreeIter& rEntry) {
OUString sID = pTreeView->get_id(rEntry);
auto* pEntry = weld::fromId<ObjectInspectorNodeInterface*>(sID);
delete pEntry;
return false;
});
pTreeView->clear();
}
/** Append interfaces to the "interfaces" tree view */
void ObjectInspectorTreeHandler::appendInterfaces(uno::Reference<uno::XInterface> const& xInterface)
{
if (!xInterface.is())
return;
uno::Reference<lang::XTypeProvider> xTypeProvider(xInterface, uno::UNO_QUERY);
if (xTypeProvider.is())
{
const auto xSequenceTypes = xTypeProvider->getTypes();
for (auto const& xType : xSequenceTypes)
{
auto xClass = convertTypeToIdlClass(xType, mxContext);
lclAppendNode(mpObjectInspectorWidgets->mpInterfacesTreeView, new ClassNode(xClass));
}
}
}
/** Append services to the "services" tree view */
void ObjectInspectorTreeHandler::appendServices(uno::Reference<uno::XInterface> const& xInterface)
{
if (!xInterface.is())
return;
auto xServiceInfo = uno::Reference<lang::XServiceInfo>(xInterface, uno::UNO_QUERY);
if (!xServiceInfo)
return;
const uno::Sequence<OUString> aServiceNames(xServiceInfo->getSupportedServiceNames());
for (auto const& aServiceName : aServiceNames)
{
lclAppendNode(mpObjectInspectorWidgets->mpServicesTreeView,
new SimpleStringNode(aServiceName));
}
}
/** Append properties to the "properties" tree view */
void ObjectInspectorTreeHandler::appendProperties(uno::Reference<uno::XInterface> const& xInterface)
{
if (!xInterface.is())
return;
GenericPropertiesNode aNode(u""_ustr, uno::Any(xInterface), u""_ustr, mxContext);
aNode.fillChildren(mpObjectInspectorWidgets->mpPropertiesTreeView, nullptr);
}
/** Append methods to the "methods" tree view */
void ObjectInspectorTreeHandler::appendMethods(uno::Reference<uno::XInterface> const& xInterface)
{
if (!xInterface.is())
return;
uno::Reference<beans::XIntrospection> xIntrospection = beans::theIntrospection::get(mxContext);
auto xIntrospectionAccess = xIntrospection->inspect(uno::Any(xInterface));
const auto xMethods = xIntrospectionAccess->getMethods(beans::MethodConcept::ALL);
for (auto const& xMethod : xMethods)
{
lclAppendNode(mpObjectInspectorWidgets->mpMethodsTreeView, new MethodNode(xMethod));
}
}
// Update the back button state depending if there are objects in the stack
void ObjectInspectorTreeHandler::updateBackButtonState()
{
mpObjectInspectorWidgets->mpToolbar->set_item_sensitive(u"back"_ustr,
maInspectionStack.size() > 1);
}
// Clears all the objects from the stack
void ObjectInspectorTreeHandler::clearStack()
{
maInspectionStack.clear();
updateBackButtonState();
}
// Adds an object to the stack
void ObjectInspectorTreeHandler::addToStack(css::uno::Any const& rAny)
{
maInspectionStack.push_back(rAny);
updateBackButtonState();
}
// Removes an object from the back of the stack and return it
css::uno::Any ObjectInspectorTreeHandler::popFromStack()
{
maInspectionStack.pop_back();
uno::Any aAny = maInspectionStack.back();
updateBackButtonState();
return aAny;
}
// Inspect the input object in the object inspector
void ObjectInspectorTreeHandler::inspectObject(uno::Reference<uno::XInterface> const& xInterface)
{
if (!xInterface.is())
return;
// Set implementation name
OUString aImplementationName = getInterfaceImplementationClass(xInterface);
mpObjectInspectorWidgets->mpClassNameLabel->set_label(aImplementationName);
sal_Int32 nStrLen = aImplementationName.getLength();
sal_Int32 nDigitWidth
= mpObjectInspectorWidgets->mpClassNameLabel->get_approximate_digit_width();
//get_about_digit_width() returns an approximate value. To always see the full class name (nStrLen+2)
mpObjectInspectorWidgets->mpClassNameLabel->set_size_request((nStrLen + 2) * nDigitWidth, -1);
// Fire entering the current opened page manually
auto rPageId = mpObjectInspectorWidgets->mpNotebook->get_current_page_ident();
NotebookEnterPage(rPageId);
}
// Inspect the input object in the object inspector.
// Make the input object the root of the stack (clear all other
// objects from the stack).
void ObjectInspectorTreeHandler::introspect(uno::Reference<uno::XInterface> const& xInterface)
{
clearStack();
addToStack(uno::Any(xInterface));
inspectObject(xInterface);
}
void ObjectInspectorTreeHandler::dispose()
{
// We need to clear all the nodes
clearAll(mpObjectInspectorWidgets->mpInterfacesTreeView);
clearAll(mpObjectInspectorWidgets->mpServicesTreeView);
clearAll(mpObjectInspectorWidgets->mpPropertiesTreeView);
clearAll(mpObjectInspectorWidgets->mpMethodsTreeView);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */