wadseekerwadstable.cpp
1 //------------------------------------------------------------------------------
2 // wadseekerwadstable.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This library 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; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library 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. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301 USA
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2011 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "wadseekerwadstable.h"
24 
25 #include "speedcalculator.h"
26 #include "strings.hpp"
27 
28 #include <QDebug>
29 #include <QHeaderView>
30 #include <QProgressBar>
31 #include <QUrl>
32 
33 WadseekerWadsTable::WadseekerWadsTable(QWidget* pParent)
34 : TableWidgetMouseAware(pParent)
35 {
36  d.bAlreadyShownOnce = false;
37  d.updateClock.start();
38 }
39 
40 WadseekerWadsTable::~WadseekerWadsTable()
41 {
42  QMap<QString, SpeedCalculator* >::iterator it;
43  for (it = d.speedCalculators.begin(); it != d.speedCalculators.end(); ++it)
44  {
45  delete it.value();
46  }
47 }
48 
49 void WadseekerWadsTable::addFile(const QString& filename)
50 {
51  // Add new row to table, but only if file is not yet added.
52  if (findFileRow(filename) < 0)
53  {
54  insertRow(rowCount());
55  int rowIndex = rowCount() - 1;
56 
57  // Create the row contents.
58  setSortingEnabled(false);
59 
60  QProgressBar* pBar = new QProgressBar();
61  pBar->setAlignment(Qt::AlignCenter);
62 
63  setItem(rowIndex, IDX_NAME_COLUMN, new QTableWidgetItem(filename));
64  setItem(rowIndex, IDX_URL_COLUMN, new QTableWidgetItem());
65  setCellWidget(rowIndex, IDX_PROGRESS_COLUMN, pBar);
66  setItem(rowIndex, IDX_SPEED_COLUMN, new QTableWidgetItem());
67  setItem(rowIndex, IDX_ETA_COLUMN, new QTableWidgetItem(tr("N/A")));
68  setItem(rowIndex, IDX_SIZE_COLUMN, new QTableWidgetItem(tr("N/A")));
69 
70  SpeedCalculator* pCalculator = new SpeedCalculator();
71  pCalculator->start();
72 
73  d.speedCalculators.insert(filename, pCalculator);
74 
75  setSortingEnabled(true);
76  }
77 }
78 
79 WadseekerWadsTable::ContextMenu* WadseekerWadsTable::contextMenu(const QModelIndex& index, const QPoint& cursorPosition)
80 {
81  WadseekerWadsTable::ContextMenu* menu = new ContextMenu(this);
82  QPoint displayPoint = this->viewport()->mapToGlobal(cursorPosition);
83  menu->move(displayPoint);
84 
85  if (!index.isValid())
86  {
87  menu->actionSkipCurrentSite->setEnabled(false);
88  }
89 
90  return menu;
91 }
92 
94 {
95  if (row < 0 || row >= this->rowCount())
96  {
97  return -1;
98  }
99 
100  QString fileName = fileNameAtRow(row);
101  return d.speedCalculators[fileName]->expectedDataSize();
102 }
103 
104 QString WadseekerWadsTable::fileNameAtRow(int row) const
105 {
106  if (row < 0 || row >= this->rowCount())
107  {
108  return QString();
109  }
110 
111  return item(row, IDX_NAME_COLUMN)->text();
112 }
113 
114 int WadseekerWadsTable::findFileRow(const QString& filename)
115 {
116  QList<QTableWidgetItem *> list = findItems(filename, Qt::MatchFixedString);
117  if (!list.isEmpty())
118  {
119  return list.first()->row();
120  }
121 
122  return -1;
123 }
124 
125 void WadseekerWadsTable::setFileDownloadFinished(const QString& filename)
126 {
127  int row = findFileRow(filename);
128 
129  if (row >= 0)
130  {
131  // Update ETA
132  // ETA will be changed to DONE if wad is installed successfully.
133  item(row, IDX_ETA_COLUMN)->setText(tr("N/A"));
134  item(row, IDX_SPEED_COLUMN)->setText(tr("N/A"));
135 
136  item(row, IDX_URL_COLUMN)->setText(tr("Awaiting URLs"));
137  item(row, IDX_URL_COLUMN)->setToolTip(tr("Awaiting URLs"));
138 
139  const bool FORCE = true;
140  updateDataInfoValues(FORCE);
141  }
142 }
143 
144 void WadseekerWadsTable::setFileFailed(const QString& filename)
145 {
146  int row = findFileRow(filename);
147 
148  if (row >= 0)
149  {
150  item(row, IDX_NAME_COLUMN)->setIcon(QIcon(":/icons/x.png"));
151 
152  item(row, IDX_URL_COLUMN)->setText("");
153  }
154 }
155 
156 void WadseekerWadsTable::setFileProgress(const QString& filename, qint64 current, qint64 total)
157 {
158  int row = findFileRow(filename);
159 
160  if (row >= 0)
161  {
162  QProgressBar* pBar = (QProgressBar*) this->cellWidget(row, IDX_PROGRESS_COLUMN);
163  pBar->setMaximum(total);
164  pBar->setValue(current);
165 
166  // Update ETA and speed
167  SpeedCalculator* pCalculator = d.speedCalculators.value(filename);
168  pCalculator->setExpectedDataSize(total);
169  pCalculator->registerDataAmount(current);
170 
171  const bool FORCE = true;
172  updateDataInfoValues(!FORCE);
173  }
174 }
175 
176 void WadseekerWadsTable::setFileSuccessful(const QString& filename)
177 {
178  int row = findFileRow(filename);
179 
180  if (row >= 0)
181  {
182  // Set progress bar to 100%.
183  QProgressBar* pBar = (QProgressBar*) this->cellWidget(row, IDX_PROGRESS_COLUMN);
184  SpeedCalculator* pCalculator = d.speedCalculators[filename];
185  if (pCalculator->expectedDataSize() == 0)
186  {
187  pCalculator->setExpectedDataSize(1);
188  }
189 
190  pCalculator->registerDataAmount(pCalculator->expectedDataSize());
191 
192  pBar->setMaximum(pCalculator->expectedDataSize());
193  pBar->setValue(pCalculator->expectedDataSize());
194 
195  item(row, IDX_NAME_COLUMN)->setIcon(QIcon(":/icons/ok.png"));
196  item(row, IDX_URL_COLUMN)->setText("");
197 
198  item(row, IDX_ETA_COLUMN)->setText(tr("Done"));
199  item(row, IDX_SPEED_COLUMN)->setText("");
200 
201  const bool FORCE = true;
202  updateDataInfoValues(FORCE);
203  }
204 }
205 
206 void WadseekerWadsTable::setFileUrl(const QString& filename, const QUrl& url)
207 {
208  // At this point we know that a new download has sstarted.
209  // We should reset certain values.
210  int row = findFileRow(filename);
211 
212  if (row >= 0)
213  {
214  QTableWidgetItem* pItem = this->item(row, IDX_URL_COLUMN);
215  pItem->setText(url.toString());
216  pItem->setToolTip(url.toString());
217 
218  QProgressBar* pBar = (QProgressBar*) this->cellWidget(row, IDX_PROGRESS_COLUMN);
219  pBar->setMaximum(0);
220  pBar->setValue(0);
221 
222  SpeedCalculator* pCalculator = d.speedCalculators[filename];
223  pCalculator->start();
224  }
225 }
226 
227 void WadseekerWadsTable::showEvent(QShowEvent* pEvent)
228 {
229  if (!d.bAlreadyShownOnce)
230  {
231  // Events in this block must occur after the widget has been
232  // constructed, but only once.
233  QHeaderView* pHeader = horizontalHeader();
234 
235  // Setup resizing
236 #if QT_VERSION >= 0x050000
237  pHeader->setSectionResizeMode(IDX_URL_COLUMN, QHeaderView::Stretch);
238 #else
239  pHeader->setResizeMode(IDX_URL_COLUMN, QHeaderView::Stretch);
240 #endif
241 
242  pHeader->resizeSection(IDX_NAME_COLUMN, 140);
243  pHeader->resizeSection(IDX_PROGRESS_COLUMN, 85);
244  pHeader->resizeSection(IDX_ETA_COLUMN, 85);
245  pHeader->resizeSection(IDX_SIZE_COLUMN, 150);
246  pHeader->resizeSection(IDX_SPEED_COLUMN, 85);
247 
248  }
249 }
250 
252 {
253  double sumDownloadPercentages = 0.0;
254 
255  if (this->rowCount() == 0)
256  {
257  return -1.0;
258  }
259 
260  for (int i = 0; i < this->rowCount(); ++i)
261  {
262  const QProgressBar* pBar = (const QProgressBar*) this->cellWidget(i, IDX_PROGRESS_COLUMN);
263  if (pBar != NULL)
264  {
265  int val = pBar->value();
266  int max = pBar->maximum();
267 
268  if (max > 0)
269  {
270  double curPercentage = (double) val / (double) max;
271  sumDownloadPercentages += curPercentage;
272  }
273  }
274  }
275 
276  // We need to multiply the value by 100 to get actual percents.
277  sumDownloadPercentages *= 100.0;
278  double averageDownloadPercentages = sumDownloadPercentages / (double) this->rowCount();
279 
280  return averageDownloadPercentages;
281 }
282 
283 void WadseekerWadsTable::updateDataInfoValues(bool bForce)
284 {
285  // Make sure updates are not performed before certain interval passes.
286  if (d.updateClock.elapsed() > UPDATE_INTERVAL_MS || bForce)
287  {
288  d.updateClock.start();
289 
290  for (int i = 0; i < this->rowCount(); ++i)
291  {
292  // Find the calculator for specified row.
293  QString filename = this->item(i, IDX_NAME_COLUMN)->text();
294  SpeedCalculator* pCalculator = d.speedCalculators.value(filename);
295 
296  // Update data amount.
297  QString strCurrent = Strings::formatDataAmount(pCalculator->lastRegisterAttemptedDataAmount());
298  QString strTotal = Strings::formatDataAmount(pCalculator->expectedDataSize());
299 
300  QString size = QString("%1 / %2").arg(strCurrent, strTotal);
301  item(i, IDX_SIZE_COLUMN)->setText(size);
302 
303  // Update ETA and speed.
304  if (pCalculator->expectedDataSize() != pCalculator->lastRegisterAttemptedDataAmount())
305  {
306  // If both above values are equal it means we have either
307  // finished the download or didn't start it yet. In either case
308  // we shouldn't change the speed and ETA displays.
309  long double ldEta = pCalculator->estimatedTimeUntilArrival();
310  long double ldSpeed = pCalculator->getSpeed();
311 
312  if (ldEta >= 0.0)
313  {
314  QString strEta = Strings::formatTime(pCalculator->estimatedTimeUntilArrival());
315  item(i, IDX_ETA_COLUMN)->setText(strEta);
316  }
317  else
318  {
319  item(i, IDX_ETA_COLUMN)->setText(tr("N/A"));
320  }
321 
322  if (ldSpeed >= 0.0)
323  {
324  QString strSpeed = Strings::formatDataSpeed(pCalculator->getSpeed());
325  item(i, IDX_SPEED_COLUMN)->setText(strSpeed);
326  }
327  else
328  {
329  item(i, IDX_SPEED_COLUMN)->setText(tr("N/A"));
330  }
331  }
332  }
333  }
334 }
336 WadseekerWadsTable::ContextMenu::ContextMenu(QWidget* pParent)
337 : QMenu(pParent)
338 {
339  this->actionSkipCurrentSite = new QAction(tr("Skip current URL"), this);
340 
341  this->addAction(this->actionSkipCurrentSite);
342 }
void setFileUrl(const QString &filename, const QUrl &url)
Fired when new URL starts for specified file.
qint64 expectedDataSize(int row) const
Total size of data in bytes for specified row.
void start()
Clears all values. Prepares SpeedCalculator for new speed measure.
static QString formatTime(float seconds)
Formats a numerical time value into a string.
Definition: strings.cpp:286
double totalDonePercentage() const
Total done percentage calculated basing on the data set by siteFileProgress().
void registerDataAmount(qint64 totalAmountOfArrivedData)
Register new total amount of data.
long double getSpeed() const
In bytes per second.
void setExpectedDataSize(qint64 size)
Maximum expected size of the data.
static QString formatDataAmount(qint64 bytes)
Similar to formatDataSpeed().
Definition: strings.cpp:219
static QString formatDataSpeed(float speedInBytesPerSecond)
Formats a numerical speed value into a string.
Definition: strings.cpp:253
qint64 lastRegisterAttemptedDataAmount() const
Last amount of data that was passed to registerDataAmount()
long double estimatedTimeUntilArrival() const
In seconds.