Vous êtes sur la page 1sur 197

The SuperWaba Companion

Version 1.54

SuperWaba Companion

Table of Contents
PART I THE PLATFORM..................................................................................................8
Overview..............................................................................................................................9
Chapter 1 - Welcome.........................................................................................................10
Current Symbian Limitations...........................................................................................13
Chapter 2 - Installation Instructions...................................................................................14
Palm OS.........................................................................................................................14
Windows CE...................................................................................................................15
Symbian OS....................................................................................................................16
Windows 98 and beyond................................................................................................17
Linux...............................................................................................................................18
Running as Applet..........................................................................................................19
Running as Application...................................................................................................19
Chapter 3 - Running the Samples......................................................................................21
Using ANT......................................................................................................................21
Troubleshooting..............................................................................................................21
Chapter 4 - Warp and Exegen Deploying the application...............................................23
Warp Instructions...........................................................................................................23
Exegen Instructions........................................................................................................25
RenameFont Instructions................................................................................................28
Wxgn Instructions...........................................................................................................28
Chapter 5 - Configuring build.xml to use in your own projects...........................................29
Chapter 6 - Configuring IDEs to Debug and Run SuperWaba Programs..........................30
NetBeans or Forte..........................................................................................................30
JBuilder 6 Personal and Pro...........................................................................................31
Visual Cafe (3.1).............................................................................................................32
Linux ..............................................................................................................................32
Eclipse 2.1 and 3.0.........................................................................................................34
Microsoft Visual J++.......................................................................................................35
General Settings.............................................................................................................35
Optional arguments to waba.applet.Applet ....................................................................36
Chapter 7 - Unicode Support.............................................................................................37
Part II USER INTERFACE...............................................................................................39
Overview............................................................................................................................40
Chapter 8 Types of User Interface..................................................................................42
Chapter 9 The MainWindow class..................................................................................44
Chapter 10 Adding Controls............................................................................................46
Chapter 11 Events...........................................................................................................51
Chapter 12 Basic Controls..............................................................................................55
waba.ui.Button................................................................................................................55
waba.ui.Check................................................................................................................57
waba.ui.ComboBox.........................................................................................................58
waba.ui.Edit....................................................................................................................60
waba.ui.Label.................................................................................................................63
waba.ui.ListBox...............................................................................................................64
waba.ui.PopList..............................................................................................................66
waba.ui.ProgressBar......................................................................................................68
waba.ui.Radio.................................................................................................................68

SuperWaba Companion

waba.ui.ScrollBar............................................................................................................70
Chapter 13 - Advanced Controls........................................................................................73
waba.ui.MenuBar and waba.ui.PopupMenu...................................................................73
waba.ui.PushButtonGroup..............................................................................................76
waba.ui.TabPanel...........................................................................................................78
waba.ui.MessageBox......................................................................................................81
waba.ui.InputDialog........................................................................................................83
waba.ui.Grid...................................................................................................................84
Chapter 14 The Window class........................................................................................86
Chapter 15 Utility Classes...............................................................................................91
waba.ui.Calculator..........................................................................................................91
waba.ui.Calendar............................................................................................................92
waba.ui.Keyboard...........................................................................................................93
Chapter 16 Splitting your application's logic using waba.ui.Container...........................94
PART III INPUT & OUTPUT............................................................................................97
Overview............................................................................................................................98
Chapter 17 - waba.io.Stream.............................................................................................99
Chapter 18 - waba.io.Catalog..........................................................................................100
Useful tips.....................................................................................................................102
addRecord....................................................................................................................103
addRecord....................................................................................................................103
close.............................................................................................................................104
delete............................................................................................................................105
listCatalogs...................................................................................................................105
getRecordCount...........................................................................................................106
isOpen..........................................................................................................................106
rename..........................................................................................................................106
setRecordPos...............................................................................................................107
inspectRecord...............................................................................................................107
getAttributes.................................................................................................................108
setAttributes..................................................................................................................109
getRecordPos...............................................................................................................109
getRecordSize..............................................................................................................110
resizeRecord................................................................................................................110
deleteRecord................................................................................................................111
readBytes......................................................................................................................111
writeBytes.....................................................................................................................112
skipBytes......................................................................................................................113
getRecordOffset...........................................................................................................113
getRecordAttributes......................................................................................................114
setRecordAttributes......................................................................................................114
setRecordOffset............................................................................................................115
getName.......................................................................................................................115
Chapter 19 - waba.io.DataStream....................................................................................116
DataStream Constructor...............................................................................................118
close.............................................................................................................................118
pad................................................................................................................................119
skip...............................................................................................................................119
readBoolean.................................................................................................................120
readByte.......................................................................................................................120

SuperWaba Companion

readBytes......................................................................................................................120
readBytes......................................................................................................................121
readFloat......................................................................................................................121
readIntLE......................................................................................................................121
readShortLE..................................................................................................................122
readInt..........................................................................................................................122
readShort......................................................................................................................122
readDouble...................................................................................................................123
readLong......................................................................................................................123
readUnsignedByte........................................................................................................123
readUnsignedShort.......................................................................................................123
writeIntLE......................................................................................................................124
writeShortLE.................................................................................................................124
writeBoolean.................................................................................................................125
writeByte.......................................................................................................................125
writeByte.......................................................................................................................126
writeBytes.....................................................................................................................126
writeBytes.....................................................................................................................127
writeFloat......................................................................................................................127
writeInt..........................................................................................................................128
writeShort......................................................................................................................128
writeDouble...................................................................................................................129
writeLong......................................................................................................................129
readString.....................................................................................................................129
readStringArray............................................................................................................130
writeString.....................................................................................................................130
writeStringArray............................................................................................................131
readCString..................................................................................................................131
writeCString..................................................................................................................132
Chapter 20 - waba.io.ResizeStream................................................................................133
startRecord...................................................................................................................134
startRecord...................................................................................................................134
restartRecord................................................................................................................134
endRecord....................................................................................................................135
readBytes......................................................................................................................135
writeBytes.....................................................................................................................136
close.............................................................................................................................136
Chapter 21 - waba.io.ByteArrayStream............................................................................138
close.............................................................................................................................139
getBuffer.......................................................................................................................139
count.............................................................................................................................139
readBytes......................................................................................................................140
reset..............................................................................................................................140
skipBytes......................................................................................................................141
reuse.............................................................................................................................141
writeBytes.....................................................................................................................141
available.......................................................................................................................142
Chapter 22 - Dealing with large databases......................................................................143
Chapter 23 waba.io.Socket...........................................................................................145
close.............................................................................................................................146

SuperWaba Companion

isOpen..........................................................................................................................146
setReadTimeout...........................................................................................................146
readBytes......................................................................................................................146
writeBytes.....................................................................................................................147
disconnect....................................................................................................................147
refreshBeforeEachRead...............................................................................................147
lastError........................................................................................................................147
Configuring...................................................................................................................150
Testing..........................................................................................................................151
Chapter 24 waba.io.SerialPort......................................................................................153
close.............................................................................................................................153
isOpen..........................................................................................................................154
setFlowControl..............................................................................................................154
setReadTimeout...........................................................................................................154
readBytes......................................................................................................................154
writeBytes.....................................................................................................................154
readCheck....................................................................................................................155
lastError........................................................................................................................155
Configuration................................................................................................................155
Testing..........................................................................................................................156
SerialPDB..................................................................................................................157
SerialSocket..............................................................................................................158
Chapter 25 waba.io.File................................................................................................160
isAvailable....................................................................................................................160
close.............................................................................................................................161
createDir.......................................................................................................................161
delete............................................................................................................................161
exists.............................................................................................................................161
getSize..........................................................................................................................162
getPath.........................................................................................................................162
isDir..............................................................................................................................162
isOpen..........................................................................................................................162
listFiles.........................................................................................................................163
readBytes......................................................................................................................163
writeBytes.....................................................................................................................164
rename..........................................................................................................................164
setPos...........................................................................................................................165
setAttributes..................................................................................................................165
getAttributes.................................................................................................................166
setTime.........................................................................................................................166
getTime.........................................................................................................................167
getCardVolume.............................................................................................................167
lastError........................................................................................................................167
PART IV EXTENSION LIBRARIES...............................................................................169
Chapter 26 Scanner Library..........................................................................................170
Chapter 27 Printer Library.............................................................................................171
OVERVIEW..................................................................................................................171
Troubleshooting............................................................................................................171
Chapter 28 Catalog Search Library...............................................................................174
OVERVIEW..................................................................................................................174

SuperWaba Companion

Sample .........................................................................................................................174
Chapter 29 Image Library.............................................................................................176
OVERVIEW..................................................................................................................176
Jpeg Error list...............................................................................................................177
Chapter 30 ZLib Native Compression...........................................................................180
OVERVIEW..................................................................................................................180
Sample..........................................................................................................................180
Chapter 31 Conduit Synchronization............................................................................183
OVERVIEW..................................................................................................................183
Conduit class................................................................................................................183
RemoteCatalog class....................................................................................................185
RemoteCatalogRecord class........................................................................................186
RemoteFile...................................................................................................................187
Conduit Registration.....................................................................................................187
Important Tips...............................................................................................................188
Sample for reading.......................................................................................................190
Sample for writing.........................................................................................................191
Sample for RemoteFile.................................................................................................192
PART V NATIVE LIBRARIES........................................................................................193
Overview..........................................................................................................................194
Chapter 33 The Java Library.........................................................................................195
Chapter 34 The Native Library......................................................................................200
Chapter 35 Java Library Generation.............................................................................211
SuperWaba Global Extension Library..........................................................................211
SuperWaba Local Extension Library............................................................................211
Chapter 36 Configuration of the Project file for CodeWarrior.......................................213
Chapter 37 Configuration of the Project file for eVC 3.0...............................................218
Chapter 38 Configuration of the Project file for VC 7....................................................220
Chapter 39 Native libraries for Linux/PalmOS using gcc..............................................221
Build setup....................................................................................................................221
Build configuration........................................................................................................226
Build..............................................................................................................................226
Platform build environment requirements.....................................................................227
Common requirements..............................................................................................227
Linux target requirements.........................................................................................227
PalmOS/m68k target requirements...........................................................................227
PalmOS5/ARM target requirements..........................................................................227
PalmOS5/ARM VMware based development environment.......................................228
Chapter 40 Native libraries for Symbian OS.................................................................231
Introduction...................................................................................................................231
Official recommended implementation.........................................................................231
Symbian OS globals hack (unofficial)...........................................................................235
Chapter 41 How to use the Libraries.............................................................................237
Chapter 42 Web Services.............................................................................................238
Introduction...................................................................................................................238
Preparing the server.....................................................................................................238
Running the test...........................................................................................................239
Creating and Deploying your Web Service..................................................................241
Using your Web Service...............................................................................................241
Understanding the SOAP request................................................................................243

SuperWaba Companion

The SOAP Class...........................................................................................................244


PART VI OPTIMIZATION TRICKS................................................................................247
Overview .......................................................................................................................248
Chapter 43 - The Tricks...................................................................................................249
Chapter 44 - Comparison Table.......................................................................................259
PART VII APPENDIXES ...............................................................................................263
Appendix I - Thanks to..................................................................................................264
Appendix II - Copyright.....................................................................................................265
Appendix III Document Changes...................................................................................266

SuperWaba Companion

PART I THE PLATFORM

SuperWaba Companion

Overview
Welcome to SuperWaba. This tutorial combines the SuperWaba introduction with
the old User Interface, Input/Output, Library and Optimization Tricks tutorials, plus the
Printer Library, CatalogSearch Library and the Image Library tutorials. It will be extended
to include the other packages as well. The Game tutorial was left standalone because it is
also released in the GPL version of the SuperWaba SDK.
This tutorial assumes that you know how to write Java programs. If not, I suggest
that you take a basic course in Java at
http://java.sun.com/docs/books/tutorial/java/index.html
Some conventions used in this tutorial:

Code is written in font Courier New monospaced.


When a code sample has ... (ellipses) between two parts, it means that some part of
that code has been stripped.
Measurements are always in pixels unless otherwise specified.
The symbol means attention.

This tutorial follows the Object Oriented naming convention: a class


containing methods (~functions) and members (~variables).
WINDOWS CE refers to all the possible names deriving from that platform:
Windows CE (up to 2.x), Pocket PC (= Windows CE 3.x), .NET (= Windows CE 4.x), and
some Smartphones. SW refers to SuperWaba. EPOC refers to the Symbian platform (it is
an old name of this platform). The term main class always refers to the class that
extends waba.ui.MainWindow.
IMPORTANT NOTICE FOR COMMUNITY (GPL) USERS: Parts V and VI are not
included, although they appear in the index. Also, part IV is available so you can see
what's available in the Professional LGPL version, but you will not be able to run them,
since the binaries are not available.

Please read the Copyright terms in appendix II. By reading this book, you're
agreeing with them.

SuperWaba Companion

10

