summaryrefslogtreecommitdiff
path: root/svx
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2021-02-03 21:33:29 +0900
committerTomaž Vajngerl <quikee@gmail.com>2021-02-10 14:16:20 +0100
commit570df33b75298b7c7c3e7afd233d36d0cdf7e0a3 (patch)
treec4998b9d544a6eb925af1db1fb07731b2efcbeae /svx
parente71350e037dcd49f24c939395ab6436051382c83 (diff)
devtools: handle object inspector with attached objects
This changes the object inspector tree view to create child nodes on demand (when expanded) and attach specialized node objects to the node, which are responsible to get the specific introspection information for the current inspected UNO object. Change-Id: Ib8431cc2a2c6d6d3ac7fd9db5bc61c9071d5e8f8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/110462 Tested-by: Tomaž Vajngerl <quikee@gmail.com> Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'svx')
-rw-r--r--svx/source/devtools/DevelopmentToolDockingWindow.cxx471
1 files changed, 318 insertions, 153 deletions
diff --git a/svx/source/devtools/DevelopmentToolDockingWindow.cxx b/svx/source/devtools/DevelopmentToolDockingWindow.cxx
index da3b8d5896b5..8c519e807125 100644
--- a/svx/source/devtools/DevelopmentToolDockingWindow.cxx
+++ b/svx/source/devtools/DevelopmentToolDockingWindow.cxx
@@ -100,105 +100,6 @@ private:
SelectionChangeHandler& operator=(const SelectionChangeHandler&) = delete;
};
-} // end anonymous namespace
-
-DevelopmentToolDockingWindow::DevelopmentToolDockingWindow(SfxBindings* pInputBindings,
- SfxChildWindow* pChildWindow,
- vcl::Window* pParent)
- : SfxDockingWindow(pInputBindings, pChildWindow, pParent, "DevelopmentTool",
- "svx/ui/developmenttool.ui")
- , mpClassNameLabel(m_xBuilder->weld_label("class_name_value_id"))
- , mpClassListBox(m_xBuilder->weld_tree_view("class_listbox_id"))
- , mpLeftSideTreeView(m_xBuilder->weld_tree_view("leftside_treeview_id"))
- , mpSelectionToggle(m_xBuilder->weld_toggle_button("selection_toggle"))
- , maDocumentModelTreeHandler(
- mpLeftSideTreeView,
- pInputBindings->GetDispatcher()->GetFrame()->GetObjectShell()->GetBaseModel())
-{
- mpLeftSideTreeView->connect_changed(LINK(this, DevelopmentToolDockingWindow, LeftSideSelected));
- mpSelectionToggle->connect_toggled(LINK(this, DevelopmentToolDockingWindow, SelectionToggled));
-
- auto* pViewFrame = pInputBindings->GetDispatcher()->GetFrame();
-
- uno::Reference<frame::XController> xController = pViewFrame->GetFrame().GetController();
-
- mxRoot = pInputBindings->GetDispatcher()->GetFrame()->GetObjectShell()->GetBaseModel();
-
- introspect(mxRoot);
- maDocumentModelTreeHandler.inspectDocument();
- mxSelectionListener.set(new SelectionChangeHandler(xController, this));
-}
-
-IMPL_LINK(DevelopmentToolDockingWindow, LeftSideSelected, weld::TreeView&, rView, void)
-{
- if (mpSelectionToggle->get_state() == TRISTATE_TRUE)
- return;
-
- OUString sID = rView.get_selected_id();
- auto xObject = DocumentModelTreeHandler::getObjectByID(sID);
- if (xObject.is())
- introspect(xObject);
-}
-
-IMPL_LINK_NOARG(DevelopmentToolDockingWindow, SelectionToggled, weld::ToggleButton&, void)
-{
- updateSelection();
-}
-
-DevelopmentToolDockingWindow::~DevelopmentToolDockingWindow() { disposeOnce(); }
-
-void DevelopmentToolDockingWindow::dispose()
-{
- auto* pSelectionChangeHandler
- = dynamic_cast<SelectionChangeHandler*>(mxSelectionListener.get());
- if (pSelectionChangeHandler)
- pSelectionChangeHandler->disconnect();
-
- mxSelectionListener = uno::Reference<view::XSelectionChangeListener>();
- maDocumentModelTreeHandler.dispose();
-
- mpClassNameLabel.reset();
- mpClassListBox.reset();
- mpSelectionToggle.reset();
- mpLeftSideTreeView.reset();
-
- SfxDockingWindow::dispose();
-}
-
-void DevelopmentToolDockingWindow::updateSelection()
-{
- TriState eTriState = mpSelectionToggle->get_state();
- if (eTriState == TRISTATE_TRUE)
- {
- introspect(mxCurrentSelection);
- mpLeftSideTreeView->set_sensitive(false);
- }
- else
- {
- mpLeftSideTreeView->set_sensitive(true);
- LeftSideSelected(*mpLeftSideTreeView);
- }
-}
-
-void DevelopmentToolDockingWindow::ToggleFloatingMode()
-{
- SfxDockingWindow::ToggleFloatingMode();
-
- if (GetFloatingWindow())
- GetFloatingWindow()->SetMinOutputSizePixel(Size(300, 300));
-
- Invalidate();
-}
-
-void DevelopmentToolDockingWindow::selectionChanged(
- uno::Reference<uno::XInterface> const& xInterface)
-{
- mxCurrentSelection = xInterface;
- updateSelection();
-}
-
-namespace
-{
uno::Reference<reflection::XIdlClass>
TypeToIdlClass(const uno::Type& rType, const uno::Reference<uno::XComponentContext>& xContext)
{
@@ -345,60 +246,133 @@ OUString AnyToString(const uno::Any& aValue, const uno::Reference<uno::XComponen
}
return aRetStr;
}
-}
-void DevelopmentToolDockingWindow::introspect(uno::Reference<uno::XInterface> const& xInterface)
+// Object inspector nodes
+
+class ObjectInspectorNode
{
- if (!xInterface.is())
- return;
+public:
+ css::uno::Reference<css::uno::XInterface> mxObject;
- uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
- if (!xContext.is())
- return;
+ ObjectInspectorNode() = default;
- auto xServiceInfo = uno::Reference<lang::XServiceInfo>(xInterface, uno::UNO_QUERY);
- OUString aImplementationName = xServiceInfo->getImplementationName();
+ ObjectInspectorNode(css::uno::Reference<css::uno::XInterface> const& xObject)
+ : mxObject(xObject)
+ {
+ }
- mpClassNameLabel->set_label(aImplementationName);
+ virtual ~ObjectInspectorNode() {}
- mpClassListBox->freeze();
- mpClassListBox->clear();
+ virtual OUString getObjectName() = 0;
+
+ virtual void fillChildren(std::unique_ptr<weld::TreeView>& rTree, weld::TreeIter const& rParent)
+ = 0;
+};
- std::unique_ptr<weld::TreeIter> pParent = mpClassListBox->make_iterator();
- OUString aServicesString("Services");
- mpClassListBox->insert(nullptr, -1, &aServicesString, nullptr, nullptr, nullptr, false,
- pParent.get());
- mpClassListBox->set_text_emphasis(*pParent, true, 0);
+OUString lclAppendNode(std::unique_ptr<weld::TreeView>& pTree, ObjectInspectorNode* pEntry,
+ bool bChildrenOnDemand = false)
+{
+ OUString sName = pEntry->getObjectName();
+ OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pEntry)));
+ std::unique_ptr<weld::TreeIter> pCurrent = pTree->make_iterator();
+ pTree->insert(nullptr, -1, &sName, &sId, nullptr, nullptr, bChildrenOnDemand, pCurrent.get());
+ pTree->set_text_emphasis(*pCurrent, true, 0);
+ return sId;
+}
- std::unique_ptr<weld::TreeIter> pResult = mpClassListBox->make_iterator();
- const uno::Sequence<OUString> aServiceNames(xServiceInfo->getSupportedServiceNames());
- for (auto const& aServiceName : aServiceNames)
+OUString lclAppendNodeToParent(std::unique_ptr<weld::TreeView>& pTree,
+ weld::TreeIter const& rParent, ObjectInspectorNode* pEntry,
+ bool bChildrenOnDemand = false)
+{
+ OUString sName = pEntry->getObjectName();
+ OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pEntry)));
+ std::unique_ptr<weld::TreeIter> pCurrent = pTree->make_iterator();
+ pTree->insert(&rParent, -1, &sName, &sId, nullptr, nullptr, bChildrenOnDemand, nullptr);
+ pTree->set_text_emphasis(*pCurrent, true, 0);
+ return sId;
+}
+
+OUString lclAppendNodeWithIterToParent(std::unique_ptr<weld::TreeView>& pTree,
+ weld::TreeIter const& rParent, weld::TreeIter& rCurrent,
+ ObjectInspectorNode* pEntry, bool bChildrenOnDemand = false)
+{
+ OUString sName = pEntry->getObjectName();
+ OUString sId(OUString::number(reinterpret_cast<sal_Int64>(pEntry)));
+ pTree->insert(&rParent, -1, &sName, &sId, nullptr, nullptr, bChildrenOnDemand, &rCurrent);
+ pTree->set_text_emphasis(rCurrent, true, 0);
+ return sId;
+}
+
+class ObjectInspectorNamedNode : public ObjectInspectorNode
+{
+public:
+ OUString msName;
+
+ ObjectInspectorNamedNode(OUString const& rName,
+ css::uno::Reference<css::uno::XInterface> const& xObject)
+ : ObjectInspectorNode(xObject)
+ , msName(rName)
{
- mpClassListBox->insert(pParent.get(), -1, &aServiceName, nullptr, nullptr, nullptr, false,
- pResult.get());
- mpClassListBox->set_text_emphasis(*pResult, false, 0);
}
- uno::Reference<beans::XIntrospection> xIntrospection;
- xIntrospection = beans::theIntrospection::get(xContext);
+ OUString getObjectName() override { return msName; }
- uno::Reference<beans::XIntrospectionAccess> xIntrospectionAccess;
- xIntrospectionAccess = xIntrospection->inspect(uno::makeAny(xInterface));
+ void fillChildren(std::unique_ptr<weld::TreeView>& /*rTree*/,
+ weld::TreeIter const& /*rParent*/) override
{
- OUString aPropertiesString("Properties");
+ }
+};
- mpClassListBox->insert(nullptr, -1, &aPropertiesString, nullptr, nullptr, nullptr, false,
- pParent.get());
- mpClassListBox->set_text_emphasis(*pParent, true, 0);
+class ServicesNode : public ObjectInspectorNamedNode
+{
+public:
+ ServicesNode(css::uno::Reference<css::uno::XInterface> const& xObject)
+ : ObjectInspectorNamedNode("Services", xObject)
+ {
+ }
+
+ void fillChildren(std::unique_ptr<weld::TreeView>& pTree,
+ weld::TreeIter const& rParent) override
+ {
+ auto xServiceInfo = uno::Reference<lang::XServiceInfo>(mxObject, uno::UNO_QUERY);
+ const uno::Sequence<OUString> aServiceNames(xServiceInfo->getSupportedServiceNames());
+ for (auto const& aServiceName : aServiceNames)
+ {
+ lclAppendNodeToParent(pTree, rParent,
+ new ObjectInspectorNamedNode(aServiceName, mxObject));
+ }
+ }
+};
- uno::Reference<beans::XPropertySet> xPropertySet(xInterface, uno::UNO_QUERY);
+class PropertiesNode : public ObjectInspectorNamedNode
+{
+public:
+ uno::Reference<uno::XComponentContext> mxContext;
+
+ PropertiesNode(css::uno::Reference<css::uno::XInterface> const& xObject,
+ uno::Reference<uno::XComponentContext> const& xContext)
+ : ObjectInspectorNamedNode("Properties", xObject)
+ , mxContext(xContext)
+ {
+ }
+
+ void fillChildren(std::unique_ptr<weld::TreeView>& pTree,
+ weld::TreeIter const& rParent) override
+ {
+ uno::Reference<beans::XIntrospection> xIntrospection
+ = beans::theIntrospection::get(mxContext);
+ auto xIntrospectionAccess = xIntrospection->inspect(uno::makeAny(mxObject));
const auto xProperties = xIntrospectionAccess->getProperties(
beans::PropertyConcept::ALL - beans::PropertyConcept::DANGEROUS);
+
+ uno::Reference<beans::XPropertySet> xPropertySet(mxObject, uno::UNO_QUERY);
+
for (auto const& xProperty : xProperties)
{
- mpClassListBox->insert(pParent.get(), -1, &xProperty.Name, nullptr, nullptr, nullptr,
- false, pResult.get());
+ std::unique_ptr<weld::TreeIter> pCurrent = pTree->make_iterator();
+ lclAppendNodeWithIterToParent(pTree, rParent, *pCurrent,
+ new ObjectInspectorNamedNode(xProperty.Name, mxObject));
if (xPropertySet.is())
{
@@ -406,50 +380,241 @@ void DevelopmentToolDockingWindow::introspect(uno::Reference<uno::XInterface> co
try
{
uno::Any aAny = xPropertySet->getPropertyValue(xProperty.Name);
- aValue = AnyToString(aAny, xContext);
+ aValue = AnyToString(aAny, mxContext);
}
catch (const beans::UnknownPropertyException&)
{
aValue = "UnknownPropertyException";
}
- mpClassListBox->set_text(*pResult, aValue, 1);
+ pTree->set_text(*pCurrent, aValue, 1);
}
}
}
+};
+
+class InterfacesNode : public ObjectInspectorNamedNode
+{
+public:
+ InterfacesNode(css::uno::Reference<css::uno::XInterface> const& xObject)
+ : ObjectInspectorNamedNode("Interfaces", xObject)
+ {
+ }
+ void fillChildren(std::unique_ptr<weld::TreeView>& pTree,
+ weld::TreeIter const& rParent) override
{
- uno::Reference<lang::XTypeProvider> xTypeProvider(xInterface, uno::UNO_QUERY);
+ uno::Reference<lang::XTypeProvider> xTypeProvider(mxObject, uno::UNO_QUERY);
if (xTypeProvider.is())
{
- OUString aTypesString("Interfaces");
- mpClassListBox->insert(nullptr, -1, &aTypesString, nullptr, nullptr, nullptr, false,
- pParent.get());
- mpClassListBox->set_text_emphasis(*pParent, true, 0);
-
const auto xSequenceTypes = xTypeProvider->getTypes();
for (auto const& xType : xSequenceTypes)
{
OUString aName = xType.getTypeName();
- mpClassListBox->insert(pParent.get(), -1, &aName, nullptr, nullptr, nullptr, false,
- pResult.get());
+ lclAppendNodeToParent(pTree, rParent,
+ new ObjectInspectorNamedNode(aName, mxObject));
}
}
}
+};
+
+class MethodsNode : public ObjectInspectorNamedNode
+{
+public:
+ uno::Reference<uno::XComponentContext> mxContext;
+
+ MethodsNode(css::uno::Reference<css::uno::XInterface> const& xObject,
+ uno::Reference<uno::XComponentContext> const& xContext)
+ : ObjectInspectorNamedNode("Methods", xObject)
+ , mxContext(xContext)
+ {
+ }
+
+ void fillChildren(std::unique_ptr<weld::TreeView>& pTree,
+ weld::TreeIter const& rParent) override
+ {
+ uno::Reference<beans::XIntrospection> xIntrospection
+ = beans::theIntrospection::get(mxContext);
+ auto xIntrospectionAccess = xIntrospection->inspect(uno::makeAny(mxObject));
+
+ const auto xMethods = xIntrospectionAccess->getMethods(beans::MethodConcept::ALL);
+ for (auto const& xMethod : xMethods)
+ {
+ OUString aMethodName = xMethod->getName();
+
+ lclAppendNodeToParent(pTree, rParent,
+ new ObjectInspectorNamedNode(aMethodName, mxObject));
+ }
+ }
+};
+
+} // end anonymous namespace
+
+DevelopmentToolDockingWindow::DevelopmentToolDockingWindow(SfxBindings* pInputBindings,
+ SfxChildWindow* pChildWindow,
+ vcl::Window* pParent)
+ : SfxDockingWindow(pInputBindings, pChildWindow, pParent, "DevelopmentTool",
+ "svx/ui/developmenttool.ui")
+ , mpClassNameLabel(m_xBuilder->weld_label("class_name_value_id"))
+ , mpClassListBox(m_xBuilder->weld_tree_view("class_listbox_id"))
+ , mpLeftSideTreeView(m_xBuilder->weld_tree_view("leftside_treeview_id"))
+ , mpSelectionToggle(m_xBuilder->weld_toggle_button("selection_toggle"))
+ , maDocumentModelTreeHandler(
+ mpLeftSideTreeView,
+ pInputBindings->GetDispatcher()->GetFrame()->GetObjectShell()->GetBaseModel())
+{
+ mpLeftSideTreeView->connect_changed(LINK(this, DevelopmentToolDockingWindow, LeftSideSelected));
+ mpSelectionToggle->connect_toggled(LINK(this, DevelopmentToolDockingWindow, SelectionToggled));
+ mpClassListBox->connect_expanding(
+ LINK(this, DevelopmentToolDockingWindow, ObjectInspectorExpandingHandler));
+
+ auto* pViewFrame = pInputBindings->GetDispatcher()->GetFrame();
+
+ uno::Reference<frame::XController> xController = pViewFrame->GetFrame().GetController();
+
+ mxRoot = pInputBindings->GetDispatcher()->GetFrame()->GetObjectShell()->GetBaseModel();
+
+ introspect(mxRoot);
+ maDocumentModelTreeHandler.inspectDocument();
+ mxSelectionListener.set(new SelectionChangeHandler(xController, this));
+}
+
+IMPL_LINK(DevelopmentToolDockingWindow, LeftSideSelected, weld::TreeView&, rView, void)
+{
+ if (mpSelectionToggle->get_state() == TRISTATE_TRUE)
+ return;
+
+ OUString sID = rView.get_selected_id();
+ auto xObject = DocumentModelTreeHandler::getObjectByID(sID);
+ if (xObject.is())
+ introspect(xObject);
+}
+
+IMPL_LINK_NOARG(DevelopmentToolDockingWindow, SelectionToggled, weld::ToggleButton&, void)
+{
+ updateSelection();
+}
+
+void DevelopmentToolDockingWindow::clearObjectInspectorChildren(weld::TreeIter const& rParent)
+{
+ bool bChild = false;
+ do
+ {
+ bChild = mpClassListBox->iter_has_child(rParent);
+ if (bChild)
+ {
+ std::unique_ptr<weld::TreeIter> pChild = mpClassListBox->make_iterator(&rParent);
+ bChild = mpClassListBox->iter_children(*pChild);
+ if (bChild)
+ {
+ clearObjectInspectorChildren(*pChild);
+ OUString sID = mpClassListBox->get_id(*pChild);
+ auto* pEntry = reinterpret_cast<ObjectInspectorNode*>(sID.toInt64());
+ delete pEntry;
+ mpClassListBox->remove(*pChild);
+ }
+ }
+ } while (bChild);
+}
- OUString aMethodsString("Methods");
- mpClassListBox->insert(nullptr, -1, &aMethodsString, nullptr, nullptr, nullptr, false,
- pParent.get());
- mpClassListBox->set_text_emphasis(*pParent, true, 0);
+DevelopmentToolDockingWindow::~DevelopmentToolDockingWindow() { disposeOnce(); }
+
+void DevelopmentToolDockingWindow::dispose()
+{
+ auto* pSelectionChangeHandler
+ = dynamic_cast<SelectionChangeHandler*>(mxSelectionListener.get());
+ if (pSelectionChangeHandler)
+ pSelectionChangeHandler->disconnect();
+
+ mxSelectionListener = uno::Reference<view::XSelectionChangeListener>();
+ maDocumentModelTreeHandler.dispose();
+
+ // destroy all ObjectInspectorNodes from the tree
+ mpClassListBox->all_foreach([this](weld::TreeIter& rEntry) {
+ OUString sID = mpClassListBox->get_id(rEntry);
+ auto* pEntry = reinterpret_cast<ObjectInspectorNode*>(sID.toInt64());
+ delete pEntry;
+ return false;
+ });
+
+ // dispose welded objects
+ mpClassNameLabel.reset();
+ mpClassListBox.reset();
+ mpSelectionToggle.reset();
+ mpLeftSideTreeView.reset();
- const auto xMethods = xIntrospectionAccess->getMethods(beans::MethodConcept::ALL);
- for (auto const& xMethod : xMethods)
+ SfxDockingWindow::dispose();
+}
+
+void DevelopmentToolDockingWindow::updateSelection()
+{
+ TriState eTriState = mpSelectionToggle->get_state();
+ if (eTriState == TRISTATE_TRUE)
+ {
+ introspect(mxCurrentSelection);
+ mpLeftSideTreeView->set_sensitive(false);
+ }
+ else
{
- OUString aMethodName = xMethod->getName();
- mpClassListBox->insert(pParent.get(), -1, &aMethodName, nullptr, nullptr, nullptr, false,
- pResult.get());
- mpClassListBox->set_text_emphasis(*pResult, false, 0);
+ mpLeftSideTreeView->set_sensitive(true);
+ LeftSideSelected(*mpLeftSideTreeView);
}
+}
+
+void DevelopmentToolDockingWindow::ToggleFloatingMode()
+{
+ SfxDockingWindow::ToggleFloatingMode();
+
+ if (GetFloatingWindow())
+ GetFloatingWindow()->SetMinOutputSizePixel(Size(300, 300));
+
+ Invalidate();
+}
+
+IMPL_LINK(DevelopmentToolDockingWindow, ObjectInspectorExpandingHandler, weld::TreeIter const&,
+ rParent, bool)
+{
+ OUString sID = mpClassListBox->get_id(rParent);
+ if (sID.isEmpty())
+ return true;
+
+ clearObjectInspectorChildren(rParent);
+ auto* pNode = reinterpret_cast<ObjectInspectorNode*>(sID.toInt64());
+ pNode->fillChildren(mpClassListBox, rParent);
+
+ return true;
+}
+
+void DevelopmentToolDockingWindow::selectionChanged(
+ uno::Reference<uno::XInterface> const& xInterface)
+{
+ mxCurrentSelection = xInterface;
+ updateSelection();
+}
+
+void DevelopmentToolDockingWindow::introspect(uno::Reference<uno::XInterface> const& xInterface)
+{
+ if (!xInterface.is())
+ return;
+
+ uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
+ if (!xContext.is())
+ return;
+
+ // Set implementation name
+ auto xServiceInfo = uno::Reference<lang::XServiceInfo>(xInterface, uno::UNO_QUERY);
+ OUString aImplementationName = xServiceInfo->getImplementationName();
+ mpClassNameLabel->set_label(aImplementationName);
+
+ // fill object inspector
+
+ mpClassListBox->freeze();
+ mpClassListBox->clear();
+
+ lclAppendNode(mpClassListBox, new ServicesNode(xInterface), true);
+ lclAppendNode(mpClassListBox, new InterfacesNode(xInterface), true);
+ lclAppendNode(mpClassListBox, new PropertiesNode(xInterface, xContext), true);
+ lclAppendNode(mpClassListBox, new MethodsNode(xInterface, xContext), true);
mpClassListBox->thaw();
}