~ubuntu-branches/ubuntu/precise/boinc/precise

« back to all changes in this revision

Viewing changes to clientgui/ViewTransfers.cpp

Tags: 6.12.8+dfsg-1
* New upstream release.
* Simplified debian/rules

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Berkeley Open Infrastructure for Network Computing
2
 
// http://boinc.berkeley.edu
3
 
// Copyright (C) 2005 University of California
4
 
//
5
 
// This is free software; you can redistribute it and/or
6
 
// modify it under the terms of the GNU Lesser General Public
7
 
// License as published by the Free Software Foundation;
8
 
// either version 2.1 of the License, or (at your option) any later version.
9
 
//
10
 
// This software is distributed in the hope that it will be useful,
11
 
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
 
// See the GNU Lesser General Public License for more details.
14
 
//
15
 
// To view the GNU Lesser General Public License visit
16
 
// http://www.gnu.org/copyleft/lesser.html
17
 
// or write to the Free Software Foundation, Inc.,
18
 
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19
 
 
20
 
#if defined(__GNUG__) && !defined(__APPLE__)
21
 
#pragma implementation "ViewTransfers.h"
22
 
#endif
23
 
 
24
 
#include "stdwx.h"
25
 
#include "BOINCGUIApp.h"
26
 
#include "BOINCBaseFrame.h"
27
 
#include "MainDocument.h"
28
 
#include "AdvancedFrame.h"
29
 
#include "BOINCTaskCtrl.h"
30
 
#include "BOINCListCtrl.h"
31
 
#include "ViewTransfers.h"
32
 
#include "Events.h"
33
 
#include "error_numbers.h"
34
 
 
35
 
 
36
 
#include "res/xfer.xpm"
37
 
 
38
 
 
39
 
#define COLUMN_PROJECT              0
40
 
#define COLUMN_FILE                 1
41
 
#define COLUMN_PROGRESS             2
42
 
#define COLUMN_SIZE                 3
43
 
#define COLUMN_TIME                 4
44
 
#define COLUMN_SPEED                5
45
 
#define COLUMN_STATUS               6
46
 
 
47
 
// buttons in the "tasks" area
48
 
#define BTN_RETRY       0
49
 
#define BTN_ABORT       1
50
 
 
51
 
 
52
 
CTransfer::CTransfer() {
53
 
}
54
 
 
55
 
 
56
 
CTransfer::~CTransfer() {
57
 
    m_strProjectName.Clear();
58
 
    m_strFileName.Clear();
59
 
    m_strProgress.Clear();
60
 
    m_strSize.Clear();
61
 
    m_strTime.Clear();
62
 
    m_strSpeed.Clear();
63
 
    m_strStatus.Clear();
64
 
}
65
 
 
66
 
 
67
 
IMPLEMENT_DYNAMIC_CLASS(CViewTransfers, CBOINCBaseView)
68
 
 
69
 
BEGIN_EVENT_TABLE (CViewTransfers, CBOINCBaseView)
70
 
    EVT_BUTTON(ID_TASK_TRANSFERS_RETRYNOW, CViewTransfers::OnTransfersRetryNow)
71
 
    EVT_BUTTON(ID_TASK_TRANSFERS_ABORT, CViewTransfers::OnTransfersAbort)
72
 
    EVT_LIST_ITEM_SELECTED(ID_LIST_TRANSFERSVIEW, CViewTransfers::OnListSelected)
73
 
    EVT_LIST_ITEM_DESELECTED(ID_LIST_TRANSFERSVIEW, CViewTransfers::OnListDeselected)
74
 
END_EVENT_TABLE ()
75
 
 
76
 
 
77
 
CViewTransfers::CViewTransfers()
78
 
{}
79
 
 
80
 
 
81
 
CViewTransfers::CViewTransfers(wxNotebook* pNotebook) :
82
 
    CBOINCBaseView(pNotebook, ID_TASK_TRANSFERSVIEW, DEFAULT_TASK_FLAGS, ID_LIST_TRANSFERSVIEW, DEFAULT_LIST_SINGLE_SEL_FLAGS)
83
 
{
84
 
        CTaskItemGroup* pGroup = NULL;
85
 
        CTaskItem*      pItem = NULL;
86
 
 
87
 
    wxASSERT(m_pTaskPane);
88
 
    wxASSERT(m_pListPane);
89
 
 
90
 
 
91
 
    //
92
 
    // Setup View
93
 
    //
94
 
        pGroup = new CTaskItemGroup( _("Commands") );
95
 
        m_TaskGroups.push_back( pGroup );
96
 
 
97
 
        pItem = new CTaskItem(
98
 
        _("Retry Now"),
99
 
        _("Click 'Retry now' to transfer the file now"),
100
 
        ID_TASK_TRANSFERS_RETRYNOW 
101
 
    );
102
 
    pGroup->m_Tasks.push_back( pItem );
103
 
 
104
 
        pItem = new CTaskItem(
105
 
        _("Abort Transfer"),
106
 
        _("Click 'Abort transfer' to delete the file from the transfer queue. "
107
 
          "This will prevent you from being granted credit for this result."),
108
 
        ID_TASK_TRANSFERS_ABORT 
109
 
    );
110
 
    pGroup->m_Tasks.push_back( pItem );
111
 
 
112
 
 
113
 
    // Create Task Pane Items
114
 
    m_pTaskPane->UpdateControls();
115
 
 
116
 
    // Create List Pane Items
117
 
    m_pListPane->InsertColumn(COLUMN_PROJECT, _("Project"), wxLIST_FORMAT_LEFT, 125);
118
 
    m_pListPane->InsertColumn(COLUMN_FILE, _("File"), wxLIST_FORMAT_LEFT, 205);
119
 
    m_pListPane->InsertColumn(COLUMN_PROGRESS, _("Progress"), wxLIST_FORMAT_CENTRE, 60);
120
 
    m_pListPane->InsertColumn(COLUMN_SIZE, _("Size"), wxLIST_FORMAT_LEFT, 80);
121
 
    m_pListPane->InsertColumn(COLUMN_TIME, _("Elapsed Time"), wxLIST_FORMAT_LEFT, 80);
122
 
    m_pListPane->InsertColumn(COLUMN_SPEED, _("Speed"), wxLIST_FORMAT_LEFT, 80);
123
 
    m_pListPane->InsertColumn(COLUMN_STATUS, _("Status"), wxLIST_FORMAT_LEFT, 150);
124
 
 
125
 
    UpdateSelection();
126
 
}
127
 
 
128
 
 
129
 
CViewTransfers::~CViewTransfers() {
130
 
    EmptyCache();
131
 
    EmptyTasks();
132
 
}
133
 
 
134
 
 
135
 
wxString& CViewTransfers::GetViewName() {
136
 
    static wxString strViewName(_("Transfers"));
137
 
    return strViewName;
138
 
}
139
 
 
140
 
 
141
 
wxString& CViewTransfers::GetViewDisplayName() {
142
 
    static wxString strViewName(_("Transfers"));
143
 
    return strViewName;
144
 
}
145
 
 
146
 
 
147
 
const char** CViewTransfers::GetViewIcon() {
148
 
    return xfer_xpm;
149
 
}
150
 
 
151
 
 
152
 
void CViewTransfers::OnTransfersRetryNow( wxCommandEvent& WXUNUSED(event) ) {
153
 
    wxLogTrace(wxT("Function Start/End"), wxT("CViewTransfers::OnTransfersRetryNow - Function Begin"));
154
 
 
155
 
    CMainDocument*  pDoc    = wxGetApp().GetDocument();
156
 
    CAdvancedFrame* pFrame  = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
157
 
 
158
 
    wxASSERT(pDoc);
159
 
    wxASSERT(wxDynamicCast(pDoc, CMainDocument));
160
 
    wxASSERT(pFrame);
161
 
    wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
162
 
 
163
 
    pFrame->UpdateStatusText(_("Retrying transfer now..."));
164
 
    pDoc->TransferRetryNow(m_pListPane->GetFirstSelected());
165
 
    pFrame->UpdateStatusText(wxT(""));
166
 
 
167
 
    UpdateSelection();
168
 
    pFrame->ResetReminderTimers();
169
 
    pFrame->FireRefreshView();
170
 
 
171
 
    wxLogTrace(wxT("Function Start/End"), wxT("CViewTransfers::OnTransfersRetryNow - Function End"));
172
 
}
173
 
 
174
 
 
175
 
