Commit 88611c6f authored by Méven Car's avatar Méven Car
Browse files

Use a better and simpler default name for multi-file archives

Now the default name of a multi-file archive created from the file actions plugin is the common prefix of those file's filename or "Archive.\[extension\]", if they don't match, instead of "\[name of parent folder\].\[extension\]".

aka:  
"Screenshot_123.jpg", "Screenshot_1234.jpg" => "Screenshot_123.\[extension\]"  
"cats.jpg", "dogs.jpg" => "Archive.\[extension\]"

CCBUG: 446728
parent 0bd3e70c
Pipeline #142456 passed with stage
in 2 minutes and 5 seconds
......@@ -42,7 +42,6 @@ QList<QAction*> CompressFileItemAction::actions(const KFileItemListProperties& f
const bool hasLocalUrl = std::any_of(urlList.begin(), urlList.end(), [](const QUrl &url) {
return url.isLocalFile();
});
const bool isSingleFile = urlList.count() == 1;
if (!hasLocalUrl) {
return {};
......@@ -50,21 +49,11 @@ QList<QAction*> CompressFileItemAction::actions(const KFileItemListProperties& f
QList<QAction*> actions;
const QIcon icon = QIcon::fromTheme(QStringLiteral("archive-insert"));
QString fileName;
if (!isSingleFile) {
fileName = AddToArchive::getFileName(urlList).section(QDir::separator(), -1);
if (fileName.length() > 20) {
fileName = fileName.left(10) + QStringLiteral("…") + fileName.right(10);
}
}
QMenu *compressMenu = new QMenu(parentWidget);
compressMenu->addAction(
createAction(icon,
isSingleFile ? i18nc("@action:inmenu Part of Compress submenu in Dolphin context menu", "Here (as TAR.GZ)")
: i18nc("@action:inmenu Part of Compress submenu in Dolphin context menu, %1 filename", "Here (to \"%1.tar.gz\")", fileName),
parentWidget,
urlList,
QStringLiteral("tar.gz")));
......@@ -74,15 +63,12 @@ QList<QAction*> CompressFileItemAction::actions(const KFileItemListProperties& f
if (!m_pluginManager->preferredWritePluginsFor(zipMime).isEmpty()) {
compressMenu->addAction(
createAction(icon,
isSingleFile ? i18nc("@action:inmenu Part of Compress submenu in Dolphin context menu", "Here (as ZIP)")
: i18nc("@action:inmenu Part of Compress submenu in Dolphin context menu, %1 filename", "Here (to \"%1.zip\")", fileName),
parentWidget,
urlList,
QStringLiteral("zip")));
}
compressMenu->addAction(createAction(icon,
i18nc("@action:inmenu Part of Compress submenu in Dolphin context menu", "Compress to..."),
parentWidget,
urlList,
QString()));
......@@ -96,8 +82,20 @@ QList<QAction*> CompressFileItemAction::actions(const KFileItemListProperties& f
return actions;
}
QAction *CompressFileItemAction::createAction(const QIcon& icon, const QString& name, QWidget *parent, const QList<QUrl>& urls, const QString& fileExtension)
QAction *CompressFileItemAction::createAction(const QIcon &icon, QWidget *parent, const QList<QUrl> &urls, const QString &fileExtension)
{
QString name;
if (fileExtension.isEmpty()) {
name = i18nc("@action:inmenu Part of Compress submenu in Dolphin context menu", "Compress to...");
} else {
QString fileName = AddToArchive::getFileNameForUrls(urls, fileExtension).section(QDir::separator(), -1);
if (fileName.length() > 21) {
fileName = fileName.left(10) + QStringLiteral("…") + fileName.right(10);
}
name = i18nc("@action:inmenu Part of Compress submenu in Dolphin context menu, %1 filename", "Here as \"%1\"", fileName);
}
QAction *action = new QAction(icon, name, parent);
connect(action, &QAction::triggered, this, [fileExtension, urls, name, parent, this]() {
......
......@@ -31,7 +31,7 @@ public:
QList<QAction*> actions(const KFileItemListProperties& fileItemInfos, QWidget* parentWidget) override;
private:
QAction *createAction(const QIcon& icon, const QString& name, QWidget *parent, const QList<QUrl>& urls, const QString& fileExtension);
QAction *createAction(const QIcon &icon, QWidget *parent, const QList<QUrl> &urls, const QString &fileExtension);
Kerfuffle::PluginManager *m_pluginManager;
};
......
......@@ -69,14 +69,16 @@ void AddToArchiveTest::testCompressHere_data()
<< 1ULL;
QTest::newRow("compress here (as TAR) - file + folder")
<< QStringLiteral("tar.gz")
<< Archive::Unencrypted
<< QStringList {
QFINDTESTDATA("data/testdir"),
QFINDTESTDATA("data/testfile.txt")
}
<< QStringLiteral("data.tar.gz")
<< 4ULL;
<< QStringLiteral("tar.gz") << Archive::Unencrypted << QStringList{QFINDTESTDATA("data/testdir"), QFINDTESTDATA("data/testfile.txt")}
<< QStringLiteral("Archive.tar.gz") << 4ULL;
QTest::newRow("compress here (as TAR) - files with same prefix")
<< QStringLiteral("tar.gz") << Archive::Unencrypted << QStringList{QFINDTESTDATA("data/textfile1.txt"), QFINDTESTDATA("data/textfile2.txt")}
<< QStringLiteral("textfile.tar.gz") << 2ULL;
QTest::newRow("compress here (as TAR) - files with same prefix too short")
<< QStringLiteral("tar.gz") << Archive::Unencrypted << QStringList{QFINDTESTDATA("data/testfile.txt"), QFINDTESTDATA("data/textfile2.txt")}
<< QStringLiteral("Archive.tar.gz") << 2ULL;
QTest::newRow("compress here (as TAR) - bug #362690")
<< QStringLiteral("tar.gz")
......@@ -115,14 +117,8 @@ void AddToArchiveTest::testCompressHere_data()
<< 1ULL;
QTest::newRow("compress here (as ZIP) - file + folder")
<< QStringLiteral("zip")
<< Archive::Unencrypted
<< QStringList {
QFINDTESTDATA("data/testdir"),
QFINDTESTDATA("data/testfile.txt")
}
<< QStringLiteral("data.zip")
<< 4ULL;
<< QStringLiteral("zip") << Archive::Unencrypted << QStringList{QFINDTESTDATA("data/testdir"), QFINDTESTDATA("data/testfile.txt")}
<< QStringLiteral("Archive.zip") << 4ULL;
QTest::newRow("compress here (as TAR) - dir with special name (see #365798)")
<< QStringLiteral("tar.gz")
......@@ -165,24 +161,12 @@ void AddToArchiveTest::testCompressHere_data()
<< 1ULL;
QTest::newRow("compress here (as RAR) - file + folder")
<< QStringLiteral("rar")
<< Archive::Unencrypted
<< QStringList {
QFINDTESTDATA("data/testdir"),
QFINDTESTDATA("data/testfile.txt")
}
<< QStringLiteral("data.rar")
<< 4ULL;
<< QStringLiteral("rar") << Archive::Unencrypted << QStringList{QFINDTESTDATA("data/testdir"), QFINDTESTDATA("data/testfile.txt")}
<< QStringLiteral("Archive.rar") << 4ULL;
QTest::newRow("compress to encrypted RAR - file + folder")
<< QStringLiteral("rar")
<< Archive::Encrypted
<< QStringList {
QFINDTESTDATA("data/testdir"),
QFINDTESTDATA("data/testfile.txt")
}
<< QStringLiteral("data.rar")
<< 4ULL;
<< QStringLiteral("rar") << Archive::Encrypted << QStringList{QFINDTESTDATA("data/testdir"), QFINDTESTDATA("data/testfile.txt")}
<< QStringLiteral("Archive.rar") << 4ULL;
} else {
qDebug() << "rar executable not found in path. Skipping compress-here-(RAR) tests.";
}
......@@ -211,6 +195,8 @@ void AddToArchiveTest::testCompressHere()
// Check the properties of the generated test archive, then remove it.
QFETCH(QString, expectedArchiveName);
QCOMPARE(addToArchiveJob->fileName().section(QLatin1Char('/'), -1), expectedArchiveName);
auto loadJob = Archive::load(QFINDTESTDATA(QStringLiteral("data/%1").arg(expectedArchiveName)));
QVERIFY(loadJob);
loadJob->setAutoDelete(false);
......
......@@ -16,11 +16,12 @@
#include <KLocalizedString>
#include <KMessageBox>
#include <QFileInfo>
#include <KFileUtils>
#include <QDir>
#include <QFileInfo>
#include <QMimeDatabase>
#include <QTimer>
#include <QPointer>
#include <QTimer>
namespace Kerfuffle
{
......@@ -70,7 +71,7 @@ bool AddToArchive::showAddDialog()
qCDebug(ARK) << "Opening add dialog";
if (m_filename.isEmpty()) {
m_filename = detectBaseName(m_entries);
m_filename = getFileNameForEntries(m_entries, QString());
}
QPointer<Kerfuffle::CreateDialog> dialog = new Kerfuffle::CreateDialog(
......@@ -183,32 +184,11 @@ void AddToArchive::slotStartJob()
void AddToArchive::detectFileName()
{
const QString base = detectBaseName(m_entries);
const QString suffix = !m_autoFilenameSuffix.isEmpty() ? QLatin1Char( '.' ) + m_autoFilenameSuffix : QString();
m_filename = getFileName(base, suffix);
}
QString AddToArchive::getFileName(const QList<QUrl> &entries)
{
return getFileName(detectBaseName(entries), QString());
}
QString AddToArchive::getFileName(const QString &base, const QString &suffix)
{
QString finalName = base + suffix;
//if file already exists, append a number to the base until it doesn't
//exist
int appendNumber = 0;
while (QFileInfo::exists(finalName)) {
++appendNumber;
finalName = base + QLatin1Char( '_' ) + QString::number(appendNumber) + suffix;
}
const QString suffix = !m_autoFilenameSuffix.isEmpty() ? m_autoFilenameSuffix : QString();
const QString finalName = getFileNameForEntries(m_entries, suffix);
qCDebug(ARK) << "Autoset filename to" << finalName;
return finalName;
m_filename = finalName;
}
void AddToArchive::slotFinished(KJob *job)
......@@ -222,33 +202,47 @@ void AddToArchive::slotFinished(KJob *job)
emitResult();
}
QString AddToArchive::detectBaseName(const QVector<Archive::Entry*> &entries) const
QString findCommonPrefixForUrls(const QList<QUrl> &list)
{
return getBaseName(entries.constFirst()->fullPath(), entries.size());
}
Q_ASSERT(!list.isEmpty());
QString prefix = list.front().fileName();
for (QList<QUrl>::const_iterator it = list.begin(); it != list.end(); ++it) {
const auto fileName = it->fileName();
if (prefix.length() > fileName.length()) {
prefix.truncate(fileName.length());
}
QString AddToArchive::detectBaseName(const QList<QUrl> &entries)
{
return getBaseName(entries.constFirst().toLocalFile(), entries.size());
for (int i = 0; i < prefix.length(); ++i) {
if (prefix.at(i) != fileName.at(i)) {
prefix.truncate(i);
break;
}
}
}
return prefix;
}
QString AddToArchive::getBaseName(const QString &url, const int size)
QString AddToArchive::getFileNameForUrls(const QList<QUrl> &urls, const QString &suffix)
{
QFileInfo fileInfo = QFileInfo(url);
QDir parentDir = fileInfo.dir();
QString base = parentDir.absolutePath() + QLatin1Char('/');
if (size > 1) {
if (!parentDir.isRoot()) {
// Use directory name for the new archive.
base += parentDir.dirName();
Q_ASSERT(!urls.isEmpty());
const QFileInfo fileInfo = QFileInfo(urls.constFirst().toLocalFile());
QString base;
if (urls.size() > 1) {
QString prefix = findCommonPrefixForUrls(urls);
if (prefix.length() < 5) {
base = i18nc("Default name of a newly-created multi-file archive", "Archive");
} else {
base = prefix;
}
} else {
// Strip filename of its extension, but only if present (see #362690).
if (!QMimeDatabase().mimeTypeForFile(fileInfo.fileName(), QMimeDatabase::MatchExtension).isDefault()) {
base += fileInfo.completeBaseName();
base = fileInfo.completeBaseName();
} else {
base += fileInfo.fileName();
base = fileInfo.fileName();
}
}
......@@ -257,11 +251,27 @@ QString AddToArchive::getBaseName(const QString &url, const int size)
base.chop(4);
}
if (base.endsWith(QLatin1Char('/'))) {
base.chop(1);
QString finalName = base + QLatin1Char('.') + suffix;
// if file already exists, append a number to the base until it doesn't
// exist
int appendNumber = 0;
const QString path = fileInfo.absolutePath() + QStringLiteral("/");
while (QFileInfo::exists(path + finalName)) {
++appendNumber;
finalName = KFileUtils::makeSuggestedName(finalName);
}
return base;
return path + finalName;
}
QString AddToArchive::getFileNameForEntries(const QVector<Archive::Entry *> &entries, const QString &suffix)
{
QList<QUrl> urls;
for (const auto &entry : entries) {
urls.append(QUrl::fromLocalFile(entry->fullPath()));
}
return getFileNameForUrls(urls, suffix);
}
void AddToArchive::setImmediateProgressReporting(bool immediateProgressReporting)
......
......@@ -39,9 +39,9 @@ public:
bool showAddDialog();
void setPreservePaths(bool value);
void setChangeToFirstPath(bool value);
QString detectBaseName(const QVector<Archive::Entry*> &entries) const;
static QString getFileName(const QList<QUrl> &entries);
void setImmediateProgressReporting(bool immediateProgressReporting);
static QString getFileNameForEntries(const QVector<Archive::Entry *> &entries, const QString &suffix);
static QString getFileNameForUrls(const QList<QUrl> &entries, const QString &suffix);
QString fileName() const
{
......@@ -65,9 +65,6 @@ private Q_SLOTS:
void slotStartJob();
private:
static QString detectBaseName(const QList<QUrl> &entries);
static QString getBaseName(const QString &url, const int size);
static QString getFileName(const QString &base, const QString &suffix);
void detectFileName();
CompressionOptions m_options;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment