Developer/2000
Strategies for Forms Cross-UI Deployment Table of Contents
IntroductionIn today's computing world, it is not uncommon to work in a heterogeneous environment which uses a multitude of different machines with a plethora of different user interfaces (UI). For example, an ordering system may need to be run on MS Windows in the branch offices, and on character-mode terminals in the warehouse where the order is fulfilled. The developers, on the other hand, may develop the system on Motif. The need for cross-platform and cross-UI application development and deployment is very evident in today's computing environment. Developer/2000 Forms 4.5 allows you to develop an application, and then re-generate and run that same application on a multitude of platforms without a single change to the source application. On each platform, the application will be displayed using that platform's native widgets, giving the unique look-and-feel of that platform. However, there are differences in the capabilities of the different environments, as well as differences in the expectations of the users on various platforms, which can cause problems when moving applications between user interfaces. This paper examines various portability issues, describes the different development strategies for writing portable applications to run on MS Windows, Macintosh, Motif and character-mode terminals, and describes some techniques to create a UI standard and to maximize reusability of your code. Development StrategiesWith the inherent hardware and UI differences, our goal is to deliver applications that users on different platforms will accept and enjoy using, thereby raising their productivity. However, this could potentially be a non-trivial task and may involve some of the tradeoffs below.
There are three strategies you can follow when writing portable applications.
These are described in more detail in the following sections. You can also use a combination of the above methods to suit your needs. You should also bear in mind the issues discussed in the section Portability Issues and Solutions. Single Source Lowest Common Denominator DevelopmentYou can use this method to create applications that look exactly the same on all platforms. Before you start to develop your application, you need to know in advance the deployment platforms and use only those capabilities that are available on all those platforms. Depending on the particular deployment platforms, you may not be able to use some of the following port-specific features in Forms:
This approach is not ideal for the following reasons.
Multiple Sources DevelopmentWith this method, the deployed application looks like it has been created on that specific deployment platform. The goal is to reuse as much of the logic in the base application as possible, while changing the UI to look exactly like a natively built application. To achieve this, you should use the following steps.
The main disadvantage of this approach is similar to maintaining different copies of the source application although the effort is greatly reduced with the use of the reusability techniques. The advantage is that the users of each platform will get to use an application which looks native for each UI, with the features that they are accustomed to. It also means that they would not be susceptible to any performance implications at startup that the Single Source Dynamic Modification method may be. Single Source Dynamic Modification DevelopmentThis approach avoids the disadvantages of the previous two methods, while still delivering pleasant-looking applications on each deployment platform. You can achieve this by:
Dynamically Modifying the ApplicationForms provides a built-in, get_application_property, to determine the UI at runtime. Depending on the UI, you can dynamically
The details are discussed in the section Portability Issues and Solutions. Re-Referencing Port-Specific ImplementationUsers on different deployment platforms are accustomed to a specific standard in their applications. The goal is to be able to pick up the port-specific functionality for each deployment platform. The architecture shown in the following figure can be achieved using the steps below.
Figure 1 Architecture for Re-Referencing Port-Specific Implementation
The advantage of this approach is being able to deliver port-specific functionality while maintaining a single source for your application. Reusability TechniquesForms provides many features that help you implement the strategies described above. The following are the techniques detailed in this section to enable you to develop and test objects and code once, and reuse them in all your applications.
Reuse individual objects and triggers that have already been tested.
Deliver applications that conform to your UI standards on different platforms using property classes.
Create entire reusable applications using object groups.
Ensure that your developers have all the necessary reusable objects by putting the libraries, object groups, property classes and color palette in a template form.
Encapsulate and protect your developers from the implementation details with the use of PL/SQL libraries by providing an API (Application Programming Interface) for reusable code.
Reduce network traffic and improve the performance of your application by moving code that need not be executed on the client to the server. Drag-and-Drop Object ReuseObjects and triggers can be encapsulated within a source module and reused by other applications. First, you need to create the objects and store them in a form module. To reuse the object, you simply drag and drop it into the destination module. When reusing objects, you have two choices.
When you copy an object, it is incorporated into the target module immediately and does not maintain a link to the source object. Thus, any subsequent changes to the source object do not affect the target object and the target object can be modified to suit the needs of the target module.
When you reference an object, a link to the source object is incorporated into the target module. Any changes made to the source object will be picked up when the target module is subsequently opened or generated. Since the reference is resolved at generate time, using this feature will not incur additional overhead at runtime. Property ClassA property class is a named list of properties and triggers. Once defined, it can be applied to any object in your application. The object will then inherit all the properties and triggers that make sense for it. Property classes can inherit properties and triggers from other property classes, thus giving you multi-level inheritance. Using this feature, you can create a hierarchy of property classes, with the more specific property classes inheriting from the more generic property classes. You can then apply these property classes to objects in your application. Any change to the property classes will then be propagated to the property classes and objects that make use of them. For example, you can create property classes for all the UI widgets according to your UI standard so that your application will have the same look-and-feel. Using the same architecture as in the section Re-Referencing Port-Specific Implementation as shown in the figure below, you can place generic property classes (UI attributes that apply across platforms) at the lowest level, and the port-specific attributes customizing the generic property classes in the port-specific repositories. Your application will pick up the UI standard you define for each platform when you use the port-specific property classes.
Figure 2 Architecture for Creating UI Standards and Reusable Objects Object GroupWith drag-and-drop object reuse, you can only reuse one object at a time. Object groups allow you to encapsulate a number of objects and triggers into a reusable component. For example, you may have a calendar application that can be used by other applications. Instead of referencing each object in the calendar application separately, you can put all the objects and triggers in the calendar application into an object group, and simply drag and drop this object group into your target module. This has the following two advantages:
These object groups are already built and tested by the original creator. You simply drag the group into your application and enjoy the use of a bug-free component.
If you had to remember which objects are required by the reusable application and drag those into your application one at a time, there is a high chance that you may omit some objects. The original creator knows exactly the objects that make up the reusable application and would be able to create the object group without any error. As a result, you will be able to make use of the reusable application with minimal effort and error. Using the architecture shown above, you can base your objects in the object groups on the port-specific property classes and libraries so that the port-specific implementation will be picked up. Template FormBefore you start developing your application, you should define a UI standard so that your application has the same look-and-feel throughout. This will increase its acceptance by your end users. You can define a template form that has all the attached libraries, object groups, property classes, and color palette needed by your developers. When they need to create a new form module, they simply open the template form and save it with a different name. This ensures that your application can be developed according to your UI standards. PL/SQL LibraryA PL/SQL library is a collection of PL/SQL program units (packages, procedures and functions) that can be attached to any form module. Once attached, these program units can be used in the same way as if they are defined directly in that form module. This has the advantage of encapsulating the implementation details from the users of the library because they will only need to know the API (Application Programming Interface). This feature is an effective way of reusing code and protecting the developers from the implementation of the provided code. Database Stored ProcedureA stored procedure is a collection of PL/SQL code which is resident on the server and can be called from a Forms application, with data being passed between the application and the procedure. For example, you may need to perform an analysis of some data residing on the server and then display that on the form. This analysis may involve a large amount of SQL interaction with objects in the database. If the work was done on the client, data would be continually passed back and forth between the client and the server to resolve the analysis. By performing the task as a database procedure on the server, we can avoid this network traffic and thus greatly improve performance. This also has the advantage that this piece of analysis code can then be reused by other parts of your application. Portability Issues and SolutionsBefore writing any portable application, there are many issues you need to consider.
Should you use the real or character coordinate system when creating your application and how does it affect object sizes and layout?
Monitors of different sizes and resolutions may be used by your users. How should you create your application so that it looks good on different monitors?
How can you still include port-specific features like VBX and OLE in your application when some of your deployment platforms do not support them?
There are several issues with various UI widgets.
With these differences, how can you create an application that provides similar functionality in all your deployment platforms?
There are a number of issues regarding the use of fonts in a heterogeneous environment.
How can you deliver an application that will be accepted by users on different platforms?
Similar to the font issues, different platforms support different colors and the same color does not always look the same on all platforms. In addition, widgets on MS Windows can only take one of sixteen colors defined in the system color palette. Moreover, you may also see the effect of color washing when displaying several high-colored images simultaneously. How can you use colors effectively to create a good-looking application that can be deployed on several platforms?
Some platforms display the menu in the MDI window while others display the menu in each window in your application. How can you adjust your window sizes to accommodate the difference?
Some platforms allow the toolbar to be attached to the MDI window while others can only attach the toolbar to a specific window in your application. How can your window sizes be adjusted to accommodate the difference?
In a similar fashion, message and status lines are displayed in the MDI window on some platforms but in the console window on other platforms. Again, how can the window sizes be adjusted accordingly? In addition, on character-mode, there are only 80x24 cells on the screen and the users cannot reposition the window with a mouse. How should you develop your application with these constraints?
On character-mode, List of Values (LOV) cannot be moved using the mouse.
How can you make use of host commands and user exits (requiring port-specific code) while writing portable applications?
There are various other issues that should be considered.
The following sections describe these portability issues in more detail, as well as the solutions to help you build applications that would be easily accepted by users of different platforms. Coordinate SystemYou can work in two different coordinate systems when building your applications. The selection of the coordinate system depends on whether one of your deployment platforms is character-mode terminals. If you are only deploying on GUI terminals, you should use the Real Inch or Real Point coordinate system to lay out your application objects. This allows you to size your objects to the exact shape you want instead of being snapped to the nearest character cell size. Since the pixel size differs on screens with different resolution, Real Pixel is not recommended because your objects' sizes and positions will change according to the deployment screen resolution. For example, all your objects will shrink proportionally when displayed on a screen with higher resolution and this may be too small for the user to work effectively. If character-mode is one of your deployment platforms, you should use the Character coordinate system and turn on the grid snap. This will ensure that your application objects' sizes are in multiples of the character cell size, and are laid out correctly in character cell units. In order to lay out your objects accurately, there are two different settings you need in the designer.
Since the pixel is dependent on the screen resolution and there are 72 points per inch, you need to perform some calculation to get an equivalent value for each setting. With the character cell size in pixels, this method has the same problem as using the Real Pixel coordinate system in that your objects will be scaled according to the screen resolution. You can turn on Default Font Scaling after laying out your objects so that they will be scaled according to the font specified in FORMS45_DEFAULTFONT. The advantage of this is that you can control your objects' sizes independently of your application. There are two issues in this approach:
MonitorsPhysical real-estate varies across platforms. Even on the same platform, monitors of different sizes and resolutions can be used. You should know in advance what kinds of monitors are used in the deployment platforms and design your application windows using the smallest screen size. Aspect ratio is the width-to-height ratio of an object. When porting to different GUI terminals, the only guarantee is that the aspect ratio of your objects is constant because not all monitors display sizes correctly. This is a problem on MS Windows because the PC architecture is not capable of determining the screen resolution and the underlying video driver may not be giving the correct information about the screen resolution. As a result, an inch may not always be an inch on MS Windows. Since Forms depends on the underlying video driver for screen resolution information, there is nothing you can do to prevent this. On the Macintosh, the screen resolution is always 72 dpi (dots per inch). To display more objects on the screen, a bigger monitor has to be used. On UNIX, the operating system is able to determine the resolution of the monitor accurately, thus this problem will not occur. Platform-Specific FeaturesDue to their popularity, Forms provides certain features that are platform-specific. For example, OLE 2.0 is available on MS Windows and Macintosh, and VBX 3.0 is only available on MS Windows. Character-mode terminals will not be able to display graphical objects like circles and charts, etc. If you choose to use these features, you should ensure that the application does not rely on having them on all the deployment platforms. For example, if your users at the goods warehouse are using character-mode terminals and the customer service representatives are using GUI terminals, then you can use images in your application so that the customer service representatives can show their customers what the products look like while the warehouse operators can perform their tasks without that functionality. While images are not displayed on a character-mode terminal automatically, OLE and VBX objects have to be hidden if you do not want your users to see their placeholders on platforms that do not support them. There are two ways to achieve this:
WHEN-NEW-FORM-INSTANCE trigger: declare ui varchar2(15); begin ui := get_application_property (user_interface); if ui = 'CHARMODE' or ui = 'MOTIF' then set_item_property ('VBXOBJECT1', displayed, property_false); set_item_property ('OLEOBJECT1', displayed, property_false); set_item_property ('TEXTITEM1', position, 43, 4); end if; end; if ui = 'MACINTOSH' then set_item_property ('VBXOBJECT1', displayed, property_false); set_item_property ('TEXTITEM1', position, 43, 4); end if; You would also need to code the KEY-NEXT and KEY-PREVIOUS triggers to skip over those hidden items. Since boilerplate text cannot be repositioned dynamically, you will have to use display items for your boilerplate instead. The first method is preferred because the application will look the same on all platforms and it is simpler to enable/disable a menu item or button than reposition the other objects in the application. UI WidgetsThis section describes issues pertaining to the various UI widgets. GeneralOn character-mode, all the UI widgets are rendered in their character-mode equivalents. For example, a button is displayed as (Query), using the button's label and two more characters for the parentheses. As a result, you have to ensure that the widgets have sufficient space to display themselves entirely. On other platforms, they will be rendered using those platforms' native widgets. On character-mode, since the users do not have the use of a mouse, you should ensure that your application does not rely on mouse navigation. Thus, item ordering is very important in your application, and you should study the work flow of your users and order the application objects accordingly. As a case in point, ensure that all your buttons have equivalent hot keys and their functionality can be invoked using the menu. On Macintosh, users will not be able to navigate to anything except text items. Your application should not rely on being able to navigate to all objects. ButtonsWhen building applications for GUI platforms, it is very easy to create a button palette that applies to all blocks. However, this does not work well in a character-mode environment where the user needs to navigate to the button because it would then have lost the context with which to work with. The possible solutions are:
The dimensions of a button include the moat (the emphatic border around a button to designate a default button) regardless of whether it is the default button. On MS Windows, this moat is very small compared to that on Motif. Therefore, you will find that the buttons shrink when run on Motif. You can reduce this moat by copying the Tk2Motif file to your home directory and setting the Tk2Motif*expandNonDefaultButtons property to true. The following figure shows the effect of this setting.
Figure 3 Reducing the Moat on Motif Buttons Icons are platform-specific. If you use iconic buttons in your application, you will need a separate set of icons for each platform. Icon design is a time-consuming process and you need to be aware that certain icons have special meanings on certain platforms. For example, the trash can on the Macintosh has a specific functionality attached. In this case, you will not want to use this for some other purpose. To ease the porting process, you should use the same names for the icons on each platform and set the respective environment variables to point to the icon directory. On MS Windows and Motif, this variable is TK21_ICON. You should refer to the Installation Guide for your platform for the specific environment variable for other platforms. On character-mode, iconic buttons will be displayed using the buttons' labels. You should ensure that iconic buttons have meaningful labels and have sufficient space to display them. Since objects below the 24th line on the character-mode screen is not visible to the user, you can also place these iconic buttons below the 24th line so that your GUI terminals users can enjoy that functionality while your character-mode users will not see them but be able to invoke their functionality through the menu. BevelsBevels are not available on Macintosh and character-mode terminals. You should not assign a meaning to an object based on its bevel attribute if you are using these platforms. On MS Windows, there is a known positioning problem when porting between VGA and SVGA screens as shown in the figure below. The two lines which are just touching each other on VGA will overlap when displayed on SVGA. Use of the bevel attribute is encouraged because it does not present this problem.
Figure 4 Effect of Positioning Problem When Porting Between VGA and SVGA FontsThere are a number of issues regarding the use of fonts in a heterogeneous environment.
There are two ways you can resolve this:
Defining Font AliasesFont aliasing allows you to substitute one font for another when porting your applications. Developer/2000 comes with a default font alias file for each platform. You can customize this file to suit your needs. The entries in this file are of the following format: source_font = destination_font You can substitute the face, size, weight and style of each font in your application. Two very simple examples are given below. Porting from MS Windows to Motif changing all MS Sans Serif font to Helvetica font: MS Sans Serif=Helvetica Porting from MS Windows to Macintosh changing all MS Sans Serif 10-point font to Geneva 12-point font: MS Sans Serif.10=Geneva.12 The font alias file gives the exact syntax for defining the aliases, as well as some comments to describe how it is used in more detail. On MS Windows, this file is found in the \orawin\cde2 directory. You should refer to the Installation Guide for the location of this file on other platforms. This approach is very simple. For example, it is very useful if you want to enable all objects using MS Sans Serif 10-point font on MS Windows to use Helvetica 9-point font on Motif in your application. However, if both your poplist and text items are using MS Sans Serif 10-point font on MS Windows, but you want your poplist and text items to use different fonts on Motif, you should use the next approach which provides you with that level of granularity. Defining Port-Specific Property ClassesAs discussed in the section Re-Referencing Port-Specific Implementation, you can define property classes according to your UI standard. You can also incorporate font information in these property classes to specify the font used for each type of object for each deployment platform. For example, you can create property classes for poplists and text items. On MS Windows, both of these property classes would specify MS Sans Serif as the font in Window.fmb. On Motif, you can specify that the poplist property class use the Helvetica 9-point font while the text item property class use the Helvetica 11-point font in Motif.fmb. This approach allows you to customize the font used for each class of objects in your application, providing a higher level of flexibility in choosing the desired font as compared to the previous method. As a result, you can deliver an application using the font that your users are accustomed to on each deployment platform. ColorsSimilar to the font issues, different platforms support different colors and the same color does not always look the same on all platforms. Using the technique in the section Re-Referencing Port-Specific Implementation, you can specify the colors to be used for each class of objects for each platform. In this way, each object in your application will take on the color that look best on each platform. If you want to color-code certain objects in your application, you should do that redundantly. For example, if you want to show negative amounts in red, you should also precede that number with a minus sign so that users of monochrome and character-mode terminals can distinguish positive and negative numbers. On MS Windows, widgets can only take one of sixteen colors defined in the system color palette. If you assign a color other than these sixteen colors, your widget will snap to one of the sixteen colors that is closest to the one you specify. Your application should use a color palette that includes these sixteen colors. On monochrome displays, colors will snap to black or white. You need to be careful not to use dark colors for both the background and foreground so that they do not both get snapped to black. On color monitors, since the color palette is only capable of displaying a certain number of colors at any point in time, color washing is seen when two applications need to display more colors concurrently than what the system's color palette can handle. As a result, when several high-colored images are displayed simultaneously, only the one in the foreground is displayed correctly while the rest will be displayed using the color palette set by the foreground image, thereby snapping to some strange colors. To minimize this, you should limit the number of colors in your color palette so that more colors in the system color palette can be used for other displays. In addition, studies have shown that a good user interface only uses a few colors and uses them consistently throughout the application. MenuMS Windows applications support Multiple Document Interfaces (MDI) where all the windows belonging to an application are contained in the application's window (also called the MDI window), and there is only one menu for the entire application. The Macintosh has a similar concept to MS Windows. On Motif, every window has a menu attached, while the menu is always displayed on the first line of the screen on character-mode. Due to these platform differences, the window sizes of the application need to be adjusted accordingly. This is discussed in the section Windows. When an application has different menu items at the root level, the user may see the screen flash when switching between form module windows. In order to avoid that, you can combine all the menu options into one single menu application, and use the set_menu_item_property built-in to dynamically enable/disable the respective menu items accordingly. On character-mode, you may want to define hot keys for the commonly used menu items so that the user does not need to access the menu all the time. In addition, you should note that magic menu items like Cut, Copy and Paste are not available on character-mode. ToolbarOn MS Windows, you can attach an MDI toolbar to your application which will be displayed in the MDI window, or you can attach a toolbar to a specified window. Again, the Macintosh uses a similar concept. On Motif, a toolbar can only be attached to a specified window. It is not advisable to use a toolbar in character-mode due to the limited amount of screen real-estate, but enable the same functionality via the menu. This can be achieved by making all the toolbar buttons non-navigable and hiding that canvas in a WHEN-NEW-FORM-INSTANCE trigger as follows. WHEN-NEW-FORM-INSTANCE trigger: if ui = 'CHARMODE' then hide_view ('toolbar'); end if; Again, these platform differences would require that the window sizes of the application be adjusted accordingly. This is discussed in the section Windows. WindowsThe placement of the menu, and message and status lines varies with the deployment platform as follows.
It is recommended that you design your window without including the menu, toolbar, nor message and status lines in the window size. On platforms that differ from this standard, you can adjust the window size dynamically in the WHEN-NEW-FORM-INSTANCE trigger as follows. WHEN-NEW-FORM-INSTANCE trigger: adjust_window ('consolewindow', true); adjust_window ('otherwindow'); procedure adjust_window (window_name in varchar2, console in boolean := false, toolbar in boolean := true) is delta number:=0; ui varchar2(15); begin ui := get_application_property (user_interface); if ui = 'MOTIF' then /* add space for menu, value depends on size of menu font */ delta := delta + 1; /* add space for message and status lines */ if console = true then delta := delta + 2; end if; /* add space for toolbar, value depends on size of toolbar */ if toolbar = true then delta := delta + 1; end if; elsif ui = 'CHARMODE' then /* add space for message and status lines */ if console = true then delta := delta + 2; end if; /* move all windows down 2 to see window frame in character-mode */ set_window_property (window_name, y_pos, to_number (get_window_property (window_name, y_pos)) + 2); end if; if delta != 0 then set_window_property (window_name, height, to_number (get_window_property (window_name, height)) + delta); end if; end; When deploying on character-mode terminals, you need to consider the following issues.
LOVOn GUI platforms, List of Values (LOV) can be moved using the mouse. However, on character-mode terminals, the LOV is a static object. You need to ensure that the LOV does not occlude the underlying data that provides its context. You can use the set_lov_property built-in to dynamically position the LOV in character-mode. Programmatic InterfacesThere are a couple of ways you can write port-specific code in Forms. These will definitely require changes when porting. The following sections discussed how to make use of these features without any changes to your form modules. Host CommandsThe host command executes a port-specific operating system (OS) command. When you embed such commands in your form module, you will need to change these commands as you port your application since OS commands differ from platform to platform. You can make your form module portable by putting all OS commands in a script file and call this file from your form module. You can then rewrite the script file for each platform and ensure that they have the same name. In this way, you can port your application without modifying your form modules. User ExitsUser exits enables you to call Third Generation Language (3GL) programs from your form module. These 3GL programs are port-specific. There are two ways to make your form modules platform-generic while using this feature.
You can create an API for your user exits that is consistent across platforms, rewrite the 3GL programs for each platform, and re-link the user exits or replace the DLL for each platform.
You can use preprocessor directives in your C programs to code port-specific functionality. Depending on the variables defined, the relevant segments of the code will be compiled. MiscellaneousThis section lists several issues that you need to be aware of.
Path names vary across platforms. You should not hardcode path names in your form module but make use of environment variables to enable Forms to find your files during runtime. Your Installation Guide should have a list of these variables.
There are two issues regarding file names:
You should ensure that your file names have a maximum of eight characters and use either uppercase or lowercase consistently.
You should be careful not to use port-specific messages in your application. For example, a message like Hit the F1 key for help will not be portable. ConclusionWith Developer/2000 Forms 4.5, you can develop an application once, and run on a multitude of platforms natively without any change to the source application. However, there are differences in the capabilities of the different environments, as well as differences in the expectations of the users on various platforms which may hinder the complete acceptance of your application on every platform. We have discussed different development strategies for writing portable applications, together with their implications on ease of maintenance and resemblance to native applications. Forms provides many features to assist you in implementing your strategy, creating a UI standard and maximizing reusability of your code. With the general strategy in mind, we have also examined the various portability issues, and have described solutions to resolve them. |