void CViewTransfers::OnTransfersAbort( wxCommandEvent& WXUNUSED(event) ) {
176
 
    wxLogTrace(wxT("Function Start/End"), wxT("CViewTransfers::OnTransfersAbort - Function Begin"));
177
 
 
178
 
    wxInt32         iAnswer    = 0; 
179
 
    wxString        strMessage = wxEmptyString;
180
 
    CMainDocument*  pDoc       = wxGetApp().GetDocument();
181
 
    CAdvancedFrame* pFrame     = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
182
 
    CTransfer*      pTransfer  = NULL;
183
 
 
184
 
    wxASSERT(pDoc);
185
 
    wxASSERT(wxDynamicCast(pDoc, CMainDocument));
186
 
    wxASSERT(pFrame);
187
 
    wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
188
 
 
189
 
    if (!pDoc->IsUserAuthorized())
190
 
        return;
191
 
 
192
 
    pFrame->UpdateStatusText(_("Aborting transfer..."));
193
 
 
194
 
    pTransfer = m_TransferCache.at(m_pListPane->GetFirstSelected());
195
 
 
196
 
    strMessage.Printf(
197
 
        _("Are you sure you want to abort this file transfer '%s'?\n"
198
 
          "NOTE: Aborting a transfer will invalidate a task and you\n"
199
 
          "will not receive credit for it."), 
200
 
        pTransfer->m_strFileName.c_str()
201
 
    );
202
 
 
203
 
    iAnswer = ::wxMessageBox(
204
 
        strMessage,
205
 
        _("Abort File Transfer"),
206
 
        wxYES_NO | wxICON_QUESTION,
207
 
        this
208
 
    );
209
 
 
210
 
    if (wxYES == iAnswer) {
211
 
        pDoc->TransferAbort(m_pListPane->GetFirstSelected());
212
 
    }
213
 
 
214
 
    pFrame->UpdateStatusText(wxT(""));
215
 
 
216
 
    UpdateSelection();
217
 
    pFrame->FireRefreshView();
218
 
 
219
 
    wxLogTrace(wxT("Function Start/End"), wxT("CViewTransfers::OnTransfersAbort - Function End"));
220
 
}
221
 
 
222
 
 
223
 
wxInt32 CViewTransfers::GetDocCount() {
224
 
    return wxGetApp().GetDocument()->GetTransferCount();
225
 
}
226
 
 
227
 
 
228
 
wxString CViewTransfers::OnListGetItemText(long item, long column) const {
229
 
    CTransfer* transfer   = m_TransferCache.at(item);
230
 
    wxString   strBuffer  = wxEmptyString;
231
 
 
232
 
    try {
233
 
        transfer = m_TransferCache.at(item);
234
 
    } catch ( std::out_of_range ) {
235
 
        transfer = NULL;
236
 
    }
237
 
 
238
 
    if (transfer) {
239
 
        switch(column) {
240
 
            case COLUMN_PROJECT:
241
 
                strBuffer = transfer->m_strProjectName;
242
 
                break;
243
 
            case COLUMN_FILE:
244
 
                strBuffer = transfer->m_strFileName;
245
 
                break;
246
 
            case COLUMN_PROGRESS:
247
 
                strBuffer = transfer->m_strProgress;
248
 
                break;
249
 
            case COLUMN_SIZE:
250
 
                strBuffer = transfer->m_strSize;
251
 
                break;
252
 
            case COLUMN_TIME:
253
 
                strBuffer = transfer->m_strTime;
254
 
                break;
255
 
            case COLUMN_SPEED:
256
 
                strBuffer = transfer->m_strSpeed;
257
 
                break;
258
 
            case COLUMN_STATUS:
259
 
                strBuffer = transfer->m_strStatus;
260
 
                break;
261
 
        }
262
 
    }
263
 
 
264
 
    return strBuffer;
265
 
}
266
 
 
267
 
 
268
 
wxString CViewTransfers::OnDocGetItemText(long item, long column) const {
269
 
    wxString       strBuffer = wxEmptyString;
270
 
 
271
 
    switch(column) {
272
 
        case COLUMN_PROJECT:
273
 
            FormatProjectName(item, strBuffer);
274
 
            break;
275
 
        case COLUMN_FILE:
276
 
            FormatFileName(item, strBuffer);
277
 
            break;
278
 
        case COLUMN_PROGRESS:
279
 
            FormatProgress(item, strBuffer);
280
 
            break;
281
 
        case COLUMN_SIZE:
282
 
            FormatSize(item, strBuffer);
283
 
            break;
284
 
        case COLUMN_TIME:
285
 
            FormatTime(item, strBuffer);
286
 
            break;
287
 
        case COLUMN_SPEED:
288
 
            FormatSpeed(item, strBuffer);
289
 
            break;
290
 
        case COLUMN_STATUS:
291
 
            FormatStatus(item, strBuffer);
292
 
            break;
293
 
    }
294
 
 
295
 
    return strBuffer;
296
 
}
297
 
 
298
 
 
299
 
wxInt32 CViewTransfers::AddCacheElement() {
300
 
    CTransfer* pItem = new CTransfer();
301
 
    wxASSERT(pItem);
302
 
    if (pItem) {
303
 
        m_TransferCache.push_back(pItem);
304
 
        return 0;
305
 
    }
306
 
    return -1;
307
 
}
308
 
 
309
 
 
310
 
wxInt32 CViewTransfers::EmptyCache() {
311
 
    unsigned int i;
312
 
    for (i=0; i<m_TransferCache.size(); i++) {
313
 
        delete m_TransferCache[i];
314
 
    }
315
 
    m_TransferCache.clear();
316
 
    return 0;
317
 
}
318
 
 
319
 
 
320
 
wxInt32 CViewTransfers::GetCacheCount() {
321
 
    return (wxInt32)m_TransferCache.size();
322
 
}
323
 
 
324
 
 
325
 
wxInt32 CViewTransfers::RemoveCacheElement() {
326
 
    delete m_TransferCache.back();
327
 
    m_TransferCache.erase(m_TransferCache.end() - 1);
328
 
    return 0;
329
 
}
330
 
 
331
 
 
332
 
wxInt32 CViewTransfers::UpdateCache(long item, long column, wxString& strNewData) {
333
 
    CTransfer* transfer   = m_TransferCache.at(item);
334
 
 
335
 
    switch(column) {
336
 
        case COLUMN_PROJECT:
337
 
            transfer->m_strProjectName = strNewData;
338
 
            break;
339
 
        case COLUMN_FILE:
340
 
            transfer->m_strFileName = strNewData;
341
 
            break;
342
 
        case COLUMN_PROGRESS:
343
 
            transfer->m_strProgress = strNewData;
344
 
            break;
345
 
        case COLUMN_SIZE:
346
 
            transfer->m_strSize = strNewData;
347
 
            break;
348
 
        case COLUMN_TIME:
349
 
            transfer->m_strTime = strNewData;
350
 
            break;
351
 
        case COLUMN_SPEED:
352
 
            transfer->m_strSpeed = strNewData;
353
 
            break;
354
 
        case COLUMN_STATUS:
355
 
            transfer->m_strStatus = strNewData;
356
 
            break;
357
 
    }
358
 
 
359
 
    return 0;
360
 
}
361
 
 
362
 
 
363
 