Chapter 1 - Welcome
Thank you for your interest in SuperWaba. If you don't know where to start, here are
some tips:
1. SuperWaba is not Java. Although it is 99% compatible with the Java language (the
only bytecode that is not implemented is synchronized), it cannot be called a Java VM
due to copyright restrictions. To use SuperWaba, you will have to forget the JDK API and
use the SuperWaba provided API (just like you would if using J2ME). Make a good read
of the API javadocs: they will show you the library differences between JDK and
SuperWaba APIs.
2. SuperWaba can run in four locations:
1. On the PDA (currently in Palm OS from 3.0 up, most Windows CE models, and most
Symbian OS phones), using a proprietary bytecode interpreter,
2. On the desktop, using the Sun JDK
3. On the desktop, using a Java-enabled browser
4. On the desktop, standalone, using the proprietary bytecode interpreter compiled for
the Windows platform (Windows 98 or beyond) and Linux.
2a. PALM OS: The VM part that needs to be installed in the Palm OS device consists of at
least three files:
SuperWaba.pdb: contains the classes available in the following packages: waba.fx,
waba.ui, waba.io, waba.sys, waba.lang, waba.util (these classes are located under
SuperwabaSDK/src/java/waba/*).
SuperWaba.prc: contains the bytecode interpreter, the class loader and the garbage
collector.
SWNatives.prc: contains the implementation for the native methods (E.G.:
Graphics.drawLine)
2b. WINDOWS CE: The VM components that must be installed in the Windows
CE/Pocket PC are:
SuperWaba.pdb: performs the same function as its Palm OS counterpart named above
SuperWaba.exe: the counterpart of the SuperWaba.prc and SWNatives.prc files used
by Palm OS.
SDL.dll, SDL_net.dll: these are the runtime engines for the Simple Direct-media Layer
library. This library enables SuperWaba to use open-gl under Windows CE, boosting
the graphics performance.
MSW.pdb: contains font files required by SuperWaba
2c. UIQ/SYMBIAN OS 7: SuperWaba's VM components must be installed using the
uiq/SuperWaba.sis file. This file contains:
SuperWaba.pdb: the counterpart of the Palm OS file with the same name
SuperWaba.app: the counterpart of the Palm OS files SuperWaba.prc and
SWNatives.prc
MSW.pdb: contains font files required by SuperWaba

SuperWaba Companion

11

2d. Series60/SYMBIAN OS 7s: SuperWaba's VM components must be installed using the


s60/SuperWaba.sis file. This file contains:
SuperWaba.pdb: the counterpart of the Palm OS file with the same name
SuperWaba.app: the counterpart of the Palm OS files SuperWaba.prc and
SWNatives.prc
6SW.pdb: contains font files required by SuperWaba
2e. Series80/SYMBIAN OS 7s: SuperWaba's VM components must be installed using the
s80/SuperWaba.sis file. This file contains:
SuperWaba.pdb: the counterpart of the Palm OS file with the same name
SuperWaba.app: the counterpart of the Palm OS files SuperWaba.prc and
SWNatives.prc
6SW.pdb: contains font files required by SuperWaba
2f. When running the software on the desktop, you'll need a JDK to be able to compile the
applications (1.2.x recommended but also compatible with 1.1.x, 1.3.x and up). When
using a 1.3.x or higher compiler, you must add -target 1.1 to the command line.
3. The image below better describes the process of developing a SuperWaba program:

When you create a SuperWaba application (Hello.java), you must compile it using JDK,
and you'll get a classfile (Hello.class). Then, you must run the superwaba.tools.Warp
tool, which will package Hello.class with all other classes and resources it references

SuperWaba Companion

12

(supported extensions are .class, .wav, .bmp, .gif, .jpeg, jpg, .png, .txt) into the file
Hello.pdb. You can see the Hello.pdb file as something similar to a JAR file.
The device does not recognize a pdb file, so you must also have a launcher. The
launcher depends on the platform (prc for Palm OS, exe/lnk files for Windows CE, and
app for Symbian). It will contain application's icon and its version, among other
information. To create the launcher, you use superwaba.tools.Exegen. Exegen also
creates installation files so you can easily install the application in Windows CE (cab),
Symbian (sis) and Palm OS (install.exe).
4. There are some examples in the SuperwabaSDK/src/java/superwaba/samples
directories. These samples use almost all the SuperWaba class library, so it is a good
source of information from where you can start your applications.
5. Currently there are no User Interface creators for SuperWaba. Perhaps, there is a
great standalone tool that lets you create user interfaces. You can even use it in your
device. See superwaba.samples.app.guiBuilder. It generates the code necessary to run
the application, which can be exported to the desktop to be compiled.
6. If you have questions, point your newsgroup reader to
news://news.superwaba.net/pilot.programmer.waba and ask questions there. But,
PLEASE, download all messages first and do a search on them. Your question may have
already been answered, and you'll save your time and the time of people at the
newsgroup. Make sure you have downloaded all messages: there are more than 25000. If
you're having problems, download the Mozilla Thunderbird e-mail client from
www.mozilla.org).
Note: there's a mirror of the newsgroup in
http://groups.google.com/groups?group=pilot.programmer.waba. Don't post messages
to it! It does not reflect the actual server (news.superwaba.net), but the old one
(news.falch.net).
7. A Professional package subscription includes 3 support incidents. Please read the email you received after you subscribed for more information on how to post questions.
8. When running your application on POSE, don't forget to turn off some settings in
"Settings/Debugging":
Hardware Register Access
Proscribed Function Call
Screen Access
Although emulators for Windows CE exist, we do not provide a special SuperWaba.exe
file to run on them because they are very poor. Better use the standalone Windows
(Win32) version of SuperWaba.exe produces better results.
9. DON'T use the Jikes compiler with SuperWaba.
10. Be sure to read the FAQ and the WIKI at the SuperWaba site, and check the API
javadocs at SuperWabaSDK/docs/html/index.html

SuperWaba Companion

13

Current Symbian Limitations


Symbian proved to be a very complicated platform, even more than Palm OS. Getting the
first samples running took 4 months of very hard work. The lack of documentation and
support is incredible. Currently, we have tested the VM on 3 Symbian OS platforms: UIQ
(SonyEricsson's P800), Series60 (Nokia 6670), Series80 (Nokia Communicator 9500) and
Series60 3rd edition (Nokia E62). If you make it work on another device, please update our
wiki at http://superwaba.sourceforge.net/cgi-bin/twiki/view/Main/SupportedDevices.
These are the currently known problems:
1. Serial, Bluetooth and Sound are not working. But Socket is.
2. File.rename is not working.
IMPORTANT You must install the VM and the samples SIS files on the SAME DRIVE !
Either on the memory card (drive D) or in main memory (drive C).

SuperWaba Companion

14

Chapter 2 - Installation Instructions


These are the basic files that must be installed in order to run SuperWaba programs.
Along with these files you must also install the files you created, and any extension
libraries they may require.
Note: the library folders referenced here are located under SuperWabaSDK/lib/vm/.

Palm OS
You can use the installation files for Palm OS located in bin/installers/vm/palm,
otherwise you can manually install the following files in your device, depending on your
Palm OS version / model:

For Palm OS < 5 Files located in folder


palm/68k/PalmOS3_or_4_with_8bits_screen
SuperWaba.prc (VM)
SWNatives.prc (native methods)

For Palm OS >= 5 devices if the libraries DB2e, IrPrint or PrintBoy are not used by your
program, you can install the new ARM VM, which is up to 20 times faster than the 68k
ones. The files are located in folder palm/arm/PalmOS5. These three libraries are
NOT PORTED to Palm OS 5 ARM.

For Palm OS >= 5 and Palm OS 4.1 16 bpp devices that can't emulate 8bpp (including
Tungsten W and Kyocera 7135) Files located in folder
palm/68k/PalmOS5_or_4_with_16bits_screen
SuperWaba.prc (VM)
SWNatives.prc (native methods)

Zire 71 and other Palm OS 5 devices that continuously reset Files located in folder
palm/68k/PalmOS5_AvoidAutoReset
SuperWaba.prc (VM)
SWNatives.prc (native methods)

For all Palm OS versions File located in folder xplat


SuperWaba.pdb (API Classes)

2. When installing a SuperWaba program on Palm OS, be sure to install both prc and pdb
files generated. You can create an install.exe file to make the install easier. See Exegen's
/inst parameter.
3. If you're using files from the superwaba.ext package, install the corresponding library
file (located in xplat crossplatform folder). Some samples also need an extension
library to run. Check the corresponding chapter in this document.
4. When creating your own programs, be sure to use the same Creator ID in both
EXEGEN and WARP (or just use the default one). Otherwise, the program won't run.

SuperWaba Companion

15

Windows CE
Windows CE files can be easily installed using cab files. So, To install the SuperWaba
VM on your device, run the SuperWabaSDK/bin/installers/vm/ce/ CEinstall_RunMe.bat
file.
Note: Intermec Norand 600 series PDAs require manual installation of the SuperWaba
VM. Use the VM located in folder SuperWabaSDK/lib/vm/ce/PPC211/x86.
Sometimes the cab installer does not work and you will have to install the files manually.
This often occurs on new devices. If this is your case, follow the instructions below:
1. Install these files in your WINDOWS CE device under a newly created /SuperWaba
folder (from the root).
SuperWaba.exe (VM) ***
SDL.dll and SDL_net.dll (Simple Direct-media Layer runtimes)
SuperWaba.pdb (API Classes)
MSW.pdb (Font file)
2. *** Windows CE has more than 10 possible choices of the SuperWaba.exe/SDL*.dll
files that must be installed. These choices are the combination between the target
platform and the processor type.
The possible targets are: HPC2000, HPC211, PocketPC, PPC211 (PocketPC also
runs on .NET)
The possible processors are: ARM, SH3 and MIPS
You must choose the right SuperWaba.exe file located under the
SuperWabaSDK/lib/vm/ce directories. If you install the wrong file, you will simply get an
error message from the operating system. The most used VM is PocketPC/ARM.
3. File SuperWaba.pdb is located in folder xplat. File MSW.pdb is located in folder fonts.
4. When installing a SuperWaba program, be sure to install both EXE and PDB files
generated with Exegen and Warp. The EXE file must be installed in the Start Menu,
ideally under a folder called SuperWaba, along with other SuperWaba programs.
5. The PDB file must be installed in a directory specific for your program. You cannot
install it in the /SuperWaba directory. The directory is specified when running the
EXEGEN program and has, by default, the same name of your Main class.
6. If you're using classes from the ext package, install the corresponding library file
(located in folders xplat and ce). Some samples also need an extension library to run.
6a. SuperWaba global libraries must be installed in the /SuperWaba directory.
6b. SuperWaba local libraries must be installed in the application's directory.

SuperWaba Companion

16

7. You can also install optional fonts. Remember, all fonts must be placed under the
/SuperWaba directory.
8. When creating your own programs, be sure to use the same Creator ID in both
EXEGEN and WARP (or just use the default one).
9. If you don't follow all these 8 rules above, your program will not run.
10. To run the welcome application on Windows CE, click in the SuperWaba.exe file
using the File Explorer or create a SuperWaba.lnk file with the following line, installing it
in the Start Menu:
24#\SuperWaba\SuperWaba.exe
11. The picture below shows a sample of directory organization (sdl.dll and sdl_net.dll are
missing from the picture):

12. It is possible to install the VM and the files in a different directory instead of
/SuperWaba. To do this, you must install the VM using the cab files and select a directory
other than the default (a registry key will store the directory you choosen, and the vm will
run) or, if you can't use the cab files (new devices may not be recognized by the cab files),
you must install SuperWaba manually and create the following registry key:
Class: HKEY_LOCAL_MACHINE
Hierarchy: SOFTWARE\\Apps\\SuperWaba VM"
Name: "InstallDir"
Type: REG_SZ
And then specify, in the Data, the directory where you had installed the VM.

Symbian OS

SuperWaba Companion

17

This is the easiest one to install: the only way to install is using a SIS (Symbian
Installation System) file. To create it, you must pass the /sis parameter to Exegen. Then
Exegen will create the file and a double-click installs on the device.
You have to install the VM and the programs in the same drive (memory card is safer).

There are three different installation files for:

UIQ (e.g. SonyEricsson's P800) in folder uiq

Nokia's Series 60 (e.g. Nokia 6670) in folder s60

Nokia's Series 80 (e.g. Nokia Communicator 9500) in folder s80

Nokia's Series 60 3rd edition (e.g. Nokia E62) in folder s60v3


If you don't know the right symbian version of your Nokia phone, you may select your
device on the site http://www.forum.nokia.com/devices/matrix_s60_1.html and look at the
Developer Platform field in the Technical Specs.

Windows 98 and beyond


1. Create a new folder, named c:\SuperWaba
2. Copy the files win32/SuperWaba.exe, xplat/SuperWaba.pdb and any other library
needed (PDB and DLL files, not JAR or CLASS files).
3. Install one of the two font files in c:\SuperWaba: 5SW.pdb or MSW.pdb. It's possible
to emulate both Windows CE and High-resolution Palm OS PDAs, passing in the
command line /w 240 /h 320 for the first one and /w 320 /h 320 for the second one. The
default is 240x320 and thus, the MSW.pdb must be installed. Do not install both font
files.
4. Create a directory for your program under c:\SuperWaba, just like in the Windows CE
targets (as explained in the last topic), and place its PDB files there.
5. To run the VM, double-click in the SuperWaba.exe file.
6. To run your program, you must call the SuperWaba.exe, passing in the command line
the parameters to configure the VM and inform your main class. To make it easier, you
can create a shortcut using Exegen with the /LNK parameter. The lnk file created
assumes that SuperWaba.exe is installed on c:\SuperWaba and that the program's folder
is c:\SuperWaba\<prcName_exegen's_parameter>.
7. You may specify the folder where Catalogs will be read/written using
waba.sys.Settings.dataPath member. See javadocs for more information.
Note: you can optionally create a cmd or bat file and pass parameters as follows (using
the uiGadgets sample):
c:\SuperWaba\SuperWaba.exe superwaba/samples/ui/UIGadgets
UIGadgets DoHD

SuperWaba Companion

18

Runs the program UIGadgets, located under c:\SuperWaba\UIGadgets folder (1 st


+ 3rd parameters) (DoHD is the creator id)
c:\SuperWabaSDK\lib\win32\SuperWaba.exe UIBench (continues in next
line)
c:\SuperWabaSDK\samples\app\UIBench\build OhdB
Runs the program UIBench, telling that the UIBench.pdb is at the given path.
(OhdB is the creator id)
It also specifies that the SuperWaba.exe file at not at the default place
c:\SuperWabaSDK\lib\win32\SuperWaba
versapalm/finance/VPFinance VPFinance AnGD
Runs the versapalm.finance.VPFinance program, located under
c:\SuperWaba\VPFinance folder (AnGD is the creator id)

Linux
Install the SuperWaba package corresponding to your Linux distribution. Currently, two
package formats are provided:

RPM package (Redhat Package Manager)


DEB package (Debian package)

To install on Redhat 9.0 or newer, run your preferred package manager and install the
bin/installers/vm/linux/superwaba-5.0.0-2.i386.rpm file. If you prefer command line, log
in as root, and run the following command:
rpm -Uvh bin/installers/vm/linux/superwaba-x.y.z-n.i386.rpm
To install on Debian, run your preferred package manager and install the
bin/installers/vm/linux/superwaba-5.0.0-3.i386.deb file. If you prefer command line, log
in as root, and run the following command:
dpkg -i bin/installers/vm/linux/superwaba-x.y.z-n.i386.deb
Both packages install a minimal SuperWaba runtime environment at the following prefix
/usr/local. The bin subfolder contains a helper script named superwaba to run the VM
and the lib/superwaba subfolder contains the required runtime files.

superwaba.bin: the VM executable


SuperWaba.pdb: the VM class files
XPlatGame.pdb: the game extension library
XPlatUtilProps.pdb: very useful util classes
MSW.pdb: font file

Insofar /usr/local/bin should be in your PATH environment variable, you should now be
able to run the VM, by just entering superwaba on the command line.
To display the list of supported options, run superwaba help.

SuperWaba Companion

19

To execute an application, you need its pdb file and its creator ID, you also have to know
the application mainclass (the class inheriting from the Waba MainWindow class).
NOTE: If you don't know an application creator ID, you may list the pdb content with Warp
which displays the creator field you have to provide to identify the pdb file to launch the
application.
The command line to run an application is:
superwaba [options] <class-name> <class-path> <creator-id>
...where <class-name> is the class name with it's package name with / (not .) as
package separator and without the trailing .class, <class-path> is the absolute path of
the directory containg the application pdb file, and the <creator-id> the PalmOS crid.
for instance to run the Ping game, enter:
superwaba superwaba/samples/ext/game/ping/Ping \
$SUPERWABA_ROOT/lib/samples/palm/ext/game/ping PiNg
You may also install the packaged SuperWaba samples for Redhat or Debian. Those
packages are available in the "bin/installers/samples/linux" folder. Install them as you
installed the VM (see the instructions above). The samples are installed in the folder
"/usr/local/share/superwaba/samples". All samples are provided with their launching script
(generated with Exegen).

Running as Applet
1. Package all the classes you need into a jar file. The main waba classes are packaged
into the file SuperWabaSDK/lib/vm/applet/Waba_only.jar. If your class uses any of the
extension libraries, then you must use the file SuperWabaSDK/lib/SuperWaba.jar file
instead.
2. Create the html file. Note that the code is not your application's main class, but it is
always waba.applet.Applet. The main class is specified using the parameter appClass.
You must also specify the used jar files, in the archive tag (separated by comma).
Check the samples in the folder SuperWabaSDK/bin/installers/samples/applet.

Running as Application
1. We recommend that you do not package the files into the jar file, unless you're
deploying the application to your client.
2. You must call something like this:
java -classpath .;/SuperWabaSDK/lib/SuperWaba.jar waba.applet.Applet
<your_main_class_here>

SuperWaba Companion

20

Do not forget the . (dot) in the classpath, or your classes won't be found. We assume in
the line above that the SDK was installed in the root and that you're in the same folder
where your main class resides.

SuperWaba Companion

21

Chapter 3 - Running the Samples


Using ANT
There are some samples in the folder samples.
To run the sample, you can use the use the build.xml ANT makefile. You may download
ANT from here: http://ant.apache.org/. If Ant is not running after you unpack it, set the
java_home environment variable pointing to where you installed JDK (e.g.: set
java_home=c:\jdk1.2.2).
Each sample has a build.xml file, with application specific settings, that calls the base
SuperWabaSDK/build.xml.
Open a shell (if running on Windows, go to the command prompt), change to the
SuperWabaSDK folder, and type ant help to see the instructions.
To rebuild all samples, use ant build-samples under the SuperWabaSDK folder.
IMPORTANT: The samples are ready to be installed in the devices or runned in the
desktop as applet just check the folders under
SuperWabaSDK/bin/installers/samples/<target platform>. Check the <target platform>
instructions below:

ce: double-click on the file <samplename>_install.bat


epoc: double-click on the file <samplename>.sis
palm: double-click on the file install.exe

Troubleshooting
If, after you install the sample in the device, an error message appears saying Can't find
class, you'll need to install also a SuperWaba Extension Library. Next is a list of the
samples and their required libraries. Note that some of them require a native library, and
the needed file may be a prc (for Palm OS) or a dll (for Windows). The root folder for the
samples below is SuperWabaSDK/src/java/superwaba/samples.

app/Guibuilder: XPlatIo.pdb, XPlatUi.pdb, PalmIoBuiltIn.pdb


app/HtmlBrowser: XPlatHtml.pdb, XPlatXML.pdb, XPlatIoHttp.pdb and the samples
contained in HtmlSampleDB.pdb
app/SWCalc: When running in Palm OS 160x160 devices, install the TinySmall.pdb
font file. If running on Clie, Palm OS 5 or Windows CE devices, install the
TinyLarge.pdb font file instead.
app/Watch: PalmIoBuiltIn.pdb
ext/game/Ping and SWBreak: XPlatGame.pdb, XPlatUtilProps.pdb
ext/image/gif and gifanimated: XPlatFxGif.pdb and XPlatFxGif.prc/dll

SuperWaba Companion

22

ext/image/jpeg and photos: XPlatFxJpeg.pdb and XPlatFxJeg.prc/dll


ext/image/png: XPlatFxPng.pdb and XPlatFxPng.prc/dll
ext/io/catsearch/longrecords: XPlatIoSearch.pdb and XPlatIoSearch.prc/dll. It also
needs the file TestSearchLongDB.pdb
ext/io/catsearch/shortrecords: XPlatIoSearch.pdb and XPlatIoSearch.prc/dll. It also
needs the file TestSearchShortDB.pdb
ext/io/PDBConduit: XPlatIo.pdb
ext/io/pimal/PimalScenarios: XPlatIo.pdb,
CeIoBuiltIn.pdb+CeIoBuiltInPimal.pdb+CeIoBuiltIn.dll (if Windows CE) or
PalmIoBuiltIn.pdb+PalmIoBuiltInPimal.pdb (if Palm OS).
ext/io/printer/irprint: XPlatIoPrint.pdb, PalmIoPrintIrPrint.pdb+PalmIoPrintIrPrint.prc
ext/io/printer/printboy: XPlatIoPrint.pdb, XPlatIoPrintPBoy.pdb+XPlatIoPrintPBoy.prc
ext/io/scanner and scannerwithwindow: XPlatIoScanner.pdb and XPlatIoScanner.prc/dll
ext/sql/AddressBook and BenchLitebase: XPlatSqlPdb.pdb, XPlatUiDb.pdb and
XPlatSqlPdb.prc/dll
ext/sql/testcases: XPlatUnit, XPlatSqlPdb.pdb and XPlatSqlPdb.prc/dll
ext/util/zip: XPlatUtilZip.pdb
ext/zlib: XPlatZlib.pdb
io/Socket: XPlatIo.pdb
ui/painter: XPlatUi.pdb
util/Zip: XPlatUtilZip.pdb, XPlatIoUiUtil.pdb

SuperWaba Companion

23

Chapter 4 - Warp and Exegen Deploying the application


The files described here are located in two places:
Sources are located under SuperWabaSDK/src/java/superwaba/tools folder
Binaries are located in SuperWabaSDK/lib/SuperWabaTools.jar file
These files were taken from the WExtras class, package wababin, and enhanced for
SuperWaba 2 and above.
Copyright 1999-2001 Rob Nielsen
Copyright 2002-2005 SuperWaba Ltda.
There are 5 callable files in this directory:
superwaba.tools.Warp - pachages your class files into a pdb
superwaba.tools.Exegen - creates an "executable" file that calls the vm inside the
device
superwaba.tools.RenameFont - renames a font pdb file so it fits in the SuperWaba
Font-Name Pattern.
superwaba.tools.Wxgn - calls warp and exegen with only one command
superwaba.tools.NativeMethodsPrototypeGenerator generates the native methods
prototypes. It will be explained in Part V of this book.

All these files are written in Java, and thus need the java.exe file to run. Below is a
command-line sample:
java.exe -classpath
/SuperWabaSDK/lib/SuperWaba.jar;/SuperWabaSDK/lib/SuperWabaTools.jar
superwaba.tools.Warp <your command-line here>
java.exe -classpath
/SuperWabaSDK/lib/SuperWaba.jar;/SuperWabaSDK/lib/SuperWabaTools.jar
superwaba.tools.Exegen <your command-line here>

NOTE: If you specified the SUPERWABA_ROOT environment variable, you may also use
the Windows or Linux helper scripts bin/Warp[.bat] and bin/Exegen[.bat]

Warp Instructions
(Super)Waba Application Resource Packager for Java Version 5.0
Copyright (C) Rob Nielsen 1999-2001. All rights reserved
Copyright (C) SuperWaba Ltda 2002-2005. All rights reserved
Usage: java superwaba.tools.Warp command [options] pdbfile [files]
Commands (case insensitive):
c Create new pdb file
l List contents of a pdb file
Options Description
/?

Displays usage text

SuperWaba Companion

24

Options Description
/!

Replaces the ! in the internal representation of the file, putting in the prc and
removing from the pdb.

/c

Override and assign PDB database creator (e.g. /c CrTr)

/r

If a directory is specified in the files, recurse any subdirs

/q

Quiet mode (no output except for errors)

/$

Set the Palm OS copy protection attribute

/x

Specify a list of package/class names whose classes won't be added.


You can specify a list without spaces as 'class1,class2/,package1,...'
. The files whose full package name starts with the given string
. The files whose class name starts with the given string
. If string ends with \, only the whole class name is used for compare
E.g.:
/x extra,jgui.sio.server,NativeMethods4JDK,Graphics\
-> packages extra.* and jgui.sio.server are excluded,
-> all class names starting with NativeMethods4JDK are excluded,
-> Graphics class is excluded (but GraphicsNat is included)

/i

Specify a list of package/class names whose classes will be the only


ones that will be included. The opposite of /x option.

/ll

Specify that this file will be a SuperWaba Local Extension Library.

/lg

Specify that this file will be a SuperWaba Global Extension Library.

/t

Includes any .txt file referenced in the sources into the pdb, so it can be loaded
using Vm.getFile. Note that the txt cannot be larger than 64kb

This program creates a .pdb file, used on all SuperWaba platforms.


The creator will be generated automatically from the name of the pdb file
if not overridden with the /c option.
The ! parameter is useful when you want to update the application's pdb file
from a remote server. You must use this option in both Warp and Exegen,
otherwise one file will overwrite the other.
The input file can be a Jar (in this case, all .class and media files in the
jar will be added).
Warp will automatically check any class files for dependencies and add
these files so you will only need to specify the main class file and
everything else will be added automatically, even directly referenced
media files. (ie. Image im=new Image("rob.bmp"); )
If no input files are specified, it will look for a .class file with
the same name of the pdb file you are creating.
Local extension library files (pdb and prc/dll) must be installed in the
same folder of the program; global extension library files must be installed

SuperWaba Companion

25

in the same folder of SuperWabaVM.


Examples:
java superwaba.tools.Warp c HelloApp
java superwaba.tools.Warp c HelloApp helloapp.jar
java superwaba.tools.Warp c /c SoPg Solipeg game\solipeg\Solipeg.class
java superwaba.tools.Warp c /r helloApp extra\
java superwaba.tools.Warp c /lg wextrasLib *.class extra\
java superwaba.tools.Warp c ExtGadgets superwaba/samples/ext/ui/gadgets/*.class
java superwaba.tools.Warp l helloApp.pdb

Exegen Instructions
SuperWaba Launch Executable Generator for Java Version 5.0
Copyright (C) Rob Nielsen 1999-2001. All rights reserved
Copyright (C) SuperWaba Ltda 2002-2005. All rights reserved
Usage: java superwaba.tools.Exegen [options] exefile [main-class] [pdbfile]

Options

Description

/?

Displays usage text

/$

Turns on the Palm OS copy protection attribute

/!

Removes the ! that is appended to the PDB name, putting on the PRC name

/0x

Specifies the Symbian OS creator id; otherwise it uses Palm's creator

/16

Specifies that this app can run in 16bpp screens (check the FAQ)

/C

Override and assign PDB creator (e.g. /c CrTr)

/E

Generates .exe files for Windows CE and Pocket PC

/F

Makes a full-screen application (supported on Windows CE, Symbian OS


and Pocket PC)

/I

Specifies the icon PREFIX

/INST

Create the install.exe file to install on Palm OS devices

/H

Assign height of application's main window

/L

Generates .lnk file for Windows CE / Pocket PC (can't be used in Win32)

/LNK

Generates .lnk file for Windows 98 or newer (can't be used in WinCE)

/M

Uses the Minimize button in Pocket PC instead of the Ok (close) one

/NOPRC

Does not create the Palm OS PRC file

/NOSEMAP Don't use the semaphore to increase available memory on Palm devices.
HORE
/P

Subdirectory name for the application under Windows CE

SuperWaba Companion

Options

26

Description

/SH

Creates the Linux script file to launch the sample

/SIS

Create the Symbian Install System for installing on a Symbian OS device

/T

Sets the title for the app in Windows CE and Pocket PC

/V

Assign the version for the application

/VENDOR Assign the vendor information


/W

Assign width of application's main window

/X

Assign the x window position for Win32 only

/Y

Assign the y window position for Win32 only

/Z

Creates CAB installation files to deploy your application under Windows CE

This program generates a Palm OS .prc and Windows CE application .exe files These
executables are used to launch (start up) a SuperWaba program.
If you don't specify the pdb file, its name will be the same of the exefile. If you don't
specify the [main-class], it will be the same of the exe too.
File extensions are generated automatically. For example, if you specify myapp as the
exefile, a myapp.exe and myapp.prc will be created.
A PalmOS PRC creator and PRC name will be assigned based on the pdbFile and exefile
respectively. The exefile must be 30 characters or less.
The ! parameter is useful when you want to update the application's pdb file from a
remote server. You must use this option in both Warp and Exegen, otherwise one file will
overwrite the other.
The /W and /H parameters define the default width and height of the application's window.
The value of 0 for either will cause the main window to appear at a default size which is
different on each platform.
The icons are automatically scanned, first in the current directory, next in the classpath
(including jar files). You may provide the following files: (WIDTHxHEIGHTxBPP):
icon15x9x1.bmp, icon15x9x8.bmp, icon16x16x4.bmp, icon22x22x1.bmp,
icon22x22x8.bmp, icon32x32x1.bmp, icon32x32x4.bmp, icon32x32x8.bmp,
icon48x48x8.bmp, icon30x18x1.bmp, icon30x18x8.bmp, icon44x44x1.bmp,
icon44x44x8.bmp. If you specify a prefix (E.g.: AAAA_), the searched files will be
AAAA_icon22x22x8.bmp, AAAA_icon22x22x1.bmp, etc. The 15x9, 22x22, 30x18 and
44x44 are for Palm OS (last 2 are for double density displays, E.G. Palm OS 5 and Sony
Clie), and the others for Windows CE. Note that for Palm OS you must create bitmaps
with the web-safe-palette. A gif with this palette is located under
SuperWabaSDK/samples. You can copy the icon files in
SuperWabaSDK/src/java/superwaba/tools/icons to your application's directory and edit
them. For Windows CE, the palette CANNOT BE THE WEBSAFE one. This happens
because in the Web safe palette, index 0 is white, and WinCE devices expect that index 0
will be black. A warning will be issued if you use an incorrect palette when generating the

SuperWaba Companion

27

exe files for WinCE. To correct this problem, you may use any image editor to increase
the image to 16bpp or more and then decrease it again to 256 colors and save the image.
Most editors don't use the web safe palette, which will correct the problem. Symbian OS
use the bitmaps with sizes 20x16x8 and 32x32x8.
The /Z parameter is used to create a bunch of cab files so your application can easily be
installed on all compatible Windows CE platforms. You may pass, optionally, a .swz file
with some global and local libraries used by your app. For example, if you need to install
the TinyLarge.pdb font and also a custom database, E.g. mydata.pdb, you must copy all
files to the current directory, then create a myapp.swz file with your favorite text editor with
the following contents:
[G]TinyLarge.pdb
[L]mydata.pdb
The [G] denotes a global library (fonts are always global libraries), and the [L] denotes a
local library. The user will then have two options to start the installation process:
1. Run the created xxx_install.bat file, or
2. If the cab files are available on the internet, the user may launch the browser from
inside the device, connect to the site and choose the appropriate cab file. The browser
will then download and install the file.
The /SIS parameter is analogous to /Z, but it targets the Epoc/Symbian platform. It can
also accept a .swz file to specify aditional files to be installed. The files must be specified
using a relative path: it searches in ., .., and build. The .swz file may also contain the
required S60v3 signing information that are a private key, its password and a certificate.
Add the following lines:
[PKEY]<path>/your_private.key
[PASS]your private key password
[CERT]<path>/your_certificate.cer
The /INST parameter is analogous to /SIS, but it targets the Palm OS platform. It can
accept a .swz file as the same way as specified above. An install.txt, if present, will be
used as the text to be shown during the installation.
The /SH parameter assumes that SuperWaba files are installed on
/usr/local/lib/superwaba and that the samples are installed under
/usr/local/share/superwaba/samples
The /Z parameter works only on the Windows platform. Optionally, you can also pass a
complete .inf file instead of a .swz file. See the SWCalc directory for an inf file sample for
how to create an installation that packages the SuperWaba files with your application.
The /L and the /LNK parameters cannot be used at the same time, because the file
created has the same extension (in the case both are specified, Windows CE will not be
created, and a warning will be given.
The /LNK assumes that SuperWaba VM for Win32 is installed under c:\\SuperWaba, and
the samples are installed under c:\\SuperWaba\\<exefile>.

SuperWaba Companion

28

The /T option specifies the title that will be shown in the window. The default is the class
name. Max title length = 40 chars
The /F specifies full screen in PocketPC (no title neither start button).
For the /P parameter, note that all applications must stay under '\\SuperWaba'. Spaces, /,
\\ and \ in the directory name are not alowed, except for Win32 whose full path (without
spaces!) may be specified.
NOTE: It is HIGHLY recommended that you ask the user to download the vm from
www.superwaba.org/install site, because it will always contain the last version, and your
installation may overwrite a newer vm.
The /NOSEMAPHORE disables the usage of the semaphore, a trick that allows PalmOS
devices to use more memory than the standard. In new devices, this may improve
application's stability, specially when using SIR, but your program may crash due to outof-memory errors. For instance, in an almost empty Treo 650, using the semaphore you
have about 27M of available RAM memory, while not using it you have 4.8MB. Read the
optimization tricks tutorial to learn how to minimize memory usage. A side effect of
disabling the semaphore is that the VM speed increases by 20%.
Examples:
java superwaba.tools.Exegen /I myicons_ /P Scribble scribble
java superwaba.tools.Exegen /W 160 /H 160 Calc CalcWindow calc
java superwaba.tools.Exegen /Z SWCalc.swz SWCalc
java superwaba.tools.Exegen ExtGadgets superwaba.samples.ext.ui.gadgets.ExtGadgets
Note: all examples above assume that the classpath environment variable includes
.;/SuperWabaSDK/lib/SuperWaba.jar;/SuperWabaSDK/lib/SuperWabaTools.jar

RenameFont Instructions
Usage: java superwaba.tools.RenameFont <fontpath> <oldfontname> <newfontname>
Please don't append the .pdb extension to the font names.
Note that the original files are preserved.

Wxgn Instructions
Usage: java superwaba.tools.Wxgn Warp_commands z Exegen_commands
Note that z is the separator
Lets you run Warp and Exegen together. Prc files only have to be built once, unless you
change any of the Exegen parameters (class name, creator id, etc).

SuperWaba Companion

29

Chapter 5 - Configuring build.xml to use in your own projects


There's an ANT file that can be inserted in your program's folder to call Exegen and Warp
from an IDE like Eclipse.
Get the build.xml file located under the docs/companion_samples and copy to your
application's directory. Change its properties as defined below, and follow steps 39-44
described in the tutorial Support / Configuring Eclipse, at the SuperWaba site.
The settings that must be changed to match your application's are:
Property Name

Example Value

Description

project name

ACME

your project's name

sw.root

c:/SuperWabaSDK

the place where you installed the


SuperWabaSDK

version

1.0

your application's version information, assigned


by you. This version is stored in the prc/exe
executable files

app.creator

ACme

the Creator ID (crid) of your application. The


crid is a 4-letter code that uniquely identifies
your application. Select 4 letters and register it
at http://dev.palmos.com/creatorid/

app.name

Live

your application's name, without the package


name

main.class

acme.coyote.Live

Your application's complete class name

app.title

Live

the titile that appears in Windows CE devices.


The default is main.class

app.package

acme/coyote/*.class the folders with the classes that must be


inserted in the pdb file

Note that this ant file is simply used to call Exegen and Warp (very useful to use from
Eclipse). It does not create the cab files nor the sis files. If you want to create them, just
change this line
<arg line="/L"/>
to
<arg line="/L /Z /sis"/>
These options are explained in chapter 4.

SuperWaba Companion

30

Chapter 6 - Configuring IDEs to Debug and Run SuperWaba


Programs
Below you see some ways of how to set up some famous IDEs to run and debug
SuperWaba programs as applets or applications in the desktop. After you debug it, you
can generate the necessary files with Warp/Exegen and deploy to the device.

NetBeans or Forte
Thanks to Jean Rissoto, Ed. J Szalajeski and Vince Nguyen
In NetBeans (or Forte)
Click the Tools menu, select Options and go to the Debugging and Execution folder:
Expand the folder
Select the "Execution Types" icon (looks like 2 arrows) and expand the tree.
Right Click your mouse on the root of the Execution Types, and select New.. External
Execution Name the Type ExternalSuperWaba
Right Click the ExternalSuperWaba Item just created, from the context menu select
Properties, and change the External Process to
-cp {filesystems} waba.applet.Applet /datapath . /x 10 /y 10 /scale 2 /bpp
8 {classname}

Select the Debugger Types tree.


Expand the tree
Right Click your mouse and select new Default Debugger. Name it DefaultSuperWaba
Right Click the DefaultSuperWaba just created, from the context menu select
Properties
Change the External Process Argument to
{classic}{debuggerOptions} -Djava.compiler=NONE
{q}{bootclasspathSwitch}{bootclasspath}{q} -classpath {q}{filesystems}{q}
waba.applet.Applet /datapath . /x 10 /y 10 /scale 2 /bpp 8 {main}
(please note: you are only adding waba.applet.Applet to the default)
Close the options menu,
In the filesystem Explorer
unmount all jar file netbeans add by default
mount Sun's source jar file for the rt.jar (src.jar) otherwise you will not be able to debug
mount the directory where SuperWaba classes are. This allows stepping through the
SW source code
X:\SuperwabaSDK\src
An alternative is to mount only the SuperWaba.jar file
(/SuperWabaSDK/lib/superwaba.jar), and not directly step into the SW libraries. Or
create a jar with both .java and .class files.
mount your own jar files or java files

Project settings:
Select your project's mount directory in the filesystem explorer, (the directory with your
source files)

SuperWaba Companion

31

Right Click your main class file, select properties from the context menu
Select the Execution Tab,
Change the Compiler to Internal Compilation
Change the Debugger to DefaultSuperWaba (your item created above should be in the
drop down combo box)
Change the executor to ExternalSuperWaba
The arguments can be adjusted from this property page too.
(Recommended arguments)
Arguments: /dataPath j:\\apps\\my\\donnees /x 10 /y 160 /bpp 8
/scale 2
j:\apps\my .... is the path to the datas of my app...
/x 10 /y 160 /bpp 8 /scale see explanations below at end of text.

JBuilder 6 Personal and Pro


1) Create a new project
1.a) Select the menu "File"->"New Project"
1.b) Set the Name of the project: for this example, "SWTest" will be the name of the
project:
2) Create/Add a "Lib":
2.a) Right click on SWTest.jpx
2.b) Select Paths
2.c) Select Required Libraries
2.d) Select Add -> New (1st time only)
2.e) Set Name to SWLib (for instance), then Select Add
2.f) Select superwaba.jar (SuperwabaSDK/lib/superwaba.jar)
2.g) Select your new Lib (SWLib) and select OK
2.h) you're back to the "Path" tab of the project properties window.
3) Select your Lib again and click on Edit. You will get the Configure Lib window.
4) Select Source -> Add and select your SuperwabaSDK/src/java folder
5) You can also set the "documentation" path to SuperWabaSDK/docs/html.
6) Select OK to close the Configure Lib window and the project properties
window
Now, you need to modify the following only for SuperWaba and restore it after for a
regular project.
7) Select, from the menu bar, Tools->Configure JDKs
8) Add and move to the top the following paths (in this order, from the top to the "bottom"):
8.a) SuperwabaSDK/src/java
8.b) SuperwabaSDK/lib/superwaba.jar
9) You can add the last 2 paths to the source and doc paths too by selecting the available
tabs
10) Select OK to close this Configure JDKs window.

SuperWaba Companion

32

You're done and ready to do everything you need now. The trick is that you have to
execute/debug the waba.applet.Applet class with the Name of your main window
subclass as the application parameters. Be sure to run/debug waba.applet.Applet as an
application and not as an applet:
Put a breakpoint on the first line of your onStart method and launch Debug. It will stop
where you did set your breakpoint. If you don't do that, you will debug waba.applet.Applet,
which is probably not what you want to do.

Visual Cafe (3.1)


1. menu File/New project. Choose "empty project".
2. menu Project/Options.
Project tab:
. Release type: "debug".
. Project type: "Application"
. Main class: "waba.applet.Applet
. program arguments: <your_app_name>
Directories Tab:
. Input Class Files: add in this order
. <visualCafe_directory>\java\Lib\classes.zip
. SuperwabaSDK/lib/superwaba.jar
. SuperWabaSDK/lib/SuperWabaTools.jar
. <your_project_directory>
. uncheck "Append classpath"
. uncheck "Auto-generate classpath"
. Source files: add
. SuperWabaSDK/src/java
3. press ok.
4. drag your .java project files to the project pane.
5. menu Project/Build Application
6. set your breakpoints
7. menu Project/Run in Debugger
Note: when you change the Project release type for "final", you must set
again the paths.

Linux
Thanks to Christopher C. Stump and Frank Diebolt
Establishing a SuperWaba development environment under Linux is a rather easy task.
Linux users can also use GUI environments such as Eclipse. All the tools necessary for
SuperWaba development are available in the SuperWaba SDK which can be downloaded
from www.superwaba.org. Once the package is obtained, it needs to be unzipped.
We will assume the SDK is used only by yourself, so may unzip the packagein a subfolder
of your home directory

SuperWaba Companion

33

$ unzip -d ~/<any path> SuperWabaSDK.zip


NOTE: Unzip the SDK to a standard shared folder such as /usr/local or /opt if you want
to provide the SDK to several users.
Once the SDK is deployed, you have to set several environment variables such as the
SDK root folder, the PATH for executables lookup (if you want to use the SuperWaba
helper scripts) and the Java classpath to include the java class libraries. In a multi user
environment, a personal startup script can be used for this purpose, for instance
~/.bash_profile which is a shell script executed at logon if the user's shell is Bash. You
may also temporarily define the environment variable in a shell and thus override the
value you set in your startup script.
In any case, the following must be defined somewhere on the system:
export SUPERWABA_ROOT=<fullpath to SDK>
export
CLASSPATH="$SUPERWABA_ROOT/lib/SuperWaba.jar:$SUPERWABA_ROOT/lib/S
uperWabaTools.jar:."
export PATH= $SUPERWABA_ROOT/bin:$PATH
The superwaba.jar holds the SuperWaba class files. The SuperWabaTools.jar file holds
tools that will be used during execution of Warp and Exegen. If a classpath variable is
already defined on the system, then the above path can be appended to the variable with
the same syntax. Also, note the last ':.', this is necessary to include the current working
directory in the classpath. Without this addition, compilation will fail. In order for the new
classpath variable to take effect, the shell or X window environment being worked in must
be exited and the system logged back into.
With the SuperWaba SDK in place and the classpath properly defined, one can begin
developing SuperWaba applications. We will assume the reader has already written a
SuperWaba program called MySuperWabaApp.java . In order to test/run this program
either on a Palm OS device or POSE, we must transform the .java source code into a
Palm OS executable .prc file. This can be accomplished in a few easy steps:
#Change to the directory with the SuperWaba source
$ cd {path to SuperWaba source}
#Compile source
$ javac MySuperWabaApp.java
#Run Warp on the newly created .class files
$ java superwaba.tools.Warp c MySuperWabaApp MySuperWabaApp.class
#Run Exegen on the .class files
$ java superwaba.tools.Exegen MySuperWabaApp
Warp is a java program found in {full path to SDK}/lib. Warp's purpose is to create the
.pdb files used by Palm OS applications and the .wrp files used by Windows CE devices.
We are only concerned with the .pdb file. The first argument to Warp, c, tells the program

SuperWaba Companion

34

to create a .pdb file. The second argument is the name of the to-be-created .pdb file, and
the third argument is all of the .class program files.
Exegen is a java program that can also be found in same directory as Warp. Exegen's
purpose is to create the .prc file, which is the SuperWaba program in Palm OS executable
form. The first argument to Exegen is the name of the to-be-created .prc file. The second
argument is the name of the main source code file. The third argument is the name of the
.wrp file.
If the above steps were successful, then a ready-to-use/test Palm OS application should
be in the current directory. There should be files called MySuperWabaApp.prc and
MySuperWabaApp.pdb . Both of these files, along with the SuperWaba virtual machine
files, must be installed on a Palm unit or POSE in order to run the application. The
SuperWaba virtual machine files can be found in {full path to the SDK}/ . Of course, the
above command line arguments can be tedious to type over and over again while
developing. Therefore, it is much nicer to place all of the commands in a simple shell
script, like this Bash script, so everything can be easily run in sequence with a single
command:
#Invoke shell script to handle SuperWaba app creation
[command prompt]$ ./superwaba_maker.sh
NOTE: When you start a new application or need an application skeleton for a quick test,
simply run the PERL {full path to the SDK}/bin/makeApp.pl script which generates a
minimal java source file and an Ant build.xml to compile and build the application and to
run its applet version.

Eclipse 2.1 and 3.0


Created by Guilherme Campos Hazan. For example, we will setup to debug the
UIGadgets example.
To create the project:
1. Open menu File/New/Project/Java/Java Project. Click next.
2. Choose a name for your project. (E.g.: UIGadgets)
3. Uncheck the Use default option and open the directory where the application is. (E.g.:
SuperWabaSDK/src/java/superwaba/samples/ui/UIGadgets)
4. Click next. Press yes when asking to create project now.
5. Select the Libraries panel. Click Add External Jars, and add the
SuperWabaSDK/lib/SuperWaba.jar file.
6. Click finish.
7. Right-click the project, choose Properties.
8. Select the Java Build Path page, then select the Libraries tab.
9. Click in the + near the SuperWaba.jar file to open the options.
10.Double-click the javadoc location. Select SuperWabaSDK/docs/html directory.
11.Double-click the source attachment. Select the SuperWabaSDK/src/java folder.
12.Click ok to finish.

SuperWaba Companion

35

To debug/run the project:


1. Click menu Debug/Debug... or Run/Run... and ensure that a "Java Application" is
selected in the "Configurations" box
2. Click New
3. Enter the name of the configuration. (E.g.: UIGadgets)
4. In the "Main" tab:
Project: click browse and select your project name (E.g.: UIGadgets)
Main class: type "waba.applet.Applet"
5. In the "Arguments" tab:
Program arguments: type the class name that extends waba.ui.MainWindow (E.g.:
"superwaba.samples.ui.gadgets.UIGadgets")
You may also enter, before the class name, the other possible parameters (see last
topic of this chapter)
6. Click Run / Debug.
Thats it! You're now able to debug your projects in Eclipse!

Microsoft Visual J++


1. Put SW classes in the first position in the classpath. E.g. if your classpath is
<code>SET CLASSPATH = C:\jdk1.2.2</code> now becomes <code>SET
CLASSPATH=C:\SuperWabaSDK\lib/superwaba.jar;C:\jdk1.2.2</code>
2. Open in Visual J++: File < New Project < Console Aplication
3. OK now you can start to write code.
4. To run, test and debug, go to Project &gt; &quot;app&quot; Properties... Launch TAB,
check Radio Button &quot;Custom&quot;
5. Set program: JVIEW.EXE and arguments: waba.applet.Applet &quot;ARGS&quot;
&quot;yourclass&quot; (where ARGS are the arguments to pass to SuperWaba Applet
and &quot;yourclass&quot; is the name of you main class. E.g.: waba.applet.Applet /scale
1 firstScreen)
6. Now Tab Output Format: uncheck Enable Packaging
PS (added by Fredie Oliveira): CLASSPATH environment variable is lost when J++ IDE
calls JView. This problem is reported by Microsoft in article "PRB: Environment Variables
Are Lost When Running from VJ6 IDE" (Q215413).
To solve the problem, follow all steps in SW faq and add the CLASSPATH env variable
contents in registry key: HKLM\SOFTWARE\Microsoft\Java VM\Classpath. Eg.:
HKLM\SOFTWARE\Microsoft\Java VM\Classpath =
%systemroot%\java\classes;.;c:\SuperWabaSDK\lib\superwaba.jar;c:\j2sdk1.4.1_01\lib\too
ls.jar.

General Settings
To be able to do the setup in any IDE, you must do as described:

SuperWaba Companion

36

1. Add to the classpath your project directory


2. Add to the classpath "SuperwabaSDK/lib/SuperWaba.jar" file. Maybe you'll need to
recompile the classes or remake the jar file if you're not using JDK 1.2.2, that is the jdk
used to deploy SuperWaba.
3. Set the main class as "waba.applet.Applet"
4. Set the program arguments to your class name with full package specification. For
example, to run the Welcome application as an applet, set the command line to
"waba.ui.Welcome"

Optional arguments to waba.applet.Applet


(when running it as application),
in any order and case insensitive:
. /x <x>
. /y <y>
. /w <width>
. /h <height>
. /uiStyle <WinCE_or_PalmOS>
. /bpp <bitsPerPixel_2_4_8_16>
. /scale <scale_1_to_4>
. /dataPath <path>
. /useSonyFonts
. /t title of the application window
. /cmdLine <the rest of arguments are passed to the app as the commandline>
. /crid <the desired creator id to be used>
. class name must always be the last argument
Note: The dataPath is used to set where the catalog and images are stored
Note2: In version 2.0beta4, appPath was changed to dataPath to make more
sense, but appPath is still used for backwards compatibility
If you want to emulate a Sony 320x320 device, use the following parameters:
rundemo /w 320 /h 320 /scale 1 /useSonyFonts /bpp 8
To emulate a Palm OS 5 device (like Tungsten T), use:
rundemo /w 320 /h 320 /scale 1 /bpp 8
To emulate a Windows CE or Pocket PC device with 240, 480 or 640 horizontal
resolution, use:
rundemo /w 240 /h 320 /scale 1 /bpp 8
rundemo /w 480 /h 240 /scale 1 /bpp 8
rundemo /w 640 /h 200 /scale 1 /bpp 8

SuperWaba Companion

37

Chapter 7 - Unicode Support


Unicode support is now added in version 4.1, with the help of Alsan Wong and Pierre G.
Richard, from a work started by Oliver Erdmann. Oliver created UFOLIB, a library
comprised of:
1. A tool/converter to generate font files from existing unicode font resources to a format
that can be used by SuperWaba programs
2. An engine which draws these chars on SuperWaba's graphical surface, and
3. Some widgets which use this engine to display its text.
Parts 2 and 3 were merged into SuperWaba by Alsan and Pierre (and Guich, in the native
part), but you must still perform step 1 to create fonts with glyphs that are not in the
current distribution's fonts. The currently available fonts are for Chinese, Korean and
Japanese languages, located in the UFF???12n.pdb (for high res devices) and
UFF???8n.pdb (for low res 160x160 devices). The fonts are located in the
SuperWabaSDK/lib folder.
Important: Some fonts are copyrighted. Alsan created the ones present in the SDK by
hand. Be sure that you're not infringing intellectual properties when converting fonts to bdf
and then to pdb.
For more information on how to create font pdbs, see http://jdict.sourceforge.net/ufolib/
To use them in your application, you will need to install the given font and set a control to
use it (currently, even if you don't use latin characters, you still must install the ?SW.pdb
font files into the PDAs that require them, as noted in the installation instructions in this
book). The following example shows how to use UFFChi font:
Font chiFont = new Font("UFFChi", Font.PLAIN, 12);
Button b = new Button("\u4e00a\u4e01\u4e02\u4e03");
b.setFont(chiFont);
add(b, LEFT, TOP);
Currently the font style and size parameters are not used. If the PDA has 160x160, the
VM will search for font named UFF???_L.pdb; otherwise, the UFF???_H.pdb will be used.
So, you must install the correct font file in the PDA you're targetting.
You can also make all controls use the same default font UFFChi by putting this in your
mainwindow's constructor:
MainWindow.defaultFont = new Font("UFFChi", Font.PLAIN, 12);
When reading and writing Strings in Unicode, you must change the default character
converter to UTF8, using this in the constructor (or in other place, before the read/write
operation):
waba.sys.Convert.setDefaultConverter(UTF8);

SuperWaba Companion

38

Currently there's no IME (input method) for unicode (in other words, you'll not be able to
input data in Unicode format). One will be uploaded by Alsan during end of December
2003.
Note that this is the first release with unicode support, so in the future versions many
things may change.
Please help us enhance the Unicode support, by providing new tools, fonts and more
documentation (localized docs are also welcome). Changes may be posted at
http://superwaba.sourceforge.net in the patches section.

SuperWaba Companion

39

Part II USER INTERFACE

SuperWaba Companion

40

Overview
The figure below shows the hierarchy of the classes in the waba.ui package,
followed with a brief description of each.

Button displays a text/image button.


Calculator popup used when the Edit has a CURRENCY mode and the abc/123 key
is pressed.
Calendar popup used when the Edit has a DATE mode and the abc/123 key is
pressed.
Check displays a check box with a text
ComboBox displays a drop down list.
Container a control that can contain another controls.
Control the parent class of all controls of this package.
ControlEvent encapsulates the event sent by many controls.
Edit an editable text gadget used to get the inputs from the Grafitti.
Event the parent class of all events.
Grid a powerful multiselection grid to display tabulated data.
IKeys an interface that contains all keys that are used by the SW programs.
InputDialog popup used to get a text input from the user.
Keyboard popup used when the Edit has a NORMAL mode and the abc/123 key is
pressed.
KeyEvent an event issued by the VM when a keystroke was detected in the device.
Label a read-only control that can display one or more lines of text.
ListBox a list with choices that can be selected.

SuperWaba Companion

41

MainWindow the father Window to where all events are sent; all SW programs must
have one and only one MainWindow.
MenuBar a menu bar with captions displayed at the top of the MainWindow when the
user presses the menu key or the windows title (if any).
MessageBox a Window that displays a text, arrows to scroll the text and a set of user
configurable buttons (with an Ok button as default)
PenEvent event issued by the VM when the user uses the stylus in the devices
touch-screen.
PopList displays a popup Window with a listbox inside it. Used by the ComboBox
class.
PopupMenu displays a menu when its corresponding caption is selected from the
MenuBar.
ProgressBar A bar used to track progresses.
PushButtonGroup a matrix of selectable buttons.
Radio a radio button with text associated.
RadioGroup keeps a set of attached Radio buttons synchronized; when a Radio is
selected, all the other are unselected by the RadioGroup.
ScrollBar a horizontal or vertical scroll bar
TabPanel a container with tabs. Each tab has a Container where other controls can
be added. At each tab selection, the containers are swapped.
Timer event issued by the VM when any active timer has finished its countdown.
Welcome the application that is called when the user clicks on the SuperWaba icon
at the device.
Window parent of all other windows and of MainWindow. Must be only extended by
popup windows.
NativeMethods stores the definition of all native methods used in this package; this
class must not be used directly by the user.
NativeMethods4JDK stores the implementation, using the Java Development Kit, of
all native methods used in this package; this class must not be used directly by the
user.

The NativeMethods and NativeMethods4JDK are for internal use only and will not
be described in this tutorial.

SuperWaba Companion

42

Chapter 8 Types of User Interface


SuperWaba has three look-and-feel types of user interfaces: Windows CE like,
PalmOS like and Pocket PC like. Each one can be easily selected:
1. Windows CE is the default. People that use Microsoft Windows may feel better with
it.
2. Flat. This type appears in Pocket PC models, and is basically like the Palm OS
style with rect borders instead of round borders.
3. PalmOS. Can be switched to by using Settings.setUIStyle(int type).
Here is an example of use:
public class Foo extends MainWindow
{
public Foo()
{
super("Hi bar",TAB_ONLY_BORDER);
waba.sys.Settings.setUIStyle(waba.sys.Settings.Flat);

There's another method to change the user interface style:


Settings.setUIStyle(byte style), using one of the three constants as parameter:
Settings.PalmOS, Settings.Flat, and Settings.WinCE.
The decision of which user interface to use must be made in the MainWindow
constructor. If nothing is changed, Windows CE with a bright or colored background is
used.

PalmOS looks better with a white background, WinCE looks better with bright
background.
In the figures below you can see both types, from a snapshot of the UIGadgets
program, running on the desktop emulating the device. Next to each description you find
the command line options to test the behavior. The command line below can be used with:
java waba.applet.Applet <cmd-line below> superwaba.samples.ui.gadgets.UIGadgets

(We assume that the location of the compiled UIGadgets is in the classpath)
(A) PalmOS style with white background in a 160x160 grayscale device with 4 colors.
/bpp 2 /scale 1 /uiStyle PalmOS
(B) WinCE style with bright background in a 160x160 grayscale device with 16 colors.
/bpp 4 /scale 1
(C) Flat style with 64k colors in a 176x189 Nokia phone
/bpp 16 /w 176 /h 189 /scale 1 /uiStyle Flat
(D) Flat style in a 160x160 device with 256 colors.
/bpp 8 /scale 1 /uiStyle Flat
(E) PalmOS style with white background in a 160x160 color device.
/bpp 8 /scale 1 /uiStyle PalmOS
(F) WinCE style with color background in a 160x160 color device.
/bpp 8 /scale 1

SuperWaba Companion

43

(G) WinCE style in a 320x320 device


For Sony Clie: /bpp 8 /useSonyFonts /w 320 /h 320 /scale 1
For Tungsten T (bold font): /bpp 8 /w 320 /h 320 /scale 1
(H) WinCE style in a 240x320 Windows CE device
/bpp 8 /w 240 /h 240 /scale 1

(A)

(B)

(D)

(E)

(G)

(C)

(F)

(H)

SuperWaba Companion

44

Chapter 9 The MainWindow class


Every SuperWaba program must have one and only one class that extends
waba.ui.MainWindow. MainWindow is the interface between the VM and the SuperWaba
program: it receives all events and dispatches them.

There must be only one class per application extending MainWindow. Every
SuperWaba program must have one class that extends waba.ui.MainWindow.
MainWindow is the interface between the VM and the SuperWaba program: it receives all
events and dispatches them.

You may begin your code with:


import waba.ui.*;
public class Foo extends MainWindow
{
public Foo()
{
super(Hi handheld world, TAB_ONLY_BORDER);
}
public void onStart()
{
// add controls here
}
public void onExit()
{
// close stuff, here
}
}

The VM first calls the MainWindow default constructor (in this case, the Foo())
and after that it calls the onStart method (which belongs to the Container class and can
also be used for classes that extend it). You can place all your controls in the constructor
and ignore the onStart method; or you can place them in the onStart method and
ignore the constructor. However, the latter approach is recommended because if you run
your program as an applet and you dont use this approach, the applet may not appear
correctly.

Since SuperWaba 3.4, the onStart method is implemented in waba.ui.Container.


So, you can use it in any class that extends Container and Window to setup the user
interface.
The onExit method is called when the VM exits in a normal situation, i.e., if the user
switches the applications or the programmer ends the program by using exit or exec.
However, if a fatal error occurs, the onExit method is not called.

SuperWaba Companion

45

MainWindow has a public static member called defaultFont, that is used to set
the default font used in each new control created. To change the default font to another
one, assign a new font to this member in your MainWindow constructor.
Other important methods in this class are:

exit(int exitCode): exits the program, calling onExit before. Good to be put
in a Quit menu item.
addTimer(Control target, int millis): adds a timer. The Timer event
will be issued to the target every millis milliseconds.
removeTimer(Timer timer): removes the given timer from the timers queue.
getCommandLine(): if this process was executed by another process (e.g.: using
the waba.sys.Vm.exec method), this method gets the command line passed.
when you click on the application icon, theres no command line.
addThread(Thread t, boolean highPriority): adds, to the VMs thread
queue, the given thread. High priority threads have the same priority as system
events; so, no event is issued while those threads are running.
threads in SuperWaba are non-preemptive, behaving like the ones in Windows
98.
removeThread(Thread t): removes the given thread from the VMs thread
queue.
getMainWindow(): returns the instance of the current MainWindow. You can use
it to get access to methods of the MainWindow class from outside the class. Is it
also possible to cast the returned class to the class that is extending MainWindow
(this is a normal Java behaviour). So, if UiGadgets is running, it is correct to do:
UIGadgets instance = (UIGadgets)MainWindow.getMainWindow();

SuperWaba Companion

46

Chapter 10 Adding Controls


Now that we created a beautiful empty MainWindow with a title and a border, let's
add some controls to it. We will do this by taking a close look at the waba.ui.Control class.
Controls are painted when the VM calls the controls onPaint method. The events
are handled when the VM calls the controls onEvent method passing the event that
occurred.
Controls are always added to a Container, or to any descendent of it, like the
Window and the TabPanel classes. This container is called the parent of the control. To
set the control bounds in the container, you must use the method setRect(x,y,
width,height).

The coordinates are always relative to the parents coordinates. This is easy to
understand, as this document has a relative position to the PDF viewer window, not to
your screen monitor.

Starting on version 5.5, the controls can be traversed using the 5-way navigation
present on most PDAs. and Smartphones. It is automatically activated on penless devices
(such most Smartphones), but can be activated on pen devices by making
Settings.keyboardFocusTraversable=true. The order of the traversal is defined
by the order of the elements in the Container.tabOrder member. The controls are added
to the vector in the order as they are added to the container. This may not be optimal; you
may assign a new order by adding the controls to the vector as this.tabOrder = new
Vector(new Object[]{ed1,btn1,btn2,ed2});
SuperWaba lets you place controls in two ways:
1. The hard way, by setting the x,y,width,height with numbers. E.g.:
control.setRect(10,10,80,12).
2. The smart way, by using constants for relative coordinates. The constants allowed
are:

Coordinate X
o LEFT: place the control at the position 0 horizontal. If the parent is a
Window, align the control at the left of the windows client rect.
o RIGHT: align the control at the right. If the parent is a Window, align the
control at the right of the windows client rect.
o CENTER: center horizontally the control in the container.
o BEFORE: place the control before the last one added.
o AFTER: place the control after the last one added.
o SAME: place the control at the same x coordinate of the last one added.
Coordinate Y
o TOP: place the control at position 0 vertical. If the parent is a Window,
align the control at the top of the windows client rect.

SuperWaba Companion

47

o BOTTOM: place the control at the bottom of the container. If the parent is
a Window, align the control at the bottom of the windows client rect.
o CENTER: center vertically the control in the container.
o BEFORE: place the control before the last one added.
o AFTER: place the control after the last one added.
o SAME: place the control at the same y coordinate of the last one added.
Width
o PREFERRED: lets the control determine its best width. This is normally
computed using the controls text width in the selected font.
o FILL: the controls width will fill the space left until the end of the
container. Cannot be used with RIGHT/CENTER.
o SAME: set the control's width with the same width of the last control
added.
o FIT: set the control's width to fit between the specified x position and the
last control added x position. For example, if you place a Label at LEFT,
a Button at RIGHT and want to place an Edit between those two controls,
use FIT as the control's width using the Label as relative control.
Height
o PREFERRED: lets the control determine its best height. This is normally
computed using the controls text height in the selected font.
o FILL: the controls height will fill the space left until the end of the
container. Cannot be used with BOTTOM/CENTER.
o SAME: set the control's height with the same height of the last control
added.
o FIT: set the control's height to fit between the specified y position and
the last control added y position. For example, if you place a Button at
TOP, a Label at BOTTOM, and want to place a ListBox between both, use
FIT as the control's height using the Button as relative control.

If you use LEFT/TOP/RIGHT/BOTTOM with the first control added to a Window, it will
use the coordinates of the Windows client rect, which are the Window area excluding the
title and the borders, if any.
You may not use FIT in both width/height. It won't work as expected because you can't
specify two controls to make it relative to. The width/height is always related to the last
control added. FIT is used by many samples; search for them in the
SuperWabaSDK/src/java/superwaba/samples folder.

Before calling setRect, the control must be added to the container and have its
characteristics (like font, border type, etc) set. This is needed because the control
position is computed based on its parent container and the control's size is computed
based on its characteristics.

The constants described above have one important feature: a variable or a number
can be used to increment/decrement the result value. Examples: CENTER+2, BOTTOM-5,
PREFERRED+4, FILL+2, BEFORE-5. Note that by using anything above 5 will make your
code appear wrong in other resolutions.

SuperWaba Companion

48

The use of relative positioning is highly recommended. Its use makes the program
portable between different resolutions and fonts. As a practical example, see the figures
E and F/G of UIGadgets in chapter 2. Because relative positioning was used, the controls
were correctly arranged in all resolutions.
Here are the methods related to gadgets placement in the Control class:
1. setRect(int x, int y, int width, int height): sets the control
bounds with the given parameters. If relative coordinates are used, they will be
relative to the last added control.
2. setRect(Rect r): same as setRect(r.x, r.y, r.width, r.height)
3. setRect(int x, int y, int width, int height, Control
relative): same if 1, but relative coordinates will be relative to the given
control instead of the last one added.
The Container class also has some handy methods to set the controls bounds:
1. add(Control control, int x, int y): same of add(control);
control.setRect(x, y, PREFERRED, PREFERRED);
2. add(Control control, int x, int y, Control relative): same of
add(control); control.setRect(x, y, PREFERRED, PREFERRED,
relative);

The last two methods are good when youre adding controls that do not need to have
any of its characteristics (like font and border) changed. If you change the characteristics
after calling those methods, you'll get strange results, because the control does not
reposition/resizes itself when you change a characteristic (just as an example, suppose
that the default font has 11 in height, and you add the control; then you change the font to
one with height 22; the control will not be resized and you'll see only half of the text).
Below are some examples of how to use the relative constants:
add(new
add(new
add(new
add(new
add(new

Label("1"),
Label("2"),
Label("3"),
Label("4"),
Label("5"),

CENTER, CENTER);
AFTER, SAME);
SAME, AFTER);
BEFORE, SAME);
BEFORE, BEFORE);

You will see this on screen:


512
43
These are taken from the waba.ui.Welcome class:
Label l = new Label("SuperWaba Virtual Machine");
l.setInvert(true);
// font must be set before the setRect method is called.
l.setFont(new Font("SW",Font.BOLD,14));
add(l,CENTER,TOP+15);
add(new Label("Version "+Settings.versionStr+" for " + Settings.platform),
CENTER,AFTER+3);
add(new Label("Virtual Machine installed and ready"), CENTER,AFTER+17);

SuperWaba Companion

49

Other important public methods in the Control class

addTimer(int millis): calls MainWindow addTimer method to add


a timer whose target is this control.
removeTimer(Timer timer): calls MainWindow removeTimer to
remove a timer associated with this control.
getSize(): returns the controls width,height.
getPos(): returns the controls x,y
getParentWindow(): returns the parent window of this control. This is
needed because the controls parent may be a Container, whose parent
may be another container, and so on.
repaintNow(): creates a Graphics for this control and calls onPaint.
Its action depends on the type of the control being repainted:
o If the control is a Window, calls repaint to mark all controls
to be repainted. This is useful when you remove a control
from a Window and want to update the whole window.
o If the control is a Container, calls onPaint on the
Container and in all its children.
o Otherwise, just call the controls onPaint.
repaint(): Marks the control for repaint. When you call repaint, the
absolute area of the control regarding its parent Window is invalidated
(marked for repaint); then, the next time an event (a keypress, a timer, a
pen event) occurs, the screen is updated. If you call repaint and the
control isn't effectively repainted, you have 2 choices: call
Window._doPaint(), or, use the Control.repaintNow method.
setEnabled(boolean enabled): Enable/disable the control to
receive events. The controls appearance is also changed to reflect the
state.
isDisplayed(): return true if the parent of this Control is added
somewhere. Some containers, like the TabPanel, have n child
containers, but only one is added at a time. With this method, you can
discover if your container is the one available.
requestFocus(): set the focus to this control.
setFocusLess(): this method makes the current control a control that
will never steal focus from other controls. It makes it very easy to create
keypads with PushButtonGroup to enter characters into Edit controls, for
example
setBackForeColors(Color back, Color fore): set background
and foreground colors at once.

repaintNow has a pitfall if the control is not a Window. If the controls parent Window
uses an offscreen image for double buffering (by calling setDoubleBuffer(true)), the
offscreen image is not updated. So, if the parent Window is a popup window with double
buffering and the user moves it, the updates you painted under the repaintNow will be
lost. There are no problems if the popup Window does not use double buffering but if it
does use double buffering and you call repaint instead of repaintNow. Double buffer
is an important feature; but be sure to test it.

SuperWaba Companion

50

SDL platforms (Epoc, Windows 98/2K/XP and Windows CE) always use offscreen
windows, so calling the setDoubleBuffer method is useless. This method will be
deprecated and removed in the future.
Here are some useful members in the Control class

FontMetrics fm : the FontMetrics object created from the controls assigned


Font. Always recreated when the font changes.
int fmH : Because this is widely used, contains the value returned by
fm.height.
int appId : a public variable that can be assigned by the application with any
value. For example, the Keyboard class uses this to store the PushButtonGroup
index and discover which one of the five had issued the event.
x2, y2 : same of x+width-1 and y+height-1.

getForeColor() and getBackColor() returns the color depending if the controls


state is enabled or disabled.
There are also some protected methods that you can implement if you're creating a
new control or extending the Window or Container classes:

onPaint(Graphics g): this is the method called when the control is going to
be painted. You can use the given Graphics object to draw what you need on
screen. The default's control font is already set, and the clipping is also set to the
control's bounds.
onBoundsChanged: called after the user invoked the setRect method. Good to
compute positions that are dependant on the bounds.
onColorsChanged(boolean colorsChanged): Called after a setEnabled,
setForeColor and setBackColor methods were called and when a control has
been added to a Container. If colorsChanged is true, it was called from
setForeColor/setBackColor/Container.add; otherwise, it was called from
setEnabled
onWindowPaintFinished: every time the _doPaint finishes paintings all
controls, this method is called. You can then do actions needed after the screen
has finished the paint. Note that this method is only called on controls that
extends Window and on the focused control.
onFontChanged: called after the setFont method is invoked.

SuperWaba Companion

51

Chapter 11 Events
We have learned how to create a main window and add controls to it. Now we need
to learn how to handle user and system interactions with the controls.
Each user interaction generates an event. Events are bundled in 3 classes:
KeyEvent, PenEvent and ControlEvent. The event is specified in the type class
member.

The event model of SuperWaba is almost identical to the one used in JDK 1.0.
There are two basic types of events: pen events and key events. Below we see
how each event is handled by the Window and forwarded to the target control:
1. The user types a key on the device. The VM intercepts the key and sends it to the
Window, which in turn creates a KeyEvent with type KEY_PRESS, the key code, and
then forwards the event to the control that currently owns the focus.
2. The user presses the touchscreen of the handheld, generating a point with x,y
coordinates. The VM sends the event to the Window; the Window searches for the control
whose bounds contain the point; it then converts the point to the controls local
coordinates, and dispatches a PenEvent with type PEN_DOWN and with the x,y
coordinates to the control. When the user releases the touchscreen a PEN_UP event is
generated as described for the PEN_DOWN. The other two possible pen events are
PEN_MOVE and PEN_DRAGGED.

PEN_MOVE events are not generated in PalmOS, only in WindowsCE and in the applet.
The two events above are handled by the controls, which may convert them to
other events, defined in the ControlEvent class. Below we see how and who generates
each of the events defined in that class:
1. PRESSED: this event is posted by controls when they receive a PEN_DOWN (like
Check, Radio, TabPanel), a PEN_UP (Button, ListBox, PushButtonGroup, ScrollBar) or
even a WINDOW_CLOSED (ComboBox).
2. FOCUS_IN and FOCUS_OUT: posted by the Window when a control different from the
current one is clicked. The FOCUS_OUT is first posted to the old control, and the event
FOCUS_IN is then posted to the new control to inform it that it is receiving focus.
3. TIMER: this is a special event that is posted to the control that has assigned a timer; it
is called when the timer countdown has reached zero.
4. WINDOW_CLOSED: called from the unpop method to notify all controls that a window
has been closed. Some controls, like the ComboBox, has a PopList assigned to it; when
the PopList issues a WINDOW_CLOSED event, the ComboBox receives it and converts to
a PRESSED event.
5. WINDOW_MOVED: issued when a window has just been moved (popup windows in
SuperWaba can be moved around the screen by dragging the windows title). The event
is broadcasted to all controls inside the window; most controls use this event to reinitialize
or translate an instantiated waba.fx.Graphics object.

SuperWaba Companion

52

If your control creates a Graphics object at initialization time, it must recreate when it
receives a WINDOW_MOVED event, otherwise it will paint things in an invalid place or even
nothing may be painted.
Now that we have all events described, lets see how to use them.
A control posts an event using the postEvent method. This method posts the
event to the control and to all of its parents. So, if we have a Button inside a TabPanel in
the Window, the event is propagated as follows:
Window.onEvent
TabPanel.onEvent
Container.onEvent
Button.onEvent

postEvent returns immediately if the control is not enabled.


Theres a way to break the event propagation: just set the Event.consumed member
to true.
If the control is moved to another container, the event propagation stops. For example,
when you pop up the Keyboard, the target Edit is removed from its parent and added to
the Keyboard window; at this time, the event propagation (of the KeyEvent) stops.
The MainWindow does not receive an event posted by a control in a popup window.
The only exception for this is the WINDOW_CLOSED, that is posted to the window that
popped it.
A control that is not added to a Container (or any parent of its Container is not added
to a Window) will never receive events nor be repainted.
Most SuperWaba programs handle the events by implementing the onEvent
method in the MainWindow class; it works for small programs, but the program can look
messy if the program gets big. An alternative is to create classes that extend Container,
adding one at a time to the window, and implement the onEvent method to handle the
events there.
Below we see an example of the onEvent method of class waba.ui.Welcome.
public void onEvent(Event e)
{
switch (e.type)
{
case KeyEvent.KEY_PRESS:
if (((KeyEvent)e).key == IKeys.LAUNCH)
popupMenuBar(); // make sure the user saw the menu
break;
case ControlEvent.WINDOW_CLOSED:
if (e.target == mbar)
switch (mbar.getSelectedMenuItem())
{
case -1: ...
break;
case
3: exit(0); break; // Exit
case 101: ...
break; // About
}

SuperWaba Companion

53

break;
}
}

Use a switch(event.type) instead of a lot of if-else; this make the code


cleaner.
Let's now look at the details of each Event class. As already described,
SuperWaba has four classes in the waba.ui package: ControlEvent, PenEvent,
KeyEvent and the parent of all, Event.
The Event class has some useful members:

type: this is the event number, used to detect which event was posted.
target: this one informs who is receiving the event (E.g.: the VM posts a
PenEvent.PEN_DOWN to a control) or who is posting it (E.g.: the Control posts an
ControlEvent.PRESSED).
timeStamp: contains the time stamp at which the event was created.
consumed: when set to true during the event propagation, breaks the propagation
chain.

Be careful with the timeStamp. There is no way to convert it to the current


hh:mm:ss:millis. It is just useful for comparison purposes; or to compute the time elapsed
since the last event occurred. You can use it to simulate a double-click, by checking the
elapsed time between two clicks
To keep memory usage low, some VM routines reuse PenEvents and KeyEvents
objects; so, if you just save a reference to the object instead of the timestamp itself, you
may get unexpected results.
The Event class also has a static method called getNextAvailableEventId.
This method is used to avoid conflicts when your application or library creates a new
Event type. It is discussed in more details in PART V of this book.
The PenEvent has three members: x,y and modifiers. The coordinates are
stored in the x,y; the modifiers are not used in the PalmOS platform, only in the other
platforms.
The KeyEvent has also two members: key and modifiers. The key can assume
values from the ASCII table and special ones defined in the waba.ui.Ikeys interface;
the modifiers are not used in PalmOS, only on WindowsCE.
Some of the Keys defined in waba.ui.IKeys need a special code to be manipulated:
they are not handled by the application unless the app requests it. For example, the
IKeys.UP and IKeys.DOWN are automatically sent to the application's event queue, but
the IKeys.KEYBOARD_* and IKeys.HARD* not. To be able to intercept these keys, you
must use the method waba.sys.Vm.interceptSystemKeys(mask). Please read the
javadocs of this method for more information, and take a look at the samples provided in
the SDK (search for interceptSystemKeys in the samples folder).

SuperWaba Companion

54

Here were ending our Events chapter. In the next chapters, we will see in more
detail all user interface gadgets available in the waba.ui package.

SuperWaba Companion

55

Chapter 12 Basic Controls


In this chapter we will learn the details of all basic controls in the package waba.ui:
Button, Check, ComboBox, Edit, Label, ListBox, PopList, ProgressBar, Radio and
ScrollBar.
Each control can have its font, foreground and background colors set, and the state
(enabled/disabled). Most controls have a different look depending of which look and feel
(PalmOS or WinCE) is set.
For each control well see its characteristics, how they compute the preferred size
(used when you set the bounds with the PREFERRED constant in the width and height
parameters), how to create them with the provided constructors, and the useful events
that they send.

waba.ui.Button
Buttons are the most used types of controls. They are used to invoke an action or
to confirm something, like <ok> or <cancel>. Here are some characteristics of SuperWaba
buttons:

Can be text-only or image-only.


They have three border styles: none, simple or 3d.

If you create an image button and call setText, the button is transformed to a text-only
button.
The preferred size is computed as below:
text height / image height
gap
text width / image width
gap
In this figure, the red rectangle is the buttons text or image; the black rectangle is
the buttons border, if any. The text width/height are computed using the FontMetrics of
the current controls font (if it is a text button) or by getting the width/height of the image (if
it is an image button). The gap is set using the setGap method or the commonGap
member.

Thats why you must set the characteristics of controls before calling setRect to set
their bounds.

SuperWaba Companion

56

There is an easy way of setting the gap of multiple buttons: use the static int
commonGap member. For example, you set Button.commonGap=2, add all the buttons
that will have this common gap, and then reset it to zero.
Here are some examples of how to construct buttons, taken from the
ButtonExample:
Button btn1 = new Button("Border none enabled");
btn1.setBorder(Button.BORDER_NONE);
add(btn1,LEFT,TOP);
Button btn2 = new Button("Border simple enabled");
btn2.setBorder(Button.BORDER_SIMPLE);
add(btn2,LEFT,AFTER+5);
Button btn3 = new Button("Border 3d enabled");
btn3.setGap(1);
add(btn3,LEFT,AFTER+5);
Button btn4 = new Button("Border none disabled");
btn4.setBorder(Button.BORDER_NONE);
add(btn4,LEFT,AFTER+10);
btn4.setEnabled(false);
Button btn5 = new Button("Border simple disabled");
btn5.setBorder(Button.BORDER_SIMPLE);
add(btn5,LEFT,AFTER+5);
btn5.setEnabled(false);
Button btn6 = new Button("Border 3d disabled");
btn6.setGap(1);
add(btn6,LEFT,AFTER+5);
btn6.setEnabled(false);
Button.commonGap = 2;
String imgName = "Diskette.bmp";
Button btn7 = new Button(new Image(imgName));
add(btn7,LEFT,AFTER+10);
Button btn8 = new Button(new Image(imgName));
add(btn8,AFTER+10,SAME);
btn8.setEnabled(false);
Button.commonGap = 0;

The following picture shows the output of the code above in both user interface
styles:

WindowsCE

PalmOS

SuperWaba Companion

57

Every time a Button is pressed, it posts a ControlEvent.PRESSED event to the


parent container. Below is an example of how to handle this event:
public void onEvent(Event event)
{
switch (event.type)
{
case ControlEvent.PRESSED:
if (event.target == btn1)
new MessageBox("HI","Michelle").popupModal();
break;
}
}

You can simulate the button being pressed by calling the method press and passing
true as parameter.

The Button class has a handy static method called createArrowButton, used to
create a Button with an arrow image. For more details on the arguments, see
Graphics.drawArrow.
Images are not controls, they can't be added to a container. The Button class can
be used to add an Image to the screen, removing the border and not acting on an event.
To make the button behave like this, construct it with an image and call the
onlyShowImage method.

You can change the color used when the button is pressed (useful when the UI is in
PalmOS style) using the setPressedColor method.

waba.ui.Check
Check box is a control that have a rectangle with a check inside and a text at right,
and are used for items that have an on/off state.
The preferred size is computed as below:
Text height + 0/2
4
14/16

Text width

In this figure, the red rectangle is the checkbox text. The check box width (green) and the
controls height (blue) depends on the user interface style (first number is for PalmOS and
2nd number is for WinCE)

The Check's text will be always right justified in the control's width.
Below we see an example code of how to create a Check in SuperWaba, taken
from the CheckExample.java file:
chk1 = new Check("Checked enabled");

SuperWaba Companion

58

add(chk1,LEFT,TOP+5);
chk1.setChecked(true);
Check chk2 = new Check("Unchecked enabled");
add(chk2,LEFT,AFTER+5);
Check chk3 = new Check("Check disabled");
add(chk3,LEFT,AFTER+5);
chk3.setChecked(true);
chk3.setEnabled(false);

And the code output:

WindowsCE

PalmOS

As the Button control, the only event that the Check control posts is the
ControlEvent.PRESSED. Below we see an example of how to handle a click on the
checkbox:
public void onEvent(Event event)
{
switch (event.type)
{
case ControlEvent.PRESSED:
if (event.target == chk1)
{
String state = chk1.getChecked()?"checked":"unchecked";
new MessageBox("SuperWaba", "Checkbox "+state).popupModal();
}
break;
}
}

waba.ui.ComboBox
ComboBox is a very useful control to display a list of items where only one can be
selected. It consists of a text with a button and a PopList control that is popped up when
the button is pressed. Then the user selects one item and the PopList window closes.
The PopList is placed depending on the user interface style: if using PalmOS, the
poplist is placed covering the control. Otherwise, if WinCE, it is placed below the control.
The PopList height also depends on the control's position: it will open in the direction that
has the most space left (above or below). If you set the public member fullHeight to
true, then it will have the same height as the screen, maximizing the number of items
displayed. In the same way, the fullWidth will set the width to the screen's one.

SuperWaba Companion

59

There's a way to change the ComboBox's ScrollBar default width: you must play with
the Button.commonGap, which is a static member from the Button class (see chapter 6,
waba.ui.Button), and the extraArrowSize, which is a static member from the
ComboBox class. The Button.commonGap increases the size of the button inside the
ComboBox's ScrollBar, and the ComboBox.extraArrowSize increases the size of the
arrow drawn inside the button. After the ComboBox creation, you must reset both to 0,
otherwise they will affect all future ComboBoxes and Buttons created.
Its preferred size is computed as below:
Text height + 4
PopList preferred width*
* This is the width of the largest item plus the width of the ScrollBar.
In this figure, the red rectangle represents the control.
The ComboBox has three types of constructors:
1. ComboBox(Object []items): This one is the most used. You can pass a String
array as the items.
2. ComboBox(ListBox userListBox): This is used when you want to display a
user-defined ListBox as the Popup window.
3. ComboBox(PopList userPopList): This is used when you want to display a
user-defined PopList. Set the userListBox like this: new
PopList(userListBox)
4. ComboBox(): The default constructor creates an empty ComboBox.

The ComboBox has a very useful method that does a sort of the items: qsort().
It is possible to make a ListBox scroll horizontally (see waba.ui.ListBox). To be able
to scroll the ListBox associated with this ComboBox, two methods are provided:
setOffset and getNeededHorizontalScrollValue.
Below we see an example code, taken from the ComboBoxExample.java file:
String []items1 = {"","Orange","Apple","Grape","Lemon"};
String []items2 = {"One","Two","Three", ...};
String []items3 = {"Disabled","Enabled"};
cb1 = new ComboBox(items1);
add(cb1,LEFT,TOP+5);
ComboBox cb2 = new ComboBox();
cb2.add(items2);
cb2.add("Twenty one");
add(cb2,RIGHT,AFTER+5);

SuperWaba Companion

60

ComboBox cb3 = new ComboBox(items3);


add(cb3);
cb3.setRect(LEFT,BOTTOM,PREFERRED+10,PREFERRED);
cb3.select(0);
cb3.setEnabled(false);

And the code output:

Windows CE

PalmOS

As the preceding controls, this one also posts a ControlEvent.PRESSED when


the user selects an item.
public void onEvent(Event event)
{
switch (event.type)
{
case ControlEvent.PRESSED:
if (event.target == cb1)
new MessageBox("SuperWaba","Item selected: " +
cb1.getSelectedItem()).popupModal();
break;
}
}

waba.ui.Edit
Edit is a control used to get text input when the user type keystrokes in the grafitti
area. It allows you to select text and cut/copy/paste it. Here are some other features:

There are two constructors: the default (with no arguments) that creates an Edit
with no constraints, and one constructor that receives a mask string. The mask is
used only to compute the preferred width. Maybe in the future it will be used for
other purposes.
If you pass an empty mask , the width will be set to FILL.
You can limit the maximum length of characters that can be entered, by using the
setMaxLength method. If the user tries to enter text above the limit, a beep is
sounded and the text is ignored. If you set a text greater than the max length, it will
be truncated.
You can also set the valid characters that can be entered by using the
setValidChars method. There are some predefined character sets that can be
localized if necessary:
o numbersSet = "0123456789"

SuperWaba Companion

61

o currencyCharsSet = "0123456789.+-"
o dateSet = numbersSet + Settings.dateSeparator
Those character sets are used in the setMode method. In this method you can use
one of the following constants:
o NORMAL : in this mode any character can be entered, and when pressing the
abc/123 keys the waba.ui.Keyboard is popped up.
o DATE: this mode uses the dateSet and the waba.ui.Calendar is the one
popped up.
o CURRENCY: the currencyCharsSet is used and the
waba.ui.Calculator is the one popped up.
o PASSWORD: any character can be entered and the waba.ui.Keyboard is
the one popped up. Only the last character typed is displayed in this mode,
all the others are replaced by an asterisk (*).
o PASSWORD_ALL: same of PASSWORD except that all characters are replaced
by an asterisk (*), including the last one.
The edit can be set as read-only by directly setting the editable member. By
setting the member hasCursorWhenNotEditable to false the cursor will not
appear when not editable.
There's a public member named overwrite which, if set to true, turns off insert
mode (ie, characters will be replaced if written over).
The member alignment lets you control the alignment of the text inside the Edit
after it looses the focus. This means that, when it has focus, it is always leftaligned, but when it looses, it may align the text to the right.
You can invoke the default popup keyboard for the edit using the popupKCC
method (KCC = Keyboard, Calculator and Calendar).
You may specify which keyboard will be popped up, overriding the default
behaviour, using the setKeyboard method, passing the constants KBD_NONE,
KBD_DEFAULT, KBD_KEYBOARD, KBD_CALCULATOR, KBD_CALENDAR.
You may force all characters entered to be automatically converted to upper or to
lower case using the method setCapitaliseMode and giving the parameters
ALL_NORMAL, ALL_UPPER and ALL_LOWER.
The member autoSelect makes the Edit automatically select the text when it
receives the focus. This is always true for penless devices.
There is a multiline Edit available in: superwaba.ext.xplat.ui.MultiEdit.
The method setCursorPos(start, end) can be used to set the selected text
of the Edit (if start != end). It can be used to set the cursor position, if start equals
end. Start must be less or equal to end, and both must be >= 0. It can also be used
to clear the selectedText, calling <code>setCursorPos(-1,0)</code>. Note: if you're
setting the cursor position before the edit is drawn for the first time, the edit will not
be scrolled if the end position goes beyond the limits. Important! No bound
checking is made. Be sure to not call this method with invalid positions!
The method getCursorPos returns an int array with the start (array index 0) and
end (array index 1) positions of the cursor. It can be used to find the selected text,
which will be the substring(start,end).
Here is how the preferred size is computed:

SuperWaba Companion

62

Text height
(plus 4 if WinCE)
if mask is null, ScreenWidth/4.
If the mask is , use the FILL,
otherwise it is the masks width;
both cases plus (4 if PalmOS, 10 if WinCE)
Below we see an example code, taken from the EditExample.java file:
ed1 = new Edit();
add(ed1);
ed1.setRect(LEFT,TOP+5,80,PREFERRED);
Edit ed2 = new Edit("9999.99");
ed2.setMode(Edit.CURRENCY);
add(ed2,LEFT,AFTER+5);
Edit ed3 = new Edit("99/99/9999");
ed3.setMode(Edit.DATE);
add(ed3,LEFT,AFTER+5);
Edit ed4 = new Edit("AAAAA");
ed4.setMode(Edit.PASSWORD);
add(ed4,LEFT,AFTER+5);
Edit ed5 = new Edit();
ed5.setMaxLength(4);
ed5.setValidChars("123ABC");
add(ed5);
ed5.setRect(LEFT,AFTER+5,40,PREFERRED);
String txt = "Can't Edit";
Edit ed6 = new Edit(txt);
ed6.setEditable(false);
ed6.setText(txt);
add(ed6,LEFT,AFTER+5);

And the code output:

Windows CE

PalmOS

The Edit control does not post any event, but you may intercept the
ControlEvent.FOCUS_OUT to validate the edits text.

SuperWaba Companion

63

waba.ui.Label
This control is used to display static text. The Label in SuperWaba can also display
multiple lines of text, separated by the character |. Here are some other features:

Label has two constructors: one with a text (that may be changed at runtime) and
one with text and an alignment parameter. The alignment can be LEFT, CENTER
and RIGHT. The text is used to compute the preferred size. If you pass an empty
string as text, the preferred width will be FILL. You can set/change the label's
alignment accessing the public member align.
You can call the set3d method to make the label have a 3d look, by drawing it with
the foreground color and with a color a little brighter than the background color.
Labels can look inverted, by swapping the background and the foreground colors.
To do this, use the setInvert method.
If the Label is a multiline one, you can use the method scroll(boolean down)
to make it scroll up and down, and also the canScroll(boolean down) method
to peek if it can be scrolled in the desired direction. To see a good usage example
of this feature, see the waba.ui.MessageBox class.
In the WinCE user interface style, a Label doesn't have the same height of an Edit.
You can adjust this setting the commonVGap public static attribute to 4. It makes
easier to vertical align Labels with Edits.

The three align constants are inherited from the waba.ui.Control class, where they are
used in the setRect method. Furthermore, you can use new Label(my
text,Label.CENTER) or new Label(my text, CENTER); it will work in the same
way.
Labels cant be inverted and 3d at the same time. Calling set3d cancels
setInverted and vice-versa.
The setText method, used to change the labels text, does not change the controls
bounds. You must be sure that the label has enough size to hold the text otherwise it will
be clipped.
Theres a handy method in the waba.sys.Convert class called
insertLineBreak(int maxWidth, char separator, waba.fx.FontMetrics
fm, String text). It is used to parse the text that will be used in the mutiline Label.
The string is not parsed automatically at runtime because this is a slow operation. You
may use it sending the resulting String to the console and pasting the result into your
code. Here is a usage example:
waba.sys.Convert.insertLineBreak(Settings.screenWidth6,'|',getFontMetrics(getFont()),"This is a very long text and i
dont want to waste my time parsing it to be fit in the
MessageBox!"). Note that Settings.screenWidth-6 is the maximum alowed width
to make the text fit in a MessageBox (where the multi line label is used); by using this
value, it may work correctly in other screen resolutions because the font is proportional to
it.
Below we can see how the preferred size is computed:

SuperWaba Companion

64

number of lines * text height


If inverted, add 1
Loop through all lines and
compute the maximum text
width. If inverted, add 2
Here is an example of code for the Label class, taken from the LabelExample.java
file:
add(new Label("This is a simple label"),LEFT,TOP+5);
Label lab1 = new Label("This is a centered label", Label.CENTER);
add(lab1);
lab1.setRect(LEFT,AFTER+5,FILL,PREFERRED);
Label lab2 = new Label("This is another centered label", CENTER);
add(lab2);
lab2.setRect(LEFT,AFTER+5,FILL,PREFERRED);
Label lab3 = new Label("Wow! A wonderful 3D label!");
lab3.set3d(true);
add(lab3,LEFT,AFTER+5);
Label lab4 = new Label("A beautiful inverted label");
lab4.setInvert(true);
add(lab4,LEFT,AFTER+5);
FontMetrics fmLab5 = getFontMetrics(getFont());
/*waba.applet.Handy.boundText(80,'|',fmLab5,"This is a very long text and i dont
want to waste my time parsing it to be fit in the MessageBox!"); */
Label lab5 = new Label("This is a very long|text and i dont|want to waste my|
time parsing it to|be fit in the|MessageBox!");
add(lab5);
lab5.setRect(CENTER,AFTER+5,80,fmLab5.getHeight()*5);

And here is the code output. The output is the same in both WinCE and PalmOS:

Windows CE and PalmOS


The Label control does not post events.

waba.ui.ListBox

SuperWaba Companion

65

The ListBox control looks like an opened ComboBox (in fact, the ComboBox uses
the ListBox control). You may use the ListBox instead of the ComboBox if the screen has
more space available. Below are some features of ListBox:

ListBox has two constructors: the default that creates a ListBox with no items and
another that accepts an object array with the items.
Items may be added or deleted at runtime, with the following methods: add,
remove, setItemAt, getItemAt, getSelectedItem, getSelectedIndex,
indexOf, select(int item), select(object) and size.
The setSimpleBorder method is used to change the border style from 3d to
simple.
If the ListBox owns the focus and you type a letter, the first item with the typed
letter is selected. Typying again selects the next item, and so on.
The up/down keys can be used to scroll the ListBox.
You may use the method qsort to sort the items in the ListBox.
ListBox can be horizontally scrolled. Although this is not implemented by the
control, it has two methods that can aid you on this task: setOffset and
getNeededHorizontalScrollValue. The first one sets the offset from where
the text is drawn (negative values makes the text flow to left, positive values to the
right). The second one determines the maximum number of pixels that can be
scrolled. See superwaba.ext.xplat.unit.SWUnit for an example on how to use
these methods.
By default, the selection is drawn using the current item's width. This behaviour can
be changed by setting useFullWidthOnSelection to true.
You can extend ListBox to implement a customized type, like a color-chooser
ListBox (see superwaba.ext.xplat.ui.ColorList). If doing so, the following methods
must be overridden:
protected void drawItem(Graphics g, int index,
int dx, int dy)
protected int getItemWidth(int index)
Below you see how the preferred size is computed:

gap

Loop through all lines and


compute the maximum text
width.

(max between number of


items * text height and
scrollbar preferred height)
+ gap
ScrollBar
preferred
width

The gap depends on the border type: if simple border, gap = 4, otherwise gap = 6.
Next we see an example code, taken from the ListBoxExample.java file:
String []items1 = {"Orange","Apple","Grape","Lemon"};
String []items2 = {"One","Two","Three", ...};
String []items3 = {"Disabled",""};

SuperWaba Companion

66

lb1 = new ListBox(items1);


add(lb1,LEFT,TOP+5);
ListBox lb2 = new ListBox();
lb2.add(items2);
lb2.add("Twenty one");
add(lb2);
lb2.setRect(RIGHT,AFTER+5,PREFERRED,82);
ListBox lb3 = new ListBox(items3);
add(lb3,RIGHT-20,TOP+5);
lb3.setEnabled(false);

And the output:

Windows CE

PalmOS

Be careful when setting the items with a String array. The array is assigned as is, no
copy is made. So, if you use the same array in another control and an item inside the
array is changed, this change will reflect in both controls. However, if you add a new item,
then a new array is created to store the added item and the program works correctly. The
best practice is to have one array for each ListBox control. To create a copy of a String
array, you can use waba.sys.Convert.cloneStringArray.
As with the ComboBox control, the ListBox also posts the
ControlEvent.PRESSED when an item is clicked. Below is an example of how to handle
the event:
public void onEvent(Event event)
{
switch (event.type)
{
case ControlEvent.PRESSED:
if (event.target == lb1)
new MessageBox("SuperWaba","Item selected: "+
lb1.getSelectedItem()).popupModal();
break;
}
}

waba.ui.PopList
The PopList is a popup window with a ListBox inside it. When an item is selected,
the window is closed. It is used with the ComboBox class. Some characteristics are
described below:

SuperWaba Companion

67

It has two constructors: the default creates an empty ListBox, and the other
receives a ListBox as parameter (it can be used when you create a customized
ListBox).
The lb member is public, it can be accessed directly.
The setRect method must be used differently: you must pass the parents
bounds (if any) because the PopList computes its bounds making sure that the
parent is not hidden. The size is computed using the ListBox items count. It sets
the position above or below the parent, depending on that computed size.
If the style is WinCE, the window is popped up in a way to not hide the parent
control. In PalmOS, the PopList hides the parent control because thats the way
PalmOS ComboBox control needs to work. You can force the control to not hide
its parent setting the dontHideParent public flag to true.
As with ComboBox, you can set the fullHeight and fullWidth flag to true
to maximize the view size.

The PopList does not have a concept of preferred size because its bounds are
computed dynamically.
The example code, taken from the PopListExample.java file, is an Edit with a
PopList, where you can select the text to be pasted in the Edit:
String []items = {"Orange","Apple","Grape","Lemon"};
add(new Label("Press the menu to open the poplist"),LEFT,TOP+10);
add(ed = new Edit());
ed.setRect(LEFT,AFTER+2,100,PREFERRED);
pop = new PopList();
pop.lb.add(items);
Rect r = ed.getRect();
pop.setRect(r.x,r.y,r.width,r.height);
ed.requestFocus();

And the output:

Windows CE

PalmOS

When the PopList closes, it posts a ControlEvent.WINDOW_CLOSED. You must


intercept this event and do what you want. Below is an example:
public void onEvent(Event event)
{
switch (event.type)
{
case KeyEvent.KEY_PRESS:
if (((KeyEvent)event).key == IKeys.MENU)

SuperWaba Companion

68

if (pop.isVisible())
pop.unpop();
else
pop.popupModal();
break;
case ControlEvent.WINDOW_CLOSED:
if (event.target == pop)
ed.setText((String)pop.lb.getSelectedItem());
break;
}
}

waba.ui.ProgressBar
The ProgressBar is the standard bar used to display a progress. It consists of a bar
and a text that is displayed with the bar.

It has two constructors: the default one, which constructs a ProgressBar with
minimum=0 and maximum=100, and another where these two values are passed as
parameters.
There are several public members: min, max, value (minimum value, maximum value
and the current value, respectively), prefix (which is the text prefix), suffix (text
suffix) and textColor, the color of the text, drawBorder (if true default the
border is drawn with the text's color). All these members can be set and retrieved
directly.
There are two methods for that set these values and display the changes immediately:
setValue(value) and setValue(value, prefix, suffix). The first one
changes the current value, and the second one changes the value plus both text prefix
and suffix.
The displayed text is: prefix + value + suffix
The default value for prefix is an empty String, and for the suffix is the percent
symbol (%)
The preferred height is fmH+2 and the preferred width is the parent container's width-6
or the screen width, if the control was not added to its container yet.
Windows CE and PalmOS
The ProgressBar control does not post events.

waba.ui.Radio
Radio is a control used when you have a few options where only one option must
be selected at a time (like a ComboBox or a ListBox). They are usually grouped together
so that when one is selected, all the others in the group are de-selected. This can be
easily achieved with the waba.ui.RadioGroup class, as described below in the example
code. It has two constructors: one that receives text, and one that also receives a
RadioGroup.

SuperWaba Companion

69

The RadioGroup cant be added to a container because it is only a class, and does not
extend waba.ui.Control. Also, it does not post events. The RadioGroup class contains a
useful method getSelectedIndex, which returns the index of the selected radio, and
also the setSelectedIndex, to set the current radio. These indexes are based in the
order that the radios are added to the container.
You may use the getRadioGroup method to make it easier to parse the events.
Here is how the preferred size is computed:

Text height
(+ 2 if WinCE)
12 if PalmOS, 14 if WinCE

Text width

The blue rectangle represents the opened/closed circle and the red rectangle represents
the text.
Below you will see example code, taken from the RadioExample.java file:
rgFruits = new RadioGroup();
add(rOrange = new Radio("Orange",rgFruits),LEFT,TOP+5);
add(rApple = new Radio("Apple",rgFruits),LEFT,AFTER);
add(rGrape = new Radio("Grape",rgFruits),LEFT,AFTER);
add(rLemon = new Radio("Lemon",rgFruits),LEFT,AFTER);
rOrange.setChecked(true);
String []numbers = {"One","Two","Three"};
rgNumbers = new RadioGroup();
for (int i =0; i < numbers.length; i++)
add(new Radio(numbers[i],rgNumbers),
i==0?CENTER:SAME, i==0?(TOP+5):AFTER);
add(rEna = new Radio("Enable"),RIGHT,BOTTOM);
add(rDis = new Radio("Disable"),BEFORE-2,BOTTOM);
rDis.setEnabled(false);
rDis.setChecked(true);

And the code output:

Windows CE

PalmOS

SuperWaba Companion

70

The Radio control posts a ControlEvent.PRESSED event when the user clicks
on it. Below is an example of its use:
public void onEvent(Event event)
{
switch (event.type)
{
case ControlEvent.PRESSED:
if (event.target instanceof waba.ui.Radio)
{
Radio r = (Radio)event.target;
RadioGroup rg = r.getRadioGroup();
if (rg == rgFruits)
{
repaintNow(); // the MessageBox below will popup before the
// screen is updated to unselect the Radio
new MessageBox("SuperWaba",r.getText()+" juice")).popupModal();
}
else
if (rg == rgNumbers)
{
repaintNow();
new MessageBox("SuperWaba","Number selected:
"+r.getText()).popupModal();
}
else
// no RadioGroup; we have to handle by ourselfes
if (r == rEna)
{
rEna.setChecked(true);
rDis.setChecked(false);
rDis.setEnabled(true);
}
else
if (r == rDis)
{
rEna.setChecked(false);
rDis.setChecked(true);
rDis.setEnabled(false);
}
}
break;
...

waba.ui.ScrollBar
ScrollBar is a control that can be used when you want the user to select a value
from a range of values. It consists of two arrow buttons and one bar that can be dragged
to make scrolling easier. The ScrollBar can be horizontal or vertical. Below are some
other features:

There are two constructors: the default one constructs a vertical ScrollBar. The
other one receives as parameter a constant defining the orientation:
ScrollBar.HORIZONTAL or ScrollBar.VERTICAL.
The following constraints can be set:
o maximum (setMaximum and getMaximum): maximum value of the
ScrollBar.

SuperWaba Companion

71

minimum (setMinimum and getMinimum): minimum value of the ScrollBar.


blockIncrement (setBlockIncrement and getBlockIncrement): is
the value added/subtracted when the user clicks below/above the bar.
Everytime the maximum value is changed, the blockIncrement is
recomputed as (maximum/4)+1.
o unitIncrement (setUnitIncrement and getUnitIncrement): value
added/subtracted when the user click on the arrow buttons.
o value (setValue and getValue): this is the current value of the scrollbar.
o visibleItems (setVisibleItems and getVisibleItems): how many
items are currently visible to the user. This is used to compute the block
size.
o liveScrolling (setLiveScrolling): if set, events are posted while the
bar is dragged. As default, the event is posted only when the PEN_UP
occurs.
You can use the up/down keys to scroll the bar by blockIncrement steps.
Theres a handy method to set all values at once: setValues(int newValue,
int newVisibleItems, int newMinimum, int newMaximum)
The default values are: maximum = 100, minimum = 0, blockIncrement = 25,
unitIncrement = 1, value = 0, visibleItems = 50.
It is possible to change the minimum size of the drag bar setting the public member
minDragBarSize.
o
o

There's a way to change the ScrollBar's default width: you must play with the
Button.commonGap, which is a static member from the Button class (see chapter 6,
waba.ui.Button), and the extraArrowSize, which is a static member from the ScrollBar
class. The Button.commonGap increases the size of the button inside the ScrollBar, and
the ScrollBar.extraArrowSize increases the size of the arrow inside the Button.
After the ComboBox creation, you must reset them to 0, otherwise they will affect all future
ComboBoxes and Buttons created.
Next you see how the preferred size is computed for both ScrollBar types:
arrow
button's
height
d

arrow button's
height

1
pixel

arrow
button's
width

arrow
button's
height

1 pixel

arrow
button's
width

arrow button's
width
The blue rectangles represent the arrow buttons. The yellow rectangles represent the
bars.

SuperWaba Companion

72

In ScrollBar, the preferred size is the minimum size. If you set the size below this
value, the ScrollBar will not be drawn correctly.
Below you see a code example for the ScrollBar, taken from the ScrollBar.java file:
add(sb1 = new ScrollBar(ScrollBar.HORIZONTAL));
sb1.setLiveScrolling(true);
sb1.setRect(LEFT,TOP+5, 60, PREFERRED);
add(sb2 = new ScrollBar(ScrollBar.VERTICAL));
sb2.setRect(LEFT+15, AFTER+5, PREFERRED, 60);
ScrollBar sb3 = new ScrollBar();
add(sb3);
sb3.setRect(SAME, AFTER+5, PREFERRED, 30);
sb3.setVisibleItems(20);
sb3.setEnabled(false);

And the output:

Windows CE

PalmOS

As most of the controls, the ScrollBar also posts ControlEvent.PRESSED events.


The events are posted every time the button is pressed, and if liveScrolling is true,
the events are also posted while the user is dragging the bar (otherwise, if it is false, the
event is posted only when the dragging stops). Below is an example of its use:
public void onEvent(Event event)
{
switch (event.type)
{
case ControlEvent.PRESSED:
if (event.target instanceof ScrollBar)
{
int value = ((ScrollBar)event.target).getValue();
sb1.setValue(value);
sb2.setValue(value);
}
break;
}
}

SuperWaba Companion

73

Chapter 13 - Advanced Controls


Advanced controls are also widely used, but because they are a little more
complex, they are in a separate chapter. These include the waba.ui.MenuBar and
waba.ui.PopupMenu, the waba.ui.PushButtonGroup, the waba.ui.Grid, the
waba.ui.TabPanel and, finally, the waba.ui.MessageBox and the waba.ui.InputDialog.

waba.ui.MenuBar and waba.ui.PopupMenu


These two classes are used together to create menus in SuperWaba. The
MenuBar is used as the menu bar that pops up when the user presses the menu key or
clicks on the title area of the Window (if any). The PopupMenu is used as the pull down
menus for each caption of the menu bar. In SuperWaba there are no submenus in pull
down menus.

Since WinCE devices dont have a menu key, the ACTION key, if not intercepted by
the user, is used to open the menu.
The user can disable this by setting Vm.actionEqualsMenu to false.
The MenuBar is assigned per Window. This means that each window can have its
own menu bar. Because the Window.menuBar member is a waba.ui.Control, you may use
third party menu controls with the Window. When the user activates the menu, the
Window class calls the menuBar.setVisible method. This makes the popup action
generic enough to use any menu control available.

The menu bar is always placed at position 0,0 on screen, regardless if it belongs to the
MainWindow or to a popup window. This increases the available area for the captions.
Currently MenuBar and PopupMenu have only the look and feel of PalmOS. To make
it more beautiful in Windows CE and in Color devices, you can use the methods
MenuBar.setPopColors and MenuBar.setCursorColor.
The items are vertically grouped in a String array, where the first item of the array
is the caption that is used by the MenuBar control and the others are the items used in the
PopupMenu control. A menu is composed of a matrix of Strings, assigned in the only
available constructor. Although not a good design practice, storing items in a String
instead of a class (like MenuItem) makes the program faster and lowers the memory
usage.
Here are some features of the menu classes:

Items are numbered in format xyy, where


o x is the index of the item selected at the MenuBar, starting from zero.
o yy is the index of the item in the String array (it will start from one, because
zero is the menu bar caption).

SuperWaba Companion

74

An item can be disabled by prepending its string with an asterisk (constant


MenuBar.DISABLED). At runtime, you may use the setEnabled(int
menuItem, boolean enable) method.
An item can be set as checkable by prepending the string with ? (constant
MenuBar.UNCHECKED). At runtime, the public setChecked(int menuItem,
boolean check) method can be used.
You can put a line between two items by naming the item as -. Note that this
divisor also counts as an item.
Menus must fit in the screen. The menu bar simply wraps items that dont fit on
screen width. The popup menu also wraps items that dont fit on screen height.
Although not recommended, you can increase the number of captions in the
MenuBar by changing the gap member. The default is 3 pixels.
Items are always manipulated through the methods in the MenuBar class. Here are
some other useful methods:
o getSelectedMenuItem: returns an integer in the xyy format with the
current menu item selected.
o isChecked(int menuItem): returns true if the given menuItem is
checked. Returns false if it is not checked or if the menu item is not
checkable.
o isCheckable(int menuItem): returns true if the given menuItem is a
checkable one.
o isEnabled(int menuItem): returns true if the given menuItem is
enabled, false if it is disabled.
The menu items can be updated at runtime calling the method setItems.

The menu item must be set as checked when constructing the menu, it cannot be
changed from a simple item to a checked item at runtime, or the width of the popup menu
will not be correctly computed.
Below you can see an example, taken from the MenuExample.java file:
String col0[] =
{
"Caption0",
"*Item1", // disabled
"-",
// item2
"?Item3_checkable", // checkable
};
String col1[] =
{
"Caption1",
"Item1 - popup",
"Item2",
};
String col2[] =
{
"Caption2",
"Item1",
"Item2",
"Item3",
"Item4",
"Item5",
};

SuperWaba Companion

75

mbar = new MenuBar(new String[][]{col0,col1,col2});


setMenuBar(mbar);
if (Settings.isColor)
{
mbar.setBackForeColors(new Color(0,0,255), Color.WHITE);
mbar.setCursorColor(new Color(100,100,255));
mbar.setBorderStyle(NO_BORDER);
mbar.setPopColors(new Color(0,120,255),new Color(0,255,255),null);
// use the default cursor color for the popup menu (last null param)
}

The following pictures show snapshots of a MenuBar with a PopupMenu:

Mono device

Color device

When the user clicks on a menu item, the window closes. You must handle the
ControlEvent.WINDOW_CLOSED event and discover which item was chosen. You may
use the value returned by the getSelectedMenuItem method as the index of a switch
statement.
public void onEvent(Event event)
{
switch (event.type)
{
case ControlEvent.WINDOW_CLOSED:
String sel = null;
if (event.target == mbar)
switch (mbar.getSelectedMenuItem())
{
case -1: break; // no item selected
case
1: sel = "Caption 0 - Item 1 - cannot be clicked
(disabled)"; break;
case
3: sel = "Caption 0 - Item 3 "+mbar.isChecked(3); break;
case 101: sel = "Caption 1 - Item 1";
new WindowWithMenu().popupModal(); break;
case 102: sel = "Caption 1 - Item 2"; break;
case
case
case
case
case

201:
202:
203:
204:
205:

sel
sel
sel
sel
sel

=
=
=
=
=

"Caption
"Caption
"Caption
"Caption
"Caption

2
2
2
2
2

Item
Item
Item
Item
Item

1";
2";
3";
4";
5";

break;
break;
break;
break;
break;

}
edSel.setText(sel != null ? (mbar.getSelectedMenuItem()+" - "+sel)
: "");
break;
}
}

SuperWaba Companion

76

waba.ui.PushButtonGroup
The PushButtonGroup is a very powerful control. Below you see some of its
features:

It can place pushbuttons in a row, in a column or in a matrix.


The pushbuttons can be set to act like:
o PushButtonGroup.NORMAL: only one pushbutton can be selected at a
time. Clicking in the button again will not unselect it. To unselect it, you must
click in the selected control bounds and drag the mouse outside the control
bounds.
o PushButtonGroup.BUTTON: when clicked, the pushbutton will be selected
and unselected immediately, acting like a real button.
o PushButtonGroup.CHECK: one click in the pushbutton will select it and
another click will unselect it. However, only one button can be selected at a
time
The selected pushbutton index can be get and set using the methods
getSelected and setSelected.
The selected pushbutton caption can be returned using the method
getSelectedCaption
There is only one constructor, with lots of options that relate to each other and
cannot be changed after the PushButtonGroup is created:
PushButtonGroup(String[] names, boolean atLeastOne, int
selected, int gap, int insideGap, int rows, boolean
allSameWidth, byte type)
o names: these are the pushbutton captions. You can specify some names as
null so an empty area is displayed instead of the button.
o atLeastOne: if true, at least one button must stay selected.
o selected: default index to appear selected, or -1 if none.
o gap: space between the buttons, -1 glue them.
o insideGap: space between the text and the button border. the ideal is 6.
o rows: if > 1, creates a button matrix with the given number of rows. The
number of columns is computed as names.length/rows. Note that if
(rows*cols != names.length) you may get some strange results; if
this is the case, complete the matrix with null elements.
o allSameWidth: if true, all the buttons will have the width of the largest
name.
o type: can be NORMAL, BUTTON or CHECK
As default, the buttons are painted with the same borders as the current user
interface style (WindowsCE has 3d borders, PalmOS has round rectangle borders).
To change it to a normal rectangle, use the setSimpleBorder method.
One very interesting thing that can be done with PushButtonGroup and the
focusLess member (inherited from the Control class) is to create keypads. See
waba.ui.Calculator sources, searching for numericPad, a numeric keypad.

SuperWaba Companion

77

As any other control, the font can be changed after the constructor is called and before
the setRect is called.
Below is how the preferred size is computed:
(maximum text width + insideGap) if allSameWidth,
(text width + insideGap) otherwise.
text height +
(2 if simpleBorder)

pushbutton

gap

gap

The controls total width is the sum of all pushbuttons widths and gaps, minus one gap;
and the controls total height is the sum of all pushbuttons heights and gaps, minus one
gap.
Next you see an example, taken from the PushButtonGroupExample.java file:
// PushButtonGroup(String[] names, boolean atLeastOne,
// int selected, int gap, int insideGap, int rows,
// boolean allSameWidth, byte type)
pbg1 = new PushButtonGroup(items1,false,-1,-1,6,4,true, PushButtonGroup.BUTTON);
add(pbg1,LEFT,TOP+2);
pbg2 = new PushButtonGroup(items1,false,-1,-1,6,4,true, PushButtonGroup.BUTTON);
pbg2.setSimpleBorder(true);
add(pbg2,AFTER+10,SAME);
pbg3 = new PushButtonGroup(items1,false,-1,-1,6,4,true, PushButtonGroup.BUTTON);
add(pbg3,AFTER+10,SAME);
pbg3.setEnabled(false);
pbg4 = new PushButtonGroup(items1,false,-1,-1,6,4,true, PushButtonGroup.BUTTON);
pbg4.setSimpleBorder(true);
add(pbg4,AFTER+10,SAME);
pbg4.setEnabled(false);
pbg5 = new PushButtonGroup(items2,false,-1,4,6,1,false, PushButtonGroup.CHECK);
add(pbg5,LEFT,AFTER+3,pbg1); // positioning relative to pbg1
pbg6 = new PushButtonGroup(items3,false,-1,1,6,1,false, PushButtonGroup.NORMAL);
add(pbg6,RIGHT,AFTER+3);
pbg7 = new PushButtonGroup(items4,false,-1,3,10,3,true, PushButtonGroup.NORMAL);
add(pbg7,CENTER,AFTER+3);
lab = new Label("",CENTER);
add(lab);
lab.setRect(CENTER,AFTER+3,100,PREFERRED);

And now a screen shot of the output:

SuperWaba Companion

78

WindowsCE

PalmOS

The PushButtonGroup posts a ControlEvent.PRESSED event when a button is


selected or unselected. As described, the getSelected method returns the index of the
currently selected pushbutton, or -1 if none is selected. Below you see an example of how
to handle the events:
public void onEvent(Event event)
{
int idx;
switch (event.type)
{
case ControlEvent.PRESSED:
if (event.target == pbg2 &&
(idx = pbg2.getSelected()) != -1)
{
lab.setText("Button pressed: "+items1[idx]);
}
break;
}
}

waba.ui.TabPanel
This control consists of some tabs and a container attached to each tab. When a
tab is clicked, the current container is removed and the tabs container is added. This
control is used to save space when you have many controls that can be grouped together
and placed in different containers. Below you see some features:

There is only one constructor. It receives a String array with the captions for the
tab. For each caption, one Container is created for it. As default, the first tab is
made active.
Tabs can be placed on top or on bottom. Therefore, you can use the setType
method giving the constants TabPanel.TABS_TOP and
TabPanel.TABS_BOTTOM.
The tabs are drawn with the controls backColor unless you specify the color for
each tab using the setPanelsBackColor(Color []backColors) method.
This method receives a waba.fx.Color array and the number of colors must
match the number of captions.
The captions color may be changed by using the setCaptionsColor method.
There's two public members:

SuperWaba Companion

79

o beepOn (true as default) that controls if a beep will sound when the a tab is
clicked.
o lastActiveTab: Stores the last active tab index, or -1 if none was
previously selected.
Here are some other useful methods:
o getPanel(int i): used to return the asked Container. It is used when
adding controls to the container.
o setType(int type): can be TAB_TOP or TAB_BOTTOM, and specify
where the tabs will be placed.
o setGaps(int gapL, int gapR, int gapT, int gapB): used to set
the gaps (Left, Right, Top, Bottom) between the containers and the
TabPanel.
o setBorderStyle(byte style): used to set the type of border for the
TabPanel. You can use, as parameters, the Window.NO_BORDER (that only
draws a line under the tabs) and Window.RECT_BORDER (default).
o setPanel(int i, Container container): Replace the default
created container of index i with the given one. By using this you can avoid
adding a container to a container and avoid wasting memory and time. Note
that you must do this before the first setRect for this tabPanel, otherwise,
you must explicitly call setRect in the TabPanel again to update the added
container bounds.
o setActiveTab(int tabIndex): Sets the currently active tab, switching
the containers.
o setCaptionColor(Color c) and setPanelsBackColor(Color
[]backColors): Used to set the color for the tabs and set the background
color for each panel.
o getClientRect: returns the rect where the containers are placed,
excluding title and borders.
Below is described how the preferred size is computed:
Text height + 4
20

Loop through all captions, compute


the sum of (text width + 2) and
add 6 to the final result.
The blue rectangle represents the tabs captions area, while the red rectangle represents
the containers area.
Below you see an example, taken from the TabPanelExample.java file:
// add the status at the bottom
lWarn = new Label("",CENTER);
lWarn.setInvert(true);
add(lWarn);

SuperWaba Companion

80

lWarn.setRect(LEFT,BOTTOM,FILL,PREFERRED);
// now add the TabPanel placing it in all client rect
// but no overlapping the warning
String []captions = {"Name/Tel.","Address"};
add(tp = new TabPanel(captions));
tp.setGaps(2,2,2,2); // before calling tp.setRect
tp.setRect(getClientRect().modifiedBy(0,0,0,lWarn.getPreferredHeight()));
// panel 0
tp.setPanel(0, new NameTel());
// panel 1
Container c = tp.getPanel(1);
c.add(new Label("Addr1:"),LEFT+5,TOP+5);
c.add(edAddr1 = new Edit(""),AFTER+5,SAME-1);
c.add(new Label("Addr2:"),LEFT+5,AFTER+10);
c.add(edAddr2 = new Edit(""),AFTER+5,SAME-1);

TabPanel has the same look and feel in both user interface types. Here is the
screen shot of the output:

The TabPanel posts a ControlEvent.PRESSED event when the tabs change.


You may need to do some action, like field validation. Below is an example of such case.
public void onEvent(Event event) {
switch (event.type)
{
case ControlEvent.PRESSED:
if (event.target == tp)
{
validateFields(lastActiveTab);
lastActiveTab = tp.getActiveTab();
}
break;

SuperWaba Companion

81

waba.ui.MessageBox
This one is a popup window used to show a text in a label with some user-defined
buttons (like <Ok> and <Cancel>). Here are some characteristics of this control:

It has three constructors:


o MessageBox(String title, String msg): creates a MessageBox
with the given title and message. The message is displayed using a Label,
and can be displayed in multiple lines if previously parsed with the |
character. This constructor creates one <Ok> button.
o MessageBox(String title, String text, String[]
buttonCaptions): Same as the previous constructor plus a String array
that specifies the button captions. A PushButtonGroup is used to display the
buttons, and the getPressedButtonIndex() method returns the pressed
button index.
o MessageBox(String title, String text, String[]
buttonCaptions, int gap, int insideGap) : Same as the previous
constructor, plus the gap and insideGap parameters that are passed to the
PushButtonGroup that's created, which can be used to increase its size.
The MessageBox is displayed centered on screen and with the width/height
computed based in the title, the text and the buttons.
If the Text height is above the screen limits, two arrows are added to the
MessageBox so the text can be scrolled.
It can also be automatically unpopped after a specified number of milliseconds
using the setUnpopDelay(int unpopDelay) method.
You may use the method setTextAlignment to set the alignment of the Label
that displays the text. The possible arguments are LEFT, CENTER, RIGHT.
You may use the up/down buttons to scroll the text.

Passing null to the buttonCaptions parameter of the second constructor will


create a MessageBox with no buttons. You must provide a way for the MessageBox to be
unpopped!
After being created, the messageBox needs to be explicitly popped up by using the
popupModal or popupBlockingModal methods.
Even if the setUnpopDelay is set, the popup of the MessageBox returns immediately.
If you want to block the Program execution while displaying the MessageBox, you must do
as the btn4 example in the code below.
You must call setUnpopDelay just before calling the popupModal method. This must
be done because setUnpopDelay starts the timer when invoked. So, if you call
setUnpopDelay in the constructor, for example, the Window will be unpopped before it
is popped up, and this will cause an exception to be thrown that will crash your program.
Below are some MessageBox examples, taken from the onEvent method in the
MessageBoxExample.java file.
case ControlEvent.PRESSED:
if (event.target == btn1)
{

SuperWaba Companion

82

new MessageBox("SuperWaba","This is a simple MessageBox").popupModal();


} else
if (event.target == btn2)
{
new MessageBox("License","SuperWaba Virtual Machine|...").popupModal();
// the execution continues normally. The MainWindow is not blocked.
} else
if (event.target == btn3)
{
String []buttonArray = {"Under 13","13 to 17","Above 17"};
mb3 = new MessageBox("SuperWaba", "How old are you?", buttonArray);
mb3.popupBlockingModal();
// the execution will block until the MessageBox is dismissed.
String []ages = {"You are a child","You are a teen",
"You are an adult"};
int idx = mb3.getPressedButtonIndex();
lab.setText(idx==-1 ? "Undefined" : ages[idx]);
} else
if (event.target == btn4)
{
mb4 = new MessageBox("SuperWaba","Please wait 5 seconds...|
(non-blocking)",null); // create with no buttons
mb4.setUnpopDelay(5000);
mb4.popupModal();
} else
if (event.target == btn5)
{
lab.setText("");
MessageBox mb = new MessageBox("Hi world!","wait 5 seconds to
close ...|(blocking)",null); // create with no buttons
mb.popupModal();
waba.sys.Vm.sleep(5000);
mb.unpop();
}
break;

MessageBox has the same look and feel in both user interface styles. Here is some
output:

As most window controls, you can handle the ControlEvent.WINDOW_CLOSED


event to check for the pressed button and do the actions needed. Below is an example:
switch (event.type)
{
case ControlEvent.WINDOW_CLOSED:
if (event.target == mb4)
{
lab.setText("Thanks to wait 5 seconds.");

SuperWaba Companion

83

}
break;
}

If you call getPressedButtonIndex before the window closes (perhaps by putting it


immediately after the popupModal method), the method will correctly return -1, because
no button was pressed yet. Be sure to use the method popupBlockingModal instead; it
will block and return the correct pressed button.

waba.ui.InputDialog
This one is a popup window used to get a text input from the user. It shows text in a
label, the Edit and some user-defined buttons (like <Ok> and <Cancel>). Here are some
characteristics of this control:

It has two constructors:


o InputDialog(String title, String text, String
defaultValue): creates an InputDialog with the given title, the text that
will be displayed in the Label and the default value placed in the Edit. The
label cannot be scrolled, so be sure to use only a few lines. This constructor
creates one <Ok> button.
o InputDialog(String title, String text, String
defaultValue, String[] buttonCaptions): Same as the previous
constructor plus a String array that specifies the button captions. A
PushButtonGroup is used to display the buttons, and the
getPressedButtonIndex() method returns the pressed button index.
buttonCaptions cannot be null!
The InputDialog is displayed centered on screen and with the width/height
computed based in the title, the text, the edit and the buttons.
The method getEdit() can be used to set any characteristic you want for the Edit.
Use the methods getValue and setValue to get and set the value of the Edit.
The focus is moved to the Edit when the InputDialog is popped up.
Next is an InputDialog example, taken from the InputDialogExample:

InputDialog id = new InputDialog("Change Caption",


"Please enter the text|for the new caption",
"InputDialog Example",new String[]{"Cancel","Ok"});
id.popupBlockingModal();
if (id.getPressedButtonIndex() == 1)
setTitle(id.getValue());

And here is the screen output:

SuperWaba Companion

84

waba.ui.Grid
The Grid class is used to display tabulated data, which is represented as a String
matrix (each row is a String array). Here are some features:

Vertical scrollbar, used to scroll up and down the information on the grid.
Horizontal scrolling in case the columns widths are grater than the screen width
An easy to use interface for adding/removing information to the grid
Optional check column, this is a column that is clickable marking an specific line as
checked/unchecked, this is useful if you want the user to be able to select multiple lines
displayed on the grid.
Columns can be resized so that the user can see all the information displayed in a
given column
Style configuration, you can set the color of captions boxes all the way thru the stripes
colors and vertical line types. The grid is compatible with your application's style (Flat,
WinCE, etc... )

It has one constructor:


o Grid(java.lang.String[] captions, int[] widths, int[]
aligns, boolean checkEnabled): creates a grid with the given
captions, column widths, column alignments and if it contains a column for
multi selection.
And these methods:
o add(String[] item): adds a new item to the grid.
o clear(): remove all items from the grid.
o del(int index): removes the given index from the grid.
o getItem(int index): returns the line from the given index.
o getItemsVector(): returns a vector containing all information inside the grid.
As with getItem, the returned data does not contain information about the
selected item's.
o getSelectedIndexes(): returns an IntVector containing the indexes of the
lines that have been marked with a check
o int getSelectedLine(): get the number of the currently selected line
o selectIndex(int idx, boolean select): selects or unselects the given index
based on the second argument
o setItems(java.lang.String[][] items): sets the grid items to be displayed,
notice that it needs to be conforming to the numbers of columns that the grid
currently have...
o setSelectedIndexes(IntVector si): sets only the given indexes as selected
o setWidths(int[] widths): sets the column widths.

SuperWaba Companion

85

Here some useful attributes:


o boolean drawCheckBox: defines if the box around the check will or not be
drawn.
o checkColor: the color used to draw the check.
o captionsBackColor: the color used to fill the captions area.
o firstStripeColor: color of the first stripe.
o secondStripeColor: color of the second stripe.
o verticalLineStyle: defines the vertical line style of the grid. Possible values
are VERT_DOT (default), VERT_LINE and VERT_NONE.
o String[] captions: these are the column captions. Can be directly assigned,
but always make sure it has the same number of elements of the widths
array, set with the setWidths method.
Next is an example, taken from the superwaba.samples.ui.grid.GridTest sample:

String []gridCaptions = {"Caption 1", "Caption 2", "Caption 3", "Caption 4",
"Caption 5", "Caption 6", "Caption 7" };
int ww = fm.getTextWidth("xxxxxxxxx");
int gridWidths[] = {ww, ww, ww, ww, ww, ww, ww};
int gridAligns[] = { LEFT,LEFT,LEFT,LEFT,LEFT,LEFT,LEFT};
grid = new Grid( gridCaptions, gridWidths, gridAligns, false );
grid.firstStripeColor = Color.GREEN;
grid.secondStripeColor = Color.YELLOW;
grid.verticalLineStyle = Grid.VERT_NONE;
add( grid );
grid.setRect( LEFT, AFTER+2, FILL, FIT, btnRemove );
String items[][] = new String[4][7];
for( int i = 0; i < 4; i++ )
for( int j = 0; j < 7; j++ )
items[i][j] = "BRAZIL "+j;
grid.setItems( items );

And here is the screen output:

SuperWaba Companion

86

Chapter 14 The Window class


Since SuperWaba 1.2, popup windows can be created by using the Window class.
In this chapter we will examine in detail the Window class.
As you already have read in chapter 3, a SuperWaba program consists of one and
only one MainWindow. This MainWindow can pop up a window, and this popup window
can pop up another window, and so on. Windows in SuperWaba are not modeless, they
are always modal, i.e., only the last popped up window can receive events and you
cannot switch from the topmost Window to the previous without closing the topmost one.
Window controls should not be added to containers, this is not recommended and
you may get some unwanted results if doing so in your code. Instead, they must be
popped up with the popupModal or the popupBlockingModal methods.
Below we see some other features of the Window class:

Windows can have a title that is set in the setTitle method or in the constructor.
The window border can be selected from multiple styles by using the
setBorderStyle method or in the Window constructor. Below you see the possible
styles:

NO_BORDER

RECT_BORDER

TAB_BORDER

ROUND_BORDER

TAB_ONLY_BORDER

There are two constructors: the default one, that creates a Window with no title and
no border, and one constructor with both title and border parameters.
Windows can be moved around the screen by dragging the windows title. If the
window has no title, it cant be moved. You can make a titled window unmovable by
calling the makeUnmovable method.
The title font can be changed using the setTitleFont method. By default, the
font is the one used by MainWindow, with bold style.
Windows can be double buffered. This means painting occurs first in an image
buffer and when finished, the image is drawn on the screen. This can speed up
drawing and make its appearance smoother. This feature can be activated by

SuperWaba Companion

87

calling the setDoubleBuffer method. The image in the buffer can be obtained
through the getOffScreen method.
Only one control can hold the focus at a time. To change focus to another control,
use the setFocus method (this can also be done through the requestFocus
method in the waba.ui.Control class). The getFocus method returns the
control that currently owns the focus.
The rectangle area excluding the border and the title is defined as the client
rectangle. You can get it with the getClientRect method.
A window can be popped up by calling the popupModal method and can be
unpopped by calling the unpop method.The popup process saves the area behind
the Window that is being popped up and the unpop process restores that area. The
unpop method posts a ControlEvent.WINDOW_CLOSED event to the caller
window. The popupModal method can be called like this.popupModal().
A window can also be popped up by calling the popupBlockingModal method,
and be unpopped by the same unpop method described above. The big difference
is that in popupModal, the program execution continues to the next line, while in
popupBlockingModal, the program execution is halted and only continues when
the popped up Window is dismissed. Menu, MessageBox, ComboBox and PopLists
are popped up using popupModal, because execution does not need to be halted.
InputDialog, Calendar, Calculator, usualy are popped up using
popupBlockingModal because the user may want to get the result of the dialog
in an easy way.

You can't use popupBlockingModal to popup alternating windows that call each
other recursively. For example, suppose that from Win1 you call
win2.popupBlockingModal(), then at Win2 you call unpop and then
win1.popupBlockingModal(). Then, from Win1 you do unpop again and
win2.popupBlockingModal(), and so on. This will lead to a hard reset on the device
due to a native stack overflow. To fix this, just replace the popupBlockingModal by
popupModal.

The topmost window (the one who receive events) can be obtained with the static
method getTopMost. To check if this window is the topmost, use the
isTopMost method.
You may check if this window is visible using the isVisible method. This method is
inherited from waba.ui.Control, but it simply checks if the current window is the
topmost one.
Using the setStatePosition method can show PalmOS Grafitti state characters. To
hide it, call setStatePosition(HIDE_STATE,HIDE_STATE). This method is
also used in Windows CE and Pocket PC to show/hide the virtual keyboard (when
applicable). Just use as parameter VK_HIDE, VK_TOP and VK_BOTTOM to hide,
display the virtual keyboard at top of the screen or at the bottom of the screen.
Note that this will have no effect in devices that don't have a virtual keyboard.
Each window can have a menu attached by using the method setMenuBar. The
menuBar can be made visible programmatically by calling the popupMenuBar
method.
Suppose you wish to allow the user to abort a task being executed by pressing.
You can use the method pumpEvents to process all events in the queue.

SuperWaba Companion

88

If you divide your application logic to classes that extend Container and are
displayed one at a time in the MainWindow, you can use the method swap to make
things easier to manage. See samples/ui/ContainerSwitch in the SDK for a good
example.
The methods getPreferredWidth and getPreferredHeight have a special
meaning for the Window class. They return the minimum width/height needed for
the correct display of this Window. The getPreferredWidth returns the width of
the title (if any) plus the width of the border (if any). The getPreferredHeight
returns the height of the title (if any) plus the height of the border (if any).
As already mentioned, the contents behind the window being popped up are saved
so they can be restored later. They are saved using the saveBehind method and
restored by using the loadBehind method. This last one has a parameter that, if
true, releases the memory used in the backup operation. You can explicitly avoid
the save operation by calling the dontSaveBehind method. It is useful when you
popup a Window in the constructor of the application, before the controls have
been drawn. High resolution devices may have some memory problems after a few
popped up windows, so disabling this feature can be useful. This method has a
parameter, repaintOnClose, that:
o if true, the parent window is fully repainted when the window is unpopped.
o if false, nothing is done when the window unpops and you must handle the
restore/repaint by yourself.
SDL devices (Windows CE, Windows 98/2K/XP and Epoc) have no direct-screen
access. To update the screen after something is changed, you must call the static
method updateScreen. This method is already called by the system when an area
is invalidated and by the repaintNow method in class Control.

There are some useful protected methods that may be implemented by controls
that extend waba.ui.Window. Those methods are placeholders and there is no need to
call the super method.

onClickedOutside(int x, int y): This method is used in popup windows. If the user
clicks outside the windows bounds, this method is called giving the absolute
coordinates of the clicked point. There are two options:
o If you had handled the action, return true in this method.
o Otherwise, false must be returned and if the beepIfOut member is true, a
beep is played (in other words, beepIfOut can be set to false to disable this
beep).
onPopup(): Called just after the behind contents are saved and before the popup
process begin. When this method is called, the topmost window is still the parent of
the Window being popped up.
postPopup(): Called after the popup process ended. When this method is called,
the popped up window is fully functional. It is a good place to put a
control.requestFocus() to make the window popup with the focus in a default
control.
onUnpop(): Called just before the unpop process begin.
postUnpop(): Called after the unpop process ended. When this method is called,
the unpopped window has gone away and the parent Window is currently the
topmost.

SuperWaba Companion

89

Some other important members of the Window class are explained here:

boolean needsPaint: true if there are any controls marked for repaint.
boolean flicker: if true, the background area is erased during the repaint
process. This causes flickering if the window is not double buffered.
Window topmost: stores the topmost Window.
boolean canDrag: if true and if this is a popup window, the user is allowed to
drag the title and make the window move around.
boolean highResPrepared: This extremely important member is used when
your program runs in devices with a screen resolution greater than the default
160x160 of Palm OS. Some devices have 320x320, 240x320, etc. For each device,
the font is usually proportional to the resolution. Since SuperWaba programs are
placed in a relative way, and since the relativeness depends on the Window's size,
your popped up Window would look squashed because the Windows bounds are
usualy set with an absolute coordinate. To avoid this, the Window manager checks
if your Window is prepared for high resolution devices (i.e., you tested it against
other resolutions and set the right value for the Window depending on each case).
If your Window is not prepared, then the setRect method will multiply the size of
the Window by a factor that depends on how much the screen resolution has
changed from the basic 160x160 (E.g.: in a 240x320 device, a 80x40 Window will
be changed to 120x80). Also, the window will be centered on screen. So, if you
have tested your Window in other resolutions, set this flag to true.

Never mess with the public member zStack. It is used to store the windows that are
currently popped up. It is made public because the waba.applet.Applet class uses it.
A very common mistake is to popup a Window without setting its bounds. If no bounds
are set, the window will not receive events.
Next is explained how controls inside a Window are repainted:
1. The programmer calls the repaint method of some controls, or a control is clicked
and marks itself for repaint.
2. The damageRect method in class Window creates a rectangle (stored in the
paintX, paintY, paintWidth and paintHeight members) with the union of
the bounds of all controls marked for repaint.
3. The next time a VM event is posted, the _doPaint method of the topmost window
is called. This method paints the windows title/border (if any) and calls the onPaint
method of all containers and controls that lies inside the rectangle area marked for
repaint. This explains why nothing in the window is updated when you receive
events directly from a native library (the Scanner class, for example). Because the
VM is not receiving the event, it never validates the window. In these cases, you
must update the window yourself, calling repaintNow or the validate methods.
Many classes in the waba.ui package extend waba.ui.Window. Examples of such
classes are waba.ui.Calculator and waba.ui.Calendar. Other good examples are
waba.ui.MessageBox and waba.ui.PopList.
It's important to be aware that it is not a good practice to create classes that extend

SuperWaba Companion

90

Window if they will occupy the whole screen, because they use a lot of memory to store
the underlying area. Opening the menu may lead to time-consuming redraws of all
opened windows due to out-of-memory problems. In these cases, it is better to extend
waba.ui.Container, as explained in chapter 10.

SuperWaba Companion

91

Chapter 15 Utility Classes


In this chapter we will examine some popup windows in the waba.ui package that
were created to increase the power of SuperWaba programs. These are the Calculator,
the Calendar and the Keyboard classes. They are automatically used in the waba.ui.Edit
class, depending on the selected Edit mode, and appear/disappear when the user clicks
on the abc/123 buttons.

waba.ui.Calculator
This class implements a very simple calculator. It lets you enter two numbers,
select an operation and compute the result. Youre then able to paste the result or the first
operand.
The Calculator class can be used standalone. Just pop it up and get the pasted
result by using the getAnswer method. The formatting precision of each entered number
is defined by the decimalPlaces public field. The code below shows an example taken
from the onEvent method in the CalculatorExample.java file:
public void onEvent(Event event)
{
switch (event.type)
{
case ControlEvent.PRESSED:
if (event.target == btn)
{
if (calc == null)
calc = new Calculator();
calc.popupModal();
}
...
}

When the window is closed, you can handle the ControlEvent.WINDOW_CLOSED


event to get the results.
public void onEvent(Event event)
{
switch (event.type)
{
case ControlEvent.WINDOW_CLOSED:
if (event.target == calc)
{
String answer = calc.getAnswer();
lab.setText(answer==null ? "Canceled" : answer);
}
/*calc = null;
Note: if your program uses the Calculator control only a few
times, i suggest that you set the calc to null because it can get
garbage collected. Calculator objects wastes memory, and
is always a good idea save memory when possible*/
break;
}
}

SuperWaba Companion

Windows CE

92

PalmOS

waba.ui.Calendar
This is a calendar where a date can be chosen. It pops up with the current day as default
and the user can scroll through the month/years. When a day is selected the window
closes and the chosen date is pasted into the Edit.
The Calendar control can be used standalone, as it shows the example below,
taken from the onEvent method in CalendarExample.java file:
public void onEvent(Event event)
{
switch (event.type)
{
case ControlEvent.PRESSED:
if (event.target == btn)
{
if (cal == null)
cal = new Calendar();
cal.popupModal();
}
}

When the window is closed, you can handle the ControlEvent.WINDOW_CLOSED event
to get the results.
public void onEvent(Event event)
{
switch (event.type)
{
case ControlEvent.WINDOW_CLOSED:
if (event.target == cal)
{
Date d = cal.getSelectedDate();
lab.setText(d==null?"no date choosen":d.toString());
}
/*cal = null;
Note: If your program uses the Calendar control only a few
times, i suggest that you set cal to null so it can get garbage
collected. Calendar objects waste memory and it is always a
good idea
to save memory when possible*/
break;
}
}

SuperWaba Companion

93

Here are the snapshots:

Windows CE

PalmOS

waba.ui.Keyboard
This class replaces the original PalmOS keyboard. The original keyboard cannot
be used in Java because it is restricted to use with original PalmOS controls. The
waba.ui.Keyboard contains all characters from the original keyboard plus some other
keys. It can also be easily extended to other languages. It currently supports the following
languages, set with the method setLanguage:

LANG_NORMAL (Americas)
LANG_GERMAN
LANG_HEBREW
LANG_TURKISH

The Keyboard class cannot be used standalone; it can only be used if called from
inside an Edit control. Below are snap shots of both styles:

Windows CE

PalmOS

SuperWaba Companion

94

Chapter 16 Splitting your application's logic using


waba.ui.Container
In this chapter we will learn how to split the application's logic using classes that
extend Container.
Normal SuperWaba applications need to display controls on screen based on the
current state of the application. To make things easier to understand, we will study the
CDTeca application. This application lets the user enter a list of compact-disc names and
tracks then search the list. CDTeca it has two states: EDITTING and SEARCHING. So,
we create two classes extending waba.ui.Container: Edit and Search:
public class CDEdit extends waba.ui.Container
{
...
}
public class CDSearch extends waba.ui.Container
{
...
}

Now we need to fill our containers with controls. We will do this with the method
onStart, the same one that we normally use in the MainWindow class. You may be
asking: why can't we add the controls to the classes constructors? The answer is simple:
because in the contructor, the size and parent of CDEdit and CDSearch are unknown.
Why is this information so important? First, without the size you will not be able to use
relative positioning. Second, without the parent you will not be able to create a Graphics
object and use some relative positioning options.
So, we can now use the onStart method to initialize our containers:
public class CDEdit extends waba.ui.Container
{
public void onStart()
{
...
}
}
public class CDSearch extends waba.ui.Container
{
public void onStart()
{
...
}
}

We have our containers filled with controls, and can now handle the events in the
onEvent method. For example:

SuperWaba Companion

95

public class CDSearch extends waba.ui.Container


{
public void onStart()
{
...
}
public void onEvent(Event e)
{
...
}
}

Now we must, of course, create our MainWindow, which will control the flow of the
application.
public class CDTeca extends waba.ui.MainWindow
{
static CDSearch cdsearch;
static CDEdit cdedit;
public CDTeca()
{
super(CDTeca, TAB_BORDER);
setDoubleBuffer(true);
}
public void onStart()
{
// now we get our client rect, excluding the border and the title
Rect r = getClientRect();
cdedit = new CDEdit();
cdedit.setRect(r);
cdsearch = new CDSearch();
cdsearch.setRect(r);
swap(cdsearch); // <-- here, the onStart method of CDSearch will be
called
}
}

At some point of the program, we will need to swap out the CDSearch container
and replace it with the CDEdit container. This can be done in various ways, such as:
1. Menu invocation: you create two menu options that, when chosen, swaps in the other
container.
2. At some event of cdsearch, it asks the main window to swap it out and swap in cdedit.
E.g.: MainWindow.getMainWindow().swap(CDTeca.cdedit). We can do this
because cdedit is a static member. If it was not a static member, we could do:
((CDTeca)MainWindow.getMainWindow()).cdedit to access the cdedit
member.
When you have only two or three containers that will be switched in the whole
application, you can use the TabPanel class to automate the swap for you. For example,
look at this:

SuperWaba Companion

96

TabPanel tp;
public void onStart()
{
tp = new TabPanel(new String[]{Edit,Search});
tp.setRect(getClientRect());
tp.setPanel(0, new CDEdit());
tp.setPanel(1, new CDSearch());
}

The TabPanel will automatically set control's bounds and call the onStart method.

It is recommended that your class extend Window instead of Container only when its
size will be smaller than the screen's size. Using Containers saves a lot of system
resources.
There are some useful methods in the Container class:

setBorderStyle: a container can have 4 kind of borders: BORDER_NONE,


BORDER_LOWERED, BORDER_RAISED, BORDER_SIMPLE.
getChildren: returns an array with all the controls directly added to the container.
broadcastEvent(Event e): it dispatches an event to all controls inside the
container, recursively. So, if there's a container inside the container, all controls
inside that container will be notified.
getClientRect: returns the area of this container excluding the borders, if any.

Finally, if you inherit the onColorsChanged method, be sure to call


super.onColorsChanged(colorsChanged) if your container has a border, otherwise
the border color will not be updated.

SuperWaba Companion

97

PART III INPUT & OUTPUT

SuperWaba Companion

98

Overview
The purpose of this part is to teach you how to use the classes in the waba.io
package. The classes that will be covered in this tutorial are outlined below:
a) waba.io.SerialPort: used to send and receive bytes via Serial cradle, USB, IrComm
and Bluetooth.
b) waba.io.Socket: used to send and receive bytes via a TCP/IP connection.
c) waba.io.File: used to create files and manage directories.
d) waba.io.Catalog: used to store data on the handheld
waba.io.ByteArrayStream: a resizable buffer that can be used to feed data to a
stream or to store data coming from a stream. It can be used to emulate a virtual
stream.
waba.io.DataStream: used to read/write primitive types and Strings.
waba.io.ResizeStream: used when creating a Catalog record of unknown size.
When output to the record is complete, the ResizeStream shrinks the record to the
optimal size.
waba.util.IntHashtable: used to speedup the search of a record inside a Catalog,
given a key representing the record contents. (Just a brief overview).
waba.io.Stream: is the main Class of all classes inside the waba.io package. It can
be viewed as a generic stream where data can flow in and out of the device. All
classes inside package waba.io extend this Class, and most classes receive a
waba.io.Stream in their constructor parameter. This allows you to combine different
streams to meet your needs.
For example, you can attach waba.io.ResizeStream to waba.io.Catalog and then
attach waba.io.DataStream to waba.io.ResizeStream, so you can store and retrieve
primitive types from the Catalog.
Another example is to use waba.io.DataStream attached to
waba.io.ByteArrayStream. This lets you write primitive types to a virtual stream, and then
send the buffer contents anywhere.
In the first chapter, youll see the methods inside waba.io.Stream; next the
waba.io.Catalog class is described in detail (chapter 2), followed by the
waba.io.DataStream. Then in chapter 4 youll see waba.io.ResizeStream, and in chapter 5
you will see waba.io.ByteArrayStream. Chapter 6 describes an approach to deal with
large databases in SuperWaba. In Chapter 7 you will see waba.io.Sockets, then
waba.io.SerialPort. After this, in chapter 9 you'll see waba.io.File and, finally, in the last
chapter you will learn some tricks and tips.

SuperWaba Companion

99

Chapter 17 - waba.io.Stream
Stream is an abstract class that all other classes inside the waba.io package
extend. It defines the behavior that a stream must have. Below are shown the list of
methods in this class:
boolean close() - Closes the stream.
int readBytes(byte[] buf, int start, int count) - Reads bytes from the stream.
int writeBytes(byte[] buf, int start, int count) - Writes bytes to the stream.
boolean isOpen() - Returns true if the stream is still open.

The Stream is used as a connector between waba.io classes. Most classes in that
package receive a Stream as a parameter to the constructor. This way, when you connect
the streams Catalog ResizeStream DataStream, the DataStream calls the
ResizeStream readBytes which in turn calls the Catalog readBytes. In the same way,
DataStream.close calls ResizeStream.close which calls Catalog.close.

SuperWaba Companion

100

Chapter 18 - waba.io.Catalog
Catalog is the most important class of this package. It lets you store persistent data
into the underlying Palm OS database system.
Starting in SuperWaba 3.0, the PDB file that the Catalog class represents was
made cross-platform. This means that a catalog created in Palm OS will be read in
Windows CE/Pocket PC, and vice-versa.
A catalog is the most rudimentary kind of database system. It is just an array of
records. Each record can have a distinct size. There are no user indexes, no table
definition, no field definition, nothing. Only you and your program know the format and the
contents of each record. From the operating systems point of view, the record content is
just raw data.
A PDB database has two components: First is an array of record handles that is
resized, as records are added/deleted. Second is the collection of chunks in the
database heap. If your database has all of its chunks the same size, then you might be
able to reduce the chance of memory fragmentation, but because all of the chunks in
the database heap can be moved around when unlocked, this isn't a huge concern
(although it might have problems on Palm OS 1.0 and 2.0, because fragmentation is
more of a problem with multiple 64K heaps).
The figure below shows the two possible kinds of catalogs:
Record 0
Record 1
Record 2
Record 3
Record 4
Record 5
All records same size

Record 0
Record 1
Record 2
Record 3
Record 4
Record 5
Each record of a different size

Theres no really performance loss when dealing with different record sizes.
Catalogs have some size restrictions:

The number of records is limited to 65536.


The records size is limited to 64Kb minus 24 bytes.

In Palm OS, the number of records, not the size of the file, mostly determines the
length of time a PDB file takes to install on the device. Having more records greatly
increases the time required for a hotsync with that database, even for installation or
backup. A 1MB PDB with 50 records would install much quicker than a 1MB PDB with
10,000 records. Consider this when creating big databases; youll probably drop your
hotsync time from several hours to a few minutes.

SuperWaba Companion

101

Starting in Palm OS 3.0, there is a new type of storage called File. Files can be greater
than 64Kb, but the truth is that files are emulated using a catalog. This makes the access
of data inside the File slower than if dealing directly with catalogs.
Below is shown a basic approach to deal with catalogs inside a program:

Open the catalog


Set the internal cursor to a record position
Store or retrieve data into/from the current record. Both operations advance the record
offset.
Go to 2, or close the catalog and finish.

Step 2 is needed because a catalog can have many records, and you must set the
current record before storing or retrieving data.
In the device, if the program does not explicitly close a catalog, it will be closed when
the object is garbage collected or when the program exits.
Note that this is not true under JDK, because under the JDK finalize does not work
well. In the desktop, if you dont close the catalog, nothing is written to disk. Starting with
version 3.2, the catalog is closed when the application exits normally. But if you abort the
Java appliction by pressing ^c in the DOS shell without explicitly closing the catalog,
nothing is saved).
Although the Catalog class has two constructors, only one is available for users:
public Catalog(String name, int mode)

In this constructor, you give the name of the catalog and the mode to open the
catalog. The available modes are READ_ONLY, WRITE_ONLY, READ_WRITE,
CREATE, which are self-explanatory. But there are some things you must know:
4. In all platforms, READ_ONLY, WRITE_ONLY, READ_WRITE, have all the
same effect. In Palm OS, since there are no concurrent operations, theres no
need to open it in exclusive modes. In Windows CE/32 and Symbian, the file
must be created in RW mode because the Catalog emulation has to save
information on the disk.
5. When CREATE is used,
a. If the catalog exists, it is not re-created, but remains the way it is and the
mode is changed to READ_WRITE.
b. If the catalog doesnt exist, it is created and the mode is changed to
READ_WRITE.
To test if a catalog exists, open it with READ_ONLY and call the isOpen method.
Now lets take a deeper look at the name parameter. It t may match the following
pattern:
name.CRTR.TYPE

SuperWaba Companion

102

5. name: must have at maximum 31 characters.


6. CRTR: must be the same creator ID of your application. You can get it from
Settings.appCreatorId (note that appCreatorId, when running on the desktop will be
as default, the automatically created one; it cannot guess the correct one if you
decided to change it to another one). The association of the creator ID of your
application with the database being created is needed because when the user
deletes an application from the device, all databases that have the same creator ID
of the application are also deleted. It must have four letters, because it is internally
stored as an integer.
7. TYPE: used to specify the type of the catalog. The most common type is DATA, but
you can give it any name. Must also have four letters, because it is internally stored
as an integer.
If CRTR and TYPE are both omitted, the applications creator ID and the DATA type
are used as default.
If running in desktop, you must provide the full pattern so the CRTR and TYPE are
compared against the existing ones in the Catalog being opened.
There is only one exception for using this pattern: when running an application at the
desktop with no user interface (by issuing waba.applet.JavaBridge.setNonGUIApp). In this
case, you may specify the full path to the file plus the CRTR and TYPE as parameter
(E.g.: "J:\\org\\superwaba\\palm\\MemoDB.memo.DATA").
Another very important observation: if youre planning to access the catalog from a
Conduit, you must make the name equal to the type (and, of course, it must have 4
letters).
The other no-argument constructor (public Catalog()) is for internal use only.
Next, will be shown in detail all the methods of the Catalog class, and a piece of
code that shows how to use it.
There are several actions that can be done in a catalog. Actions can be classified
as per Catalog and per Record. Next, we will examine the actions that can be done per
Catalog.

Useful tips
Some useful tips when dealing with databases:

If your record stores lots of information, put the relevant ones (the ones that may
be used in searches) in the beginning.
When storing dates that will be used as keys, store them as integers in the format
YYYYMMDD (E.g.: 19700325) as the first information of the record. With this, you
may keep the database ordered and do a binary search just by comparing the first
int.
See the methods findString and findInteger in this tutorial.

SuperWaba Companion

103

It's better to write lots of Strings in one record than only one String in different
records. The write and read times are less for the former.
The Catalog.inspectRecord is faster than a (Catalog.setRecordPos +
Catalog.readBytes).
If you want to save the state of your application when exiting, use
Settings.appSettings instead of writing them to a Catalog; its handier.
Dont call hashCode in arrays ([]) of objects or primitive data types: in
SuperWaba, if you call myArray.toString() or myArray.hashCode() youll
get a fatal error on the device.
Remember: writing for PDAs require you to do good software engineering. Dont
store unnecessary information on the PDA.
If you open a Catalog for read only, don't use Catalog ResizeStrem
DataStream, but attach the DataStream directly to the Catalog. You'll have a 6%
speed improvement.

addRecord
public int addRecord(int size)

Adds a record to the end of the catalog. If this operation is successful, the position
of the new record is returned and the current position is set to the new record. If it
is unsuccessful the current position is unset and -1 is returned.
Parameters:
size - the size in bytes of the record to add

The operation will be unsuccessful if:


The catalog is not opened.
The record could not be created (probably the record size was too big).
The record could not be locked.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
byte []b = new byte[2];
// Add the record in position 0
c.addRecord(2);
c.writeBytes(b,0,b.length);
// Add the record in position 1
c.addRecord(2);
c.writeBytes(b,0,b.length);
// Add the record in position 2
c.addRecord(2);
c.writeBytes(b,0,b.length);
}
c.close();

addRecord

SuperWaba Companion

104

public int addRecord(int size,


int pos)

Adds a record to the specified position of the catalog, shifting up all the other
records. If this operation is successful, the position of the new record is returned
and the current position is set to the new record. If it is unsuccessful the current
position is unset and -1 is returned.
Just as an historical note, this was the first method implemented in the very first
version of SuperWaba, on 06/30/2000.
Parameters:
size - the size in bytes of the record to add

The operation will be unsuccessful if:


The catalog is not opened.
The record could not be created (probably the record size was too big or the index
range is invalid).
The record could not be locked.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
byte []b = new byte[2];
// Add the record in position 0
c.addRecord(2,0);
c.writeBytes(b,0,b.length);
// Add the record in position 0, before the last inserted
c.addRecord(2,0);
c.writeBytes(b,0,b.length);
}
c.close();

close
public boolean close()

Closes the catalog. Returns true if the operation is successful and false otherwise.
Overrides:
close in class Stream

The operation will be unsuccessful if:


The catalog is not opened.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
...
}

SuperWaba Companion

105

c.close();

delete
public boolean delete()

Deletes the catalog. Returns true if the operation is successful and false otherwise.
Note that this behavior is different when running on the desktop and running on the
device, because in applets we cannot erase files on the server, in this case all the
records are deleted, but the file still exists, with the palm-info-header. The file will
be deleted only if you're running as an application on the desktop.

The operation will be unsuccessful if:


The catalog is not opened.
Palm OS internal errors: dmErrCantFind, dmErrCantOpen, memErrChunkLocked,
dmErrDatabaseOpen, dmErrROMBased, memErrInvalidParam,
memErrNotEnoughSpace.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.READ_WRITE);
if (c.isOpen())
c.delete();

listCatalogs
public static String[] listCatalogs()

Returns the complete list of existing catalogs, in the pattern name.CRTR.TYPE. If


no catalogs exist, this method returns null. In the desktop, it searches in the
already opened files and also the pdb files in the current "." directory.

The operation will be unsuccessful if:


No databases found.
Native stack overflow.
No memory available to create the String array.

Below is an example:
String []catalogs = Catalog.listCatalogs();
// need to check for null because some databases can't be
// read, thus null is returned in place
int n = catalogs.length;
for (int i = 0; i < n; i++)
// must test with null. Is this a SuperWaba application?
if (catalogs[i] != null && catalogs[i].endsWith("Wrp2"))
Vm.debug(catalogs[i]+ is a SW app!);

SuperWaba Companion

106

getRecordCount
public int getRecordCount()

Returns the number of records in the catalog or -1 if the catalog is not open.

The operation will be unsuccessful if:


the database is not open.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.READ_WRITE);
if (c.isOpen())
{
int n = c.getRecordCount();
for (int i = 0; i < n; i++)
if (c.setRecordPos(i))
{
...
}
}

