Build Environment Effort/HID List

From Apache OpenOffice Wiki
Jump to: navigation, search

Edit.png

Build Environment Effort

Quick Navigation

About this template


The problem

Function commands (e.g. entries in menus or toolbars) and GUI elements like controls, dialogs or windows in OOo have IDs. Such an ID is called a "help ID" (HID). The reason for that is - surprise! - that this ID is used to assign help content to the command or to the GUI element. As an example, a user can activate the "Extended Help" feature in OOo and click on a menu entry or a toolbar button. Then a HID is taken from the command that is bound to the selected menu entry or clicked toolbar button. In the same way a user can click on a button in a dialog. Then a HID is retrieved from the button that was clicked. In both cases the HID is "wrapped" into a help URL and the OOo Help Content Provider is asked to provide help content for this URL.

HIDs can also be used to automate OOo: the testtool application uses HIDs to instruct OOo to execute a command or operate a control. OOo contains a testtool client component that is instructed by the testtool application through a remote bridge. If this client receives a HID for a command, it executes this command using the Dispatch API of the Controller object representing the currently active document window. If the client receives a HID for a GUI element, it searches for the GUI element with that HID in the currently active window and performs an action on it.

How do these HIDs look like? In the testtool application and the executed test scripts HIDs are strings, sometimes called "long names". The help content provider also uses these "long names" to reference a particular help content. If we have "long names", what are the short ones? That's simple: inside of OOo the HIDs are integer values (with some exceptions explained below).

Obviously OOo and the HID "customers" (Help Content Provider, testtool application) speak different languages and so a translator is needed. This translator is the famous (notorious?) "HID list", hid.lst. It defines a mapping from the "long names" to the integer values. If a test script contains a "long name" of a GUI element or command, the test tool "translates" it into the assigned numerical ID and uses it to address the GUI element or execute the command. OTOH if help is requested for a GUI element or a command, the help content provider internally "translates" the ID in the help URL to the "long name" und uses that one to find the content assigned to it. So far, so good.

Unfortunately the hid.lst imposes some problems on our build process:

  • We have a hen and egg problem: the hid.lst is built at the end of the build, but it is needed to build the helpcontent2 module, where it is even committed to the SCM repository. So this list always is not the most current one. If this was the only problem, we could fix that by changing the build order (though this has some other drawbacks), but unfortunately there are more of them.
  • The testtool can't work correctly if the hid.lst from the CWS is not "delivered" correctly; there is always some confusion and uncertainty which list is the correct one to use and the whole process is prone to errors.
  • Some ID mappings are generated automatically; this mapping is susceptible for subtle changes that can happen unnoticed.
  • The HID list generation is an awkward and time consuming process.

So it would be desirable to get rid of the hid.lst by letting all participants (help, testtool, OOo itself) work with the same "long names".

The current process

Commands and GUI elements are treated differently.

Commands

In the olden days of OOo our commands have been represented by an integer number only. These numbers are called "slot IDs". In the source code we have a lot of #defines for slot IDs, e.g. in sfx2/inc/sfx2/sfxsids.hrc where we have code lines like

#define SID_SAVEDOC 5505

From the problem description above it shouldn't be surprising that "SID_SAVEDOC" is used as the long name of the command while 6505 is the internal numerical ID. Thus the hid.lst contains a line

SID_SAVEDOC 5505

that does the mapping.

When we moved our command dispatching to a UNO based framework that always uses URL style command strings, we first simply used "URLs" like "slot:5505" to execute the corresponding command. Later on we gave them "speaking" names. The command with slot ID 5505 e.g. now is called ".uno:Save". This gives us an opportunity to get rid of the ID mapping as explained below.

GUI elements

There are three ways how a control can get a HID:

Automatic HIDs

GUI elements created from a resource file can get "automatic" HIDs when the resource is loaded. The corresponding "long names" of course must be created in the build process. Otherwise they couldn't get into the hid.lst. These IDs are generated in a special context (the particular resource) and so without further actions can't be used in a global list because of possible name clashes. We avoid these clashes in the same way as we do it in C++ source code: by using name spaces. Here's an example for an automatic HID:

sfx2:CheckBox:RID_DLG_ALIEN_WARNING:CB_WARNING_OFF 1111557136 

It defines the HID for the checkbox labeled CB_WARNING_OFF that belongs to the dialog RID_DLG_ALIEN_WARNING that is defined in the code module sfx2. The numerical value is calculated by the resource compiler (it doesn't matter here how this is done). Here's an explanation for the construction of that "long name":

RID_ALIEN_WARNING is the resource ID of the dialog. It is defined in a globally accessible header file as

#define RID_DLG_ALIEN_WARNING           ( RC_DIALOG_BEGIN + 0)

CB_WARNING_OFF defines a sub resource that is only valid in the context of the global resource RID_DLG_ALIEN_WARNING. It is defined in an internal header file that is only included by the resource (rsc) file defining the dialog and the code (cxx) implementing it:

#define CB_WARNING_OFF  16

How can we verify that the "long name" shown above is globally unique?

Usually several resource source files (src) are compiled into one binary resource (res) file. The resource compiler guarantees that

  • in one binary resource file a particular resource ID value can not be used for more than one resource elements of the same type (here: a dialog)
  • in one resource element a particular resource ID value can not be used for more than one sub resource elements of the same type (here: a checkbox)

So we can make the "long name" unique for the whole compiled binary resource file if we never use the same define for different numerical values in the same context (binary resource file or single resource), something that can be controlled easily. To make the "long name" globally unique, we add a prefix that identifies the resource file. In sfx2 we have only one binary resource file, so the module name is sufficient.

HIDs assigned by resource files

A HID can be assigned explicitly in the resource file:

ModalDialog RID_DLG_ALIEN_WARNING
{
   HelpId = HID_WARNING_ALIENFORMAT;
   (...)
};

defines a HID for the whole dialog. The hid.lst file contains

HID_WARNING_ALIENFORMAT 33388

The numerical value is taken from a header file that defines HIDs. Each code module where HIDs are used has its reserved integer value range:

#define HID_WARNING_ALIENFORMAT                     (HID_SFX_START + 320)

HIDs assigned by code

Not every GUI element is created from a resource file, some are only handled by code. So also the HIDs are assigned in the C++ code by calling the SetHelpId() method of the CUI element, inherited from the vcl class Window. As an example, here's the code that assigns a HID to the Navigator window:

pWindow->SetHelpId ( HID_NAVIGATOR_WINDOW );

Again the HID is taken from a header file:

#define HID_NAVIGATOR_WINDOW                        (HID_SFX_START +  86)

and ends up in the hid.lst as

HID_NAVIGATOR_WINDOW 33154

The generation of the hid.lst is completely based on resource (rsc) files. So the HID of the Navigator would be invisible for the build if we didn't apply a trick: each HID used in code only is collected in a special resource file called "hidother.src" that is processed by the HID compilation, but not included in the binary resource file. For the Navigator it contains

hidspecial HID_NAVIGATOR_WINDOW                 { HelpID = HID_NAVIGATOR_WINDOW; };

The proposal

Commands and GUI elements must be treated differently and code changes will happen at different places. So my proposal has two parts.

Commands

With the mentioned ".uno:..." command names we have a string that can be used as a long name for a command that is directly understood by the OOo code without any "tranlastion" (mapping). And indeed for some commands they are already used in the test scripts. By converting all tests and all help indices to use these ".uno:..." names we can get rid of all command HID mappings in the hid.lst. This will require changes only in the automation(?), testautomation and helpcontent2 modules.

GUI elements

GUI elements all derive from the Window class in vcl. This class has two methods that deal with HelpIds:

void SetHelpId ( ULONG nId );
ULONG GetHelpId() const;

We also have methods dealing with "SmartIds" that more or less use Strings as HelpIDs. But I don't think that HIDs should be strings and will explain that below.

Personal tools