The FORCE

Top-Level Design Document

Author: Jeff Alexander (jla)

Overview

This document serves as a description of a proposed top level design for The FORCE. The document is divided into several sections, one for each top level software component of The FORCE. Logically speaking, each of these six components will reside within The FORCE's Application class.

In addition to the top level components, this document discusses a few major subcomponents which exist independently of the Application class, such as the Graph Builder, and the Graph Builder Graphical Interface.

Note: Throughout this document, the term "interface" will be used to describe a logical (and physical) wrapper around a particular class. This should not be confused with a class which represents the graphical user interface of a particular logical construct - these classes will be described as (and contain the name) "user interface".

TFMainApp - The FORCE Application

This is the application or "top level" class which contains all base components of The FORCE and provides a means of communication as well as a central "dumping ground" for these components. TFApp will contain instances of TFCLCLUIBuilder, TFGBGUIBuilder, TFFLFunctionLibInterface, TFCBCodeBuilder, TFFGFunctionLibUserInterface, TFHSHelpServer, and finally TFCOCompiler. Each of these components will be described in detail in the coming sections.

The TFApp itself will be responsible for the main menu of the application, as well as the preferences dialog box and load/save options (although the other components will be responsible for generating the material to save).

The FORCE Application
class TFMainApp {
public:
    ...
    // currently selected item in function library
    virtual void setSelectedFunction(FunctionID fid);

    // get handle for current function
    virtual FunctionID getSelectedFunction();

    // get pointer to particular component
    virtual ComponentType* get-ComponentName-();
    ...
private:
    ...
    // pointers to each component
    ...
};

Command Line User Interface (CLUI) Builder

The CLUIBuilder encapsulates all user activity specific to creating a command line program within The FORCE. From the user interface perspective, this is represented as a simple window shell with a Graph Builder User Interface within it.

Internally, the CLUIBuilder contains a couple core elements. First, as mentioned above, the CLUIBuilder contains a UI class which has a Graph Builder User Interface embedded within it, providing the basic editting environment for the program as a whole. Additionally, the CLUIBuilder should maintain a list of currently open sub-graphs to track which windows the user has open.

Of particular importance to the CLUIBuilder's functionality is its "Undo" feature. This should be supported by using the "Command" pattern as described in "Design Patterns" (Gamma, et al), pg 233. The Invokers should be the Graph Builder User Interface, and its containing class, and the receiver should be the CLUIBuilder itself. A queue of commands with Execute and Unexecute methods should be maintained within the CLUIBuilder.

CLUIBuilder Diagram
class TFCLCLUIBuilder {
public:
    ...
    // execute and take responsibility for a command
    virtual void executeCommand(Command* cmd);

    // undo, store, and return a command
    virtual Command* undoCommand();

    // redo an undone command, and return it
    virtual Command* redoCommand();

    // get graph for code generation
    virtual GraphBuilderInterface* getGraphBuilder();
    ...
private:
    ...
    CommandList* _commandsPerformed;
    CommandList* _commandsUndone;
    CLUIWrapper* _wrapper; // wrapper around graph builder user interface
    ...
};

Graphical User Interface (GUI) Builder

The GUIBuilder encapsupates all user activity specific to creating a program within The FORCE which has a graphical user interface. Like the CLUIBuilder, the GUIBuilder will contain a container for a Graph BUilder User Interface. Unlike the CLUIBuilder, however, the GUIBuilder's wrapper is very significant. The GUIBuilder's user interface consists of several windows, represented logically as classes contained within the GUIBuilder.

First, the UI Layout window is used to actually model the user interface and allows creation of all of the various control widgets (buttons, text fields, sliders, checkboxes, etc) which can be obtained from the Control Toolbox (another window contained in the GUI Builder). Show by double clicking a widget created in the UI Layout window is the Control Edit window. This window is presented with a tab view - one tab for each event associated with the control being editted. Each tabbed section contains an embedded Graph Builder User Interface, allowing the programmer to create graphs associated with responses to each event. The UI Layout window should maintain a list of open windows as to avoid bringing up the same control in multiple editing windows.

Finally, the GUIBuilder needs a general purpose window of information. The primary focus of this window is the list of global variables available in the program. Global variables may be created explicticly by the user, and are created implicitly when controls are created (each control represented by a variable). This window may also be used for other information which may need to be displayed in the GUIBuilder.

As with the CLUIBuilder, the GUIBuilder must fully support Undo/Redo and so must make use of the Command design pattern as described above.

GUIBuilder Diagram
class TFGBGUIBuilder {
public:
    ...
    // command interface as in TFCLCLUIBuilder

    // edit the graphs for a control widget
    virtual void openGraphForControl(ControlID cid);

    // necessary to maintain state:
    virtual void closeGraphForControl(ControlID cid);

    // manipulate global variables
    virtual Variable* getSelectedVariable();
    ...
private:
    ...
    GBGlobalVariableDisplay*   _globalVarDisplay;
    GBLayoutWindow*            _layoutWindow;
    GBWindowList*           _windowList;
    ...
};

Function Library

The Function Library represents all stored knowledge about the functions available to be used in the creation of programs within The FORCE. It stores all information about the code to be generated for functions, the description blurb for the function, and all information related to user-defined functions, whether they be code based or graph based.

In its actual implementation, the internal class FunctionLibrary is not directly accessible. Since it will be used by so many other classes, it must be accessed through a FunctionLibraryInterface class. The FunctionLibraryInterface will mirror the functionality of the FunctionLibrary and will export its interface to the world. Only the Interface class will be allowed direct access to the implementation class, thus reducing compile time overhead and confusion.

When constructing a graph, the user chooses functions from the Function Library (via the Function Library User Interface), identified by a unique identifier. This identifier is later used to retrieve information about the function's name and parameters. In the case of a user-defined function, the Function Library also stores the graph or the code associated with that function.

The Function Library has primary control over the editing of user-defined functions. To avoid multiple edit sessions and potentially a great deal of confusion, user-defined functions must be checked out of the Library before they can be modified. This can be enforced programmatically by returning either a read-only or a read-write subclass of a generic edit wrapper class when a program component requests the internals of a particular user-defined function.

class TFFLFunctionLibrary {
public:
    ...

    // for use by Function Library User Interface
    virtual CategoryList* getCategories();
    virtual FunctionList* getFunctionsFromCategory(CategoryID cid);

    // for use in graph creation and code generation
    virtual char* getNameOfFunction(FunctionID fid);
    virtual char* getDescriptionOfFunction(FunctionID fid);
    virtual CodeTemplate* getCodeOfFunction(FunctionID fid);
    virtual Parameters* getParametersOfFunction(FunctionID fid);

    // Check out/in a function for editing
    virtual FunctionEditInterface* editUserFunction(FunctionID fid,
                                                GraphBuilderInterface* gbi);
    virtual void checkInFunction(FunctionEditInterface *fei);
    ...
private:
    ...
    // database-like data structure
    ...
}

Code Builder

The Code Builder is responsible for the generation of code in files on the filesystem. The Code Builder parses all relevant Graph Builder graphs and uses the Function Library (via the Function Library Interface) to retrieve the templates and naming information required for code generation.

Most of the significance of the Code Builder actually lies in the implementation of the graph traversing algorithm, and less so in the design. The Code Builder will be a relatively simple component from the design perspective, consisting only of any helper classes for implementation. The design of the Code Builder will not affect any other components. The main restriction on the Code Builder is that it maintain modularity to allow for the possible creation of Code Builders for other languages.

Function Library User Interface

The Function Library User Interface is the programmer's main access to the toolbox of routines available within The FORCE. The Function Library User Interface itself, however, will not contain any of its own information. The FLUI's main purposes are 1) to allow the user to select a function to meet her demands, and 2) to help teach the user what a particular function does internally so that he will be able to use it in textual C code.

Internally, the Function Library User Interface should follow the standard methods of representing a semi-complex GUI in an object oriented program. To be implemented as described in the Specifications document, the FLUI should consist of several classes, representing the category selection list, the function selection list, and finally the description text box. It is important for each of these elements to be smart objects in and of themselves because they will be serving as the interface into the Function Library database. They will need to query the database and display results based on the user's actions.

The only other interaction the Function Library User Interface has with the rest of The FORCE is to inform it of what the currently selected function is. This data will be used by the GUIBuilder and the CLUIBuilder (which in turn will be used by the Graph Builder User Interface) to create nodes in Graph Builder graphs.

class TFFGFunctionLibraryUserInterface {
public:
    ...
private:
    ...
    // window components
    CategoryListControl* _catList;
    FunctionListControl* _funcList;
    DescriptionField*    _desc;
};

Help Server

The Help Server is responsible for providing non-function-related help to the user. The Help Server serves as a central repository for all help messages, describing all components of The FORCE, as well as processes within The FORCE - creating a new project, building your first graph, integrating C code, etc. The material that is stored seperately from the Help Server is the descriptions of functions which will reside in the Function Library, closely tied to the functions they describe. All other help information is factored out into the Help Server so that it can be easily changed.

