Extending GTInspector with support for exploring HelpTopic objects

Help Browser is a tool from Pharo that provides an introductory help for the environment and its tools:

Message Browser

Internally, the content displayed by this tool is stored in HelpTopic objects. Each HelpTopic object has:

  • a title;
  • a content instance variable storing the help text;
  • a list of subtopics (also HelpTopic objects);
  • an owner topic.

Hence, the entire help is stored as a tree of HelpTopic objects. Help Browser provides a user interface for exploring the content of this tree.

When developing Help Browser one has to explore both the internal representation and the actual content of a HelpTopic object. An object inspector that focuses exclusively on object state only shows the internal representation of HelpTopic objects:

HelpTopic tree inspector

This, however, is not the best approach for exploring the content of a HelpTopic object, as ones has to permanently expand and collapse objects in the tree view. To provide a better mechanism for exploring the content of a HelpTopic object we can extend GTInspector with two custom views.

First, we add a view that shows the contents of a HelpTopic object by adding in the HelpTopic class a method that constructs the presentation and annotating that method with gtInspectorPresentationOrder:, so that the inspector can find it. The annotation expects an integer parameter used to order views. Creating this view requires just 6 lines of code:

HelpTopic>>#gtInspectorContentsIn: composite
        <gtInspectorPresentationOrder: 40>
        composite text
                title: 'Contents';
                display: [ self contents ];
                when: [ self contents notEmpty ]  

To create the view we first indicate that we need a text view and configure the view with a title. Then using the display: method we set the block used to get the actual object displayed by the text view; in this case the content of the topic object. Last by not least, we use the when: method to only display the view if the topic object has actual content.

Second, we add a view that displays the tree of subtopics from a HelpTopic object. We follow the same process as before. This time we need 8 lines of code:

HelpTopic>>#gtInspectorSubtopicsIn: composite
        <gtInspectorPresentationOrder: 50>
        composite tree
                title: 'Subtopics';
                display: [ self subtopics ];
                children: [ :each | each subtopics ];
                format: [:each | each title];
                when: [ self hasSubtopics ]

Here the display: method returns the root elements of the tree. children: is used to extract the children of a node. format: sets the block used to transform each node of the tree into a string.

Now, when inspecting a HelpTopic object we get directly in the inspector a simple tool for browsing the content of such objects. We can use this inspector to explore both the implementation and the content of HelpTopic objects.

HelpTopic custom inspector

The inspector includes, by default, both the Raw and the Meta views. While useful for a developer, showing these views to a user that is just interested in the content of a HelpTopic object introduces an overhead. To remove it we can use the filtering feature of the inspector and create an object inspector that only contains the two custom views previously created:

inspector := GTInspector new.
inspector presentationFilter: (GTInspectorMethodListFilter new
        addAndSelectSignatureFor: HelpTopic>>#gtInspectorContentsIn:;
        addAndSelectSignatureFor: HelpTopic>>#gtInspectorSubtopicsIn:).
inspector openOn: SystemHelp asHelpTopic. 

This transforms the inspector into a Help Browser:

Message Browser in the inspector

HelpTopic is just an example of a domain object interesting from both an implementation and a domain-specific point of view. Many other domain objects have similar requirements. The GTInspector makes is possible to easily create custom views for objects so that they can be inspected from multiple points of view.

– Many thanks to Torsten Bergmann for starting this extension.