Commit ae737977 authored by Ragnar Thomsen's avatar Ragnar Thomsen
Browse files

Support for setting compression method

Summary:
Support for setting compression method was implemented. The setting is
available in the Compression collapsible group.

Reviewers: elvisangelaccio

Reviewed By: elvisangelaccio

Subscribers: kde-utils-devel

Tags: #ark

Differential Revision: https://phabricator.kde.org/D2879
parent 7d769304
......@@ -304,6 +304,9 @@ void MainWindow::newArchive()
qCDebug(ARK) << "Setting volume size:" << QString::number(dialog.data()->volumeSize());
m_openArgs.metaData()[QStringLiteral("volumeSize")] = QString::number(dialog.data()->volumeSize());
}
if (!dialog.data()->compressionMethod().isEmpty()) {
m_openArgs.metaData()[QStringLiteral("compressionMethod")] = dialog.data()->compressionMethod();
}
m_openArgs.metaData()[QStringLiteral("encryptionPassword")] = password;
if (dialog.data()->isHeaderEncryptionEnabled()) {
......
......@@ -153,7 +153,6 @@ void AddToArchiveTest::testCompressHere_data()
<< QStringLiteral("data.zip")
<< 3ULL
<< 1ULL;
QTest::newRow("compress here (as TAR) - dir with special name (see #365798)")
<< QStringLiteral("tar.gz")
<< Archive::Unencrypted
......@@ -161,6 +160,7 @@ void AddToArchiveTest::testCompressHere_data()
<< QStringLiteral("test%dir.tar.gz")
<< 2ULL
<< 1ULL;
} else {
qDebug() << "7z/zip executable not found in path. Skipping compress-here-(ZIP) tests.";
}
......
......@@ -266,48 +266,63 @@ void Cli7zTest::testAddArgs_data()
QTest::addColumn<QString>("password");
QTest::addColumn<bool>("encryptHeader");
QTest::addColumn<int>("compressionLevel");
QTest::addColumn<QString>("compressionMethod");
QTest::addColumn<ulong>("volumeSize");
QTest::addColumn<QStringList>("expectedArgs");
QTest::newRow("unencrypted")
<< QStringLiteral("/tmp/foo.7z")
<< QString() << false << 5 << 0UL
<< QString() << false << 5 << QStringLiteral("LZMA2") << 0UL
<< QStringList {
QStringLiteral("a"),
QStringLiteral("/tmp/foo.7z"),
QStringLiteral("-mx=5")
QStringLiteral("-mx=5"),
QStringLiteral("-m0=LZMA2")
};
QTest::newRow("encrypted")
<< QStringLiteral("/tmp/foo.7z")
<< QStringLiteral("1234") << false << 5 << 0UL
<< QStringLiteral("1234") << false << 5 << QStringLiteral("LZMA2") << 0UL
<< QStringList {
QStringLiteral("a"),
QStringLiteral("/tmp/foo.7z"),
QStringLiteral("-p1234"),
QStringLiteral("-mx=5")
QStringLiteral("-mx=5"),
QStringLiteral("-m0=LZMA2")
};
QTest::newRow("header-encrypted")
<< QStringLiteral("/tmp/foo.7z")
<< QStringLiteral("1234") << true << 5 << 0UL
<< QStringLiteral("1234") << true << 5 << QStringLiteral("LZMA2") << 0UL
<< QStringList {
QStringLiteral("a"),
QStringLiteral("/tmp/foo.7z"),
QStringLiteral("-p1234"),
QStringLiteral("-mhe=on"),
QStringLiteral("-mx=5")
QStringLiteral("-mx=5"),
QStringLiteral("-m0=LZMA2")
};
QTest::newRow("multi-volume")
<< QStringLiteral("/tmp/foo.7z")
<< QString() << false << 5 << 2500UL
<< QString() << false << 5 << QStringLiteral("LZMA2") << 2500UL
<< QStringList {
QStringLiteral("a"),
QStringLiteral("/tmp/foo.7z"),
QStringLiteral("-mx=5"),
QStringLiteral("-m0=LZMA2"),
QStringLiteral("-v2500k")
};
QTest::newRow("comp-method-bzip2")
<< QStringLiteral("/tmp/foo.7z")
<< QString() << false << 5 << QStringLiteral("BZip2") << 0UL
<< QStringList {
QStringLiteral("a"),
QStringLiteral("/tmp/foo.7z"),
QStringLiteral("-mx=5"),
QStringLiteral("-m0=BZip2")
};
}
void Cli7zTest::testAddArgs()
......@@ -320,6 +335,7 @@ void Cli7zTest::testAddArgs()
QStringLiteral("$Archive"),
QStringLiteral("$PasswordSwitch"),
QStringLiteral("$CompressionLevelSwitch"),
QStringLiteral("$CompressionMethodSwitch"),
QStringLiteral("$MultiVolumeSwitch"),
QStringLiteral("$Files") };
......@@ -327,8 +343,9 @@ void Cli7zTest::testAddArgs()
QFETCH(bool, encryptHeader);
QFETCH(int, compressionLevel);
QFETCH(ulong, volumeSize);
QFETCH(QString, compressionMethod);
QStringList replacedArgs = plugin->substituteAddVariables(addArgs, {}, password, encryptHeader, compressionLevel, volumeSize);
QStringList replacedArgs = plugin->substituteAddVariables(addArgs, {}, password, encryptHeader, compressionLevel, volumeSize, compressionMethod);
QFETCH(QStringList, expectedArgs);
QCOMPARE(replacedArgs, expectedArgs);
......
......@@ -324,21 +324,23 @@ void CliRarTest::testAddArgs_data()
QTest::addColumn<QString>("password");
QTest::addColumn<bool>("encryptHeader");
QTest::addColumn<int>("compressionLevel");
QTest::addColumn<QString>("compressionMethod");
QTest::addColumn<ulong>("volumeSize");
QTest::addColumn<QStringList>("expectedArgs");
QTest::newRow("unencrypted")
<< QStringLiteral("/tmp/foo.rar")
<< QString() << false << 3 << 0UL
<< QString() << false << 3 << QStringLiteral("RAR4") << 0UL
<< QStringList {
QStringLiteral("a"),
QStringLiteral("/tmp/foo.rar"),
QStringLiteral("-m3")
QStringLiteral("-m3"),
QStringLiteral("-ma4")
};
QTest::newRow("encrypted")
<< QStringLiteral("/tmp/foo.rar")
<< QStringLiteral("1234") << false << 3 << 0UL
<< QStringLiteral("1234") << false << 3 << QString() << 0UL
<< QStringList {
QStringLiteral("a"),
QStringLiteral("/tmp/foo.rar"),
......@@ -348,7 +350,7 @@ void CliRarTest::testAddArgs_data()
QTest::newRow("header-encrypted")
<< QStringLiteral("/tmp/foo.rar")
<< QStringLiteral("1234") << true << 3 << 0UL
<< QStringLiteral("1234") << true << 3 << QString() << 0UL
<< QStringList {
QStringLiteral("a"),
QStringLiteral("/tmp/foo.rar"),
......@@ -358,13 +360,22 @@ void CliRarTest::testAddArgs_data()
QTest::newRow("multi-volume")
<< QStringLiteral("/tmp/foo.rar")
<< QString() << false << 3 << 2500UL
<< QString() << false << 3 << QString() << 2500UL
<< QStringList {
QStringLiteral("a"),
QStringLiteral("/tmp/foo.rar"),
QStringLiteral("-m3"),
QStringLiteral("-v2500k")
};
QTest::newRow("comp-method-RAR5")
<< QStringLiteral("/tmp/foo.rar")
<< QString() << false << 3 << QStringLiteral("RAR5") << 0UL
<< QStringList {
QStringLiteral("a"),
QStringLiteral("/tmp/foo.rar"),
QStringLiteral("-m3"),
QStringLiteral("-ma5")
};
}
void CliRarTest::testAddArgs()
......@@ -377,15 +388,17 @@ void CliRarTest::testAddArgs()
QStringLiteral("$Archive"),
QStringLiteral("$PasswordSwitch"),
QStringLiteral("$CompressionLevelSwitch"),
QStringLiteral("$CompressionMethodSwitch"),
QStringLiteral("$MultiVolumeSwitch"),
QStringLiteral("$Files") };
QFETCH(QString, password);
QFETCH(bool, encryptHeader);
QFETCH(int, compressionLevel);
QFETCH(QString, compressionMethod);
QFETCH(ulong, volumeSize);
QStringList replacedArgs = rarPlugin->substituteAddVariables(addArgs, {}, password, encryptHeader, compressionLevel, volumeSize);
QStringList replacedArgs = rarPlugin->substituteAddVariables(addArgs, {}, password, encryptHeader, compressionLevel, volumeSize, compressionMethod);
QFETCH(QStringList, expectedArgs);
QCOMPARE(replacedArgs, expectedArgs);
......
......@@ -69,26 +69,38 @@ void CliZipTest::testAddArgs_data()
QTest::addColumn<QString>("archiveName");
QTest::addColumn<QString>("password");
QTest::addColumn<int>("compressionLevel");
QTest::addColumn<QString>("compressionMethod");
QTest::addColumn<QStringList>("expectedArgs");
QTest::newRow("unencrypted")
<< QStringLiteral("/tmp/foo.zip")
<< QString() << 3
<< QString() << 3 << QStringLiteral("deflate")
<< QStringList {
QStringLiteral("-r"),
QStringLiteral("/tmp/foo.zip"),
QStringLiteral("-3")
QStringLiteral("-3"),
QStringLiteral("-Zdeflate")
};
QTest::newRow("encrypted")
<< QStringLiteral("/tmp/foo.zip")
<< QStringLiteral("1234") << 3
<< QStringLiteral("1234") << 3 << QString()
<< QStringList {
QStringLiteral("-r"),
QStringLiteral("/tmp/foo.zip"),
QStringLiteral("-P1234"),
QStringLiteral("-3")
};
QTest::newRow("comp-method-bzip2")
<< QStringLiteral("/tmp/foo.zip")
<< QString() << 3 << QStringLiteral("bzip2")
<< QStringList {
QStringLiteral("-r"),
QStringLiteral("/tmp/foo.zip"),
QStringLiteral("-3"),
QStringLiteral("-Zbzip2")
};
}
void CliZipTest::testAddArgs()
......@@ -101,12 +113,14 @@ void CliZipTest::testAddArgs()
QStringLiteral("$Archive"),
QStringLiteral("$PasswordSwitch"),
QStringLiteral("$CompressionLevelSwitch"),
QStringLiteral("$CompressionMethodSwitch"),
QStringLiteral("$Files") };
QFETCH(QString, password);
QFETCH(int, compressionLevel);
QFETCH(QString, compressionMethod);
QStringList replacedArgs = plugin->substituteAddVariables(addArgs, {}, password, false, compressionLevel, 0);
QStringList replacedArgs = plugin->substituteAddVariables(addArgs, {}, password, false, compressionLevel, 0, compressionMethod);
QFETCH(QStringList, expectedArgs);
QCOMPARE(replacedArgs, expectedArgs);
......
......@@ -25,6 +25,8 @@
#include "archiveformat.h"
#include <QJsonArray>
namespace Kerfuffle
{
......@@ -40,7 +42,9 @@ ArchiveFormat::ArchiveFormat(const QMimeType& mimeType,
int defaultCompLevel,
bool supportsWriteComment,
bool supportsTesting,
bool supportsMultiVolume) :
bool supportsMultiVolume,
QStringList compressionMethods,
QString defaultCompressionMethod) :
m_mimeType(mimeType),
m_encryptionType(encryptionType),
m_minCompressionLevel(minCompLevel),
......@@ -48,7 +52,9 @@ ArchiveFormat::ArchiveFormat(const QMimeType& mimeType,
m_defaultCompressionLevel(defaultCompLevel),
m_supportsWriteComment(supportsWriteComment),
m_supportsTesting(supportsTesting),
m_supportsMultiVolume(supportsMultiVolume)
m_supportsMultiVolume(supportsMultiVolume),
m_compressionMethods(compressionMethods),
m_defaultCompressionMethod(defaultCompressionMethod)
{
}
......@@ -70,6 +76,13 @@ ArchiveFormat ArchiveFormat::fromMetadata(const QMimeType& mimeType, const KPlug
bool supportsTesting = formatProps[QStringLiteral("SupportsTesting")].toBool();
bool supportsMultiVolume = formatProps[QStringLiteral("SupportsMultiVolume")].toBool();
QStringList compressionMethods;
QJsonArray array = formatProps[QStringLiteral("CompressionMethods")].toArray();
foreach (const QJsonValue &value, array) {
compressionMethods.append(value.toString());
}
QString defaultCompMethod = formatProps[QStringLiteral("CompressionMethodDefault")].toString();
Archive::EncryptionType encType = Archive::Unencrypted;
if (formatProps[QStringLiteral("HeaderEncryption")].toBool()) {
encType = Archive::HeaderEncrypted;
......@@ -77,7 +90,7 @@ ArchiveFormat ArchiveFormat::fromMetadata(const QMimeType& mimeType, const KPlug
encType = Archive::Encrypted;
}
return ArchiveFormat(mimeType, encType, minCompLevel, maxCompLevel, defaultCompLevel, supportsWriteComment, supportsTesting, supportsMultiVolume);
return ArchiveFormat(mimeType, encType, minCompLevel, maxCompLevel, defaultCompLevel, supportsWriteComment, supportsTesting, supportsMultiVolume, compressionMethods, defaultCompMethod);
}
return ArchiveFormat();
......@@ -123,4 +136,14 @@ bool ArchiveFormat::supportsMultiVolume() const
return m_supportsMultiVolume;
}
QStringList ArchiveFormat::compressionMethods() const
{
return m_compressionMethods;
}
QString ArchiveFormat::defaultCompressionMethod() const
{
return m_defaultCompressionMethod;
}
}
......@@ -44,7 +44,9 @@ public:
int defaultCompLevel,
bool supportsWriteComment,
bool supportsTesting,
bool suppportsMultiVolume);
bool suppportsMultiVolume,
QStringList compressionMethods,
QString defaultCompressionMethod);
/**
* @return The archive format of the given @p mimeType, according to the given @p metadata.
......@@ -67,6 +69,8 @@ public:
bool supportsWriteComment() const;
bool supportsTesting() const;
bool supportsMultiVolume() const;
QStringList compressionMethods() const;
QString defaultCompressionMethod() const;
private:
QMimeType m_mimeType;
......@@ -77,6 +81,8 @@ private:
bool m_supportsWriteComment;
bool m_supportsTesting;
bool m_supportsMultiVolume;
QStringList m_compressionMethods;
QString m_defaultCompressionMethod;
};
}
......
......@@ -233,13 +233,15 @@ bool CliInterface::addFiles(const QList<Archive::Entry*> &files, const Archive::
int compLevel = options.value(QStringLiteral("CompressionLevel"), -1).toInt();
ulong volumeSize = options.value(QStringLiteral("VolumeSize"), 0).toULongLong();
QString compMethod = options.value(QStringLiteral("CompressionMethod")).toString();
const auto args = substituteAddVariables(m_param.value(AddArgs).toStringList(),
filesToPass,
password(),
isHeaderEncryptionEnabled(),
compLevel,
volumeSize);
volumeSize,
compMethod);
return runProcess(m_param.value(AddProgram).toStringList(), args);
}
......@@ -754,7 +756,7 @@ QStringList CliInterface::substituteExtractVariables(const QStringList &extractA
return args;
}
QStringList CliInterface::substituteAddVariables(const QStringList &addArgs, const QList<Archive::Entry*> &entries, const QString &password, bool encryptHeader, int compLevel, ulong volumeSize)
QStringList CliInterface::substituteAddVariables(const QStringList &addArgs, const QList<Archive::Entry*> &entries, const QString &password, bool encryptHeader, int compLevel, ulong volumeSize, QString compMethod)
{
// Required if we call this function from unit tests.
cacheParameterList();
......@@ -778,6 +780,11 @@ QStringList CliInterface::substituteAddVariables(const QStringList &addArgs, con
continue;
}
if (arg == QLatin1String("$CompressionMethodSwitch")) {
args << compressionMethodSwitch(compMethod);
continue;
}
if (arg == QLatin1String("$MultiVolumeSwitch")) {
args << multiVolumeSwitch(volumeSize);
continue;
......@@ -1037,6 +1044,21 @@ QString CliInterface::compressionLevelSwitch(int level) const
return compLevelSwitch;
}
QString CliInterface::compressionMethodSwitch(const QString &method) const
{
if (method.isEmpty()) {
return QString();
}
Q_ASSERT(m_param.contains(CompressionMethodSwitch));
QString compMethodSwitch = m_param.value(CompressionMethodSwitch).toString();
Q_ASSERT(!compMethodSwitch.isEmpty());
compMethodSwitch.replace(QLatin1String("$CompressionMethod"), method);
return compMethodSwitch;
}
QString CliInterface::multiVolumeSwitch(ulong volumeSize) const
{
// The maximum value we allow in the QDoubleSpinBox is 1000MB. Converted to
......
......@@ -287,7 +287,8 @@ enum CliInterfaceParameters {
TestArgs,
TestPassedPattern,
MultiVolumeSwitch,
MultiVolumeSuffix
MultiVolumeSuffix,
CompressionMethodSwitch
};
typedef QHash<int, QVariant> ParameterList;
......@@ -335,7 +336,7 @@ public:
QStringList substituteListVariables(const QStringList &listArgs, const QString &password);
QStringList substituteExtractVariables(const QStringList &extractArgs, const QList<Archive::Entry*> &entries, bool preservePaths, const QString &password);
QStringList substituteAddVariables(const QStringList &addArgs, const QList<Archive::Entry*> &entries, const QString &password, bool encryptHeader, int compLevel, ulong volumeSize);
QStringList substituteAddVariables(const QStringList &addArgs, const QList<Archive::Entry*> &entries, const QString &password, bool encryptHeader, int compLevel, ulong volumeSize, QString compMethod);
QStringList substituteMoveVariables(const QStringList &moveArgs, const QList<Archive::Entry*> &entriesWithoutChildren, const Archive::Entry *destination, const QString &password);
QStringList substituteDeleteVariables(const QStringList &deleteArgs, const QList<Archive::Entry*> &entries, const QString &password);
QStringList substituteCommentVariables(const QStringList &commentArgs, const QString &commentFile);
......@@ -366,6 +367,7 @@ public:
*/
QString compressionLevelSwitch(int level) const;
virtual QString compressionMethodSwitch(const QString &method) const;
QString multiVolumeSwitch(ulong volumeSize) const;
/**
......
......@@ -65,6 +65,9 @@ CompressionOptions CompressionOptionsWidget::commpressionOptions() const
// Convert to kilobytes.
opts[QStringLiteral("VolumeSize")] = QString::number(volumeSize());
}
if (!compMethodComboBox->currentText().isEmpty()) {
opts[QStringLiteral("CompressionMethod")] = compMethodComboBox->currentText();
}
return opts;
}
......@@ -78,6 +81,11 @@ int CompressionOptionsWidget::compressionLevel() const
}
}
QString CompressionOptionsWidget::compressionMethod() const
{
return compMethodComboBox->currentText();
}
ulong CompressionOptionsWidget::volumeSize() const
{
if (collapsibleMultiVolume->isEnabled() && multiVolumeCheckbox->isChecked()) {
......@@ -132,14 +140,20 @@ void CompressionOptionsWidget::updateWidgets()
encryptHeaderCheckBox->setToolTip(QString());
}
collapsibleCompression->setEnabled(true);
if (archiveFormat.maxCompressionLevel() == 0) {
collapsibleCompression->setEnabled(false);
collapsibleCompression->setToolTip(i18n("It is not possible to set compression level for the %1 format.",
compLevelSlider->setEnabled(false);
lblCompLevel1->setEnabled(false);
lblCompLevel2->setEnabled(false);
lblCompLevel3->setEnabled(false);
compLevelSlider->setToolTip(i18n("It is not possible to set compression level for the %1 format.",
m_mimetype.comment()));
} else {
collapsibleCompression->setEnabled(true);
collapsibleCompression->setToolTip(QString());
compLevelSlider->setEnabled(true);
lblCompLevel1->setEnabled(true);
lblCompLevel2->setEnabled(true);
lblCompLevel3->setEnabled(true);
compLevelSlider->setToolTip(QString());
compLevelSlider->setMinimum(archiveFormat.minCompressionLevel());
compLevelSlider->setMaximum(archiveFormat.maxCompressionLevel());
if (m_opts.contains(QStringLiteral("CompressionLevel"))) {
......@@ -149,6 +163,27 @@ void CompressionOptionsWidget::updateWidgets()
}
}
if (archiveFormat.compressionMethods().isEmpty()) {
lblCompMethod->setEnabled(false);
compMethodComboBox->setEnabled(false);
compMethodComboBox->setToolTip(i18n("It is not possible to set compression method for the %1 format.",
m_mimetype.comment()));
compMethodComboBox->clear();
} else {
lblCompMethod->setEnabled(true);
compMethodComboBox->setEnabled(true);
compMethodComboBox->setToolTip(QString());
compMethodComboBox->clear();
compMethodComboBox->insertItems(0, archiveFormat.compressionMethods());
if (m_opts.contains(QStringLiteral("CompressionMethod")) &&
compMethodComboBox->findText(m_opts.value(QStringLiteral("CompressionMethod")).toString()) > -1) {
compMethodComboBox->setCurrentText(m_opts.value(QStringLiteral("CompressionMethod")).toString());
} else {
compMethodComboBox->setCurrentText(archiveFormat.defaultCompressionMethod());
}
}
collapsibleCompression->setEnabled(compLevelSlider->isEnabled() || compMethodComboBox->isEnabled());
if (archiveFormat.supportsMultiVolume()) {
collapsibleMultiVolume->setEnabled(true);
collapsibleMultiVolume->setToolTip(QString());
......
......@@ -45,6 +45,7 @@ public:
explicit CompressionOptionsWidget(QWidget *parent = Q_NULLPTR,
const CompressionOptions &opts = QHash<QString, QVariant>());
int compressionLevel() const;
QString compressionMethod() const;
ulong volumeSize() const;
QString password() const;
CompressionOptions commpressionOptions() const;
......
......@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>401</width>
<width>402</width>
<height>90</height>
</rect>
</property>
......@@ -23,15 +23,15 @@
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QLabel" name="label_6">
<item row="1" column="1">
<widget class="QLabel" name="lblCompLevel2">
<property name="text">
<string>Min</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_7">
<item row="1" column="2">
<widget class="QLabel" name="lblCompLevel3">
<property name="text">
<string>Max</string>
</property>
......@@ -40,8 +40,8 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<item row="2" column="0">
<widget class="QLabel" name="lblCompLevel1">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
......@@ -51,9 +51,12 @@
<property name="text">
<string>Level:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<item row="2" column="1" colspan="2">
<widget class="QSlider" name="compLevelSlider">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
......@@ -84,6 +87,19 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="compMethodComboBox"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblCompMethod">
<property name="text">
<string>Method:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
......@@ -202,15 +218,15 @@
</widget>
<customwidgets>
<customwidget>
<class>KCollapsibleGroupBox</class>
<class>KNewPasswordWidget</class>
<extends>QWidget</extends>
<header>kcollapsiblegroupbox.h</header>
<header>knewpasswordwidget.h</header>
<container>1</container>
</customwidget>