isOpen
public boolean isOpen()

Returns true if the catalog is open and false otherwise. This can be used to check if
opening or creating a catalog was successful.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
...

rename
public boolean rename(String newName)

Renames the currently open catalog to the given name. You can use it to change
the creator and/or type if needed. The name must be in the form
"MyNewCatalogName.CRTR.TYPE".
On the desktop only, the old file may remain if deletion is not possible (in other
words, on the desktop the rename operation may work like a "copy oldName
newName").

The operation will be unsuccessful if:


The catalog is not opened.
The string is empty.
The string does not match the name pattern name.CRTR.TYPE
The catalog is being renamed to the memo MemoDB.memo.DATA

SuperWaba Companion

107

Here is an example of use:


Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
byte []b = new byte[2];
c.addRecord(2);
c.writeBytes(b,0,b.length);
c.rename("flor.CRTR.TYPe");
}
c.close();

setRecordPos
public boolean setRecordPos(int pos)

Sets the current record position and locks the given record. The value
-1 can be passed to unset and unlock the current record. If the operation is
successful, true is returned and the read/write offset is set to the beginning of the
record. Otherwise, false is returned.
Always test that the method return true.

The operation will be unsuccessful if:


The database is not open.
The given position is less than zero
The given position is greater than the number of records in the database.
The database is the memo record and the position is for the SuperWaba Debug
Console.
The record could not be locked.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.READ_WRITE);
if (c.isOpen())
{
int n = c.getRecordCount();
for (int i = 0; i < n; i++)
if (c.setRecordPos(i))
{
...
}
}