void CViewTransfers::UpdateSelection() {
364
 
    CTaskItemGroup* pGroup = m_TaskGroups[0];
365
 
 
366
 
    CBOINCBaseView::PreUpdateSelection();
367
 
 
368
 
    if (m_pListPane->GetSelectedItemCount()) {
369
 
        m_pTaskPane->EnableTaskGroupTasks(pGroup);
370
 
    } else {
371
 
        m_pTaskPane->DisableTaskGroupTasks(pGroup);
372
 
    }
373
 
 
374
 
    CBOINCBaseView::PostUpdateSelection();
375
 
}
376
 
 
377
 
 
378
 
wxInt32 CViewTransfers::FormatProjectName(wxInt32 item, wxString& strBuffer) const {
379
 
    FILE_TRANSFER* transfer = wxGetApp().GetDocument()->file_transfer(item);
380
 
 
381
 
    if (transfer) {
382
 
        strBuffer = HtmlEntityDecode(wxString(transfer->project_name.c_str(), wxConvUTF8));
383
 
    }
384
 
    return 0;
385
 
}
386
 
 
387
 
 
388
 
wxInt32 CViewTransfers::FormatFileName(wxInt32 item, wxString& strBuffer) const {
389
 
    FILE_TRANSFER* transfer = wxGetApp().GetDocument()->file_transfer(item);
390
 
 
391
 
    if (transfer) {
392
 
        strBuffer = wxString(transfer->name.c_str(), wxConvUTF8);
393
 
    }
394
 
    return 0;
395
 
}
396
 
 
397
 
 
398
 
wxInt32 CViewTransfers::FormatProgress(wxInt32 item, wxString& strBuffer) const {
399
 
    float          fBytesSent = 0;
400
 
    float          fFileSize = 0;
401
 
    FILE_TRANSFER* transfer = wxGetApp().GetDocument()->file_transfer(item);
402
 
 
403
 
    if (transfer) {
404
 
        fBytesSent = transfer->bytes_xferred;
405
 
        fFileSize = transfer->nbytes;
406
 
    }
407
 
 
408
 
    // Curl apparently counts the HTTP header in byte count.
409
 
    // Prevent this from causing > 100% display
410
 
    //
411
 
    if (fBytesSent > fFileSize) {
412
 
        fBytesSent = fFileSize;
413
 
    }
414
 
 
415
 
    if ( 0.0 == fFileSize ) {
416
 
        strBuffer = wxT("0%");
417
 
    } else {
418
 
        strBuffer.Printf(wxT("%.2f%%"), floor((fBytesSent / fFileSize) * 10000)/100);
419
 
    }
420
 
 
421
 
    return 0;
422
 
}
423
 
 
424
 
 
425
 
wxInt32 CViewTransfers::FormatSize(wxInt32 item, wxString& strBuffer) const {
426
 
    float          fBytesSent = 0;
427
 
    float          fFileSize = 0;
428
 
    double         xTera = 1099511627776.0;
429
 
    double         xGiga = 1073741824.0;
430
 
    double         xMega = 1048576.0;
431
 
    double         xKilo = 1024.0;
432
 
    FILE_TRANSFER* transfer = wxGetApp().GetDocument()->file_transfer(item);
433
 
 
434
 
    if (transfer) {
435
 
        fBytesSent = transfer->bytes_xferred;
436
 
        fFileSize = transfer->nbytes;
437
 
    }
438
 
 
439
 
    if (fFileSize != 0) {
440
 
        if      (fFileSize >= xTera) {
441
 
            strBuffer.Printf(wxT("%0.2f/%0.2f TB"), fBytesSent/xTera, fFileSize/xTera);
442
 
        } else if (fFileSize >= xGiga) {
443
 
            strBuffer.Printf(wxT("%0.2f/%0.2f GB"), fBytesSent/xGiga, fFileSize/xGiga);
444
 
        } else if (fFileSize >= xMega) {
445
 
            strBuffer.Printf(wxT("%0.2f/%0.2f MB"), fBytesSent/xMega, fFileSize/xMega);
446
 
        } else if (fFileSize >= xKilo) {
447
 
            strBuffer.Printf(wxT("%0.2f/%0.2f KB"), fBytesSent/xKilo, fFileSize/xKilo);
448
 
        } else {
449
 
            strBuffer.Printf(wxT("%0.0f/%0.0f bytes"), fBytesSent, fFileSize);
450
 
        }
451
 
    } else {
452
 
        if      (fBytesSent >= xTera) {
453
 
            strBuffer.Printf(wxT("%0.2f TB"), fBytesSent/xTera);
454
 
        } else if (fBytesSent >= xGiga) {
455
 
            strBuffer.Printf(wxT("%0.2f GB"), fBytesSent/xGiga);
456
 
        } else if (fBytesSent >= xMega) {
457
 
            strBuffer.Printf(wxT("%0.2f MB"), fBytesSent/xMega);
458
 
        } else if (fBytesSent >= xKilo) {
459
 
            strBuffer.Printf(wxT("%0.2f KB"), fBytesSent/xKilo);
460
 
        } else {
461
 
            strBuffer.Printf(wxT("%0.0f bytes"), fBytesSent);
462
 
        }
463
 
    }
464
 
 
465
 
    return 0;
466
 
}
467
 
 
468
 
 
469
 
wxInt32 CViewTransfers::FormatTime(wxInt32 item, wxString& strBuffer) const {
470
 
    float          fBuffer = 0;
471
 
    wxInt32        iHour = 0;
472
 
    wxInt32        iMin = 0;
473
 
    wxInt32        iSec = 0;
474
 
    wxTimeSpan     ts;
475
 
    FILE_TRANSFER* transfer = wxGetApp().GetDocument()->file_transfer(item);
476
 
 
477
 
    if (transfer) {
478
 
        fBuffer = transfer->time_so_far;
479
 
    }
480
 
 
481
 
    iHour = (wxInt32)(fBuffer / (60 * 60));
482
 
    iMin  = (wxInt32)(fBuffer / 60) % 60;
483
 
    iSec  = (wxInt32)(fBuffer) % 60;
484
 
 
485
 
    ts = wxTimeSpan(iHour, iMin, iSec);
486
 
 
487
 
    strBuffer = ts.Format();
488
 
 
489
 
    return 0;
490
 
}
491
 
 
492
 
 
493
 
wxInt32 CViewTransfers::FormatSpeed(wxInt32 item, wxString& strBuffer) const {
494
 
    float          fTransferSpeed = 0;
495
 
    FILE_TRANSFER* transfer = wxGetApp().GetDocument()->file_transfer(item);
496
 
 
497
 
    if (transfer) {
498
 
        if (transfer->xfer_active)
499
 
            fTransferSpeed = transfer->xfer_speed / 1024;
500
 
        else
501
 
            fTransferSpeed = 0.0;
502
 
    }
503
 
 
504
 
    strBuffer.Printf(wxT("%.2f KBps"), fTransferSpeed);
505
 
 
506
 
    return 0;
507
 
}
508
 
 
509
 
 
510
 
wxInt32 CViewTransfers::FormatStatus(wxInt32 item, wxString& strBuffer) const {
511
 
    CMainDocument* doc = wxGetApp().GetDocument();
512
 
    FILE_TRANSFER* transfer = wxGetApp().GetDocument()->file_transfer(item);
513
 
    CC_STATUS      status;
514
 
 
515
 
    wxASSERT(doc);
516
 
    wxASSERT(wxDynamicCast(doc, CMainDocument));
517
 
 
518
 
    doc->GetCoreClientStatus(status);
519
 
 
520
 
    wxDateTime dtNextRequest((time_t)transfer->next_request_time);
521
 
    wxDateTime dtNow(wxDateTime::Now());
522
 
 
523
 
    if (transfer) {
524
 
        if      (dtNextRequest > dtNow) {
525
 
            wxTimeSpan tsNextRequest(dtNextRequest - dtNow);
526
 
            strBuffer = _("Retry in ") + tsNextRequest.Format();
527
 
        } else if (ERR_GIVEUP_DOWNLOAD == transfer->status) {
528
 
            strBuffer = _("Download failed");
529
 
        } else if (ERR_GIVEUP_UPLOAD == transfer->status) {
530
 
            strBuffer = _("Upload failed");
531
 
        } else {
532
 
            if (status.network_suspend_reason) {
533
 
                strBuffer = _("Suspended");
534
 
            } else {
535
 
                if (transfer->xfer_active) {
536
 
                    strBuffer = transfer->generated_locally? _("Uploading") : _("Downloading");
537
 
                } else {
538
 
                    strBuffer = transfer->generated_locally? _("Upload pending") : _("Download pending");
539
 
                }
540
 
            }
541
 
        }
542
 
    }
543
 
 
544
 
    return 0;
545
 
}
546
 
 
547
 
 
548
 
