alpha version, October 2000
Note: this is not the particular contents the document will eventually have--it will become an XApplication Kit overview, with links to the descriptions of the particular XApplication classes.
Though, currently the Application Kit is in a most unfinished state of all the XSdk parts. More or less, just one part of the Application Kit is currently in an useable alpha stage, and that is the command redirection system and the XSdkAppController class suite. Therefore, now this document describes those.
The standard Epoc SDK support for application commands is a notably programmer-unfriendly one: so as to prepare a menu of some three-odd plain items you have to prepare at least a 20-line text source file in a specialized, quite non-intuitive programming language--and such a menu will not support hotkeys, for those you need to extend the source even more! So as to make a functional and guidelines-aware toolbar, you have to be a real Epoc guru, or you have to perform an indecent amount of copying&pasting of an absolutely unintelligible code (and the Symbian authorities even dare to recommend this in their book!!!!).
Well, that is definitely bad. Therefore, the XSdk Application Kit command redirection brings a quite different approach: you just prepare the menu items, tollbar buttons or shortcuts in a GUI tool, and link each one of them visually to a method name. Then, you implement the method in the application controller, and voila! It gets called automatically when the appropriate command is performed. In case you do not implement the method, the application runs as well, but when the command is triggered, it informs the user that the appropriate service is unimplemented.
The menu, toolbar and shortcuts editors are placed in different panes of one common window, opened by a Tools / XSdk Tools / MenuToolbars command. In the menu mode, it looks more or less this way (you will find the standard Epoc menu and toolbar items and shortcuts are predefined by the XSdk project template system; a programmer needs only to delete the unneeded ones, and to add the application-specific ones):

(note the lower half of the window is cut out; we will return to it soon). The editor should be intuitive enough; using the four buttons in the upper right corner you can edit the menu layout, the text field below allows to change tha name (it is a combo box to allow to select some predefined standard menu item names). The small checkboxes below allows to disable the menu item, and/or to separate it from the next one by a horisontal line. The two small arrow buttons below allows to reorder menu items.
Finally, the menu item type popup allows to select one of the following variants:
Besides the somewhat unintelligible radio buttons the XSdk allows another way for showing a switchable menu state (impossible without programming in the plain Epoc SDK): the menu title itself can be switchable. Just enter more menu titles separated by a backslash into the text field; the menu item then will show its state by selecting the appropriate one of the menu titles. In case the menu item should contain the backslash, use it twice.
Finally, you can finish the menu item by three dots (as seen in the picture); the editor will recognize it and replace the dots by the ellipsis character.
In the bottom right corner, an information of the assigned command and shortcut--if any--is shown. Assigning commands will be described below; a shortcut for a menu item is just any shortcut with the same assigned command.
Incidentally, as is common with all XSdk GUI panels, the Assistant icon in the very upper right corner opens an on-line help.
When switched to a toolbar mode, the editor looks this way:

In principle, the toolbar editor does not work too differently from the menu editor. Three buttons are sufficient in the upper right corner, since there are no "subtoolbars". Any toolbar item can be stretchable or can have its height set; that is allowed by the two controls below.
The toolbar item type popup offers the following types; each of them features appropriate controls for setting the details:
For the Normal Button there is a text field to specify the button label (use a backslash to cut it for two lines, like with the "Cnvrt\File" button in the example picture), and a XSdk MBM View for the button icon. Just drag&drop any image file over the icon view, and it will be accepted by the panel and assigned to the button.
The "Extra" button below allows to set a few general toolbar options, which are generally kept in the default state:

Finally, the shortcut--if any--is shown near the bottom of the pane. Just as it is for the menu, a shortcut is just any shortcut with the same command assigned as the toolbar item. The appropriate commands are shown directly in the table; how to assign a command will be described below.
When switched to a shortcut mode, the editor looks this way:

There is little to be said for it: just add as many shortcuts you want to, select the keys and the modifiers from the popup. Assigned commands are shown directly in the table on the left.
The bottom half of the dialogue window contains a command editor. Its look is the same regardless the mode of the upper half:

The browser in the left part contains all the application commands. The groups "General"..."Printing" contain all the standard Epoc commands (as defined by the Symbian and considerably extended by the XSdk); in the "Application" group there are specific commands of the particular application.
To assign a command to a command source (like a menu or toolbar item or a shortcut), just select the command source in the upper half of the window, the desired command in the lower half, and click the button "Connect"; that's all.
In case you try to assign a command which does not exist yet, it will be connected all right, and automatically added to the "Application" command group. You can also edit the commands there directly using the small buttons "New", "Rename", and "Del".
Each command is just a method name of the application controller. Thence, for example, since we have assigned the shortcut Shift-Ctrl-h to the command "help", in the resulting application a press of Shift-Ctrl-h will call the method help of the application controller object.
As we shall see below, many of the standard Epoc commands (like the help, or terminate,...) are already implemented in the application controller base class, and thus you do not need to implement them; just assign them, and it will immediately start working. Others--namely the project-specific commands in the "Application" group--you have to implement; just prepare the appropriate methods in the application controller, and recompile the project, that's all.
Each application in the XSdk must have an object, which stands for application controller. No other objects are needed for a minimal application; thence, you can forget all the Application, Document, AppUI etc. classes, known from the plain Symbian API (naturally they are there, but they are provided automatically by the XApplication framework, so you do not need to prepare them manually).
The application controller is a subclass of a standard XApplication class CXSdkStandardAppController, and itself is by convention name CXSdkAppController. Its skeleton was automatically made for you by the XSdk template system when you prepared a new application project; anyway, it is pretty plain. The header file XSdkAppController.h looks like this:
// XSdkAppController.h created by <you> on <date>
// Copyright (c) <you>
//
#error Use XSdk! This code cannot be compiled directly in the Epoc SDK
// the XSdk toolkit from the X.soft (http://www.x-soft.cz/XSdk) offers many
// convenient language extensions, not available in plain C++
#ifndef __XSdkAppController_h__
#define __XSdkAppController_h__
#include "XSdkStandardAppController.h"
@interface CXSdkAppController:CXSdkStandardAppController
{
}
// to be reimplemented if needed
//-void appDidInit;
//-BOOL appWillFinish;
//-void appDidForeground;
@actions
// standard commands
//-void preferences;
// other commands
@endactions
// generated, just ignore
+unsigned applicationUid;
@end
#endif
The header is a standard header of all XSdk files. The @action and @endaction directives are needed to simulate the dynamic messages in the static C++ rot: all the commands have to be placed between the directives. Apart from that, the skeleton class is empty: for your convenience, there are only outcommented declarations of some standard methods you might want to implement (they will be described in some details below).
The skeleton implementation in the XSdkAppController.cpp is even simpler: it is quite empty, allowing you to implement any methods you might want to. The @action and @endaction directives are used in the implementation the very same way as in the interface (in future versions that will not be needed).
As we already know, the commands--defined using the GUI tools described above--are automatically redirected to the appropriate methods in the application controller. Thus, let's say you have defined a menu item "Call a Jabberwocky" and assigned it to a command "callJabberwocky" this way:

All you have to do to make the command work is to implement the appropriate method:
@interface CXSdkAppController:CXSdkStandardAppController
...
@actions
...
-void callJabberwocky; // blame the C++ for the need to declare each method!
...
@endactions
...
@end
@implementation CXSdkAppController
...
@actions
...
-void callJabberwocky
{
XLog(@"Beware the Jabberwock, my son!");
}
...
@endactions
...
@end
That's all. The appropriate menu item will be automatically made for you, and each time it is selected, the method callJabberwocky will be automatically called. In case you do not implement the method, an alert will be presented with information "Unimplemented command: callJabberwocky". It is even possible to programmatically alter the application behaviour when an unimplemented command is encountered; the how is described below.
Now presume you need the menu item to be disabled in some conditions, or perhaps that you need a menu which represents a state--either using the checkmark, or thru a switchable menu titles (see the menu editor above for a description how to prepare these). Or, sometimes you might even want to set the contents of the menu title programmatically. There is support for all these tasks:
In case a menu item for a command XXX might be dimmed, just implement a method -BOOL XXXIsDimmed. It will be checked automatically before the appropriate menu item is show, and in case it returns YES, the item will be dimmed. Thus, should the Jabbewocky be available sometimes only, we might implement
-BOOL callJabberwockyIsDimmed
{
return can_see_looking_glass?NO:YES;
}
Though the menu item is visibly dimmed and not selectable, it might be possible to trigger the same command using a toolbar botton (these are not dimmable by the Epoc User Interface Guidelines) or a shortcut (which is naturally "not dimmable" at all). Thence, the XApplication provides a special support: in case a command, assigned to a dimmed menu item, is selected anyhow, an info message "Currently unavailable" is shown. You may want to override this: in case you implement a method -CXString *XXXIsDimmedReason, it is called automatically, and the string it returns will be shown:
-BOOL callJabberwockyIsDimmedReason
{
return @"Can't see the looking glass!";
}
Note that we don't check anything, for this method is called only if the appropriate menu item is dimmed. Incidentally, the method can return a nil, which means that no information message will be shown (generally, it is a bad practice, but sometimes you might want this behaviour). It is even possible to programmatically alter the way the message is show (eg. you might want to show an alert instead of an info message); the how is described below.
The menu item is able to express a state: either a boolean YES/NO state by means of the checkmark, or a enumeration state value using a switchable menu titles (see the menu editor above how to set them).
In both cases, the current menu state is determined by calling a method -int XXXState, if any. In case this method exists and the menu item is checked, the checkmark will be shown if and only if the method returns nonzero. In case there are switchable menu titles, the value returned by the method is used as an index, and the appropriate menu title is used (in case the value returned is too big, the first menu title is used, as if a zero was returned).
Suppose, for example, that we have named the "jabberwocky" menu item not just "Call Jabberwocky", but "Call Jabberwocky\Call Humpty Dumpty\Call Unicorn\Call Lion". That way we prepared a menu item with four switchable titles, and we can set which one will be displayed the following way:
-int callJabberwockyState
{
switch (whom_I_want_to_call) {
case Jabberwocky: return 0;
case Humpty: return 1;
case Unicorn: return 2;
case Lion: return 3;
}
}
Should we use this very same callJabberwockyState implementation, but defined the "Call Jabberwocky" menu item with this title and a checkmark, it will be shown checked for Humpty Dumty, Unicorn, or Lion, and unchecked for Jabberwocky.
In case the switchable menu titles are not sufficient for the needs of our application, there is a support for a fully dynamic menu title. Just implement a method -CXString *XXXDynamicMenuText; it will be automatically called before the menu item is displayed, and the string it returns is used for the menu title:
-int callJabberwockyDynamicMenuText
{
@Static; // see the XSdk preprocessor for a support...
int num=(int)@Static(NumberOfJabberwockies); // ...of statics...
@Static(NumberOfJabberwockies,++num); // ...in Epoc DLLs
return [CXString stringWith:@"This item was shown %d times",num];
}
There is a number of standard methods, implemented in the standard class CXSdkStandardAppController. They are called whenever some kind of event occurs; in case you want your application to respond to the event, just reimplement the appropriate method:
-void appDidInit;
This method gets called automatically as soon as the application is launched and all the standard objects are properly initialized. You can place here any action the application should perform automtically after start, like your own initializations, registering of application defaults, showing spash screens etc.
The default implementation is empty.
-BOOL appWillFinish;
This method gets called automatically when the application is about to quit (ie. the "Exit" menu item was selected, or alike). In case it returns YES, the application will quit; should it return NO, the termination will be cancelled and the application will go on running.
Place here any code to be done before the application ends; in case the code fails so that it would not be advisabe to quit the application, you can return NO.
The default implementation does nothing, just returns YES.
-void appDidForeground;
-void appDidBackground;
These methods are called automatically whenever the application goes to foreground (appDidForeground) or background (appDidBackground). The default implementations are empty.
-void showDimmedCommandReason(CXString *reason);
This method is called to present the reason a dimmed commad cannot be performed (see Dimmed menu items above). The string it gets is either the standard "Currently unavailable" one, or the string returned by the appropriate XXXIsDimmedReason method.
The default implementation shows the string as an info message.
-void showUnimplementedCommandName(CXString *name);
This method is called to inform the user that the command name is not implemented. The default implementation presents an alert, containing two lines: "Unimplemented command" and the name.
-void generalCommandExceptionHandler(CXException *exception);
This method is called in case an uncatched exception was raised during the execution of a command. The default implementation presents an alert, containing two lines: "Exception" and a combination of the exception name and the exception reason (see the CXException class).
Note that the Epoc uses internally an exception with number -1003 for termination; thence, should you want to reimplement this method without calling the default implementation, you must check for this manually:
-void generalCommandExceptionHandler(CXException *exception)
{
if ([exception epocLeaveNumber]==-1003) [exception raise];
...
}
There are some standard commands there as well; generally, you will just assign them to some menu or toolbar item or shortcut. Though, in case the standard action does not suit the needs of your application, you can reimplement them to change the action taken when the command is triggered:
-void help;
-BOOL helpIsDimmed;
The command help tries to locate a file with the name as the application's DLL, but with an extension "hlp" in the application folder. If it succeeds, the file is opened, or activated, in case it has been opened previously. It is presumed to be a file in the format of the Epoc Data application, for that is the Epoc standard help format. In case a help file is opened when the application terminates, it is automatically closed; you need not to take care of it.
The helpIsDimmed switch ensures any "Help" command in the menu (if any) will be dimmed in case the help file does not exist.
-void aboutApplication;
This command tries to locate a file "About.mbm" inside the application folder. If it succeeded, it loads the image, and shows a dialogue containing just the image loaded. Otherwise, it shows the application full name as an info message.
Note: the behaviour of the command in case there is no About.mbm file will be much more comprehensive in future ApplicationKit versions.
-void terminate;
The terminate command first check whether the application can be terminated using the appWillFinish standard method (see above), and in case it returned YES, it quits the application. All currently opened help files (see the command help above and the service method showHelpFile below) are automatically closed.
It is not recommended to reimplement this method, for (a) its implementation is not trivial, and (b) all the application-specific behaviour should be placed in the appWillFinish method anyway. Should you for any reason do so, just call the [super terminate] as the last command in the new implementation.
Note: there will be considerably more predefined standard commands in future releases of the ApplicationKit.
The application controller not only performs the command implementations; it serves as the main application centre, which offers a number of useable commands, as well. Therefore, there is a global macro XApp, which always represents the current application controller. For example, from any place in the application code you can call the service showInfoMessage (precisely described below) to show an info message this way:
[XApp showInfoMessage:@"Gee, I'm here!"]
Incidentally, some commands can be reasonably used as services as well--presume you want to programmatically quit the application in case some license check did not pass, or, say, use the "About" application dialogue as a splash screen. If so, you just call
if (want_to_quit) [XApp terminate:nil]; // the appWillFinish will be properly called
...
if (splash) [XApp aboutApplication:nil];
It really is that easy! As for the nil argument, each command can have one argument for a greater flexibility; many of them just ignore it.
Currently, the application controller offers the following services (all implemented in the standard superclass CXSdkStandardAppController):
-void showInfoMessage(CXString *msg,...);
-void showInfoMessage(XScreenCorner corner, CXString *msg,...);
These methods show an info message, ie. an inverted text in an edge of the screen shown for a few seconds. The text to be shown can be dynamically created using a printf-like format (with the "%@" allowed, just like anywhere in the XSdk):
[XApp showInfoMessage:@"The value cannot exceed %d!",max];
The first version shows the message in the default upper right corner. Or, you can use the second version and the predefined constants
typedef enum {
XTopLeft,XTopCentre,XTopRight,
XCentreLeft,XCentreCentre,XCentreRight,
XBottomLeft,XBottomCentre,XBottomRight
} XScreenCorner;
to place the message anywhere on the screen.
-void showBusyMessage(CXString *msg,...);
-void showBusyMessage(XTimeInterval delay,CXString *msg,...);
-void showBusyMessage(XScreenCorner corner,XTimeInterval delay,CXString *msg,...);
-void cancelBusyMessage;
These methods show a busy message, ie. a blinking inverted text in an edge of the screen, shown till cancelled. The text to be shown can be dynamically created using a printf-like format (with the "%@" allowed, just like anywhere in the XSdk):
[XApp showBusyMessage:@"Still preparing %d lines",numberOfLines];
The first version shows the message immediately in the default lower right corner. The second version allows for an initial delay: the message will be shown after a given number of seconds (not some unintelligible mili- or microseconds!!!) elapsed:
[XApp showBusyMessage:0.5:@"Sorry this takes more than a half of second!"];
Or, you can use the third version and the predefined constants
typedef enum {
XTopLeft,XTopCentre,XTopRight,
XCentreLeft,XCentreCentre,XCentreRight,
XBottomLeft,XBottomCentre,XBottomRight
} XScreenCorner;
to place the message anywhere on the screen.
-void alertDialogue(CXString *title,CXString *msg,...);
The method constructs and shows an one or two line alert dialogue. To construct the second line (or the first and only one in case the title is nil) a printf-like format can be used (with the "%@" allowed, just like anywhere in the XSdk).
-BOOL yesnoDialogue(CXString *title,CXString *msg,...);
Just like the previous one, but this case the dialogue contains buttons Yes and No, and the result (ie. which one the user has selected) is returned.
-void showHelpFile(CXString *helpFile,CXString *helpPath=nil);
-BOOL checkHelpFile(CXString *helpFile,CXString *helpPath=nil);
The method xx allows to present the user any help file. The help file name is given as the first argument; in case it has no extension, a "hlp" is added automatically. The second argument specified the path; if it is nil, the help file is searched for in the application folder.
If the help file is found, it is opened or activated in case it has been opened before. The framework remembers all opened help files, and they all are automatically closed when the application is terminated; you do not need take care of that.
The second method just checks whether the help file exists; it can be used eg. to dim an appropriate menu item or a button, in case there is no help file to be opened by it.
Note: there will be considerably more predefined services in future releases of the ApplicationKit.
Note that the global macro XApp is casted to the CXSdkAppController (not a CXSdkStandardAppController). That means you can easily call any of the application-specific commands yourself, or you can extend these services any way you might want to. With the example methods shown above implemented, the following would be perfectly valid anywhere in the application code:
[XApp callJabberwocky:nil];
(As for the nil argument, each command can have one argument for a greater flexibility; many of them just ignore it.)
Copyright © 1999-2000 X.soft, all rights reserved