inspectRecord
public int inspectRecord(byte[] buf,
int recPosition)

Inspects a record. Use this method with care, as none of the parameters are
checked for validity. Neither the offset nor the current record positions are changed

SuperWaba Companion

108

by this method. This method must be used only for a fast way of viewing the
contents of a record, such as searching for a specific header or filling a grid of
data. buf.length bytes (at maximum) are read from the record into buf. Returns the
number of bytes read (can be different from buf.length if buf.length is greater than
the record size) or -1 if an error prevented the read operation from occurring.

The operation will be unsuccessful if:


The database is not open.
The record could not be queried (please note that the record can be locked when
using this function).
Below is an example:
int findInteger(int searchingFor)
{
Catalog c = new Catalog("guich.Crtr.Type",Catalog.READ_WRITE);
ByteArrayStream b = new ByteArrayStream(4);
DataStream ds = new DataStream(b);
int n = c.getRecordCount();
byte []buf = b.getBuffer(); // get the buffer
// do a search in the record
for (int i =0; i < n; i++)
if (c.inspectRecord(buf,i) >= 4 &&
ds.readInt() == searchingFor)
return i;
else
b.reset(); // reset the buffer offset
return 1;
}

getAttributes
public int getAttributes()

Retrieves this catalog's attributes. The DB_ATTR_xxx masks are used to retrieve
its states:
DB_ATTR_READ_ONLY: If set, the database is read-only.
DB_ATTR_APPINFODIRTY: If set, the database has been modified since last
hotsync.
DB_ATTR_BACKUP: If set, the database will be backed up in the next hotsync if
no application conduit is available.
DB_ATTR_OK_TO_INSTALL_NEWER: The backup conduit can install a newer
vesion of this database with a different name if the current database is open.
DB_ATTR_RESET_AFTER_INSTALL: The hotsync application forces a reset after
installing this database.
DB_ATTR_COPY_PREVENTION: Dont let this application be beamed or copied to
another device.
DB_ATTR_STREAM: This database is a file stream.

The operation will be unsuccessful if:


The database is not open.

SuperWaba Companion

109

Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.READ_WRITE);
if (c.isOpen())
{
int attr = c.getAttributes();
boolean isReadOnly = (attr & Catalog.DB_ATTR_READ_ONLY) != 0;
boolean isDirty
= (attr & Catalog.DB_ATTR_APPINFODIRTY) != 0;
boolean toBackup
= (attr & Catalog.DB_ATTR_BACKUP) != 0;
boolean canInstall = (attr & Catalog.DB_ATTR_OK_TO_INSTALL_NEWER) != 0;
boolean pleaseReset= (attr & Catalog.DB_ATTR_RESET_AFTER_INSTALL) != 0;
boolean cantCopy
= (attr & Catalog.DB_ATTR_COPY_PREVENTION) != 0;
boolean isStream
= (attr & Catalog.DB_ATTR_STREAM) != 0;
}

setAttributes
public void setAttributes(int attrs)

Sets this catalog's attributes, defined by the DB_ATTR_xxx constants. The original
attributes must be retrieved prior to applying this value. If not, you can lose your
database and your app will crash.

The operation will be unsuccessful if:


The database is not open.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.READ_WRITE);
if (c.isOpen())
c.setAttributes(Catalog.DB_ATTR_COPY_PREVENTION
| Catalog.DB_ATTR_BACKUP);

getRecordPos
public int getRecordPos()

Returns the current record position or -1 if there is no current record.


Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.READ_WRITE);
if (c.isOpen())
{
Vm.debug(Current record: +c.getRecordPos()); // will print -1
if (c.setRecordPos(2))
Vm.debug(Current record: +c.getRecordPos()); // will print 2
}

And now, well see the actions that can be done with the records.

SuperWaba Companion

110

getRecordSize
public int getRecordSize()

Returns the size of the current record in bytes or -1 if there is no current record.

The operation will be unsuccessful if:


The database is not open.
No record position is set.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
byte []b = new byte[2];
c.addRecord(2);
c.writeBytes(b,0,b.length);
Vm.debug(Current record has +getRecordSize()+ bytes);
}

resizeRecord
public boolean resizeRecord(int size)

Resizes a record. This method changes the size (in bytes) of the current record.
The contents of the existing record are preserved if the new size is larger than the
existing size. If the new size is less than the existing size, the contents of the
record are also preserved but truncated to the new size. Returns true if the
operation is successful and false otherwise.
Parameters:
size - the new size of the record

The operation will be unsuccessful if:


The database is not open.
No record position is set.
The given size is less than zero
The record could not be locked.
Theres not enough space to resize the record.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
byte []b = new byte[2];
c.addRecord(2);
c.writeBytes(b,0,b.length);
Vm.debug(Current record has +getRecordSize()+ bytes);
if (c.resizeRecord(8))
Vm.debug(Ok, we had memory to resize the record to 8 bytes!);
else
Vm.debug(Oops! No more memory...);

SuperWaba Companion

111

Vm.debug(And now has +getRecordSize()+ bytes);


}

deleteRecord
public boolean deleteRecord()

Deletes the current record and sets the current record position to -1. The record is
immediately removed from the catalog and all subsequent records are moved up
one position.

The operation will be unsuccessful if:


the database is not open.
No record position is set.
Internal Palm OS error codes: dmErrReadOnly, dmErrIndexOutOfRange,
dmErrNotRecordDB, memErrChunkLocked, memErrInvalidParam.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.READ_WRITE);
if (c.isOpen())
{
if (c.setRecordPos(2) && c.deleteRecord())
Vm.debug(Record 2 deleted. Now record 3 is record 2, record 4 is
record 3, etc.);
}

readBytes
public int readBytes(byte[] buf,
int start,
int count)

Read bytes from the current record into a byte array. Returns the number of bytes
actually read or -1 if an error prevented the read operation from occurring. After the
read is complete, the number of bytes written advances the offset of the current
record.
Overrides:
readBytes in class Stream
Parameters:
buf - the byte array to read data into
start - the start position in the array
count - the number of bytes to read

The operation will be unsuccessful if:


the database is not open.
No record position is set.
buf is null or start is less than zero or count is less than zero or the sum of start
plus count is greater than the records length.
The sum of the record offset with count is greater than the record length.

SuperWaba Companion

112

Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
byte []b = new byte[2];
b[0] = 11; b[1] = 22; // lets fill the array with something.
c.addRecord(2);
c.writeBytes(b,0,b.length);
c.setRecordPos(c.getRecordPos()); // reset the offset to the beginning
c.readBytes(b,0,b.length);
Vm.debug(Record store +b[0]+,+b[1]);
}

writeBytes
public int writeBytes(byte[] buf,
int start,
int count)

Writes to the current record. Returns the number of bytes written or -1 if an error
prevented the write operation from occurring. After the write is complete, the
number of bytes written advances the offset of the current record.
Overrides:
writeBytes in class Stream
Parameters:
buf - the byte array to write data from
start - the start position in the byte array
count - the number of bytes to write
You must make sure that the record is large enough to hold the contents you
want to write. If it does not have enough space, you must use resizeRecord before
to resize the record. This is done automatically when using waba.io.ResizeStream.

The operation will be unsuccessful if:


the database is not open.
No record position is set.
buf is null or start is less than zero or count is less than zero or the sum of start
plus count is greater than the records length.
The sum of the record offset with count is greater than the record length.
The devices memory is full or the record overflowed its maximum allowable size.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
byte []b = new byte[2];
c.addRecord(2);
c.writeBytes(b,0,b.length);
}

SuperWaba Companion

113

skipBytes
public int skipBytes(int count)

Changes the offset in the current record by the given number of bytes. The offset
defines where read and write operations start from in the record. Returns the
number of bytes actually skipped or -1 if an error occurs.
Parameters:
count - the number of bytes to skip. Can be less than zero.

The operation will be unsuccessful if:


the database is not open.
No record position is set.
The sum of the record offset with count is less than zero or is greater than the
record length.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
byte []b = new byte[2];
b[0] = 11; b[1] = 22; // lets fill the array with something.
c.addRecord(2);
c.writeBytes(b,0,b.length);
c.skipBytes(-2); // reset the offset to the beginning same effect
// as least example
c.readBytes(b,0,b.length);
Vm.debug(Record store +b[0]+,+b[1]);
}

getRecordOffset
public int getRecordOffset()

Returns the internal record offset. You may use this value in conjunction with
the skipBytes method. Note that setRecordPos resets the offset to 0.

The operation will be unsuccessful if:


the database is not open.
No record position is set.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
byte []b = new byte[2];
b[0] = 11; b[1] = 22; // lets fill the array with something.
c.addRecord(2);
c.writeBytes(b,0,b.length);
c.skipBytes(-c.getRecordOffset()); // reset the offset to the beginning
c.readBytes(b,0,b.length);
Vm.debug(Record store +b[0]+,+b[1]);
}

SuperWaba Companion

114

getRecordAttributes
public byte getRecordAttributes()

Retrieves the attributes of the current record. Use the REC_ATTR_xxx masks to
set/retrieve its states. Returns 0 if database doesnt exists.

The attributes are defined as below:


REC_ATTR_DELETE: Indicates that the record was deleted. This is used when
dealing with logical deletion, which does not occur in SuperWaba. In SuperWaba,
the record is deleted immediately. Note that after a record has its delete attribute
set you don't have access to it anymore (because it is deleted, you cant do a
setRecordPos in it).
REC_ATTR_DIRTY: Indicates that the record has been modified since last
hotsync.
REC_ATTR_SECRET: Indicates that the record is for private use only, and the
record will be available only if the user uses the Show private records.
The operation will be unsuccessful if:
the database is not open.
No record position is set.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.READ_WRITE);
if (c.isOpen())
{
if (c.setRecordPos(2))
{
int attr = c.getRecordAttributes();
boolean isDirty = (attr & Catalog.REC_ATTR_DIRTY) != 0;
boolean isSecret = (attr & Catalog.REC_ATTR_SECRET) != 0;
}
}

setRecordAttributes
public void setRecordAttributes(byte attr)

Sets the attributes of the current record. Use the REC_ATTR_xxx masks to
set/retrieve its states.

The operation will be unsuccessful if:


the database is not open.
No record position is set.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.READ_WRITE);

SuperWaba Companion

115

if (c.isOpen())
{
if (c.setRecordPos(2))
c.setRecordAttributes(Catalog.REC_ATTR_DIRTY | REC_ATTR_SECRET);
}

setRecordOffset
public void setRecordOffset(int ofs)

Sets the offset of the current record. It is equivalent to:


skipBytes(-getRecordOffset()+ofs).

The operation will be unsuccessful if:


the database is not open.
No record position is set.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.READ_WRITE);
if (c.isOpen())
{
if (c.setRecordPos(2))
c.setRecordOffset(10);
}

getName
public String getName()

Gets the name passed in the constructor.


Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.READ_WRITE);
String name = c.getName(); // "guich.Crtr.Type"

SuperWaba Companion

116

Chapter 19 - waba.io.DataStream
DataStream is a wrapper that you can place around any Stream such as a SerialPort,
Catalog, Socket, ByteArrayStream or ResizeStream, which lets you read and write
primitive SuperWaba data types like integers, floats, longs, doubles and Strings in a
simple and standardized manner.
Into the same record you can write integers, floats, longs, strings, or bytes, without the
need of a delimiter, as long as you read them back in the same order.
All methods that write values to the stream return the number of bytes written. For
example, the writeInt method returns 4 and writeDouble returns 8. This is useful to the
waba.io.ResizeStream class so it can know how many bytes the current record has and
expand/shrink as necessary. It may also be useful for you to do this control by yourself.
All Strings in SuperWaba are written and read in the Pascal format, with the length
first, followed by the char array. This approach was chosen because reading the length,
creating an array with that length and reading the char array at once is much faster than
reading byte per byte until the zero String end marker is found (like in the C format for
dealing with Strings). You must be aware of this because all other programs outside
SuperWaba (like servers, C programs and the internal databases as Memo, To-Do, etc)
use the C format.
The most common bug that happens when you read a String written in the C format
using the readString method (instead of the readCString one) is an out of memory
exception. This happens because the first two bytes, which would be letters, are
interpreted as the length of the String. Suppose you try to read SuperWaba\0. Su will
be read as the length of the String, in this case, 0x5375 = 21365 bytes!
The primitive data types are written in the big endian format (E.g.: 0x12345678 is
written as bytes 12 34 56 78), which is the format of the 68000 processor. Most other
programs, like the ones written for the Intel and Arm processors, use the little endian
format (E.g.: 0x12345678 is written as bytes 78 56 34 12). Be aware of this when
interchanging primitive types between platforms, like in TCP/IP and Serial connections,
and use the correct one (if you write using writeInt, read it using the analogous readInt).
To avoid the problems of compatibility mentioned above, it is recommended that you
always use the waba.io.DataStream to send and receive those primitives and Strings
between different platforms. You can use the following class to join the JDK and
SuperWaba streams. You can see the full class under the directory where this tutorial is.
public class JDKSWStream extends waba.io.Stream
{
/** Use this member to read or write primitive types. */
public waba.io.DataStream ds;
private java.io.InputStream is;
private java.io.OutputStream os;
/** Open the stream for input only */
public JDKSWStream(java.io.InputStream is)

SuperWaba Companion
{
this(is,null);
}
/** Open the stream for output only */
public JDKSWStream(java.io.OutputStream os)
{
this(null,os);
}
/** Open the stream for input and output */
public JDKSWStream(java.io.InputStream is, java.io.OutputStream os)
{
this.is = is;
this.os = os;
ds = new waba.io.DataStream(this);
}
/** Read from the input stream */
public int readBytes(byte buf[], int start, int count)
{
if (is != null)
try
{
is.read(buf,start,count);
return count;
}
catch (Exception e) {}
return -1;
}
/** Write to the output stream */
public int writeBytes(byte buf[], int start, int count)
{
if (os != null)
try
{
os.write(buf,start,count);
return count;
}
catch (Exception e) {}
return -1;
}
/** Close the underlying streams */
public boolean close()
{
try
{
if (is != null) is.close();
if (os != null) os.close();
} catch (Exception e) {}
return true;
}
}

And here is an example of how to use this class:


public static void main(String []args)
{
try
{

117

SuperWaba Companion

118

java.io.FileOutputStream fos;
java.io.FileInputStream fis;
JDKSWStream jss;
// create first a file and feed it with data
fos = new java.io.FileOutputStream("test1.dat");
jss = new JDKSWStream(fos);
jss.ds.writeInt(25031970);
jss.ds.writeDouble(3.1416);
jss.ds.writeString("I'm being serialized!");
jss.close();
// now read from this file and send it to another file.
// Note that the input/output could also be a serial or tcp/ip connection
fis = new java.io.FileInputStream("test1.dat");
fos = new java.io.FileOutputStream("test2.dat");
jss = new JDKSWStream(fis,fos);
// read the stored values
int myInt = jss.ds.readInt();
double myDouble = jss.ds.readDouble();
// and send them to another stream
jss.ds.writeInt(myInt);
jss.ds.writeDouble(myDouble);
// read and write directly. Just as example.
jss.ds.writeString(jss.ds.readString());
// Dump values and close.
System.out.println("int: "+myInt);
System.out.println("double: "+myDouble);
jss.close();
} catch (Exception e) {e.printStackTrace();}
}

