[Previous Page] [Next Page] [Integration Kit Contents] [Integration Kit What's New] [Integration Kit Function Index] [More Documentation] [PTC]

Creating Graphical Browsers

Image of sample browser

Table of Contents

Concepts

Graphical browsers provide the means to display information in a graphical structure within a dynamic environment. They can be used in a wide variety of situations with the only real requirement that the displayed data can be represented by a standard tree structure. Not only can the browsers be used to display data, but they also have the capability to directly interact with that data (i.e. drag and drop actions, plus much more).

Shown below, is a typical browser UI containing a both a graphical and tabular representation of the data being displayed by the browser. Typical elements of the browser are labeled to help establish the terminology used in this document.

Sample browser with UI

Image of sample browser

To produce such a browser, a set of tools has been provided. These are described fully in the reference manual. Within this section the major components of the browser are described along with the role they play within a browser.

The Data Tree

At the heart of the browser is the data that it displays. Before the browser can display data, a data tree must be built. Basically a data tree is composed of nodes or leaves (called BrowserNodes) which have a parent/child relationship. In the simplest form, a data tree consist of any number of nodes with at least one parent. A BrowserNode consits of four pieces a data:

  1. A unique ID (i.e. path to object)
  2. The display name of the object
  3. A parent node
  4. Any client data

The client data can be any piece of data that the programmer may wish to associate with that object.

Interrogators

Any time the browser displays an object, a set of interrogators are executed to determine the appearance of the object. Through the use of the provided interrogators, each object in the browser can have its own set of properties such as:

To control the appearance of the objects within a browser, any number of these interrogators can be used. It should also be noted that these properties are not static. Since interrogators are executed when any action takes place on a browser (i.e. an object is selected, the tree is expanded/contracted,...), they provide an extremely dynamic method to control the appearance of the objects in a browser. (e.g. The primary pixmap of an object could change when it is selected or even when another object is selected.)

Attaching mouse events to browser actions

To allow for interaction with the browsers, a browser writer can customize the use of mouse events to initiate a browser action. By default, the browsers provide the following mappings:

The browser supports all of the allowed masks and button clicks supported by X11 protocol, thereby allowing over 200 customized actions to be defined. In addition, actions can be specified should a mouse click occur on the primary pixmap or secondary pixmap.

The UI

In addition to defining a browser, a user interface will be built for the browser. When creating a browser, it is possible to create one as shown above with a UI, or an extended one with your personalized requirements. With a UI, the browser provides the ability to define:

Popup menus

In addition to the UI which encompasses the browser, it is possible to define a context sensitive popup menu within the browser. By convention, this menu is displayed whenever a right mouse click occurs within the browser. The menu can be defined to display options that are only valid for an object, and/or options that can be equally applied to all objects. In general you have the ability to control:

Table Definitions

Any browser can control whether a table display is available. If one is present, objects can be displayed in it by setting a table root. A table root is simply an object whose children are shown in the table side (hence, the parent is the root of the table). For those objects that are displayed in the table side, it is possible to display additional supplemental information within the cells of the table. At this time, the table interface provides a relatively simple interface that allows you to:

It is possible to define several tables definitions for a browser and chose which one is the currently active table based upon your own criteria. This provides the capability to show/toggle between multiple table definitions easily.

Querying the browser

To provide a truly dynamic browser, it may be necessary to query the browser for information. In this regards, the browser makes available several queries to determine the current state of the browser and objects within the browser. Shown below are some of the typical types of data that can be queried from the browser:

Through the use of these queries, a robust and highly tunable browser can be created.

Executing browser commands

In addition to the normal interactive interaction with the browser, programmatic access is also provided. This allows the browser writer to execute commands useful for initialization, change settings, or to control the mode of the browsers. Normally after each browser command, the browser will update itself to represent the new state. Shown below are some of the typical type of commands that can be invoked.

Five Steps to Create a Browser

This section covers the basic steps required to produce a browser will be covered. Throughout this section, references will be made to a sample file browser that could be created with the graphical browsers.

  1. Define a function to produce a data tree by creating BrowserNodes
    To produce a data tree, it is required that a function be written which scans through the data that is to be displayed (this usually involves creating a function which can be called recursively). Each time an object that is to be displayed in the browser is encountered, a BrowserNode must be created. For this purpose, a the function sd-create-BrowserNode is used. As stated earlier, several pieces of data must be provided to produce a BrowserNode: In our example file browser, the unique ID would be the full path to the object (file). The print name will be the file or directory. The client data is selected to be a structure which contains file/directory status information. For this example, the following structure was chosen:
    (defstruct my-struct
         (has-been-opened nil)  ;flag to determine if this directory has been opened
         (file-type nil)     ;what type of file is this
         (is-hidden nil)     ;is this a hidden file (starts with .)
    )
    
    
    Depending on the object that we are creating, the structure would be initialized with the appropriate data and attached as clientData to the browser object.

    Once the design for a browser object is complete, a user defined function needs to be created which will create the data tree that you wish to display within the browser. Shown below is a portion of the function which may be used to build the data tree for a file browser.

    (defun build-file-tree()
    ...
      ;encountered a directory object "/dir1"
      (setq directory (sd-create-BrowserNode "dir-tree" :obj-path "/dir1" :parent nil
                      :obj-printname "dir1" :obj-data 
                         (make-my-struct :file-type :dir)))
    
      ;encountered a file object "/dir1/file1"
      (setq file (sd-create-BrowserNode "dir-tree" :obj-path "/dir1/file1" 
                      :parent directory :obj-printname "file1" :obj-data 
                         (make-my-struct :file-type :file)))
    ...
    )
    
    * Reference Manual

  2. Define the properties of the data tree
    After defining your data tree constructor function, it is necessary to describe its properties. For this purpose the function sd-create-browser-tree is provided. There are three key properties of a tree that are necessary to provide: The update function is the user defined function described above which builds the data tree. The update event is an event name that determines when the update function should be executed. For our example browser, we would want our update function (build-file-tree) to be executed whenever a change directory event occurs.
    (sd-create-browser-tree "dir-tree" :udpate-func 'build-file-tree 
      :update-event  oli:*SD-CHANGE-CURRENT-DIRECTORY-EVENT*)
    
    * Reference Manual

  3. Create a browser with a UI
    Once the data tree creation function and properties are defined, the next step is to realize the browser. This step involves associating (attaching) a data tree with a browser name and creating the UI associated with the browser. This may include the specification of many of the following:
    (sd-create-graphical-browser "file-browser" 
        :tree "dir-tree" )
    
    * Reference Manual

  4. Add behaviour to the browser
    After the browser is created, it is generally required to add behaviour to the browser. All browsers have a default behaviour, however this will generally not be sufficient to satisfy all the needs of your browser. On the other hand, it is generally useful to first create your browser without any personality so that you may test out your data tree creation functions. Once you are satisfied with the results of the data tree creation process, then it is recommended that you begin the process of adding browser behaviours. In general, their are six different types of behaviours that exists.
    1. Interrogators
      Interrogators are the functions which determine how the browser presents the data to the user. Almost all interrogators are expected to accept two parameters (one expects three parameters) . The first is the BrowserNode for which the interrogator is being called. The second is the name of the browser which is calling the interrogator. To extract data out of the BrowserNode structure, there exists four access functions:
      • BrowserNode-objPath
        The full path string for this BrowserNode.
      • BrowserNode-objPName
        The display name of this BrowserNode.
      • BrowserNode-objClientData
        The clientdata which was attached to this node at creation
      • BrowserNode-NodeID
        The symbolic name of this BrowserNode
      * Reference Manual

      As described in the reference manual, each interrogator is expected to return a relevant return value which is used by the browser to determine that property of the browser. For our example browser, we may want to specify that only directories should appear on the graphics side. Also, we would like to show different pixmaps for the different type of file-types that we encounter. Shown below are some samples interrogators:

      (defun get-primary-pixmap(obj name &aux type)
        (setq type (my-struct-file-type (BrowserNode-objClientData obj)))
        (cond ((eq :dir type) "dir-pixmap")
              ((eq :sd_ses type) "ses-pixmap")
              ((eq :sd_pkg type) "pkg-pixmap")
              (t "file-pixmap")
        )
      )
      
      (defun get-display-in-graphics(obj name)
        (eq :dir (my-struct-file-type (BrowserNode-objClientData obj)))
      )
      
      )
      (sd-browser-add-interrogator "file-browser" :interrogator 
         :primary-pixmap 'get-primary-pixmap)
      (sd-browser-add-interrogator "file-browser" :interrogator 
         :display-in-graphics 'get-display-in-graphics)
      
      * Reference Manual

    2. Click Handlers
      Click handlers provide the ability to execute some user defined action should a specified mouse click action occur. There are five basic types of click handlers:
      • Single click actions
      • Double click actions
      • Drag actions
      • Primary icon clicks
      • Secondary icon clicks
      For both the single-click, multi-click actions and drag actions, it is possible to attach an action to any mask and mouse button combination. (button3 without a mask is reserved for the popup menu action.) With our example, we may want to specify that when a the secondary icon is selected, that the directory should be expanded (i.e. show it's children).
      (defun sec-icon-click(obj name)
        (if (sd-query-browser name :is-object-expanded obj)
          ;browser object is already expanded, so let's contract it
          (sd-browser-exec-cmd name :SET-OBJECT-EXPANSION obj nil)
          ;else
          (progn
            ;if this directory has not been opened before, we need to build this
            ;part of the tree.
            (unless (my-struct-has-been-opened (BrowserNode-objClientData obj))
              (build-file-tree :parent-node obj))
            (sd-browser-exec-cmd name :SET-OBJECT-EXPANSION obj t)
          )
        )
      )
      
      (sd-browser-click-action "file-browser" :action :sec-icon-click
        :func 'sec-icon-click)
      
    3. Popup menu definitions
    4. Inquiry functions
      To determine the state of the browser or a BrowserNode, inquiry functions can be used. Several examples are shown above.
    5. Browser commands
      To change the state of the browser or BrowserNodes, browser commands can be executed.
    6. Table Specifications
      By default, all objects shown in the table will simply display their print name or their full path name (depending on whether multiple table roots are selected). To display more details on the objects shown in the table requires the creation of a table specification. For our example, we may wish to show the file permissions, the owner, size and date of all the objects in the table.

  5. Display the browser
    Congratulations, you have now reached the final step in creating your own custom browser. This final step simply involves opening/closing the browser to the end user. For this, two utilities are provided: Generally, these functions would be the push and release actions behind a toggle button in the UI. As previously stated, the browsers employ an intelligent update process. If a tree update event occurs while a browser is hidden, the update of the tree will be delayed until the browser is displayed. Therefore, if a browser is closed, no processing time is spent updating a data tree that will never be seen.

Glossary

Graphical browser
A browser derived from the graphical browser class.
BrowserNode
represents a node in a tree and is used to establish the parent child relationship between browser objects.
BrowserObject
The representation of each object in a browser tree. It consist a three pieces of data; 1) a unique id, 2) a print name, 3) client Data.
[Previous Page] [Next Page] [Integration Kit Contents] [Integration Kit What's New] [Integration Kit Function Index] [More Documentation] [PTC]
© 2023 Parametric Technology GmbH
(a subsidiary of PTC Inc.), All Rights Reserved