In its implementation, the Help Server should only be accessed through an interface class, TFHSHelpServerInterface to prevent excessive dependencies on volatile code. Since almost all components will make use of the Help Server in one form or another, it will be extremely helpful to isolate the interface of this code from its implementation.

To get a particular help message from the Help Server, a component should give the Help Server its component ID, and the help ID of the message to be displayed. Messages from the Help Server are identified uniquely by a combination of their component ID and their help ID.

class TFHSHelpServer {
public:
    ...
    // read in help stored externally
    virtual void parseHelpFile(char* fileName);

    // return help information
    virtual Help* getHelpFor(ComponentID cid, HelpID hid);
    ...
private:
    ...
    // database-like structure storing help
    ...
};

Compiler

The Compiler component is responsible for take the code generated by the Code Builder and building a working executable from it. It is also responsible for running the resulting executable. The Compiler will store all information related to the compiler - such as any preferences that the user selects in the Compiler (advanced) preferences.

The Compiler will consist of only a couple classes which will get its job done. Most of the trick of the compiler will be correctly making the executable, and executing it. Additionally, the Compiler class should be able to kill the executable.

Finally, since the Compiler stores compile information (needed compiler flags, etc), it must provide a simple interface to allow the Code Builder to retrieve that information when it is time to generate a Makefile.


Graph Builder

The Graph Builder is one of the largest components of The FORCE. It is not directly contained within the TFApp since it is used by several of the App's components and instances will be made and destroyed as needed, and stored within the Function Library. The Graph Builder represents a complete piece of "code" within The FORCE. It will store graphs of command line programs, graphs of events in GUI programs, and any functions created within either of those contexts.

A Graph Builder is not only the means of creating and editing a graph, but is also the graph itself. A Graph Builder instance is the complete set of tools and data used to store a user written routine both in memory (in its data structure) and on disk (in a particular file format). Since the Graph Builder does contain so much, and it will be used in multiple places, it will be accessed through a Graph Builder Interface class, shielding the internal implementation from the rest of the project.

Internally, the Graph Builder conists of three main classes, the encapsulation of the Parameters, encapsulation of the Return Values, and finally the encapsulation of the Flow Graph. The Flow Graph conists of a collection of Nodes, and a list of Variables.

To edit a Graph Builder, the GUIBuilder, the CLUIBuilder, or possibly the Function Library needs to contact the Function Library and request permission to edit a graph using one of the get functions. The Function Library allows access through its FunctionEditInterface mechanism described above, which in turn allows access to a Graph Builder Interface, which finally talks to code in the Graph Builder.

Graph Builder User Interface

The Graph Builder User Interface is particularly simple from the design perspective, but still very important in its simplicity. The GBUI is the interface that allows the programmer to create and modify graphs. The trick to the GBUI is that it should essentially act as a (very very) glorified widget, in that it should be a module that can be swallowed inside another widget. This is necessary to embed the Graph Builder User Interface in the various shells that might contain it such as the GUIBuilder or the CLUIBuilder.

Of importance is the GBUI's counterpart which will allow the user to enter code as opposed to a graph, but that is not discussed indendently since it is no different in design or behavior from the GBUI.

Whenever a Graph Builder User Interface is created, it should be given a Graph Builder Interface (or a FunctionEditInterface class provided by the Function Library) which it will pass all user interaction to. The Graph Builder User Interface contains all graphical user interaction and manipulation, but it doesn't do anything unless 'authorized' to do so by the Graph Builder.


Development Schedule


In closing, I'd like to make a note about the proposed algorythm animation aspect of The FORCE. I believe that it would be very helpful to be able to see a visualization of the "code" written in The FORCE, but I do not believe this to be a practical thing. I think it is more helpful in learning the C language to be able to add actual C code to flow graphs than it is to be able to see an animation of the code. While animation may help novices understand flow of control better, I do not think it provides any more information than that. Integrated C code, on the other hand, helps novices advance to become intermediate users and then allows them to break away from using The FORCE as their skills and programs get larger. The problem is that the two options are mutually exclusive. Including a visualization aspect of The FORCE greatly increases the size of the project not only because the visualization is far from trivial, but also because it would require parsing and almost compiling C code. Since C code can be located anywhere in The FORCE, we would need to understand the code were we to animate any of it. This is far beyond the scope of the project, and would add little to it.


Last modified: Wed Feb 24 01:48:38 EST 1999