LibreOffice Module sfx2 (master) 1
ObjectInspectorTreeHandler.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 */
10
11#include <memory>
12
14#include <sfx2/sfxresid.hxx>
15#include <utility>
16#include <vcl/svapp.hxx>
17#include "DevToolsStrings.hrc"
18
19#include <com/sun/star/beans/theIntrospection.hpp>
20#include <com/sun/star/beans/XIntrospection.hpp>
21#include <com/sun/star/beans/XIntrospectionAccess.hpp>
22#include <com/sun/star/beans/PropertyConcept.hpp>
23#include <com/sun/star/beans/PropertyAttribute.hpp>
24#include <com/sun/star/beans/MethodConcept.hpp>
25
26#include <com/sun/star/reflection/theCoreReflection.hpp>
27#include <com/sun/star/reflection/XIdlReflection.hpp>
28#include <com/sun/star/reflection/XIdlMethod.hpp>
29#include <com/sun/star/reflection/XIdlArray.hpp>
30#include <com/sun/star/reflection/XEnumTypeDescription.hpp>
31
32#include <com/sun/star/container/XNamed.hpp>
33#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
34#include <com/sun/star/container/XIndexAccess.hpp>
35#include <com/sun/star/container/XNameAccess.hpp>
36#include <com/sun/star/container/XEnumerationAccess.hpp>
37
38#include <com/sun/star/script/Invocation.hpp>
39#include <com/sun/star/script/XInvocation2.hpp>
40#include <com/sun/star/script/MemberType.hpp>
41
42#include <com/sun/star/lang/XServiceInfo.hpp>
43#include <com/sun/star/lang/XTypeProvider.hpp>
44
47
48#include <vcl/settings.hxx>
50
51using namespace css;
52
53namespace
54{
55constexpr OUStringLiteral constTypeDescriptionManagerSingletonName
56 = u"/singletons/com.sun.star.reflection.theTypeDescriptionManager";
57
58OUString enumValueToEnumName(uno::Any const& aValue,
59 uno::Reference<uno::XComponentContext> const& xContext)
60{
61 sal_Int32 nIntValue = 0;
62 if (!cppu::enum2int(nIntValue, aValue))
63 return OUString();
64
65 uno::Reference<container::XHierarchicalNameAccess> xManager;
66 xManager.set(xContext->getValueByName(constTypeDescriptionManagerSingletonName),
67 uno::UNO_QUERY);
68
69 uno::Reference<reflection::XEnumTypeDescription> xTypeDescription;
70 xTypeDescription.set(xManager->getByHierarchicalName(aValue.getValueType().getTypeName()),
71 uno::UNO_QUERY);
72
73 const uno::Sequence<sal_Int32> aValues = xTypeDescription->getEnumValues();
74 sal_Int32 nValuesIndex = std::find(aValues.begin(), aValues.end(), nIntValue) - aValues.begin();
75 uno::Sequence<OUString> aNames = xTypeDescription->getEnumNames();
76 return aNames[nValuesIndex];
77}
78
79OUString getInterfaceImplementationClass(uno::Reference<uno::XInterface> const& xInterface)
80{
81 auto xServiceInfo = uno::Reference<lang::XServiceInfo>(xInterface, uno::UNO_QUERY);
82 if (xServiceInfo.is())
83 return xServiceInfo->getImplementationName();
84 return OUString();
85}
86
88OUString convertBasicValueToString(const uno::Any& aValue,
89 const uno::Reference<uno::XComponentContext>& xContext)
90{
91 OUString aRetStr;
92
93 // return early if we don't have any value
94 if (!aValue.hasValue())
95 return SfxResId(STR_ANY_VALUE_NULL);
96
97 uno::TypeClass eType = aValue.getValueTypeClass();
98
99 switch (eType)
100 {
101 case uno::TypeClass_BOOLEAN:
102 {
103 bool bBool = aValue.get<bool>();
104 aRetStr = bBool ? SfxResId(STR_ANY_VALUE_TRUE) : SfxResId(STR_ANY_VALUE_FALSE);
105 break;
106 }
107 case uno::TypeClass_CHAR:
108 {
109 sal_Unicode aChar = aValue.get<sal_Unicode>();
110 aRetStr = OUString::number(aChar);
111 break;
112 }
113 case uno::TypeClass_STRING:
114 {
115 aRetStr = u"\"" + aValue.get<OUString>() + u"\"";
116 break;
117 }
118 case uno::TypeClass_FLOAT:
119 {
120 auto aNumber = aValue.get<float>();
121 aRetStr = OUString::number(aNumber);
122 break;
123 }
124 case uno::TypeClass_DOUBLE:
125 {
126 auto aNumber = aValue.get<double>();
127 aRetStr = OUString::number(aNumber);
128 break;
129 }
130 case uno::TypeClass_BYTE:
131 {
132 auto aNumber = aValue.get<sal_Int8>();
133 aRetStr = OUString::number(aNumber);
134 break;
135 }
136 case uno::TypeClass_SHORT:
137 {
138 auto aNumber = aValue.get<sal_Int16>();
139 aRetStr = OUString::number(aNumber);
140 break;
141 }
142 case uno::TypeClass_LONG:
143 {
144 auto aNumber = aValue.get<sal_Int32>();
145 aRetStr = OUString::number(aNumber);
146 break;
147 }
148 case uno::TypeClass_HYPER:
149 {
150 auto aNumber = aValue.get<sal_Int64>();
151 aRetStr = OUString::number(aNumber);
152 break;
153 }
154 case uno::TypeClass_UNSIGNED_SHORT:
155 {
156 auto aNumber = aValue.get<sal_uInt16>();
157 aRetStr = OUString::number(aNumber);
158 break;
159 }
160 case uno::TypeClass_UNSIGNED_LONG:
161 {
162 auto aNumber = aValue.get<sal_uInt32>();
163 aRetStr = OUString::number(aNumber);
164 break;
165 }
166 case uno::TypeClass_UNSIGNED_HYPER:
167 {
168 auto aNumber = aValue.get<sal_uInt64>();
169 aRetStr = OUString::number(aNumber);
170 break;
171 }
172 case uno::TypeClass_TYPE:
173 {
174 auto aType = aValue.get<uno::Type>();
175 aRetStr = aType.getTypeName();
176 break;
177 }
178 case uno::TypeClass_ENUM:
179 {
180 aRetStr = enumValueToEnumName(aValue, xContext);
181 break;
182 }
183
184 default:
185 break;
186 }
187 return aRetStr;
188}
189
190// returns a name of the object, if available
191OUString getInterfaceName(uno::Reference<uno::XInterface> const& xInterface,
192 const uno::Reference<uno::XComponentContext>& xContext)
193{
194 uno::Reference<container::XNamed> xNamed(xInterface, uno::UNO_QUERY);
195 if (xNamed.is())
196 return xNamed->getName();
197
198 auto xInvocationFactory = css::script::Invocation::create(xContext);
199 uno::Sequence<uno::Any> aParameters = { uno::Any(xInterface) };
200 auto xInvocationInterface = xInvocationFactory->createInstanceWithArguments(aParameters);
201 if (xInvocationInterface.is())
202 {
203 uno::Reference<script::XInvocation2> xInvocation(xInvocationInterface, uno::UNO_QUERY);
204 if (xInvocation.is() && xInvocation->hasProperty("Name"))
205 {
206 uno::Any aAny = xInvocation->getValue("Name");
207 if (aAny.hasValue() && aAny.getValueTypeClass() == uno::TypeClass_STRING)
208 return aAny.get<OUString>();
209 }
210 }
211 return OUString();
212}
213
214OUString convertAnyToString(const uno::Any& aValue,
215 const uno::Reference<uno::XComponentContext>& xContext)
216{
217 // return early if we don't have any value
218 if (!aValue.hasValue())
219 return SfxResId(STR_ANY_VALUE_NULL);
220
221 OUString aRetStr;
222
223 uno::TypeClass eType = aValue.getValueTypeClass();
224
225 switch (eType)
226 {
227 case uno::TypeClass_INTERFACE:
228 {
229 uno::Reference<uno::XInterface> xInterface(aValue, uno::UNO_QUERY);
230 if (!xInterface.is())
231 aRetStr = SfxResId(STR_ANY_VALUE_NULL);
232 else
233 {
234 OUString aImplementationClass = getInterfaceImplementationClass(xInterface);
235 if (aImplementationClass.isEmpty())
236 aImplementationClass = SfxResId(STR_CLASS_UNKNOWN);
237 aRetStr
238 = SfxResId(STR_PROPERTY_VALUE_OBJECT).replaceFirst("%1", aImplementationClass);
239
240 OUString aString = getInterfaceName(xInterface, xContext);
241 if (!aString.isEmpty())
242 aRetStr += " {" + aString + "}";
243 }
244 break;
245 }
246 case uno::TypeClass_STRUCT:
247 {
248 aRetStr = SfxResId(STR_PROPERTY_VALUE_STRUCT);
249 break;
250 }
251 default:
252 {
253 aRetStr = convertBasicValueToString(aValue, xContext);
254 break;
255 }
256 }
257 return aRetStr;
258}
259
260OUString convertAnyToShortenedString(const uno::Any& aValue,
261 const uno::Reference<uno::XComponentContext>& xContext)
262{
263 // return early if we don't have any value
264 if (!aValue.hasValue())
265 return SfxResId(STR_ANY_VALUE_NULL);
266
267 OUString aRetStr;
268
269 uno::TypeClass eType = aValue.getValueTypeClass();
270
271 constexpr const sal_Int32 constMaxStringLength = 60;
272
273 switch (eType)
274 {
275 case uno::TypeClass_INTERFACE:
276 {
277 aRetStr = convertAnyToString(aValue, xContext);
278
279 if (aRetStr.getLength() > constMaxStringLength + 3)
280 aRetStr = OUString::Concat(aRetStr.subView(0, constMaxStringLength)) + u"...";
281 break;
282 }
283 case uno::TypeClass_STRING:
284 {
285 OUString aString = convertAnyToString(aValue, xContext);
286 if (aString.getLength() > constMaxStringLength + 4)
287 aString = OUString::Concat(aString.subView(0, constMaxStringLength)) + u"\"...";
288 aRetStr = aString.replaceAll("\n", " ");
289 break;
290 }
291 default:
292 {
293 aRetStr = convertAnyToString(aValue, xContext);
294 break;
295 }
296 }
297 return aRetStr;
298}
299
301OUString getAnyType(const uno::Any& aValue)
302{
303 OUString aTypeName = aValue.getValueType().getTypeName();
304 return aTypeName.replaceAll("com.sun.star", "css");
305}
306
308uno::Reference<reflection::XIdlClass>
309convertTypeToIdlClass(const uno::Type& rType,
310 const uno::Reference<uno::XComponentContext>& xContext)
311{
312 auto xReflection = reflection::theCoreReflection::get(xContext);
313 return xReflection->forName(rType.getTypeName());
314}
315
316// Object inspector nodes
317
327class ObjectInspectorNodeInterface
328{
329public:
330 ObjectInspectorNodeInterface() = default;
331
332 virtual ~ObjectInspectorNodeInterface() {}
333
334 // main value (object name) of the tree view node
335 virtual OUString getObjectName() = 0;
336
337 // should show the expander for the tree view node
338 virtual bool shouldShowExpander() { return false; }
339
340 // fill the children for the current tree view node
341 virtual void fillChildren(std::unique_ptr<weld::TreeView>& rTree, const weld::TreeIter* pParent)
342 = 0;
343
344 // fill any additional column values for the current tree view node
345 virtual std::vector<std::pair<sal_Int32, OUString>> getColumnValues()
346 {
347 return std::vector<std::pair<sal_Int32, OUString>>();
348 }
349};
350
351// appends the node to the root of the tree view
352OUString lclAppendNode(const std::unique_ptr<weld::TreeView>& pTree,
353 ObjectInspectorNodeInterface* pEntry)
354{
355 OUString sName = pEntry->getObjectName();
356 OUString sId(weld::toId(pEntry));
357 std::unique_ptr<weld::TreeIter> pCurrent = pTree->make_iterator();
358 pTree->insert(nullptr, -1, &sName, &sId, nullptr, nullptr, pEntry->shouldShowExpander(),
359 pCurrent.get());
360 pTree->set_text_emphasis(*pCurrent, true, 0);
361
362 for (auto const& rPair : pEntry->getColumnValues())
363 {
364 pTree->set_text(*pCurrent, rPair.second, rPair.first);
365 }
366
367 return sId;
368}
369
370// appends the node to the parent
371OUString lclAppendNodeToParent(const std::unique_ptr<weld::TreeView>& pTree,
372 const weld::TreeIter* pParent, ObjectInspectorNodeInterface* pEntry)
373{
374 OUString sName = pEntry->getObjectName();
375 OUString sId(weld::toId(pEntry));
376 std::unique_ptr<weld::TreeIter> pCurrent = pTree->make_iterator();
377 pTree->insert(pParent, -1, &sName, &sId, nullptr, nullptr, pEntry->shouldShowExpander(),
378 pCurrent.get());
379 pTree->set_text_emphasis(*pCurrent, true, 0);
380
381 for (auto const& rPair : pEntry->getColumnValues())
382 {
383 pTree->set_text(*pCurrent, rPair.second, rPair.first);
384 }
385
386 return sId;
387}
388
390class SimpleStringNode : public ObjectInspectorNodeInterface
391{
392protected:
393 OUString msName;
394
395public:
396 SimpleStringNode(OUString sName)
397 : msName(std::move(sName))
398 {
399 }
400
401 void fillChildren(std::unique_ptr<weld::TreeView>& /*rTree*/,
402 const weld::TreeIter* /*pParent*/) override
403 {
404 }
405
406 OUString getObjectName() override { return msName; }
407};
408
410class MethodNode : public ObjectInspectorNodeInterface
411{
412private:
413 uno::Reference<reflection::XIdlMethod> mxMethod;
414
415public:
416 MethodNode(uno::Reference<reflection::XIdlMethod> xMethod)
417 : mxMethod(std::move(xMethod))
418 {
419 }
420
421 OUString getObjectName() override { return mxMethod->getName(); }
422
423 static OUString simpleTypeName(uno::Reference<reflection::XIdlClass> const& xClass)
424 {
425 switch (xClass->getTypeClass())
426 {
427 case uno::TypeClass_INTERFACE:
428 return SfxResId(STR_METHOD_TYPE_OBJECT);
429 case uno::TypeClass_STRUCT:
430 return SfxResId(STR_METHOD_TYPE_STRUCT);
431 case uno::TypeClass_ENUM:
432 return SfxResId(STR_METHOD_TYPE_ENUM);
433 case uno::TypeClass_SEQUENCE:
434 return SfxResId(STR_METHOD_TYPE_SEQUENCE);
435 default:
436 break;
437 }
438 return xClass->getName();
439 }
440
441 std::vector<std::pair<sal_Int32, OUString>> getColumnValues() override
442 {
443 OUString aOutString;
444 auto xClass = mxMethod->getReturnType();
445 aOutString = simpleTypeName(xClass);
446
447 OUString aInString;
448 const auto aParameters = mxMethod->getParameterInfos();
449 bool bFirst = true;
450 for (auto const& rParameterInfo : aParameters)
451 {
452 if (!bFirst)
453 aInString += ", ";
454 else
455 bFirst = false;
456
457 switch (rParameterInfo.aMode)
458 {
459 case reflection::ParamMode_IN:
460 aInString += SfxResId(STR_PARMETER_MODE_IN) + " ";
461 break;
462 case reflection::ParamMode_OUT:
463 aInString += SfxResId(STR_PARMETER_MODE_OUT) + " ";
464 break;
465 case reflection::ParamMode_INOUT:
466 aInString += SfxResId(STR_PARMETER_MODE_IN_AND_OUT) + " ";
467 break;
468 default:
469 break;
470 }
471
472 aInString += rParameterInfo.aName + " : " + simpleTypeName(rParameterInfo.aType);
473 }
474
475 OUString aImplementationClass = mxMethod->getDeclaringClass()->getName();
476
477 return {
478 { 1, aOutString },
479 { 2, aInString },
480 { 3, aImplementationClass },
481 };
482 }
483
484 void fillChildren(std::unique_ptr<weld::TreeView>& /*rTree*/,
485 const weld::TreeIter* /*pParent*/) override
486 {
487 }
488};
489
496class ClassNode : public ObjectInspectorNodeInterface
497{
498private:
499 uno::Reference<reflection::XIdlClass> mxClass;
500
501 static bool isXInterface(uno::Reference<reflection::XIdlClass> const& xClass)
502 {
503 return xClass->getName() == "com.sun.star.uno.XInterface";
504 }
505
506public:
507 ClassNode(uno::Reference<reflection::XIdlClass> xClass)
508 : mxClass(std::move(xClass))
509 {
510 }
511
512 bool shouldShowExpander() override
513 {
514 auto const& xSuperClasses = mxClass->getSuperclasses();
515 return xSuperClasses.getLength() > 2
516 || (xSuperClasses.getLength() == 1 && !isXInterface(xSuperClasses[0]));
517 }
518
519 OUString getObjectName() override { return mxClass->getName(); }
520
521 // Fill superclasses
522 void fillChildren(std::unique_ptr<weld::TreeView>& rTree,
523 const weld::TreeIter* pParent) override
524 {
525 auto const& xSuperClasses = mxClass->getSuperclasses();
526 for (auto const& xSuper : xSuperClasses)
527 {
528 if (!isXInterface(xSuper))
529 lclAppendNodeToParent(rTree, pParent, new ClassNode(xSuper));
530 }
531 }
532};
533
535class BasicValueNode : public SimpleStringNode
536{
537protected:
538 uno::Any maAny;
539 OUString mrInfo;
540 uno::Reference<uno::XComponentContext> mxContext;
541
542 ObjectInspectorNodeInterface*
543 createNodeObjectForAny(OUString const& rName, const uno::Any& rAny, OUString const& mrInfo);
544
545public:
546 BasicValueNode(OUString const& rName, uno::Any aAny, OUString aInfo,
547 uno::Reference<uno::XComponentContext> xContext)
548 : SimpleStringNode(rName)
549 , maAny(std::move(aAny))
550 , mrInfo(std::move(aInfo))
551 , mxContext(std::move(xContext))
552 {
553 }
554
555 const uno::Any& getAny() const { return maAny; }
556
557 bool shouldShowExpander() override
558 {
559 if (maAny.hasValue())
560 {
561 switch (maAny.getValueType().getTypeClass())
562 {
563 case uno::TypeClass_INTERFACE:
564 {
565 uno::Reference<uno::XInterface> xInterface(maAny, uno::UNO_QUERY);
566 return xInterface.is();
567 }
568 case uno::TypeClass_SEQUENCE:
569 return true;
570 default:
571 break;
572 }
573 }
574 return false;
575 }
576
577 std::vector<std::pair<sal_Int32, OUString>> getColumnValues() override
578 {
579 OUString aValue = convertAnyToShortenedString(maAny, mxContext);
580 OUString aType = getAnyType(maAny);
581
582 return { { 1, aValue }, { 2, aType }, { 3, mrInfo } };
583 }
584};
585
587class GenericPropertiesNode : public BasicValueNode
588{
589public:
590 GenericPropertiesNode(OUString const& rName, uno::Any const& rAny, OUString const& rInfo,
591 uno::Reference<uno::XComponentContext> const& xContext)
592 : BasicValueNode(rName, rAny, rInfo, xContext)
593 {
594 }
595
596 void fillChildren(std::unique_ptr<weld::TreeView>& pTree,
597 const weld::TreeIter* pParent) override;
598};
599
601class StructNode : public BasicValueNode
602{
603public:
604 StructNode(OUString const& rName, uno::Any const& rAny, OUString const& rInfo,
605 uno::Reference<uno::XComponentContext> const& xContext)
606 : BasicValueNode(rName, rAny, rInfo, xContext)
607 {
608 }
609
610 bool shouldShowExpander() override { return true; }
611
612 void fillChildren(std::unique_ptr<weld::TreeView>& pTree,
613 const weld::TreeIter* pParent) override;
614};
615
617class SequenceNode : public BasicValueNode
618{
619 uno::Reference<reflection::XIdlArray> mxIdlArray;
620
621public:
622 SequenceNode(OUString const& rName, uno::Any const& rAny, OUString const& rInfo,
623 uno::Reference<uno::XComponentContext> const& xContext)
624 : BasicValueNode(rName, rAny, rInfo, xContext)
625 {
626 auto xClass = convertTypeToIdlClass(maAny.getValueType(), mxContext);
627 mxIdlArray = xClass->getArray();
628 }
629
630 bool shouldShowExpander() override
631 {
632 // Show expander only if the sequence has elements
633 int nLength = mxIdlArray->getLen(maAny);
634 return nLength > 0;
635 }
636
637 void fillChildren(std::unique_ptr<weld::TreeView>& pTree,
638 const weld::TreeIter* pParent) override
639 {
640 int nLength = mxIdlArray->getLen(maAny);
641
642 for (int i = 0; i < nLength; i++)
643 {
644 uno::Any aArrayValue = mxIdlArray->get(maAny, i);
645
646 auto* pObjectInspectorNode
647 = createNodeObjectForAny(OUString::number(i), aArrayValue, "");
648 if (pObjectInspectorNode)
649 lclAppendNodeToParent(pTree, pParent, pObjectInspectorNode);
650 }
651 }
652
653 std::vector<std::pair<sal_Int32, OUString>> getColumnValues() override
654 {
655 int nLength = mxIdlArray->getLen(maAny);
656
657 OUString aType
658 = getAnyType(maAny).replaceAll(u"[]", u"") + u"[" + OUString::number(nLength) + u"]";
659
660 OUString aValue
661 = SfxResId(STR_PROPERTY_VALUE_SEQUENCE).replaceFirst("%1", OUString::number(nLength));
662
663 return {
664 { 1, aValue },
665 { 2, aType },
666 };
667 }
668};
669
670void GenericPropertiesNode::fillChildren(std::unique_ptr<weld::TreeView>& pTree,
671 const weld::TreeIter* pParent)
672{
673 if (!maAny.hasValue())
674 return;
675
676 try
677 {
678 const auto xNameAccess = uno::Reference<container::XNameAccess>(maAny, uno::UNO_QUERY);
679 if (xNameAccess.is())
680 {
681 const uno::Sequence<OUString> aNames = xNameAccess->getElementNames();
682 for (OUString const& rName : aNames)
683 {
684 uno::Any aAny = xNameAccess->getByName(rName);
685 auto* pObjectInspectorNode = createNodeObjectForAny(
686 u"@" + rName, aAny, SfxResId(STR_PROPERTY_TYPE_IS_NAMED_CONTAINER));
687 lclAppendNodeToParent(pTree, pParent, pObjectInspectorNode);
688 }
689 }
690 }
691 catch (...)
692 {
693 }
694
695 try
696 {
697 const auto xIndexAccess = uno::Reference<container::XIndexAccess>(maAny, uno::UNO_QUERY);
698 if (xIndexAccess.is())
699 {
700 for (sal_Int32 nIndex = 0; nIndex < xIndexAccess->getCount(); ++nIndex)
701 {
702 uno::Any aAny = xIndexAccess->getByIndex(nIndex);
703 auto* pObjectInspectorNode
704 = createNodeObjectForAny(u"@" + OUString::number(nIndex), aAny,
705 SfxResId(STR_PROPERTY_TYPE_IS_INDEX_CONTAINER));
706 lclAppendNodeToParent(pTree, pParent, pObjectInspectorNode);
707 }
708 }
709 }
710 catch (...)
711 {
712 }
713
714 try
715 {
716 const auto xEnumAccess
717 = uno::Reference<container::XEnumerationAccess>(maAny, uno::UNO_QUERY);
718 if (xEnumAccess.is())
719 {
720 uno::Reference<container::XEnumeration> xEnumeration = xEnumAccess->createEnumeration();
721 if (xEnumeration.is())
722 {
723 for (sal_Int32 nIndex = 0; xEnumeration->hasMoreElements(); nIndex++)
724 {
725 uno::Any aAny = xEnumeration->nextElement();
726 auto* pObjectInspectorNode
727 = createNodeObjectForAny(u"@" + OUString::number(nIndex), aAny,
728 SfxResId(STR_PROPERTY_TYPE_IS_ENUMERATION));
729 lclAppendNodeToParent(pTree, pParent, pObjectInspectorNode);
730 }
731 }
732 }
733 }
734 catch (...)
735 {
736 }
737
738 auto xInvocationFactory = css::script::Invocation::create(mxContext);
739 uno::Sequence<uno::Any> aParameters = { maAny };
740 auto xInvocationInterface = xInvocationFactory->createInstanceWithArguments(aParameters);
741 if (!xInvocationInterface.is())
742 return;
743
744 uno::Reference<script::XInvocation2> xInvocation(xInvocationInterface, uno::UNO_QUERY);
745 if (!xInvocation.is())
746 return;
747
748 auto const& xInvocationAccess = xInvocation->getIntrospection();
749 if (!xInvocationAccess.is())
750 return;
751
752 uno::Sequence<script::InvocationInfo> aInvocationInfoSequence;
753 try
754 {
755 aInvocationInfoSequence = xInvocation->getInfo();
756 }
757 catch (...)
758 {
759 }
760
761 for (auto const& aInvocationInfo : std::as_const(aInvocationInfoSequence))
762 {
763 if (aInvocationInfo.eMemberType == script::MemberType_PROPERTY)
764 {
765 uno::Any aCurrentAny;
766 auto const& aPropertyName = aInvocationInfo.aName;
767
768 bool bIsAttribute = false;
769 bool bIsGetSetMethod = false;
770 bool bMethodGet = false;
771 bool bMethodSet = false;
772 bool bMethodIs = false;
773 try
774 {
775 aCurrentAny = xInvocation->getValue(aPropertyName);
776 bIsAttribute = xInvocationAccess->hasProperty(aPropertyName,
777 beans::PropertyConcept::ATTRIBUTES);
778 bIsGetSetMethod = xInvocationAccess->hasProperty(aPropertyName,
779 beans::PropertyConcept::METHODS);
780 if (bIsGetSetMethod)
781 {
782 bMethodGet = xInvocationAccess->hasMethod(u"get" + aPropertyName,
783 beans::MethodConcept::PROPERTY);
784 bMethodSet = xInvocationAccess->hasMethod(u"set" + aPropertyName,
785 beans::MethodConcept::PROPERTY);
786 bMethodIs = xInvocationAccess->hasMethod(u"is" + aPropertyName,
787 beans::MethodConcept::PROPERTY);
788 }
789 }
790 catch (...)
791 {
792 }
793
794 std::vector<OUString> aInfoCollection;
795 if (bIsAttribute)
796 aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_IS_ATTRIBUTE));
797 if (bIsGetSetMethod)
798 {
799 bool bHasGet = false;
800 OUString aString;
801 if (bMethodGet || bMethodIs)
802 {
803 aString += SfxResId(STR_PROPERTY_ATTRIBUTE_GET);
804 bHasGet = true;
805 }
806 if (bMethodSet)
807 {
808 if (bHasGet)
809 aString += u"+";
810 aString += SfxResId(STR_PROPERTY_ATTRIBUTE_SET);
811 }
812 aInfoCollection.push_back(aString);
813 if (bMethodSet && !bHasGet)
814 aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_WRITEONLY));
815 }
816 if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::MAYBEVOID)
817 aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_MAYBEVOID));
818 if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::READONLY)
819 aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_READONLY));
820 if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::REMOVABLE)
821 aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_REMOVABLE));
822 if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::BOUND)
823 aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_BOUND));
824 if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::CONSTRAINED)
825 aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_CONSTRAINED));
826 if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::TRANSIENT)
827 aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_TRANSIENT));
828 if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::MAYBEAMBIGUOUS)
829 aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_MAYBEAMBIGUOUS));
830 if (aInvocationInfo.PropertyAttribute & beans::PropertyAttribute::MAYBEDEFAULT)
831 aInfoCollection.push_back(SfxResId(STR_PROPERTY_ATTRIBUTE_MAYBEDEFAULT));
832
833 bool bSet = false;
834 OUString aInfoString;
835 for (auto const& rString : aInfoCollection)
836 {
837 if (bSet)
838 aInfoString += ", ";
839 else
840 bSet = true;
841
842 aInfoString += rString;
843 }
844
845 auto* pObjectInspectorNode
846 = createNodeObjectForAny(aPropertyName, aCurrentAny, aInfoString);
847 if (pObjectInspectorNode)
848 lclAppendNodeToParent(pTree, pParent, pObjectInspectorNode);
849 }
850 }
851}
852
853void StructNode::fillChildren(std::unique_ptr<weld::TreeView>& pTree, const weld::TreeIter* pParent)
854{
855 auto xReflection = reflection::theCoreReflection::get(mxContext);
856 uno::Reference<reflection::XIdlClass> xClass
857 = xReflection->forName(maAny.getValueType().getTypeName());
858
859 const auto xFields = xClass->getFields();
860
861 for (auto const& xField : xFields)
862 {
863 OUString aFieldName = xField->getName();
864 uno::Any aFieldValue = xField->get(maAny);
865
866 auto* pObjectInspectorNode = createNodeObjectForAny(aFieldName, aFieldValue, "");
867 if (pObjectInspectorNode)
868 {
869 lclAppendNodeToParent(pTree, pParent, pObjectInspectorNode);
870 }
871 }
872}
873
874ObjectInspectorNodeInterface* BasicValueNode::createNodeObjectForAny(OUString const& rName,
875 const uno::Any& rAny,
876 OUString const& rInfo)
877{
878 switch (rAny.getValueType().getTypeClass())
879 {
880 case uno::TypeClass_INTERFACE:
881 return new GenericPropertiesNode(rName, rAny, rInfo, mxContext);
882
883 case uno::TypeClass_SEQUENCE:
884 return new SequenceNode(rName, rAny, rInfo, mxContext);
885
886 case uno::TypeClass_STRUCT:
887 return new StructNode(rName, rAny, rInfo, mxContext);
888
889 default:
890 break;
891 }
892
893 return new BasicValueNode(rName, rAny, rInfo, mxContext);
894}
895
896} // end anonymous namespace
897
898// Object inspector tree view helper functions
899namespace
900{
901ObjectInspectorNodeInterface* getSelectedNode(weld::TreeView const& rTreeView)
902{
903 OUString sID = rTreeView.get_selected_id();
904 if (sID.isEmpty())
905 return nullptr;
906
907 if (auto* pNode = weld::fromId<ObjectInspectorNodeInterface*>(sID))
908 return pNode;
909
910 return nullptr;
911}
912
913uno::Reference<uno::XInterface> getSelectedXInterface(weld::TreeView const& rTreeView)
914{
915 uno::Reference<uno::XInterface> xInterface;
916
917 if (auto* pNode = getSelectedNode(rTreeView))
918 {
919 if (auto* pBasicValueNode = dynamic_cast<BasicValueNode*>(pNode))
920 {
921 uno::Any aAny = pBasicValueNode->getAny();
922 xInterface.set(aAny, uno::UNO_QUERY);
923 }
924 }
925
926 return xInterface;
927}
928
929} // end anonymous namespace
930
932 std::unique_ptr<ObjectInspectorWidgets>& pObjectInspectorWidgets)
933 : mpObjectInspectorWidgets(pObjectInspectorWidgets)
935 , mxSorter(mxContext, Application::GetSettings().GetLanguageTag().getLocale())
936{
937 mpObjectInspectorWidgets->mpInterfacesTreeView->connect_expanding(
938 LINK(this, ObjectInspectorTreeHandler, ExpandingHandlerInterfaces));
939 mpObjectInspectorWidgets->mpServicesTreeView->connect_expanding(
940 LINK(this, ObjectInspectorTreeHandler, ExpandingHandlerServices));
941 mpObjectInspectorWidgets->mpPropertiesTreeView->connect_expanding(
942 LINK(this, ObjectInspectorTreeHandler, ExpandingHandlerProperties));
943 mpObjectInspectorWidgets->mpMethodsTreeView->connect_expanding(
944 LINK(this, ObjectInspectorTreeHandler, ExpandingHandlerMethods));
945
946 mpObjectInspectorWidgets->mpPropertiesTreeView->connect_popup_menu(
947 LINK(this, ObjectInspectorTreeHandler, PopupMenuHandler));
948
949 mpObjectInspectorWidgets->mpInterfacesTreeView->connect_changed(
950 LINK(this, ObjectInspectorTreeHandler, SelectionChanged));
951 mpObjectInspectorWidgets->mpServicesTreeView->connect_changed(
952 LINK(this, ObjectInspectorTreeHandler, SelectionChanged));
953 mpObjectInspectorWidgets->mpPropertiesTreeView->connect_changed(
954 LINK(this, ObjectInspectorTreeHandler, SelectionChanged));
955 mpObjectInspectorWidgets->mpMethodsTreeView->connect_changed(
956 LINK(this, ObjectInspectorTreeHandler, SelectionChanged));
957
958 mpObjectInspectorWidgets->mpInterfacesTreeView->make_sorted();
959 mpObjectInspectorWidgets->mpServicesTreeView->make_sorted();
960 mpObjectInspectorWidgets->mpPropertiesTreeView->make_sorted();
961 mpObjectInspectorWidgets->mpMethodsTreeView->make_sorted();
962
963 setSortFunction(mpObjectInspectorWidgets->mpInterfacesTreeView);
964 setSortFunction(mpObjectInspectorWidgets->mpServicesTreeView);
965 setSortFunction(mpObjectInspectorWidgets->mpPropertiesTreeView);
966 setSortFunction(mpObjectInspectorWidgets->mpMethodsTreeView);
967
968 mpObjectInspectorWidgets->mpInterfacesTreeView->connect_column_clicked(
969 LINK(this, ObjectInspectorTreeHandler, HeaderBarClick));
970 mpObjectInspectorWidgets->mpServicesTreeView->connect_column_clicked(
971 LINK(this, ObjectInspectorTreeHandler, HeaderBarClick));
972 mpObjectInspectorWidgets->mpPropertiesTreeView->connect_column_clicked(
973 LINK(this, ObjectInspectorTreeHandler, HeaderBarClick));
974 mpObjectInspectorWidgets->mpMethodsTreeView->connect_column_clicked(
975 LINK(this, ObjectInspectorTreeHandler, HeaderBarClick));
976
977 mpObjectInspectorWidgets->mpToolbar->connect_clicked(
978 LINK(this, ObjectInspectorTreeHandler, ToolbarButtonClicked));
979 mpObjectInspectorWidgets->mpToolbar->set_item_sensitive("inspect", false);
980 mpObjectInspectorWidgets->mpToolbar->set_item_sensitive("back", false);
981
982 mpObjectInspectorWidgets->mpNotebook->connect_leave_page(
983 LINK(this, ObjectInspectorTreeHandler, NotebookLeavePage));
984 mpObjectInspectorWidgets->mpNotebook->connect_enter_page(
985 LINK(this, ObjectInspectorTreeHandler, NotebookEnterPage));
986
987 auto nPropertiesDigitWidth
988 = mpObjectInspectorWidgets->mpPropertiesTreeView->get_approximate_digit_width();
989 std::vector<int> aPropertiesWidths(4, nPropertiesDigitWidth * 30);
990 mpObjectInspectorWidgets->mpPropertiesTreeView->set_column_fixed_widths(aPropertiesWidths);
991
992 auto nMethodsDigitWidth
993 = mpObjectInspectorWidgets->mpMethodsTreeView->get_approximate_digit_width();
994 std::vector<int> aMethodsWidths{ static_cast<int>(nMethodsDigitWidth * 30),
995 static_cast<int>(nMethodsDigitWidth * 15),
996 static_cast<int>(nMethodsDigitWidth * 30),
997 static_cast<int>(nMethodsDigitWidth * 50) };
998 mpObjectInspectorWidgets->mpMethodsTreeView->set_column_fixed_widths(aMethodsWidths);
999
1000 mpObjectInspectorWidgets->mpPaned->set_position(160);
1001}
1002
1003void ObjectInspectorTreeHandler::setSortFunction(std::unique_ptr<weld::TreeView>& pTreeView)
1004{
1005 pTreeView->set_sort_func(
1006 [this, &pTreeView](const weld::TreeIter& rLeft, const weld::TreeIter& rRight) {
1007 return compare(pTreeView, rLeft, rRight);
1008 });
1009}
1010
1011sal_Int32 ObjectInspectorTreeHandler::compare(std::unique_ptr<weld::TreeView>& pTreeView,
1012 const weld::TreeIter& rLeft,
1013 const weld::TreeIter& rRight)
1014{
1015 int nSortColumn = pTreeView->get_sort_column();
1016
1017 OUString sLeft = pTreeView->get_text(rLeft, nSortColumn);
1018 OUString sRight = pTreeView->get_text(rRight, nSortColumn);
1019 sal_Int32 nCompare = mxSorter.compare(sLeft, sRight);
1020 return nCompare;
1021}
1022
1023void ObjectInspectorTreeHandler::handleExpanding(std::unique_ptr<weld::TreeView>& pTreeView,
1024 weld::TreeIter const& rParent)
1025{
1026 OUString sID = pTreeView->get_id(rParent);
1027 if (sID.isEmpty())
1028 return;
1029
1030 clearObjectInspectorChildren(pTreeView, rParent);
1031 auto* pNode = weld::fromId<ObjectInspectorNodeInterface*>(sID);
1032 pNode->fillChildren(pTreeView, &rParent);
1033}
1034
1035IMPL_LINK(ObjectInspectorTreeHandler, ExpandingHandlerInterfaces, weld::TreeIter const&, rParent,
1036 bool)
1037{
1038 handleExpanding(mpObjectInspectorWidgets->mpInterfacesTreeView, rParent);
1039 return true;
1040}
1041
1042IMPL_LINK(ObjectInspectorTreeHandler, ExpandingHandlerServices, weld::TreeIter const&, rParent,
1043 bool)
1044{
1045 handleExpanding(mpObjectInspectorWidgets->mpServicesTreeView, rParent);
1046 return true;
1047}
1048
1049IMPL_LINK(ObjectInspectorTreeHandler, ExpandingHandlerProperties, weld::TreeIter const&, rParent,
1050 bool)
1051{
1052 handleExpanding(mpObjectInspectorWidgets->mpPropertiesTreeView, rParent);
1053 return true;
1054}
1055
1056IMPL_LINK(ObjectInspectorTreeHandler, ExpandingHandlerMethods, weld::TreeIter const&, rParent, bool)
1057{
1058 handleExpanding(mpObjectInspectorWidgets->mpMethodsTreeView, rParent);
1059 return true;
1060}
1061
1062IMPL_LINK(ObjectInspectorTreeHandler, SelectionChanged, weld::TreeView&, rTreeView, void)
1063{
1064 bool bHaveNodeWithObject = false;
1065 mpObjectInspectorWidgets->mpTextView->set_text("");
1066 if (mpObjectInspectorWidgets->mpPropertiesTreeView.get() == &rTreeView)
1067 {
1068 auto* pNode = getSelectedNode(rTreeView);
1069 if (auto* pBasicValueNode = dynamic_cast<BasicValueNode*>(pNode))
1070 {
1071 uno::Any aAny = pBasicValueNode->getAny();
1072 uno::Reference<uno::XInterface> xInterface(aAny, uno::UNO_QUERY);
1073 bHaveNodeWithObject = xInterface.is();
1074 mpObjectInspectorWidgets->mpTextView->set_text(convertAnyToString(aAny, mxContext));
1075 }
1076 }
1077
1078 mpObjectInspectorWidgets->mpToolbar->set_item_sensitive("inspect", bHaveNodeWithObject);
1079}
1080
1081static void updateOrder(const std::unique_ptr<weld::TreeView>& pTreeView, sal_Int32 nColumn)
1082{
1083 pTreeView->set_sort_column(nColumn);
1084
1085 bool bSortAtoZ = pTreeView->get_sort_order();
1086 pTreeView->set_sort_order(!bSortAtoZ);
1087 pTreeView->set_sort_indicator(!bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn);
1088}
1089
1090IMPL_LINK(ObjectInspectorTreeHandler, HeaderBarClick, int, nColumn, void)
1091{
1092 auto rPageId = mpObjectInspectorWidgets->mpNotebook->get_current_page_ident();
1093
1094 if (rPageId == "object_inspector_interfaces_tab")
1095 updateOrder(mpObjectInspectorWidgets->mpInterfacesTreeView, nColumn);
1096 else if (rPageId == "object_inspector_services_tab")
1097 updateOrder(mpObjectInspectorWidgets->mpServicesTreeView, nColumn);
1098 else if (rPageId == "object_inspector_properties_tab")
1099 updateOrder(mpObjectInspectorWidgets->mpPropertiesTreeView, nColumn);
1100 else if (rPageId == "object_inspector_methods_tab")
1101 updateOrder(mpObjectInspectorWidgets->mpMethodsTreeView, nColumn);
1102}
1103
1104IMPL_LINK(ObjectInspectorTreeHandler, PopupMenuHandler, const CommandEvent&, rCommandEvent, bool)
1105{
1106 if (rCommandEvent.GetCommand() != CommandEventId::ContextMenu)
1107 return false;
1108
1109 auto xInterface = getSelectedXInterface(*mpObjectInspectorWidgets->mpPropertiesTreeView);
1110 if (xInterface.is())
1111 {
1112 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(
1113 mpObjectInspectorWidgets->mpPropertiesTreeView.get(), "sfx/ui/devtoolsmenu.ui"));
1114 std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("inspect_menu"));
1115
1116 OUString sCommand(
1117 xMenu->popup_at_rect(mpObjectInspectorWidgets->mpPropertiesTreeView.get(),
1118 tools::Rectangle(rCommandEvent.GetMousePosPixel(), Size(1, 1))));
1119
1120 if (sCommand == "inspect")
1121 {
1122 addToStack(uno::Any(xInterface));
1123 inspectObject(xInterface);
1124 }
1125 }
1126 return true;
1127}
1128
1129IMPL_LINK(ObjectInspectorTreeHandler, ToolbarButtonClicked, const OUString&, rSelectionId, void)
1130{
1131 if (rSelectionId == "inspect")
1132 {
1133 auto xInterface = getSelectedXInterface(*mpObjectInspectorWidgets->mpPropertiesTreeView);
1134 if (xInterface.is())
1135 {
1136 addToStack(uno::Any(xInterface));
1137 inspectObject(xInterface);
1138 }
1139 }
1140 else if (rSelectionId == "back")
1141 {
1142 uno::Any aAny = popFromStack();
1143 if (aAny.hasValue())
1144 {
1145 uno::Reference<uno::XInterface> xInterface(aAny, uno::UNO_QUERY);
1146 inspectObject(xInterface);
1147 }
1148 }
1149 else if (rSelectionId == "refresh")
1150 {
1151 auto rPageId = mpObjectInspectorWidgets->mpNotebook->get_current_page_ident();
1152 NotebookEnterPage(rPageId);
1153 }
1154}
1155
1156IMPL_LINK(ObjectInspectorTreeHandler, NotebookEnterPage, const OUString&, rPageId, void)
1157{
1158 uno::Any aAny = maInspectionStack.back();
1159 if (!aAny.hasValue())
1160 return;
1161
1162 uno::Reference<uno::XInterface> xInterface(aAny, uno::UNO_QUERY);
1163 if (rPageId == "object_inspector_interfaces_tab")
1164 {
1165 mpObjectInspectorWidgets->mpInterfacesTreeView->freeze();
1166 clearAll(mpObjectInspectorWidgets->mpInterfacesTreeView);
1167 appendInterfaces(xInterface);
1168 mpObjectInspectorWidgets->mpInterfacesTreeView->thaw();
1169 }
1170 else if (rPageId == "object_inspector_services_tab")
1171 {
1172 mpObjectInspectorWidgets->mpServicesTreeView->freeze();
1173 clearAll(mpObjectInspectorWidgets->mpServicesTreeView);
1174 appendServices(xInterface);
1175 mpObjectInspectorWidgets->mpServicesTreeView->thaw();
1176 }
1177 else if (rPageId == "object_inspector_properties_tab")
1178 {
1179 mpObjectInspectorWidgets->mpPropertiesTreeView->freeze();
1180 clearAll(mpObjectInspectorWidgets->mpPropertiesTreeView);
1181 appendProperties(xInterface);
1182 mpObjectInspectorWidgets->mpPropertiesTreeView->thaw();
1183 }
1184 else if (rPageId == "object_inspector_methods_tab")
1185 {
1186 mpObjectInspectorWidgets->mpMethodsTreeView->freeze();
1187 clearAll(mpObjectInspectorWidgets->mpMethodsTreeView);
1188 appendMethods(xInterface);
1189 mpObjectInspectorWidgets->mpMethodsTreeView->thaw();
1190 }
1191}
1192
1193IMPL_LINK(ObjectInspectorTreeHandler, NotebookLeavePage, const OUString&, rPageId, bool)
1194{
1195 if (rPageId == "object_inspector_interfaces_tab")
1196 {
1197 mpObjectInspectorWidgets->mpInterfacesTreeView->freeze();
1198 clearAll(mpObjectInspectorWidgets->mpInterfacesTreeView);
1199 mpObjectInspectorWidgets->mpInterfacesTreeView->thaw();
1200 }
1201 else if (rPageId == "object_inspector_services_tab")
1202 {
1203 mpObjectInspectorWidgets->mpServicesTreeView->freeze();
1204 clearAll(mpObjectInspectorWidgets->mpServicesTreeView);
1205 mpObjectInspectorWidgets->mpServicesTreeView->thaw();
1206 }
1207 else if (rPageId == "object_inspector_properties_tab")
1208 {
1209 mpObjectInspectorWidgets->mpPropertiesTreeView->freeze();
1210 clearAll(mpObjectInspectorWidgets->mpPropertiesTreeView);
1211 mpObjectInspectorWidgets->mpPropertiesTreeView->thaw();
1212 }
1213 else if (rPageId == "object_inspector_methods_tab")
1214 {
1215 mpObjectInspectorWidgets->mpMethodsTreeView->freeze();
1216 clearAll(mpObjectInspectorWidgets->mpMethodsTreeView);
1217 mpObjectInspectorWidgets->mpMethodsTreeView->thaw();
1218 }
1219 return true;
1220}
1221
1223 std::unique_ptr<weld::TreeView>& pTreeView, weld::TreeIter const& rParent)
1224{
1225 bool bChild = false;
1226 do
1227 {
1228 bChild = pTreeView->iter_has_child(rParent);
1229 if (bChild)
1230 {
1231 std::unique_ptr<weld::TreeIter> pChild = pTreeView->make_iterator(&rParent);
1232 bChild = pTreeView->iter_children(*pChild);
1233 if (bChild)
1234 {
1235 clearObjectInspectorChildren(pTreeView, *pChild);
1236 OUString sID = pTreeView->get_id(*pChild);
1237 auto* pEntry = weld::fromId<ObjectInspectorNodeInterface*>(sID);
1238 delete pEntry;
1239 pTreeView->remove(*pChild);
1240 }
1241 }
1242 } while (bChild);
1243}
1244
1246void ObjectInspectorTreeHandler::clearAll(std::unique_ptr<weld::TreeView>& pTreeView)
1247{
1248 // destroy all ObjectInspectorNodes from the tree
1249 pTreeView->all_foreach([&pTreeView](weld::TreeIter& rEntry) {
1250 OUString sID = pTreeView->get_id(rEntry);
1251 auto* pEntry = weld::fromId<ObjectInspectorNodeInterface*>(sID);
1252 delete pEntry;
1253 return false;
1254 });
1255 pTreeView->clear();
1256}
1257
1259void ObjectInspectorTreeHandler::appendInterfaces(uno::Reference<uno::XInterface> const& xInterface)
1260{
1261 if (!xInterface.is())
1262 return;
1263
1264 uno::Reference<lang::XTypeProvider> xTypeProvider(xInterface, uno::UNO_QUERY);
1265 if (xTypeProvider.is())
1266 {
1267 const auto xSequenceTypes = xTypeProvider->getTypes();
1268 for (auto const& xType : xSequenceTypes)
1269 {
1270 auto xClass = convertTypeToIdlClass(xType, mxContext);
1271 lclAppendNode(mpObjectInspectorWidgets->mpInterfacesTreeView, new ClassNode(xClass));
1272 }
1273 }
1274}
1275
1277void ObjectInspectorTreeHandler::appendServices(uno::Reference<uno::XInterface> const& xInterface)
1278{
1279 if (!xInterface.is())
1280 return;
1281
1282 auto xServiceInfo = uno::Reference<lang::XServiceInfo>(xInterface, uno::UNO_QUERY);
1283 const uno::Sequence<OUString> aServiceNames(xServiceInfo->getSupportedServiceNames());
1284 for (auto const& aServiceName : aServiceNames)
1285 {
1286 lclAppendNode(mpObjectInspectorWidgets->mpServicesTreeView,
1287 new SimpleStringNode(aServiceName));
1288 }
1289}
1290
1292void ObjectInspectorTreeHandler::appendProperties(uno::Reference<uno::XInterface> const& xInterface)
1293{
1294 if (!xInterface.is())
1295 return;
1296 GenericPropertiesNode aNode("", uno::Any(xInterface), "", mxContext);
1297 aNode.fillChildren(mpObjectInspectorWidgets->mpPropertiesTreeView, nullptr);
1298}
1299
1301void ObjectInspectorTreeHandler::appendMethods(uno::Reference<uno::XInterface> const& xInterface)
1302{
1303 if (!xInterface.is())
1304 return;
1305
1306 uno::Reference<beans::XIntrospection> xIntrospection = beans::theIntrospection::get(mxContext);
1307 auto xIntrospectionAccess = xIntrospection->inspect(uno::Any(xInterface));
1308
1309 const auto xMethods = xIntrospectionAccess->getMethods(beans::MethodConcept::ALL);
1310 for (auto const& xMethod : xMethods)
1311 {
1312 lclAppendNode(mpObjectInspectorWidgets->mpMethodsTreeView, new MethodNode(xMethod));
1313 }
1314}
1315
1316// Update the back button state depending if there are objects in the stack
1318{
1319 mpObjectInspectorWidgets->mpToolbar->set_item_sensitive("back", maInspectionStack.size() > 1);
1320}
1321
1322// Clears all the objects from the stack
1324{
1325 maInspectionStack.clear();
1327}
1328
1329// Adds an object to the stack
1330void ObjectInspectorTreeHandler::addToStack(css::uno::Any const& rAny)
1331{
1332 maInspectionStack.push_back(rAny);
1334}
1335
1336// Removes an object from the back of the stack and return it
1338{
1339 maInspectionStack.pop_back();
1340 uno::Any aAny = maInspectionStack.back();
1342 return aAny;
1343}
1344
1345// Inspect the input object in the object inspector
1346void ObjectInspectorTreeHandler::inspectObject(uno::Reference<uno::XInterface> const& xInterface)
1347{
1348 if (!xInterface.is())
1349 return;
1350
1351 // Set implementation name
1352 OUString aImplementationName = getInterfaceImplementationClass(xInterface);
1353 mpObjectInspectorWidgets->mpClassNameLabel->set_label(aImplementationName);
1354 sal_Int32 nStrLen = aImplementationName.getLength();
1355 sal_Int32 nDigitWidth
1356 = mpObjectInspectorWidgets->mpClassNameLabel->get_approximate_digit_width();
1357
1358 //get_about_digit_width() returns an approximate value. To always see the full class name (nStrLen+2)
1359 mpObjectInspectorWidgets->mpClassNameLabel->set_size_request((nStrLen + 2) * nDigitWidth, -1);
1360
1361 // Fire entering the current opened page manually
1362 auto rPageId = mpObjectInspectorWidgets->mpNotebook->get_current_page_ident();
1363 NotebookEnterPage(rPageId);
1364}
1365
1366// Inspect the input object in the object inspector.
1367// Make the input object the root of the stack (clear all other
1368// objects from the stack).
1369void ObjectInspectorTreeHandler::introspect(uno::Reference<uno::XInterface> const& xInterface)
1370{
1371 clearStack();
1372 addToStack(uno::Any(xInterface));
1373 inspectObject(xInterface);
1374}
1375
1377{
1378 // We need to clear all the nodes
1379 clearAll(mpObjectInspectorWidgets->mpInterfacesTreeView);
1380 clearAll(mpObjectInspectorWidgets->mpServicesTreeView);
1381 clearAll(mpObjectInspectorWidgets->mpPropertiesTreeView);
1382 clearAll(mpObjectInspectorWidgets->mpMethodsTreeView);
1383}
1384
1385/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static void updateOrder(const std::unique_ptr< weld::TreeView > &pTreeView, sal_Int32 nColumn)
IMPL_LINK(ObjectInspectorTreeHandler, ExpandingHandlerInterfaces, weld::TreeIter const &, rParent, bool)
SbMethodRef xMethod
static std::unique_ptr< weld::Builder > CreateBuilder(weld::Widget *pParent, const OUString &rUIFile, bool bMobile=false, sal_uInt64 nLOKWindowId=0)
Object inspector tree handler.
std::deque< css::uno::Any > maInspectionStack
void inspectObject(css::uno::Reference< css::uno::XInterface > const &xInterface)
static void handleExpanding(std::unique_ptr< weld::TreeView > &pTreeView, weld::TreeIter const &rParent)
css::uno::Reference< css::uno::XComponentContext > mxContext
void appendProperties(css::uno::Reference< css::uno::XInterface > const &xInterface)
Append properties to the "properties" tree view.
void introspect(css::uno::Reference< css::uno::XInterface > const &xInterface)
std::unique_ptr< ObjectInspectorWidgets > & mpObjectInspectorWidgets
static void clearAll(std::unique_ptr< weld::TreeView > &pTreeView)
Deletes all the node objects in a tree view.
void appendMethods(css::uno::Reference< css::uno::XInterface > const &xInterface)
Append methods to the "methods" tree view.
sal_Int32 compare(std::unique_ptr< weld::TreeView > &pTreeView, const weld::TreeIter &rLeft, const weld::TreeIter &rRight)
ObjectInspectorTreeHandler(std::unique_ptr< ObjectInspectorWidgets > &pObjectInspectorWidgets)
comphelper::string::NaturalStringSorter mxSorter
void appendInterfaces(css::uno::Reference< css::uno::XInterface > const &xInterface)
Append interfaces to the "interfaces" tree view.
void setSortFunction(std::unique_ptr< weld::TreeView > &pTreeView)
void appendServices(css::uno::Reference< css::uno::XInterface > const &xInterface)
Append services to the "services" tree view.
static void clearObjectInspectorChildren(std::unique_ptr< weld::TreeView > &pTreeView, weld::TreeIter const &rParent)
void addToStack(css::uno::Any const &rAny)
sal_Int32 compare(const OUString &rLHS, const OUString &rRHS) const
virtual OUString get_selected_id() const=0
uno::Reference< uno::XComponentContext > mxContext
float u
Sequence< OUString > aServiceNames
OUString aImplementationName
DocumentType eType
OUString sName
TRISTATE_FALSE
TRISTATE_TRUE
sal_Int32 nIndex
Reference< XIntrospection > xIntrospection
const LanguageTag & getLocale()
Reference< XComponentContext > getProcessComponentContext()
bool enum2int(sal_Int32 &rnEnum, const css::uno::Any &rAny)
int i
OUString toId(const void *pValue)
Reference< XInvocation2 > xInvocation
OUString SfxResId(TranslateId aId)
Definition: sfxresid.cxx:22
bool hasValue()
OUString msName
sal_uInt16 sal_Unicode
signed char sal_Int8
OUString sId
sal_Int32 nLength