File indexing completed on 2024-05-12 04:58:05
0001 /* ============================================================ 0002 * Falkon - Qt web browser 0003 * Copyright (C) 2010-2018 David Rosca <nowrep@gmail.com> 0004 * 0005 * This program is free software: you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation, either version 3 of the License, or 0008 * (at your option) any later version. 0009 * 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU General Public License 0016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0017 * ============================================================ */ 0018 #include "downloaditem.h" 0019 #include "ui_downloaditem.h" 0020 #include "mainapplication.h" 0021 #include "browserwindow.h" 0022 #include "tabwidget.h" 0023 #include "webpage.h" 0024 #include "downloadmanager.h" 0025 #include "networkmanager.h" 0026 #include "qztools.h" 0027 #include "datapaths.h" 0028 0029 #include <QMenu> 0030 #include <QClipboard> 0031 #include <QListWidgetItem> 0032 #include <QMouseEvent> 0033 #include <QTimer> 0034 #include <QFileInfo> 0035 #include <QMessageBox> 0036 #include <QFileIconProvider> 0037 #include <QDesktopServices> 0038 #include <QWebEngineDownloadRequest> 0039 #include <QtWebEngineWidgetsVersion> 0040 0041 #ifdef Q_OS_WIN 0042 #include "Shlwapi.h" 0043 #include "shellapi.h" 0044 #endif 0045 0046 //#define DOWNMANAGER_DEBUG 0047 0048 DownloadItem::DownloadItem(QListWidgetItem *item, QWebEngineDownloadRequest* downloadItem, const QString &path, const QString &fileName, bool openFile, DownloadManager* manager) 0049 : QWidget() 0050 , ui(new Ui::DownloadItem) 0051 , m_item(item) 0052 , m_download(downloadItem) 0053 , m_path(path) 0054 , m_fileName(fileName) 0055 , m_downUrl(downloadItem->url()) 0056 , m_openFile(openFile) 0057 , m_downloading(false) 0058 , m_downloadStopped(false) 0059 , m_currSpeed(0) 0060 , m_received(downloadItem->receivedBytes()) 0061 , m_total(downloadItem->totalBytes()) 0062 { 0063 #ifdef DOWNMANAGER_DEBUG 0064 qDebug() << __FUNCTION__ << item << reply << path << fileName; 0065 #endif 0066 0067 ui->setupUi(this); 0068 setMaximumWidth(525); 0069 0070 ui->cancelButton->setPixmap(QIcon::fromTheme(QSL("process-stop")).pixmap(20, 20)); 0071 ui->pauseResumeButton->setPixmap(QIcon::fromTheme(QSL("media-playback-pause")).pixmap(20, 20)); 0072 ui->fileName->setText(m_fileName); 0073 ui->downloadInfo->setText(tr("Remaining time unavailable")); 0074 0075 setContextMenuPolicy(Qt::CustomContextMenu); 0076 connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(customContextMenuRequested(QPoint))); 0077 connect(ui->cancelButton, &ClickableLabel::clicked, this, &DownloadItem::stop); 0078 connect(ui->pauseResumeButton, &ClickableLabel::clicked, this, &DownloadItem::pauseResume); 0079 connect(manager, &DownloadManager::resized, this, &DownloadItem::parentResized); 0080 } 0081 0082 void DownloadItem::startDownloading() 0083 { 0084 connect(m_download, &QWebEngineDownloadRequest::isFinishedChanged, this, &DownloadItem::finished); 0085 connect(m_download, &QWebEngineDownloadRequest::receivedBytesChanged, this, &DownloadItem::receivedOrTotalBytesChanged); 0086 connect(m_download, &QWebEngineDownloadRequest::totalBytesChanged, this, &DownloadItem::receivedOrTotalBytesChanged); 0087 0088 m_downloading = true; 0089 if (!m_downTimer.isValid()) { 0090 m_downTimer.start(); 0091 } 0092 0093 updateDownloadInfo(0, m_download->receivedBytes(), m_download->totalBytes()); 0094 0095 #ifdef Q_OS_LINUX 0096 // QFileIconProvider uses only suffix on Linux 0097 QFileIconProvider iconProvider; 0098 QIcon fileIcon = iconProvider.icon(QFileInfo(m_fileName)); 0099 if (!fileIcon.isNull()) { 0100 ui->fileIcon->setPixmap(fileIcon.pixmap(30)); 0101 } else { 0102 ui->fileIcon->setPixmap(style()->standardIcon(QStyle::SP_FileIcon).pixmap(30)); 0103 } 0104 #else 0105 ui->fileIcon->hide(); 0106 #endif 0107 } 0108 0109 void DownloadItem::parentResized(const QSize &size) 0110 { 0111 if (size.width() < 200) { 0112 return; 0113 } 0114 setMaximumWidth(size.width()); 0115 } 0116 0117 void DownloadItem::finished() 0118 { 0119 #ifdef DOWNMANAGER_DEBUG 0120 qDebug() << __FUNCTION__ << m_reply; 0121 #endif 0122 0123 bool success = false; 0124 QString host = m_download->url().host(); 0125 0126 switch (m_download->state()) { 0127 case QWebEngineDownloadRequest::DownloadCompleted: 0128 success = true; 0129 ui->downloadInfo->setText(tr("Done - %1 (%2)").arg(host, QLocale().toString(QDateTime::currentDateTime(), QLocale::ShortFormat))); 0130 break; 0131 0132 case QWebEngineDownloadRequest::DownloadInterrupted: 0133 ui->downloadInfo->setText(tr("Error - %1").arg(host)); 0134 break; 0135 0136 case QWebEngineDownloadRequest::DownloadCancelled: 0137 ui->downloadInfo->setText(tr("Cancelled - %1").arg(host)); 0138 break; 0139 0140 default: 0141 break; 0142 } 0143 0144 ui->progressBar->hide(); 0145 ui->cancelButton->hide(); 0146 ui->pauseResumeButton->hide(); 0147 ui->frame->hide(); 0148 0149 m_item->setSizeHint(sizeHint()); 0150 m_downloading = false; 0151 0152 if (success && m_openFile) 0153 openFile(); 0154 0155 Q_EMIT downloadFinished(true); 0156 } 0157 0158 void DownloadItem::receivedOrTotalBytesChanged() 0159 { 0160 qint64 received = m_download->receivedBytes(); 0161 qint64 total = m_download->totalBytes(); 0162 #ifdef DOWNMANAGER_DEBUG 0163 qDebug() << __FUNCTION__ << received << total; 0164 #endif 0165 qint64 currentValue = 0; 0166 qint64 totalValue = 0; 0167 if (total > 0) { 0168 currentValue = received * 100 / total; 0169 totalValue = 100; 0170 } 0171 ui->progressBar->setValue(currentValue); 0172 ui->progressBar->setMaximum(totalValue); 0173 m_currSpeed = received * 1000.0 / m_downTimer.elapsed(); 0174 m_received = received; 0175 m_total = total; 0176 0177 updateDownloadInfo(m_currSpeed, m_received, m_total); 0178 Q_EMIT progressChanged(m_currSpeed, m_received, m_total); 0179 } 0180 0181 int DownloadItem::progress() 0182 { 0183 return ui->progressBar->value(); 0184 } 0185 0186 bool DownloadItem::isCancelled() 0187 { 0188 return ui->downloadInfo->text().startsWith(tr("Cancelled")); 0189 } 0190 0191 QString DownloadItem::remaingTimeToString(QTime time) 0192 { 0193 if (time < QTime(0, 0, 10)) { 0194 return tr("few seconds"); 0195 } 0196 else if (time < QTime(0, 1)) { 0197 //~ singular %n second 0198 //~ plural %n seconds 0199 return tr("%n seconds", "", time.second()); 0200 } 0201 else if (time < QTime(1, 0)) { 0202 //~ singular %n minute 0203 //~ plural %n minutes 0204 return tr("%n minutes", "", time.minute()); 0205 } 0206 else { 0207 //~ singular %n hour 0208 //~ plural %n hours 0209 return tr("%n hours", "", time.hour()); 0210 } 0211 } 0212 0213 QString DownloadItem::currentSpeedToString(double speed) 0214 { 0215 if (speed < 0) { 0216 return tr("Unknown speed"); 0217 } 0218 0219 speed /= 1024; // kB 0220 if (speed < 1000) { 0221 return QString::number(speed, 'f', 0) + QLatin1String(" ") + tr("kB/s"); 0222 } 0223 0224 speed /= 1024; //MB 0225 if (speed < 1000) { 0226 return QString::number(speed, 'f', 2) + QLatin1String(" ") + tr("MB/s"); 0227 } 0228 0229 speed /= 1024; //GB 0230 return QString::number(speed, 'f', 2) + QLatin1String(" ") + tr("GB/s"); 0231 } 0232 0233 void DownloadItem::updateDownloadInfo(double currSpeed, qint64 received, qint64 total) 0234 { 0235 #ifdef DOWNMANAGER_DEBUG 0236 qDebug() << __FUNCTION__ << currSpeed << received << total; 0237 #endif 0238 // QString QString QString QString 0239 // | m_remTime | |m_currSize| |m_fileSize| |m_speed| 0240 // Remaining 26 minutes - 339MB of 693 MB (350kB/s) 0241 0242 if (m_download->isPaused()) { 0243 return; 0244 } 0245 0246 int estimatedTime = ((total - received) / 1024) / (currSpeed / 1024); 0247 QString speed = currentSpeedToString(currSpeed); 0248 // We have QString speed now 0249 0250 QTime time(0, 0, 0); 0251 time = time.addSecs(estimatedTime); 0252 QString remTime = remaingTimeToString(time); 0253 m_remTime = time; 0254 0255 QString currSize = QzTools::fileSizeToString(received); 0256 QString fileSize = QzTools::fileSizeToString(total); 0257 0258 if (fileSize == tr("Unknown size")) { 0259 ui->downloadInfo->setText(tr("%2 - unknown size (%3)").arg(currSize, speed)); 0260 } 0261 else { 0262 ui->downloadInfo->setText(tr("Remaining %1 - %2 of %3 (%4)").arg(remTime, currSize, fileSize, speed)); 0263 } 0264 } 0265 0266 void DownloadItem::stop() 0267 { 0268 #ifdef DOWNMANAGER_DEBUG 0269 qDebug() << __FUNCTION__; 0270 #endif 0271 if (m_downloadStopped) { 0272 return; 0273 } 0274 m_downloadStopped = true; 0275 ui->progressBar->hide(); 0276 ui->cancelButton->hide(); 0277 ui->pauseResumeButton->hide(); 0278 m_item->setSizeHint(sizeHint()); 0279 ui->downloadInfo->setText(tr("Cancelled - %1").arg(m_download->url().host())); 0280 m_download->cancel(); 0281 m_downloading = false; 0282 0283 Q_EMIT downloadFinished(false); 0284 } 0285 0286 void DownloadItem::pauseResume() 0287 { 0288 if (m_download->isPaused()) { 0289 m_download->resume(); 0290 ui->pauseResumeButton->setPixmap(QIcon::fromTheme(QSL("media-playback-pause")).pixmap(20, 20)); 0291 } else { 0292 m_download->pause(); 0293 ui->pauseResumeButton->setPixmap(QIcon::fromTheme(QSL("media-playback-start")).pixmap(20, 20)); 0294 ui->downloadInfo->setText(tr("Paused - %1").arg(m_download->url().host())); 0295 } 0296 } 0297 0298 void DownloadItem::mouseDoubleClickEvent(QMouseEvent* e) 0299 { 0300 openFile(); 0301 e->accept(); 0302 } 0303 0304 void DownloadItem::customContextMenuRequested(const QPoint &pos) 0305 { 0306 QMenu menu; 0307 menu.addAction(QIcon::fromTheme(QSL("document-open")), tr("Open File"), this, &DownloadItem::openFile); 0308 0309 menu.addAction(tr("Open Folder"), this, &DownloadItem::openFolder); 0310 menu.addSeparator(); 0311 menu.addAction(QIcon::fromTheme(QSL("edit-copy")), tr("Copy Download Link"), this, &DownloadItem::copyDownloadLink); 0312 menu.addSeparator(); 0313 menu.addAction(QIcon::fromTheme(QSL("process-stop")), tr("Cancel downloading"), this, &DownloadItem::stop)->setEnabled(m_downloading); 0314 0315 if (m_download->isPaused()) { 0316 menu.addAction(QIcon::fromTheme(QSL("media-playback-start")), tr("Resume downloading"), this, &DownloadItem::pauseResume)->setEnabled(m_downloading); 0317 } else { 0318 menu.addAction(QIcon::fromTheme(QSL("media-playback-pause")), tr("Pause downloading"), this, &DownloadItem::pauseResume)->setEnabled(m_downloading); 0319 } 0320 0321 menu.addAction(QIcon::fromTheme(QSL("list-remove")), tr("Remove From List"), this, &DownloadItem::clear)->setEnabled(!m_downloading); 0322 0323 if (m_downloading || ui->downloadInfo->text().startsWith(tr("Cancelled")) || ui->downloadInfo->text().startsWith(tr("Error"))) { 0324 menu.actions().at(0)->setEnabled(false); 0325 } 0326 menu.exec(mapToGlobal(pos)); 0327 } 0328 0329 void DownloadItem::copyDownloadLink() 0330 { 0331 QApplication::clipboard()->setText(m_downUrl.toString()); 0332 } 0333 0334 void DownloadItem::clear() 0335 { 0336 Q_EMIT deleteItem(this); 0337 } 0338 0339 void DownloadItem::openFile() 0340 { 0341 if (m_downloading) { 0342 return; 0343 } 0344 QFileInfo info(m_path, m_fileName); 0345 if (info.exists()) { 0346 QDesktopServices::openUrl(QUrl::fromLocalFile(info.absoluteFilePath())); 0347 } 0348 else { 0349 QMessageBox::warning(m_item->listWidget()->parentWidget(), tr("Not found"), tr("Sorry, the file \n %1 \n was not found!").arg(info.absoluteFilePath())); 0350 } 0351 } 0352 0353 void DownloadItem::openFolder() 0354 { 0355 #ifdef Q_OS_WIN 0356 QString winFileName = QSL("%1/%2").arg(m_path, m_fileName); 0357 0358 if (m_downloading) { 0359 winFileName.append(QSL(".download")); 0360 } 0361 0362 winFileName.replace(QLatin1Char('/'), QSL("\\")); 0363 QString shExArg = QSL("/e,/select,\"") + winFileName + QSL("\""); 0364 ShellExecute(NULL, NULL, TEXT("explorer.exe"), shExArg.toStdWString().c_str(), NULL, SW_SHOW); 0365 #else 0366 QDesktopServices::openUrl(QUrl::fromLocalFile(m_path)); 0367 #endif 0368 } 0369 0370 QUrl DownloadItem::url() const 0371 { 0372 return m_downUrl; 0373 } 0374 0375 QString DownloadItem::path() const 0376 { 0377 return m_path; 0378 } 0379 0380 QString DownloadItem::fileName() const 0381 { 0382 return m_fileName; 0383 } 0384 0385 DownloadItem::~DownloadItem() 0386 { 0387 delete ui; 0388 delete m_item; 0389 }