mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-01-06 04:58:16 -05:00
218 lines
6.7 KiB
C++
218 lines
6.7 KiB
C++
/*
|
|
* Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
|
|
*
|
|
* This program 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 2 or (at your option)
|
|
* version 3 of the License.
|
|
*
|
|
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "IconDownloaderDialog.h"
|
|
#include "ui_IconDownloaderDialog.h"
|
|
|
|
#include "core/Config.h"
|
|
#include "core/Database.h"
|
|
#include "core/Entry.h"
|
|
#include "core/Metadata.h"
|
|
#include "core/Tools.h"
|
|
#include "gui/IconDownloader.h"
|
|
#include "gui/IconModels.h"
|
|
#include "gui/Icons.h"
|
|
#include "osutils/OSUtils.h"
|
|
#ifdef Q_OS_MACOS
|
|
#include "gui/osutils/macutils/MacUtils.h"
|
|
#endif
|
|
|
|
#include <QStandardItemModel>
|
|
|
|
IconDownloaderDialog::IconDownloaderDialog(QWidget* parent)
|
|
: QDialog(parent)
|
|
, m_ui(new Ui::IconDownloaderDialog())
|
|
, m_dataModel(new QStandardItemModel(this))
|
|
{
|
|
setWindowFlags(Qt::Window);
|
|
setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
m_ui->setupUi(this);
|
|
showFallbackMessage(false);
|
|
|
|
m_dataModel->clear();
|
|
m_dataModel->setHorizontalHeaderLabels({tr("URL"), tr("Status")});
|
|
|
|
m_ui->tableView->setModel(m_dataModel);
|
|
m_ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
|
|
|
connect(m_ui->cancelButton, SIGNAL(clicked()), SLOT(abortDownloads()));
|
|
connect(m_ui->closeButton, SIGNAL(clicked()), SLOT(close()));
|
|
}
|
|
|
|
IconDownloaderDialog::~IconDownloaderDialog()
|
|
{
|
|
abortDownloads();
|
|
}
|
|
|
|
void IconDownloaderDialog::downloadFavicons(const QSharedPointer<Database>& database,
|
|
const QList<Entry*>& entries,
|
|
bool force)
|
|
{
|
|
m_db = database;
|
|
m_urlToEntries.clear();
|
|
abortDownloads();
|
|
for (const auto& e : entries) {
|
|
// Only consider entries with a valid URL and without a custom icon
|
|
auto webUrl = e->webUrl();
|
|
if (!webUrl.isEmpty() && (force || e->iconUuid().isNull())) {
|
|
m_urlToEntries.insert(webUrl, e);
|
|
}
|
|
}
|
|
|
|
if (m_urlToEntries.count() > 0) {
|
|
#ifdef Q_OS_MACOS
|
|
macUtils()->raiseOwnWindow();
|
|
Tools::wait(100);
|
|
#endif
|
|
showFallbackMessage(false);
|
|
m_ui->progressLabel->setText(tr("Please wait, processing entry list…"));
|
|
open();
|
|
QApplication::processEvents();
|
|
|
|
for (const auto& url : m_urlToEntries.uniqueKeys()) {
|
|
m_dataModel->appendRow(QList<QStandardItem*>()
|
|
<< new QStandardItem(url) << new QStandardItem(tr("Downloading…")));
|
|
m_activeDownloaders.append(createDownloader(url));
|
|
}
|
|
|
|
// Setup the dialog
|
|
updateProgressBar();
|
|
updateCancelButton();
|
|
QApplication::processEvents();
|
|
|
|
// Start the downloads
|
|
for (auto downloader : m_activeDownloaders) {
|
|
downloader->download();
|
|
}
|
|
}
|
|
}
|
|
|
|
void IconDownloaderDialog::downloadFaviconInBackground(const QSharedPointer<Database>& database, Entry* entry)
|
|
{
|
|
m_db = database;
|
|
m_urlToEntries.clear();
|
|
abortDownloads();
|
|
|
|
auto webUrl = entry->webUrl();
|
|
if (!webUrl.isEmpty()) {
|
|
m_urlToEntries.insert(webUrl, entry);
|
|
}
|
|
|
|
if (m_urlToEntries.count() > 0) {
|
|
m_activeDownloaders.append(createDownloader(webUrl));
|
|
m_activeDownloaders.first()->download();
|
|
}
|
|
}
|
|
|
|
IconDownloader* IconDownloaderDialog::createDownloader(const QString& url)
|
|
{
|
|
auto downloader = new IconDownloader();
|
|
connect(downloader,
|
|
SIGNAL(finished(const QString&, const QImage&)),
|
|
this,
|
|
SLOT(downloadFinished(const QString&, const QImage&)));
|
|
|
|
downloader->setUrl(url);
|
|
return downloader;
|
|
}
|
|
|
|
void IconDownloaderDialog::downloadFinished(const QString& url, const QImage& icon)
|
|
{
|
|
// Prevent re-entrance from multiple calls finishing at the same time
|
|
QMutexLocker locker(&m_mutex);
|
|
|
|
// Cleanup the icon downloader that sent this signal
|
|
auto downloader = qobject_cast<IconDownloader*>(sender());
|
|
if (downloader) {
|
|
downloader->deleteLater();
|
|
m_activeDownloaders.removeAll(downloader);
|
|
}
|
|
|
|
updateProgressBar();
|
|
updateCancelButton();
|
|
|
|
if (m_db && !icon.isNull()) {
|
|
// Don't add an icon larger than 128x128, but retain original size if smaller
|
|
constexpr auto maxIconSize = 128;
|
|
auto scaledIcon = icon;
|
|
if (icon.width() > maxIconSize || icon.height() > maxIconSize) {
|
|
scaledIcon = icon.scaled(maxIconSize, maxIconSize);
|
|
}
|
|
|
|
QByteArray serializedIcon = Icons::saveToBytes(scaledIcon);
|
|
QUuid uuid = m_db->metadata()->findCustomIcon(serializedIcon);
|
|
if (uuid.isNull()) {
|
|
uuid = QUuid::createUuid();
|
|
m_db->metadata()->addCustomIcon(uuid, serializedIcon);
|
|
updateTable(url, tr("Ok"));
|
|
} else {
|
|
updateTable(url, tr("Already Exists"));
|
|
}
|
|
|
|
// Set the icon on all the entries associated with this url
|
|
for (const auto entry : m_urlToEntries.values(url)) {
|
|
entry->setIcon(uuid);
|
|
}
|
|
} else {
|
|
showFallbackMessage(true);
|
|
updateTable(url, tr("Download Failed"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
void IconDownloaderDialog::showFallbackMessage(bool state)
|
|
{
|
|
// Show fallback message if the option is not active
|
|
bool show = state && !config()->get(Config::Security_IconDownloadFallback).toBool();
|
|
m_ui->fallbackLabel->setVisible(show);
|
|
}
|
|
|
|
void IconDownloaderDialog::updateProgressBar()
|
|
{
|
|
int total = m_urlToEntries.uniqueKeys().count();
|
|
int value = total - m_activeDownloaders.count();
|
|
m_ui->progressBar->setValue(value);
|
|
m_ui->progressBar->setMaximum(total);
|
|
m_ui->progressLabel->setText(
|
|
tr("Downloading favicons (%1/%2)…").arg(QString::number(value), QString::number(total)));
|
|
}
|
|
|
|
void IconDownloaderDialog::updateCancelButton()
|
|
{
|
|
m_ui->cancelButton->setEnabled(!m_activeDownloaders.isEmpty());
|
|
}
|
|
|
|
void IconDownloaderDialog::updateTable(const QString& url, const QString& message)
|
|
{
|
|
for (int i = 0; i < m_dataModel->rowCount(); ++i) {
|
|
if (m_dataModel->item(i, 0)->text() == url) {
|
|
m_dataModel->item(i, 1)->setText(message);
|
|
}
|
|
}
|
|
}
|
|
|
|
void IconDownloaderDialog::abortDownloads()
|
|
{
|
|
for (auto* downloader : m_activeDownloaders) {
|
|
downloader->deleteLater();
|
|
}
|
|
m_activeDownloaders.clear();
|
|
updateProgressBar();
|
|
updateCancelButton();
|
|
}
|