A Complete Porting Example


Introduction

In this Magercise, we will port a complete OS/2 application from C/PM to Java.  This Magercise will cover the following concepts:

Examining the old application

The application that we will be porting is a "Mini Personal Information Manager" known as MiniPIM.  It's a fairly simple application that's really four applications in one.  A set of four buttons at the top of all screens allow you to switch between the components of MiniPIM:

  • Notepad -- a very simple text editor/viewer.  Text can be opened or saved using menus.

  • Phone List -- a simple phone list that will contains business, home and fax numbers.  This information is automatically loaded when you start MiniPIM, and is saved when you exit MiniPIM.

  • Calculator -- a simple four-function floating-point calculator.

  • To-Do List -- a simple to do list.  Entries are loaded and saved in the same manner as the phone list.

 

warp_a.gif (18009 bytes) Complete source code and the executable for the OS/2 version is here.

 

The Old Interface

The original application looks as follows:

onotepad.jpg (44670 bytes)

The MiniPIM Notepad

 

ophonelist.jpg (28908 bytes)

The MiniPIM Phone List

 

ocalc.jpg (26180 bytes)

The MiniPIM Calculator

 

otodo.jpg (25520 bytes)

The MiniPIM To-Do List

 

One thing you may notice is that the interface looks very simple.   Depending upon how you implement it, it might prove to be tricky to get it to look quite like you'd like.

A big difference in most OS/2 and Java GUIs is resizability of the windows.  In many OS/2 applications, the windows cannot be resized at all.  In some, you can resize the window, but the contents stay fixed in the same position.   And in a few, resizing the window will cause the GUI to be rearranged dynamically like Java Layout Managers.

This application will allow you to resize windows, but it does not adjust component positions.  Keep this in mind for when we discuss enhancements.

Examine each of the above screen pictures.  Think about how each screen is organized, which parts of the GUI could be split out into sub parts.

Examining the Old Behavior

The MiniPIM application has the following behavior:

  • General

    • Buttons at top of screen select the named component.

    • Menus are present for all screens but only affect the Notepad.

  • Notepad

    • Acts like a simple editor

    • Menu always acts on Notepad

      • New -- clears the text area and the current file name

      • Open -- opens a file into the text area

      • Save -- saves a file using the current name. If no current name set, this acts the same as Save as.  The data is stored in the named file in ASCII (readable text) format.

      • Save as -- brings up a file requestor and saves the file with the selected name. The data is stored in the named file in ASCII (readable text) format.

  • Phone List

    • Data is saved upon MiniPIM exit, loaded on re-entry.  A fixed file name of minipim.ini is used to hold the data.  The data is stored in binary format.

    • Names can be typed or edited in the combobox and this will change the current value. Keep this in mind -- Java does not have ComboBoxes and we must come up with a different way to handle this.

    • Add Button adds a new entry to the list.

    • Remove removes the currently-displayed entry from the list.

  • Calculator

    • A very simple four-function floating point calculator.

    • Modeled after standard four-function calculator.  No data is saved between MiniPIM sessions.

  • To-Do List

    • Entries may be typed in the TextEntryField at the top of the screen.

    • Pressing the Add button adds the entry to the central list.

    • Pressing the Remove button removes the currently-selected item in the list.

    • The list is saved upon MiniPIM exit, loaded on reentry.  A fixed file name of minipim.ini is used to hold the data.  The data is stored in binary format.

Thinking About Enhancements

Whenever you are porting an application, it usually is going to involve a great deal of work.

If you have been thinking about possible enhancements to the application being ported, it would be a very wise idea to consider the enhancements before you port it.  This is important for two reasons:

  • Thinking about later enhancements ensures that you have an open mindset.  If you consider possible changes, you are much less likely to implement your port in a manner that prevents those enhancements from being added later.  Better still, many times this will help influence design decisions that will make it even easier to modify the application later.
  • Thinking about enhancements opens the possibility that some enhancements can be included during the port itself.  Most language-to-language ports cannot possibly implement the exact same behavior as the original application.  This is usually due to restrictions in the target language, or the lifting of restirctions in the target langauge that allow for a more natural way to implement the program.  Because the program is likely to be different anyway, it can often make sense to make some enhancements at the time of the port.  This decision should be weighed against the complexity of the enhacement.  You want to make sure the program was ported correctly, and give as low a chance as possible of enhancements breaking the application.

We will implement the following enhancements/changes during our port:

  • The GUI should be dynamic.  If the window is resized, the component layout should be rearranged appropriately.  This is generally easy, as layout managers take care of this for us.
  • A more natural way to combine the four mini applications together would be to use a tabbed panel. This is a control that acts like cards in a Rolodex, each card having a tab that provides access to that card.  MageLang provides a free tabbed panel called TabSplitter that we will use for this task.  As it turns out, using a pre-made control to handle movement between the panels simplifies the GUI as well.
  • Java does not have a ComboBox control.  There is a Choice control, which looks like a ComboBox, but you cannot edit the textfield at its top.  We will need to have the Add button bring up a dialog to get the name of the person to add to the phone list.
  • Java has a few nice ways of handling numeric exceptions.  We should take advantage of them.  As a matter of fact, they're hard to avoid.  This handling includes:
    • Division of a positive number by zero returns the value Float.POSITIVE_INFINITY.
    • Division of a negative number by zero returns the value Float.NEGATIVE_INFINITY.
    • Division of 0 by 0 returns Float.NaN (Not a Number).

    The String representations of these are "Infinity", "-Infinity" and "NaN" respectively.  We should make sure that if the display has one of these values that the appropriate value for the float is used.

  • Just for fun, we'll enhance the look of the Calculator display by making its background black, text color green, and use a larger italic font.

Building the New GUI

The first step to building the new GUI in Java is to determine how we want to lay out the components.  Examine the above screen shots of the OS/2 components.  Now pretend that the application had been implemented using a nice tabbed panel look in OS/2.   If you pretend hard enough, it almost appears as though someone has used a paint program to create some newer screen pictures...

xnotepad.gif (6772 bytes)

xphone.gif (6891 bytes)

Xcalculator.gif (8116 bytes)

xtodo.gif (7150 bytes)

 

That's the look we want to implement in Java!  And when we're finished the application might look like this:

jnotepad.gif (4670 bytes)

jphone.gif (4971 bytes)

jcalc.gif (5221 bytes)

jtodo.gif (4243 bytes)

 

Looks like our imagination is fertile enough.  But how exactly are those components laid out to make the Java application look like that?  That's where you have to do some thinking!

If you need help, follow this link to see some diagrams and trees that describe the GUI layouts used for this application.

The tabbed panel component is called com.magelang.TabSplitter.   You can add it to your design by using the Options->Add bean menu item and specifying its name.  You add componets or panels to it by dropping panels on it.  One note -- as it uses a CardLayout for its representation of components, you'll need to use the Beans List to move between the components.  You can get to the Beans List via the Tools->Beans List menu item.  Get used to the Beans List -- there are many times when it will become the only way to manipulate components, especially when adding components to a BorderLayout that has a container in its center.

If you're really having trouble building the GUI, follow this link to get instructions on how to proceed.

When you're finished, make sure you save and test your application's GUI.

Just for fun, try dragging one of the tabs in the TabSplitter on top of another tab...

Writing the Java Kernel Code

In Examining the Old Behavior, we discussed the behavior of the application as it currently exists.  We want to emulate all of the existing behavior, with the following exceptions:

  • Component positions should be dynamic -- this is taken care of through the use of layout managers in the previous step.
  • ComboBox is not supported in Java, so we need to bring up a dialog to add an entry.
  • File names for the phone list and to-do list should not be hardcoded in the code - they should be provided as property values to the beans.
  • We used a tabbed panel instead of buttons.
  • We want to handle floating point problems in a nicer way.

To implement the functionality, we'll need to define four Kernel classes.  The Kernel is a piece of code that is essentially the "guts" of the application.   We're having four Kernels because the functionality is well separated between the components.  We shall call these Kernels:

  • NotepadKernel
  • PhoneListKernel
  • CalculatorKernel
  • ToDoListKenel

The following describes the behavior of these Kernels in pseudocode.  See the solution code in project MageLang Magercise Solutions, package magercises.minipim for a sample implementation.

Define all the listed properties and public methods using the BeanInfo browser in VisualAge.  Inside BeanInfo, press the "New property feature" button on the toolbar to add a propety, "New method feature" to add a method.

Note that there are two types of file I/O mentioned in the behavior specification: binary and ASCII.  Take a look at the descriptions of the Java File I/O classes in the Java API reference (select "Help->Reference" inside VisualAge.)

NotepadKernel


Properties
String dirName name of directory containing file to save
String fileName name of file to save
TextArea text a ref to the text area to load/save

Methods
public void load()
open the file that dirName and fileName refer to for READ
set readText to ""
while not end-of-file
  read text and append it to readText
  set the contents of text to readText
close the file
public void save()
if no filename is set
  throw a runtime exception "no file set"

open the file that dirName and fileName refer to for WRITE
dump the contents of text to the file
close the file

 

PhoneListKernel


Properties
Choice name the Choice list of names in the phone book
Hashtable fax a ref to a hash table of fax numbers
Hashtable business a ref to a hash table of business numbers
Hashtable home a ref to a hash table of home numbers
String    fileame the file name to store the phone list
String    dirName the dir containing the save file

Methods
public void load()
open the file referenced by dirName/fileName for READ
for each group of stuff in the file
  read a String for the name
  read a String for the fax number
  read a String for the home number
  read a String for the business number
  add the name to the name Choice
  add (name, fax) to the fax hashtable
  add (name, home) to the home hashtable
  add (name, business) to the business hashtable
close the file
public void save()
open the file referenced by dirName/fileName for WRITE
for each name in the name Choice
  write the name to the file
  get the fax number for the name & write it to the file
  get the home number for the name & write it to the file
  get the business number for the name & write it to the file
close the file

 

CalculatorKernel


Properties
String display the value to display on the calculator

Note that this should be a bound property!  That is, whenever this field changes, it will fire a propertyChange event.  This is easily done by checking the "bound" box when creating a property under BeanInfo.


Other (Recommended) Data
float memory an internal memory to keep track of current computation
boolean startNewDisplay tells the key() method whether to append the key pressed to the display or start a new display
String pendingOperation the label of the _last_ operation key pressed(remember, when a key is pressed, we are in the middle of the current operation, so we finalize the last operation and store the current one for the next operation key pressed to compute

Methods
protected void compute()
convert display to a float
compute the new memory value based on pendingOperation
set the display
public void key(String keyName)
if the key pressed was 0-9
  if we should start a new display or
    current display is "0"
      set display to key pressed
      make sure we do not start a new display next time
  else
      append key pressed to current display

else if the key pressed was clear
  clear the display to "0"
  make sure we start a new display next time
  clear memory
  send pendingOperation to "+" (adds display to 0 memory)

else if the key pressed was an operation key or "="
  compute()
  set pending operation to the key that was pressed
  make sure we start a new display the next time
  if key pressed was "="
    clear memory

 

ToDoListKernel


Properties
String fileName the name of the file to save/load
String dirName the name of the directory containing fileName
List   list the list of to-do items

Methods
public void load()
open the file referenced by dirName/fileName for READ
for each String in the file
  add the string to list
close the file
public void save()
open the file referenced by dirName/fileName for WRITE
for each String in list
  write the string to the file
close the file

 

Connecting the GUI to the Kernel

Finally, you need to connect the GUI components to the kernel components.  If you paid close attention to the kernel descriptions given, yo may have noticed that the kernels do not peform all of the work.  Much of the work to be done in the connections will be done entirely in the GUI.  For example, you will need to set up the To-Do List buttons to add and remove items from the List component.  The kernel isn't even used until the aplication is exited or restarted.

Note that you will need to add the following pieces to finish the Magercise:

  • A dialog that asks for the name of a person to add to the phone list
  • An instance of each of the kernels that you defined in the last step
  • Three hashtables to be used for storing data in the phone listing component.  (Use Options->Add Bean and add java.util.Hashtable components.)

If you need help determining which connections you need, follow this link.


Copyright © 1996-1997 MageLang Institute. All Rights Reserved.