wadseekerwadstable.cpp
1 //------------------------------------------------------------------------------
2 // wadseekerwadstable.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program 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
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; 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.h"
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  pHeader->setResizeMode(IDX_URL_COLUMN, QHeaderView::Stretch);
237 
238  pHeader->resizeSection(IDX_NAME_COLUMN, 140);
239  pHeader->resizeSection(IDX_PROGRESS_COLUMN, 85);
240  pHeader->resizeSection(IDX_ETA_COLUMN, 85);
241  pHeader->resizeSection(IDX_SIZE_COLUMN, 150);
242  pHeader->resizeSection(IDX_SPEED_COLUMN, 85);
243 
244  }
245 }
246 
248 {
249  double sumDownloadPercentages = 0.0;
250 
251  if (this->rowCount() == 0)
252  {
253  return -1.0;
254  }
255 
256  for (int i = 0; i < this->rowCount(); ++i)
257  {
258  const QProgressBar* pBar = (const QProgressBar*) this->cellWidget(i, IDX_PROGRESS_COLUMN);
259  if (pBar != NULL)
260  {
261  int val = pBar->value();
262  int max = pBar->maximum();
263 
264  if (max > 0)
265  {
266  double curPercentage = (double) val / (double) max;
267  sumDownloadPercentages += curPercentage;
268  }
269  }
270  }
271 
272  // We need to multiply the value by 100 to get actual percents.
273  sumDownloadPercentages *= 100.0;
274  double averageDownloadPercentages = sumDownloadPercentages / (double) this->rowCount();
275 
276  return averageDownloadPercentages;
277 }
278 
279 void WadseekerWadsTable::updateDataInfoValues(bool bForce)
280 {
281  // Make sure updates are not performed before certain interval passes.
282  if (d.updateClock.elapsed() > UPDATE_INTERVAL_MS || bForce)
283  {
284  d.updateClock.start();
285 
286  for (int i = 0; i < this->rowCount(); ++i)
287  {
288  // Find the calculator for specified row.
289  QString filename = this->item(i, IDX_NAME_COLUMN)->text();
290  SpeedCalculator* pCalculator = d.speedCalculators.value(filename);
291 
292  // Update data amount.
293  QString strCurrent = Strings::formatDataAmount(pCalculator->lastRegisterAttemptedDataAmount());
294  QString strTotal = Strings::formatDataAmount(pCalculator->expectedDataSize());
295 
296  QString size = QString("%1 / %2").arg(strCurrent, strTotal);
297  item(i, IDX_SIZE_COLUMN)->setText(size);
298 
299  // Update ETA and speed.
300  if (pCalculator->expectedDataSize() != pCalculator->lastRegisterAttemptedDataAmount())
301  {
302  // If both above values are equal it means we have either
303  // finished the download or didn't start it yet. In either case
304  // we shouldn't change the speed and ETA displays.
305  long double ldEta = pCalculator->estimatedTimeUntilArrival();
306  long double ldSpeed = pCalculator->getSpeed();
307 
308  if (ldEta >= 0.0)
309  {
310  QString strEta = Strings::formatTime(pCalculator->estimatedTimeUntilArrival());
311  item(i, IDX_ETA_COLUMN)->setText(strEta);
312  }
313  else
314  {
315  item(i, IDX_ETA_COLUMN)->setText(tr("N/A"));
316  }
317 
318  if (ldSpeed >= 0.0)
319  {
320  QString strSpeed = Strings::formatDataSpeed(pCalculator->getSpeed());
321  item(i, IDX_SPEED_COLUMN)->setText(strSpeed);
322  }
323  else
324  {
325  item(i, IDX_SPEED_COLUMN)->setText(tr("N/A"));
326  }
327  }
328  }
329  }
330 }
332 WadseekerWadsTable::ContextMenu::ContextMenu(QWidget* pParent)
333 : QMenu(pParent)
334 {
335  this->actionSkipCurrentSite = new QAction(tr("Skip current URL"), this);
336 
337  this->addAction(this->actionSkipCurrentSite);
338 }
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:284
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:217
static QString formatDataSpeed(float speedInBytesPerSecond)
Formats a numerical speed value into a string.
Definition: strings.cpp:251
qint64 lastRegisterAttemptedDataAmount() const
Last amount of data that was passed to registerDataAmount()
long double estimatedTimeUntilArrival() const
In seconds.