> What is the syntax for adding new fields?  I haven't seen any examples
> of it anywhere.

It's the same for the "company" slot you posted.  Currently, we don't do
any slot combination like CLOS does; we just use direct override.  So in
the example, the `company' slot works by shadowing the inherited one.
If you want to see how inheritance works, apply the attached patch
before reading get-object-view-fields (the patch will be pushed to dev
once I'm more comfortable with it).


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"weblocks" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/weblocks?hl=en
-~----------~----~----~----~------~----~------~--~---

diff --git a/src/views/view/utils.lisp b/src/views/view/utils.lisp
--- a/src/views/view/utils.lisp
+++ b/src/views/view/utils.lisp
@@ -33,6 +33,86 @@
 if it was mixed into the view."
   field object parent-info)
 
+(defun factor-overridden-fields (field-info-list)
+  "Overrides parent fields redefined in children."
+  ;; XXX this is less quite inefficient (at least n^2 + n*log(n))
+  #+lp-view-field-debug
+  (format t "fil: ~S~%" field-info-list)
+  (labels ((field-key (field-info)
+	     (cons (fi-slot-name field-info)
+		   (awhen (parent field-info)
+		     (view-field-slot-name (field-info-field IT)))))
+	   (fi-slot-name (field-info)
+	     (view-field-slot-name (field-info-field field-info)))
+	   (parent (field-info)
+	     (field-info-parent-info field-info))
+	   (mixin-p (field-info)
+	     (typep (field-info-field field-info) 'mixin-view-field)))
+    #+lp-view-field-debug
+    (format t "in: ~S~%" (mapcar (compose #'describe #'field-info-field) field-info-list))
+    (let ((fields (remove-duplicates field-info-list
+				     :test #'equal :key #'field-key)))
+      (multiple-value-bind (expanded-mixin-fields true-inline-fields)
+	  (partition fields (disjoin #'parent #'mixin-p))
+	(setf expanded-mixin-fields
+	      (remove-if (curry-after #'find true-inline-fields
+				      :test #'equal :key #'fi-slot-name)
+			 expanded-mixin-fields))
+	(let* ((pos-table
+		(let ((pos-table (make-hash-table :test 'equal)))
+		  (loop for pos from 0
+			;; We use field-info-list instead of FIELDS
+			;; below, with backward filling (like `find'),
+			;; for compatibility with r1132:980bccf and
+			;; older.
+			for field in field-info-list
+			for key = (field-key field)
+			unless (nth-value 1 (gethash key pos-table))
+			  do (setf (gethash key pos-table) pos))
+		  pos-table))
+	       (merged-fields
+		(sort (union true-inline-fields expanded-mixin-fields)
+		      #'< :key (f_ (gethash (field-key _) pos-table 0)))))
+	  #+lp-view-field-debug
+	  (progn
+	    (format t "true inline: ~S~%" (mapcar #'field-key true-inline-fields))
+	    (format t "expanded ~S~%" (mapcar #'field-key expanded-mixin-fields))
+	    (format t "fields ~S~%" (mapcar #'field-key fields))
+	    (format t "merged ~S~%" (mapcar (compose #'describe #'field-info-field) merged-fields)))
+	  merged-fields)))))
+
+(defun map-view-field-info-list (proc view-designator obj parent-field-info)
+  "Walk a full list of view fields, including inherited fields."
+  (let ((view (when view-designator
+		(find-view view-designator))))
+    (when view
+      (map-view-field-info-list proc (view-inherit-from view) obj
+				parent-field-info)
+      (dolist (field (view-fields view))
+	(funcall proc (make-field-info :field field :object obj
+				       :parent-info parent-field-info))))))
+
+(defun map-expanding-mixin-fields (proc field-info-list &optional include-invisible-p)
+  "Expands mixin fields into inline fields. Returns two values - a
+list of expanded field-infos, and true if at least one field has been
+expanded."
+  (labels ((map-emf (field-info)
+	     (let ((field (field-info-field field-info))
+		   (obj (field-info-object field-info)))
+	       (etypecase field
+		 (inline-view-field (funcall proc field-info))
+		 (mixin-view-field
+		    (when (or include-invisible-p
+			      (not (view-field-hide-p field)))
+		      (map-view-field-info-list
+		       #'map-emf
+		       (mixin-view-field-view field)
+		       (when obj
+			 (or (obtain-view-field-value field obj)
+			     (funcall (mixin-view-field-init-form field))))
+		       field-info)))))))
+    (mapc #'map-emf field-info-list)))
+
 (defun get-object-view-fields (obj view-designator &rest args
 			       &key include-invisible-p (expand-mixins t) custom-fields
 			       &allow-other-keys)
@@ -55,101 +135,26 @@
 view-field. Field-info structures are inserted as is, and view-fields
 are wrapped in field-info structures with common-sense defaults."
   (declare (ignore args))
-  (labels ((compute-view-field-info-list (view-designator obj parent-field-info)
-	     "Computes a full list of view fields, including inherited
-	     fields. Returns a list of field-infos."
-	     (let ((view (when view-designator
-			   (find-view view-designator))))
-	       (when view
-		 (append (compute-view-field-info-list
-			  (view-inherit-from view) obj
-			  parent-field-info)
-			 (mapcar (lambda (field)
-				   (make-field-info :field field :object obj
-						    :parent-info parent-field-info))
-				 (view-fields view))))))
-	   (factor-overriden-fields (field-info-list)
-	     "Overrides parent fields redefined in children."
-             ;(format t "fil: ~S~%" field-info-list)
-             (flet ((field-key (field-info &aux (field (field-info-field field-info)))
-                      (cons (view-field-slot-name field) (awhen (field-info-parent-info field-info)
-                                                              (view-field-slot-name (field-info-field IT)))))
-                    (parent (field-info &aux (field (field-info-field field-info)))
-                      (field-info-parent-info field-info))
-                    (mixin-p (field-info &aux (field (field-info-field field-info)))
-                      (typep field 'mixin-view-field)))
-               ;(format t "in: ~S~%" (mapcar (compose #'describe #'field-info-field) field-info-list))
-               (let* ((fields (remove-duplicates field-info-list :key #'field-key :from-end nil))
-                      (true-inline-fields (remove-duplicates fields :test #'equal
-                                                             :key (compose #'view-field-slot-name #'field-info-field)
-                                                             :from-end nil))
-                      (true-inline-fields (remove-if (lambda (fi) (or (parent fi) (mixin-p fi))) true-inline-fields
-                                                     :from-end t))
-                      (expanded-mixin-fields (remove-if-not (lambda (fi) (or (parent fi) (mixin-p fi)))
-                                                            fields))
-                      (expanded-mixin-fields (remove-duplicates expanded-mixin-fields :test #'equal :key #'field-key))
-                      (expanded-mixin-fields (remove-if (curry-after #'find true-inline-fields
-                                                                     :test #'equal :key (compose #'view-field-slot-name
-                                                                                                 #'field-info-field)
-                                                                     :from-end nil) expanded-mixin-fields))
-                      (merged-fields (sort (union true-inline-fields expanded-mixin-fields)
-                                           #'< :key (lambda (field)
-                                                      (flet ((pos (field where)
-                                                               (let ((r (position (field-key field) where :key #'field-key :test #'equal)))
-                                                               ;(format t "field: ~S / where: ~S -> ~S%" (field-key field)
-                                                               ;        (mapcar #'field-key where) r)
-                                                               r
-                                                               )))
-                                                        (let ((result (or (pos field fields)
-                                                                          (pos field true-inline-fields)
-                                                                          (pos field expanded-mixin-fields)
-                                                                          0)))
-                                                        #+(or)(format t "result for field ~A: ~A~%" field result) result))))))
-                 ;(format t "true inline: ~S~%" (mapcar #'field-key true-inline-fields))
-                 ;(format t "expanded ~S~%" (mapcar #'field-key expanded-mixin-fields))
-                 ;(format t "fields ~S~%" (mapcar #'field-key fields))
-                 ;(format t "merged ~S~%" (mapcar (compose #'describe #'field-info-field) merged-fields))
-                 merged-fields))) ; XXX this is quite inefficient (at least n^2 + n*log(n))
-	   (expand-mixin-fields (field-info-list)
-	     "Expands mixin fields into inline fields. Returns two
-              values - a list of expanded field-infos, and true if at
-              least one field has been expanded."
-	     (apply #'append
-		    (mapcar (lambda (field-info)
-			      (let ((field (field-info-field field-info))
-				    (obj (field-info-object field-info)))
-				(etypecase field
-				  (inline-view-field (list field-info))
-				  (mixin-view-field (when (or include-invisible-p
-							      (not (view-field-hide-p field)))
-						      (compute-view-field-info-list
-						       (mixin-view-field-view field)
-						       (when obj
-							 (or (obtain-view-field-value field obj)
-							     (funcall (mixin-view-field-init-form field))))
-						       field-info))))))
-			    field-info-list)))
-	   (custom-field->field-info (custom-field)
+  (labels ((custom-field->field-info (custom-field)
 	     (etypecase custom-field
 	       (field-info custom-field)
 	       (view-field (make-field-info :field custom-field
 					    :object obj
 					    :parent-info nil)))))
-    (let* ((initial-step (factor-overriden-fields
-			  (compute-view-field-info-list view-designator obj nil)))
-	   (results
-	    (if expand-mixins
-		(loop for field-info-list = initial-step
-		   then (factor-overriden-fields
-			 (expand-mixin-fields field-info-list))
-		   until (notany (lambda (field-info)
-				   (typep (field-info-field field-info) 'mixin-view-field))
-				 field-info-list)
-		   finally (return (if include-invisible-p
-				       field-info-list
-				       (remove-if #'view-field-hide-p field-info-list
-						  :key #'field-info-field))))
-		initial-step)))
+    (let* ((results (factor-overridden-fields
+		     (let ((expansion '()))
+		       (map-view-field-info-list (f_ (push _ expansion))
+						 view-designator obj nil)
+		       (nreverse expansion)))))
+      (when expand-mixins
+	(setf results (factor-overridden-fields
+		       (let ((expansion '()))
+			 (map-expanding-mixin-fields
+			  (f_ (push _ expansion)) results include-invisible-p)
+			 (nreverse expansion)))))
+      (unless include-invisible-p
+	(setf results (remove-if #'view-field-hide-p results
+				 :key #'field-info-field)))
       (dolist (custom-field custom-fields results)
 	(if (consp custom-field)
 	    (insert-at (custom-field->field-info (cdr custom-field)) results (car custom-field))
The syntax is the [FIELD-NAME | (FIELD-NAME ...)] described in defview's
docstring.  Full details start with the "FIELD-NAME" entry in the
docstring.

> I've been poring over the code (and documentation strings) in
> compiler.lisp, but I don't see how this can be easily done.

To really get this, you need to chase down the relevant classes.  For a
view with `:type form' (where `form' has symbol-package=weblocks), the
VIEW-KWARGS available are initargs defined by class `form-view' (and so
inherited, such as the :caption arg from class `view'), and the
FIELD-KWARGS available are those on `form-view-field'.  Lots of this can
be overridden using the relevant generic functions.

The nice thing about the `...' syntax is that Emacs understands that
it's a symbol delimiter.  To learn more about a symbol the defview
docstring talks about, just stick point there, hit M-., and read.  For
example, to read up on the `form-view' slot `satisfies', stick point in
the form-view part, hit M-., and find the slot docstring for `satisfies'
in the list of slots it has.

-- 
Sorry but you say Nibiru is a Hoax?  Doesnt Exist?  So maybe The
Sumerian people doesnt exist also! --Anonymous by way of SkI

Reply via email to