Please ensure you have the latest version (1.7) of the RMREvent program from the RMR web site before reading through this tutorial. If you use an older version, some of the text may not make sense.
The Series 5 help system is a real kludge. You probably knew that already, but I thought I'd confirm it. There's simply no way to trap the 'Help' keypress within your program and do something about it - instead, the main system-wide (and most definitely not context-sensitive) help database gets launched. Most OPL/32 programmers have now learned to live with this EPOC idiosyncrasy, adding Help menu options, dialog and toolbar buttons in an attempt to make sure the user of their programs spots that some specific application help does exist after all!
EPOC's designers decided in their wisdom to use DATA itself as their 'engine' to display all the help text. Whilst restrictive in that you can't put in hyperlinks between topics, there is at least the advantage that icons, screenshots, notes and even sound clips can all be embedded in a help database entry.
Making a help database for your program is the fun bit of the help-making process. To make your help file have the same 'look and feel' as the Series 5's built in help database, set up a new DATA file with 3 fields, called 'Title', 'Help text' and 'Keywords'. All 3 fields should be set up as 'Memo' type fields, i.e. unlimited amount of text.
In the Label preferences dialog, set the 'Keywords' field to be hidden.
The font setting for the 'Title' field should be Arial 9 points bold, and should be set from the Label preferences dialog. The font used in the 'Help text' field is Times New Roman 9 points, but selected bits of text can be highlighted in bold, italic and so on. It's even possible to import text into this field from Word, which allows you to change the paragraph formatting, set tab positions, use automatic bullets and so on. In this field, "anything goes" to a large extent. The font used in the 'Keywords' field is irrelevant, as it's hidden anyway.
In the Find by labels dialog, the 'Title' and 'Keywords' fields should be ticked and the 'Help text' field left un-ticked. In the View preferences dialog, the Show card browser box should be ticked, the card width set to 55% and the Show labels box un-ticked.
No sorting should be used. If you do need to re-sort the file, it's usually best to do the sorting and then use 'Create new file' to create a blank DATA file with the same structure. You can then import the sorted file into the new document and then rename that accordingly. Give the finished help database a filename with extension .hlp and this will ensure that it is opened using DATA's special 'help' mode.
So what's the difference between a HLP file
and a normal DATA file? Well for a start, any DATA menu options which would
encourage the user to alter the file (Edit, Delete etc) are removed from the
menu system. The toolbar is also changed, with two basic searching modes.
'QuickFind' is hard-coded in EPOC to just search the first and third fields of
a help database (I use this to good effect in the UK Pocket
Directory), whilst 'Find in all text' does just what it says, taking longer
but searching all fields in all records.
Right. You've made your help database and want to integrate it into your
application. Let's see how RMREvent handles this situation. Locate the
procedure Help:
PROC Help:
LOCAL HelpFile$(255)
IF Device:(Path$+"RMREvent.hlp")
Helpfile$=Dev$+Path$+"RMREvent.hlp"
IF Thread&<>0
ONERR Notopen::
SetForegroundByThread&:(Thread&,0)
ELSE
Notopen::
ONERR OFF
Thread&=RunApp&:("Data",Helpfile$,"",0)
ENDIF
ELSE
giPRINT "Help file not found"
ENDIF
ENDP
The basic idea is that the first time the user asks for help, the database is opened in a new instance of the DATA application and a note made of the name of the 'thread' (the unique number the running program is assigned within the Series 5 so that EPOC [and your main program] can keep track of it easily). If the user asks for help again at a later stage, your program just switches to the running DATA application rather than starting a new one.
A few notes about the code itself:
Device: is the RMREvent routine we've met before, and just
establishes that the file exists, returning the value of TRUE (numerical value
-1). IF Thread&<>0 is where the decision is made on what to do. If DATA
has been launched before in this execution of RMREvent, the variable Thread&
will be non-zero, containing the thread number of the running DATA instance.
And so all we've got to do is use SetForegroundByThread&:(Thread&,0) (one of the routines in system.opx)
to switch to it (i.e. bring it to the 'foreground'). If Thread& is zero,
then Thread&=RunApp&:("Data",Helpfile$,"",0) is executed instead to launch DATA using the RMREvent help file as
its source document. Thread& is non-zero) but has
then closed Help independently (e.g. from the system 'open file' list). In this
case there would be nothing left to switch to, which is why ONERR is set up
here to trap any error generated by the SetForegroundByThread&:(Thread&,0) call and switch the procedure
over to the other bit of the IF...ELSE...ENDIF code, where DATA gets launched again etc.
A screendump from Psion's SPY utility, showing
running processes on my Series 5. Note the two help files currently open and
also the TID (ThreadID) column, showing each process's unique identification
code.
The only other thing we have to do is remember to close DATA down again when our program finishes. If you look ahead a few lines in the RMREvent code, you'll see its 'general close down' routine:
PROC Exit:
Save_INI_File:
IF Thread&<>0
ONERR Exitanyway::
EndTask&:(Thread&,0)
ENDIF
Exitanyway::
STOP
ENDP
The same principle applies here: if Thread& is non-zero, try to close it
down. It's always a good idea to tidy up any system resources your
programs make use of, by attending to them in your own Exit: routine. Usually
these will just be help files, temporary files etc, but the principle holds
good for more complicated situations, too.
Next week, we'll take our first look at OPL/32 advanced database
handling...
Go to next lesson | Programming index