Next we show all methods and constructors for the DataStream class:

DataStream Constructor
public DataStream(Stream stream)

Constructs a new DataStream, which sits upon the given stream using big endian
notation for multibyte values.
The current available streams that you can give as parameters are:
waba.io.Catalog, waba.io.SerialPort, waba.io.Socket, waba.io.ResizeStream and
waba.io.ByteArrayStream. The most common one is waba.io.ResizeStream,
because it makes the buffer grow when writing bytes. When reading bytes, you can
attach directly to any of the other classes.
Parameters:
stream - the base stream

close
public boolean close()

SuperWaba Companion

119

Closes the stream. This method simply calls the close method of the underlying
stream.
A very common mistake occurs when you call this close method, and also call
the streams close method. This is not necessary. For example, if you have a
DataStream directly attached to a Catalog, you can just call myDataStream.close().
Theres no need to call myCatalog.close(), because myDataStream.close() will call
myCatalog.close(). Note that this mistake is not harmful.
Overrides:
close in class Stream

pad
public int pad(int n)

Pads the stream writing n bytes. All bytes will be 0. This method is useful when you
want to clean the rest of the record, filling it with zeros. It is also useful when youre
using a DataStream object attached to a ResizeStream; in this case, you can make
sure that the record has a specific number of bytes. This last case is shown below.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
ResizeStream rs = new ResizeStream(c, 64);
DataStream ds = new DataStream(rs);
rs.startRecord();
int n = 0;
n += ds.writeString(Michelle);
n += ds.writeInt(25);
ds.pad(64-n);
// note: without the pad above, the endRecord below would shrink
// the record to 4+8+2 = 14 bytes.
rs.endRecord();
c.close();
}

skip
public void skip(int n)

Skips reading the next n bytes in the stream. Note that, contrary to the
Catalog.skipBytes method, this method does not skip backwards, only forward. For
example, in a socket connection theres no way to pull back the input data.
Parameters:
n - the number of bytes to skip
Below is an example:

SuperWaba Companion

120

SerialPort port = new SerialPort(0, 9600);


if (port.isOpen())
{
DataStream ds = new DataStream(port);
ds.skip(6); // skip first 6 bytes.

readBoolean
public boolean readBoolean()

Reads a boolean from the stream as a byte. True is returned if the byte is not zero,
false if it is zero.
Below is an example:
SerialPort port = new SerialPort(0, 9600);
if (port.isOpen())
{
DataStream ds = new DataStream(port);
boolean firstBoolean = ds.readBoolean();

readByte
public byte readByte()

Reads a single byte from the stream. The returned value will range from -128 to
127.
Below is an example:
SerialPort port = new SerialPort(0, 9600);
if (port.isOpen())
{
DataStream ds = new DataStream(port);
byte firstByte = ds.readByte();

readBytes
public int readBytes(byte[] buf,
int start,
int count)

Reads bytes from the stream. Returns the number of bytes actually read or -1 if an
error prevented the read operation from occurring.
Overrides:
readBytes in class Stream
Parameters:
buf - the byte array to read data into
start - the start position in the array
count - the number of bytes to read

SuperWaba Companion

121

Below is an example:
SerialPort port = new SerialPort(0, 9600);
if (port.isOpen())
{
DataStream ds = new DataStream(port);
byte []buf = new byte[16];
int read = ds.readBytes(buf,0,buf.length); // reads 16 bytes.

readBytes
public int readBytes(byte[] buf)

Reads bytes from the stream. Returns the number of bytes actually read or -1 if an
error prevented the read operation from occurring.
Parameters:
buf - the byte array to read data into

readFloat
public float readFloat()

Reads a float value from the stream as four bytes in IEEE 754 format.
Returns:
the float value
Below is an example:
SerialPort port = new SerialPort(0, 9600);
if (port.isOpen())
{
DataStream ds = new DataStream(port);
float firstFloat = ds.readFloat();

readIntLE
public int readIntLE()

Reads an integer using little endian from the stream as four bytes. The returned
value will range from -2147483648 to 2147483647.
Returns:
An integer
Below is an example:
SerialPort port = new SerialPort(0, 9600);
if (port.isOpen())
{

SuperWaba Companion

122

DataStream ds = new DataStream(port);


int firstLEInteger = ds.readIntLE();

readShortLE
public short readShortLE()

Reads a short from the stream as two bytes in the little endian format. The returned
value will range from -32768 to 32767.
Returns:
A short
Below is an example:
SerialPort port = new SerialPort(0, 9600);
if (port.isOpen())
{
DataStream ds = new DataStream(port);
short firstShortLe = ds.readShortLE();

readInt
public int readInt()

Reads an integer from the stream as four bytes. The returned value will range from
-2147483648 to 2147483647.
Returns:
An integer
Below is an example:
SerialPort port = new SerialPort(0, 9600);
if (port.isOpen())
{
DataStream ds = new DataStream(port);
int firstInt = ds.readInt();

readShort
public short readShort()

Reads a short from the stream as two bytes. The returned value will range from
-32768 to 32767.
Returns:
A short
Below is an example:
SerialPort port = new SerialPort(0, 9600);
if (port.isOpen())

SuperWaba Companion

123

{
DataStream ds = new DataStream(port);
short firstShort = ds.readShort();

readDouble
public double readDouble()

Reads a double in the IEEE 754 format.


Below is an example:
SerialPort port = new SerialPort(0, 9600);
if (port.isOpen())
{
DataStream ds = new DataStream(port);
double firstDouble = ds.readDouble();

readLong
public long readLong()

Reads a long from the stream.


Below is an example:
SerialPort port = new SerialPort(0, 9600);
if (port.isOpen())
{
DataStream ds = new DataStream(port);
long firstLong = ds.readLong();

readUnsignedByte
public int readUnsignedByte()

Reads a single unsigned byte from the stream. The returned value will range from
0 to 255. Note that the unsigned byte is stored in an integer (otherwise it could not
be unsigned).
Below is an example:
SerialPort port = new SerialPort(0, 9600);
if (port.isOpen())
{
DataStream ds = new DataStream(port);
int firstUnsignedByte = ds.readUnsignedByte();

readUnsignedShort

SuperWaba Companion

124

public int readUnsignedShort()

Reads an unsigned short from the stream as two bytes. The returned value will
range from 0 to 65535. As the unsigned byte, the result is also stored in an integer.
Returns:
A short (stored in an integer)
Below is an example:
SerialPort port = new SerialPort(0, 9600);
if (port.isOpen())
{
DataStream ds = new DataStream(port);
int firstUnsignedShort = ds.readUnsignedShort();

writeIntLE
public int writeIntLE(int i)

Writes an integer to the stream in little-endian format as four bytes.


Parameters:
i - the integer to write
Returns:
the number of bytes written
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
DataStream ds = new DataStream(c);
int n = 0;
c.addRecord(4); // number of bytes that will be written
int myInt = 0x12345678;
n += ds.writeIntLE(myInt);
c.close();
Vm.debug(Total of +n+ bytes written);
}

writeShortLE
public int writeShortLE(int i)

Writes a short to the stream as two bytes in little-endian format. As there is no


short type in Waba but we often want to use only two bytes in storage. An int is
used but the upper two bytes are ignored.
Parameters:
i - the short to write
Returns:
the number of bytes written
Below is an example:

SuperWaba Companion

125

Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);


if (c.isOpen())
{
DataStream ds = new DataStream(c);
int n = 0;
c.addRecord(2); // number of bytes that will be written
int myShort = 0x1234;
n += ds.writeIntLE(myInt);
c.close();
Vm.debug(Total of +n+ bytes written);
}

writeBoolean
public int writeBoolean(boolean bool)

Writes a boolean to the stream as a byte. True values are written as 1 and false
values as 0.
Parameters:
b - the boolean to write
Returns:
the number of bytes written
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
DataStream ds = new DataStream(c);
int n = 0;
c.addRecord(2); // number of bytes that will be written
boolean iAmHappy = true;
boolean iAmRich = false;
n += ds.writeBoolean(iAmHappy);
n += ds.writeBoolean(iAmRich);
c.close();
Vm.debug(Total of +n+ bytes written);
}

writeByte
public int writeByte(byte by)

Writes a single byte to the stream.


Parameters:
b - the byte to write
Returns:
The number of bytes written
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{

SuperWaba Companion

126

DataStream ds = new DataStream(c);


int n = 0;
c.addRecord(2); // number of bytes that will be written
byte byte1 = (byte)1;
byte byte2 = (byte)2;
n += ds.writeByte(byte1);
n += ds.writeByte(byte2);
c.close();
Vm.debug(Total of +n+ bytes written);
}

writeByte
public int writeByte(int by)

Writes a single byte to the stream. In this method an integer is used instead of a
byte.
Parameters:
b - the byte to write (only least significant byte is written)
Returns:
the number of bytes written
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
DataStream ds = new DataStream(c);
int n = 0;
c.addRecord(1); // number of bytes that will be written
int byte1 = 100;
n += ds.writeByte(byte1);
c.close();
Vm.debug(Total of +n+ bytes written);
}

writeBytes
public int writeBytes(byte[] buf,
int start,
int count)

Writes bytes to the stream. Returns the number of bytes actually written or -1 if an
error prevented the write operation from occurring.
Overrides:
writeBytes in class Stream
Parameters:
buf - the byte array to write data from
start - the start position in the byte array
count - the number of bytes to write
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);

SuperWaba Companion

127

if (c.isOpen())
{
DataStream ds = new DataStream(c);
int n = 0;
byte []bytes = new byte[16];
for (int i = 0; i < bytes.length; i++)
bytes[i] = (byte)i;
c.addRecord(bytes.length); // number of bytes that will be written
n += ds.writeBytes(bytes,0,bytes.length);
c.close();
Vm.debug(Total of +n+ bytes written);
}

writeBytes
public int writeBytes(byte[] buf)

Writes bytes to the stream. Returns the number of bytes actually written or -1 if an
error prevented the write operation from occurring.
Parameters:
buf - the byte array to write data from
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
DataStream ds = new DataStream(c);
int n = 0;
byte []bytes = new byte[16];
for (int i = 0; i < bytes.length; i++)
bytes[i] = (byte)i;
c.addRecord(bytes.length); // number of bytes that will be written
n += ds.writeBytes(bytes);
c.close();
Vm.debug(Total of +n+ bytes written);
}

writeFloat
public int writeFloat(float f)

Writes a float value to the stream as four bytes in IEEE 754 format
Parameters:
f - the float to write
Returns:
the number of bytes written
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
DataStream ds = new DataStream(c);

SuperWaba Companion

128

int n = 0;
c.addRecord(4); // number of bytes that will be written
float myFloat = 123.456f;
n += ds.writeFloat(myFloat);
c.close();
Vm.debug(Total of +n+ bytes written);
}

writeInt
public int writeInt(int i)

Writes an integer to the stream as four bytes.


Parameters:
i - the integer to write
Returns:
the number of bytes written
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
DataStream ds = new DataStream(c);
int n = 0;
c.addRecord(4); // number of bytes that will be written
int myInt = 100000;
n += ds.writeByte(myInt);
c.close();
Vm.debug(Total of +n+ bytes written);
}

writeShort
public int writeShort(int i)

Writes a short to the stream as two bytes. There is no short type in Waba but we
often want to use only two bytes in storage. An int is used but the upper two bytes
are ignored.
Parameters:
i - the short to write
Returns:
the number of bytes written
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
DataStream ds = new DataStream(c);
int n = 0;
c.addRecord(1); // number of bytes that will be written
short myShort = (short)32000;
n += ds.writeShort(myShort);

SuperWaba Companion
c.close();
Vm.debug(Total of +n+ bytes written);
}

writeDouble
public int writeDouble(double d)

Writes a double in the IEEE 754 format in 8 bytes.


Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
DataStream ds = new DataStream(c);
int n = 0;
c.addRecord(8); // number of bytes that will be written
double pi = 3.141592654;
n += ds.writeDouble(pi);
c.close();
Vm.debug(Total of +n+ bytes written);
}

writeLong
public int writeLong(long l)

Writes a long in 8 bytes.


Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
DataStream ds = new DataStream(c);
int n = 0;
c.addRecord(8); // number of bytes that will be written
long myLong = 0x123456789ABCDEF0L;
n += ds.writeLong(myLong);
c.close();
Vm.debug(Total of +n+ bytes written);
}

readString
public String readString()

Reads a String, converting from bytes to java format using the current
waba.sys.CharacterConverter.

129

SuperWaba Companion

130

Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.READ_WRITE);
if (c.isOpen())
{
DataStream ds = new DataStream(c);
String s1 = ds.readString();
String s2 = ds.readString();
String s3 = ds.readString();
c.close();
}

readStringArray
public String[] readStringArray()

Reads an array of Strings. Note: to use this method, the String array must have
been written using the writeStringArray method in this class.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.READ_WRITE);
if (c.isOpen())
{
DataStream ds = new DataStream(c);
String []as = ds.readStringArray();
if (as == null)
Vm.debug(Empty String array was readen);
else
Vm.debug(The array contains +as.length+ strings);
c.close();
}

writeString
public int writeString(String s)

Writes the String into the stream, converting it from international format to a byte
array using the current waba.sys.CharacterConverter. The String is written by writing a
short with the byte array size and followed by the byte array itself.
A null String is written as 2 consecutive zeros.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
int n = 0;
ResizeStream rs = new ResizeStream(c,128);
DataStream ds = new DataStream(rs);
rs.startRecord();
n += ds.writeString(SuperWaba);
n += ds.writeString(The REAL Power);

SuperWaba Companion

131

n += ds.writeString(Of portable computing);


rs.endRecord();
c.close();
Vm.debug(Total of +n+ bytes written);
}

writeStringArray
public int writeStringArray(String[] v)

Writes the string array into the stream. The length of the array is stored in the first
2 bytes (as a short) and the strings are stored in sequence.
A null array is written as 2 consecutive zeros.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
int n = 0;
ResizeStream rs = new ResizeStream(c,128);
DataStream ds = new DataStream(rs);
rs.startRecord();
String []as = {SuperWaba,The REAL Power,Of Portable Computing};
n += ds.writeStringArray(as);
rs.endRecord();
c.close();
Vm.debug(Total of +n+ bytes written);
}

readCString
public String readCString()

Reads a C-style string from the stream. This is a NUL (0) terminated series of
characters. This format is commonly used by other Palm applications. Note: if
you're creating your own stream, choose readString instead of readCString,
because readCString is much slower. Also, this method does not handle
international characters correctly.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.READ_WRITE);
if (c.isOpen())
{
DataStream ds = new DataStream(c);
String s1 = ds.readCString();
String s2 = ds.readCString();
String s3 = ds.readCString();
c.close();
}

SuperWaba Companion

132

writeCString
public int writeCString(String s)

Writes a C-style string to the stream. This means that all the characters of the
string are written out, followed by a NUL (0) character. This format is commonly
used by other Palm applications. Note: if you're creating your own stream, choose
writeString instead of writeCString, because writeCString is much slower. Also, this
method does not handle international characters correctly.
Parameters:
s - the string to write
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
int n = 0;
ResizeStream rs = new ResizeStream(c,128);
DataStream ds = new DataStream(rs);
rs.startRecord();
n += ds.writeCString(SuperWaba);
n += ds.writeCString(The REAL Power);
n += ds.writeCString(Of portable computing);
rs.endRecord();
c.close();
Vm.debug(Total of +n+ bytes written);
}

SuperWaba Companion

133

Chapter 20 - waba.io.ResizeStream
The ResizeStream class is very useful when youre dealing with Catalogs in SuperWaba.
A Catalog can resize its record as needed, and because the device has very limited
memory, in general your applications do not write fixed size records. The ResizeStream
class is very handy to help you create variable sized records.
It works as described below:

You call startRecord. This will create a new record with the specified initial size.
You keep writing bytes to it.
Before transferring the bytes to the record, its current size is checked.
If the record needs to grow, ResizeStream calls Catalog.resizeRecord to get more
space.
When the record is finished, you call endRecord; it then shrinks the record to the exact
amount of bytes written.

It has only one constructor:


public ResizeStream(Catalog cat, int initialSize)
In this constructor you give the underlying Catalog to be used, and also the initial size of
the record. All records created will have the specified initial size (in bytes).
Be careful with the initialSize parameter. In most cases, you can estimate how many
bytes your record will have. If you specify a very large parameter (E.g.: 8000), the device
will probably have trouble when allocating such large records, and it will fragment the
memory when you shrink it. On the other hand, if you specify a size that is too small
(compared to what will be written), the ResizeStream class will need to grow the record
many times to accommodate all the data.
The initialSize parameter is also used as the increment step when the buffer needs to
grow. The buffer is expanded until the total memory required is allocated.
Theres no need to use ResizeStream when reading data from a Catalog; it is
useless but not harmful. The data will be read normally, as if there were no ResizeStream
at all.
A ResizeStream is commonly used with waba.io.DataStream, because in most records a
String is written and in general the Strings are variable length.
Next we will see the methods for this class.

SuperWaba Companion

134

startRecord
public boolean startRecord(int pos)

Inserts the record at the specified position in the Catalog. If the position is greater
than the number of records in the Catalog, then the record is added at the end.
Returns:
true if operation was successful, false otherwise.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
ResizeStream rs = new ResizeStream(c,128);
DataStream ds = new DataStream(rs);
// start a new record inserting it at position 0
rs.startRecord(0);
ds.writeCString(SuperWaba);
ds.writeCString(The REAL Power);
ds.writeCString(Of portable computing);
rs.endRecord();
c.close();
}

startRecord
public boolean startRecord()

Append a new record to the catalog.


Returns:
true if operation was successful, false otherwise.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
ResizeStream rs = new ResizeStream(c,128);
DataStream ds = new DataStream(rs);
// append a new record to the end of the Catalog
rs.startRecord();
ds.writeCString(SuperWaba);
ds.writeCString(The REAL Power);
ds.writeCString(Of portable computing);
rs.endRecord();
c.close();
}

restartRecord
public boolean restartRecord(int pos)

SuperWaba Companion

135

Restart writing the record in the given pos. If pos is greater than the size of the
stream, the record is appended.
This method is useful when you want to overwrite an existing record.
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
ResizeStream rs = new ResizeStream(c,128);
DataStream ds = new DataStream(rs);
// overwrite record 0.
rs.restartRecord(0);
ds.writeCString(SuperWaba);
ds.writeCString(The REAL Power);
ds.writeCString(Of portable computing);
rs.endRecord();
c.close();
}

endRecord
public void endRecord()

Must be called after the record is finished so it can be shrunk.


Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
ResizeStream rs = new ResizeStream(c,128);
DataStream ds = new DataStream(rs);
rs.startRecord();
ds.writeCString(SuperWaba);
ds.writeCString(The REAL Power);
ds.writeCString(Of portable computing);
// ok, everything written, now lets finish this record
rs.endRecord();
c.close();
}

readBytes
public int readBytes(byte[] buf,
int start,
int count)

This method simply reads the bytes from the associated catalog.
This method just calls catalog.readBytes. Nothing special is done.

SuperWaba Companion

Overrides:
readBytes in class Stream
Parameters:
buf - the byte array to read data into
start - the start position in the array
count - the number of bytes to read
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.READ_WRITE);
if (c.isOpen())
{
ResizeStream rs = new ResizeStream(c, 2);
DataStream ds = new DataStream(rs);
// Here ds.readString calls DataStream.readBytes, which in turn
// calls ResizeStream.readBytes which calls Catalog.readBytes.
// The ResizeStream here is useless but not harmful.
String oneString = ds.readString();
c.close();
}

writeBytes
public int writeBytes(byte[] buf,
int start,
int count)

writes to the buffer, growing the record if necessary.


Overrides:
writeBytes in class Stream
Parameters:
buf - the byte array to write data from
start - the start position in the byte array
count - the number of bytes to write
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
byte []b = new byte[8]; // filled with zeros.
ResizeStream rs = new ResizeStream(c, 2);
rs.startRecord();
// because the buffer started with 2, it will grow 3 times to
// accommodate the 8 bytes buffer.
rs.writeBytes(b,0,b.length);
rs.endRecord();
c.close();
}

close
public boolean close()

136

SuperWaba Companion

137

Closes the catalog. This method does exactly that: calls the method close in the
Catalog class. So, its not necessary to call this method and the Catalogs close
method.
Overrides:
close in class Stream
Below is an example:
Catalog c = new Catalog("guich.Crtr.Type",Catalog.CREATE);
if (c.isOpen())
{
ResizeStream rs = new ResizeStream(c,128);
DataStream ds = new DataStream(rs);
rs.startRecord();
ds.writeString(SuperWaba);
rs.endRecord();
// lets close the catalog.
rs.close();
}

SuperWaba Companion

138

Chapter 21 - waba.io.ByteArrayStream
The ByteArrayStream is commonly used as a buffer. Sometimes, it is faster or less
resource consuming to send more data at once. For example, when youre using sockets,
its far faster to send 50kb of data at once instead of 10 packets of 5kb each. So, you add
all the data to a ByteArrayStream and after that you send its buffer to the socket (or
SerialPort or Catalog).
When writing to the buffer, it expands dynamically as needed (at a 20% rate).
A ByteArrayStream must not be used for read and write operations at the same time.
You must read or write to it. When you use it as a write-only buffer, each time the
writeBytes method is called, an internal cursor position is advanced. When you use it as a
read-only buffer, the same position is also advanced. So, theres only one position
variable for both operations. If you want to write 10 bytes and after this read them, you
must call the reset method to reset the cursor position to 0.

Below are some examples of use:


2. Image.saveBmp uses a DataStream passed as parameter to save the bitmap. You can
attach a DataStream to a ByteArrayStream and then use the buffer to send the full
bitmap somewhere. See SuperWabaSDK/samples/ui/painter/Painter.java.
3. Suppose you receive a byte array from somewhere (maybe from the method
Catalog.inspectRecord) and want to parse its contents using DataStream. You can
wrap the byte array in a ByteArrayStream and attach a DataStream to it. Then, just
read the primitive data from the DataStream. See
SuperWabaSDK/src/java/waba/io/NativeMethods4JDK.java method fromPdb for an
example.
4. There is a separate library, called CatalogSearch, which is sold at the SuperWaba site.
This library is used to do fast sequential searches in a Catalog (it's 5 to 10 times faster
than in Java). You use ByteArrayStream with a DataStream to set the data to be
searched.
5. If you have a socket client that is communicating with a server, and the server sends
you an http header plus the information, you can use the ByteArrayStream to get the
bytes from the server, and make it behave like a pushback stream.
The ByteArrayStream has two constructors:

public ByteArrayStream(byte []buffer) : This constructor is used when you already


have an array of bytes filled with data and want to use it as the input buffer.
public ByteArrayStream(int size) : This constructor receives the initial size of a byte
buffer that will be created.

Next we will see the methods of this class.

SuperWaba Companion

139

close
public boolean close()

This method does nothing. Theres really no need to close a ByteArrayStream. It


should set the buffer to null to let the GC work, but if you do this, the Catalog class
will stop working.
Overrides:
close in class Stream

getBuffer
public byte[] getBuffer()

Gets the currently allocated buffer.


The size of the buffer may be different from the array length. You can get the
number of valid bytes written in the buffer with the count method.
Below is an example:
int findString(String searchingFor)
{
Catalog c = new Catalog("guich.Crtr.Type",Catalog.READ_WRITE);
// create a buffer that will be expanded to the size of the string
// were searching for
ByteArrayStream bas = new ByteArrayStream(2);
DataStream ds = new DataStream(bas);
// Store the string in the buffer to make its size the same
// because inspectRecord reads up to the size of the buffer.
ds.writeString(searchingFor);
int len = bas.count();
// reset the buffer so we can use it again
bas.reset();
int n = c.getRecordCount();
byte []buf = bas.getBuffer(); // get the buffer
// do a search in the record
for (int i =0; i < n; i++)
if (c.inspectRecord(buf,i) == len &&
ds.readString().equals(searchingFor))
return i;
else
bas.reset(); // reset the buffer position
return 1;
}

count
public int count()

Returns the current internal cursor position. If the buffer is being used as writeonly, this method will return the number of bytes written to the buffer. If the buffer is
being as read-only, this method will return the number of bytes read at the moment.

SuperWaba Companion

140

Below is an example:
// create the image and fill it with something
Image img = new Image(160,160);
Graphics g = img.getGraphics();
for (int i =0; i < 16; i++)
{
g.setBackColor(new Color(10*i,10*i,10*i));
g.fillRect(i*10,0,10,160);
}
// save the bmp in a ByteArrayStream
ByteArrayStream bas = new ByteArrayStream(4096);
DataStream ds = new DataStream(bas);
img.createBmp(ds);
// get how many bytes the image occupies.
int totalBytesWritten = bas.count();

readBytes
public int readBytes(byte[] buf,
int start,
int count)

Transfers count bytes from the internal class buffer to buf. The start parameter
indicates where to start writing in the array buf.
Does not perform range checking! Use this method with care!
Overrides:
readBytes in class Stream
Returns:
the number of bytes readen.
Below is an example:
ByteArrayStream bas = new ByteArrayStream(16);
DataStream ds = new DataStream(bas);
ds.writeByte(1);
ds.writeByte(2);
ds.writeByte(3);
ds.writeByte(4);
byte []b = new byte[4];
bas.reset();
bas.readBytes(b,0,4); // just read the stored bytes.

reset
public void reset()

Resets the internal cursor position to 0 so the buffer can be reused.


Below is an example:

SuperWaba Companion

141

ByteArrayStream bas = new ByteArrayStream(16);


DataStream ds = new DataStream(bas);
ds.writeString(SuperWaba);
// reset the position so we can read what we wrote
bas.reset();
String theBest = ds.readString();

skipBytes
public int skipBytes(int count)

Skips the number of bytes from the current position. It may be < than 0. Returns the
number of bytes skipped, or -1 if error.
Below is an example:
ByteArrayStream bas = new ByteArrayStream(16);
DataStream ds = new DataStream(bas);
ds.writeString(SuperWaba);
ds.writeInt(1234);
// reset the position so we can read what we wrote
bas.reset();
// skip the string, reading its size and skipping the rest
bas.skipBytes(ds.readUnsignedShort()*2); // char = 2 bytes
int theNumber = ds.readInt();

reuse
public void reuse()

Reuses the already read part of the buffer. This method shifts the buffer from the
current position to 0, so you can reuse the buffer, avoid exceeding the memory
limits.
Below is an example:
ByteArrayStream bas = new ByteArrayStream(60000);
bas.writeBytes(new byte[60000]);
bas.reset();
bas.readBytes(new byte[50000]); // read only 50000 bytes.
bas.reuse(); // here the bytes at 50000 to 59999 are
// shifted to positions 0 to 9999, and
// the rest of the buffer is now available

writeBytes
public int writeBytes(byte[] buf,
int start,
int count)

This writes to the byte array, expanding it as necessary.


Returns:
The number of bytes written.

SuperWaba Companion

Overrides:
writeBytes in class Stream
Parameters:
buf - the byte array to write data from
start - the start position in the byte array
count - the number of bytes to write
Below is an example:
ByteArrayStream bas = new ByteArrayStream(16);
DataStream ds = new DataStream(bas);
byte []buf = {(byte)1, (byte)2, (byte)3, (byte)4};
// writes the buf to the ByteArrayStream
bas.writeBytes(buf,0,4);
bas.reset();
int = ds.readInt(); // read 1 2 3 4 as an int

available
public int available()

Returns the number of bytes available from the actual read position,
computed from buffer.length-pos.
Below is an example:
ByteArrayStream bas = new ByteArrayStream(16);
DataStream ds = new DataStream(bas);
byte []buf = {(byte)1, (byte)2, (byte)3, (byte)4};
// writes the buf to the ByteArrayStream
bas.writeBytes(buf,0,4);
bas.reset();
int = ds.readShort(); // read 1 2
int avail = bas.available(); // return 2 (bytes available)

142

SuperWaba Companion

143

Chapter 22 - Dealing with large databases


PDAs are very limited devices: they have a small memory and slow CPUs. Some users
often forget this and try to send huge amount of data to the PDA. Because SuperWaba is
relatively slow compared with the C programming language, it is necessary to take some
further precautions to make your application run smoothly.
For example, suppose you have a database of 3000 records stored on the PDA. If your
database is ordered, great, you can do a binary search to find the record. Otherwise,
youll need to do a linear search.
Its unfeasible to do a linear search of the Catalog in Java. There is a separate library
(available at the SuperWaba site) that does that search in C, and the results are 5 to 10
times faster than in Java. But theres a fee (although small, US$19.95) to get it. If you
dont want to pay for it, you still have an alternative.
Starting in SuperWaba 4.0, there's a Litebase, where you can manipulate PDBs
using SQL. Some searches are 20 times faster than the catalog search library.
To deal with large unordered databases, the best idea is to make an index to the records.
If youre storing just strings, storing each record with only one String, the best approach is
to make the Strings hashCode the key. If youre not storing Strings, but some other kind
of data, you can try to create the key by using the same hashCode function of String, but
slightly modified:
public int customHashCode(byte []ac)
{
int i = 0;
int j = 0;
int k = ac.length;
for (int l = 0; l < k; l++)
i = (i<<5)-i + ac[j++];
return i;
}

Note that this may not lead to unique identifiers for all records in your database; youll
need to test it (using equals) before use.
Once you get a key that uniquely identifies your record, you can use the
waba.util.IntHashtable class. This class uses an integer as the hash value and the stored
value is also an integer. In our case, the value will be the position of the record in the
Catalog. Of course, this approach needs to make sure that the database will not be
modified (a static database, such as a dictionary). The good news is that the search will
have retrieval complexity of O(1): it will be instantaneous.
To create the indexes of the static database, you can run SuperWabas class at the
desktop. Then you just synchronize the index to the PDA.
The following functions can be used to create the index database, read again the
IntHashtable and search for a String.

SuperWaba Companion

144

public boolean callCreateIndex()


{
Catalog dataCat = new Catalog("Dictionary."+Settings.appCreatorId
+".DATA", Catalog.READ_ONLY);
Catalog indexCat = new Catalog("Dictionary."+Settings.appCreatorId
+".INDX", Catalog.READ_ONLY);
if (indexCat.isOpen()) // make sure the catalog is empty
{
indexCat.delete();
indexCat = new Catalog("Dictionary."+Settings.appCreatorId+".INDX",
Catalog.CREATE);
}
if (dataCat.isOpen() && indexCat.isOpen())
return createIndex(dataCat, indexCat);
return false;
}
// if possible, this method should be run only at the desktop
public boolean createIndex(Catalog dataCat, Catalog indexCat)
{
int n = dataCat.getRecordCount();
IntHashtable ih = new IntHashtable(n*13/10); // grows the hashtable
// parse the input
DataStream ds = new DataStream(dataCat);
for (int i =0; i < n; i++)
if (dataCat.setRecordPos(i))
{
// here we're reading a String. You may change this to any other
// type of data and change the hashCode below to the
// customHashCode function described before
String s = ds.readString();
int key = s.hashCode();
boolean keyIsUnique = ih.put(key, i) != IntHashtable.INVALID;
if (!keyIsUnique)
return false;
}
// create the index catalog
ds = new DataStream(indexCat);
ih.saveTo(ds);
dataCat.close();
indexCat.close();
return true;
}
// reads the previously stored IntHashtable with the indexes
public IntHashtable readIndex(Catalog indexCat)
{
DataStream ds = new DataStream(indexCat);
return new IntHashtable(ds);
}
// returns the position of the String s in the catalog or -1 if not found
public int getPosition(String s, IntHashtable keys)
{
int key = s.hashCode();
int pos = keys.get(key);
if (pos != IntHashtable.INVALID && pos >= 0)
return pos;
return -1;
}

SuperWaba Companion

145

Chapter 23 waba.io.Socket
The Socket class is one of the most useful classes of SuperWaba: it enables you to
open TCP/IP connections from your PDA. Of course, to do this, your PDA must have a
modem, attached or embedded on it. Although powerful, it is also a big source of
headaches, since it will rely on each device characteristics, and sometimes this can be a
real pain.
Next are some examples of devices that you can use to open Socket connections
in SuperWaba:

A Palm Vx with an external modem attached


A Pocket PC with an external modem
A Pocket PC placed on the cradle.
A Kyocera: it was the first Palm OS device that was also a CDMA phone. So, you
could open a socket anywhere you were.
A Tungsten W, which has an internal modem
A Tungsten T speaking via InfraRed or Bluetooth with an Ericsson or Siemens cell
phone.

In most cases, using sockets is something simple: first, you have to setup your
phone and select the provider address, the phone destination, etc. Then, you just open
the socket; it will dial the number and connect. Then you send and receive bytes based
on a protocol, and then close and disconnect. In nearly all cases, it is not a good idea to
keep the line open, since you (or someone else) will be paying for that. Unless, of course,
a GPRS connection is used (GPRS connections are based in the number of bytes
sent/received, not on the open time).
When you create a Socket object for the first time, a system dialog will appear
saying something like connecting.... Then, if the connection is successful, it will close
and control will return to your program.
Under Java and Windows CE, if no network is present, the socket constructor may
hang for an extended period of time due to the implementation of sockets in the
underlying OS. This is a known problem.
You cannot open a socket before the main event loop. In other words, you cannot
open a socket in the app's constructor, or even in the onStart method. The socket can
only be openned after the onStart method finishes. You may setup a timer in the onStart
that, when called, opens the socket. Or maybe open it in the onWindowPaintFinished
method. Or simply open the socket after a button press.
Palm OS devices can't open a socket connection when the PDA is in the cradle. But
this can be easily done with Windows CE devices.
There's a class, superwaba.ext.ce.io.gprs.GPRS that can be used to open GPRS
connections on Pocket PC 2002 Smartphones.

SuperWaba Companion

146

Let's now see the constructors of the Socket class:

Socket(): this constructor is protected, and is used by the JDK emulation.


Socket(String host, int port, int timeout, boolean noLinger): connects to the given
host, using the given port, timeout in milliseconds for the open procedure (set to -1
to wait forever). The noLinger parameter is used in PalmOS only: If set to true, the
close method will not wait for a response from the server to really close the
connection. If set to false, a response from the server is required to really close the
connection, and you'll probably have problems opening more than 16 connections.
Socket(String host, int port, int timeout): same of Socket(host, port, timeout, false).
Socket(String host, int port): same of Socket(host,port, 1500, false).
Here are the methods available in the Socket class:

close
public boolean close()

This method closes the logical socket connection. Note that in most cases, calling
close is not enough to disconnect the modem. This happens because there may
exist more than one socket open at the same time. If close is not called, the socket
will be closed by the garbage collector when the object gets collected.

isOpen
public boolean isOpen()

Used to verify if the socket was successfully opened. If isOpen returns false, you
may want to check the lastError variable (described ahead).

setReadTimeout
public boolean setReadTimeout(int millis)

Sets the time in which the socket will wait for something to be read until it returns
the control to the program. A good practice is to set a small timeout, and retry the
read a couple of times.

readBytes
public int readBytes(byte[] buf,
int start,
int count)

Reads the given number of bytes from the open socket connection. It returns the
number of bytes really read, which may be smaller than the requested one.

SuperWaba Companion

147

writeBytes
public int writeBytes(byte[] buf,
int start,
int count)

Writes the given number of bytes from the open socket connection. It returns the
number of bytes really written, which may be smaller than the sent one.

disconnect
public boolean disconnect()

Disconnects the modem, closing all open socket connections.

There are also two important members in the Socket class:

refreshBeforeEachRead
boolean refreshBeforeEachRead

When set to true, the function NetLibConnectionRefresh (Palm OS only) will be


called before each read/write operation. This can be useful when the device is
turned off with a socket open. When the device is turned on again, the physical
connection is gone, only the logical connection is available. To recreate the
physical connection, NetLibConnectionRefresh must be called, which is always
done when this flag is true.
Note that setting this flag to true makes read and write operations 3 times slower.
You can set to true/false anytime, after the creation of the socket object.
It is false by default.

lastError
int lastError

This member stores the last error generated by a method call. Since basic
SuperWaba packages dont generate exceptions, you must always check if a
method call returns success (most of them return a boolean or -1 if problems are
detected), and then check lastError. Each method call resets this to 0 when it is
called, and sets to one of the following values if an error occurs:

SuperWaba Companion

148

PalmOS - Net Error Codes


AlreadyOpen

4609

DNSBadProtocol

4676

NotOpen

4610

DNSTruncated

4677

StillOpen

4611

DNSNoRecursion

4678

ParamErr

4612

DNSIrrelevant

4679

NoMoreSockets

4613

DNSNotInLocalCache

4680

OutOfResources

4614

DNSNoPort

4681

OutOfMemory

4615

IPCantFragment

4682

SocketNotOpen

4616

IPNoRoute

4683

SocketBusy

4617

IPNoSrc

4684

MessageTooBig

4618

IPNoDst

4685

SocketNotConnected

4619

IPktOverflow

4686

NoInterfaces

4620

TooManyTCPConnections

4687

BufTooSmall

4621

NoDNSServers

4688

Unimplemented

4622

InterfaceDown

4689

PortInUse

4623

NoChannel

4690

QuietTimeNotElapsed

4624

DieState

4691

Internal

4625

ReturnedInMail

