/* Copyright (C) 2012 Sebastian Herbord. All rights reserved. This file is part of Mod Organizer. Mod Organizer is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Mod Organizer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see . */ #include "downloadlistwidget.h" #include "ui_downloadlistwidget.h" #include #include #include #include #include DownloadListWidget::DownloadListWidget(QWidget *parent) : QWidget(parent), ui(new Ui::DownloadListWidget) { ui->setupUi(this); } DownloadListWidget::~DownloadListWidget() { delete ui; } DownloadListWidgetDelegate::DownloadListWidgetDelegate(DownloadManager *manager, bool metaDisplay, QTreeView *view, QObject *parent) : QItemDelegate(parent) , m_Manager(manager) , m_MetaDisplay(metaDisplay) , m_ItemWidget(new DownloadListWidget) , m_ContextRow(0) , m_View(view) { m_NameLabel = m_ItemWidget->findChild("nameLabel"); m_SizeLabel = m_ItemWidget->findChild("sizeLabel"); m_Progress = m_ItemWidget->findChild("downloadProgress"); m_InstallLabel = m_ItemWidget->findChild("installLabel"); m_InstallLabel->setVisible(false); m_Progress->setTextVisible(true); connect(manager, SIGNAL(stateChanged(int,DownloadManager::DownloadState)), this, SLOT(stateChanged(int,DownloadManager::DownloadState))); connect(manager, SIGNAL(downloadRemoved(int)), this, SLOT(resetCache(int))); } DownloadListWidgetDelegate::~DownloadListWidgetDelegate() { delete m_ItemWidget; } void DownloadListWidgetDelegate::stateChanged(int row,DownloadManager::DownloadState) { m_Cache.remove(row); } void DownloadListWidgetDelegate::resetCache(int) { m_Cache.clear(); } void DownloadListWidgetDelegate::drawCache(QPainter *painter, const QStyleOptionViewItem &option, const QPixmap &cache) const { QRect rect = option.rect; rect.setLeft(0); rect.setWidth(m_View->columnWidth(0) + m_View->columnWidth(1) + m_View->columnWidth(2)); painter->drawPixmap(rect, cache); } QString DownloadListWidgetDelegate::sizeFormat(quint64 size) const { qreal calc = size; QStringList list; list << "KB" << "MB" << "GB" << "TB"; QStringListIterator i(list); QString unit("byte(s)"); while (calc >= 1024.0 && i.hasNext()) { unit = i.next(); calc /= 1024.0; } return QString().setNum(calc, 'f', 2) + " " + unit; } void DownloadListWidgetDelegate::paintPendingDownload(int downloadIndex) const { std::tuple nexusids = m_Manager->getPendingDownload(downloadIndex); m_NameLabel->setText(tr("< game %1 mod %2 file %3 >").arg(std::get<0>(nexusids)).arg(std::get<1>(nexusids)).arg(std::get<2>(nexusids))); m_SizeLabel->setText("???"); m_InstallLabel->setVisible(true); m_InstallLabel->setText(tr("Pending")); m_Progress->setVisible(false); } void DownloadListWidgetDelegate::paintRegularDownload(int downloadIndex) const { QString name = m_MetaDisplay ? m_Manager->getDisplayName(downloadIndex) : m_Manager->getFileName(downloadIndex); if (name.length() > 53) { name.truncate(50); name.append("..."); } m_NameLabel->setText(name); m_SizeLabel->setText(sizeFormat(m_Manager->getFileSize(downloadIndex) )); DownloadManager::DownloadState state = m_Manager->getState(downloadIndex); if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR) || (state == DownloadManager::STATE_PAUSING)) { QPalette labelPalette; m_InstallLabel->setVisible(true); m_Progress->setVisible(false); #if QT_VERSION >= QT_VERSION_CHECK(5,0,0) m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Paused - Double Click to resume", 0)); #else m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Paused - Double Click to resume", 0, QApplication::UnicodeUTF8)); #endif labelPalette.setColor(QPalette::WindowText, Qt::darkRed); m_InstallLabel->setPalette(labelPalette); } else if (state == DownloadManager::STATE_FETCHINGMODINFO) { m_InstallLabel->setText(tr("Fetching Info 1")); m_Progress->setVisible(false); } else if (state == DownloadManager::STATE_FETCHINGFILEINFO) { m_InstallLabel->setText(tr("Fetching Info 2")); m_Progress->setVisible(false); } else if (state >= DownloadManager::STATE_READY) { QPalette labelPalette; m_InstallLabel->setVisible(true); m_Progress->setVisible(false); if (state == DownloadManager::STATE_INSTALLED) { // the tr-macro doesn't work here, maybe because the translation is actually associated with DownloadListWidget instead // of DownloadListWidgetDelegate? #if QT_VERSION >= QT_VERSION_CHECK(5,0,0) m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Installed - Double Click to re-install", 0)); #else m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Installed - Double Click to re-install", 0, QApplication::UnicodeUTF8)); #endif labelPalette.setColor(QPalette::WindowText, Qt::darkGray); } else if (state == DownloadManager::STATE_UNINSTALLED) { #if QT_VERSION >= QT_VERSION_CHECK(5,0,0) m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Uninstalled - Double Click to re-install", 0)); #else m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Uninstalled - Double Click to re-install", 0, QApplication::UnicodeUTF8)); #endif labelPalette.setColor(QPalette::WindowText, Qt::lightGray); } else { #if QT_VERSION >= QT_VERSION_CHECK(5,0,0) m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Done - Double Click to install", 0)); #else m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Done - Double Click to install", 0, QApplication::UnicodeUTF8)); #endif labelPalette.setColor(QPalette::WindowText, Qt::darkGreen); } m_InstallLabel->setPalette(labelPalette); if (m_Manager->isInfoIncomplete(downloadIndex)) { m_NameLabel->setText(" " + m_NameLabel->text()); } } else { m_InstallLabel->setVisible(false); m_Progress->setVisible(true); m_Progress->setValue(m_Manager->getProgress(downloadIndex).first); m_Progress->setFormat(m_Manager->getProgress(downloadIndex).second); } } void DownloadListWidgetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { try { auto iter = m_Cache.find(index.row()); if (iter != m_Cache.end()) { drawCache(painter, option, *iter); return; } m_ItemWidget->resize(QSize(m_View->columnWidth(0) + m_View->columnWidth(1) + m_View->columnWidth(2), option.rect.height())); int downloadIndex = index.data().toInt(); if (downloadIndex >= m_Manager->numTotalDownloads()) { paintPendingDownload(downloadIndex - m_Manager->numTotalDownloads()); } else { paintRegularDownload(downloadIndex); } #pragma message("caching disabled because changes in the list (including resorting) doesn't work correctly") // if (state >= DownloadManager::STATE_READY) { if (false) { #if QT_VERSION >= QT_VERSION_CHECK(5,0,0) QPixmap cache = m_ItemWidget->grab(); #else QPixmap cache = QPixmap::grabWidget(m_ItemWidget); #endif m_Cache[index.row()] = cache; drawCache(painter, option, cache); } else { painter->save(); painter->translate(QPoint(0, option.rect.topLeft().y())); m_ItemWidget->render(painter); painter->restore(); } } catch (const std::exception &e) { qCritical("failed to paint download list: %s", e.what()); } } QSize DownloadListWidgetDelegate::sizeHint(const QStyleOptionViewItem&, const QModelIndex&) const { const int width = m_ItemWidget->minimumWidth(); const int height = m_ItemWidget->height(); return QSize(width, height); } void DownloadListWidgetDelegate::issueInstall() { emit installDownload(m_ContextRow); } void DownloadListWidgetDelegate::issueQueryInfo() { emit queryInfo(m_ContextRow); } void DownloadListWidgetDelegate::issueDelete() { if (QMessageBox::question(nullptr, tr("Delete Files?"), tr("This will permanently delete the selected download."), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { emit removeDownload(m_ContextRow, true); } } void DownloadListWidgetDelegate::issueRemoveFromView() { emit removeDownload(m_ContextRow, false); } void DownloadListWidgetDelegate::issueRestoreToView() { emit restoreDownload(m_ContextRow); } void DownloadListWidgetDelegate::issueRestoreToViewAll() { emit restoreDownload(-1); } void DownloadListWidgetDelegate::issueVisitOnNexus() { emit visitOnNexus(m_ContextRow); } void DownloadListWidgetDelegate::issueOpenInDownloadsFolder() { emit openInDownloadsFolder(m_ContextRow); } void DownloadListWidgetDelegate::issueCancel() { emit cancelDownload(m_ContextRow); } void DownloadListWidgetDelegate::issuePause() { emit pauseDownload(m_ContextRow); } void DownloadListWidgetDelegate::issueResume() { emit resumeDownload(m_ContextRow); } void DownloadListWidgetDelegate::issueDeleteAll() { if (QMessageBox::question(nullptr, tr("Delete Files?"), tr("This will remove all finished downloads from this list and from disk."), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { emit removeDownload(-1, true); } } void DownloadListWidgetDelegate::issueDeleteCompleted() { if (QMessageBox::question(nullptr, tr("Delete Files?"), tr("This will remove all installed downloads from this list and from disk."), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { emit removeDownload(-2, true); } } void DownloadListWidgetDelegate::issueRemoveFromViewAll() { if (QMessageBox::question(nullptr, tr("Are you sure?"), tr("This will remove all finished downloads from this list (but NOT from disk)."), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { emit removeDownload(-1, false); } } void DownloadListWidgetDelegate::issueRemoveFromViewCompleted() { if (QMessageBox::question(nullptr, tr("Are you sure?"), tr("This will remove all installed downloads from this list (but NOT from disk)."), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { emit removeDownload(-2, false); } } bool DownloadListWidgetDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { try { if (event->type() == QEvent::MouseButtonDblClick) { QModelIndex sourceIndex = qobject_cast(model)->mapToSource(index); if (m_Manager->getState(sourceIndex.row()) >= DownloadManager::STATE_READY) { emit installDownload(sourceIndex.row()); } else if ((m_Manager->getState(sourceIndex.row()) >= DownloadManager::STATE_PAUSED) || (m_Manager->getState(sourceIndex.row()) == DownloadManager::STATE_PAUSING)) { emit resumeDownload(sourceIndex.row()); } return true; } else if (event->type() == QEvent::MouseButtonRelease) { QMouseEvent *mouseEvent = static_cast(event); if (mouseEvent->button() == Qt::RightButton) { QMenu menu(m_View); bool hidden = false; m_ContextRow = qobject_cast(model)->mapToSource(index).row(); if (m_ContextRow < m_Manager->numTotalDownloads()) { DownloadManager::DownloadState state = m_Manager->getState(m_ContextRow); hidden = m_Manager->isHidden(m_ContextRow); if (state >= DownloadManager::STATE_READY) { menu.addAction(tr("Install"), this, SLOT(issueInstall())); if (m_Manager->isInfoIncomplete(m_ContextRow)) { menu.addAction(tr("Query Info"), this, SLOT(issueQueryInfo())); }else { menu.addAction(tr("Visit on Nexus"), this,SLOT(issueVisitOnNexus())); } menu.addAction(tr("Show in Folder"), this, SLOT(issueOpenInDownloadsFolder())); menu.addSeparator(); menu.addAction(tr("Delete"), this, SLOT(issueDelete())); if (hidden) { menu.addAction(tr("Un-Hide"), this, SLOT(issueRestoreToView())); } else { menu.addAction(tr("Hide"), this, SLOT(issueRemoveFromView())); } } else if (state == DownloadManager::STATE_DOWNLOADING){ menu.addAction(tr("Cancel"), this, SLOT(issueCancel())); menu.addAction(tr("Pause"), this, SLOT(issuePause())); menu.addAction(tr("Show in Folder"), this, SLOT(issueOpenInDownloadsFolder())); } else if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR) || (state == DownloadManager::STATE_PAUSING)) { menu.addAction(tr("Delete"), this, SLOT(issueDelete())); menu.addAction(tr("Resume"), this, SLOT(issueResume())); menu.addAction(tr("Show in Folder"), this, SLOT(issueOpenInDownloadsFolder())); } menu.addSeparator(); } menu.addAction(tr("Delete Installed..."), this, SLOT(issueDeleteCompleted())); menu.addAction(tr("Delete All..."), this, SLOT(issueDeleteAll())); if (!hidden) { menu.addSeparator(); menu.addAction(tr("Hide Installed..."), this, SLOT(issueRemoveFromViewCompleted())); menu.addAction(tr("Hide All..."), this, SLOT(issueRemoveFromViewAll())); } if (hidden) { menu.addSeparator(); menu.addAction(tr("Un-Hide All..."), this, SLOT(issueRestoreToViewAll())); } menu.exec(mouseEvent->globalPos()); event->accept(); return true; } } } catch (const std::exception &e) { qCritical("failed to handle editor event: %s", e.what()); } return QItemDelegate::editorEvent(event, model, option, index); }