Objects perform actions on behalf of the user. Sometimes it is desirable to inform the application user of progress, status or problems. In older applications, the action code often contained knowledge about the environment in which the object was embedded. This harms reusability and therefore XPCE provides a generic mechanism to deal with such messages.
Whenever an object needs to inform the user, the programmer can use
the
`object->
report'
method. The definition of this method is below.
->
format'
for a description of the C printf-like formatting syntax of XPCE. type
describes the nature of the message and is used by the reporting
mechanism to decide on the presentation-style. See section
10.7.2.1 for the available types and their meaning.
The object posting the report message will normally not be able to display the message. The main task of the implementations of this method in class object, visual, frame and dialog is to divert the report to an object that can present it. By default, this is either a label or the display object (@display).
The implementation of `object->
report'
will simply check whether there is a current event (see @event),
which implicates the action was initiated by the user and then forward
the ->
report message to the
`event<-
receiver',
which is normally the controller activated by the user. If there is no
current event, the action must be initiated by a user query to the
host-language and therefore `object->
report'
will print its feedback to the host-language console using `@pce->
format'.
The implementation of `visual->
report'
will simply forward the message to its containing visual object. If the
message arrives at an instance of class frame,
the implementation of `frame->
report'
will broadcast the message to each of its windows, but avoid sending it
back to the window it came from. If this fails and the frame is a
transient frame for another frame, the report is forward to the main
frame. Class
dialog will look for an
object named reporter. If it can find such an object (typically
a label), the report is
sent to this object.
If all fails, the report will arrive at the @display object, which takes care of default handling. See section 10.7.2.1 on how the different report types are handled.
The report type indicates the semantic category of the report and defines how it is handled. The following report types are defined:
->
inform',
presenting a messagebox.
->
flush'
to take immediate effect. A sequence of progress reports should
be closed with a
done report.
->
report: progress
messages.
->
alert'
suffices. If there is an appropriate location for the message it will be
formatted there.
->
inform'
is used to bring the message to the attention of the user.
There are two aspects in which the reporting mechanism can be
redefined. The first concerns the location and the other the presentation
of the report. The location is changed by defining the method <-
report_to.
All the generic implementations of this method will first invoke <-
report_to
on itself. If this method yields an answer, the report is forwarded to
this answer. For example, class
text_buffer
defines a <-
report_to that forwards all reports
to its associated editor object.
The presentation is changed by changing the implementation
of
`label->
report'
or `display->
report.
As this determines the look and feel of an application, applications
should be reluctant using this.
The typical way to exploit the report mechanism is by attaching a label named reporter to a dialog window of the applications frame. For example, an application consisting of a menu-bar, browser and a graphical window window could choose to make place for a small dialog for feedback at the bottom. The following fragment would build the window layout of such an application:
reportdemo :- new(Frame, frame('Reporter demo')), new(B, browser), send(new(picture), right, B), send(new(MD, dialog), above, B), send(new(RD, dialog), below, B), send(Frame, append, B), send(MD, append, new(MB, menu_bar)), send(MD, pen, 0), send(MD, gap, size(0,0)), send(MB, append, new(File, popup(file))), send_list(File, append, [ menu_item(load, message(@prolog, load, Frame), end_group := @on), menu_item(quit, message(Frame, destroy)) ]), send(RD, append, label(reporter)), send(RD, gap, size(5, 0)), send(Frame, open).
Now suppose the implementation of the `load' action takes considerable time. The implementation below reads a file assuming each line in the file contains a word.
:- pce_autoload(finder, library(find_file)). :- pce_global(@finder, new(finder)). load(Frame) :- get(@finder, file, exists := @on, FileName), send(Frame, report, progress, 'Loading %s ...', FileName), get(Frame, member, browser, Browser), new(File, file(FileName)), send(File, open, read), ( repeat, ( get(File, read_line, Line) -> send(Line, strip), send(Browser, append, Line), fail ; !, send(File, close) ) ), send(Frame, report, done).
The result is shown in figure 18.
Figure 18 : The `reporter' demo |