4692

Timeout

4626

ReturnedNoTransfer

4693

SocketAlreadyConnected

4627

ReturnedIllegal

4694

SocketClosedByRemote

4628

ReturnedCongest

4695

OutOfCmdBlocks

4629

ReturnedError

4696

WrongSocketType

4630

ReturnedBusy

4697

SocketNotListening

4631

GMANState

4698

UnknownSetting

4632

QuitOnTxFail

4699

InvalidSettingSize

4633

FlexListFull

4700

PrefNotFound

4634

SenderMAN

4701

InvalidInterface

4635

IllegalType

4702

InterfaceNotFound

4636

IllegalState

4703

TooManyInterfaces

4637

IllegalFlags

4704

BufWrongSize

4638

IllegalSendlist

4705

UserCancel

4639

IllegalMPAKLength

4706

BadScript

4640

IllegalAddressee

4707

NoSocket

4641

IllegalPacketClass

4708

SocketRcvBufFull

4642

BufferLength

4709

SuperWaba Companion

149

PalmOS - Net Error Codes


NoPendingConnect

4643

NiCdLowBattery

4710

UnexpectedCmd

4644

RFinterfaceFatal

4711

NoTCB

4645

IllegalLogout

4712

NilRemoteWindowSize

4646

AAARadioLoad

4713

NoTimerProc

4647

AntennaDown

4714

SocketInputShutdown

4648

NiCdCharging

4715

CmdBlockNotCheckedOut

4649

AntennaWentDown

4716

CmdNotDone

4650

NotActivated

4717

UnknownProtocol

4651

RadioTemp

4718

UnknownService

4652

NiCdChargeError

4729

UnreachableDest

4653

NiCdSag

4720

ReadOnlySetting

4654

NiCdChargeSuspend

4721

WouldBlock

4655

reserved

4722

AlreadyInProgress

4656

ConfigNotFound

4723

PPPTimeout

4657

ConfigCantDelete

4724

PPPBroughtDown

4658

ConfigTooMany

4725

AuthFailure

4659

ConfigBadName

4726

PPPAddressRefused

4660

ConfigNotAlias

4727

DNSNameTooLong

4661

ConfigCantPointToAlias

4728

DNSBadName

4662

ConfigEmpty

4729

DNSBadArgs

4663

AlreadyOpenWithOtherConfig 4730

DNSLabelTooLong

4664

ConfigAliasErr

DNSAllocationFailure

4665

NoMultiPktAddr

DNSTimeout

4666

OutOfPackets

4733

DNSUnreachable

4667

MultiPktAddrReset

4734

DNSFormat

4668

StaleMultiPktAddr

4735

DNSServerFailure

4669

ScptPluginMissing

4736

DNSNonexistantName

4670

ScptPluginLaunchFail

4737

DNSNIY

4671

ScptPluginCmdFail

4738

DNSRefused

4672

ScptPluginInvalidCmd

4739

DNSImpossible

4673

TelMissingComponent

4740

DNSNoRRS

4674

TelErrorNotHandled

4741

DNSAborted

4675

4731
4732

SuperWaba Companion

150

PalmOS Modem Error Codes

NoTone

4353

NoModem

4358

NoCarrier

4354

OutOfMemory

4359

LineBusy

4355

PrefsNotSetup

4360

UserCancelled

4356

DialStringErr

4361

CmdError

4357

mdmErrNoPhoneNum

4362

SuperWaba Custom VM Codes*


Invalid host

65526
(-10)

Net not opened properly

65523
(-13)

No net library available

65525
(-11)

Array range check

65522
(-14)

Net not ready for open

65524
(-12)
* See nmpalm_wabaio.c for details
The Windows CE error code list is too big to put here. You can download it from
this link: http://www.superwaba.org/etc/winerror.h

Configuring
Next will be explained how to configure a dial up connection on some PDAs. The
configurations on other PDAs may be almost identical to these ones.
Palm Vx with an external modem
1. Go to Prefs app, select Connection. Select the type of configuration you need. Click
Edit. Change what's needed. Click Details. Change the speed or other setting if
needed.
2. Still in Prefs app, select Network. Enter a service name, choose the user name, the
password, the phone and the same connection you choose in step 1.
3. Hit connect to verify if you can dial with success.
Kyocera Smartphone QCP6035
1. Go to Prefs app, select Connection. Select Wireless Modem.
2. Still in Prefs app, select Network. Enter a service name, choose the user name, the
password, the phone and the same connection you choose in step 1 (Wireless
Modem).
4. Hit connect to verify if you can dial with success.
Tungsten T with a mobile phone
1. Download the list of updated phone links from here:
http://www.palmone.com/us/support/downloads/phonelink.html

SuperWaba Companion

151

2. Install the phone link entry for the phone you're targetting
3. Go to the Phone Link app. Click Phone Connection and select the manufacturer and
model. If your model isn't listed, go to step 1. Click next, select your PDA's connection
to what you're going to dial: Infrared, cable, bluetooth, etc. When asked Would you
like to use this as the default connection for your phone applications, click Yes.
4. Go to the Prefs app. Select Communication. Click Phone. Make sure your connection
match the one specified in step 3.
5. Click Network. Enter your service, user name, password, connection and phone.
6. Hit connect to verify if everything is ok.
If you're using a GPRS connection, in step 5 you need to enter the right information
from this pdf: http://www.superwaba.com.br/etc/GPRS_Network_parameters.pdf
For example, to connect using TIM: Service=tim gprs, user name=tim, password=tim,
phone=*99***1#. Then you'll get a beautiful GPRS connection.

Testing
We already said that what is going to be written and read must follow a pattern, or
protocol. In the example below, we will use the HTTP protocol to connect to a server,
request a page from that server, and read a few bytes back.
socket = new Socket(www.google.com, 80, 15000);
if (!socket.isOpen())
status("Cant open socket: "+socket.lastError);
else
{
socket.setReadTimeout(500);
byte buf[] = new byte[10]; // we'll read only 10 bytes
byte []bytes = "GET / HTTP/1.0\n\n".getBytes();
socket.writeBytes(bytes,0,bytes.length);
int tries = 0;
do
{
int count = socket.readBytes(buf, 0, buf.length);
if (count == buf.length)
{
status(Read: +new String(buf,0,count));
break;
}
else status("couldnt read: "+socket.lastError);
// some sites can take a longer delay to start sending things,
// so we loop until we find something to read
} while (tries++ < 4 && socket.lastError == 4626);
status("Closing socket");
socket.close();
status("Socket closed: "+socket.lastError);
}
// Ps: status(String) is a method that displays the text in a listbox.

You can also use the superwaba.ext.xplat.io.http classes to handle http connections.

SuperWaba Companion

152

Note, in the example above, that there's a loop while the error is 4626. In my tests,
I found that sometimes this error can occur, and if I retry a few times, the connection is
established. Just setting a big read timeout is not enough.
You can easily connect to an ASP or Servlet or whatever page you want; you only
need to make sure that you pass the correct parameters.
Socket socket = new Socket(200.215.250.0, 80, 25000);
if (socket.isOpen())
{
String url = "GET /servlet/VerifyUser?user=" + user +
"&pass=" + password + "\n";
byte[] inBuf = new byte[1000];
byte[] outBuf = url.getBytes();
int read;
// fetch page
if (socket.writeBytes(outBuf, 0, outBuf.length) == outBuf.length)
read = socket.readBytes(inBuf, 0, inBuf.length);
socket.close();
}
Socket.disconnect(); // not necessary, just illustrative

You could also connect directly to a program listening on some host, using a
protocol that you have created. For an example of such protocol, see the
SuperWabaSDK\src\superwaba\ext\xplat\io\SerialSocket and SerialSocketServer classes.
Avoid using large buffers in Palm OS 5, because, in this version, a temporary buffer is
allocated and deallocated. Data read/written is copied to this buffer and when the
operation is done, it is moved to the provided user buffer.

SuperWaba Companion

153

Chapter 24 waba.io.SerialPort
The SerialPort class is used to connect the device to the external world using a
serial cable, bluetooth, or IR instead of a Modem.
Dealing with Serial connections is also another painful task with some
combinations of PDAs and desktop operating systems. One of the biggest pains is with
the combination of USB and Windows 98/2k/XP platforms. It simply doesn't work!
The SerialPort has three constructors:

SerialPort(int number, int baudRate, int bits, boolean parity,


int stopBits): calls SerialPort(number, baudRate, bits,
parity?PARITY_EVEN:PARITY_NONE).
SerialPort(int number, int baudRate, int bits, int parity, int
stopBits): you pass the port number, the baud rate, the number of bits per char (5
to 8), the parity state (SerialPort.PARITY_EVEN or SerialPort.PARITY_NONE
only works for Palm OS), and the stop bits. The port number, is usually one of the
following constants:
SerialPort.DEFAULT: this represents the cradle. It may be either a Serial port or a
USB port
SerialPort.IRCOMM: this a serial connection on top of the IrDA protocol. This is
the one chosen when you want to communicate with another PDA using it's
infrared port.
SerialPort.SIR: this is the physical layer of the IrDA stack. Most devices will crash
if you use it, so be careful.
Important! In order to access the SIR port on Pocket PCs the following has to
be UNCHECKED: Settings/Connections/Beam/Receive all incoming beams and
select discoverable mode.
SerialPort.USB: this is the USB port of Palm OS Handspring or WinCE devices.
SerialPort.BLUETOOTH: open the built-in Bluetooth discovery dialog, then
establish a Serial Port Profile (just serial emulation across Bluetooth, using the
RFComm BT layer) virtual serial port connection. Note: in WinCE, this maps to
the Serial (port 0). Note that the Bluetooth support in SuperWaba is very simple,
although it is enough for most uses. It gives you no control over Bluetooth
functions like discovery and parameter setup. Everything must be configured
outside SuperWaba.

SerialPort(int number, int baudRate): same of SerialPort(number,


baudRate, 8, PARITY_NONE, 1). This is the most used constructor, because
you generally don't need to set the other parameters.
Next, let's see the methods inside this class.

close
public boolean close()

SuperWaba Companion

154

This method closes the connection. If close is not called, the socket will be closed
by the garbage collector when the object gets collected.

isOpen
public boolean isOpen()

Returns true if the port is open and false otherwise. This can be used to check if
opening the serial port was successful. This method does not clear the lastError
flag. If false is returned, check for the lastError flag to find the reason the port could
not be opened.

setFlowControl
public boolean setFlowControl(boolean on)

Turns RTS/CTS flow control (hardware flow control) on or off. No serial XON/XOFF
flow control (commonly called software flow control) is used and RTS/CTS flow
control (commonly called hardware flow control) is turn on by default on all
platforms but Windows CE.

setReadTimeout
public boolean setReadTimeout(int millis)

Sets the timeout value for read operations. The value specifies the number of
milliseconds to wait from the time of last activity before timing out a read operation.
Passing a value of 0 sets no timeout causing any read operation to return
immediately with or without data. The default timeout is 100 milliseconds. This
method returns true if successful and false if the value passed is negative or the
port is not open.

readBytes
public int readBytes(byte buf[], int start, int count)

Reads bytes from the port into a byte array. Returns the number of bytes actually
read or -1 if an error prevented the read operation from occurring. The read will
timeout if no activity takes place within the timeout value for the port.

writeBytes
public int writeBytes(byte buf[], int start, int count)

SuperWaba Companion

155

Writes to the port. Returns the number of bytes written or -1 if an error prevented
the write operation from occurring. If data can't be written to the port and flow
control is on, the write operation will time out and fail after approximately 2
seconds.

readCheck
public int readCheck()

Returns the number of bytes currently available to be read from the serial port's
queue.

Like in the Socket class, the SerialPort also has a lastError member.

lastError
int lastError

This stores the last error generated by a method call. Since basic SuperWaba
packages don't generate exceptions, you must always check if a method call
returns success (most of them return a boolean or -1 if there are problems), and
then check lastError. Each method call resets this to 0 when it is called, and sets to
one of the following values if an error occurs:
SuperWaba Custom VM Codes
No Serial Library available

65525
(-11)

Array range check

65522
(-14)

PalmOS Serial Codes


serErrBadParam

769

AlreadyOpen

775

BadPort

770

StillOpen

776

NoMem

771

NotOpen

777

BadConnID

772

NotSupported

778

TimeOut

773

NoDevicesAvail

779

LineErr

774

USBConfigurationFailed

780

The Windows CE error code list is too big to put here. You can download it from
this link: http://www.superwaba.org/etc/winerror.h

Configuration
The configuration for Palm OS and Windows CE is straight forward: no setup is
needed. The problem relies on the destination: if it is another device, then you'll have to

SuperWaba Companion

156

try the baud rates until you find the correct one. If the destination is a desktop computer,
then, prepare for some problems.
I don't use Linux/Unix, but users say that there's no problem connecting the PDA in
a cradle to it, even if the cradle is USB.
But using Windows is only easy if your PDA has a serial connection. You will have
to kill hotsync, and then start some kind of server or a program (like HyperTerm) to
receive the sending bytes. Unfortunately, using USB with Windows is impossible.
The best approach you can use to connect a PalmOS PDA to Windows is buying a
USB-TO-SERIAL cable, and then opening the connection using SerialPort.DEFAULT.
You can also try to use a free utility called IrCOMM2k, which maps the IRCOMM to a port
that can be used under Windows 2k. Then you could create a program that listens to this
port and transfer data to/from the device. The program's site is here:
http://www.stud.uni-hannover.de/~kiszka/IrCOMM2k/English/index.html
You can also test the SerialPort class at desktop, under JDK. For this, you will just
need to add, to your classpath, the SuperWabaSDK\bin\tools\commapi\comm.jar file. This
file adds support for serialport under JDK (the version inside the SDK is for the Windows
platform. Please visit Sun's site to download the version for Linux and Mac). SuperWaba's
file waba.io.NativeMethods4JDK use the methods of this class, but due to a trick (using
introspection to call the methods), you can compile SuperWaba files without the
comm.jar in the classpath. We will use it in next topic. To emulate the various ports in
JDK, we use a file called swserial.properties. This file is read from the current directory
by the SWSDK when you try to use SerialPort under Windows/Linux/Mac. The file
contents are:
DEFAULT=COM1
IRCOMM=COM2
SIR=COM3
USB=COM4

You can change the file if you want, to match your desktop's configuration. If the
file is not found, these default settings are used.

Testing
In the SDK samples directory there are some interesting programs made by
SuperWaba users. We won't get into the details of each program here, but they will be
described so you may look into them by yourself. The parent directory for all listed
programs is: SuperWabaSDK/java/src/.

superwaba.samples.io.IRChat: this program is used to chat using an infrared port.


Two users logs in and then connect via IRCOMM. The messages are encrypted
using a repeating-keyword Ceasar cypher. The program was created by Shaun
O'Brian.

SuperWaba Companion

157

superwaba.samples.io.SerialPipe: this one acts as a pipe between two ports. It


uses threads to keep reading from one stream and writing to the other. Created by
Michal Hobot.
superwaba.samples.io.SerialPort: this application is useful to test the various ports
of the device. Pretty simple.

Now we're going to run two sample programs that can be very useful. They both
were tested using devices connected to a desktop's serial port (also works with USB-TOSERIAL cable).
The first program is PDBConduit. The PDBConduit program has a protocol that can
be used to send/receive text files to/from the desktop, as well as pieces of PDB files. The
PDBConduit is placed in two directories: the SuperWabaSDK\java\src contains the client
application example, superwaba.samples.ext.io.pdbconduit.PDBConduit, that runs in the
device. The directory SuperWabaSDK\src\java contains the server and the client
interface, named superwaba.ext.xplat.io.SerialPDBServer and
superwaba.ext.xplat.io.SerialPDB, respectively.

SerialPDB
The SerialPDB interface, used by the client, contains the methods below:

SerialPDB(int baud, int timeout): the constructor, where you specify the
baud rate and the read timeout. Note that the program is hardcoded to use
SerialPort.DEFAULT.
isOpen(): returns true if the port is opened.
boolean put(Catalog cat2send, String name, int startRecord, int
endRecord, boolean onlyDirty, boolean resetDirtyAttr): Send the
specified catalog to the server. If onlyDirty is true, only dirty records will be sent. You
may also specify resetDirtyAttr to reset the flag in all record sync'ed. startRecord and
endRecord can be -1 to send all Catalog. You may specify in the name the full path to
the catalog.
boolean get(Catalog fillIn, String name, int startRecord, int
endRecord, boolean onlyDirty, boolean resetDirtyAttr): Requests the
server to send the specified catalog, placing the records in the given fillIn catalog.
startRecord and endRecord can be -1 to bring the full Catalog. If onlyDirty is true, only
dirty records will be received. You may also specify resetDirtyAttr to reset the flag in all
record sync'ed. You may specify in the name parameter the full path to the file.
boolean put(String fileName, boolean deleteIfExists, String
[]strings): Send the following String array to the server, placing it in the given txt
filename. You may specify the full path to the fileName.
String[] get(String fileName): Get a String array from the server from the
specified text file. You may specify the full path to the fileName.
delete(String fileName): Delete a catalog at the server. This method does NOT
delete a txt (txt files are always overwritten)!
shutdownServer(): Shuts down the server.
Now let's test the program:

SuperWaba Companion

158

1. Install the files XPlatIo.pdb, PDBConduit.prc, PDBConduit.pdb in the device.


2. Before running the program on the device, we need to start the server.
3. Place your PDA in the cradle, connect the cradle to the serial port of the desktop, then
open the console (or DOS prompt).
4. Change to the folder SuperWabaSDK/src/java
5. Open the hotsync program at the taskbar, click Setup/Local and memorize the Serial
Port in use. Now, exit HotSync.
6. If you want, copy the file swserial.properties to the current folder and edit it, changing
the needed ports.
7. type java -classpath
.;..\..\lib\superwaba.jar;..\..\bin\tools\commapi\comm.jar
-Djava.library.path=..\..\bin\tools\commapi
superwaba.ext.xplat.io.SerialPDBServer <use the same port that
hotsync was using see step 6> 57600
8. A java.lang.ClassNotFoundException: javax.comm.CommPortIdentifier will occur if
the JDK comm.jar file or the file named by the -D switch does not exist. Try to use the
full absolute path to the SuperWabaSDK, instead of a relative path.
9. That's it! You should receive a message like:
Port found: COM1
Idle
10.Now, start the program in the PDA and press the buttons to see the server working.
Notes:

When the PDBConduit program exits, it does a shutdown in the server.


The baud rate is fixed in the PDBConduit program and also in the bat file.
The files, as specified in the program, will be placed in the current directory (in this
case, in the superwaba/ext/xplat/io path).
This is the first release, so just the basic error detection cases were implemented.

SerialSocket
The second program described is SerialSocket. You may know that the PalmOS
devices can't open a Socket directly from the cradle (however, this is a trivial operation on
a Windows CE device). After reading the article Cure Your Waba Woes with a Serial
Socket, an article written by Rick Grehan at JavaPro Magazine, I changed it a bit and
created this useful library.
SerialSocket acts just like the SerialPDB: you have a client, a client interface and a
server. The server receive the commands from the client and routes them to the network,
sending answers back.
Our client test program will be the same SocketTest program we used in last
chapter. The program has an option where you choose if you want to use the real Socket
class or the SerialSocket. This can be easily done because
superwaba.ext.xplat.io.SerialSocket extends waba.io.Socket. It has the same methods of
waba.io.Socket, plus one method, shutdownServer, which can be used to shut down the
server.

SuperWaba Companion

159

The program setup is almost the same of the SerialPDB:


1. Install the files XPlatIoUIUtil.pdb, SocketTest.prc, SocketTest.pdb in the device.
2. Before running the program at the device, we need to start the server.
3. Place your PDA in the cradle, connect the cradle to the serial port of the desktop, then
open the console (or DOS prompt).
4. Change to the SuperWabaSDK/src/java folder
5. Open the hotsync program at the taskbar, click Setup/Local and memorize the Serial
Port in use. Now, exit HotSync.
6. If you want, copy the file swserial.properties to the current folder and edit it, changing
the needed ports.
7. type java -classpath
.;..\..\lib\superwaba.jar;..\..\bin\tools\commapi\comm.jar
-Djava.library.path=..\..\bin\tools\commapi
superwaba.ext.xplat.io.SerialSocketServer <use the same port
that hotsync was using see step 6> 19200
8. A java.lang.ClassNotFoundException: javax.comm.CommPortIdentifier may occur if
the JDK comm.jar file was not found or the file named by the -D switch does not exist.
Try to use the full absolute path to the SuperWabaSDK instead of a relative path.
If you receive a message from the server saying Unknown command received,
be sure that you set the baud rate to 19200, which is the same one hardcoded in the
SocketTest program.
9. That's it! You should receive a message like:
Port found: COM1
Idle
10.Now, start the program in the PDA and press the buttons to see the server working.

SuperWaba Companion

160

Chapter 25 waba.io.File
The waba.io.File class was introduced in SuperWaba version 3.5. Its usage
depends on the platform:

On the desktop and on Windows CE / Pocket PC devices, it access the file system and
memory cards, managing directories and files.
On PalmOS devices with an OS version greater than 3.5 and a memory card, it access
the virtual file system, enabling you to manage directories and files on the memory
card only. However, you will not be able to access the default storage memory using
the waba.io.File (you must still use waba.io.Catalog in this case).

You can't create files in the root directory of a memory card.


Writing files on a memory card is about 5 times slower than in normal memory.
To write files in the memory card of a Pocket PC device, you must prefix the folder with
Storage Card (most commonly used) or SD Card. Unfortunately, there's no way
to find which prefix is the right one for the device without testing. There's a method that
tests on the most common places, named getCardVolume().
The File class has two constructors:

File(String path, int mode): Opens a file with the given name and mode. If
mode is CREATE, the file will be created if it does not exist. The DONT_OPEN mode
allows the exists(), rename(), delete(), listDir(), createDir() and isDir() methods to be
called without requiring the file to be opened for reading or writing. The other mode
options are READ_ONLY, WRITE_ONLY and READ_WRITE. Note that the filename
must not contain accented characters. Also, the path separator MUST be the slash
"/".
File(String path): Opens a file in DONT_OPEN mode. This constructor is
useful for directory manipulation and to check if a file exists. No read/write operation
can be done with a File object created in this mode.

Don't forget to try the samples/io/File/FileTest.java sample. Next we will see the
various methods in this class:

isAvailable
public static boolean isAvailable()

Returns true if a File System is available in the current PDA. In Windows CE and
on the desktop, this always returns true. In Palm OS, it will depend if the file has an
external card (Secure Digital, Smart Media, etc). Using other methods in this class
without first checking if this class is available in the target device will simply reset
it. Starting on SuperWaba 5.5, the isAvailable also checks if the card is inserted on
Palm OS devices only.
Below is an example:

SuperWaba Companion

161

new MessageBox(File System, waba.io.File.isAvailable()?Available and


inserted:Not available or card not inserted).popupModal();

close
public boolean close()

Closes the file. Returns true if the operation is successful and false otherwise. If
you don't explicitly close the file, it will be closed by the garbage collector.

createDir
public boolean createDir()

Creates a directory. Returns true if the operation is successful and false otherwise.
Below is an example:
File f = new File("/TempDir");
if (!f.exists())
f.createDir();

delete
public boolean delete()

Deletes the file or directory (the directory must be empty). Returns true if the
operation is successful and false otherwise. After this operation, this File object is
invalid and must not be used further.
Below is an example:
File f = new File("/TestRename/Test2.txt");
ok = f.delete();
new MessageBox(Test File.delete, ok?"Test2.txt deleted":("Test2.txt not
deleted. err="+f.lastError).popupModal();

exists
public boolean exists()

Returns true if the file exists and false otherwise.


Below is an example:
File f = new File("/TempDir");

SuperWaba Companion

162

boolean exists = f.exists();

getSize
public int getSize()

Returns the size of the file in bytes. If the file is not opened, 0 will be returned.
Below is an example:
File f = new File("/Teste.txt",File.CREATE);
DataStream ds = new DataStream(f);
ds.writeString("Test");
ds.writeInt(1234);
new MessageBox(Test File.getSize, "File size now is: "+f.getSize()+
bytes)popupModal();

getPath
public String getPath()

Return the file's path. The getPath is also used in the File.toString method
implementation.
Below is an example:
File f = new File("/TempDir");
Vm.debug(Path is: +f.getPath());

isDir
public boolean isDir()

Returns true if the file is a directory and false otherwise.


Below is an example:
File f = new File("/TempDir");
if (!f.exists())
f.createDir();
Vm.debug("/TempDir isDir?"+f.isDir()); // true
f = new File(/TempDir/Test.txt, File.CREATE);
Vm.debug("/TempDir/Test.txt isDir?"+f.isDir()); // false

isOpen

SuperWaba Companion

163

public boolean isOpen()

Returns true if the file is open for reading or writing and false otherwise. This can
be used to check if opening or creating a file was successful.
Below is an example:
File f = new File("/Teste.txt",File.CREATE);
new MessageBox(File created?, f.isOpen() ? Created! : Not
created.).popupModal();

listFiles
public String []listFiles()

Lists the files contained in a directory. The strings returned are the names of the
files and directories contained within this directory. This method returns null if the
directory can't be read or if the operation fails. Volume labels are returned between
[ ], and paths have a / after the name. Using this pattern makes easy and fast
finding if a String is a path, a file or a volume label.
Below is an example:
void recursiveList(String path, Vector v)
{
if (path == null) return;
File file = new File(path);
String []list = file.listFiles();
if (list != null)
for (int i =0; i < list.length; i++)
if (list[i] != null)
{
v.addElement(path+list[i]);
if (list[i].endsWith("/")) // is a path?
recursiveList(path+list[i],v);
}
}
Vector v = new Vector(50);
recursiveList("/",v);
String []files = (String[])v.toObjectArray();
if (files == null)
files = new String[]{"No files"};
else
if (files[0].charAt(1) == '[') // is it a volume label?
files[0] = files[0].substring(1); // remove the preceding slash
add(new ComboBox(files), LEFT,TOP);

readBytes
public int readBytes(byte b[], int off, int len)

SuperWaba Companion

164

Reads bytes from the file into a byte array. Returns the number of bytes actually
read or -1 if an error prevented the read operation from occurring. After the read is
complete, the location of the file pointer (where read and write operations start
from) is advanced the number of bytes read.
Below is an example:
File f = new File("/Teste.txt",File.CREATE);
byte []buf = SuperWaba = POWER!.getBytes();
f.writeBytes(buf,0,buf.length);
f.setPos(0);
if (f.readBytes(buf,0,buf.length) == buf.length)
new MessageBox(Test, new String(buf)).popupModal();

writeBytes
public int writeBytes(byte buf[], int start, int count)

Writes to the file. Returns the number of bytes written or -1 if an error prevented
the write operation from occurring. After the write is complete, the file pointer
(where read and write operations start from) is advanced the number of bytes
written.
See readBytes for an example.

rename
public boolean rename(String path)

Renames the file. You must give the full directory specification for the file, to
maintain compatibility between all platforms. WinCE platforms let you move a file
using rename, while Palm OS does not let you move the file. Returns true if the
renaming was successful and false otherwise. After this operation, this File object
is invalid and must not be reused.
Below is an example:
File f = new File("/TempRename");
f.createDir();
boolean ok = f.rename("/TestRename");
if (ok)
{
// file object is now invalid. create a new one.
f = new File("/TestRename");
Vm.debug("TestRename.isDir? "+f.isDir());
f = new File("/TestRename/Teste.txt",File.CREATE);
// Rename Teste.txt to Teste2.txt
ok = f.rename("/TestRename/Teste2.txt");
if (ok)
{

SuperWaba Companion

165

// file object is now invalid. create a new one


f = new File("/TestRename/Teste2.txt");
Vm.debug("Teste2.txt exists? "+f.exists());
ok = f.delete();
Vm.debug(ok?"Teste2.txt deleted":("Teste2.txt not deleted.
err="+f.lastError));
}
f = new File("/TestRename");
ok = f.delete();
}

setPos
public boolean setPos(int pos)

Sets the file pointer for read and write operations to the given position. The position
passed is an absolute position, in bytes, from the beginning of the file. To set the
position to just after the end of the file, you can call:
file.setPos(file.getSize());

True is returned if the operation is successful and false otherwise.


See readBytes for an example.

setAttributes
public void setAttributes(int attr)

Sets this file attributes. This method does not work on the desktop. The file must be
opened in a mode different than DONT_OPEN. The attr parameter must be one or
more ATTR_xxx constants ORed together: ATTR_ARCHIVE, ATTR_HIDDEN,
ATTR_READ_ONLY, ATTR_SYSTEM. These values are platform independent, ie,
they are internally mapped to the target platform values. Values different from the
given ATTR_xxx constants are simply ignored.
Below is an example:
String getAttrDescription(int attr)
{
String s = "";
if ((attr & File.ATTR_ARCHIVE) != 0)
s += "A";
if ((attr & File.ATTR_HIDDEN) != 0)
s += "H";
if ((attr & File.ATTR_READ_ONLY) != 0)
s += "R";
if ((attr & File.ATTR_SYSTEM) != 0)
s += "S";
return s;
}
File f = new File("TestAttr.txt",File.CREATE);
int attr = f.getAttributes();
Vm.debug("File attributes: "+getAttrDescription(attr));

SuperWaba Companion

166

// Setting to hidden
f.setAttributes(attr | File.ATTR_HIDDEN);
attr = f.getAttributes();
Vm.debug("Attributes changed to "+getAttrDescription(attr));

getAttributes
public int getAttributes()

Gets this file attributes. See the ATTR_xxx constants, which can be ORed together.
This method does not work on the desktop. The file must be opened in a mode
different than DONT_OPEN. Returns -1 if failure, otherwise the attributes ORed
together.
See setAttributes for an example

setTime
public void setTime(byte whichTime, waba.sys.Time time)

Sets the time for the given time type. The whichTime must be one of the following
constants, ORed together:
TIME_ALL: This sets all times to the given time
TIME_CREATED: time in which the file was created
TIME_MODIFIED: last time the file was modified (written)
TIME_ACCESSED: last time the file was accessed (read)
The TIME_xxx constants are platform independent, what means that they will be
mapped internally to the values used by each operating system.
This method does not work on the desktop, running under JDK.
The file must be opened in a mode different than DONT_OPEN.
Below is an example:
File f = new File("TestAttr.txt",File.CREATE);
Time t;
Vm.debug("File Created Time:");
t = f.getTime(File.TIME_CREATED);
Vm.debug(""+new Date(t)+" "+t);
Vm.debug("File Modified Time:");
t = f.getTime(File.TIME_MODIFIED);
Vm.debug(""+new Date(t)+" "+t);
Vm.debug("File Acessed Time:");
t = f.getTime(File.TIME_ACCESSED);
Vm.debug(""+new Date(t)+" "+t);

SuperWaba Companion

167

Vm.debug("Changing Modified time to 25/03/2000 13:30:15");


f.setTime(File.TIME_MODIFIED, new Time(2000,3,25,13,30,15,0));
Vm.debug("File Modified Time now is:");
t = f.getTime(File.TIME_MODIFIED);
Vm.debug(""+new Date(t)+" "+t);

getTime
public waba.sys.Time getTime(byte whichTime)

Gets the time for the given time type.


The whichTime must be one of the following constants:
TIME_CREATED: time in which the file was created
TIME_MODIFIED: last time the file was modified (written)
TIME_ACCESSED: last time the file was accessed (read)
Note that the constants in this method cannot be ORed together; in other words,
this method only returns one time for each call.
This method does not work on the desktop.
The file must be opened in a mode different than DONT_OPEN.
See setTime for an example.

getCardVolume
public String getCardVolume()

Returns the volume File for the Windows CE and Pocket PC devices. In these
devices, the volume has a special folder name, but since there's no system call that
informs this, we must just test the existence of each folder, returning the first one
that exists.
This method does not work on the desktop.
Like the Socket and SerialPort classes, the File class also has a lastError member.

lastError
int lastError

This stores the last error generated by a method call. Because basic SuperWaba
packages do not generate exceptions, you must always check if a method call
returns success (most of them return a boolean or -1 if problems are detected) and
then check lastError. Each method resets this to 0 when it is called, and if an error
occurs sets it to one of the following values before returning:

SuperWaba Companion

168

PalmOS Virtual File System Codes


BufferOverflow

10753

NoFileSystem

10763

FileGeneric

10754

BadData

10764

FileBadRef

10755

DirNotEmpty

10765

FileStillOpen

10756

BadName

10766

FilePermissionDenied

10757

VolumeFull

10767

FileAlreadyExists

10758

Unimplemented

10768

FileEOF

10759

NotADirectory

10769

FileNotFound

10760

IsADirectory

10770

VolumeBadRef

10761

DirectoryNotFound

10771

VolumeStillMounted

10762

NameShortened

10772

The Windows CE error codes list is too big to put here. You can download it from
this link: http://www.superwaba.org/etc/winerror.h

SuperWaba Companion

PART IV EXTENSION LIBRARIES

169

SuperWaba Companion

170

Chapter 26 Scanner Library


The scanner library, located in the package superwaba.ext.xplat.io.scanner, is used with
the following devices:

Symbol scanners for Palm OS


Scanners supported: SPT 1500, 1550, 1700, 1800, 1846.
The following files must be installed:
\SuperWabaSDK\lib\vm\xplat\XPlatIoScanner.pdb and
\SuperWabaSDK\lib\vm\palm\68k\XPlatIoScanner.prc.
Note that you must use the 68K vm, because the ARM VM is not compatible with
this scanner library
Symbol scanners for Pocket PC
Scanners supported: the PDT8100 (Pocket PC 3.0), PDT8146 (Pocket PC 2002),
PPT8800 (HPC211_ARM), MC3000.
The following files must be installed:
SuperWabaSDK\lib\vm\xplat\XPlatIoScanner.pdb and one of the following files:
SuperWabaSDK\lib\vm\ce\PocketPC\MIPS\XPlatIoScanner.dll or
SuperWabaSDK\lib\vm\ce\PocketPC\ARM\XPlatIoScanner.dll
Other devices may be supported, try to install one of these two files and test them.
If it works, please update the list at
http://www.superwaba.net:8100/twiki/bin/view/Main/SupportedDevices
SDIO Socket Scan for Pocket PC
Scanners supported: all the SDIO cards (RFID and IR)
The following files must be insalled:
SuperWabaSDK\lib\vm\xplat\XPlatIoScanner.pdb and
SuperWabaSDK\lib\vm\ce\PocketPC\ARM\XPlatIoSocketScan.dll
Opticon OPL-2724 for Palm OS
You must install the file
SuperWabaSDK\docs\companion_samples\Chapter26\TScan.prc, which is a
modified version of the file created by Opticon that copies the scanner data to the
clipboard.
The code located at Chapter26/TScanTest shows how to get the data from the
Scanner: it creates a thread that keeps pooling data from the clipboard. Note that
some limitations are imposed in this solution: the amount of data beins scanned
must be small.
The TScan.prc works fine with the ARM VM

There are some samples for the Scanner library in the folder
SuperWabaSDK\src\java\superwaba\samples\ext\io\scanner. Note that this sample does
not work with the Opticon scanner.
Note that the SDIO and Opticon libraries are available only with the Professional
subscription.

SuperWaba Companion

171

Chapter 27 Printer Library


OVERVIEW
The SuperWaba printer library is simply a Java bridge between SuperWaba and an
IR printer library, such as PrintBoy or IrPrint. This library currently works only on Palm OS.
Drivers will be ported to Windows CE in the future.
PrintBoy was the first driver created to use with this library. Currently you have also
the choice for IrPrint, but this is a more limitted library, which supports less printers and
also have no Graphics support.
Important! The printboy library now needs at least PrintBoy 5.1 to run. If you can't
upgrade to it, please continue to use the old versions of the Printer Library.
The packages that belongs to this library are specified below:

superwaba.ext.xplat.io.print (Print API)


superwaba.ext.xplat.io.print.pboy (PrintBoy implementation of the Print API)
superwaba.ext.palm.io.print.irprint (IrPrint implementation of the Print API)
Samples are also provided under superwaba.samples.ext.io.print

Troubleshooting

I cannot print. Any suggestions?


1. Try to decrease the baud rate.
2. If using PrintBoy, be sure to test the demo of PageMgr and PrintMgr.
3. Be sure to install all needed files:
a) For PrintBoy:
PrintBoy files:
PrintMgr.prc
PageMgr.prc
IrMgr.prc
BPMComfig.prc
BPMDeskJet.prc (or any other driver)
BPM_CourierNew10.PDB
SuperWaba files:
XPlatIoPrintPBoy.pdb
XPlatIoPrintPBoy.prc
XPlatIoPrint.pdb
b) For IrPrint:
IrPrint files:
IrPrintV<version>.prc
SuperWaba files:
PalmIoPrintIrPrint.pdb

SuperWaba Companion

172

PalmIoPrintIrPrint.prc
XPlatIoPrint.pdb
4. If you have a notebook near, disable its IR Wireless port. It may interfere with the
device IR.

Although my printer has support for graphics at Windows, it does not work with
PrintBoy. What's wrong?
Quoted by the PrintBoy author:

This is because the deskjet printers can't render and entire page in memory; they
lay down the ink as they move down the page and aren't smart enough to feed the paper
back through to get to the top of the page again if a command comes it that tells it to draw
something back up the page. For example, if you tell the printer to draw two vertical lines
2 inches apart it will get the command for the first line and draw it. Now it is below the
point where it can start the next line.
It might be ok telling it to print horizontal lines if they are sorted in descending Y
direction but don't quote me on that.
In general it is required to sort your page in descending Y direction for these types
of printers. Someday, when the page is being rendered on the device in raster format,
then sent to the printer, this won't be a problem. But IMO that's prohibitively slow at this
point. Maybe the new ARM processors will do a better job but you still have the relatively
slow SIR link to deal with.

I'm trying to print using Graphics but the formFeed+finishPage doesnt work.

This happens when you try to use an unsupported operation with PrintBoy (like
writting lines in a deskjet printer). You must test the Printer Capabilities before doing
some kinds of action.

I'm getting a fatal reset

Whenever you do a wrong action, like an invalid command or not being too near
the ir device, a fatal reset is likely to occur.
Are you using the last SuperWaba version?

My tests doesnt print!

The printing routines must be fast. There should be no big delays between the
commands you send to the printer, otherwise it will "forget" and won't work.

When i run the application, i get some messages in the memobook log file: "Cannot
find native method..."
You forgot to add the Vm.attachNativeLibrary. Check the samples.

When i try some functions, i got something like "Please try another driver".

SuperWaba Companion

173

If this occurs in PrintBoy, turn to Appendix A of the PrintBoy SDK User


Documentation ( the Printer Compatibility Matrix ), then check if your printer supports the
feature. For example, on the line for Citizen printers, the last column ( PrintBoy API
Support ) says: "Page Manager" That means the printer driver supports the Page
Manager API. Because it does not also say "Print Manager," this printer does not support
the Print Manager, and bad things will happen if you use any calls from it. At the very
least, you're going to get "Not Implemented" errors.

SuperWaba Companion

174

Chapter 28 Catalog Search Library


OVERVIEW
With this class, you can do searches in a Catalog 5 to 10 times faster than in Java.
The files XPlatIoSearch.pdb+XPlatIoSearch.prc (for Palm OS) or
XPlatIoSearch.pdb+XPlatIoSearch.dll (for Windows) must be installed in the proper
places.
There's only one class available:
superwaba.ext.xplat.io.search.CatalogSearch
And this class has only one method available:
searchBytes(byte []toSearch, int length, int offsetInRec).
The recordOffset is useful when you write something before of what you want to
search. For example, if your record contains an int before a string, you may set
recordOffset to 4 (the int is stored in the first 4 bytes).
Be careful: to search for a substring inside a String, you must remember to skip the
first two bytes where the String length is stored.
The search starts from the current positioned record in the Catalog.

Sample
if (Vm.attachNativeLibrary("XPlatIoSearch"))
{
Catalog cat = new
Catalog("TestDB."+Settings.appCreatorId+".DATA",
Catalog.READ_ONLY);
CatalogSearch catSearch = new CatalogSearch(cat);
String text = "a9999"; // string to search
int offset = 0; // offset in record
int startRec = 10; // start searching from record 10
cat.setRecordPos(startRec);
// now we convert the String to a byte array
// Note that we're searching for the exact string,
// case sensitive and whole word only.
int length = 0;
ByteArrayStream bas = new ByteArrayStream(16);
DataStream ds = new DataStream(bas);
length += ds.writeString(text);
byte []toSearch = bas.getBuffer(); // the buffer may be
greater than length

SuperWaba Companion

175

int start = Vm.getTimeStamp();


int recIndex = catSearch.searchBytes(toSearch, length,
offset);
int end = Vm.getTimeStamp();
Vm.debug("Returned record: "+recIndex);
Vm.debug("Elapsed: "+Vm.getTimeElapsed(end,start)+" ms");
}

SuperWaba Companion

176

Chapter 29 Image Library


OVERVIEW
The image library lets you read GIF (and animated GIF!), JPEG and PNG image
file types. The files can be read from a Stream (catalog, socket, serial) or directly from
your application's pdb file. Except for sockets and serial, they are limited to 64kb in size.
Note that the Png library can run only on JDK 1.3 or newer. Also, when running as
a Java application, it is better to use /bpp 16 as parameter so that you can display all
the colors on the image.
This library is also used by the superwaba.samples.app.htmlbrowser.HtmlBrowser
class to display the images from a web page.
You can now display the photos captured by your Palm OS device's camera, using
this Jpeg library (see superwaba.samples.ext.fx.photos sample).
The support for each type of image are implemented in their respective package:

superwaba.ext.xplat.fx.gif
superwaba.ext.xplat.fx.jpeg
superwaba.ext.xplat.fx.png
Check the other samples in the package superwaba.samples.ext.fx.

An important note is that all GifImage, JpegImage and PngImage extend


waba.fx.Image, and thus, have all the methods defined in that class (internally, after
the file is read, it is transformed into a waba.fx.Image).
The three classes contains common constructors:

(), where you can construct the object and then load the image with the load method.
(String filename): this one is used when you add the image to your PDB using
Warp. Note that it cannot have a path qualifier, just the name of the image.
(waba.io.Stream stream): here you can use any type of streams (Socket,
SerialPort, Catalog, File) to read an image. You can also use the
superwaba.ext.xplat.io.RecordPipe to read an image split into various records
of a Catalog.

Important: there's currently a limitation that may result in corrupted images when you read
from a Stream like waba.io.File or waba.io.Catalog. If this happen, you must read the
entire image to memory and then pass it to the 3rd constructor above. Here's a sample on
how to read a Jpeg image using waba.io.File (the same may apply to the other streams):
JpegImage img = new JpegImage();
File f = new File("DCIM/photo.jpg");

SuperWaba Companion

177

byte []buf = new byte[f.getSize()];


f.readBytes(buf,0,buf.length);
ByteArrayStream bas = new ByteArrayStream(buf);
img.load(bas);
The GifImage class contains some constructors where you can pass the image
number you want to read. Please see javadocs for further information.

Jpeg Error list


00
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

Bogus message code %d


Sorry, there are legal restrictions on arithmetic coding
ALIGN_TYPE is wrong, please fix
MAX_ALLOC_CHUNK is wrong, please fix
Bogus buffer control mode
Invalid component ID %d in SOS
DCT coefficient out of range
IDCT output block size %d not supported
Bogus Huffman table definition
Bogus input colorspace
Bogus JPEG colorspace
Bogus marker length
Wrong JPEG library version: library is %d, caller expects %d
Sampling factors too large for interleaved scan
Invalid memory pool code %d
Unsupported JPEG data precision %d
Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d
Invalid progressive parameters at scan script entry %d
Bogus sampling factors
Invalid scan script at entry %d
Improper call to JPEG library in state %d
JPEG parameter struct mismatch: library thinks size is %u, caller expects %u
Bogus virtual array access
Buffer passed to JPEG library is too small
Suspension not allowed here
CCIR601 sampling not implemented yet
Too many color components: %d, max %d
Unsupported color conversion request
Bogus DAC index %d
Bogus DAC value 0x%x
Bogus DHT index %d
Bogus DQT index %d
Empty JPEG image (DNL not supported)
Read from EMS failed
Write to EMS failed
Didn't expect more than one scan
Input file read error
Output file write error --- out of disk space?
Fractional sampling not implemented yet
Huffman code size table overflow

SuperWaba Companion

40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
87
88
89
90

Missing Huffman code table entry


Maximum supported image dimension is %u pixels
Empty input file
Premature end of input file
Cannot transcode due to multiple use of quantization table %d
Scan script does not transmit all data
Invalid color quantization mode change
Not implemented yet
Requested feature was omitted at compile time
Backing store not supported
Huffman table 0x%02x was not defined
JPEG datastream contains no image
Quantization table 0x%02x was not defined
Not a JPEG file: starts with 0x%02x 0x%02x
Insufficient memory (case %d)
Cannot quantize more than %d color components
Cannot quantize to fewer than %d colors
Cannot quantize to more than %d colors
Invalid JPEG file structure: two SOF markers
Invalid JPEG file structure: missing SOS marker
Unsupported JPEG process: SOF type 0x%02x
Invalid JPEG file structure: two SOI markers
Invalid JPEG file structure: SOS before SOF
Failed to create temporary file %s
Read failed on temporary file
Seek failed on temporary file
Write failed on temporary file --- out of disk space?
Application transferred too few scanlines
Unsupported marker type 0x%02x
Virtual array controller messed up
Image too wide for this implementation
Read from XMS failed
Write to XMS failed
JCOPYRIGHT)
JVERSION)
Caution: quantization tables are too coarse for baseline JPEG
Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d
Unknown APP0 marker (not JFIF), length %u
Unknown APP14 marker (not Adobe), length %u
Define Arithmetic Table 0x%02x: 0x%02x
Define Huffman Table 0x%02x
Define Quantization Table %d precision %d
Define Restart Interval %u
Freed EMS handle %u
Obtained EMS handle %u
End Of Image
JFIF APP0 marker: version %d.%02d, density %dx%d %d
Warning: thumbnail image size does not match data length %u
JFIF extension marker: type 0x%02x, length %u
with %d x %d thumbnail image

