Changeset 1009

Show
Ignore:
Timestamp:
07/31/08 04:33:49 (1 month ago)
Author:
MaierMan
Message:
  • #826: Download Fails when size is unknown
  • #827: SessionManager? should load asynchronously
  • Various speed improvements
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/chrome/content/dta/manager.js

    r993 r1009  
    8686Components.utils.import('resource://dta/prompts.jsm', Prompts); 
    8787 
     88var TEXT_PAUSED; 
     89var TEXT_QUEUED; 
     90var TEXT_COMPLETE; 
     91var TEXT_CANCELED; 
     92 
    8893var Dialog = { 
    8994        _observes: [ 
     
    116121        totalbytes: 0, 
    117122        init: function D_init() { 
     123                 
     124                TEXT_PAUSED = _('paused'); 
     125                TEXT_QUEUED = _('queued'); 
     126                TEXT_COMPLETE = _('complete'); 
     127                TEXT_CANCELED = _('canceled'); 
     128                 
    118129                Tree.init($("downloads")); 
    119130                SessionManager.init(); 
     
    136147                         
    137148                document.getElementById("dtaHelp").hidden = !("openHelp" in window); 
     149        }, 
    138150         
    139          
     151        start: function() { 
    140152                if ("arguments" in window) { 
    141153                        startDownloads(window.arguments[0], window.arguments[1]); 
    142154                } 
    143155 
    144                 Tree.invalidate(); 
    145156                this._initialized = true; 
    146157                for (let d in Tree.all) { 
     
    152163                new Timer("Dialog.refreshWritten();", 100, true, true); 
    153164                new Timer("Dialog.saveRunning();", 10000, true); 
    154         }, 
     165                 
     166                $('mainstack').selectedIndex++;          
     167        }, 
     168         
    155169        observe: function D_observe(subject, topic, data) { 
    156170                if (topic == 'quit-application-requested') { 
     
    177191                        let sum = 0; 
    178192                        const now = Utils.getTimestamp(); 
    179                         this._running.forEach( 
    180                                 function(i) { 
    181                                         let d = i.d; 
    182                                          
    183                                         let advanced = (d.partialSize - i.lastBytes); 
    184                                         sum += advanced; 
    185                                          
    186                                         let elapsed = (now - i.lastTime) / 1000;                                         
    187                                         if (elapsed < 1) { 
    188                                                 return; 
    189                                         }                                                
    190                                          
    191                                         let speed = Math.round(advanced / elapsed); 
    192                                          
    193                                         i.lastBytes = d.partialSize; 
    194                                         i.lastTime = now;                                
    195  
    196                                         // Refresh item speed 
    197                                         d.speeds.push(speed > 0 ? speed : 0); 
    198                                         if (d.speeds.length > SPEED_COUNT) { 
    199                                                 d.speeds.shift(); 
     193                        for each (i in this._running) { 
     194                                let d = i.d; 
     195                                 
     196                                let advanced = (d.partialSize - i.lastBytes); 
     197                                sum += advanced; 
     198                                 
     199                                let elapsed = (now - i.lastTime) / 1000;                                         
     200                                if (elapsed < 1) { 
     201                                        return; 
     202                                }                                                
     203                                 
     204                                let speed = Math.round(advanced / elapsed); 
     205                                 
     206                                i.lastBytes = d.partialSize; 
     207                                i.lastTime = now;                                
     208 
     209                                // Refresh item speed 
     210                                d.speeds.push(speed > 0 ? speed : 0); 
     211                                if (d.speeds.length > SPEED_COUNT) { 
     212                                        d.speeds.shift(); 
     213                                } 
     214                                i.lastBytes = d.partialSize; 
     215                                i.lastTime = now; 
     216                                 
     217                                speed = 0; 
     218                                d.speeds.forEach( 
     219                                        function(s) { 
     220                                                speed += s; 
    200221                                        } 
    201                                         i.lastBytes = d.partialSize; 
    202                                         i.lastTime = now; 
    203                                          
    204                                         speed = 0; 
    205                                         d.speeds.forEach( 
    206                                                 function(s) { 
    207                                                         speed += s; 
    208                                                 } 
    209                                         ); 
    210                                         speed /= d.speeds.length; 
    211                                          
    212                                         // Calculate estimated time                                      
    213                                         if (advanced != 0 && d.totalSize > 0) { 
    214                                                 let remaining = Math.ceil((d.totalSize - d.partialSize) / speed); 
    215                                                 if (!isFinite(remaining)) { 
    216                                                         d.status = _("unknown"); 
    217                                                 } 
    218                                                 else { 
    219                                                         d.status = Utils.formatTimeDelta(remaining); 
    220                                                 } 
     222                                ); 
     223                                speed /= d.speeds.length; 
     224                                 
     225                                // Calculate estimated time                                      
     226                                if (advanced != 0 && d.totalSize > 0) { 
     227                                        let remaining = Math.ceil((d.totalSize - d.partialSize) / speed); 
     228                                        if (!isFinite(remaining)) { 
     229                                                d.status = _("unknown"); 
    221230                                        } 
    222                                         d.speed = Utils.formatBytes(speed) + "/s"; 
    223                                 } 
    224                         ); 
     231                                        else { 
     232                                                d.status = Utils.formatTimeDelta(remaining); 
     233                                        } 
     234                                } 
     235                                d.speed = Utils.formatBytes(speed) + "/s"; 
     236                        } 
    225237                        let elapsed = (now - this._lastTime) / 1000; 
    226238                        this._lastTime = now; 
     
    304316                        } 
    305317 
    306                         if (!this.offline) {                                     
     318                        if (!this.offline) { 
     319                                // XXX Improve                                   
    307320                                if (Prefs.autoRetryInterval) { 
    308321                                        for (let d in Tree.all) { 
     
    403416                try { 
    404417                        // check if there is something running or scheduled 
    405                         if (this.startNext() || Tree.some(function(d) { return d.is(FINISHING, RUNNING, QUEUED); } )) { 
     418                        if (this.startNext() || Tree.some(function(d) { return d.isOf(FINISHING, RUNNING, QUEUED); } )) { 
    406419                                return; 
    407420                        } 
     
    435448        }, 
    436449        _canClose: function D__canClose() { 
    437                 if (Tree.some(function(d) { return d.started && !d.resumable && d.is(RUNNING); })) { 
     450                if (Tree.some(function(d) { return d.started && !d.resumable && d.isOf(RUNNING); })) { 
    438451                        var rv = Prompts.confirmYN( 
    439452                                window, 
     
    465478                Tree.updateAll( 
    466479                        function(d) { 
    467                                 if (d.is(RUNNING, QUEUED)) { 
     480                                if (d.isOf(RUNNING, QUEUED)) { 
    468481                                        // enumerate all running chunks 
    469482                                        d.chunks.forEach( 
     
    667680        fileName: null, 
    668681        acceptRanges: 'bytes', 
    669         contentlength: 0, 
     682        contentLength: 0, 
    670683        time: null, 
    671684 
     
    703716 
    704717                                case 'content-length': 
    705                                         this.contentlength = Number(aValue); 
     718                                        let contentLength = new Number(aValue); 
     719                                        if (contentLength > 0 && !isNaN(contentLength)) { 
     720                                                this.ccontentLength = Math.floor(contentLength);  
     721                                        } 
    706722                                break; 
    707723 
    708724                                case 'content-range': { 
    709                                         let cl = new Number(aValue.split('/').pop()); 
    710                                         if (cl > 0) { 
    711                                                 this.contentlength = cl
     725                                        let contentLength = new Number(aValue.split('/').pop()); 
     726                                        if (contentLength > 0) { 
     727                                                this.contentLength = Math.floor(contentLength)
    712728                                        } 
    713729                                } 
     
    892908        }, 
    893909        set state(nv) { 
    894                 if (this._state != nv) { 
    895                         if (this._state == RUNNING) { 
    896                                 // remove ourself from inprogresslist 
    897                                 Dialog.wasStopped(this); 
    898                         } 
    899                         this._state = nv; 
    900                         this.invalidate(); 
    901                         Tree.refreshTools(); 
    902                         Dialog.signal(this); 
    903                 } 
     910                if (this._state == nv) { 
     911                        return nv; 
     912                } 
     913                if (this._state == RUNNING) { 
     914                        // remove ourself from inprogresslist 
     915                        Dialog.wasStopped(this); 
     916                } 
     917                this._state = nv; 
     918                this.invalidate(); 
     919                Dialog.signal(this); 
     920                Tree.refreshTools(); 
     921                return nv; 
    904922        }, 
    905923         
     
    911929        }, 
    912930        set fileName(nv) { 
     931                if (this._fileName == nv) { 
     932                        return nv; 
     933                } 
    913934                this._fileName = nv; 
    914935                this.rebuildDestination(); 
     
    975996        }, 
    976997        set conflicts(nv) { 
    977                 if (typeof(nv) != 'number') { 
    978                         return this._conflicts
     998                if (this._conflicts == nv) { 
     999                        return nv
    9791000                } 
    9801001                this._conflicts = nv; 
     
    10141035         *Takes one or more state indicators and returns if this download is in state of any of them 
    10151036         */ 
    1016         is: function QI_is() { 
    1017                 let state = this.state; 
     1037        is: function QI_is(state) { 
     1038                return this._state == state;  
     1039        }, 
     1040        isOf: function QI_isOf() { 
     1041                let state = this._state; 
    10181042                for (let i = 0, e = arguments.length; i < e; ++i) { 
    10191043                        if (state == arguments[i]) { 
     
    10211045                        } 
    10221046                } 
    1023                 return false; 
     1047                return false;           
    10241048        }, 
    10251049         
     
    10661090        get totalSize() { return this._totalSize; }, 
    10671091        set totalSize(nv) { 
    1068                 this._totalSize = nv; 
     1092                if (this._totalSize == nv) { 
     1093                        return nv; 
     1094                } 
     1095                if (nv >= 0 && !isNaN(nv)) { 
     1096                        this._totalSize = Math.floor(nv); 
     1097                } 
    10691098                this.invalidate(); 
    10701099                return this._totalSize; 
     
    11551184        _status : '', 
    11561185        get status() { 
    1157                 if (Dialog.offline && this.is(QUEUED, PAUSED)) { 
     1186                if (Dialog.offline && this.isOf(QUEUED, PAUSED)) { 
    11581187                        return _('offline'); 
    11591188                } 
     
    13501379                this.activeChunks = 0; 
    13511380                this.state = COMPLETE; 
    1352                 this.status = _("complete")
     1381                this.status = TEXT_COMPLETE
    13531382        }, 
    13541383        rebuildDestination: function QI_rebuildDestination() { 
     
    15501579                this._autoRetryTime = 0; 
    15511580                this.state = QUEUED; 
    1552                 this.status = _('queued')
     1581                this.status = TEXT_QUEUED
    15531582        }, 
    15541583        resumeDownload: function QI_resumeDownload() { 
     
    16431672        dumpScoreboard: function QI_dumpScoreboard() { 
    16441673                let scoreboard = ''; 
    1645                 let len = String(this.totalSize).length;  
     1674                let len = this.totalSize.toString().length; 
    16461675                this.chunks.forEach( 
    16471676                        function(c,i) { 
     
    16981727                } 
    16991728                // Store this so we can later resume. 
    1700                 if (!this.is(CANCELED, COMPLETE) && this.partialSize) { 
     1729                if (!this.isOf(CANCELED, COMPLETE) && this.partialSize) { 
    17011730                        e.tmpFile = this.tmpFile.path; 
    17021731                } 
     
    17151744                e.chunks = []; 
    17161745 
    1717                 if (this.is(RUNNING, PAUSED, QUEUED) && this.resumable) { 
    1718                         this.chunks.forEach( 
    1719                                 function(c) { 
    1720                                         e.chunks.push({start: c.start, end: c.end, written: c.safeBytes}); 
    1721                                 } 
    1722                         ); 
     1746                if (this.isOf(RUNNING, PAUSED, QUEUED) && this.resumable) { 
     1747                        for each (let c in this.chunks) { 
     1748                                e.chunks.push({start: c.start, end: c.end, written: c.safeBytes}); 
     1749                        } 
    17231750                } 
    17241751                return Serializer.encode(e); 
     
    22422269                } 
    22432270 
    2244                 if (visitor.contentlength > 0) { 
    2245                         d.totalSize = visitor.contentlength; 
    2246                 } else { 
     2271                if (visitor.contentLength > 0) { 
     2272                        d.totalSize = visitor.contentLength; 
     2273                } 
     2274                else { 
    22472275                        d.totalSize = 0; 
    22482276                } 
     
    24592487                } 
    24602488 
    2461                 if (!d.is(PAUSED, CANCELED, FINISHING) && d.chunks.length == 1 && d.chunks[0] == c) { 
     2489                if (!d.isOf(PAUSED, CANCELED, FINISHING) && d.chunks.length == 1 && d.chunks[0] == c) { 
    24622490                        if (d.resumable) { 
    24632491                                d.pause(); 
     
    24742502                        return;                  
    24752503                } 
    2476                 if (!d.is(PAUSED, CANCELED)) { 
     2504                if (!d.isOf(PAUSED, CANCELED)) { 
    24772505                        d.resumeDownload(); 
    24782506                } 
     
    26092637                qi.state = start ? QUEUED : PAUSED; 
    26102638                if (qi.is(QUEUED)) { 
    2611                         qi.status = _('queued')
     2639                        qi.status = TEXT_QUEUED
    26122640                } 
    26132641                else { 
    2614                         qi.status = _('paused')
     2642                        qi.status = TEXT_PAUSED
    26152643                } 
    26162644                qi.save();               
  • trunk/chrome/content/dta/manager.xul

    r968 r1009  
    120120        </popupset>      
    121121         
    122         <vbox flex="1"> 
    123                 <toolbox chromedir="&locale.dir;"> 
    124                   <toolbar id="tools"> 
    125                         <spacer/> 
    126                         <toolbarbutton label="&tooladd.label;" id="tooladd" onclick="window.openDialog('chrome://dta/content/dta/addurl.xul','_blank','chrome, centerscreen, dialog=no, dependent=yes');" tooltiptext="&tooladd.tooltip;" /> 
    127                         <spacer class="visible" /> 
    128                         <toolbarbutton label="&resume.label;" id="toolplay" onclick="Tree.resume();"/> 
    129                         <toolbarbutton label="&pause.label;" id="toolpause" onclick="Tree.pause();"/> 
    130                         <toolbarbutton label="&cancel.label;" id="toolcancel" onclick="Tree.cancel();"/> 
    131                         <spacer class="visible" /> 
    132                         <toolbarbutton label="&movetop.label;" id="toolmovetop" onclick="Tree.top();" /> 
    133                         <toolbarbutton label="&moveup.label;" id="toolmoveup" onclick="Tree.up();"/> 
    134                         <toolbarbutton label="&movedown.label;" id="toolmovedown" onclick="Tree.down();"/> 
    135                         <toolbarbutton label="&movebottom.label;" id="toolmovebottom" onclick="Tree.bottom();"  /> 
    136                         <spacer flex="1" /> 
    137                         <spacer chromedir="&locale.dir;" id="tooldonate" onclick="DTA_Mediator.openTab('http://www.downthemall.net/howto/donate/');" tooltiptext="&tooldonate.tooltiptext;" /> 
    138                   </toolbar> 
    139                 </toolbox> 
    140  
    141                 <tree 
    142                         id="downloads" 
    143                         flex="1" 
    144                         hidecolumnpicker="false" 
    145                         context="popup" 
    146                         seltype="multiple" 
    147                         enableColumnDrag="true" 
    148                         style="margin:0px;" 
    149                         ondblclick="FileHandling.openFile();" 
    150                         onselect="Tree.selectionChanged();" 
    151                         onmousemove="Tree.hovering(event);" 
    152                         ondraggesture="if (event.originalTarget.localName == 'treechildren') nsDragAndDrop.startDrag(event, Tree);" 
    153                         chromedir="&locale.dir;" 
    154                 > 
    155                         <treecols> 
    156                                 <treecol id="task" label="&task.label;" ordinal="1" flex="30" crop="center" persist="width ordinal hidden"/> 
    157                                 <splitter class="tree-splitter"/> 
    158                                 <treecol id="pct" label="&pct.label;" ordinal="2" type="progressmeter" flex="20" persist="width ordinal hidden"/> 
    159                                 <splitter class="tree-splitter"/> 
    160                                 <treecol id="per" label="&per.label;" ordinal="3" flex="4" persist="width ordinal hidden"/> 
    161                                 <splitter class="tree-splitter"/> 
    162                                 <treecol id="dim" label="&dim.label;" ordinal="4" flex="10" persist="width ordinal hidden"/> 
    163                                 <splitter class="tree-splitter"/> 
    164                                 <treecol id="status" label="&time.label;" ordinal="5" flex="7" persist="width ordinal hidden"/> 
    165                                 <splitter class="tree-splitter"/> 
    166                                 <treecol id="speed" label="&speed.label;" ordinal="6" flex="7" persist="width ordinal hidden"/> 
    167                                 <splitter class="tree-splitter"/> 
    168                                 <treecol id="parts" label="&parts.label;" ordinal="7" flex="4" hidden="true" persist="width ordinal hidden" style="text-align:center;" /> 
    169                                 <splitter class="tree-splitter"/> 
    170                                 <treecol id="mask" label="&mask.label;" ordinal="8" hidden="true" crop="left" flex="8" persist="width ordinal hidden" /> 
    171                                 <splitter class="tree-splitter"/> 
    172                                 <treecol id="path" label="&path.label;" ordinal="9" hidden="true" crop="center" flex="10" persist="width ordinal hidden" /> 
    173                                 <splitter class="tree-splitter"/> 
    174                                 <treecol id="hash" label="&hash.label;" ordinal="10" hidden="true" flex="6" persist="width ordinal hidden"/> 
    175                         </treecols> 
    176                         <treechildren tooltip="tooltip"> 
    177                         </treechildren> 
    178                 </tree> 
    179  
    180         </vbox> 
     122        <deck flex="1" id="mainstack"> 
     123                <hbox align="center"> 
     124                        <label flex="1" align="center" id="loading"/> 
     125                </hbox> 
     126                <vbox flex="1">          
     127                        <toolbox chromedir="&locale.dir;"> 
     128                          <toolbar id="tools"> 
     129                                <spacer/> 
     130                                <toolbarbutton label="&tooladd.label;" id="tooladd" onclick="window.openDialog('chrome://dta/content/dta/addurl.xul','_blank','chrome, centerscreen, dialog=no, dependent=yes');" tooltiptext="&tooladd.tooltip;" /> 
     131                                <spacer class="visible" /> 
     132                                <toolbarbutton label="&resume.label;" id="toolplay" onclick="Tree.resume();"/> 
     133                                <toolbarbutton label="&pause.label;" id="toolpause" onclick="Tree.pause();"/> 
     134                                <toolbarbutton label="&cancel.label;" id="toolcancel" onclick="Tree.cancel();"/> 
     135                                <spacer class="visible" /> 
     136                                <toolbarbutton label="&movetop.label;" id="toolmovetop" onclick="Tree.top();" /> 
     137                                <toolbarbutton label="&moveup.label;" id="toolmoveup" onclick="Tree.up();"/> 
     138                                <toolbarbutton label="&movedown.label;" id="toolmovedown" onclick="Tree.down();"/> 
     139                                <toolbarbutton label="&movebottom.label;" id="toolmovebottom" onclick="Tree.bottom();"  /> 
     140                                <spacer flex="1" /> 
     141                                <spacer chromedir="&locale.dir;" id="tooldonate" onclick="DTA_Mediator.openTab('http://www.downthemall.net/howto/donate/');" tooltiptext="&tooldonate.tooltiptext;" /> 
     142                          </toolbar> 
     143                        </toolbox> 
     144                         
     145                                <tree 
     146                                        id="downloads" 
     147                                        flex="1" 
     148                                        hidecolumnpicker="false" 
     149                                        context="popup" 
     150                                        seltype="multiple" 
     151                                        enableColumnDrag="true" 
     152                                        style="margin:0px;" 
     153                                        ondblclick="FileHandling.openFile();" 
     154                                        onselect="Tree.selectionChanged();" 
     155                                        onmousemove="Tree.hovering(event);" 
     156                                        ondraggesture="if (event.originalTarget.localName == 'treechildren') nsDragAndDrop.startDrag(event, Tree);" 
     157                                        chromedir="&locale.dir;" 
     158                                > 
     159                                        <treecols> 
     160                                                <treecol id="task" label="&task.label;" ordinal="1" flex="30" crop="center" persist="width ordinal hidden"/> 
     161                                                <splitter class="tree-splitter"/> 
     162                                                <treecol id="pct" label="&pct.label;" ordinal="2" type="progressmeter" flex="20" persist="width ordinal hidden"/> 
     163                                                <splitter class="tree-splitter"/> 
     164                                                <treecol id="per" label="&per.label;" ordinal="3" flex="4" persist="width ordinal hidden"/> 
     165                                                <splitter class="tree-splitter"/> 
     166                                                <treecol id="dim" label="&dim.label;" ordinal="4" flex="10" persist="width ordinal hidden"/> 
     167                                                <splitter class="tree-splitter"/> 
     168                                                <treecol id="status" label="&time.label;" ordinal="5" flex="7" persist="width ordinal hidden"/> 
     169                                                <splitter class="tree-splitter"/> 
     170                                                <treecol id="speed" label="&speed.label;" ordinal="6" flex="7" persist="width ordinal hidden"/> 
     171                                                <splitter class="tree-splitter"/> 
     172                                                <treecol id="parts" label="&parts.label;" ordinal="7" flex="4" hidden="true" persist="width ordinal hidden" style="text-align:center;" /> 
     173                                                <splitter class="tree-splitter"/> 
     174                                                <treecol id="mask" label="&mask.label;" ordinal="8" hidden="true" crop="left" flex="8" persist="width ordinal hidden" /> 
     175                                                <splitter class="tree-splitter"/> 
     176                                                <treecol id="path" label="&path.label;" ordinal="9" hidden="true" crop="center" flex="10" persist="width ordinal hidden" /> 
     177                                                <splitter class="tree-splitter"/> 
     178                                                <treecol id="hash" label="&hash.label;" ordinal="10" hidden="true" flex="6" persist="width ordinal hidden"/> 
     179                                        </treecols> 
     180                                        <treechildren tooltip="tooltip"> 
     181                                        </treechildren> 
     182                                </tree>                  
     183                </vbox> 
     184        </deck> 
    181185 
    182186        <statusbar id="footer" chromedir="&locale.dir;"> 
  • trunk/chrome/content/dta/manager/info.js

    r970 r1009  
    5959                                        $('sourcePage')._value = $("sourcePage").value = d.referrer.spec; 
    6060                                } 
    61                                 if (!d.is(FINISHING, COMPLETE)) { 
     61                                if (!d.isOf(FINISHING, COMPLETE)) { 
    6262                                        $('sourcePage').removeAttribute('readonly'); 
    6363                                } 
     
    9292                                $('canvasGrid').hidden = true; 
    9393                        }                                
    94                         if (downloads.every(function(d) { return d.is(COMPLETE, FINISHING); })) { 
     94                        if (downloads.every(function(d) { return d.isOf(COMPLETE, FINISHING); })) { 
    9595                                for each (let e in $('directory', 'renaming', 'mask', 'browsedir')) { 
    9696                                        e.setAttribute('readonly', 'true'); 
     
    148148                 
    149149                for each (let d in t) { 
    150                         if (d.is(COMPLETE, FINISHING)) { 
     150                        if (d.isOf(COMPLETE, FINISHING)) { 
    151151                                return; 
    152152                        } 
  • trunk/chrome/content/dta/manager/sessionmanager.js

    r976 r1009  
    4141const DB_VERSION = 1; 
    4242 
     43Components.utils.import('resource://dta/cothread.jsm'); 
     44 
    4345var SessionManager = { 
    4446        init: function() { 
     
    7678        shutdown: function() { 
    7779                try { 
    78                         ['_addStmt', '_saveStmt', '_savePosStmt', '_delStmt'].forEach( 
    79                                 function(e) { 
    80                                         try { this[e].finalize(); } catch (ex) { /* no op */ } 
    81                                 }, 
    82                                 this 
    83                         ); 
     80                        for each (let e in ['_addStmt', '_saveStmt', '_savePosStmt', '_delStmt']) { 
     81                                try { 
     82                                        this[e].finalize(); 
     83                                        delete this[e]; 
     84                                } 
     85                                catch (ex) { 
     86                                        // no-op 
     87                                } 
     88                        } 
     89                        this._con.executeSimpleSQL('VACUUM'); 
     90                        try { 
     91                                this._con.close(); 
     92                                delete this._con; 
     93                        } 
     94                        catch (ex) { 
     95                                Debug.log("Cannot close!", ex); 
     96                        } 
    8497                } 
    8598                catch (ex) { 
    8699                        Debug.log("SessionManager::shutdown", ex); 
    87                 } 
    88                 this._con.executeSimpleSQL('VACUUM'); 
    89                 if ('close' in this._con) { 
    90                         try { 
    91                                 this._con.close(); 
    92                         } 
    93                         catch (ex) { 
    94                                 // 
    95                         } 
    96100                } 
    97101        }, 
     
    154158 
    155159        load: function() { 
    156                 return Tree.update(this._load, this); 
    157         }, 
    158         _load: function() { 
    159  
    160                 var stmt = this._con.createStatement('SELECT uuid, item FROM queue ORDER BY pos'); 
     160                this._loaded = false; 
     161                 
     162                let stmt = this._con.createStatement('SELECT COUNT(*) FROM queue'); 
     163                stmt.executeStep(); 
     164                let count = stmt.getInt64(0); 
     165                stmt.finalize(); 
     166                let loading = $('loading'); 
     167 
     168                stmt = this._con.createStatement('SELECT uuid, item FROM queue ORDER BY pos'); 
     169                this.beginUpdate(); 
    161170                Tree.beginUpdate(); 
    162                 this.beginUpdate(); 
    163                 while (stmt.executeStep()) { 
    164                         try { 
    165                                 let dbId = stmt.getInt64(0); 
    166                                 let down = Serializer.decode(stmt.getUTF8String(1)); 
    167                                 let get = function(attr) { 
    168                                         if (attr in down) { 
    169                                                 return down[attr]; 
    170                                         } 
    171                                         return null; 
    172                                 } 
    173  
    174                                 let d = new QueueItem(); 
    175                                 d.dbId = dbId; 
    176                                 d.urlManager = new UrlManager(down.urlManager); 
    177                                 d.numIstance = get("numIstance"); 
    178  
    179                                 let referrer = get('referrer'); 
    180                                 if (referrer) { 
    181                                         try { 
    182                                                 d.referrer = referrer.toURL(); 
    183                                         } 
    184                                         catch (ex) { 
    185                                                 // We might have been fed with about:blank or other crap. so ignore. 
    186                                         } 
    187                                 } 
    188                          
    189                                 // only access the setter of the last so that we don't generate stuff trice. 
    190                                 d._pathName = get('pathName'); 
    191                                 d._description = get('description'); 
    192                                 d._mask = get('mask'); 
    193                                 d.fileName = get('fileName'); 
     171                new CoThread( 
     172                        function(idx) { 
     173                                loading.value = _('loading', [++idx, count]); 
     174                                // Are we done? 
     175                                if (!stmt || !stmt.executeStep()) { 
     176                                        this.endUpdate(); 
     177                                        Tree.endUpdate(); 
     178                                        Tree.invalidate(); 
     179                                        Dialog.start(); 
     180                                        return false; 
     181                                } 
    194182                                 
    195                                 let tmpFile = get('tmpFile'); 
    196                                 if (tmpFile) { 
    197                                         try { 
    198                                                 tmpFile = new FileFactory(tmpFile); 
    199                                                 if (tmpFile.exists()) { 
    200                                                         d._tmpFile = tmpFile; 
    201                                                 } 
    202                                                 else { 
    203                                                         // Download partfile is gone! 
    204                                                         // XXX find appropriate error message! 
    205                                                         d.fail(_("accesserror"), _("permissions") + " " + _("destpath") + ". " + _("checkperm"), _("accesserror")); 
    206                                                 } 
    207                                         } 
    208                                         catch (ex) { 
    209                                                 Debug.log("tried to construct with invalid tmpFile", ex); 
    210                                                 d.cancel(); 
    211                                         } 
    212                                 }                                
    213  
    214                                 d.startDate = new Date(get("startDate")); 
    215                                 d.visitors = new VisitorManager(down.visitors); 
    216  
    217                                 [ 
    218                                         'contentType', 
    219                                         'conflicts', 
    220                                         'postData', 
    221                                         'destinationName', 
    222                                         'resumable', 
    223                                         'totalSize', 
    224                                         'compression', 
    225                                         'fromMetalink', 
    226