Falkon Develop
Cross-platform Qt-based web browser
downloaditem.cpp
Go to the documentation of this file.
1/* ============================================================
2* Falkon - Qt web browser
3* Copyright (C) 2010-2018 David Rosca <nowrep@gmail.com>
4*
5* This program is free software: you can redistribute it and/or modify
6* it under the terms of the GNU General Public License as published by
7* the Free Software Foundation, either version 3 of the License, or
8* (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, see <http://www.gnu.org/licenses/>.
17* ============================================================ */
18#include "downloaditem.h"
19#include "ui_downloaditem.h"
20#include "mainapplication.h"
21#include "browserwindow.h"
22#include "tabwidget.h"
23#include "webpage.h"
24#include "downloadmanager.h"
25#include "networkmanager.h"
26#include "qztools.h"
27#include "datapaths.h"
28
29#include <QMenu>
30#include <QClipboard>
31#include <QLocale>
32#include <QListWidgetItem>
33#include <QMouseEvent>
34#include <QTimer>
35#include <QFileInfo>
36#include <QMessageBox>
37#include <QFileIconProvider>
38#include <QDesktopServices>
39#include <QWebEngineDownloadRequest>
40#include <QtWebEngineWidgetsVersion>
41
42#ifdef Q_OS_WIN
43#include "Shlwapi.h"
44#include "shellapi.h"
45#endif
46
47//#define DOWNMANAGER_DEBUG
48
49DownloadItem::DownloadItem(QListWidgetItem *item, QWebEngineDownloadRequest* downloadItem, const QString &path, const QString &fileName, bool openFile, DownloadManager* manager)
50 : QWidget()
51 , ui(new Ui::DownloadItem)
52 , m_item(item)
53 , m_download(downloadItem)
54 , m_path(path)
55 , m_fileName(fileName)
56 , m_downUrl(downloadItem->url())
57 , m_openFile(openFile)
58 , m_downloading(false)
59 , m_downloadStopped(false)
60 , m_currSpeed(0)
61 , m_received(downloadItem->receivedBytes())
62 , m_total(downloadItem->totalBytes())
63{
64#ifdef DOWNMANAGER_DEBUG
65 qDebug() << __FUNCTION__ << item << reply << path << fileName;
66#endif
67
68 ui->setupUi(this);
69 setMaximumWidth(525);
70
71 ui->cancelButton->setPixmap(QIcon::fromTheme(QSL("process-stop")).pixmap(20, 20));
72 ui->pauseResumeButton->setPixmap(QIcon::fromTheme(QSL("media-playback-pause")).pixmap(20, 20));
73 ui->fileName->setText(m_fileName);
74 ui->downloadInfo->setText(tr("Remaining time unavailable"));
75
76 setContextMenuPolicy(Qt::CustomContextMenu);
77 connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(customContextMenuRequested(QPoint)));
78 connect(ui->cancelButton, &ClickableLabel::clicked, this, &DownloadItem::stop);
79 connect(ui->pauseResumeButton, &ClickableLabel::clicked, this, &DownloadItem::pauseResume);
80 connect(manager, &DownloadManager::resized, this, &DownloadItem::parentResized);
81}
82
84{
85 connect(m_download, &QWebEngineDownloadRequest::isFinishedChanged, this, &DownloadItem::finished);
86 connect(m_download, &QWebEngineDownloadRequest::receivedBytesChanged, this, &DownloadItem::receivedOrTotalBytesChanged);
87 connect(m_download, &QWebEngineDownloadRequest::totalBytesChanged, this, &DownloadItem::receivedOrTotalBytesChanged);
88
89 m_downloading = true;
90 if (!m_downTimer.isValid()) {
91 m_downTimer.start();
92 }
93
94 updateDownloadInfo(0, m_download->receivedBytes(), m_download->totalBytes());
95
96#ifdef Q_OS_LINUX
97 // QFileIconProvider uses only suffix on Linux
98 QFileIconProvider iconProvider;
99 QIcon fileIcon = iconProvider.icon(QFileInfo(m_fileName));
100 if (!fileIcon.isNull()) {
101 ui->fileIcon->setPixmap(fileIcon.pixmap(30));
102 } else {
103 ui->fileIcon->setPixmap(style()->standardIcon(QStyle::SP_FileIcon).pixmap(30));
104 }
105#else
106 ui->fileIcon->hide();
107#endif
108}
109
110void DownloadItem::parentResized(const QSize &size)
111{
112 if (size.width() < 200) {
113 return;
114 }
115 setMaximumWidth(size.width());
116}
117
118void DownloadItem::finished()
119{
120#ifdef DOWNMANAGER_DEBUG
121 qDebug() << __FUNCTION__ << m_reply;
122#endif
123
124 bool success = false;
125 QString host = m_download->url().host();
126
127 switch (m_download->state()) {
128 case QWebEngineDownloadRequest::DownloadCompleted:
129 success = true;
130 ui->downloadInfo->setText(tr("Done - %1 (%2)").arg(host, QLocale().toString(QDateTime::currentDateTime(), QLocale::ShortFormat)));
131 break;
132
133 case QWebEngineDownloadRequest::DownloadInterrupted:
134 ui->downloadInfo->setText(tr("Error - %1").arg(host));
135 break;
136
137 case QWebEngineDownloadRequest::DownloadCancelled:
138 ui->downloadInfo->setText(tr("Cancelled - %1").arg(host));
139 break;
140
141 default:
142 break;
143 }
144
145 ui->progressBar->hide();
146 ui->cancelButton->hide();
147 ui->pauseResumeButton->hide();
148 ui->frame->hide();
149
150 m_item->setSizeHint(sizeHint());
151 m_downloading = false;
152
153 if (success && m_openFile)
154 openFile();
155
156 Q_EMIT downloadFinished(true);
157}
158
159void DownloadItem::receivedOrTotalBytesChanged()
160{
161 qint64 received = m_download->receivedBytes();
162 qint64 total = m_download->totalBytes();
163#ifdef DOWNMANAGER_DEBUG
164 qDebug() << __FUNCTION__ << received << total;
165#endif
166 qint64 currentValue = 0;
167 qint64 totalValue = 0;
168 if (total > 0) {
169 currentValue = received * 100 / total;
170 totalValue = 100;
171 }
172 ui->progressBar->setValue(currentValue);
173 ui->progressBar->setMaximum(totalValue);
174 m_currSpeed = received * 1000.0 / m_downTimer.elapsed();
175 m_received = received;
176 m_total = total;
177
178 updateDownloadInfo(m_currSpeed, m_received, m_total);
179 Q_EMIT progressChanged(m_currSpeed, m_received, m_total);
180}
181
183{
184 return ui->progressBar->value();
185}
186
188{
189 return ui->downloadInfo->text().startsWith(tr("Cancelled"));
190}
191
193{
194 if (time < QTime(0, 0, 10)) {
195 return tr("few seconds");
196 }
197 else if (time < QTime(0, 1)) {
198 //~ singular %n second
199 //~ plural %n seconds
200 return tr("%n seconds", "", time.second());
201 }
202 else if (time < QTime(1, 0)) {
203 //~ singular %n minute
204 //~ plural %n minutes
205 return tr("%n minutes", "", time.minute());
206 }
207 else {
208 //~ singular %n hour
209 //~ plural %n hours
210 return tr("%n hours", "", time.hour());
211 }
212}
213
215{
216 if (speed < 0) {
217 return tr("Unknown speed");
218 }
219
220 QLocale locale;
221 speed /= 1024; // kB
222 if (speed < 1000) {
223 return tr("%1 kB/s").arg(locale.toString(speed, 'f', 0));
224 }
225
226 speed /= 1024; //MB
227 if (speed < 1000) {
228 return tr("%1 MB/s").arg(locale.toString(speed, 'f', 2));
229 }
230
231 speed /= 1024; //GB
232 return tr("%1 GB/s").arg(locale.toString(speed, 'f', 2));
233}
234
235void DownloadItem::updateDownloadInfo(double currSpeed, qint64 received, qint64 total)
236{
237#ifdef DOWNMANAGER_DEBUG
238 qDebug() << __FUNCTION__ << currSpeed << received << total;
239#endif
240 // QString QString QString QString
241 // | m_remTime | |m_currSize| |m_fileSize| |m_speed|
242 // Remaining 26 minutes - 339MB of 693 MB (350kB/s)
243
244 if (m_download->isPaused()) {
245 return;
246 }
247
248 int estimatedTime = ((total - received) / 1024) / (currSpeed / 1024);
249 QString speed = currentSpeedToString(currSpeed);
250 // We have QString speed now
251
252 QTime time(0, 0, 0);
253 time = time.addSecs(estimatedTime);
254 QString remTime = remaingTimeToString(time);
255 m_remTime = time;
256
257 QString currSize = QzTools::fileSizeToString(received);
258 QString fileSize = QzTools::fileSizeToString(total);
259
260 if (fileSize == tr("Unknown size")) {
261 ui->downloadInfo->setText(tr("%2 - unknown size (%3)").arg(currSize, speed));
262 }
263 else {
264 ui->downloadInfo->setText(tr("Remaining %1 - %2 of %3 (%4)").arg(remTime, currSize, fileSize, speed));
265 }
266}
267
268void DownloadItem::stop()
269{
270#ifdef DOWNMANAGER_DEBUG
271 qDebug() << __FUNCTION__;
272#endif
273 if (m_downloadStopped) {
274 return;
275 }
276 m_downloadStopped = true;
277 ui->progressBar->hide();
278 ui->cancelButton->hide();
279 ui->pauseResumeButton->hide();
280 m_item->setSizeHint(sizeHint());
281 ui->downloadInfo->setText(tr("Cancelled - %1").arg(m_download->url().host()));
282 m_download->cancel();
283 m_downloading = false;
284
285 Q_EMIT downloadFinished(false);
286}
287
288void DownloadItem::pauseResume()
289{
290 if (m_download->isPaused()) {
291 m_download->resume();
292 ui->pauseResumeButton->setPixmap(QIcon::fromTheme(QSL("media-playback-pause")).pixmap(20, 20));
293 } else {
294 m_download->pause();
295 ui->pauseResumeButton->setPixmap(QIcon::fromTheme(QSL("media-playback-start")).pixmap(20, 20));
296 ui->downloadInfo->setText(tr("Paused - %1").arg(m_download->url().host()));
297 }
298}
299
300void DownloadItem::mouseDoubleClickEvent(QMouseEvent* e)
301{
302 openFile();
303 e->accept();
304}
305
306void DownloadItem::customContextMenuRequested(const QPoint &pos)
307{
308 QMenu menu;
309 menu.addAction(QIcon::fromTheme(QSL("document-open")), tr("Open File"), this, &DownloadItem::openFile);
310
311 menu.addAction(tr("Open Folder"), this, &DownloadItem::openFolder);
312 menu.addSeparator();
313 menu.addAction(QIcon::fromTheme(QSL("edit-copy")), tr("Copy Download Link"), this, &DownloadItem::copyDownloadLink);
314 menu.addSeparator();
315 menu.addAction(QIcon::fromTheme(QSL("process-stop")), tr("Cancel downloading"), this, &DownloadItem::stop)->setEnabled(m_downloading);
316
317 if (m_download->isPaused()) {
318 menu.addAction(QIcon::fromTheme(QSL("media-playback-start")), tr("Resume downloading"), this, &DownloadItem::pauseResume)->setEnabled(m_downloading);
319 } else {
320 menu.addAction(QIcon::fromTheme(QSL("media-playback-pause")), tr("Pause downloading"), this, &DownloadItem::pauseResume)->setEnabled(m_downloading);
321 }
322
323 menu.addAction(QIcon::fromTheme(QSL("list-remove")), tr("Remove From List"), this, &DownloadItem::clear)->setEnabled(!m_downloading);
324
325 if (m_downloading || ui->downloadInfo->text().startsWith(tr("Cancelled")) || ui->downloadInfo->text().startsWith(tr("Error"))) {
326 menu.actions().at(0)->setEnabled(false);
327 }
328 menu.exec(mapToGlobal(pos));
329}
330
331void DownloadItem::copyDownloadLink()
332{
333 QApplication::clipboard()->setText(m_downUrl.toString());
334}
335
336void DownloadItem::clear()
337{
338 Q_EMIT deleteItem(this);
339}
340
341void DownloadItem::openFile()
342{
343 if (m_downloading) {
344 return;
345 }
346 QFileInfo info(m_path, m_fileName);
347 if (info.exists()) {
348 QDesktopServices::openUrl(QUrl::fromLocalFile(info.absoluteFilePath()));
349 }
350 else {
351 QMessageBox::warning(m_item->listWidget()->parentWidget(), tr("Not found"), tr("Sorry, the file \n %1 \n was not found!").arg(info.absoluteFilePath()));
352 }
353}
354
355void DownloadItem::openFolder()
356{
357#ifdef Q_OS_WIN
358 QString winFileName = QSL("%1/%2").arg(m_path, m_fileName);
359
360 if (m_downloading) {
361 winFileName.append(QSL(".download"));
362 }
363
364 winFileName.replace(QLatin1Char('/'), QSL("\\"));
365 QString shExArg = QSL("/e,/select,\"") + winFileName + QSL("\"");
366 ShellExecute(NULL, NULL, TEXT("explorer.exe"), shExArg.toStdWString().c_str(), NULL, SW_SHOW);
367#else
368 QDesktopServices::openUrl(QUrl::fromLocalFile(m_path));
369#endif
370}
371
373{
374 return m_downUrl;
375}
376
377QString DownloadItem::path() const
378{
379 return m_path;
380}
381
383{
384 return m_fileName;
385}
386
388{
389 delete ui;
390 delete m_item;
391}
void clicked(QPoint)
QString fileName() const
static QString remaingTimeToString(QTime time)
DownloadItem(QListWidgetItem *item, QWebEngineDownloadRequest *downloadItem, const QString &path, const QString &fileName, bool openFile, DownloadManager *manager)
QString path() const
void startDownloading()
static QString currentSpeedToString(double speed)
bool isCancelled()
void downloadFinished(bool success)
void deleteItem(DownloadItem *)
QUrl url() const
void progressChanged(double currSpeed, qint64 received, qint64 total)
~DownloadItem() override
void resized(QSize)
static QString fileSizeToString(qint64 size)
Definition: qztools.cpp:376
locale
Definition: i18n.py:21
#define QSL(x)
Definition: qzcommon.h:40