CLIM mail archive

[Prev][Next][Index][Thread]

Question about defining presentation types with parameters and options



    Date: Mon, 27 Jul 1992 05:06 EDT
    From: Thomas Ruedesheim <Thomas.Ruedesheim@sniap.mchp.sni.de>

There is in fact a CLIM bug here.  However there are some problems with
the example, too, and it is probably worthwhile going through them so
just for all of our benefit.

    Consider the following small example:

    ;;; -*- Mode: Common-Lisp; Package: CLIM-USER; -*-

    (define-presentation-type sentence
	(language)
      :options (direction)
      :inherit-from 'string)

First off, I think that the SENTENCE type needs to store what language
it is in in the SENTENCE object itself, not simply in the presentation.
This is because the sentence's language is a property of the sentence,
not simply a property of its user-interface behavior.

    (define-presentation-method accept
	((type sentence) stream (view textual-view) &key)
      (with-input-editing (stream) (read-line stream)))

You don't need WITH-INPUT-EDITING, since ACCEPT does that for you.  This
will need to create a SENTENCE object instead of just returning a string.

    (define-presentation-method present
	(object (type sentence) stream (view textual-view) &key)
      (format stream "~a" object))

This will need to access the string within the SENTENCE object.

    (define-presentation-method presentation-typep
	(object (type sentence))
      (and (typep object 'standard-presentation)
	   (let ((ptype (presentation-type object)))
	     (and (listp ptype)
		  (equal ptype (list 'sentence language)))))
      )

This is all confused.  The PRESENTATION-TYPEP method will never see any
objects of type STANDARD-PRESENTATION, only objects of type SENTENCE.
Thus, you can't extract this information from the presentation object
that you don't even have.  Also, this conses.  PRESENTATION-TYPEP
methods get called all the time, so they shouldn't cons.

    (define-presentation-method presentation-subtypep
	((type sentence) putative-supertype)
      (let (language1)
	(with-presentation-type-parameters (sentence type)
	  (setf language1 language))
	(with-presentation-type-parameters (sentence putative-supertype)
	  (if (eq language1 language)
	      (values t t)
	    (values nil t)))))

    (defun test ()
      (present "Das Haus brennt" '((sentence german) :direction :source))
      (terpri)
      (present "The house burns." '((sentence english) :direction :target))
      (terpri)
      (accept '((sentence german) :direction :source)))

This needs to create SENTENCE objects

    Here is my question:
    Call the function test inside an application frame's interactor pane.
    The inner call to ACCEPT accepts both the german and the english
    sentence.
    How could I change my code, so that only german sentences are
    accepted?

    Thomas

The following is the code I would write:

;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Package: CLIM-USER; Base: 10; Lowercase: Yes -*-

(in-package :clim-user)

(defclass sentence ()
    ((string :initarg :string :reader sentence-string)
     (language :initarg :language :reader sentence-language)))

(declaim (inline make-sentence))
(defun make-sentence (string &optional (language '*))
  (make-instance 'sentence :string string :language language))

;; Language of '* means anything is OK
(define-presentation-type sentence (&optional (language '*))
  :options (direction))

(define-presentation-method accept
			    ((type sentence) stream (view textual-view) &key)
  (let ((string (read-line stream)))
    (make-sentence string language)))

(define-presentation-method present
			    (sentence (type sentence) stream (view textual-view) &key)
  (format stream "~A" (sentence-string sentence)))

(define-presentation-method presentation-typep
			    (sentence (type sentence))
  (or (eql language '*)
      (eql language (sentence-language sentence))))

(define-presentation-method presentation-subtypep ((type1 sentence) type2)
  (let ((language1 (with-presentation-type-parameters (sentence type1)
		     language))
	(language2 (with-presentation-type-parameters (sentence type2)
		     language)))
    (values (or (eql language2 '*)
		(eql language1 language2))
	    t)))

(defun test ()
  (present (make-sentence "Das Haus brennt" 'german)
	   '((sentence german) :direction :source))
  (terpri)
  (present (make-sentence "The house burns." 'english)
	   '((sentence english) :direction :target))
  (terpri)
  (accept '((sentence german) :direction :source)))

------------
Now we get to the CLIM bug.  It seems that the function
IDENTITY-TRANSLATOR-APPLICABLE-P is accepting too much, which is simply
awful.  I did not test this completely thoroughly, but you might try
this definition for it:

(in-package :clim)
(defun identity-translator-applicable-p (presentation context-type)
  (let* ((type (presentation-type presentation))
	 (type-name (presentation-type-name type))
	 (object (presentation-object presentation)))
    (with-presentation-type-decoded (context-name context-parameters) context-type
      (if (eq type-name 'blank-area)
	  (eq context-name 'blank-area)
	;; Let MENU-ITEM-IDENTITY take care of pure menu items
	(unless (and (eq type-name 'menu-item)
		     (eq context-name 'menu-item))
	  ;; Either the types definitely match, or the types nominally match
	  ;; and the object must be validated.
	  (or (presentation-subtypep type context-type)
	      (and (not (null context-parameters))
		   (presentation-typep object context-type))))))))


References:

Main Index | Thread Index