178

SuperWaba Companion

91
92
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123

Miscellaneous marker 0x%02x, length %u


Unexpected marker 0x%02x
Quantizing to %d = %d*%d*%d colors
Quantizing to %d colors
Selected %d colors for quantization
At marker 0x%02x, recovery action %d
RST%d
Smoothing not supported with nonstandard sampling ratios
Start Of Frame 0x%02x: width=%u, height=%u, components=%d
Component %d: %dhx%dv q=%d
Start of Image
Start Of Scan: %d components
Component %d: dc=%d ac=%d
Ss=%d, Se=%d, Ah=%d, Al=%d
Closed temporary file %s
Opened temporary file %s
JFIF extension marker: JPEG-compressed thumbnail image, length %u
JFIF extension marker: palette thumbnail image, length %u
JFIF extension marker: RGB thumbnail image, length %u
Unrecognized component IDs %d %d %d, assuming YCbCr
Freed XMS handle %u
Obtained XMS handle %u
Unknown Adobe color transform code %d
Inconsistent progression sequence for component %d coefficient %d
Corrupt JPEG data: %u extraneous bytes before marker 0x%02x
Corrupt JPEG data: premature end of data segment
Corrupt JPEG data: bad Huffman code
Warning: unknown JFIF revision number %d.%02d
Premature end of JPEG file
Corrupt JPEG data: found marker 0x%02x instead of RST%d
Invalid SOS parameters for sequential JPEG
Application transferred too many scanlines

179

SuperWaba Companion

180

Chapter 30 ZLib Native Compression


OVERVIEW
The ZLib library allows you to compress and decompress data very fast, because it
is written in C, not in Java. It is about 100 times faster than the superwaba.ext.xplat.util.zip
one.
There are two provided methods:

int deflate(int compression_level, waba.io.Stream in,


waba.io.Stream out), used to compress data from the input stream to the output
stream, using the specified compression level (0 = NO_COMPRESSION, 1 =
BEST_SPEED, 9 = BEST_COMPRESSION).

int inflate(waba.io.Stream in, waba.io.Stream out), used to


decompress data from the input stream to the output stream.

IMPORTANT - There are two current problems with this library:


1. There's currently a problem in the native part, that makes the code work only if the
streams are ByteArrayStream ones.
2. There's another problem regarding memory: the expanded memory block cannot
exceed 30kb.

Sample
There's a sample at the folder src/java/superwaba/samples/ext/zlib/test that shows
how to compress and uncompress.
This other sample shows how to read a text file at desktop, line per line, compress
it into a Catalog that can later be decompressed at the PDA. The files are located in a
folder at the companion_samples folder, and are named CompressAtDesktop.java and
DecompressAtPDA.java.
This is the main compression part:
for (int i =0; i <= n; i++)
{
// write the input line on the uncompressed stream
dsOut.writeString(lines[i]);
written++;
// reached the limit or the last input line?
int c = os.count();
if (c > limit || i == n)
{
// now we compress the data.

SuperWaba Companion

181

// note that the compression buffer must have the exact size of the stream
ByteArrayStream temp = new ByteArrayStream(c);
temp.writeBytes(outBuf,0,c);
temp.reset(); // let the compressor read the data from the beginning
os.reset(); // reuse the output buffer, now to store the compressed data
int size = ZLib.deflate(ZLib.BEST_COMPRESSION, temp, os); // compress it
// save on the catalog
if (cat.addRecord(size) >= 0)
{
cat.writeBytes(outBuf,0,size);
System.out.println("Compressed: "+c+" -> "+size+" bytes ("+written+"
lines)");
}
else throw new Exception("Error when writing "+size+" bytes");
os.reset(); // restart the output buffer to be able to add more lines
written = 0;
}
}

And this is the main decompression part:


for (int j = 0; j < nr; j++)
if (inFile.setRecordPos(j))
{
try
{
// get the record size
int size = inFile.getRecordSize();
// read the whole record
if (inFile.readBytes(inBuf,0,size) != size)
{
// can't read record!
continue;
}
// reuse the input and output buffers
is.reset();
os.reset();
// decompress the input stream to the output stream.
int sz = ZLib.inflate(is, os);
// start reading the uncompressed buffer
os.reset();
while (os.count() < sz)
{
String line = dos.readString();
processRecord(/*outFile,*/line);
count++;
}
// set the progressbar value
bar.setValue(j+1);
}
catch (OutOfMemoryError oo)
{
status.setText("Insufficient memory");
status.repaintNow();
}
catch (Exception e)
{
status.setText(e.getMessage());
status.repaintNow();

SuperWaba Companion
}
}

182

SuperWaba Companion

183

Chapter 31 Conduit Synchronization


OVERVIEW
This API, introduced in SuperWaba 5.1, makes really easy to develop conduits for
Palm Desktop and also for ActiveSync. As you may know, the usual ways to write conduits
are in C/C++, Delphi and Java (this one, using JSync). But JSync is going to be removed
from the upcoming Palm Desktop versions.
The synchronization API is now extended for Pocket PC devices. It works like a
Palm Desktop conduit: when the Pocket PC device connects, a SuperWaba application
(the conduit) is called and can then access the device to do a remote synchronization.
The only difference is that there's no user interaction for the synchronization start; when
ActiveSync connects to the device, the synchronization starts.
With the SyncConduit API, it is possible to write conduits using SuperWaba,
running on Windows. As you know, SuperWaba can run as a native Windows 32
application, on desktop. The supported Windows versions are 98, 2000, ME and XP. So,
the idea is to implement the conduit using the standard SuperWaba API and use the
Windows 32 VM to interpret it.
There are currently four classes available in the superwaba.ext.xplat.sync
package: Conduit, RemoteCatalog, RemoteCatalogRecord and RemoteFile. They will be
explained below.
A sample conduit is also provided: the
superwaba.samples.ext.sync.painter.PainterConduit. It is used to
synchronize to the desktop the image created using the Painter application. It retrieves
the image, displays it on the application and saves it to disk.
In general, to be able to create a conduit, you must:
1.
2.
3.
4.

Create a SuperWaba application that extends superwaba.ext.xplat.sync.Conduit.


Register the conduit.
Handle the synchronization and configuration requests.
If you uninstall your application, you must also unregister the conduit.

Conduits are always attached to a single creator id (but may be attached to multiple
users on a single machine). Desktop will only call your conduit during a hotsync if the
application with the corresponding creator id is installed. Thus, in the very first
synchronization, the one that installs your application, your conduit will NOT be called,
since there are no applications with the conduit's creator id. This is not true for
ActiveSync: when the conduit is registered, it will always run.

Conduit class

SuperWaba Companion

184

This abstract class is the one that defines that your SuperWaba application is a
conduit. It extends waba.ui.MainWindow, and so, you can display controls on it.
Palm Desktop Conduits has two states: configuration and synchronization. The
configuration occurs when the user select the customize option on the HotSync menu
icon. The synchronization happens when the user presses the hotsync button on the
cradle or on the PDA. Now, ActiveSync conduits also has both states, but there's no way
to access the configuration through ActiveSync; you must create a link to invoke the
configuration's screen.
There are, thus, two methods that must be implemented to handle these two states:
protected abstract void doSync()
protected abstract void doConfig()
In a normal SuperWaba program, you create your user interface in the onStart
method. When creating a conduit, the user interface creation must be handled instead in
the two distinct methods above. Note that your program is responsible for closing itself
and return the control to the caller process. Note also that, during a hotsync, no other
conduits will be run until your conduit application finishes.
A good way to separate the synchronization's logic from the configuration's is to
create two classes that extend waba.ui.Container and implement the logic inside each
class (see chapter 16), and, on each method above, do a swap to your classes. This is
the code for the PainterConduit class:
public class PainterConduit extends Conduit
{
public PainterConduit()
{
super("", TAB_ONLY_BORDER);
}
protected void doConfig()
{
setTitle("Painter Conduit - Configuration");
swap(new SetupPanel());
}
protected void doSync()
{
setTitle("Painter Conduit - Synchronization");
swap(new SyncPanel());
}
}
Note that the default constructor, Conduit(), is not implemented by the Conduit
class, thus you must always use the super(title, border_type) constructor.
There are two other useful public static methods:

log(String text): prints a text in the HotSync.Log file, inside the user's folder. For
Pocket PC, it writes text to the debugconsole.txt file, just like a Vm.debug would.

SuperWaba Companion

185

yield(): this one lets hotsync take a breath. What you think would happen if your
program never return control to HotSync during a configuration? Simple: the
connection between the computer and the PDA would die. So, the way to tell HS that
your program is alive and also to let HotSync keep the connection alive is to call often
the yield method. Note that there's a thread on the Conduit class that keeps yielding
while there are no events on your conduit; but if you're inside a loop bringing things
from the server, you must remember to call this method by yourself. Fortunately, it is
very easy to know if hotsync is happy or not: the animated arrows will stop when
hotsync is not being yielded. Note that this method does nothing on Pocket PC
conduits.

RemoteCatalog class
This is the class that handles a catalog (PDB file) stored on the PDA. It is used with
the superwaba.ext.xplat.sync.RemoteCatalogRecord class, which in turn
represents a single record of the PDB. This model resembles the one used in Palm
Desktop's JSync.
The RemoteCatalogRecord contains two abstract records: write and read.
The underlying C++ API has some restrictions that are passed over to SuperWaba:

Only ONE catalog can be open at a time. Trying to open more than one, before closing
the prior, will result in a RuntimeException.
You must not read and write at a catalog at the same time. First, do all the readings,
then all the writings (or vice-versa).
Access the records in sequence, it is much faster.
If you plan to delete records from the pdb, be careful: this can be a very high timeconsuming operation. The usual way to treat this is to delete records always from the
end, or delete the whole catalog and create another one with the same name.
Lets see the available methods inside the RemoteCatalog class:

RemoteCatalog(String name, int mode, int recordSize): opens a remote


catalog.
name: must follow the standard pattern used in the Catalog class: name.crtr.type
mode: can be one of these: Catalog.READ_ONLY, Catalog.WRITE_ONLY,
Catalog.READ_WRITE, Catalog.CREATE. They work in the exact same way as
the Catalog class.
recordSize: Used only when writting records. If you plan to write records with fixed
size, pass in the desired size. Otherwise, pass
RemoteCatalog.RECORD_SIZE_AUTO to automatically expand or shrink the
record.
RemoteCatalog(String name): opens a remote catalog in READ_ONLY mode.
isOpen(): returns true if the catalog is open, false otherwise.
delete(): completely deletes the catalog, closing it first.
getRecordCount(): returns the number of records in the catalog.

SuperWaba Companion

186

readRecord(int index, RemoteCatalogRecord rec): this method is used to


read a record from the remote catalog. It returns true or false, if the operation is
successful or not.
index: the record index you want to retrieve.
rec: an instance of RemoteCatalogRecord, who will read the data provided by the
conduit through the read method.
writeRecord(int index, RemoteCatalogRecord rec): used to write a record
to the remote catalog. Also returns the status of the operation.
index: the record index you want to store. IMPORTANT: if index is -1, the record is
appended, otherwise, the given record is OVERWRITTEN. It is not possible to insert
a record into a given position due to limitations of the native API. Also, passing a
record index greater than the number of records may cause unexpected results.
rec: an instance of RemoteCatalogRecord, who will write the data.
getRecordPos(): returns the current record position.
deleteRecord(int index): deletes the given record index.
skipBytes: offsets the cursor in the current record a number of bytes. The cursor
defines where read and write operations start from in the record. It can be negative but
cannot underflow neither overflow the record size.
getNextModifiedRecordIndex(): Returns the next modified record index. Can be
used with the readRecord to only retrieve the changed records since the last
synchronization.
close(): closes the current Catalog. Note that you must explicitly close the catalog,
otherwise, no other conduit will be able to open it and also you will not be able to open
another remote catalog.
static String []listCatalogs(int crtr, int type): Lists the available
catalogs on the device that has the given creator id and type. If you don't pass a
creator id and/or a type, this method will return with NO RESULTS. Returns a String
array with the answer, or null if no db was found that matched the criteria. You can
convert a creator String into an integer using waba.sys.Convert.chars2int
method.

RemoteCatalogRecord class
This abstract class is used to read and write data, and is used in conjunction with
the methods readRecord and writeRecord of the RemoteCatalog class.
Two methods must be implemented:
protected abstract void write(DataStream ds)
protected abstract void read(DataStream ds)
With the given DataStream, you can read or write all your needed data.
There are also two useful members:

RemoteCatalog rc: the reference to the RemoteCatalog.


int size: the size of the current record being read. It is meaningless when writing
data.

SuperWaba Companion

187

RemoteFile
This class is used to copy a whole file between the desktop and the Pocket PC. We
plan to extend it in the future to also handle data on the card of a Palm OS device (using
the functions provided by the Virtual File System).
Only static members are provided to list, copy to/from and delete files, as shown
below:

String[] listFiles(String dir): list the files from the given dir. The strings
returned are the names of the files and directories contained within this directory. This
method returns null if the directory can't be read or if the operation fails. Path names
ends with /, so it is easy to distinguish them from a file. The dir parameter can contain
wildcards, and can use '\' or '/' (it will be internally converted to '\'). If it doesn't ends
with a wildcard, *.* will be appended.
copyToRemote(String srcFile, String dstFile): Copies a file from desktop
to remote. Note that dstFile must be the file name, not just a folder. For example, to
copy a file Test.jpg to a folder \Palm, the function must be called as
copyToRemote("c:\\folder\\Test.jpg","\\Palm\\Test.jpg").
copyFromRemote(String srcFile, String dstFile): Copies on the opposite
direction when compared to copyToRemote.
delete(String fileOrFolder): deletes a file or a folder from the remote device.
Read-only files are also deleted.

Conduit Registration
If you don't had installed both ActiveSync and PalmDesktop, you will have to copy
some dlls to the windows/system32 directory, otherwise the conduits will not be
registered. These dlls are located in folder bin/tools/dlls. If you had installed PalmDesktop
but not ActiveSync, you must copy the files rapi.dll and ceutil.dll to the system32 folder.
Otherwise, if you had installed ActiveSync but not PalmDesktop, you must copy all the dlls
in the hotsync folder to system32.
As said before, a Conduit must be registered to be recognized by HotSync or by
ActiveSync. Fortunately, the Conduit class has a method to register and another to
unregister a conduit. You can do this by invoking SuperWaba.exe from the command line,
passing some parameters. This is how you do it:
For Palm Desktop:

To register a conduit:

cd C:\SuperWaba
SuperWaba.exe <full command line to your app> /rp <full command line to your
app>

To unregister a conduit:
cd C:\SuperWaba
SuperWaba.exe <full command line to your app> /up <app creator id>

SuperWaba Companion

188

For Active Sync:


It uses the same commands as above, only replacing /rp by /ra and /up by /ua
(p stands for Palm Desktop and a for ActiveSync).
The calls above return an errorlevel: 0 means success, 1 means error.
The <full command line to your app> is defined as: <full package
name> <folder inside SuperWaba that contains your classes> <creator id>.
This is also generated using /L option with Exegen (to create a lnk file for Windows CE )
and checking the command line inside the lnk file (you may need to rename it to
something else before dumping its contents).
Here's a sample, used for the PainterConduit, used to register for PalmDesktop
(everything on the same line!):

To register:

c:\superwaba >superwaba.exe
superwaba/samples/ext/sync/painter/PainterConduit PainterConduit
PAin /rp superwaba/samples/ext/sync/painter/PainterConduit
PainterConduit PAin<enter>

To unregister:

c:\superwaba >superwaba.exe
superwaba/samples/ext/sync/painter/PainterConduit PainterConduit
PAin /up PAin<enter>
As noticied above, we're invoking the SuperWaba.exe to interpret our Conduit
class, which is located under c:\SuperWaba\PainterConduit and has creator id PAin to
register or unregister the application itself. And all this must be done from inside
c:\SuperWaba.
It is possible to execute SuperWaba.exe from outside the c:\superwaba folder. Starting
on version 5.1, when the VM starts, it checks if it the current folder has SuperWaba on its
name. If not, then it will try to change to \SuperWaba. This is very useful if your
installation program cannot change the current directory. Note that there are two
restrictions: one, SuperWaba must already be installed on c:\SuperWaba; two, the
following dlls must be in the SuperWaba's folder: cmds21.dll, condmgr.dll, hsapi.dll. They
are present in the Palm Desktop program and may be deleted after the conduit's
registration.

Important Tips

The conduit's creator id MUST MATCH the one used for the application, otherwise, the
Pocket PC conduit will not work as expected.

SuperWaba Companion

189

It is always worth to remember that, if your application is not installed in the PDA, the
conduit for Palm Desktop will not run.
It is not possible to use JDBC from your SuperWaba's program. So, if you plan to
retrieve data via waba.io.Socket, you should use the HttpStream class to communicate
with a server program (an asp page, perl, servlet, or anything else). This server
program will then use JDBC or any other kinds of database communication.
Only during a hotync is possible to find the name of the user who's handheld is being
synchronized, through the waba.sys.Settings.userName member. It is not
possible to get the userName during the configuration stage.
Also during a hotsync, the waba.sys.Settings.romVersion member will store the
rom version of the device being synchronized.
All the SuperWaba API and native libraries will run on Windows (like CatalogSearch,
ZLib, Gif/Png/JPeg images, etc).
You must install SuperWaba on the user's machine so that your conduit can run.
Fortunately, there's an installshield setup prepared for this on
SuperWabaSDK\bin\installers\vm\win32 (it also installs the Conduit files).
To install your program on the user's PDA, you can create an installation using Exegen
The SuperWaba Global Library files are XPlatSyncConduit.pdb and
XPlatSyncConduit.dll.
You MUST NEVER try to install these two files on the PDA: they target only Microsoft
Windows 98 and beyond.
The required Palm Desktop software is: 4.1.0 for Windows 2000 (and before), and
4.1.4 for Windows XP.
The conduit, when registered using the /r option, registers itself for all users. If you
want to register a conduit for a single user, you must update the created registry key
(inside HKEY_CURRENT_USER\Software\U.S. Robotics\Pilot
Desktop\Applicaton<number>), adding a Creator key.
It is always a good idea to read the C++SyncCompanion.pdf present in the Conduit
Development Kit available at http://www.palmos.com/dev/tech/conduits/
The used CDK was 4.03, not 6.01. This ensures compatibility with old Palm Desktops.
As any SuperWaba program, the conduit must also respect the limit of 65500 bytes for
arrays and other data structures. Keep this in mind if you're planning to receive a huge
file or a String bigger than 65500/2 chars in length.
The ActiveSync conduit uses a trick. There's a special registry key that is called when
a device is connected. This key is located at
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE Services\AutoStartOnConnect.
Search the web and you'll find more information about it. The conduit for Pocket PC
uses the Remote API to communicate with the device.
There's no way to call the configuration panel from ActiveSync; you must, instead, run
the program passing the parameter /ca, like this (which runs the setup for the
PaintConduit sample):
c:\superwaba >SuperWaba superwaba/samples/ext/sync/painter/PainterConduit
PainterConduit PAin /ca

If the registration fails, added <path to palmdesktop's root folder>;C:\SuperWaba; to


the begining of the path, because there may also be a restriction of 256 for env
variables on Windows.
If you have only PalmDesktop and not ActiveSync, you must copy the ActiveSync dlls
located in \SuperWabaSDK\bin\tools\dlls\activesync to c:\SuperWaba. On the other
hand, if you don't have PalmDesktop installed, but only ActiveSync, then you must

SuperWaba Companion

190

copy PalmDesktop's dlls, located at \SuperWabaSDK\bin\tools\dlls\hotsync, to


c:\SuperWaba.

Sample for reading


The PainterConduit was already shown above. Here's the SetupPanel class:
public class SetupPanel extends Container
{
private Check chBringImage;
public void onStart()
{
add(chBringImage = new Check("Bring image"),LEFT,AFTER+5);
chBringImage.setChecked("yes".equals(Settings.appSettings));
}
public void onEvent(Event e)
{
switch (e.type)
{
case ControlEvent.PRESSED:
if (e.target == chBringImage)
Settings.appSettings = chBringImage.getChecked() ? "yes" : null;
break;
}
}
}

And the SyncPanel class:


public class SyncPanel extends Container
{
String bmpName = "image.bmp";
class PaintRecord extends RemoteCatalogRecord
{
protected void read(DataStream ds)
{
File out = new File(bmpName,File.READ_ONLY);
if (out.isOpen())
out.delete();
// write to the file
out = new File(bmpName,File.CREATE);
byte []bytes = new byte[size];
ds.readBytes(bytes,0,size);
out.writeBytes(bytes,0,size);
out.close();
// show it here
bmp = new Image(bytes);
}
protected void write(DataStream ds)
{
}
}
private Image bmp; // set by the PaintRecord
Label status;
public void onStart()

SuperWaba Companion

191

{
boolean bringImages = "yes".equals(Settings.appSettings);
if (bringImages)
{
add(status = new Label("",CENTER),LEFT,BOTTOM);
MainWindow.getMainWindow().repaintNow();
showStatus("Synchronizing Painter for "+Settings.userName,false);
String catName = "BMP.PAin.BITM";
String []cats =
RemoteCatalog.listCatalogs(Convert.chars2int("PAin"),Convert.chars2int("BITM"));
if (cats == null)
showStatus("No bitmaps to synchronize",true);
else
if (cats[0].equals(catName))
{
RemoteCatalog rc = new RemoteCatalog(catName);
showStatus("Retrieving record...",false);
PaintRecord pr = new PaintRecord();
if (rc.isOpen() && rc.getRecordCount() > 0 && rc.readRecord(0,pr))
{
if (bmp.getWidth() > 0)
{
rc.delete(); // already closes it (of course).
showStatus("Bitmap stored on "+bmpName,true);
Button btn = new Button(bmp);
btn.onlyShowImage();
add(btn,CENTER,TOP+3);
repaintNow();
Vm.sleep(2000); // let the user
}
else showStatus("Error when loading bitmap",true);
}
else
{
showStatus("Error! Bitmap not synchronized.",true);
if (rc.isOpen())
rc.close();
}
}
}
MainWindow.getMainWindow().exit(0);
}
private void showStatus(String s, boolean log2)
{
status.setText(s);
status.repaintNow();
if (log2)
{
Conduit.log(s);
Vm.sleep(1000);
}
}
}

Sample for writing


The sample below just shows how to write a record, based on the PainterConduit. It could
be changed to write a bmp from the desktop to the device.

SuperWaba Companion

192

String catName = "BMP.PAin.BITM";


RemoteCatalog rc =
new
RemoteCatalog(catName,Catalog.CREATE,RemoteCatalog.RECORD_SIZE_AUTO);
PaintRecord pr = new PaintRecord();
if (rc.isOpen())
{
showStatus(rc.writeRecord(-1,pr)?"written":"error on write",false);
rc.close();
}

Sample for RemoteFile


// Try to delete the BMP.pdb file - in the dumb way (no lookup were needed)
String []files = RemoteFile.listFiles("/SuperWaba/Painter");
if (files != null)
{
showStatus(files.length+" files found",true);
int i;
for (i =0; i < files.length; i++)
if (files[i].equals("BMP.pdb"))
{
showStatus(RemoteFile.delete("/SuperWaba/Painter/BMP.pdb")?"file
BMP.pdb deleted":"file not deleted",true);
break;
}
if (i == files.length) showStatus("file BMP.pdb not found",true);
}
boolean ok;
ok=RemoteFile.copyFromRemote("/SuperWaba/Painter/Painter.pdb","c:/Painter.pdb");
showStatus("Copied from?"+ok,true);
ok=RemoteFile.copyToRemote("`c:/uigadgetsFlat.bmp","/SuperWaba/Painter/image.bmp
");
showStatus("Copied to?"+ok,true);

SuperWaba Companion

263

PART VII APPENDIXES

SuperWaba Companion

264

Appendix I - Thanks to
All SuperWaba community who are always helping to improve this software.
Special thanks to:

Rick Wild: who created Waba and started everything


Tom Cuthill: who provided the Scanner support
Eric Frick (AirNet Systems) who donated a Symbol SPT 1500
Dave Slaughter: for the 1.21 WinCE/desktop versions
Diego Montalvo, the webdesigner of the first SuperWaba.org site
Ed Crandell, creator of the helpful WabaWorkbench site
Rob Nielsen, creator of WExtras and the java version of exegen/warp
Mike Aeneas, who is constantly helping me in various issues
Mike Brereton, author of EWE, who kindly helped me every time I asked for help in the
Windows platform
David Britto, who presented me to the Java and the Palm worlds
Peter Dickerson, who is always helping improve SuperWaba's reliability.
David Haysmith (from The WhiteClarkeGroup), a valuable SuperWaba partner
Sir Andy Faeryblood, who provided important improvements for the VM (popup
blocking modal windows, and the db2e library)
Arnaud Farine, for the great support in France.
Jean Rissoto, for the MultiEdit class and also many other VM improvements.
Frank Diebolt, for the great work in the game package, the new SuperWaba
ant build process and the complete setup of SourceForge.
Daniel Tauschke, author of the first IDE dedicated to easy SuperWaba
development/deployment.
Osvaldo Garcia and Renan Bundt (from Copel S.A.) for the donation of a Kyocera QCP
6035.
Pierre G. Richard, for the many enhancements in XML and image libraries. Pierre now
represent SuperWaba in Europe. Welcome to the team, Pierre!
Alsan Wong, for his hard work in the unicode port.
Oliver Erdmann, for his great UfoLib library, which was merged into SuperWaba to add
unicode support.
Marcos Guirland Nowosad, who created the SuperOpt and also improves the
PDBDriver. Marcos represent us in USA. Welcome to the team, Marcos!
Rony G. Flatcher, Kathrin Braunwarth, Gilbert Fridgen and Fabian Krher, for the great
PIMAL.
Ian Reinhart Geiser for the great Palm OS installation tool.

Thanks also to Greg Ouzounian and to Steve Kelem who made some grammatical
revisions.

SuperWaba Companion

265

Appendix II - Copyright
All contents of this tutorial, including text, programs, applets, source code, and images are
copyrighted and owned by SuperWaba Ltda, all rights reserved. No material can be
reproduced and/or distributed electronically or in print without written permission.
The use of the source code for the examples is permitted to the company that purchased
this subscription, only.

SuperWaba Companion

266

Appendix III Document Changes

1.01
added ComboBox field
1.02
fixed IrPrint neede files. 196
added Known Incompatibilities topic. 15
1.03
removed ComboBox field added in 1.01
added Edit.alignment field 64
1.04
added comments 202
1.1
added long/float comments. 183
added new Conduit Synchronization chapter (31), and renumbered the following
ones.
added minDragBarSize. 75
changed info for read modes. 104
info on new Flat ui style. 45-46
1.11
fixed toc
added memory info on conduits.
removed blank pages
important tip at 204
changed ziplib sample.
1.12
enhanced the conduit synchronization chapter.
1.2
enhanced the Conduit API chapter.
1.42
added "PalmOS5/ARM VMware based development environment" on chapter 38
1.43
added conduit dll installation instructions. 231
1.44
rnovais - improved PDBDriver's section
1.45
rnovais improved PDBDriver table's structure information.
1.46
rnovais added the RENAME TABLE command in PDBDriver.
guich added "Logging and Debugging" at PDBDriver's section
rnovais added the RENAME COLUMN command in PDBDriver.
1.47
Added new chapter PDBDriver Synchronization Sample
1.48
rnovais added Date and DateTime data type in PDBDriver's section
rnovais added ResultSet.getDate(col | colName) and ResultSet.getDateTime(col |
colName) methods in ResultSet's section
1.49

SuperWaba Companion

rnovais added LIKE statements usage in PDBDriver's section


1.50
rnovais added new section PDBDriver SQL Functions in PDBDriver's chapter.
1.51
rnovais fixed the DATE and DATETIME format.
1.52
rnovais added the SQL functions UPPER, LOWER, ABS in PDBDriver SQL
functions section.
rnovais added the the SQL function ABS to short, long, float and double types
rnovais added DATE and DATETIME to table structure
rnovais improved the ResultSet.getDate() and ResultSet.getTime() section
1.53
rnovais fixed and improved the PreparedStatement's section
rnovais added setDate and setDateTime in PreparedStatement's section
1.54
rnovais Removed the PDBDriver's section
guich added Scanner chapter (26)

267

Vous aimerez peut-être aussi