const char *BOINC_RCSID_7aadb93332 = "$Id: ViewTransfers.cpp 13804 2007-10-09 11:35:47Z fthomas $";
 
1
// This file is part of BOINC.
 
2
// http://boinc.berkeley.edu
 
3
// Copyright (C) 2008 University of California
 
4
//
 
5
// BOINC is free software; you can redistribute it and/or modify it
 
6
// under the terms of the GNU Lesser General Public License
 
7
// as published by the Free Software Foundation,
 
8
// either version 3 of the License, or (at your option) any later version.
 
9
//
 
10
// BOINC is distributed in the hope that it will be useful,
 
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
13
// See the GNU Lesser General Public License for more details.
 
14
//
 
15
// You should have received a copy of the GNU Lesser General Public License
 
16
// along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
 
17
 
 
18
#if defined(__GNUG__) && !defined(__APPLE__)
 
19
#pragma implementation "ViewTransfers.h"
 
20
#endif
 
21
 
 
22
#include "stdwx.h"
 
23
#include "BOINCGUIApp.h"
 
24
#include "BOINCBaseFrame.h"
 
25
#include "MainDocument.h"
 
26
#include "AdvancedFrame.h"
 
27
#include "BOINCTaskCtrl.h"
 
28
#include "BOINCListCtrl.h"
 
29
#include "ViewTransfers.h"
 
30
#include "Events.h"
 
31
#include "error_numbers.h"
 
32
 
 
33
 
 
34
#include "res/xfer.xpm"
 
35
 
 
36
 
 
37
#define COLUMN_PROJECT              0
 
38
#define COLUMN_FILE                 1
 
39
#define COLUMN_PROGRESS             2
 
40
#define COLUMN_SIZE                 3
 
41
#define COLUMN_TIME                 4
 
42
#define COLUMN_SPEED                5
 
43
#define COLUMN_STATUS               6
 
44
 
 
45
// buttons in the "tasks" area
 
46
#define BTN_RETRY       0
 
47
#define BTN_ABORT       1
 
48
 
 
49
 
 
50
CTransfer::CTransfer() {
 
51
    m_fProgress = -1.0;
 
52
    m_fBytesXferred = -1.0;
 
53
    m_fTotalBytes = -1.0;
 
54
    m_dTime = -1.0;
 
55
    m_dSpeed = -1.0;
 
56
}
 
57
 
 
58
 
 
59
CTransfer::~CTransfer() {
 
60
    m_strProjectName.Clear();
 
61
    m_strFileName.Clear();
 
62
    m_strStatus.Clear();
 
63
}
 
64
 
 
65
 
 
66
IMPLEMENT_DYNAMIC_CLASS(CViewTransfers, CBOINCBaseView)
 
67
 
 
68
BEGIN_EVENT_TABLE (CViewTransfers, CBOINCBaseView)
 
69
    EVT_BUTTON(ID_TASK_TRANSFERS_RETRYNOW, CViewTransfers::OnTransfersRetryNow)
 
70
    EVT_BUTTON(ID_TASK_TRANSFERS_ABORT, CViewTransfers::OnTransfersAbort)
 
71
    EVT_LIST_ITEM_SELECTED(ID_LIST_TRANSFERSVIEW, CViewTransfers::OnListSelected)
 
72
    EVT_LIST_ITEM_DESELECTED(ID_LIST_TRANSFERSVIEW, CViewTransfers::OnListDeselected)
 
73
    EVT_LIST_COL_CLICK(ID_LIST_TRANSFERSVIEW, CViewTransfers::OnColClick)
 
74
    EVT_LIST_CACHE_HINT(ID_LIST_TRANSFERSVIEW, CViewTransfers::OnCacheHint)
 
75
END_EVENT_TABLE ()
 
76
 
 
77
 
 
78
static CViewTransfers* MyCViewTransfers;
 
79
 
 
80
static bool CompareViewTransferItems(int iRowIndex1, int iRowIndex2) {
 
81
    CTransfer*      transfer1;
 
82
    CTransfer*      transfer2;
 
83
    int             result = 0;
 
84
 
 
85
    try {
 
86
        transfer1 = MyCViewTransfers->m_TransferCache.at(iRowIndex1);
 
87
    } catch ( std::out_of_range ) {
 
88
        return 0;
 
89
    }
 
90
 
 
91
    try {
 
92
        transfer2 = MyCViewTransfers->m_TransferCache.at(iRowIndex2);
 
93
    } catch ( std::out_of_range ) {
 
94
        return 0;
 
95
    }
 
96
 
 
97
    switch (MyCViewTransfers->m_iSortColumn) {
 
98
    case COLUMN_PROJECT:
 
99
        result = transfer1->m_strProjectName.CmpNoCase(transfer2->m_strProjectName);
 
100
        break;
 
101
    case COLUMN_FILE:
 
102
        result = transfer1->m_strFileName.CmpNoCase(transfer2->m_strFileName);
 
103
        break;
 
104
    case COLUMN_PROGRESS:
 
105
        if (transfer1->m_fProgress < transfer2->m_fProgress) {
 
106
            result = -1;
 
107
        } else if (transfer1->m_fProgress > transfer2->m_fProgress) {
 
108
            result = 1;
 
109
        }
 
110
        break;
 
111
    case COLUMN_SIZE:
 
112
        if (transfer1->m_fBytesXferred < transfer2->m_fBytesXferred) {
 
113
            result = -1;
 
114
        } else if (transfer1->m_fBytesXferred > transfer2->m_fBytesXferred) {
 
115
            result = 1;
 
116
        }
 
117
        break;
 
118
    case COLUMN_TIME:
 
119
        if (transfer1->m_dTime < transfer2->m_dTime) {
 
120
            result = -1;
 
121
        } else if (transfer1->m_dTime > transfer2->m_dTime) {
 
122
            result = 1;
 
123
        }
 
124
        break;
 
125
    case COLUMN_SPEED:
 
126
        if (transfer1->m_dSpeed < transfer2->m_dSpeed) {
 
127
            result = -1;
 
128
        } else if (transfer1->m_dSpeed > transfer2->m_dSpeed) {
 
129
            result = 1;
 
130
        }
 
131
        break;
 
132
    case COLUMN_STATUS:
 
133
        result = transfer1->m_strStatus.CmpNoCase(transfer2->m_strStatus);
 
134
        break;
 
135
    }
 
136
 
 
137
    // Always return FALSE for equality (result == 0)
 
138
    return (MyCViewTransfers->m_bReverseSort ? (result > 0) : (result < 0));
 
139
}
 
140
 
 
141
 
 
142
CViewTransfers::CViewTransfers()
 
143
{}
 
144
 
 
145
 
 
146
CViewTransfers::CViewTransfers(wxNotebook* pNotebook) :
 
147
    CBOINCBaseView(pNotebook, ID_TASK_TRANSFERSVIEW, DEFAULT_TASK_FLAGS, ID_LIST_TRANSFERSVIEW, DEFAULT_LIST_MULTI_SEL_FLAGS)
 
