
* Another big chunk of v4-require-isms * Allow `#lang framework/keybinding-lang' for keybinding files * Move hierlist sources into "mrlib/hierlist", leave stub behind svn: r10689
529 lines
21 KiB
Scheme
529 lines
21 KiB
Scheme
|
|
(module bug-report mzscheme
|
|
(require string-constants
|
|
net/head
|
|
mred
|
|
framework
|
|
mzlib/class
|
|
mzlib/etc
|
|
mzlib/list
|
|
net/url
|
|
net/uri-codec
|
|
browser/htmltext
|
|
setup/dirs
|
|
"private/buginfo.ss")
|
|
|
|
(provide help-desk:report-bug)
|
|
|
|
(define bug-www-server "bugs.plt-scheme.org")
|
|
(define bug-www-server-port 80)
|
|
|
|
;; this one should be defined by help desk.
|
|
(define frame-mixin
|
|
(namespace-variable-value 'help-desk:frame-mixin #f (lambda () (lambda (x) x))))
|
|
|
|
(preferences:set-default 'drscheme:email "" string?)
|
|
(preferences:set-default 'drscheme:full-name "" string?)
|
|
|
|
(define bug-frame%
|
|
(class (frame-mixin (frame:standard-menus-mixin frame:basic%))
|
|
(init title)
|
|
|
|
;; a bunch of stuff we don't want
|
|
(define/override (file-menu:between-print-and-close menu) (void))
|
|
(define/override (edit-menu:between-find-and-preferences menu) (void))
|
|
(define/override (file-menu:create-open?) #f)
|
|
(define/override (file-menu:create-open-recent?) #f)
|
|
(define/override (file-menu:create-new?) #f)
|
|
(define/override (file-menu:create-save?) #f)
|
|
(define/override (file-menu:create-revert?) #f)
|
|
|
|
(field (ok-to-close? #f))
|
|
(public set-ok-to-close)
|
|
(define (set-ok-to-close ok?) (set! ok-to-close? #t))
|
|
(define/augment (can-close?)
|
|
(or ok-to-close?
|
|
(ask-yes-or-no (string-constant cancel-bug-report?)
|
|
(string-constant are-you-sure-cancel-bug-report?)
|
|
this)))
|
|
|
|
(super-make-object title)))
|
|
|
|
|
|
(define (help-desk:report-bug)
|
|
(define bug-frame (instantiate bug-frame% () (title (string-constant bug-report-form))))
|
|
(define single (new panel:single% (parent (send bug-frame get-area-container))))
|
|
(define outermost-panel (make-object vertical-panel% single))
|
|
|
|
(define response-panel (new vertical-panel% (parent single)))
|
|
(define response-text (new (html-text-mixin text%) (auto-wrap #t)))
|
|
(define response-ec (new editor-canvas% (parent response-panel) (editor response-text)))
|
|
(define response-button-panel (new horizontal-panel%
|
|
(stretchable-height #f)
|
|
(parent response-panel)
|
|
(alignment '(right center))))
|
|
(define cancel-kill-thread #f)
|
|
(define response-reset (new button%
|
|
(parent response-button-panel)
|
|
(enabled #f)
|
|
(label (string-constant dialog-back))
|
|
(callback
|
|
(lambda (x y)
|
|
(switch-to-compose-view)))))
|
|
(define response-abort (new button%
|
|
(parent response-button-panel)
|
|
(enabled #f)
|
|
(callback
|
|
(lambda (x y)
|
|
(kill-thread cancel-kill-thread)
|
|
(switch-to-compose-view)))
|
|
(label (string-constant abort))))
|
|
(define response-close (new button%
|
|
(parent response-button-panel)
|
|
(enabled #f)
|
|
(callback (lambda (x y) (cleanup-frame)))
|
|
(label (string-constant close))))
|
|
(define stupid-internal-define-syntax1
|
|
(new grow-box-spacer-pane% (parent response-button-panel)))
|
|
|
|
(define top-panel (make-object vertical-panel% outermost-panel))
|
|
|
|
(define (switch-to-response-view)
|
|
(send response-text lock #f)
|
|
(send response-text erase)
|
|
(render-html-to-text ; hack to get nice text in
|
|
(open-input-string
|
|
" <br><br><br><br><br><div align=\"center\"><h2><b>Submitting bug report...</b></h2></div>")
|
|
response-text #t #f)
|
|
(send response-text lock #t)
|
|
(send single active-child response-panel))
|
|
(define (switch-to-compose-view)
|
|
(send single active-child outermost-panel)
|
|
(send (if (string=? "" (preferences:get 'drscheme:full-name))
|
|
name
|
|
summary)
|
|
focus))
|
|
|
|
(define lps null)
|
|
|
|
; build/label : ((union string (list-of string))
|
|
; (area-container<%> -> item<%>)
|
|
; boolean
|
|
; area-container<%>
|
|
; -> item<%>)
|
|
; constructs and arranges the gui objects for the bug report form
|
|
; effect: updates lps with the new label panel, for future alignment
|
|
(define build/label
|
|
(opt-lambda (text make-item top? [stretch? #f] [top-panel top-panel] [vertical? #f])
|
|
(let*-values ([(hp) (make-object (if vertical?
|
|
vertical-panel%
|
|
horizontal-panel%)
|
|
top-panel)]
|
|
[(lp) (make-object vertical-panel% hp)]
|
|
[(ip) (make-object vertical-panel% hp)]
|
|
[(label/s) (if (string? text)
|
|
(make-object message% text lp)
|
|
(map (lambda (s)
|
|
(make-object message% s lp))
|
|
text))]
|
|
[(item) (make-item ip)])
|
|
(set! lps (cons lp lps))
|
|
(unless stretch?
|
|
(send hp stretchable-height #f)
|
|
(send lp stretchable-height #f)
|
|
(send ip stretchable-height #f))
|
|
(send lp stretchable-width #f)
|
|
(send lp stretchable-height #f)
|
|
(send lp set-alignment (if vertical? 'left 'right) (if top? 'top 'center))
|
|
(send ip set-alignment 'left 'top)
|
|
item)))
|
|
|
|
(define (align-labels)
|
|
(let ([width (apply max (map (lambda (x) (send (car (send x get-children)) min-width))
|
|
lps))])
|
|
(for-each (lambda (x) (send x min-width width)) lps)))
|
|
|
|
(define name
|
|
(build/label
|
|
(string-constant bug-report-field-name)
|
|
(lambda (panel)
|
|
(keymap:call/text-keymap-initializer
|
|
(lambda ()
|
|
(make-object text-field% #f panel
|
|
(lambda (text event)
|
|
(preferences:set 'drscheme:full-name (send text get-value)))
|
|
(preferences:get 'drscheme:full-name)))))
|
|
#f))
|
|
|
|
(define email
|
|
(build/label
|
|
(string-constant bug-report-field-email)
|
|
(lambda (panel)
|
|
(keymap:call/text-keymap-initializer
|
|
(lambda ()
|
|
(make-object text-field% #f panel
|
|
(lambda (text event)
|
|
(preferences:set 'drscheme:email (send text get-value)))
|
|
(preferences:get 'drscheme:email)))))
|
|
#f))
|
|
|
|
(define summary
|
|
(build/label
|
|
(string-constant bug-report-field-summary)
|
|
(lambda (panel)
|
|
(keymap:call/text-keymap-initializer
|
|
(lambda ()
|
|
(make-object text-field% #f panel void))))
|
|
#f))
|
|
|
|
(define severity
|
|
(build/label
|
|
(string-constant bug-report-field-severity)
|
|
(lambda (panel)
|
|
(make-object choice%
|
|
#f
|
|
(list "critical" "serious" "non-critical")
|
|
panel
|
|
void))
|
|
#f))
|
|
|
|
(define bug-classes '(("software bug" "sw-bug")
|
|
("documentation bug" "doc-bug")
|
|
("change request" "change-request")
|
|
("support" "support")))
|
|
|
|
(define bug-class
|
|
(build/label
|
|
(string-constant bug-report-field-class)
|
|
(lambda (panel)
|
|
(make-object choice%
|
|
#f
|
|
(map car bug-classes)
|
|
panel
|
|
void))
|
|
#f))
|
|
|
|
(define (translate-class class)
|
|
(cadr (assoc class bug-classes)))
|
|
|
|
(define (make-big-text label . args)
|
|
(let ([canvas
|
|
(apply
|
|
build/label
|
|
label
|
|
(lambda (panel)
|
|
(let* ([text (new (editor:standard-style-list-mixin
|
|
(editor:keymap-mixin
|
|
text:basic%)))]
|
|
[canvas (new canvas:basic%
|
|
(style '(hide-hscroll))
|
|
(parent panel)
|
|
(editor text))])
|
|
(send text set-paste-text-only #t)
|
|
(send text auto-wrap #t)
|
|
(send text set-max-undo-history 'forever)
|
|
(send text set-styles-fixed #t)
|
|
canvas))
|
|
#t
|
|
args)])
|
|
(send canvas min-width 500)
|
|
(send canvas min-height 130)
|
|
(send canvas get-editor)
|
|
(send canvas allow-tab-exit #t)
|
|
canvas))
|
|
|
|
(define description (make-big-text (string-constant bug-report-field-description) #t))
|
|
(define reproduce (make-big-text (list (string-constant bug-report-field-reproduce1)
|
|
(string-constant bug-report-field-reproduce2))
|
|
#t))
|
|
|
|
(define synthesized-dialog (make-object dialog% (string-constant bug-report-synthesized-information)))
|
|
(define synthesized-panel (make-object vertical-panel% synthesized-dialog))
|
|
(define synthesized-button-panel
|
|
(new horizontal-panel% [parent synthesized-dialog]
|
|
[alignment '(right center)] [stretchable-height #f]))
|
|
(define synthesized-ok-button (make-object button% (string-constant ok) synthesized-button-panel
|
|
(lambda (x y)
|
|
(send synthesized-dialog show #f))))
|
|
(define synthesized-info-shown? #t)
|
|
(define (show-synthesized-info)
|
|
(send synthesized-dialog show #t))
|
|
|
|
(define version
|
|
(build/label
|
|
(string-constant bug-report-field-version)
|
|
(lambda (panel)
|
|
(keymap:call/text-keymap-initializer
|
|
(lambda ()
|
|
(make-object text-field% #f panel void ""))))
|
|
#f
|
|
#f
|
|
synthesized-panel
|
|
#f))
|
|
(define environment
|
|
(build/label
|
|
(string-constant bug-report-field-environment)
|
|
(lambda (panel)
|
|
(keymap:call/text-keymap-initializer
|
|
(lambda ()
|
|
(make-object text-field% #f panel void ""))))
|
|
#f
|
|
#f
|
|
synthesized-panel
|
|
#f))
|
|
|
|
(define human-language
|
|
(build/label
|
|
(string-constant bug-report-field-human-language)
|
|
(lambda (panel)
|
|
(keymap:call/text-keymap-initializer
|
|
(lambda ()
|
|
(make-object text-field% #f panel void ""))))
|
|
#f
|
|
#f
|
|
synthesized-panel))
|
|
|
|
(define memory-use
|
|
(build/label
|
|
(string-constant bug-report-field-memory-use)
|
|
(lambda (panel)
|
|
(keymap:call/text-keymap-initializer
|
|
(lambda ()
|
|
(make-object text-field% #f panel void ""))))
|
|
#f
|
|
#f
|
|
synthesized-panel))
|
|
|
|
(define collections
|
|
(make-big-text
|
|
(string-constant bug-report-field-collections)
|
|
#t
|
|
synthesized-panel))
|
|
|
|
(define extras
|
|
(map (lambda (bri)
|
|
(let ([label (bri-label bri)])
|
|
(cons
|
|
label
|
|
(build/label
|
|
label
|
|
(lambda (panel)
|
|
(let ([field
|
|
(keymap:call/text-keymap-initializer
|
|
(lambda ()
|
|
(make-object text-field% #f panel void "")))])
|
|
(send field set-value (bri-value bri))
|
|
field))
|
|
#f
|
|
#f
|
|
synthesized-panel))))
|
|
(get-bug-report-infos)))
|
|
|
|
(define button-panel
|
|
(new horizontal-panel% [parent outermost-panel]
|
|
[alignment '(right center)] [stretchable-height #f]))
|
|
(define synthesized-button (make-object button%
|
|
(string-constant bug-report-show-synthesized-info)
|
|
button-panel (lambda x (show-synthesized-info))))
|
|
(define _spacer (new horizontal-pane% (parent button-panel)))
|
|
(define cancel-button (make-object button% (string-constant cancel) button-panel (lambda x (cancel))))
|
|
(define ok-button (make-object button% (string-constant bug-report-submit) button-panel (lambda x (ok))))
|
|
(define _grow-box
|
|
(new grow-box-spacer-pane% [parent button-panel]))
|
|
|
|
(define (get-query)
|
|
(list (cons 'help-desk "true")
|
|
(cons 'replyto (preferences:get 'drscheme:email))
|
|
(cons 'originator (preferences:get 'drscheme:full-name))
|
|
(cons 'subject (send summary get-value))
|
|
(cons 'severity (send severity get-string-selection))
|
|
(cons 'class (translate-class (send bug-class get-string-selection)))
|
|
(cons 'release (send version get-value))
|
|
(cons 'description (apply string-append (map (lambda (x) (string-append x "\n"))
|
|
(get-strings description))))
|
|
(cons 'how-to-repeat (apply string-append
|
|
(map (lambda (x) (string-append x "\n"))
|
|
(get-strings reproduce))))
|
|
(cons 'platform (get-environment))))
|
|
|
|
(define (get-environment)
|
|
(string-append (send environment get-value)
|
|
"\n"
|
|
(format "Human Language: ~a\n" (send human-language get-value))
|
|
(format "(current-memory-use) ~a\n" (send memory-use get-value))
|
|
"\nCollections:\n"
|
|
(format "~a" (send (send collections get-editor) get-text))
|
|
"\n"
|
|
(apply
|
|
string-append
|
|
(map (lambda (extra)
|
|
(format "~a: ~a\n"
|
|
(car extra)
|
|
(send (cdr extra) get-value)))
|
|
extras))))
|
|
|
|
; send-bug-report : (-> void)
|
|
;; initiates sending the bug report and switches the GUI's mode
|
|
(define (send-bug-report)
|
|
(letrec ([query (get-query)]
|
|
[url
|
|
(string->url (format "http://~a:~a/cgi-bin/bug-report"
|
|
bug-www-server
|
|
bug-www-server-port))]
|
|
[post-data
|
|
(parameterize ([current-alist-separator-mode 'amp])
|
|
(string->bytes/utf-8 (alist->form-urlencoded query)))]
|
|
[http-thread
|
|
(parameterize ([current-custodian (make-custodian)])
|
|
(thread
|
|
(lambda ()
|
|
(with-handlers ([(lambda (x) (exn:break? x))
|
|
(lambda (x) (void))]
|
|
[(lambda (x) (not (exn:break? x)))
|
|
(lambda (x)
|
|
(queue-callback
|
|
(lambda ()
|
|
(switch-to-compose-view)
|
|
(message-box
|
|
(string-constant error-sending-bug-report)
|
|
(format (string-constant error-sending-bug-report-expln)
|
|
(if (exn? x)
|
|
(exn-message x)
|
|
(format "~s" x)))))))])
|
|
(parameterize ([current-alist-separator-mode 'amp])
|
|
(call/input-url
|
|
url
|
|
(case-lambda
|
|
[(x) (post-pure-port x post-data)]
|
|
[(x y) (post-pure-port x post-data y)])
|
|
(lambda (port)
|
|
(send response-text lock #f)
|
|
(send response-text erase)
|
|
(render-html-to-text port response-text #t #f)
|
|
(send response-text lock #t))))
|
|
(queue-callback
|
|
(lambda ()
|
|
(send response-abort enable #f)
|
|
(send response-reset enable #t)
|
|
(send response-close enable #t)
|
|
(set! cancel-kill-thread #f)
|
|
(send bug-frame set-ok-to-close #t)
|
|
(send response-close focus)))))))])
|
|
(set! cancel-kill-thread http-thread)
|
|
(send response-abort enable #t)
|
|
(switch-to-response-view)))
|
|
|
|
(define (get-strings canvas)
|
|
(let ([t (send canvas get-editor)])
|
|
(let loop ([n 0])
|
|
(cond
|
|
[(> n (send t last-paragraph)) null]
|
|
[else (cons (send t get-text
|
|
(send t paragraph-start-position n)
|
|
(send t paragraph-end-position n))
|
|
(loop (+ n 1)))]))))
|
|
|
|
(define (sanity-checking)
|
|
(let ([no-value?
|
|
(lambda (f)
|
|
(cond
|
|
[(is-a? f editor-canvas%)
|
|
(= 0 (send (send f get-editor) last-position))]
|
|
[else (string=? "" (send f get-value))]))])
|
|
(let/ec done-checking
|
|
(for-each
|
|
(lambda (field field-name)
|
|
(when (no-value? field)
|
|
(message-box (string-constant illegal-bug-report)
|
|
(format (string-constant pls-fill-in-field) field-name))
|
|
(done-checking #f)))
|
|
(list name summary)
|
|
(list (string-constant bug-report-field-name)
|
|
(string-constant bug-report-field-summary)))
|
|
|
|
(when (and (no-value? description)
|
|
(no-value? reproduce))
|
|
(message-box (string-constant illegal-bug-report)
|
|
(string-constant pls-fill-in-either-description-or-reproduce))
|
|
(done-checking #f))
|
|
|
|
(unless (regexp-match #rx"@" (or (preferences:get 'drscheme:email) ""))
|
|
(message-box (string-constant illegal-bug-report)
|
|
(string-constant malformed-email-address))
|
|
(done-checking #f))
|
|
(done-checking #t))))
|
|
|
|
(define (ok)
|
|
(when (sanity-checking)
|
|
(send-bug-report)))
|
|
|
|
(define (cancel)
|
|
(cleanup-frame))
|
|
|
|
(define (cleanup-frame)
|
|
(send bug-frame close))
|
|
|
|
(define (directories-contents dirs)
|
|
(map (lambda (d)
|
|
(cons (path->string d)
|
|
(if (directory-exists? d)
|
|
(map path->string (directory-list d))
|
|
'(non-existent-path))))
|
|
dirs))
|
|
|
|
(define (split-by-directories dirs split-by)
|
|
(let ([res (append (map list (map path->string split-by)) '((*)))]
|
|
[dirs (map path->string dirs)])
|
|
(for-each
|
|
(lambda (d)
|
|
(let* ([l (string-length d)]
|
|
[x (assf
|
|
(lambda (d2)
|
|
(or (eq? d2 '*)
|
|
(let ([l2 (string-length d2)])
|
|
(and (< l2 l) (equal? d2 (substring d 0 l2))
|
|
(member (string-ref d l2) '(#\/ #\\))))))
|
|
res)])
|
|
(append x (list (if (string? (car x))
|
|
(substring d (add1 (string-length (car x))))
|
|
d)))))
|
|
dirs)
|
|
(filter (lambda (x) (pair? (cdr x))) res)))
|
|
|
|
(send response-ec allow-tab-exit #t)
|
|
|
|
(send severity set-selection 1)
|
|
(send version set-value (format "~a" (version:version)))
|
|
|
|
(send environment set-value
|
|
(format "~a ~s (~a) (get-display-depth) = ~a"
|
|
(system-type)
|
|
(system-type 'machine)
|
|
(system-library-subpath)
|
|
(get-display-depth)))
|
|
|
|
(send (send collections get-editor)
|
|
insert
|
|
(format "~s" (directories-contents (get-collects-search-dirs))))
|
|
|
|
(send human-language set-value (format "~a" (this-language)))
|
|
(send memory-use set-value (format "~a" (current-memory-use)))
|
|
|
|
(send (send collections get-editor) auto-wrap #t)
|
|
|
|
;; Currently, the help-menu is left empty
|
|
(frame:remove-empty-menus bug-frame)
|
|
|
|
(align-labels)
|
|
(switch-to-compose-view)
|
|
|
|
(send bug-frame show #t))
|
|
|
|
(define (ask-yes-or-no title msg parent)
|
|
(gui-utils:get-choice msg
|
|
(string-constant yes)
|
|
(string-constant no)
|
|
title
|
|
#f
|
|
parent)))
|