Monday, March 1, 2021

Built-in "Xray" like UNO object inspector – Part 2

Since my last blog post I've been continuing the work on DevTools and since then a lot of things have progressed. Point & click has been implemented and the object inspector view has been greatly improved to show current object’s properties and methods. In this part I will mainly talk about the point & click and a bit about the current state, and in the next blog I will extensively talk about the object inspector.

Point & click

Figure 1: Current selection button


The idea of this functionality is to provide a way to inspect selected objects in the document, for example an image or a shape. For this, I have implemented a selection change listener (sfx2/source/devtools/SelectionChangeHandler.hxx), whose purpose is to listen to the selection changes that happen in the document and store the latest selection object. It is started when the DevTools docking window is instantiated and shown. I have added a new toggle button “Current Selection” (see Figure 1) to the UI. When the button is selected, it automatically shows the current selected object (gathered with the selection change listener) in the object inspector. 

Figure 2: Current selected shape's properties shown in the object inspector

In the example shown in Figure 2, we can see the shape is selected in the document and its properties are shown in the object inspector. If the "Current Selection" button wouldn't be toggled, then the document top-level object would be shown in the object inspector or the selected object in the DOM tree view.

While the "Current Selection" button is toggled, selecting any object in the DOM tree view (left-hand side tree view) has no effect, however if the current selected object is also present in the current DOM tree view, it will be selected. Note that if the object is not present in the tree, it won't be selected, because the DOM tree view will not force creation of on-demand object because of performance considerations.

Figure 3: "Inspect Object" command in "Customize" dialog 


In addition to showing the selected object, I have added a UNO command named “Inspect Object” (.uno:InspectSelectedObject), which can be added to context menus for objects (See Figure 3). The purpose of this command is to provide a way to open the DevTools docking window and automatically show the current selected object. If a user regularly uses the object inspector, this may be a more convenient way for them to access DevTools. Note that by default the command isn't added to any context menu, this is up to the user. However, if there will be demand to add this to context menus, it can be easily added. 

Figure 4: "Inspect Object" context menu entry on a shape object

The example in Figure 4 shows the context menu of a shape object, where the selected entry is the added "Inspect Object". 

From the implementation standpoint, it was necessary to move the whole DevTools from svx to sfx2 module. This was mainly necessary to get .uno:InspectSelectedObject to work, because we need to signal to DevTools that we want to show the current selection and not the document root in the object inspector. Because the svx depends on sfx2 module, it is not possible to access svx from sfx2 (only the other way around). 

Improvements to object inspector

The object inspector was previously a single tree view only, which had services, interfaces, properties and methods categories as root tree entries. This has now been changed so that the categories are now pages in a tab view, and each category has its own tree view (can be seen in Figure 2). The main problem with one tree view is that columns for each of the categories are different. For example, the properties category has object, value and type categories but the same columns make no sense for methods (which has return type and input parameters). 

For methods it now shows the method name, return type and parameters. The types are currently simplified types, which are easier to read (instead of exact type name of the object it just writes "object"), but the user will want to know the exact type too, so this is a WIP.

For properties it shows the type and value of the property, and it is possible to expand a property if the type is a complex type (object, struct) so it lists nested properties. If the value is an enum, then we get the name of the enum value automatically and show the name instead. 

Support for sequences was also added, so the sequence can be expanded and a list of indices and values is presented. If the current object supports XNameAccess or XIndexAccess, the names and indices are added into the property list, so the user can navigate to those. 

With this additions, it is already easier to inspect objects than it previously was using the Xray tool, and I'm sure it will get even better when it is finished. 

Next steps

The object inspector is already in a very good shape so I encourage everyone to try it and give feedback, what can be improved, changed or added - especially if you use Xray or MRI regularly. 

For the next steps the major focus will be to fix a couple of bugs and crashes (mainly due to missing checks if objects are available), work on the UI, object stack (so it is possible to go back to the previous object) and finalizing all the features of the object inspector. 

Credits

Many thanks to TDF and users that support the foundation by providing donations, to make this work possible. 

To be continued...

Thursday, January 21, 2021

Built-in "Xray" like UNO object inspector – Part 1

When developing macros and extensions in LibreOffice it is very useful to have an object inspector. With that tool you inspect the object tree and the methods, properties and interfaces of individual objects to understand its structure. There are quite some different object inspectors available for LibreOffice as extension. Probably the best known is called “XrayTool”, but there were also others like MRI, which was build for a similar purpose and various other more simple object inspectors (for example one is provided as an code example in ODK).

