1 /***************************************************************************
2 *                                                                         *
3 *   This program is free software; you can redistribute it and/or modify  *
4 *   it under the terms of the GNU General Public License as published by  *
5 *   the Free Software Foundation; either version 3 of the License, or     *
6 *   (at your option) any later version.                                   *
7 *                                                                         *
8 ***************************************************************************/
9 
10 #include "HashProgress.h"
11 #include "WulforUtil.h"
12 
13 #include <QDir>
14 
15 #include "dcpp/stdinc.h"
16 #include "dcpp/HashManager.h"
17 #include "dcpp/ShareManager.h"
18 #include "dcpp/TimerManager.h"
19 
20 using namespace dcpp;
21 
getHashStatus()22 unsigned HashProgress::getHashStatus() {
23     ShareManager *SM = ShareManager::getInstance();
24     HashManager  *HM = HashManager::getInstance();
25     if( SM->isRefreshing() )
26         return LISTUPDATE;
27 
28     if( HM->isHashingPaused() ) {
29         return (Util::getUpTime() < SETTING(HASHING_START_DELAY)) ? DELAYED : PAUSED;
30     }
31 
32     string path;
33     int64_t bytes = 0;
34     size_t files = 0;
35     HM->getStats(path, bytes, files);
36 
37     if( bytes || files )
38         return RUNNING;
39 
40     return IDLE;
41 }
42 
HashProgress(QWidget * parent)43 HashProgress::HashProgress(QWidget *parent):
44         QDialog(parent),
45         autoClose(false),
46         startBytes(0),
47         startFiles(0),
48         startTime(0)
49 {
50     setupUi(this);
51 
52     setWindowModality(Qt::ApplicationModal);
53     setAttribute( Qt::WA_QuitOnClose, false ); // Very important, wo this line app exits then hide
54 
55     HashManager::getInstance()->setPriority(Thread::NORMAL);
56 
57     timer = new QTimer();
58     timer->setInterval(250);
59 
60     connect(timer, SIGNAL(timeout()), this, SLOT(timerTick()));
61     connect(pushButton_START, SIGNAL(clicked()), this, SLOT(slotStart()));
62     connect(checkBox, SIGNAL(toggled(bool)), this, SLOT(slotAutoClose(bool)));
63 
64     timer->start();
65 }
66 
resetProgress()67 void HashProgress::resetProgress() {
68         startBytes = 0;
69         startFiles = 0;
70         startTime  = 0;
71 }
72 
~HashProgress()73 HashProgress::~HashProgress(){
74     timer->stop();//really need?
75 
76     delete timer;
77 
78     HashManager::getInstance()->setPriority(Thread::LOW);
79 }
80 
getProgress()81 float HashProgress::getProgress() {
82     return static_cast<float>( progress->value() )/progress->maximum();
83 }
84 
timerTick()85 void HashProgress::timerTick(){
86     string path;
87     int64_t bytes = 0;
88     size_t files = 0;
89     uint64_t tick = GET_TICK();
90 
91     stateButton();
92 
93     HashManager::getInstance()->getStats(path, bytes, files);
94     if(ShareManager::getInstance()->isRefreshing()) {
95         file->setText(tr("Refreshing file list"));
96         return;
97     }
98 
99     if( startTime == 0 )
100         startTime = tick;
101 
102     if(bytes > startBytes)
103         startBytes = bytes;
104 
105     if(files > startFiles)
106         startFiles = files;
107 
108     if(autoClose && !files) {
109         accept();
110 
111         return;;
112     }
113 
114     double diff = tick - startTime;
115     bool paused = HashManager::getInstance()->isHashingPaused();
116 
117     QString eta;
118 
119     if(startFiles == 0 || startBytes == 0)
120         progress->setValue(0);
121     else
122         progress->setValue( (10000*(startBytes - bytes))/startBytes);
123 
124     if( diff == 0. || files == 0 || bytes == 0 || paused) {
125         status->setText(QString(tr("-.-- files/h, %1 files left")).arg((uint32_t)files));
126         speed->setText(tr("-.-- B/s, %1 left").arg(WulforUtil::formatBytes(bytes)));
127         eta = tr("-:--:--");
128     } else {
129         double filestat = (((double)(startFiles - files)) * 60 * 60 * 1000) / diff;
130         double speedStat = (((double)(startBytes - bytes)) * 1000) / diff;
131 
132         status->setText(tr("%1 files/h, %2 files left").arg(filestat).arg((uint32_t)files));
133         speed->setText(tr("%1/s, %2 left, %3 shared").arg(WulforUtil::formatBytes((int64_t)speedStat))
134                                                      .arg(WulforUtil::formatBytes(bytes))
135                                                      .arg(WulforUtil::formatBytes(ShareManager::getInstance()->getShareSize())));
136 
137         if(/*filestat == 0 ||*/ speedStat == 0) {
138             eta = tr("-:--:--");
139         }
140         else {
141             double ss = bytes / speedStat;
142 
143             eta = _q(Text::toT(Util::formatSeconds((int64_t)(ss))));
144         }
145     }
146     progress->setFormat( tr("%p% %1 left").arg(eta) );
147 
148     if(!files) {
149         //progress->setValue(10000); // generates anoying blinking 0 -> 100%
150         file->setText(tr("Done"));
151     } else {
152         QString fname = QString::fromStdString(path);
153         QFontMetrics metrics(font());
154 
155         file->setToolTip(fname);
156 
157         if (metrics.width(fname) > file->width()*3/4){
158             QStringList parts = fname.split(QDir::separator(), QString::SkipEmptyParts);
159 
160             if (parts.size() > 1){
161                 QString out = "";
162 
163                 for (int i = (parts.size()-1); i >= 0; i--){
164                     if (metrics.width(out+parts.at(i)+QDir::separator()) < file->width()*3/4){
165                         out = parts.at(i) + (out.isEmpty()? out : (QDir::separator() + out));
166                     }
167                     else{
168                         out = QString("..") + QDir::separator() + out;
169 
170                         break;
171                     }
172                 }
173 
174                 if (out.isEmpty())
175                     out = parts.last();
176 
177                 fname = out;
178             }
179         }
180 
181         file->setText(fname);
182     }
183 }
184 
slotStart()185 void HashProgress::slotStart(){
186     ShareManager *SM = ShareManager::getInstance();
187     HashManager  *HM = HashManager::getInstance();
188     switch( getHashStatus() ) {
189     case IDLE:
190             SM->setDirty();
191             SM->refresh(true);
192             break;
193     case LISTUPDATE:
194     case RUNNING:
195             HM->pauseHashing();
196             //HM->setPriority(Thread::IDLE);
197             break;
198     case DELAYED:
199     case PAUSED:
200             HM->resumeHashing();
201             //HM->setPriority(Thread::NORMAL);
202             break;
203     }
204     stateButton();
205 }
206 
slotAutoClose(bool b)207 void HashProgress::slotAutoClose(bool b){
208     autoClose = b;
209 
210     blockSignals(true);
211     checkBox->setChecked(b);
212     blockSignals(false);
213 }
214 
stateButton()215 void HashProgress::stateButton(){
216     switch( getHashStatus() ) {
217     case IDLE:
218         pushButton_START->setText(tr("Start"));
219         break;
220     case LISTUPDATE:
221     case RUNNING:
222         pushButton_START->setText(tr("Pause"));
223         break;
224     case DELAYED:
225     case PAUSED:
226         pushButton_START->setText(tr("Resume"));
227         break;
228     }
229 }
230