original commit: 17a9d0959ba561241cfca0946e212a5617095523
This commit is contained in:
Robby Findler 2005-02-22 01:58:06 +00:00
parent 1d882e9a54
commit 43dbaa5bcf
2 changed files with 113 additions and 105 deletions

View File

@ -19,6 +19,8 @@
[color-prefs : framework:color-prefs^] [color-prefs : framework:color-prefs^]
[scheme : framework:scheme^]) [scheme : framework:scheme^])
(preferences:read)
(application-preferences-handler (λ () (preferences:show-dialog))) (application-preferences-handler (λ () (preferences:show-dialog)))
(preferences:set-default 'framework:basic-canvas-background (preferences:set-default 'framework:basic-canvas-background

View File

@ -1,3 +1,44 @@
#|
save needs contracts
showing the dialog needs preferences.
There are four attributes for each preference (technically, "read from
disk" is global, but we can just think of it happening to each one
independently, but simultaneously):
- read from disk, or not
- default set, or not
- marshalling function set, or not
- initialization still okay, or not
the state transitions / contracts are:
get(true, true, _, _) -> (true, true, _, false)
get(false, _, _, _) -> error not yet read from disk
get(_, false, _, _) -> error default not yet set
set is just like get.
set-default(true, false, _, true) -> set-default(true, true, _, true)
set-default(false, _, _, _) -> error not yet read from disk
set-default(_, true, _, _) -> error default already set
set-default(_, _, _, false) -> initialization not okay anymore /* cannot happen, I think */
set-marshallingfn(true, _, false, true) -> (true, _, true, true)
... similar to set-default ...
read(false, _, _, true) -> (true, _, _, true)
read(true, _, _, _) -> error, already read from disk
read(_, _, _, false) -> initialization phase over /* cannot happen */
for all syms:
prefs-snapshot(true, _, _, _) -> (true, _, _, false)
for the last one, need a global "no more initialization can happen" flag.
|#
(module preferences mzscheme (module preferences mzscheme
(require (lib "string-constant.ss" "string-constants") (require (lib "string-constant.ss" "string-constants")
@ -24,32 +65,36 @@
(define main-preferences-symbol 'plt:framework-prefs) (define main-preferences-symbol 'plt:framework-prefs)
;; preferences : sym -o> (union marshalled any) ;; preferences : hash-table[sym -o> any]
;; for a given preference symbol, p, ;; the current values of the preferences
;; when the table maps to a marshalled struct, the
;; preference has not been examined (via get or set)
(define preferences (make-hash-table)) (define preferences (make-hash-table))
;; marshalled : hash-table[sym -o> any]
;; the values of the preferences, as read in from the disk
;; each symbol will only be mapped in one of the preferences
;; hash-table and this hash-table, but not both.
(define marshalled (make-hash-table))
;; marshall-unmarshall : sym -o> un/marshall ;; marshall-unmarshall : sym -o> un/marshall
(define marshall-unmarshall (make-hash-table)) (define marshall-unmarshall (make-hash-table))
;; callbacks : sym -o> (listof (sym TST -> boolean)) ;; callbacks : sym -o> (listof (sym TST -> boolean))
(define callbacks (make-hash-table)) (define callbacks (make-hash-table))
;; defaults : sym -o> default ;; defaults : hash-table[sym -o> default]
(define defaults (make-hash-table)) (define defaults (make-hash-table))
;; changed : hash-table[symbol -o> true] ;; these four functions determine the state of a preference
;; the mapped symbols are the ones that have changed (define (pref-read?) read?)
;; but not yet written out to disk. (define (pref-marshall-set? pref) (hash-table-bound? marshall-unmarshall pref))
(define changed (make-hash-table)) (define (pref-default-set? pref) (hash-table-bound? defaults pref))
(define (pref-can-init? pref)
(and (not snapshot-grabbed?)
(not (hash-table-bound? preferences pref))))
;; type un/marshall = (make-un/marshall (any -> prinable) (printable -> any)) ;; type un/marshall = (make-un/marshall (any -> prinable) (printable -> any))
(define-struct un/marshall (marshall unmarshall)) (define-struct un/marshall (marshall unmarshall))
;; type marshalled = (make-marshalled printable)
(define-struct marshalled (data))
;; type pref = (make-pref any) ;; type pref = (make-pref any)
(define-struct pref (value)) (define-struct pref (value))
@ -71,10 +116,15 @@
(hash-table-get preferences (hash-table-get preferences
p p
(λ () (λ ()
(cond
[(hash-table-bound? marshalled p)
(hash-table-put! preferences p (unmarshall p (hash-table-get marshalled p)))
(hash-table-remove! marshalled p)]
[else
(let* ([def (hash-table-get defaults p)] (let* ([def (hash-table-get defaults p)]
[def-val (default-value def)]) [def-val (default-value def)])
(hash-table-put! preferences p def-val) (hash-table-put! preferences p def-val))])
def-val)))) (hash-table-get preferences p))))
;; set : symbol any -> void ;; set : symbol any -> void
;; updates the preference ;; updates the preference
@ -92,6 +142,7 @@
"tried to set preference ~e to ~e but it does not meet test from preferences:set-default" "tried to set preference ~e to ~e but it does not meet test from preferences:set-default"
p value)) p value))
(check-callbacks p value) (check-callbacks p value)
(hash-table-remove! marshalled p)
(hash-table-put! preferences p value))) (hash-table-put! preferences p value)))
(define (raise-unknown-preference-error fmt . args) (define (raise-unknown-preference-error fmt . args)
@ -101,18 +152,17 @@
;; unmarshall : symbol marshalled -> any ;; unmarshall : symbol marshalled -> any
;; unmarshalls a preference read from the disk ;; unmarshalls a preference read from the disk
(define (unmarshall p marshalled) (define (unmarshall p data)
(let/ec k (let/ec k
(let* ([data (marshalled-data marshalled)] (let* ([unmarshall-fn (un/marshall-unmarshall
[unmarshall-fn (un/marshall-unmarshall
(hash-table-get marshall-unmarshall (hash-table-get marshall-unmarshall
p p
(λ () (k data))))] (λ () (k data))))]
[default (hash-table-get defaults p)]) [default (hash-table-get defaults p)]
(let ([result (unmarshall-fn data)]) [result (unmarshall-fn data)])
(if ((default-checker default) result) (if ((default-checker default) result)
result result
(default-value default)))))) (default-value default)))))
;; add-callback : sym (-> void) -> void ;; add-callback : sym (-> void) -> void
(define add-callback (define add-callback
@ -169,8 +219,8 @@
(unless (hash-table-bound? defaults p) (unless (hash-table-bound? defaults p)
(error 'set-un/marshall "must call set-default for ~s before calling set-un/marshall for ~s" (error 'set-un/marshall "must call set-default for ~s before calling set-un/marshall for ~s"
p p)) p p))
(when (pref-has-value? p) (unless (pref-can-init? p)
(error 'preferences:set-un/marshall "a value for the preference ~e has already been looked up or set" p)) (error 'preferences:set-un/marshall "the preference ~e cannot be configured any more" p))
(hash-table-put! marshall-unmarshall p (make-un/marshall marshall unmarshall)))) (hash-table-put! marshall-unmarshall p (make-un/marshall marshall unmarshall))))
(define (hash-table-bound? ht s) (define (hash-table-bound? ht s)
@ -186,9 +236,9 @@
;; set-default : (sym TST (TST -> boolean) -> void ;; set-default : (sym TST (TST -> boolean) -> void
(define (set-default p default-value checker) (define (set-default p default-value checker)
(when (pref-has-value? p) (unless (pref-can-init? p)
(error 'preferences:set-default (error 'preferences:set-default
"tried to call set-default for preference ~e but it already has a value" "tried to call set-default for preference ~e but it cannot be configured any more"
p)) p))
(let ([default-okay? (checker default-value)]) (let ([default-okay? (checker default-value)])
(unless default-okay? (unless default-okay?
@ -196,14 +246,6 @@
p checker default-okay? default-value)) p checker default-okay? default-value))
(hash-table-put! defaults p (make-default default-value checker)))) (hash-table-put! defaults p (make-default default-value checker))))
;; pref-has-value? : symbol -> boolean
;; returns #t if the preference's value has been examined with set or get
(define (pref-has-value? p)
(let/ec k
(let ([b (hash-table-get preferences p (λ () (k #f)))])
(not (marshalled? b)))))
(define (save) (raw-save #f)) (define (save) (raw-save #f))
(define (silent-save) (raw-save #f)) (define (silent-save) (raw-save #f))
@ -244,15 +286,13 @@
;; marshall-pref : symbol any -> (list symbol printable) ;; marshall-pref : symbol any -> (list symbol printable)
(define (marshall-pref p value) (define (marshall-pref p value)
(if (marshalled? value)
(list p (marshalled-data value))
(let/ec k (let/ec k
(let* ([marshaller (let* ([marshaller
(un/marshall-marshall (un/marshall-marshall
(hash-table-get marshall-unmarshall p (hash-table-get marshall-unmarshall p
(λ () (k (list p value)))))] (λ () (k (list p value)))))]
[marshalled (marshaller value)]) [marshalled (marshaller value)])
(list p marshalled))))) (list p marshalled))))
(define (read-err input msg) (define (read-err input msg)
(message-box (message-box
@ -275,65 +315,31 @@
;; read : -> void ;; read : -> void
(define (-read) (define (-read)
(get-disk-prefs/install void) (set! read? #t)
(void))
;; get-disk-prefs/install : (-> A) -> (union A sexp)
(define (get-disk-prefs/install fail)
(let/ec k (let/ec k
(let ([sexp (get-disk-prefs (λ () (k (fail))))]) (let ([sexp (get-preference main-preferences-symbol (λ () (k (void))))])
(install-stashed-preferences sexp '()) (when (andmap (lambda (x)
sexp))) (and (pair? x)
(symbol? (car x))
(pair? (cdr x))
(null? (cddr x))))
sexp)
(for-each (lambda (pr)
(let ([sym (car pr)]
[pref (cadr pr)])
(hash-table-put! marshalled sym pref)))
sexp)))))
(define read? #f)
;; get-disk-prefs : (-> A) -> (union A sexp) (define snapshot-grabbed? #f)
(define (get-disk-prefs fail) (define (get-prefs-snapshot)
(let/ec k (set! snapshot-grabbed? #t)
(let* ([filename (find-system-path 'pref-file)] (hash-table-map preferences cons))
[mod (and (file-exists? filename) (file-or-directory-modify-seconds filename))]
[sexp (get-preference main-preferences-symbol (λ () (k (fail))))])
sexp)))
;; install-stashed-preferences : sexp (listof symbol) -> void (define (restore-prefs-snapshot snapshot)
;; ensure that `prefs' is actuall a well-formed preferences (for-each (lambda (lst) (set (car lst) (cdr lst)))
;; table and installs them as the current preferences. snapshot))
(define (install-stashed-preferences prefs skip)
(for-each-pref-in-sexp
prefs
(λ (p marshalled)
(unless (memq p skip)
(let ([unmarshalled (unmarshall p (make-marshalled marshalled))])
(hash-table-put! preferences p unmarshalled)
(check-callbacks p unmarshalled))))))
(define (for-each-pref-in-file parse-pref preferences-filename)
(let/ec k
(let ([input (with-handlers
([(λ (x) #f) ;exn:fail?
(λ (exn)
(message-box
(string-constant error-reading-preferences)
(string-append
(string-constant error-reading-preferences)
(format "\n~a" (exn-message exn))))
(k #f))])
(call-with-input-file preferences-filename read 'text))])
(if (eof-object? input)
(void)
(for-each-pref-in-sexp input parse-pref)))))
;; for-each-pref-in-sexp : sexp (symbol TST -> void) -> void
(define (for-each-pref-in-sexp input parse-pref)
(let/ec k
(let loop ([input input])
(when (pair? input)
(let ([pre-pref (car input)])
(if (and (pair? pre-pref)
(pair? (cdr pre-pref))
(null? (cddr pre-pref)))
(parse-pref (car pre-pref) (cadr pre-pref))
(begin (read-err pre-pref (string-constant expected-list-of-length2))
(k #f))))
(loop (cdr input))))))
@ -448,14 +454,14 @@
(define can-close-dialog-callbacks null) (define can-close-dialog-callbacks null)
(define (make-preferences-dialog) (define (make-preferences-dialog)
(letrec ([stashed-prefs (get-disk-prefs/install (λ () null))] (letrec ([stashed-prefs (get-prefs-snapshot)]
[frame-stashed-prefs% [frame-stashed-prefs%
(class frame:basic% (class frame:basic%
(define/override (show on?) (define/override (show on?)
(when on? (when on?
(set! stashed-prefs (get-disk-prefs/install (λ () null)))) (set! stashed-prefs (get-prefs-snapshot)))
(super show on?)) (super show on?))
(super-instantiate ()))] (super-new))]
[frame [frame
(make-object frame-stashed-prefs% (make-object frame-stashed-prefs%
(string-constant preferences))] (string-constant preferences))]
@ -513,7 +519,7 @@
(hide-dialog)))] (hide-dialog)))]
[cancel-callback (λ (_1 _2) [cancel-callback (λ (_1 _2)
(hide-dialog) (hide-dialog)
(install-stashed-preferences stashed-prefs '()))]) (restore-prefs-snapshot stashed-prefs))])
(gui-utils:ok/cancel-buttons (gui-utils:ok/cancel-buttons
bottom-panel bottom-panel
ok-callback ok-callback