#lang racket/base
(require string-constants
net/head
racket/gui/base
framework
racket/class
racket/port
net/url
net/uri-codec
browser/htmltext
"private/bug-report-controls.rkt"
"private/buginfo.rkt"
"private/save-bug-report.rkt")
(provide help-desk:report-bug
(struct-out brinfo)
saved-bug-report-titles/ids
discard-all-saved-bug-reports)
(define (bug-server-url path)
(string->url (string-append "http://bugs.racket-lang.org/" path)))
(define bug-report-url (bug-server-url "bug-report.cgi"))
(define captcha-text-url (bug-server-url "captcha-text"))
(define (get-captcha-text)
(let* ([s (port->string (get-pure-port captcha-text-url))]
[s (regexp-replace #px"^\\s+" s "")]
[s (regexp-replace #px"\\s+$" s "")]
[s (if (<= (string-length s) 200)
s
(substring s 0 200))])
(and ((string-length s) . > . 0) s)))
(preferences:set-default 'drracket:email "" string? #:aliases '(drscheme:email))
(preferences:set-default 'drracket:full-name "" string? #:aliases '(drscheme:full-name))
(define open-frames '())
(define (discard-all-saved-bug-reports)
(discard-all-except
(λ (id) (ormap (λ (frame) (equal? (send frame get-bug-id) id))
open-frames))))
(define (help-desk:report-bug [this-bug-id #f] #:frame-mixin [frame-mixin values])
(cond
[this-bug-id
(let loop ([open-frames open-frames])
(cond
[(null? open-frames)
(report-bug/new-frame this-bug-id frame-mixin)]
[else
(let ([open-frame (car open-frames)])
(if (= (send open-frame get-bug-id) this-bug-id)
(send open-frame show #t)
(loop (cdr open-frames))))]))]
[else
(report-bug/new-frame this-bug-id frame-mixin)]))
(define (report-bug/new-frame this-bug-id frame-mixin)
(define bug-frame%
(class (frame-mixin (frame:standard-menus-mixin frame:basic%))
(init title)
(init-field bug-id)
(define/public (get-bug-id) (and editing? bug-id))
(define editing? #t)
(define/public (no-longer-editing) (set! editing? #f))
(define close-box-clicked? #t)
(define/public (set-close-box-not-clicked) (set! close-box-clicked? #f))
(define/augment (can-close?)
(cond
[close-box-clicked?
(cond
[(eq? (send single active-child) finished-panel)
#t]
[(empty-bug-report?)
(no-more-saving)
(unsave-bug-report bug-id)
(set! editing? #f)]
[else
(define user-choice
(message-box/custom (string-constant cancel-bug-report?)
(string-constant do-you-want-to-discard-or-save-this-bug-report)
(string-constant save)
(string-constant cancel)
(string-constant discard)
this
'(default=1)
1))
(case user-choice
[(1) #t] ;; saving happens automatically
[(2) #f]
[(3)
(no-more-saving)
(unsave-bug-report bug-id)
(set! editing? #f)
#t])])]
[else #t]))
(define/augment (on-close)
(inner (void) on-close)
(set! open-frames (remq this open-frames)))
(super-make-object title)
(set! open-frames (cons this open-frames))
;; 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)))
(define init-bug-report (if this-bug-id
(lookup-bug-report this-bug-id)
(register-new-bug-id)))
(define bug-frame (new bug-frame%
[bug-id (saved-report-id init-bug-report)]
[title (string-constant bug-report-form)]))
(define single (new panel:single% (parent (send bug-frame get-area-container))))
(define compose-panel (make-object vertical-panel% single))
(define cancel-kill-cust #f)
(define-values (compose-view-focus get-query sanity-checking no-more-saving empty-bug-report?)
(add-bug-report-controls compose-panel
init-bug-report
(λ () (ok))
(λ () (cancel))
(λ () (close-and-save))))
(define pending-panel (new vertical-panel% (parent single)))
(define pending-text (new html-text% (auto-wrap #t)))
(define (reset-pending-text)
(with-pending-text
(λ ()
(send pending-text erase)
(render-html-to-text ; hack to get nice text in
(open-input-string
"
\n\nERROR:\n"to-render"\n\n")]) (render-error (open-input-string str)))] [(exn? to-render) (define sp (open-output-string)) (fprintf sp "~a\n" (exn-message to-render)) (for ([x (in-list (continuation-mark-set->context (exn-continuation-marks to-render)))]) (fprintf sp " ~s\n" x)) (render-error (get-output-string sp))] [(or (input-port? to-render) (not to-render)) (queue-callback (λ () (when to-render (with-pending-text (λ () (render-html-to-text to-render pending-text #t #f)))) (send pending-back enable #t) (send pending-abort enable #f)))] [else (error 'render-error "internal error")])) (thread (λ () (sync (handle-evt exn-chan render-error) (handle-evt (thread-dead-evt worker-thread) (λ (_) (render-error "reporting process killed"))) (handle-evt response-chan (λ (finished-text) (queue-callback (λ () (switch-to-finished-view finished-text)))))))) (init-pending-view)) (define (ok) (when (sanity-checking) (send-bug-report))) (define (cancel) (when (or (empty-bug-report?) (ask-yes-or-no (string-constant cancel-bug-report?) (string-constant are-you-sure-cancel-bug-report?) bug-frame)) (unsave-bug-report (saved-report-id init-bug-report)) (send bug-frame set-close-box-not-clicked) (send bug-frame close))) (define (close-and-save) (send bug-frame set-close-box-not-clicked) (send bug-frame close)) ;; Currently, the help-menu is left empty (frame:remove-empty-menus bug-frame) (switch-to-compose-view) (send bug-frame show #t)) (define html-text% (text:hide-caret/selection-mixin (html-text-mixin text:basic%))) (define (ask-yes-or-no title msg parent) (gui-utils:get-choice msg (string-constant yes) (string-constant no) title #f parent))