Changeset 14591


Ignore:
Timestamp:
Jan 23, 2011, 8:25:29 AM (14 years ago)
Author:
Paul Krueger
Message:

Enhanced data conversion

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/cocoa-ide-contrib/krueger/InterfaceProjects/Utilities/ns-object-utils.lisp

    r14585 r14591  
    3535  (:export
    3636   archive-slots
     37   bound-slot-modified
    3738   class-name-string
    3839   clear-instance-hash
     
    246247                 ((ccl::subclassp lisp-class (find-class 'symbol))
    247248                  (string-to-interned-symbol lisp-str))
     249                 ((ccl::subclassp lisp-class (find-class 'number))
     250                  (let ((num (read-from-string lisp-str :nil 0)))
     251                    (if (numberp num)
     252                      num
     253                      0)))
    248254                 (t
    249255                  lisp-str))))
     
    697703  (ccl::%get-selector (ccl::load-objc-selector (concatenate 'string "set" (string-capitalize str :end 1)))))
    698704
    699 (objc:defmethod (#/valueForKey: :id)
    700                 ((self lisp-ptr-wrapper) (path :id))
    701   ;; Treat path as a lisp path as long as it works.
    702   ;; If it is not valid and the next target is an Objective-C object
    703   ;; then treat the path as a normal Objective-C Key and return the results
    704   ;; of calling #/valueForKey: on the target using path as the key.
    705   (let* ((lisp-str (ns-to-lisp-string path))
    706          (lisp-path (objc-to-lisp-keypathname lisp-str))
    707          (ptr-obj (lpw-lisp-ptr self))
    708          ;; to set next-obj we try 3 ways:
    709          ;; 1. If the path is a valid lisp function name use it to access the slot
    710          ;; 2. If the object is an Objective-C object try calling its #/valueForKey method
    711          ;; 3. Look for any KVO slots defined for the object with path specified as the KVO
    712          ;;    accessor and use the lisp function value-for-kvo-key to access that slot
    713          (next-obj (cond ((and (typep lisp-path 'function-name)
    714                                (fboundp lisp-path))
    715                           (funcall lisp-path ptr-obj))
    716                          ((and (typep ptr-obj 'objc:objc-object)
    717                                (#/respondsToSelector: ptr-obj (reader-selector lisp-str)))
    718                           (#/valueForKey: ptr-obj path))
    719                          (t
    720                           (ccl::value-for-kvo-key ptr-obj lisp-str)))))
    721     ;; First track that the path is being observed by somebody
    722     (note-kvc-observed self (lpw-lisp-ptr self) lisp-path)
    723     (note-kvc-observed self (lpw-lisp-ptr self) lisp-str)
    724     ;; (ns-log (format nil "(~s ~s) returned ~s" lisp-path (lpw-lisp-ptr self) next-obj))
    725     (cond ((eql next-obj (%null-ptr))
    726            next-obj)
    727           ((null next-obj)
    728            (%null-ptr))
    729           ((and (typep next-obj 'ns:ns-object)
    730                 (not (typep next-obj 'ccl::kvo-object)))
    731            ;; any kvo-objects will be encapsulated in a lisp-ptr-wrapper
    732            ;; so that subsequent accesses through this method will try to
    733            ;; use ccl::value-for-kvo-key
    734            next-obj)
    735           ((typep next-obj 'objc-displayable)
    736            (lisp-to-ns-object next-obj))
    737           (t
    738            (wrapper-for (lpw-controller self) next-obj :parent (lpw-lisp-ptr self))))))
    739 
    740 (objc:defmethod (#/setValue:forKey: :void)
    741                 ((self lisp-ptr-wrapper) (new-value :id) (path :id))
    742   (let* ((lisp-str (ns-to-lisp-string path))
    743          (lisp-path (objc-to-lisp-keypathname lisp-str))
    744          (ptr-obj (lpw-lisp-ptr self))
    745          (prev-obj (cond ((and (typep lisp-path 'function-name)
    746                                (fboundp lisp-path))
    747                           (funcall lisp-path ptr-obj))
    748                          ((and (typep ptr-obj 'objc:objc-object)
    749                                (#/respondsToSelector: self (reader-selector lisp-str)))
    750                           (#/valueForKey: ptr-obj path))
    751                          (t
    752                           (ccl::value-for-kvo-key ptr-obj lisp-str))))
    753          (prev-class (class-of prev-obj))
    754          (new-lisp-obj (ns-to-lisp-object new-value :lisp-class prev-class))
    755          (setf-func (fboundp (list 'setf lisp-path)))
    756          ;;`(setf (,lisp-path ,(lpw-lisp-ptr self)) ,new-lisp-obj))
    757          (ctrl (lpw-controller self)))
    758     ;; (ns-log (format nil "Prev Class: ~s" prev-class))
    759     (cond (setf-func
    760            (funcall setf-func new-lisp-obj ptr-obj))
    761           ((and (typep ptr-obj 'objc:objc-object)
    762                 (typep new-lisp-obj 'objc:objc-object)
    763                 (#/respondsToSelector: self (writer-selector lisp-str)))
    764            (#/setValue:forKey: ptr-obj new-lisp-obj path))
    765           (t
    766            (multiple-value-bind (value found-slot)
    767                                 (setf (ccl::value-for-kvo-key ptr-obj lisp-str) new-lisp-obj)
    768              (declare (ignore value))
    769              (unless found-slot
    770                ;; If the setf  failed, log the original condition
    771                (error "No way to setValue: ~s forKey: ~s for lisp-ptr ~s"
    772                       new-lisp-obj
    773                       lisp-str
    774                       ptr-obj)))))
    775     (when ctrl
    776       (lc::modified-bound-value ctrl
    777                                 (lpw-lisp-ptr self)
    778                                 lisp-path
    779                                 prev-obj
    780                                 new-lisp-obj))
    781     new-lisp-obj))
     705(defmethod bound-slot-modified ((self standard-object) slot-name)
     706  (declare (ignore slot-name))
     707  ;; do nothing by default
     708  )
     709
     710(defmethod real-observer (nskvo)
     711  ;; nskvo will be an instance of NSKeyValueObservance which isn't public as far as I can tell.
     712  ;; All we want is a pointer to the original observer extracted from that object, but without
     713  ;; a public API that is a little tricky. But we are trickier. We use the #/description of that
     714  ;; object which provides a substring of the form "Observer: 0x<whatever>" which points to
     715  ;; possibly another non-public object of type NSSelectionBinder. We extract the address and
     716  ;; create a pointer to the NSSelectionbinder. We now use its description to extract its
     717  ;; "object" slot address, which hopefully points to the original view object that we bound
     718  ;; to our lisp object. We use that to create a macptr and return it.
     719  (let* ((desc (ns-to-lisp-string (#/description nskvo)))
     720         (obs-start (search "Observer: " desc))
     721         (hex-start (and obs-start (position #\x desc :start (+ obs-start 9))))
     722         (hex-end (and hex-start (position #\, desc :start hex-start)))
     723         (hex-val (and hex-end (read-from-string (concatenate 'string "#" (subseq desc hex-start hex-end)) nil 0)))
     724         (nssb-ptr (and hex-val (ccl::%int-to-ptr hex-val)))
     725         (nssb-desc (and nssb-ptr (ns-to-lisp-string (#/description nssb-ptr))))
     726         (obj-start (search "object:" nssb-desc))
     727         (obj-class-end (and obj-start (position #\: nssb-desc :start (+ obj-start 8))))
     728         (obj-hex-start (and obj-class-end (position #\x nssb-desc :start obj-class-end)))
     729         (obj-hex-end (and obj-hex-start (position #\> nssb-desc :start obj-hex-start)))
     730         (obj-hex-val (and obj-hex-end (read-from-string (concatenate 'string "#" (subseq nssb-desc obj-hex-start obj-hex-end)) nil 0))))
     731    (when obj-hex-val
     732      (ccl::%int-to-ptr obj-hex-val))))
     733
     734(let ((format-assoc (make-instance 'assoc-array :rank 2 :tests (list #'eql #'equal))))
     735  ;; used to hold needed Objective-C format information for slots that are observed by
     736  ;; Objective-C objects that have associated formatter objects from which we can take hints.
     737
     738  (objc:defmethod (#/addObserver:forKeyPath:options:context: :void)
     739                  ((self lisp-ptr-wrapper) (obs :id) (key-path :id) (options #>NSUInteger) (context :address))
     740    (let ((observer (real-observer obs)))
     741      (ns-log (format nil "~s observed by ~s" (lpw-lisp-ptr self) observer))
     742      (when (subtypep (type-of observer) 'ns:ns-control)
     743        (let* ((cell (#/cell observer))
     744               (formatter (#/formatter cell))
     745               (ns-format nil))
     746          (cond ((or (typep cell 'ns:ns-date-picker-cell)
     747                     (typep formatter 'ns:ns-date-formatter))
     748                 (setf ns-format :date))
     749                ((typep formatter 'ns:ns-number-formatter)
     750                 (cond ((#/generatesDecimalNumbers formatter)
     751                        (let ((dec-digits (#/maximumFractionDigits formatter)))
     752                          (setf ns-format (list :decimal dec-digits))))
     753                       (t
     754                        (setf ns-format :number)))))
     755          (when ns-format
     756            (ns-log (format nil "Observer data format: ~s" ns-format))
     757            (setf (assoc-aref format-assoc self (ns-to-lisp-string key-path)) ns-format)))))
     758    (call-next-method obs key-path options context))
     759
     760  (objc:defmethod (#/valueForKey: :id)
     761                  ((self lisp-ptr-wrapper) (path :id))
     762    ;; Treat path as a lisp path as long as it works.
     763    ;; If it is not valid and the next target is an Objective-C object
     764    ;; then treat the path as a normal Objective-C Key and return the results
     765    ;; of calling #/valueForKey: on the target using path as the key.
     766    (let* ((lisp-str (ns-to-lisp-string path))
     767           (lisp-path (objc-to-lisp-keypathname lisp-str))
     768           (ptr-obj (lpw-lisp-ptr self))
     769           ;; to set next-obj we try 3 ways:
     770           ;; 1. If the path is a valid lisp function name use it to access the slot
     771           ;; 2. If the object is an Objective-C object try calling its #/valueForKey method
     772           ;; 3. Look for any KVO slots defined for the object with path specified as the KVO
     773           ;;    accessor and use the lisp function value-for-kvo-key to access that slot
     774           (next-obj (cond ((and (typep lisp-path 'function-name)
     775                                 (fboundp lisp-path))
     776                            (funcall lisp-path ptr-obj))
     777                           ((and (typep ptr-obj 'objc:objc-object)
     778                                 (#/respondsToSelector: ptr-obj (reader-selector lisp-str)))
     779                            (#/valueForKey: ptr-obj path))
     780                           (t
     781                            (ccl::value-for-kvo-key ptr-obj lisp-str)))))
     782      ;; First track that the path is being observed by somebody
     783      (note-kvc-observed self (lpw-lisp-ptr self) lisp-path)
     784      (note-kvc-observed self (lpw-lisp-ptr self) lisp-str)
     785      ;; (ns-log (format nil "(~s ~s) returned ~s" lisp-path (lpw-lisp-ptr self) next-obj))
     786      (cond ((eql next-obj (%null-ptr))
     787             next-obj)
     788            ((null next-obj)
     789             (%null-ptr))
     790            ((and (typep next-obj 'ns:ns-object)
     791                  (not (typep next-obj 'ccl::kvo-object)))
     792             ;; any kvo-objects will be encapsulated in a lisp-ptr-wrapper
     793             ;; so that subsequent accesses through this method will try to
     794             ;; use ccl::value-for-kvo-key
     795             next-obj)
     796            ((typep next-obj 'objc-displayable)
     797             (lisp-to-ns-object next-obj (assoc-aref format-assoc self lisp-str)))
     798            (t
     799             (wrapper-for (lpw-controller self) next-obj :parent (lpw-lisp-ptr self))))))
     800
     801  (objc:defmethod (#/setValue:forKey: :void)
     802                  ((self lisp-ptr-wrapper) (new-value :id) (path :id))
     803    (let* ((lisp-str (ns-to-lisp-string path))
     804           (lisp-path (objc-to-lisp-keypathname lisp-str))
     805           (ptr-obj (lpw-lisp-ptr self))
     806           (prev-obj (cond ((and (typep lisp-path 'function-name)
     807                                 (fboundp lisp-path))
     808                            (funcall lisp-path ptr-obj))
     809                           ((and (typep ptr-obj 'objc:objc-object)
     810                                 (#/respondsToSelector: self (reader-selector lisp-str)))
     811                            (#/valueForKey: ptr-obj path))
     812                           (t
     813                            (ccl::value-for-kvo-key ptr-obj lisp-str))))
     814           (prev-class (class-of prev-obj))
     815           (new-lisp-obj (ns-to-lisp-object new-value :lisp-class prev-class))
     816           (setf-func (fboundp (list 'setf lisp-path)))
     817           ;;`(setf (,lisp-path ,(lpw-lisp-ptr self)) ,new-lisp-obj))
     818           (ctrl (lpw-controller self)))
     819      ;; (ns-log (format nil "Prev Class: ~s" prev-class))
     820      (cond (setf-func
     821             (funcall setf-func new-lisp-obj ptr-obj))
     822            ((and (typep ptr-obj 'objc:objc-object)
     823                  (typep new-lisp-obj 'objc:objc-object)
     824                  (#/respondsToSelector: self (writer-selector lisp-str)))
     825             (#/setValue:forKey: ptr-obj new-lisp-obj path))
     826            (t
     827             (multiple-value-bind (value found-slot)
     828                                  (setf (ccl::value-for-kvo-key ptr-obj lisp-str) new-lisp-obj)
     829               (declare (ignore value))
     830               (if found-slot
     831                 (bound-slot-modified ptr-obj (ccl::slot-definition-name found-slot))
     832                 ;; If the setf  failed, log the original condition
     833                 (error "No way to setValue: ~s forKey: ~s for lisp-ptr ~s"
     834                        new-lisp-obj
     835                        lisp-str
     836                        ptr-obj)))))
     837      (when ctrl
     838        (lc::modified-bound-value ctrl
     839                                  (lpw-lisp-ptr self)
     840                                  lisp-path
     841                                  prev-obj
     842                                  new-lisp-obj))
     843      new-lisp-obj))
     844
     845)
    782846
    783847;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Note: See TracChangeset for help on using the changeset viewer.