diff --git a/src/widgets/checksumswidget.ui b/src/widgets/checksumswidget.ui
--- a/src/widgets/checksumswidget.ui
+++ b/src/widgets/checksumswidget.ui
@@ -23,7 +23,7 @@
-
- Expected checksum (MD5, SHA1 or SHA256)...
+ Expected checksum (MD5, SHA1-SHA512, etc.)
@@ -55,141 +55,48 @@
-
-
-
-
-
+
+
-
+
- MD5:
+ Value
- -
-
+
-
+
- SHA1:
+
- -
-
-
-
-
-
- Calculate
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Click to copy the checksum to the clipboard.
-
-
- Copy
-
-
-
- ..
-
-
-
-
+ -
+
+
+ Algorithm
+
+
- -
-
+
-
+
- SHA256:
+ Calculate
- -
-
-
-
-
-
- Calculate
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Click to copy the checksum to the clipboard.
-
-
- Copy
-
-
-
- ..
-
-
-
-
+ -
+
+
+ Copy
+
+
+
+ ..
+
+
-
-
-
-
-
-
- Calculate
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Click to copy the checksum to the clipboard.
-
-
- Copy
-
-
-
- ..
-
-
-
-
+
@@ -214,6 +121,12 @@
KSeparator
QFrame
+ 1
+
+
+ KComboBox
+ QComboBox
+
diff --git a/src/widgets/kpropertiesdialog.cpp b/src/widgets/kpropertiesdialog.cpp
--- a/src/widgets/kpropertiesdialog.cpp
+++ b/src/widgets/kpropertiesdialog.cpp
@@ -54,6 +54,7 @@
#include
#include
+#include
#include
#include
#include
@@ -70,6 +71,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -77,6 +79,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -2633,6 +2636,60 @@
emit leaveModality();
}
+/**
+ * List model for displaying `QCryptographicHash::Algorithm`s in a combobox
+ */
+class KChecksumAlgorithmListModel: public QAbstractListModel {
+ QVector algorithms;
+
+public:
+
+ KChecksumAlgorithmListModel(QObject *parent)
+ : QAbstractListModel(parent), algorithms({
+ QCryptographicHash::Md4,
+ QCryptographicHash::Md5,
+ QCryptographicHash::Sha1,
+ QCryptographicHash::Sha224,
+ QCryptographicHash::Sha256,
+ QCryptographicHash::Sha384,
+ QCryptographicHash::Sha512,
+ QCryptographicHash::Sha3_224,
+ QCryptographicHash::Sha3_256,
+ QCryptographicHash::Sha3_384,
+ QCryptographicHash::Sha3_512
+ }) {}
+
+ int rowCount(const QModelIndex &parent) const override {
+ return algorithms.size();
+ }
+
+ QCryptographicHash::Algorithm at(int index) const {
+ return algorithms.at(index);
+ }
+
+ int find(QCryptographicHash::Algorithm alg) const {
+ return algorithms.indexOf(alg);
+ }
+
+ QVariant data(const QModelIndex &index, int role) const override {
+ if (!index.isValid())
+ return {};
+
+ if (index.row() >= algorithms.size() || index.row() < 0)
+ return {};
+
+ if (role == Qt::DisplayRole) {
+ const auto alg = algorithms.at(index.row());
+ const auto v = QVariant::fromValue(alg);
+ return QVariant::fromValue(
+ v.toString().replace("Real", "").replace('_', '-').toUpper()
+ );
+ }
+
+ return {};
+ }
+};
+
class KChecksumsPlugin::KChecksumsPluginPrivate
{
public:
@@ -2648,43 +2705,44 @@
Ui::ChecksumsWidget m_ui;
QFileSystemWatcher fileWatcher;
- QString m_md5;
- QString m_sha1;
- QString m_sha256;
+ QMap cache;
+ mutable QMutex mutex;
+
+ KConfigGroup configGroup;
};
KChecksumsPlugin::KChecksumsPlugin(KPropertiesDialog *dialog)
: KPropertiesDialogPlugin(dialog), d(new KChecksumsPluginPrivate)
{
d->m_ui.setupUi(&d->m_widget);
- properties->addPage(&d->m_widget, i18nc("@title:tab", "C&hecksums"));
+ properties->addPage(&d->m_widget, i18nc("@title:tab", "Checksums"));
- d->m_ui.md5CopyButton->hide();
- d->m_ui.sha1CopyButton->hide();
- d->m_ui.sha256CopyButton->hide();
+ d->configGroup = KConfigGroup(KSharedConfig::openConfig(), "KPropertiesDialog");
+
+ d->m_ui.algorithmComboBox->setModel(new KChecksumAlgorithmListModel(this));
+
+ setAlgorithm(readDefaultAlgorithm());
+
+ connect(d->m_ui.algorithmComboBox, static_cast(&QComboBox::currentIndexChanged), this, [=](int) {
+ writeDefaultAlgorithm(algorithm());
+ });
connect(d->m_ui.lineEdit, &QLineEdit::textChanged, this, [=](const QString &text) {
slotVerifyChecksum(text.toLower());
});
- connect(d->m_ui.md5Button, &QPushButton::clicked, this, &KChecksumsPlugin::slotShowMd5);
- connect(d->m_ui.sha1Button, &QPushButton::clicked, this, &KChecksumsPlugin::slotShowSha1);
- connect(d->m_ui.sha256Button, &QPushButton::clicked, this, &KChecksumsPlugin::slotShowSha256);
-
d->fileWatcher.addPath(properties->item().localPath());
connect(&d->fileWatcher, &QFileSystemWatcher::fileChanged, this, &KChecksumsPlugin::slotInvalidateCache);
- auto clipboard = QApplication::clipboard();
- connect(d->m_ui.md5CopyButton, &QPushButton::clicked, this, [=]() {
- clipboard->setText(d->m_md5);
+ connect(d->m_ui.calculateButton, &QPushButton::clicked, this, [=]() {
+ showChecksum(algorithm());
});
- connect(d->m_ui.sha1CopyButton, &QPushButton::clicked, this, [=]() {
- clipboard->setText(d->m_sha1);
- });
+ auto clipboard = QApplication::clipboard();
- connect(d->m_ui.sha256CopyButton, &QPushButton::clicked, this, [=]() {
- clipboard->setText(d->m_sha256);
+ d->m_ui.copyButton->hide();
+ connect(d->m_ui.copyButton, &QPushButton::clicked, this, [=]() {
+ clipboard->setText(d->m_ui.valueLabel->text());
});
connect(d->m_ui.pasteButton, &QPushButton::clicked, this, [=]() {
@@ -2705,56 +2763,62 @@
return false;
}
- const KFileItem item = items.first();
+ const auto& item = items.first();
return item.isFile() && item.isLocalFile() && item.isReadable() && !item.isDesktopFile() && !item.isLink();
}
void KChecksumsPlugin::slotInvalidateCache()
{
- d->m_md5 = QString();
- d->m_sha1 = QString();
- d->m_sha256 = QString();
+ d->cache.clear();
}
-void KChecksumsPlugin::slotShowMd5()
+void KChecksumsPlugin::verifyChecksums(const QString input, QVector algorithms)
{
- auto label = new QLabel(i18nc("@action:button", "Calculating..."), &d->m_widget);
- label->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
+ if (algorithms.isEmpty()) {
+ return;
+ }
- d->m_ui.calculateWidget->layout()->replaceWidget(d->m_ui.md5Button, label);
- d->m_ui.md5Button->hide();
+ auto futureWatcher = new QFutureWatcher(this);
- showChecksum(QCryptographicHash::Md5, label, d->m_ui.md5CopyButton);
-}
+ connect(futureWatcher, &QFutureWatcher::finished, this, [=]() {
+ const bool match = futureWatcher->result();
+ futureWatcher->deleteLater();
-void KChecksumsPlugin::slotShowSha1()
-{
- auto label = new QLabel(i18nc("@action:button", "Calculating..."), &d->m_widget);
- label->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
+ if (match) {
+ showMatchedChecksum();
+ setMatchState();
+ } else {
+ setMismatchState();
+ }
+ });
- d->m_ui.calculateWidget->layout()->replaceWidget(d->m_ui.sha1Button, label);
- d->m_ui.sha1Button->hide();
+ std::function mapper = [this](QCryptographicHash::Algorithm alg) {
+ const QString cache = cachedChecksum(alg);
+ if (!cache.isEmpty()) {
+ return cache;
+ }
- showChecksum(QCryptographicHash::Sha1, label, d->m_ui.sha1CopyButton);
-}
+ const QString checksum = computeChecksum(alg, properties->item().localPath());
+ cacheChecksum(checksum, alg);
-void KChecksumsPlugin::slotShowSha256()
-{
- auto label = new QLabel(i18nc("@action:button", "Calculating..."), &d->m_widget);
- label->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
+ return checksum;
+ };
+
+ std::function reducer = [input](bool& match, const QString& checksum) {
+ match |= checksum == input;
+ };
- d->m_ui.calculateWidget->layout()->replaceWidget(d->m_ui.sha256Button, label);
- d->m_ui.sha256Button->hide();
+ QFuture future = QtConcurrent::mappedReduced(algorithms, mapper, reducer);
- showChecksum(QCryptographicHash::Sha256, label, d->m_ui.sha256CopyButton);
+ futureWatcher->setFuture(future);
}
void KChecksumsPlugin::slotVerifyChecksum(const QString &input)
{
- auto algorithm = detectAlgorithm(input);
+ auto algorithms = detectAlgorithms(input);
// Input is not a supported hash algorithm.
- if (algorithm == QCryptographicHash::Md4) {
+ if (algorithms.isEmpty()) {
if (input.isEmpty()) {
setDefaultState();
} else {
@@ -2763,74 +2827,10 @@
return;
}
- const QString checksum = cachedChecksum(algorithm);
-
- // Checksum alread in cache.
- if (!checksum.isEmpty()) {
- const bool isMatch = (checksum == input);
- if (isMatch) {
- setMatchState();
- } else {
- setMismatchState();
- }
-
- return;
- }
-
- // Calculate checksum in another thread.
- auto futureWatcher = new QFutureWatcher(this);
- connect(futureWatcher, &QFutureWatcher::finished, this, [=]() {
-
- const QString checksum = futureWatcher->result();
- futureWatcher->deleteLater();
-
- cacheChecksum(checksum, algorithm);
-
- switch (algorithm) {
- case QCryptographicHash::Md5:
- slotShowMd5();
- break;
- case QCryptographicHash::Sha1:
- slotShowSha1();
- break;
- case QCryptographicHash::Sha256:
- slotShowSha256();
- break;
- default:
- break;
- }
-
- const bool isMatch = (checksum == input);
- if (isMatch) {
- setMatchState();
- } else {
- setMismatchState();
- }
- });
-
// Notify the user about the background computation.
setVerifyState();
- auto future = QtConcurrent::run(&KChecksumsPlugin::computeChecksum, algorithm, properties->item().localPath());
- futureWatcher->setFuture(future);
-}
-
-bool KChecksumsPlugin::isMd5(const QString &input)
-{
- QRegularExpression regex(QStringLiteral("^[a-f0-9]{32}$"));
- return regex.match(input).hasMatch();
-}
-
-bool KChecksumsPlugin::isSha1(const QString &input)
-{
- QRegularExpression regex(QStringLiteral("^[a-f0-9]{40}$"));
- return regex.match(input).hasMatch();
-}
-
-bool KChecksumsPlugin::isSha256(const QString &input)
-{
- QRegularExpression regex(QStringLiteral("^[a-f0-9]{64}$"));
- return regex.match(input).hasMatch();
+ verifyChecksums(input, algorithms);
}
QString KChecksumsPlugin::computeChecksum(QCryptographicHash::Algorithm algorithm, const QString &path)
@@ -2846,22 +2846,31 @@
return QString::fromLatin1(hash.result().toHex());
}
-QCryptographicHash::Algorithm KChecksumsPlugin::detectAlgorithm(const QString &input)
+QVector KChecksumsPlugin::detectAlgorithms(const QString &input)
{
- if (isMd5(input)) {
- return QCryptographicHash::Md5;
- }
+ static const QVector> regexes{
+ {QCryptographicHash::Md4, QRegularExpression("^[a-f0-9]{32}$")},
+ {QCryptographicHash::Md5, QRegularExpression("^[a-f0-9]{32}$")},
+ {QCryptographicHash::Sha1, QRegularExpression("^[a-f0-9]{40}$")},
+ {QCryptographicHash::Sha224, QRegularExpression("^[a-f0-9]{56}$")},
+ {QCryptographicHash::Sha256, QRegularExpression("^[a-f0-9]{64}$")},
+ {QCryptographicHash::Sha384, QRegularExpression("^[a-f0-9]{96}$")},
+ {QCryptographicHash::Sha512, QRegularExpression("^[a-f0-9]{128}$")},
+ {QCryptographicHash::Sha3_224, QRegularExpression("^[a-f0-9]{56}$")},
+ {QCryptographicHash::Sha3_256, QRegularExpression("^[a-f0-9]{64}$")},
+ {QCryptographicHash::Sha3_384, QRegularExpression("^[a-f0-9]{96}$")},
+ {QCryptographicHash::Sha3_512, QRegularExpression("^[a-f0-9]{128}$")}
+ };
- if (isSha1(input)) {
- return QCryptographicHash::Sha1;
- }
+ QVector algorithms;
- if (isSha256(input)) {
- return QCryptographicHash::Sha256;
+ for (const auto &p : regexes) {
+ if (p.second.match(input).hasMatch()) {
+ algorithms.push_back(p.first);
+ }
}
- // Md4 used as negative error code.
- return QCryptographicHash::Md4;
+ return algorithms;
}
void KChecksumsPlugin::setDefaultState()
@@ -2929,8 +2938,23 @@
d->m_ui.feedbackLabel->show();
}
-void KChecksumsPlugin::showChecksum(QCryptographicHash::Algorithm algorithm, QLabel *label, QPushButton *copyButton)
+void KChecksumsPlugin::showMatchedChecksum()
+{
+ for (const auto alg : d->cache.keys()) {
+ if(d->m_ui.lineEdit->text() == d->cache.value(alg, "")) {
+ showChecksum(alg);
+ return;
+ }
+ }
+}
+
+void KChecksumsPlugin::showChecksum(QCryptographicHash::Algorithm algorithm)
{
+ setAlgorithm(algorithm);
+
+ auto label = d->m_ui.valueLabel;
+ label->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
+
const QString checksum = cachedChecksum(algorithm);
// Checksum in cache, nothing else to do.
@@ -2948,44 +2972,48 @@
label->setText(checksum);
cacheChecksum(checksum, algorithm);
- copyButton->show();
+ d->m_ui.copyButton->show();
});
auto future = QtConcurrent::run(&KChecksumsPlugin::computeChecksum, algorithm, properties->item().localPath());
futureWatcher->setFuture(future);
}
-QString KChecksumsPlugin::cachedChecksum(QCryptographicHash::Algorithm algorithm) const
+void KChecksumsPlugin::writeDefaultAlgorithm(QCryptographicHash::Algorithm algorithm)
{
- switch (algorithm) {
- case QCryptographicHash::Md5:
- return d->m_md5;
- case QCryptographicHash::Sha1:
- return d->m_sha1;
- case QCryptographicHash::Sha256:
- return d->m_sha256;
- default:
- break;
+ d->configGroup.writeEntry("algorithm", static_cast(algorithm));
+}
+
+QCryptographicHash::Algorithm KChecksumsPlugin::readDefaultAlgorithm() const
+{
+ return static_cast(d->configGroup.readEntry("algorithm", static_cast(QCryptographicHash::Sha256)));
+}
+
+void KChecksumsPlugin::setAlgorithm(QCryptographicHash::Algorithm algorithm)
+{
+ const auto *model = d->m_ui.algorithmComboBox->model();
+ const KChecksumAlgorithmListModel *m = dynamic_cast(model);
+ if (m) {
+ d->m_ui.algorithmComboBox->setCurrentIndex(m->find(algorithm));
}
+}
+
+QCryptographicHash::Algorithm KChecksumsPlugin::algorithm() const
+{
+ const QAbstractItemModel *model = d->m_ui.algorithmComboBox->model();
+ const KChecksumAlgorithmListModel *m = dynamic_cast(model);
+ return m->at(d->m_ui.algorithmComboBox->currentIndex());
+}
- return QString();
+QString KChecksumsPlugin::cachedChecksum(QCryptographicHash::Algorithm algorithm) const
+{
+ return d->cache.value(algorithm, QString{});
}
void KChecksumsPlugin::cacheChecksum(const QString &checksum, QCryptographicHash::Algorithm algorithm)
{
- switch (algorithm) {
- case QCryptographicHash::Md5:
- d->m_md5 = checksum;
- break;
- case QCryptographicHash::Sha1:
- d->m_sha1 = checksum;
- break;
- case QCryptographicHash::Sha256:
- d->m_sha256 = checksum;
- break;
- default:
- return;
- }
+ QMutexLocker locker(&d->mutex);
+ d->cache.insert(algorithm, checksum);
}
class KUrlPropsPlugin::KUrlPropsPluginPrivate
diff --git a/src/widgets/kpropertiesdialog_p.h b/src/widgets/kpropertiesdialog_p.h
--- a/src/widgets/kpropertiesdialog_p.h
+++ b/src/widgets/kpropertiesdialog_p.h
@@ -30,8 +30,10 @@
#include "kpropertiesdialog.h"
+#include
#include
+class QPushButton;
class QComboBox;
class QLabel;
@@ -173,27 +175,31 @@
private Q_SLOTS:
void slotInvalidateCache();
- void slotShowMd5();
- void slotShowSha1();
- void slotShowSha256();
+
/**
* Compare @p input (required to be lowercase) with the checksum in cache.
*/
void slotVerifyChecksum(const QString &input);
private:
- static bool isMd5(const QString &input);
- static bool isSha1(const QString &input);
- static bool isSha256(const QString &input);
+ void verifyChecksums(const QString input, QVector algorithms);
+
static QString computeChecksum(QCryptographicHash::Algorithm algorithm, const QString &path);
- static QCryptographicHash::Algorithm detectAlgorithm(const QString &input);
+ static QVector detectAlgorithms(const QString &input);
void setDefaultState();
void setInvalidChecksumState();
void setMatchState();
void setMismatchState();
void setVerifyState();
- void showChecksum(QCryptographicHash::Algorithm algorithm, QLabel *label, QPushButton *copyButton);
+ void showChecksum(QCryptographicHash::Algorithm algorithm);
+ void showMatchedChecksum();
+
+ void writeDefaultAlgorithm(QCryptographicHash::Algorithm algorithm);
+ QCryptographicHash::Algorithm readDefaultAlgorithm() const;
+
+ void setAlgorithm(QCryptographicHash::Algorithm algorithm);
+ QCryptographicHash::Algorithm algorithm() const;
QString cachedChecksum(QCryptographicHash::Algorithm algorithm) const;
void cacheChecksum(const QString &checksum, QCryptographicHash::Algorithm algorithm);