As a tool like this is very valuable it makes sense that it would be provided out-of-the-box by LibreOffice without the need for the user to get it separately. Also the user could even be unaware the such a tool exists.  For this reasons The Document Foundation (TDF) put up a tender to create a built-in Xray like UNO object inspector, which was awarded to Collabora and we are now in the process of implementing it.

Thank you TDF and the donating users of LibreOffice to make the work on this tool possible.

The Plan

The major gripe with Xray and other tools is that the user needs to go into the macro editor and run a the script with the inspecting object as the parameter. 

For example to inspect the root UNO object:

Xray ThisComponent

or for example to inspect a specific (first) Calc sheet:

Document = ThisComponent
AllSheets = Document.getSheets()
MySheet = AllSheets.getByIndex(0)
Xray MySheet

Figure 1: Watch window in the macro editor

We can do much better than this. So the idea is to have a object inspector tool as a dockable bottom widget, very similar to “developer tools” that you can find in popular web browsers.

The left hand side of the tool will have a subset of the document model (DOM) presented as a tree and on the right hand side a object inspector view that will show the current UNO object’s properties, methods in a tree view that is taken from the Watch window in the LibreOffice macro editor (see Figure 1). When the user would select an UNO object in the DOM tree view (left-hand side), the object inspector (right-hand side) would show it.

An additional functionality that is present in developer tools in web browsers is the ability to point & click an object directly in the document, which can then be inspected in the developer tool. A similar functionality to this will be possible in LibreOffice, where you will be able to select an object in the document, that is then be shown in the object inspector (right-hand side).

Implementation so-far

The implementation has been divided into 4 parts:

  1. Introduce a new dockable window on the bottom of the UI.
  2. DOM tree view (left-hand side)
  3. Implement point&click functionality.
  4. Object inspector view (right-hand side)

Currently the 1. and 2. part have been implemented, so this blog post serves as a report of the work that has been done until now. For 3. and 4. part, a limited subset of the functionality has been  already implemented, but it is not yet expected to work correctly and may change a lot in the future.

Dockable window

Figure 2: Development Tool in the menu

The dockable window has been added to all components of LibreOffice, which can be enabled in the menu (see Figure 2) under Help / Development tool (this location and the name can still change). The development tool code is all contained under svx/source/devtools/ where the docking window is implemented in DevelopmentToolDockingWindow.cxx.

DOM tree view (Left-hand)

Figure 3: Development tool dockable window

The idea of the DOM tree view is to provide a useful subset of the DOM objects, that the user can quickly access and inspect. Without this, the users would have to traverse to the objects they are interested in inside the object inspector itself, which may not be as straight forward to the users that aren’t familiar with the DOM, and even if they are, the DOM subset still makes it easier.

The DOM tree view as currently implemented (see Figure 3), has a root “Document” element always available, which represents the root document UNO object, from where you can traverse to any other relevant UNO object in the DOM tree. Other available objects depend on the component.

In Writer the available objects are:

  • Paragraphs
  • Shapes
  • Tables
  • Frames
  • Graphic Objects
  • Embedded Objects (OLE)
  • Style Families & Styles

In Calc:

  • Sheets
  • Shapes (per sheet)
  • Charts (per sheet)
  • Pivot Tables (per sheet)
  • Style Families & Styles

In Impress and Draw:

  • Pages / Slides
  • Shapes (per page / slide)
  • Master Slides
  • Style Families & Styles

If there are other object(s) you would like to see in the DOM tree view, please let me know.

The main implementation file for the left-side DOM tree view is DocumentModelTreeHandler.cxx in the svx/source/devtools/ folder. For each node of the tree view, there is an object attached (subclass  DocumentModelTreeEntry) to the node, which is responsible to fill the child nodes and provide the UNO object of the current node. The whole DOM tree view is populated on-demand, when the tree is expanded. This makes sure that we don’t take a lot of time inserting the whole object tree before-hand and have a more up-to-date view of the UNO objects. 

All the code is present in the LibreOffice master repository. Please try out the development tools in a recent daily build. Any comments or suggestion are welcome. 

Next part - point&click functionality

Partial support for the point&click has already been added. There is a selection listener added, which remembers what the selected object in the document is. This object is the available in the DOM tree view under the name “Current Selection”. If the user clicks on the node in the tree view, then the right-hand object inspector shows the UNO object.

To be continued..