1###############################################################################
2###############################################################################
3#####                            Ventana.tcl
4###############################################################################
5##### Creates the window which will provide some information to the user
6##### while a file is being downloaded.
7###############################################################################
8##### Copyright 1999-2008 Andr�s Garc�a Garc�a - fandom@telefonica.net
9##### Distributed under the terms of the GPL v2
10###############################################################################
11
12namespace eval Ventana {
13
14source [file join $dirGetleft(scripts) Rizo.tcl]
15
16set family [font configure TkTextFont -family]
17set size   [font configure TkTextFont -size]
18
19catch {font create labelFont -family $family -size $size -weight bold}
20
21###############################################################################
22# DefineButtonImages
23#    Reads the images needed to create the 'downloading' window.
24###############################################################################
25proc DefineButtonImages {} {
26    global   dirGetleft getleftState
27    variable images
28
29    set ext $getleftState(imgExt)
30
31    set images(url)    [image create photo                             \
32            -file [file join "$dirGetleft(icons)" html.$ext]]
33    set images(folder) [image create photo                             \
34            -file [file join "$dirGetleft(icons)" folder.$ext]]
35    set images(files)  [image create photo                             \
36            -file [file join "$dirGetleft(icons)" files.$ext]]
37    set images(clock)  [image create photo                             \
38            -file [file join "$dirGetleft(icons)" clock.$ext]]
39
40    set images(pause)  [image create photo                             \
41            -file  [file join "$dirGetleft(icons)" pauses.$ext]]
42    set images(resume) [image create photo                             \
43            -file  [file join "$dirGetleft(icons)" resumes.$ext]]
44    set images(stop)   [image create photo                             \
45            -file  [file join "$dirGetleft(icons)" stops.$ext]]
46    set images(conf)   [image create photo                             \
47            -file  [file join "$dirGetleft(icons)" confs.$ext]]
48
49    return
50}
51
52###############################################################################
53# ChangeProgressBar
54#     During a download we need a determinate progress bar, but while
55#     connecting or processing a file an indeterminate one is better.
56#
57# Parameter:
58#     action: 'start' or 'stop'.
59###############################################################################
60proc  ChangeProgressBar {action} {
61    variable window
62
63    if {$action=="start"} {
64        $window(bar) configure -mode indeterminate
65        $window(bar) start
66    } else {
67        $window(bar) stop
68        set Ventana::Rizo::curlReport(percentage) 0
69        $window(bar) configure -mode determinate
70    }
71
72    return
73}
74
75###############################################################################
76# ShowResumeButton
77#    When the user pauses the download, the 'Pause' menu button is
78#    subtituted by the 'Resume' button
79###############################################################################
80proc ShowResumeButton {} {
81    variable window
82    variable menus
83    global   getleftState
84
85    $window(pause) configure -state disabled
86    place $window(resume) -in $window(pause)
87    $menus(stop) entryconfigure 3 -state disabled
88
89    return
90}
91
92###############################################################################
93# HideResumeButton
94#    And when the download is resumed it is hidden again.
95###############################################################################
96proc HideResumeButton {} {
97    variable window
98    variable menus
99
100    place forget $window(resume)
101    $window(pause) configure -state normal
102
103    $menus(stop) entryconfigure 3 -state normal
104
105    return
106}
107
108###############################################################################
109# PauseDownloading
110#    Pauses the downloading according to the menu entries.
111#
112# Parameter
113#    which: either 'file' or 'page'
114###############################################################################
115proc Pause {which} {
116    global getleftOptions labelTitles labelMessages
117    variable window
118
119    set windowState [wm state $window(top)]
120    if {$windowState=="iconic"} {
121        wm deiconify $window(top)
122    }
123
124    ShowResumeButton
125
126    if {$which=="file"} {
127        tkwait variable getleftOptions(pauseFile)
128    } else {
129        tkwait variable getleftOptions(pausePage)
130    }
131
132    return
133}
134
135###############################################################################
136# CancelDownloading
137#    This procedure is invoked from the downloading window when you click on
138#    the 'cancel' button or you want to close the window
139#
140# Parameter:
141#    parent: The window over which the asking dialog will appear.
142#    skip: if skip is 'skip' the current file will be skipped and the next one
143#    will begin to be downloaded. If there is no parameter, the downloading
144#    will be stopped.
145#
146# Returns
147#    '0' if we are not going to stop.
148#    '1' if we are.
149###############################################################################
150proc CancelDownloading {parent {skip {} }} {
151    global labelTitles labelMessages
152    global getleftState getleftOptions
153    global ::Ventana::Rizo::curlReport
154    variable waitingPid
155    variable window
156
157    if {$getleftState(delayedDown)==0} {
158        set what [Dialogos::Dialogo $parent.error -type yesno -icon question \
159                -title $labelTitles(confirm)                                 \
160                -message $labelMessages(stopDownload)]
161        if {$what=="no"} {
162            return 0
163        }
164        if {[info exists window(bar)]} {
165            $window(bar) configure -value 0
166        }
167        set Ventana::Rizo::curlReport(left) ""
168    }
169    catch {after cancel $waitingPid}
170    catch {Rizo::Lector stopNow}
171
172    set getleftOptions(cancelDown)     1
173    set Ventana::Rizo::curlReport(end) 1
174    set getleftState(autoDown)         0
175
176    if {($skip=="")||($getleftState(filesChosen)==0)} {
177        set getleftOptions(stopFile)  1
178        set getleftState(downloading) 0
179        catch {wm withdraw $window(top)}
180    }
181
182    incr curlReport(nextFile)
183
184    if {$getleftState(waiting)==1} {
185        set getleftState(waiting) 0
186    }
187    return 1
188}
189
190###############################################################################
191# TrimString
192#    Trims the given string so that if it is longer than the available space
193#    the middle of it gets substituted with '...', and puts the resulting
194#    string in the given label.
195#
196# Par�metros
197#    cadena: string to trim.
198#    labelPath: the label in which the string is going to be shown
199###############################################################################
200proc TrimString {cadena labelPath} {
201
202    set font     labelFont
203    set varName  [$labelPath cget -textvariable]
204
205    upvar #0 $varName textVariable
206
207    set textVariable $cadena
208    set labelLength  [expr {[winfo width $labelPath]-5}]
209    set strLength    [font measure $font -displayof $labelPath $cadena]
210
211    if {$labelLength<=$strLength} {
212        set strChars [string length $cadena]
213        set middle   [expr {round($strChars/2)-2}]
214        set primer   [string range $cadena 0 $middle]
215        set segun    [string range $cadena [expr {$middle+1}] end]
216        set textVariable ""
217        append textVariable $primer "..." $segun
218        while {[font measure $font -displayof $labelPath $textVariable]>$labelLength} {
219            regsub {(.)(\.\.\.)(.)} $textVariable {...} textVariable
220        }
221        BalloonHelp::set_balloon $labelPath $cadena
222    } else {
223        BalloonHelp::delete_balloon $labelPath
224    }
225    return
226}
227
228###############################################################################
229# FileStrings
230#    Controls the strings that will be put in the downloading window, to
231#    show the name and directory of the file being processed or downloaded
232#
233# Parameter:
234#    url to be downloaded or preprocessed
235###############################################################################
236proc FileStrings {url} {
237    global directories labelMessages
238    variable window
239
240    set fileName  [::Commands::UrlToFile $url $directories(base)]
241    set parsedUrl [HtmlParser::ParseUrl $url]
242    set domain    [string tolower [lindex $parsedUrl 1]]
243    set domainTmp [string map {: ""} $domain]
244    if {[regexp -nocase "(?:$directories(base)/$domainTmp/)(.*)" \
245            $fileName nada tmp]==0} {
246        set tmp ""
247    }
248
249    if {![regexp {(.*)(?:/)(.*)} $tmp nada tmpDir tmpFile]} {
250        set tmpDir ""
251        set tmpFile $tmp
252    }
253
254    TrimString $domain  $window(url)
255    TrimString $tmpDir  $window(dir)
256    TrimString $tmpFile $window(file)
257
258    update
259
260    return
261}
262
263###############################################################################
264# DownloadWindow
265#    Creates the window, in which some info about the downloading will be
266#    displayed.
267###############################################################################
268proc DownloadWindow {} {
269    global labelButtons labelDialogs labelMenus dirGetleft
270    global getleftOptions getleftState
271    variable window
272    variable menus
273    variable images
274
275    DefineButtonImages
276
277    set win [toplevel .bajando]
278    wm resizable $win 0 0
279    wm maxsize $win 299 200
280
281    if {$getleftState(os)=="mac"} {
282        set labelWidth  27
283    } else {
284        set labelWidth 35
285    }
286
287    set marco     [ttk::frame $win.marco -class ExternalFrame]
288    set marco_in  [ttk::frame $marco.marco_interno]
289    set marco_url [ttk::frame $marco_in.url]
290    set marco_dir [ttk::frame $marco_in.dir]
291    set marco_fil [ttk::frame $marco_in.fil]
292    set marco_que [ttk::frame $marco_in.que]
293    set marco_bar [ttk::frame $marco_in.bar]
294    set exButtons [ttk::frame $win.exButtons -class ExternalFrame]
295    set botones   [ttk::frame $exButtons.botones]
296
297    set etq_url   [ttk::label $marco_url.etq_url  -image $images(url)]
298    set etq_dir   [ttk::label $marco_dir.etq_dir  -image $images(folder)]
299    set etq_file  [ttk::label $marco_fil.etq_file -image $images(files)]
300    set etq_que   [ttk::label $marco_que.etq_que  -image $images(clock)]
301
302    BalloonHelp::set_balloon $etq_url  $labelDialogs(url)
303    BalloonHelp::set_balloon $etq_dir  $labelDialogs(dir)
304    BalloonHelp::set_balloon $etq_file $labelDialogs(file)
305    BalloonHelp::set_balloon $etq_que  $labelDialogs(left)
306
307    set etq_url2  [ttk::label $marco_url.etq_url2  -width $labelWidth -anchor w   \
308            -relief sunken -textvariable Ventana::window(labelUrl) -font labelFont]
309    set etq_dir2  [ttk::label $marco_dir.etq_dir2  -width $labelWidth -anchor w   \
310            -textvariable Ventana::window(labelDir)       -font labelFont]
311    set etq_file2 [ttk::label $marco_fil.etq_file2 -width $labelWidth -anchor w   \
312            -textvariable Ventana::window(labelFile)      -font labelFont]
313    set etq_que2  [ttk::label $marco_que.etq_que2  -width $labelWidth -anchor w   \
314            -textvariable Ventana::Rizo::curlReport(left) -font labelFont]
315
316    set progressBar [ttk::progressbar $marco_bar.progress -orient horizontal \
317            -length 275 -mode determinate                                    \
318            -variable Ventana::Rizo::curlReport(percentage)]
319
320    set window(top)  $win
321    set window(url)  $etq_url2
322    set window(dir)  $etq_dir2
323    set window(file) $etq_file2
324    set window(left) $etq_que2
325    set window(bar)  $progressBar
326
327    set config   [ttk::button     $botones.config -image $images(conf)          \
328            -command "mainWin::UrlListChangeOptions $window(top)" -style Toolbutton]
329    set pause    [ttk::menubutton $botones.pause -menu $botones.pause.menu      \
330            -image $images(pause) -style Toolbutton]
331    set stop     [ttk::menubutton $botones.stop  -menu $botones.stop.menu       \
332            -image $images(stop) -style Toolbutton]
333    set resume   [ttk::button     $botones.resume -image $images(resume)        \
334            -command "::Ventana::ResumeDownloading" -style Toolbutton]
335
336    ::BalloonHelp::set_balloon $config $labelDialogs(options)
337    ::BalloonHelp::set_balloon $pause  $labelDialogs(pause)
338    ::BalloonHelp::set_balloon $stop   $labelDialogs(stop)
339    ::BalloonHelp::set_balloon $resume $labelDialogs(start)
340
341    set menus(pause) [menu $pause.menu -tearoff 0 -fg black -bg $getleftOptions(menus) \
342            -postcommand "
343                BalloonHelp::kill_balloon
344    "]
345    $menus(pause) add command -label $labelMenus(stopNow) -command {
346            Ventana::PauseDownloading now
347    }
348    $menus(pause) add check -variable getleftOptions(pausePage)              \
349            -onvalue 1 -offvalue 0 -label $labelMenus(stopPage)
350    $menus(pause) add check -variable getleftOptions(pauseFile)              \
351            -onvalue 1 -offvalue 0 -label $labelMenus(stopFile)
352
353    set menus(stop) [menu $stop.menu -tearoff 0 -fg black -bg $getleftOptions(menus) \
354            -postcommand "
355                    BalloonHelp::kill_balloon
356    "]
357    $menus(stop) add command -label $labelMenus(stopNow) -command {
358        if {$getleftState(delayedDown)==1} Delay::DelayedCancelDelay
359        ::Ventana::CancelDownloading $Ventana::window(top)
360    }
361    $menus(stop) add check -variable getleftOptions(stopPage)                \
362            -onvalue 1 -offvalue 0 -label $labelMenus(stopPage)              \
363            -command {
364                set getleftState(autoDown) 0
365                if {$getleftState(delayedDown)==1} Delay::DelayedCancelDelay
366            }
367    $menus(stop) add check -variable getleftOptions(stopFile)                \
368            -onvalue 1 -offvalue 0 -label $labelMenus(stopFile)              \
369            -command {
370                set getleftState(autoDown) 0
371                if {$getleftState(delayedDown)==1} Delay::DelayedCancelDelay
372            }
373    $menus(stop) add command -label $labelButtons(skip)                      \
374            -command "::Ventana::CancelDownloading $Ventana::window(top) skip"
375
376    set window(cancel) $stop
377    set window(pause)  $pause
378    set window(resume) $resume
379
380    pack $marco     -ipady 5
381    pack $exButtons -fill x
382    pack $botones   -fill x -side right -padx 7
383    pack $marco_in  -padx 10 -side bottom
384    pack $marco_url $marco_in $marco_dir $marco_fil $marco_que $marco_bar \
385            -fill x
386    pack $etq_url   $etq_url2  -side left -pady 2 -padx 2
387    pack $etq_dir   $etq_dir2  -side left -pady 2 -padx 2
388    pack $etq_file  $etq_file2 -side left -pady 2 -padx 2
389    pack $etq_que   $etq_que2  -side left -pady 2 -padx 2
390    pack $progressBar
391    pack $stop $pause $config -side right -padx 3 -pady 5
392
393    wm protocol $win WM_DELETE_WINDOW "::Ventana::CancelDownloading $win"
394
395    return
396}
397
398###############################################################################
399# ShowWindow
400#   If needed, maps the downloading window, and sets its title bar
401#
402# Parameter
403#   which: either 'head', 'down', 'process' or 'wait' depending on the action
404#          taking place.
405###############################################################################
406proc ShowWindow {which} {
407    global   labelTitles labelButtons getleftState
408    variable window
409
410    if {$::getleftState(downloading)==0} {
411        if {$::DEBUG==1} {
412            Dialogos::Dialogo .error -title Error -icon error -type ok       \
413                    -message "Pringamos en ShowWindow: $which"
414        }
415        return
416    }
417
418    if {![winfo exists .bajando]} {
419        DownloadWindow
420    } else {
421        set state [wm state $window(top)]
422        if {$state=="withdrawn"} {
423            wm deiconify $window(top)
424        }
425    }
426
427    switch -exact $which {
428        head {
429            wm title $window(top) $labelTitles(connect)
430            ChangeProgressBar start
431        }
432        down {
433            wm title $window(top) $labelTitles(download)
434            ChangeProgressBar stop
435        }
436        process {
437            wm title $window(top) $labelTitles(process)
438            ChangeProgressBar start
439        }
440        wait {
441            StartWaiting 10
442        }
443    }
444
445    update
446
447    return
448}
449
450###############################################################################
451# FileDownloading
452#   Creates a nice window to show info about how the downloading goes
453#
454# Parameters:
455#    fichero: file in which the link will be saved.
456#    enlace:  file url.
457#    madre:   referer page for the link
458###############################################################################
459proc FileDownloading {fichero enlace madre} {
460    global   getleftState directories
461    global   labelTitles
462    global   Ventana::Rizo::meta
463    global   Ventana::Rizo::curlReport
464    variable window
465    variable file
466    variable link
467    variable mother
468    variable action
469
470    if {$getleftState(downloading)==0} {
471        return
472    }
473
474    set file   $fichero
475    set action body
476
477    ShowWindow down
478    FileStrings $enlace
479
480    set curlReport(end)   0
481    set curlReport(long)  1
482    set curlReport(pause) 0
483
484    if {([file exists $fichero])&&($meta(versionServer)>=1.1)} {
485        set size [file size $fichero]
486        if {($size>$meta(totalBytes))&&($meta(totalBytes)!=0)} {
487            file delete $fichero
488        } elseif {($size==$meta(totalBytes))&&($meta(totalBytes)!=0)} {
489            after 1000 "set ::Ventana::Rizo::curlReport(nextFile) 1"
490            return
491        }
492        Ventana::Rizo::DataRequest $fichero $enlace $madre 1
493    } else {
494        Ventana::Rizo::DataRequest $fichero $enlace $madre
495    }
496    CheckDownload
497
498    return
499}
500
501###############################################################################
502# HeadDownloading
503#    Gets the headers of the url from the server.
504#
505# Parameters:
506#    enlace: url to download
507#    madre:  referer page of the link
508###############################################################################
509proc HeadDownloading {enlace madre} {
510    global siteUrl getleftState
511    variable link
512    variable mother
513    variable action
514    variable window
515
516    set link   $enlace
517    set mother $madre
518    set action head
519
520    ShowWindow head
521    FileStrings $enlace
522
523    HideResumeButton
524
525    if {[regexp {^ftp://} $enlace]} {
526        set ::Ventana::Rizo::meta(content)       "nada"
527        set ::Ventana::Rizo::meta(totalBytes)    0
528        set ::Ventana::Rizo::meta(versionServer) 1.1
529        set ::Ventana::Rizo::meta(relocate)      ""
530        set ::Ventana::Rizo::curlError           0
531        set ::Ventana::Rizo::errorMessage        ""
532        return
533    }
534
535    set Ventana::Rizo::curlReport(end) 0
536    Ventana::Rizo::HeadRequest $enlace $madre
537    tkwait variable Ventana::Rizo::curlReport(end)
538
539    return
540}
541
542###############################################################################
543# PauseDownloading
544#    Takes control when you click on the 'Pause' button.
545#
546# Parameter:
547#    when: 'now' when we click on the 'Now' menu entry, usuful to pause
548#    the downloading while a file is being process for links.
549###############################################################################
550proc PauseDownloading {{when ""}} {
551    global labelButtons getleftOptions
552    variable window
553
554    if {$when=="now"} {
555        set getleftOptions(pauseNow) 1
556    }
557    set Ventana::Rizo::curlReport(pause) 1
558    set ::Ventana::Rizo::curlReport(left) ""
559    ChangeProgressBar stop
560    catch {Rizo::Lector stopNow}
561    ShowResumeButton
562
563    return
564}
565
566###############################################################################
567# ResumeDownloading
568#    Takes control when you click on the 'Resume' button
569###############################################################################
570proc ResumeDownloading {} {
571    global labelButtons getleftOptions
572    variable window
573    variable file
574    variable link
575    variable mother
576    variable action
577
578    HideResumeButton
579
580    if {($getleftOptions(pauseFile)==1)||($getleftOptions(pausePage)==1)} {
581        set getleftOptions(pauseFile) 0
582        set getleftOptions(pausePage) 0
583        return
584    }
585    set getleftOptions(pauseNow)              0
586    set Ventana::Rizo::curlReport(pause)      0
587    set Ventana::Rizo::curlReport(percentage) 0
588
589    if {$action=="body"} {
590        Ventana::Rizo::DataRequest "$file" "$link" "$mother" 1
591        Ventana::CheckDownload
592    } else {
593        HeadDownloading "$link" "$mother"
594    }
595    return
596}
597
598###############################################################################
599# StartWaiting
600#    This procedure is invoked when a timeout has ocurred, to wait before
601#    trying again.
602#
603# Parameter
604#    seconds: The seconds yet to wait
605###############################################################################
606proc StartWaiting {seconds} {
607    global   getleftState labelTitles
608    variable window
609    variable waitingPid
610
611    if {$seconds==0} {
612        InterruptWaiting
613        return
614    }
615
616    wm title $window(top) "$labelTitles(waiting) $seconds"
617
618    ShowResumeButton
619    $window(resume) configure -command ::Ventana::InterruptWaiting
620
621    set waitingPid [after 1000 ::Ventana::StartWaiting [expr $seconds -1]]
622
623    return
624}
625
626###############################################################################
627# InterruptWaiting
628#    While waiting to retry after a timeout, if you click on resume
629#    this procedure will be invoked.
630###############################################################################
631proc InterruptWaiting {} {
632    global   getleftState
633    variable window
634    variable waitingPid
635
636    after cancel $waitingPid
637
638    HideResumeButton
639    $window(resume) configure -command ::Ventana::ResumeDownloading
640
641    set getleftState(waiting) 0
642
643    return
644}
645
646###############################################################################
647# CheckDownload
648#    The procedure get invoked from time to time in order to check whether
649#    the transfer has ended, with success or not.
650###############################################################################
651proc CheckDownload {} {
652    global Ventana::Rizo::curlReport
653    global Ventana::Rizo::curlError
654    global Ventana::Rizo::meta
655    global labelDialogs downOptions getleftOptions
656    variable file
657    variable link
658    variable mother
659    variable window
660
661    if {[string match $curlReport(percentage) ""]} return
662    if {$getleftOptions(pauseNow)==1} {
663        return
664    }
665    if {($curlReport(end)==0) && ($curlReport(stop)!=1) \
666            && ($curlReport(pause)==0)} {
667        set afterId [after 750 Ventana::CheckDownload]
668    } else {
669        set curlReport(left) ""
670        if {($::DEBUG==1)&&($curlError!=0)} {
671            puts "Error $curlError en $file"
672        }
673        if {($curlError==18)||($curlError==28)} {
674            getLog::FileLogEnter $labelDialogs(fileIncom) \
675                    "$link" "$mother"
676            if {($downOptions(resume)==1)&&($curlReport(stop)!=1)} {
677                $window(bar) stop
678                set ::Ventana::Rizo::curlReport(percentage) 0
679                if {$curlError==18} {
680                    FileDownloading "$file" "$link" "$mother"
681                } else {
682                    incr curlReport(nextFile)
683                }
684                return
685            }
686        }
687        if {$curlError==0} {
688            $window(bar) configure -value 100
689            update
690        }
691        after 75
692        $window(bar)  configure -value 0
693        set ::Ventana::Rizo::curlReport(percentage) 0
694        $window(dir)  configure -text ""
695        $window(file) configure -text ""
696        incr curlReport(nextFile)
697    }
698    return
699}
700}
701