148
{
 
149
        CTaskItemGroup* pGroup = NULL;
 
150
        CTaskItem*      pItem = NULL;
 
151
 
 
152
    wxASSERT(m_pTaskPane);
 
153
    wxASSERT(m_pListPane);
 
154
 
 
155
 
 
156
    //
 
157
    // Setup View
 
158
    //
 
159
        pGroup = new CTaskItemGroup( _("Commands") );
 
160
        m_TaskGroups.push_back( pGroup );
 
161
 
 
162
        pItem = new CTaskItem(
 
163
        _("Retry Now"),
 
164
        _("Click 'Retry now' to transfer the file now"),
 
165
        ID_TASK_TRANSFERS_RETRYNOW 
 
166
    );
 
167
    pGroup->m_Tasks.push_back( pItem );
 
168
 
 
169
        pItem = new CTaskItem(
 
170
        _("Abort Transfer"),
 
171
        _("Click 'Abort transfer' to delete the file from the transfer queue. This will prevent you from being granted credit for this result."),
 
172
        ID_TASK_TRANSFERS_ABORT 
 
173
    );
 
174
    pGroup->m_Tasks.push_back( pItem );
 
175
 
 
176
 
 
177
    // Create Task Pane Items
 
178
    m_pTaskPane->UpdateControls();
 
179
 
 
180
    // Create List Pane Items
 
181
    m_pListPane->InsertColumn(COLUMN_PROJECT, _("Project"), wxLIST_FORMAT_LEFT, 125);
 
182
    m_pListPane->InsertColumn(COLUMN_FILE, _("File"), wxLIST_FORMAT_LEFT, 205);
 
183
    m_pListPane->InsertColumn(COLUMN_PROGRESS, _("Progress"), wxLIST_FORMAT_CENTRE, 60);
 
184
    m_pListPane->InsertColumn(COLUMN_SIZE, _("Size"), wxLIST_FORMAT_LEFT, 80);
 
185
    m_pListPane->InsertColumn(COLUMN_TIME, _("Elapsed Time"), wxLIST_FORMAT_LEFT, 80);
 
186
    m_pListPane->InsertColumn(COLUMN_SPEED, _("Speed"), wxLIST_FORMAT_LEFT, 80);
 
187
    m_pListPane->InsertColumn(COLUMN_STATUS, _("Status"), wxLIST_FORMAT_LEFT, 150);
 
188
 
 
189
    m_iProgressColumn = COLUMN_PROGRESS;
 
190
 
 
191
    // Needed by static sort routine;
 
192
    MyCViewTransfers = this;
 
193
    m_funcSortCompare = CompareViewTransferItems;
 
194
 
 
195
    UpdateSelection();
 
196
}
 
197
 
 
198
 
 
199
CViewTransfers::~CViewTransfers() {
 
200
    EmptyCache();
 
201
    EmptyTasks();
 
202
}
 
203
 
 
204
 
 
205
wxString& CViewTransfers::GetViewName() {
 
206
    static wxString strViewName(wxT("Transfers"));
 
207
    return strViewName;
 
208
}
 
209
 
 
210
 
 
211
wxString& CViewTransfers::GetViewDisplayName() {
 
212
    static wxString strViewName(_("Transfers"));
 
213
    return strViewName;
 
214
}
 
215
 
 
216
 
 
217
const char** CViewTransfers::GetViewIcon() {
 
218
    return xfer_xpm;
 
219
}
 
220
 
 
221
 
 
222
const int CViewTransfers::GetViewCurrentViewPage() {
 
223
    return VW_XFER;
 
224
}
 
225
 
 
226
 
 
227
wxString CViewTransfers::GetKeyValue1(int iRowIndex) {
 
228
    CTransfer*  transfer;
 
229
    
 
230
    if (GetTransferCacheAtIndex(transfer, m_iSortedIndexes[iRowIndex])) {
 
231
        return wxEmptyString;
 
232
    }
 
233
 
 
234
    return transfer->m_strFileName;
 
235
}
 
236
 
 
237
 
 
238
wxString CViewTransfers::GetKeyValue2(int iRowIndex) {
 
239
    CTransfer*  transfer;
 
240
    
 
241
    if (GetTransferCacheAtIndex(transfer, m_iSortedIndexes[iRowIndex])) {
 
242
        return wxEmptyString;
 
243
    }
 
244
    
 
245
    return transfer->m_strProjectURL;
 
246
}
 
247
 
 
248
 
 
249
int CViewTransfers::FindRowIndexByKeyValues(wxString& key1, wxString& key2) {
 
250
    CTransfer*  transfer;
 
251
    unsigned int iRowIndex, n = GetCacheCount();
 
252
        for(iRowIndex=0; iRowIndex < n; iRowIndex++) {
 
253
        if (GetTransferCacheAtIndex(transfer, m_iSortedIndexes[iRowIndex])) {
 
254
            continue;
 
255
        }
 
256
        if(! (transfer->m_strFileName).IsSameAs(key1)) continue;
 
257
        if((transfer->m_strProjectURL).IsSameAs(key2)) return iRowIndex;
 
258
        }
 
259
        return -1;
 
260
}
 
261
 
 
262
 
 
263
void CViewTransfers::OnTransfersRetryNow( wxCommandEvent& WXUNUSED(event) ) {
 
264
    wxLogTrace(wxT("Function Start/End"), wxT("CViewTransfers::OnTransfersRetryNow - Function Begin"));
 
265
 
 
266
    CMainDocument*  pDoc    = wxGetApp().GetDocument();
 
267
    CAdvancedFrame* pFrame  = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
 
268
    int row;
 
269
 
 
270
    wxASSERT(pDoc);
 
271
    wxASSERT(wxDynamicCast(pDoc, CMainDocument));
 
272
    wxASSERT(pFrame);
 
273
    wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
 
274
    wxASSERT(m_pListPane);
 
275
 
 
276
    CC_STATUS status;
 
277
    pDoc->GetCoreClientStatus(status);
 
278
    if (status.network_suspend_reason) {
 
279
        wxString msg = _("Network activity is suspended - ");
 
280
        msg += suspend_reason_wxstring(status.network_suspend_reason);
 
281
        msg += _(".\nYou can enable it using the Activity menu.");
 
282
        wxGetApp().SafeMessageBox(
 
283
            msg,
 
284
            _("BOINC"),
 
285
            wxOK | wxICON_INFORMATION,
 
286
            this
 
287
        );
 
288
        return;
 
289
    }
 
290
 
 
291
    pFrame->UpdateStatusText(_("Retrying transfer now..."));
 
292
    row = -1;
 
293
    while (1) {
 
294
        // Step through all selected items
 
295
        row = m_pListPane->GetNextItem(row, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
 
296
        if (row < 0) break;
 
297
        
 
298
        pDoc->TransferRetryNow(m_iSortedIndexes[row]);
 
299
    }
 
300
    pFrame->UpdateStatusText(wxT(""));
 
301
 
 
302
    UpdateSelection();
 
303
    pFrame->ResetReminderTimers();
 
304
    pFrame->FireRefreshView();
 
305
 
 
306
    wxLogTrace(wxT("Function Start/End"), wxT("CViewTransfers::OnTransfersRetryNow - Function End"));
 
307
}
 
308
 
 
309
 
 
310
void CViewTransfers::OnTransfersAbort( wxCommandEvent& WXUNUSED(event) ) {
 
311
    wxLogTrace(wxT("Function Start/End"), wxT("CViewTransfers::OnTransfersAbort - Function Begin"));
 
312
 
 
313
    wxInt32         iAnswer    = 0; 
 
314
    wxString        strMessage = wxEmptyString;
 
315
    CMainDocument*  pDoc       = wxGetApp().GetDocument();
 
316
    CAdvancedFrame* pFrame     = wxDynamicCast(GetParent()->GetParent()->GetParent(), CAdvancedFrame);
 
317
    CTransfer*      pTransfer  = NULL;
 
318
    int row;
 
319
 
 
320
    wxASSERT(pDoc);
 
321
    wxASSERT(wxDynamicCast(pDoc, CMainDocument));
 
322
    wxASSERT(pFrame);
 
323
    wxASSERT(wxDynamicCast(pFrame, CAdvancedFrame));
 
324
    wxASSERT(m_pListPane);
 
325
 
 
326
    if (!pDoc->IsUserAuthorized())
 
327
        return;
 
328
 
 
329
    pFrame->UpdateStatusText(_("Aborting transfer..."));
 
330
 
 
331
    row = -1;
 
332
    while (1) {
 
333
        // Step through all selected items
 
334
        row = m_pListPane->GetNextItem(row, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
 
335
        if (row < 0) break;
 
336
        
 
337
        if (GetTransferCacheAtIndex(pTransfer, m_iSortedIndexes[row])) {
 
338
            return;
 
339
        }
 
340
 
 
341
        strMessage.Printf(
 
342
            _("Are you sure you want to abort this file transfer '%s'?\nNOTE: Aborting a transfer will invalidate a task and you\nwill not receive credit for it."), 
 
343
            pTransfer->m_strFileName.c_str()
 
344
        );
 
345
 
 
346
        iAnswer = wxGetApp().SafeMessageBox(
 
347
            strMessage,
 
348
            _("Abort File Transfer"),
 
349
            wxYES_NO | wxICON_QUESTION,
 
350
            this
 
351
        );
 
352
 
 
353
        if (wxYES == iAnswer) {
 
354
            pDoc->TransferAbort(m_iSortedIndexes[row]);
 
355
        }
 
356
    }
 
357
    
 
358
    pFrame->UpdateStatusText(wxT(""));
 
359
 
 
360
    UpdateSelection();
 
361
    pFrame->FireRefreshView();
 
362
 
 
363
    wxLogTrace(wxT("Function Start/End"), wxT("CViewTransfers::OnTransfersAbort - Function End"));
 
364
}
 
365
 
 
366
 
 
367
wxInt32 CViewTransfers::GetDocCount() {
 
368
    return wxGetApp().GetDocument()->GetTransferCount();
 
369
}
 
370
 
 
371
 
 
372
wxString CViewTransfers::OnListGetItemText(long item, long column) const {
 
373
    CTransfer* transfer;
 
374
    wxString   strBuffer  = wxEmptyString;
 
375
 
 
376
    m_pListPane->AddPendingProgressBar(item);
 
377
 
 
378
    try {
 
379
        transfer = m_TransferCache.at(m_iSortedIndexes[item]);
 
380
    } catch ( std::out_of_range ) {
 
381
        transfer = NULL;
 
382
    }
 
383
 
 
384
    if (transfer) {
 
385
        switch(column) {
 
386
        case COLUMN_PROJECT:
 
387
            strBuffer = transfer->m_strProjectName;
 
388
            break;
 
389
        case COLUMN_FILE:
 
390
            strBuffer = transfer->m_strFileName;
 
391
            break;
 
392
        case COLUMN_PROGRESS:
 
393
            // CBOINCListCtrl::DrawProgressBars() will draw this using 
 
394
            // data provided by GetProgressText() and GetProgressValue(), 
 
395
            // but we need it here for accessibility programs.
 
396
            strBuffer = transfer->m_strProgress;
 
397
            break;
 
398
        case COLUMN_SIZE:
 
399
            strBuffer = transfer->m_strSize;
 
400
            break;
 
401
        case COLUMN_TIME:
 
402
            strBuffer = transfer->m_strTime;
 
403
            break;
 
404
        case COLUMN_SPEED:
 
405
            strBuffer = transfer->m_strSpeed;
 
406
            break;
 
407
        case COLUMN_STATUS:
 
408
            strBuffer = transfer->m_strStatus;
 
409
            break;
 
410
        }
 
411
    }
 
412
 
 
413
    return strBuffer;
 
414
}
 
415
 
 
416
 
 
417
wxInt32 CViewTransfers::AddCacheElement() {
 
418
    CTransfer* pItem = new CTransfer();
 
419
    wxASSERT(pItem);
 
420
    if (pItem) {
 
421
        m_TransferCache.push_back(pItem);
 
422
        m_iSortedIndexes.Add((int)m_TransferCache.size()-1);
 
423
        return 0;
 
424
    }
 
425
    return -1;
 
426
}
 
427
 
 
428
 
 
429
wxInt32 CViewTransfers::EmptyCache() {
 
430
    unsigned int i;
 
431
    for (i=0; i<m_TransferCache.size(); i++) {
 
432
        delete m_TransferCache[i];
 
433
    }
 
434
    m_TransferCache.clear();
 
435
    m_iSortedIndexes.Clear();
 
436
    return 0;
 
437
}
 
438
 
 
439
 
 
440
wxInt32 CViewTransfers::GetCacheCount() {
 
441
    return (wxInt32)m_TransferCache.size();
 
442
}
 
443
 
 
444
 
 
445
wxInt32 CViewTransfers::RemoveCacheElement() {
 
446
    unsigned int i;
 
447
    delete m_TransferCache.back();
 
448
    m_TransferCache.erase(m_TransferCache.end() - 1);
 
449
    m_iSortedIndexes.Clear();
 
450
    for (i=0; i<m_TransferCache.size(); i++) {
 
451
        m_iSortedIndexes.Add(i);
 
452
    }
 
453
    return 0;
 
454
}
 
455
 
 
456
 
 
457
bool CViewTransfers::IsSelectionManagementNeeded() {
 
458
    return true;
 
459
}
 
460
 
 
461
 
 
462
void CViewTransfers::UpdateSelection() {
 
463
    CTaskItemGroup* pGroup = m_TaskGroups[0];
 
464
 
 
465
    CBOINCBaseView::PreUpdateSelection();
 
466
 
 
467
    if (m_pListPane->GetSelectedItemCount()) {
 
468
        m_pTaskPane->EnableTaskGroupTasks(pGroup);
 
469
    } else {
 
470
        m_pTaskPane->DisableTaskGroupTasks(pGroup);
 
471
    }
 
472
 
 
473
    CBOINCBaseView::PostUpdateSelection();
 
474
}
 
475
 
 
476
 
 
477
bool CViewTransfers::SynchronizeCacheItem(wxInt32 iRowIndex, wxInt32 iColumnIndex) {
 
478
    wxString    strDocumentText  = wxEmptyString;
 
479
    wxString    strDocumentText2 = wxEmptyString;
 
480
    float       fDocumentFloat = 0.0;
 
481
    double      fDocumentDouble = 0.0, fDocumentDouble2 = 0.0;
 
482
    CTransfer*  transfer;
 
483
    bool        bNeedRefresh = false;
 
484
 
 
485
    strDocumentText.Empty();
 
486
 
 
487
    if (GetTransferCacheAtIndex(transfer, m_iSortedIndexes[iRowIndex])) {
 
488
        return false;
 
489
    }
 
490
 
 
491
    switch(iColumnIndex) {
 
492
        case COLUMN_PROJECT:
 
493
            GetDocProjectName(m_iSortedIndexes[iRowIndex], strDocumentText);
 
494
            GetDocProjectURL(m_iSortedIndexes[iRowIndex], strDocumentText2);
 
495
            if (!strDocumentText.IsSameAs(transfer->m_strProjectName) || !strDocumentText2.IsSameAs(transfer->m_strProjectURL)) {
 
496
                transfer->m_strProjectName = strDocumentText;
 
497
                transfer->m_strProjectURL = strDocumentText2;
 
498
                bNeedRefresh =  true;
 
499
            }
 
500
            break;
 
501
        case COLUMN_FILE:
 
502
            GetDocFileName(m_iSortedIndexes[iRowIndex], strDocumentText);
 
503
            if (!strDocumentText.IsSameAs(transfer->m_strFileName)) {
 
504
                transfer->m_strFileName = strDocumentText;
 
505
                bNeedRefresh =  true;
 
506
            }
 
507
            break;
 
508
        case COLUMN_PROGRESS:
 
509
            GetDocProgress(m_iSortedIndexes[iRowIndex], fDocumentFloat);
 
510
            if (fDocumentFloat != transfer->m_fProgress) {
 
511
                transfer->m_fProgress = fDocumentFloat;
 
512
                FormatProgress(fDocumentFloat, transfer->m_strProgress);
 
513
                bNeedRefresh =  true;
 
514
            }
 
515
            break;
 
516
        case COLUMN_SIZE:
 
517
            GetDocBytesXferred(m_iSortedIndexes[iRowIndex], fDocumentDouble);
 
518
            GetDocTotalBytes(m_iSortedIndexes[iRowIndex], fDocumentDouble2);
 
519
            if (( fDocumentDouble != transfer->m_fBytesXferred) || 
 
520
                (fDocumentDouble2 != transfer->m_fTotalBytes)
 
521
                ) {
 
522
                transfer->m_fBytesXferred = fDocumentDouble;
 
523
                transfer->m_fTotalBytes = fDocumentDouble2;
 
524
                FormatSize(fDocumentDouble, fDocumentDouble2, transfer->m_strSize);
 
525
                bNeedRefresh =  true;
 
526
            }
 
527
            break;
 
528
        case COLUMN_TIME:
 
529
            GetDocTime(m_iSortedIndexes[iRowIndex], fDocumentDouble);
 
530
            if (fDocumentDouble != transfer->m_dTime) {
 
531
                transfer->m_dTime = fDocumentDouble;
 
532
                FormatTime(fDocumentDouble, transfer->m_strTime);
 
533
                bNeedRefresh =  true;
 
534
            }
 
535
            break;
 
536
        case COLUMN_SPEED:
 
537
            GetDocSpeed(m_iSortedIndexes[iRowIndex], fDocumentDouble);
 
538
            if (fDocumentDouble != transfer->m_dSpeed) {
 
539
                transfer->m_dSpeed = fDocumentDouble;
 
540
                FormatSpeed(fDocumentDouble, transfer->m_strSpeed);
 
541
                bNeedRefresh =  true;
 
542
            }
 
543
            break;
 
544
        case COLUMN_STATUS:
 
545
            GetDocStatus(m_iSortedIndexes[iRowIndex], strDocumentText);
 
546
            if (!strDocumentText.IsSameAs(transfer->m_strStatus)) {
 
547
                transfer->m_strStatus = strDocumentText;
 
548
                return true;
 
549
            }
 
550
            break;
 
551
    }
 
552
 
 
553
    return bNeedRefresh;
 
554
}
 
555
 
 
556
 
 
557
void CViewTransfers::GetDocProjectName(wxInt32 item, wxString& strBuffer) const {
 
558
    FILE_TRANSFER* transfer = NULL;
 
559
    CMainDocument* pDoc = wxGetApp().GetDocument();
 
560
    
 
561
    if (pDoc) {
 
562
        transfer = pDoc->file_transfer(item);
 
563
    }
 
564
 
 
565
    if (transfer) {
 
566
        strBuffer = HtmlEntityDecode(wxString(transfer->project_name.c_str(), wxConvUTF8));
 
567
    } else {
 
568
        strBuffer = wxEmptyString;
 
569
    }
 
570
}
 
571
 
 
572
 
 
573
void CViewTransfers::GetDocFileName(wxInt32 item, wxString& strBuffer) const {
 
574
    FILE_TRANSFER* transfer = NULL;
 
575
    CMainDocument* pDoc = wxGetApp().GetDocument();
 
576
    
 
577
    if (pDoc) {
 
578
        transfer = pDoc->file_transfer(item);
 
579
    }
 
580
 
 
581
    if (transfer) {
 
582
        strBuffer = wxString(transfer->name.c_str(), wxConvUTF8);
 
583
    } else {
 
584
        strBuffer = wxEmptyString;
 
585
    }
 
586
}
 
587
 
 
588
 
 
589
void CViewTransfers::GetDocProgress(wxInt32 item, float& fBuffer) const {
 
590
    float          fBytesSent = 0;
 
591
    float          fFileSize = 0;
 
592
    FILE_TRANSFER* transfer = NULL;
 
593
    CMainDocument* pDoc = wxGetApp().GetDocument();
 
594
    
 
595
    if (pDoc) {
 
596
        transfer = pDoc->file_transfer(item);
 
597
    }
 
598
 
 
599
    fBuffer = 0;
 
600
    if (transfer) {
 
601
        fBytesSent = transfer->bytes_xferred;
 
602
        fFileSize = transfer->nbytes;
 
603
    }
 
604
 
 
605
    // Curl apparently counts the HTTP header in byte count.
 
606
    // Prevent this from causing > 100% display
 
607
    //
 
608
    if (fBytesSent > fFileSize) {
 
609
        fBytesSent = fFileSize;
 
610
    }
 
611
 
 
612
    if (fFileSize) {
 
613
        fBuffer = floor((fBytesSent / fFileSize) * 10000)/100;
 
614
    }
 
615
}
 
616
 
 
617
 
 
618
wxInt32 CViewTransfers::FormatProgress(float fBuffer, wxString& strBuffer) const {
 
619
    strBuffer.Printf(wxT("%.2f%%"), fBuffer);
 
620
    return 0;
 
621
}
 
622
 
 
623
 
 
624
void CViewTransfers::GetDocBytesXferred(wxInt32 item, double& fBuffer) const {
 
625
    FILE_TRANSFER* transfer = NULL;
 
626
    CMainDocument* pDoc = wxGetApp().GetDocument();
 
627
    
 
628
    if (pDoc) {
 
629
        transfer = pDoc->file_transfer(item);
 
630
    }
 
631
 
 
632
    if (transfer) {
 
633
        fBuffer = transfer->bytes_xferred;
 
634
    } else {
 
635
        fBuffer = 0.0;
 
636
    }
 
637
}
 
638
 
 
639
 
 
640
void CViewTransfers::GetDocTotalBytes(wxInt32 item, double& fBuffer) const {
 
641
    FILE_TRANSFER* transfer = NULL;
 
642
    CMainDocument* pDoc = wxGetApp().GetDocument();
 
643
    
 
644
    if (pDoc) {
 
645
        transfer = pDoc->file_transfer(item);
 
646
    }
 
647
 
 
648
    if (transfer) {
 
649
        fBuffer = transfer->nbytes;
 
650
    } else {
 
651
        fBuffer = 0.0;
 
652
    }
 
653
}
 
654
 
 
655
 
 
656
wxInt32 CViewTransfers::FormatSize(double fBytesSent, double fFileSize, wxString& strBuffer) const {
 
657
    double          xTera = 1099511627776.0;
 
658
    double          xGiga = 1073741824.0;
 
659
    double          xMega = 1048576.0;
 
660
    double          xKilo = 1024.0;
 
661
 
 
662
    if (fFileSize != 0) {
 
663
        if      (fFileSize >= xTera) {
 
664
            strBuffer.Printf(wxT("%0.2f/%0.2f TB"), fBytesSent/xTera, fFileSize/xTera);
 
665
        } else if (fFileSize >= xGiga) {
 
666
            strBuffer.Printf(wxT("%0.2f/%0.2f GB"), fBytesSent/xGiga, fFileSize/xGiga);
 
667
        } else if (fFileSize >= xMega) {
 
668
            strBuffer.Printf(wxT("%0.2f/%0.2f MB"), fBytesSent/xMega, fFileSize/xMega);
 
669
        } else if (fFileSize >= xKilo) {
 
670
            strBuffer.Printf(wxT("%0.2f/%0.2f KB"), fBytesSent/xKilo, fFileSize/xKilo);
 
671
        } else {
 
672
            strBuffer.Printf(wxT("%0.0f/%0.0f bytes"), fBytesSent, fFileSize);
 
673
        }
 
674
    } else {
 
675
        if      (fBytesSent >= xTera) {
 
676
            strBuffer.Printf(wxT("%0.2f TB"), fBytesSent/xTera);
 
677
        } else if (fBytesSent >= xGiga) {
 
678
            strBuffer.Printf(wxT("%0.2f GB"), fBytesSent/xGiga);
 
679
        } else if (fBytesSent >= xMega) {
 
680
            strBuffer.Printf(wxT("%0.2f MB"), fBytesSent/xMega);
 
681
        } else if (fBytesSent >= xKilo) {
 
682
            strBuffer.Printf(wxT("%0.2f KB"), fBytesSent/xKilo);
 
683
        } else {
 
684
            strBuffer.Printf(wxT("%0.0f bytes"), fBytesSent);
 
685
        }
 
686
    }
 
687
 
 
688
    return 0;
 
689
}
 
690
 
 
691
 
 
692
void CViewTransfers::GetDocTime(wxInt32 item, double& fBuffer) const {
 
693
    FILE_TRANSFER* transfer = NULL;
 
694
    CMainDocument* pDoc = wxGetApp().GetDocument();
 
695
    
 
696
    if (pDoc) {
 
697
        transfer = pDoc->file_transfer(item);
 
698
    }
 
699
 
 
700
    if (transfer) {
 
701
        fBuffer = transfer->time_so_far;
 
702
    } else {
 
703
        fBuffer = 0.0;
 
704
    }
 
705
}
 
706
 
 
707
 
 
708
wxInt32 CViewTransfers::FormatTime(double fBuffer, wxString& strBuffer) const {
 
709
    wxInt32        iHour = 0;
 
710
    wxInt32        iMin = 0;
 
711
    wxInt32        iSec = 0;
 
712
    wxTimeSpan     ts;
 
713
 
 
714
    iHour = (wxInt32)(fBuffer / (60 * 60));
 
715
    iMin  = (wxInt32)(fBuffer / 60) % 60;
 
716
    iSec  = (wxInt32)(fBuffer) % 60;
 
717
 
 
718
    ts = wxTimeSpan(iHour, iMin, iSec);
 
719
 
 
720
    strBuffer = ts.Format();
 
721
 
 
722
    return 0;
 
723
}
 
724
 
 
725
 
 
726
void CViewTransfers::GetDocSpeed(wxInt32 item, double& fBuffer) const {
 
727
    FILE_TRANSFER* transfer = NULL;
 
728
    CMainDocument* pDoc = wxGetApp().GetDocument();
 
729
    
 
730
    if (pDoc) {
 
731
        transfer = pDoc->file_transfer(item);
 
732
    }
 
733
 
 
734
    if (transfer) {
 
735
        if (transfer->xfer_active)
 
736
            fBuffer = transfer->xfer_speed / 1024;
 
737
        else
 
738
            fBuffer = 0.0;
 
739
    }
 
740
}
 
741
 
 
742
 
 
743
wxInt32 CViewTransfers::FormatSpeed(double fBuffer, wxString& strBuffer) const {
 
744
    strBuffer.Printf(wxT("%.2f KBps"), fBuffer);
 
745
 
 
746
    return 0;
 
747
}
 
748
 
 
749
 
 
750
void CViewTransfers::GetDocStatus(wxInt32 item, wxString& strBuffer) const {
 
751
    FILE_TRANSFER* transfer = NULL;
 
752
    CMainDocument* pDoc = wxGetApp().GetDocument();
 
753
    int            retval;
 
754
    
 
755
    if (pDoc) {
 
756
        transfer = pDoc->file_transfer(item);
 
757
    }
 
758
    CC_STATUS      status;
 
759
 
 
760
    wxASSERT(pDoc);
 
761
    wxASSERT(wxDynamicCast(pDoc, CMainDocument));
 
762
 
 
763
    retval = pDoc->GetCoreClientStatus(status);
 
764
 
 
765
    wxDateTime dtNextRequest((time_t)transfer->next_request_time);
 
766
    wxDateTime dtNow(wxDateTime::Now());
 
767
 
 
768
    if (transfer && !retval) {
 
769
        if      (dtNextRequest > dtNow) {
 
770
            wxTimeSpan tsNextRequest(dtNextRequest - dtNow);
 
771
            strBuffer = _("Retry in ") + tsNextRequest.Format();
 
772
        } else if (ERR_GIVEUP_DOWNLOAD == transfer->status) {
 
773
            strBuffer = _("Download failed");
 
774
        } else if (ERR_GIVEUP_UPLOAD == transfer->status) {
 
775
            strBuffer = _("Upload failed");
 
776
        } else {
 
777
            if (status.network_suspend_reason) {
 
778
                strBuffer = transfer->generated_locally
 
779
                    ?_("Upload suspended - ")
 
780
                    :_("Download suspended - ")
 
781
                ;
 
782
                strBuffer += suspend_reason_wxstring(status.network_suspend_reason);
 
783
            } else {
 
784
                if (transfer->xfer_active) {
 
785
                    strBuffer = transfer->generated_locally? _("Uploading") : _("Downloading");
 
786
                } else {
 
787
                    strBuffer = transfer->generated_locally? _("Upload pending") : _("Download pending");
 
788
                }
 
789
            }
 
790
        }
 
791
        if (transfer->project_backoff) {
 
792
            wxString x;
 
793
            FormatTime(transfer->project_backoff, x);
 
794
            strBuffer += _(" (project backoff: ") + x + _(")");
 
795
        }
 
796
    }
 
797
}
 
798
 
 
799
 
 
800
void CViewTransfers::GetDocProjectURL(wxInt32 item, wxString& strBuffer) const {
 
801
    FILE_TRANSFER* transfer = NULL;
 
802
    CMainDocument* pDoc = wxGetApp().GetDocument();
 
803
    
 
804
    if (pDoc) {
 
805
        transfer = pDoc->file_transfer(item);
 
806
    }
 
807
 
 
808
    wxASSERT(transfer);
 
809
 
 
810
    if (transfer) {
 
811
        strBuffer = wxString(transfer->project_url.c_str(), wxConvUTF8);
 
812
    }
 
813
}
 
814
 
 
815
 
 
816
double CViewTransfers::GetProgressValue(long item) {
 
817
    double          fBytesSent = 0;
 
818
    double          fFileSize = 0;
 
819
    FILE_TRANSFER* transfer = NULL;
 
820
    CMainDocument* pDoc = wxGetApp().GetDocument();
 
821
    
 
822
    if (pDoc) {
 
823
        transfer = pDoc->file_transfer(m_iSortedIndexes[item]);
 
824
    }
 
825
 
 
826
    if (transfer) {
 
827
        fBytesSent = transfer->bytes_xferred;
 
828
        fFileSize = transfer->nbytes;
 
829
    }
 
830
 
 
831
    // Curl apparently counts the HTTP header in byte count.
 
832
    // Prevent this from causing > 100% display
 
833
    //
 
834
    if (fBytesSent > fFileSize) {
 
835
        fBytesSent = fFileSize;
 
836
    }
 
837
 
 
838
    if ( 0.0 == fFileSize ) return 0.0;
 
839
    
 
840
    return (fBytesSent / fFileSize);
 
841
}
 
842
 
 
843
 
 
844
wxString CViewTransfers::GetProgressText( long item) {
 
845
    CTransfer* transfer;
 
846
    wxString   strBuffer  = wxEmptyString;
 
847
 
 
848
    GetTransferCacheAtIndex(transfer, m_iSortedIndexes[item]);
 
849
    if (transfer) {
 
850
        strBuffer = transfer->m_strProgress;
 
851
    }
 
852
    return strBuffer;
 
853
}
 
854
 
 
855
 
 
856
int CViewTransfers::GetTransferCacheAtIndex(CTransfer*& transferPtr, int index) {
 
857
    try {
 
858
        transferPtr = m_TransferCache.at(index);
 
859
    } catch ( std::out_of_range ) {
 
860
        transferPtr = NULL;
 
861
        return -1;
 
862
    }
 
863
    
 
864
    return 0;
 
865
}
 
866