Creating Graphical Browsers
Table of Contents
-
Concepts
- The Data Tree
- Interrogators
- Attaching mouse events to browser actions
- The UI
- Popup menu
- Table Definition
- Querying the browser
- Executing commands
-
Five Steps to Create a Browser
- Define a function to produce a data tree by creating
BrowserNodes
- Define the properties of the data tree
- Create a browser with/without a UI
- Add behavior to the browser
- Display the browser
- Glossary
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
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:
- A unique ID (i.e. path to object)
- The display name of the object
- A parent node
- 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:
- pixmap representation of the object
- secondary pixmap (auxiliary representation or use).
- displayable in graphics tree, table or both
- selectable
- sensitive/active object
- alternate print name
- valid drag and drop sources
- can expand the object (i.e. show its children)
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:
- Left mouse click selects a single object in the browser
- Control left click, adds/removes the object from the select list.
- Left double click selects and operates on the object
- Control left double click, selects and operates on the list of
selected objects
- Middle mouse click displays the children of an object in the
table
- Control middle click toggles the object as a table root (i.e show/hide
its children in the table view)
- Shift middle click expands/contract the object (i.e. show/hide its
children in the tree)
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:
- An unlimited number of pull down menus with:
- Toggle actions
- Mutual-exclusion list (i.e. if one button is set, all others in
the mutual-exclusion list are released.)
- Push actions
- a top menu area for toggle or push actions
- ability to specify what happens when the OK & Cancel buttons are
used
- ability to attach any user defined form within the browser UI
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:
- If a menu entry is visible/invisible if it is selected over an
object.
- If a menu entry is sensitve/insensitive when selected over an
object.
- The action to occur if menu is selected on a object.
- The action to occur if menu is selected over no object.
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:
- Describe how many columns should exist.
- The header for each column.
- The data type for each column.
- The initial width of a column.
- The function to execute to gather the data for that column.
- To add a new column to an existing table.
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:
- Current mode (graphics mode, table mode, dual mode)
- Which objects are currently selected.
- Which objects are table roots.
- Is an object currently expanded or contracted (i.e. showing its
children)
- Which object is the current graphics root.
- List the children of an object.
- Determine is a object is a descendant of another.
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.
- Set the browser mode (i.e. graphics mode, table mode, dual mode).
- Select an object.
- Clear the selection list
- Expand/contract an object.
- Set the table root.
- Set the graphics root.
- Expand all branches in the tree
- Expand the table to show all children or just one level of
children
- Turn secondary pixmaps on/off
- refresh/redraw the tree manually (normally not required)
- Change the vertical/horizontal spacing between browser objects.
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.
-
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:
- The name of the data tree to attach this browser node to.
- A unique ID for the object
This is a string that will uniquely represent the object within the
data tree.
- The print name for the object
This is the default name that is displayed by the browser.
- The parent BrowserNode of the object
- Any desired client data This is any user data that you wish to
attach to an object within the browser. Care should be taken to attach
the right data to produce easy to use and efficient browsers.
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
-
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:
- name of tree
- update function
- update event
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
-
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:
- The name of this browser
- The name of the tree attached to this browser
- Pull down menus
- Top menu bar
- Action to take with OK/CANCEL button if other than default
- Index into the help system
- Title bar
- Pin/Close actions if other than default
(sd-create-graphical-browser "file-browser"
:tree "dir-tree" )
Reference
Manual
-
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.
- 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
- 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)
- Popup menu definitions
- Inquiry functions
To determine the state of the browser or a BrowserNode, inquiry
functions can be used. Several examples are shown above.
- Browser commands
To change the state of the browser or BrowserNodes, browser commands
can be executed.
- 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.
-
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:
- sd-show-graphical-browser
- sd-hide-graphical-browser
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.
© 2023 Parametric
Technology GmbH
(a subsidiary of PTC Inc.), All Rights Reserved |