[mcclim-cvs] CVS mcclim/ESA
thenriksen
thenriksen at common-lisp.net
Sat Dec 8 08:53:48 UTC 2007
Update of /project/mcclim/cvsroot/mcclim/ESA
In directory clnet:/tmp/cvs-serv13736/ESA
Modified Files:
utils.lisp packages.lisp esa.lisp esa-buffer.lisp
Log Message:
Changed Drei to use a view-based paradigm, didn't make any significant
changes to ESA just yet.
--- /project/mcclim/cvsroot/mcclim/ESA/utils.lisp 2007/08/13 21:56:04 1.3
+++ /project/mcclim/cvsroot/mcclim/ESA/utils.lisp 2007/12/08 08:53:48 1.4
@@ -18,7 +18,7 @@
;;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;;; Boston, MA 02111-1307 USA.
-;;; Miscellaneous utilities used in Climacs.
+;;; Miscellaneous utilities used in ESA.
(in-package :esa-utils)
@@ -212,3 +212,99 @@
specifiers."
(some (lambda (x)
(subtypep x `(and , at types))) types))
+
+(defclass observable-mixin ()
+ ((%observers :accessor observers
+ :initform '()))
+ (:documentation "A mixin class that adds the capability for a
+subclass to have a list of \"event subscribers\" (observers) that
+can be informed via callback (the function `observer-notified')
+whenever the state of the object changes. The order in which
+observers will be notified is undefined."))
+
+(defgeneric add-observer (observable observer)
+ (:documentation "Add an observer to an observable object. If
+the observer is already observing `observable', it will not be
+added again."))
+
+(defmethod add-observer ((observable observable-mixin) observer)
+ ;; Linear in complexity, perhaps a transparent switch to a hash
+ ;; table would be a good idea for large amounts of observers.
+ (pushnew observer (observers observable)))
+
+(defgeneric remove-observer (observable observer)
+ (:documentation "Remove an observer from an observable
+object. If observer is not in the list of observers of
+`observable', nothing will happen."))
+
+(defmethod remove-observer ((observable observable-mixin) observer)
+ (setf (observers observable)
+ (delete observer (observers observable))))
+
+(defgeneric observer-notified (observer observable data)
+ (:documentation "This function is called by `observable' when
+its state changes on each observer that is observing
+it. `Observer' is the observing object, `observable' is the
+observed object. `Data' is arbitrary data that might be of
+interest to `observer', it is recommended that subclasses of
+`observable-mixin' specify exactly which form this data will
+take, the observer protocol does not guarantee anything. It is
+non-&optional so that methods may be specialised on it, if
+applicable. The default method on this function is a no-op, so it
+is never an error to not define a method on this generic function
+for an observer.")
+ (:method (observer (observable observable-mixin) data)
+ ;; Never a no-applicable-method error.
+ nil))
+
+(defgeneric notify-observers (observable &optional data-fn)
+ (:documentation "Notify each observer of `observable' by
+calling `observer-notified' on them. `Data-fn' will be called,
+with the observer as the single argument, to obtain the `data'
+argument to `observer-notified'. The default value of `data-fn'
+should cause the `data' argument to be NIL."))
+
+(defmethod notify-observers ((observable observable-mixin)
+ &optional (data-fn (constantly nil)))
+ (dolist (observer (observers observable))
+ (observer-notified observer observable
+ (funcall data-fn observer))))
+
+(defclass name-mixin ()
+ ((%name :accessor name
+ :initarg :name
+ :type string
+ :documentation "The name of the named object."))
+ (:documentation "A class used for defining named objects."))
+
+(defclass subscriptable-name-mixin (name-mixin)
+ ((%subscript :accessor subscript
+ :documentation "The subscript of the named object.")
+ (%subscript-generator :accessor subscript-generator
+ :initarg :subscript-generator
+ :initform (constantly 1)
+ :documentation "A function used for
+finding the subscript of a `name-mixin' whenever the name is
+set (including during object initialization). This function will
+be called with the name as the single argument."))
+ (:documentation "A class used for defining named objects. A
+facility is provided for assigning a named object a \"subscript\"
+uniquely identifying the object if there are other objects of the
+same name in its collection (in particular, if an editor has two
+buffers with the same name)."))
+
+(defmethod initialize-instance :after ((name-mixin subscriptable-name-mixin)
+ &rest initargs)
+ (declare (ignore initargs))
+ (setf (subscript name-mixin)
+ (funcall (subscript-generator name-mixin) (name name-mixin))))
+
+(defmethod subscripted-name ((name-mixin subscriptable-name-mixin))
+ ;; Perhaps this could be written as a single format statement?
+ (if (/= (subscript name-mixin) 1)
+ (format nil "~A <~D>" (name name-mixin) (subscript name-mixin))
+ (name name-mixin)))
+
+(defmethod (setf name) :after (new-name (name-mixin subscriptable-name-mixin))
+ (setf (subscript name-mixin)
+ (funcall (subscript-generator name-mixin) new-name)))
--- /project/mcclim/cvsroot/mcclim/ESA/packages.lisp 2007/11/19 20:34:10 1.5
+++ /project/mcclim/cvsroot/mcclim/ESA/packages.lisp 2007/12/08 08:53:48 1.6
@@ -41,7 +41,12 @@
#:invoke-with-dynamic-bindings-1
#:invoke-with-dynamic-bindings
#:maptree
- #:subtype-compatible-p))
+ #:subtype-compatible-p
+ #:observable-mixin
+ #:add-observer #:remove-observer
+ #:observer-notified #:notify-observers
+ #:name-mixin #:name
+ #:subscriptable-name-mixin #:subscripted-name #:subscript #:subscript-generator))
(defpackage :esa
(:use :clim-lisp :clim :esa-utils)
--- /project/mcclim/cvsroot/mcclim/ESA/esa.lisp 2007/11/19 20:28:43 1.11
+++ /project/mcclim/cvsroot/mcclim/ESA/esa.lisp 2007/12/08 08:53:48 1.12
@@ -41,10 +41,18 @@
(defgeneric esa-current-buffer (esa)
(:documentation "Return the current buffer of APPLICATION-FRAME."))
+(defgeneric (setf esa-current-buffer) (new-buffer esa)
+ (:documentation "Replace the current buffer of
+APPLICATION-FRAME with NEW-BUFFER."))
+
(defun current-buffer ()
"Return the currently active buffer of the running ESA."
(esa-current-buffer *esa-instance*))
+(defun (setf current-buffer) (new-buffer)
+ "Return the currently active buffer of the running ESA."
+ (setf (esa-current-buffer *esa-instance*) new-buffer))
+
(defgeneric windows (esa)
(:documentation "Return a list of all the windows of the ESA.")
(:method ((esa application-frame))
--- /project/mcclim/cvsroot/mcclim/ESA/esa-buffer.lisp 2007/11/13 13:05:38 1.2
+++ /project/mcclim/cvsroot/mcclim/ESA/esa-buffer.lisp 2007/12/08 08:53:48 1.3
@@ -45,10 +45,10 @@
representation"
(frame-save-buffer-to-stream *application-frame* buffer stream))
-(defclass esa-buffer-mixin ()
+(defclass esa-buffer-mixin (name-mixin)
((%filepath :initform nil :accessor filepath)
- (%name :initarg :name :initform "*scratch*" :accessor name)
(%needs-saving :initform nil :accessor needs-saving)
(%file-write-time :initform nil :accessor file-write-time)
(%file-saved-p :initform nil :accessor file-saved-p)
- (%read-only-p :initform nil :accessor read-only-p)))
+ (%read-only-p :initform nil :accessor read-only-p))
+ (:default-initargs :name "*scratch*"))
More information about the Mcclim-cvs
mailing list