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


When asked for a TWiki account, use your own or the default TWikiGuest account.

Revision: r1.3 - 18 Dec 2006 - 20:38 - ClausBrod
CoCreateModeling > OsdmMacros > MacroDirectoryBrowser
Copyright © 1999-2024 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback