OneSpace Modeling macros: Simple directory browser
This code shows how to build a graphical browser in OneSpace Modeling. For simplicity, we
just recurse over a directory tree and display it in the browser.
This is hardly useful in itself, but it highlights a typical pattern
when working with graphical browsers. The structure in the browser
is backed up by a hierarchical data structure
on the application side of the code. In our case, we build up a tree
of
dir-tree-items; this tree is populated by traversing a file
system directory.
The graphical browser is created by traversing the
dir-tree-item
tree
and calling
sd-create-browsernode
for each item.
;; -*-Lisp-*-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Description: Directory browser for OneSpace Modeling
;; Author: Claus Brod
;; Created: 11/19/2004
;; Language: Lisp
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
(in-package :clausbrod.de)
(use-package :oli)
;;;;;;;;;;;;;;;;;;;; Data model ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Definition of a model tree item
(defstruct dir-tree-item
(name nil)
(children nil)
)
(defparameter *dir-root-item*
(make-dir-tree-item :name "/" :children nil))
;; add child item to an item
(defun add-dir-item-child (item child)
(setf (dir-tree-item-children item)
(cons child (dir-tree-item-children item)))
)
;; populate data model tree
(defun read-directory-structure (dir item)
(dolist (direntry (directory (format nil "~A/*" dir)))
(let ((child-item (make-dir-tree-item :name (file-namestring direntry))))
(add-dir-item-child item child-item)
(read-directory-structure (namestring direntry) child-item)
)
)
)
;;;;;;;;;;;;;;;;;;;; Browser code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar *dirbrowser* "Dir-Browser")
;; Populate browser
(defun dirbrowser-build-tree (&rest args)
(if args
;; first args: item-id, second args: list of children
(dolist (child-item (second args))
(let ((item-id
(sd-create-browsernode
:tree *dirbrowser* :parent (first args)
:objPname (dir-tree-item-name child-item)
:objClientData child-item)))
(dirbrowser-build-tree item-id (dir-tree-item-children child-item))
)
)
;; else - root
(dirbrowser-build-tree nil (list *dir-root-item*))
) ;; if
)
;; create directory browser and dock it
(defun dirbrowser-create ()
(sd-destroy-browser-tree *dirbrowser*)
(sd-create-browser-tree *dirbrowser* :update-func 'dirbrowser-build-tree)
(sd-destroy-graphical-browser *dirbrowser*)
(sd-create-graphical-browser
*dirbrowser* :tree *dirbrowser*
:createAsTab t :tabname "DirBrowser"
:topLabel "DirBrowser"
)
(oli:sd-dock-graphical-browser *dirbrowser* :show nil)
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; list contents of "personality" in installation dir
(read-directory-structure
(format nil "~A/personality" (oli:sd-inq-install-dir)) *dir-root-item*)
(dirbrowser-create)
(dirbrowser-build-tree)
Challenge: How could this example be done without the intermediate
data structure? Here's how:
;; -*-Lisp-*-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Description: Directory browser for OneSpace Modeling
;; Author: Claus Brod
;; Created: 11/19/2004
;; Language: Lisp
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
(in-package :clausbrod.de)
(use-package :oli)
(defvar *dirbrowser* "Dir-Browser")
(defun dirbrowser-build-tree (&rest args)
(if args
(dolist (child-item (second args))
(let ((item-id
(sd-create-browsernode :tree *dirbrowser* :parent (first args)
:objPname (file-namestring child-item)
:objClientData nil)))
(dirbrowser-build-tree item-id
(directory (format nil "~A/*" (namestring child-item))))
)
)
;;
(dirbrowser-build-tree nil (list (pathname *root-path*)))
)
)
;; create directory browser and dock it
(defun dirbrowser-create ()
(sd-destroy-browser-tree *dirbrowser*)
(sd-create-browser-tree *dirbrowser* :update-func 'dirbrowser-build-tree)
(sd-destroy-graphical-browser *dirbrowser*)
(sd-create-graphical-browser
*dirbrowser* :tree *dirbrowser*
:createAsTab t :tabname "DirBrowser"
:topLabel "DirBrowser"
)
(oli:sd-dock-graphical-browser *dirbrowser* :show nil)
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; list contents of "personality" in installation dir
(defparameter *root-path* (format nil "~A/personality" (oli:sd-inq-install-dir)))
(dirbrowser-create)
(dirbrowser-build-tree)
In this trivial example, the only data which the browser holds are the names
of the file or directory nodes, so we don't need corresponding structures to
hold more data. Note that this code passes in
nil
for the
:objClientData
parameter of the
sd-create-browsernode
call.
In most real-life cases, however, this is not sufficient, because the browser
is only a graphical representation of complex data structures. So you'll
probably end up building a parallel data model tree anyway.
Also, I'm not sure how the above reduced example behaves in the context
of browser refreshes. Comments most welcome - I'm on a learning path myself
here.
--
ClausBrod
to top