summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElvis Angelaccio <elvis.angelaccio@kde.org>2016-10-02 14:00:26 (GMT)
committerElvis Angelaccio <elvis.angelaccio@kde.org>2016-10-02 14:00:26 (GMT)
commit88acd303900853f796e08107e34337bcb3a49971 (patch)
tree315cd0bba8087a67d5762e0c60a76035c00ae079
parent8cb2ca5f284c22ce17568391318fadfaae3468f4 (diff)
Refactor archive loading
Ark currently loads an archive by using `Archive *Archive::create()` first and then `ListJob *archive->list()`. If an archive property is read *before* list() is called, the archive is listed in the background with listIfNotListed(). This design is responsible for a lot or problems (see T1877, T3296 and T330). This commit refactors ListJob in a new LoadJob class. Is not possible anymore to create an archive and then list() it. Instead, a LoadJob is started first and then the archive can be retrieved at the end of the job. Differential Revision: D2811
-rw-r--r--app/batchextract.cpp98
-rw-r--r--app/batchextract.h20
-rw-r--r--autotests/kerfuffle/addtest.cpp9
-rw-r--r--autotests/kerfuffle/addtoarchivetest.cpp72
-rw-r--r--autotests/kerfuffle/copytest.cpp9
-rw-r--r--autotests/kerfuffle/extracttest.cpp27
-rw-r--r--autotests/kerfuffle/jobstest.cpp28
-rw-r--r--autotests/kerfuffle/movetest.cpp9
-rw-r--r--autotests/plugins/cli7zplugin/cli7ztest.cpp10
-rw-r--r--autotests/plugins/clirarplugin/clirartest.cpp13
-rw-r--r--autotests/plugins/cliunarchiverplugin/cliunarchivertest.cpp21
-rw-r--r--autotests/testhelper/testhelper.cpp8
-rw-r--r--kerfuffle/addtoarchive.cpp60
-rw-r--r--kerfuffle/archive_kerfuffle.cpp166
-rw-r--r--kerfuffle/archive_kerfuffle.h100
-rw-r--r--kerfuffle/extractiondialog.cpp15
-rw-r--r--kerfuffle/extractiondialog.h2
-rw-r--r--kerfuffle/jobs.cpp198
-rw-r--r--kerfuffle/jobs.h102
-rw-r--r--part/archivemodel.cpp48
-rw-r--r--part/archivemodel.h12
-rw-r--r--part/part.cpp82
-rw-r--r--part/part.h2
23 files changed, 716 insertions, 395 deletions
diff --git a/app/batchextract.cpp b/app/batchextract.cpp
index c3d755d..52cb73a 100644
--- a/app/batchextract.cpp
+++ b/app/batchextract.cpp
@@ -28,18 +28,16 @@
#include "batchextract.h"
#include "ark_debug.h"
-#include "kerfuffle/archive_kerfuffle.h"
#include "kerfuffle/extractiondialog.h"
#include "kerfuffle/jobs.h"
#include "kerfuffle/queries.h"
+#include <KIO/JobTracker>
#include <KLocalizedString>
#include <KMessageBox>
#include <KRun>
-#include <KIO/RenameDialog>
#include <kwidgetjobtracker.h>
-#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QPointer>
@@ -64,46 +62,21 @@ BatchExtract::~BatchExtract()
}
}
-void BatchExtract::addExtraction(Kerfuffle::Archive* archive)
+void BatchExtract::addExtraction(const QUrl& url)
{
QString destination = destinationFolder();
- const bool isSingleFolderRPM = (archive->isSingleFolderArchive() &&
- (archive->mimeType().name() == QLatin1String("application/x-rpm")));
-
- if ((autoSubfolder()) && (!archive->isSingleFolderArchive() || isSingleFolderRPM)) {
- const QDir d(destination);
- QString subfolderName = archive->subfolderName();
-
- // Special case for single folder RPM archives.
- // We don't want the autodetected folder to have a meaningless "usr" name.
- if (isSingleFolderRPM && subfolderName == QStringLiteral("usr")) {
- qCDebug(ARK) << "Detected single folder RPM archive. Using archive basename as subfolder name";
- subfolderName = QFileInfo(archive->fileName()).completeBaseName();
- }
-
- if (d.exists(subfolderName)) {
- subfolderName = KIO::suggestName(QUrl::fromUserInput(destination, QString(), QUrl::AssumeLocalFile), subfolderName);
- }
- d.mkdir(subfolderName);
-
- destination += QLatin1Char( '/' ) + subfolderName;
- }
+ auto job = Kerfuffle::Archive::batchExtract(url.toLocalFile(), destination, autoSubfolder(), preservePaths());
- Kerfuffle::ExtractionOptions options;
- options[QStringLiteral("PreservePaths")] = preservePaths();
-
- Kerfuffle::ExtractJob *job = archive->extractFiles(QList<Kerfuffle::Archive::Entry*>(), destination, options);
-
- qCDebug(ARK) << QString(QStringLiteral("Registering job from archive %1, to %2, preservePaths %3")).arg(archive->fileName(), destination, QString::number(preservePaths()));
+ qCDebug(ARK) << QString(QStringLiteral("Registering job from archive %1, to %2, preservePaths %3")).arg(url.toLocalFile(), destination, QString::number(preservePaths()));
addSubjob(job);
- m_fileNames[job] = qMakePair(archive->fileName(), destination);
+ m_fileNames[job] = qMakePair(url.toLocalFile(), destination);
connect(job, SIGNAL(percent(KJob*,ulong)),
this, SLOT(forwardProgress(KJob*,ulong)));
- connect(job, &Kerfuffle::Job::userQuery,
+ connect(job, &Kerfuffle::BatchExtractJob::userQuery,
this, &BatchExtract::slotUserQuery);
}
@@ -129,14 +102,13 @@ void BatchExtract::start()
void BatchExtract::slotStartJob()
{
- // If none of the archives could be loaded, there is no subjob to run
if (m_inputs.isEmpty()) {
emitResult();
return;
}
- foreach(Kerfuffle::Archive *archive, m_inputs) {
- addExtraction(archive);
+ foreach (const auto& url, m_inputs) {
+ addExtraction(url);
}
KIO::getJobTracker()->registerJob(this);
@@ -167,25 +139,24 @@ void BatchExtract::slotResult(KJob *job)
// TODO: The user must be informed about which file caused the error, and that the other files
// in the queue will not be extracted.
if (job->error()) {
- qCDebug(ARK) << "There was en error:" << job->error() << ", errorText:" << job->errorText();
+ qCDebug(ARK) << "There was en error:" << job->error() << ", errorText:" << job->errorString();
- setErrorText(job->errorText());
+ setErrorText(job->errorString());
setError(job->error());
removeSubjob(job);
if (job->error() != KJob::KilledJobError) {
- KMessageBox::error(NULL, job->errorText().isEmpty() ?
- i18n("There was an error during extraction.") : job->errorText());
+ KMessageBox::error(Q_NULLPTR, job->errorString().isEmpty() ?
+ i18n("There was an error during extraction.") : job->errorString());
}
emitResult();
-
return;
- } else {
- removeSubjob(job);
}
+ removeSubjob(job);
+
if (!hasSubjobs()) {
if (openDestinationAfterExtraction()) {
QUrl destination(destinationFolder());
@@ -213,21 +184,16 @@ void BatchExtract::forwardProgress(KJob *job, unsigned long percent)
setPercent(jobPart *(m_initialJobCount - subjobs().size()) + percent / m_initialJobCount);
}
-bool BatchExtract::addInput(const QUrl& url)
+void BatchExtract::addInput(const QUrl& url)
{
qCDebug(ARK) << "Adding archive" << url.toLocalFile();
- Kerfuffle::Archive *archive = Kerfuffle::Archive::create(url.toLocalFile(), this);
- Q_ASSERT(archive);
-
if (!QFileInfo::exists(url.toLocalFile())) {
m_failedFiles.append(url.fileName());
- return false;
+ return;
}
- m_inputs.append(archive);
-
- return true;
+ m_inputs.append(url);
}
bool BatchExtract::openDestinationAfterExtraction() const
@@ -280,14 +246,36 @@ bool BatchExtract::showExtractDialog()
dialog.data()->setCurrentUrl(QUrl::fromUserInput(destinationFolder(), QString(), QUrl::AssumeLocalFile));
dialog.data()->setPreservePaths(preservePaths());
+ // Only one archive, we need a LoadJob to get the single-folder and subfolder properties.
+ // TODO: find a better way (e.g. let the dialog handle everything), otherwise we list
+ // the archive twice (once here and once in the following BatchExtractJob).
+ Kerfuffle::LoadJob *loadJob = Q_NULLPTR;
if (m_inputs.size() == 1) {
- if (m_inputs.at(0)->isSingleFolderArchive()) {
- dialog.data()->setSingleFolderArchive(true);
- }
- dialog.data()->setSubfolder(m_inputs.at(0)->subfolderName());
+ loadJob = Kerfuffle::Archive::load(m_inputs.at(0).toLocalFile(), this);
+ // We need to access the job after result has been emitted, if the user rejects the dialog.
+ loadJob->setAutoDelete(false);
+
+ connect(loadJob, &KJob::result, this, [=](KJob *job) {
+ if (job->error()) {
+ return;
+ }
+
+ auto archive = qobject_cast<Kerfuffle::LoadJob*>(job)->archive();
+ dialog->setSingleFolderArchive(archive->isSingleFolder());
+ dialog->setSubfolder(archive->subfolderName());
+ });
+
+ connect(loadJob, &KJob::result, dialog.data(), &Kerfuffle::ExtractionDialog::setReadyGui);
+ dialog->setBusyGui();
+ // NOTE: we exploit the dialog->exec() below to run this job.
+ loadJob->start();
}
if (!dialog.data()->exec()) {
+ if (loadJob) {
+ loadJob->kill();
+ loadJob->deleteLater();
+ }
delete dialog.data();
return false;
}
diff --git a/app/batchextract.h b/app/batchextract.h
index ff0ae8e..33efe17 100644
--- a/app/batchextract.h
+++ b/app/batchextract.h
@@ -29,9 +29,10 @@
#ifndef BATCHEXTRACT_H
#define BATCHEXTRACT_H
-#include <kcompositejob.h>
+#include <KCompositeJob>
#include <QMap>
+#include <QVector>
namespace Kerfuffle
{
@@ -63,15 +64,15 @@ public:
virtual ~BatchExtract();
/**
- * Creates an ExtractJob for the given @p archive and puts it on the queue.
+ * Creates a BatchExtractJob for the given @p url and puts it on the queue.
*
- * If necessary, the destination directory for the archive is created.
+ * If necessary, the destination directory for the archive is created by the job.
*
- * @param archive The archive that will be extracted.
+ * @param url The url of the archive that will be extracted.
*
* @see setAutoSubfolder
*/
- void addExtraction(Kerfuffle::Archive* archive);
+ void addExtraction(const QUrl& url);
/**
* A wrapper that calls slotStartJob() when the event loop has started.
@@ -106,13 +107,8 @@ public:
* Adds a file to the list of files that will be extracted.
*
* @param url The file that will be added to the list.
- *
- * @return @c true The file exists and a suitable plugin
- * could be found for it.
- * @return @c false The file does not exist or a suitable
- * plugin could not be found.
*/
- bool addInput(const QUrl& url);
+ void addInput(const QUrl& url);
/**
* Shows the extract options dialog before extracting the files.
@@ -220,7 +216,7 @@ private:
QMap<KJob*, QPair<QString, QString> > m_fileNames;
bool m_autoSubfolder;
- QList<Kerfuffle::Archive*> m_inputs;
+ QVector<QUrl> m_inputs;
QString m_destinationFolder;
QStringList m_failedFiles;
bool m_preservePaths;
diff --git a/autotests/kerfuffle/addtest.cpp b/autotests/kerfuffle/addtest.cpp
index 788bc66..3bcc294 100644
--- a/autotests/kerfuffle/addtest.cpp
+++ b/autotests/kerfuffle/addtest.cpp
@@ -23,7 +23,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "autotests/testhelper/testhelper.h"
+#include "testhelper.h"
using namespace Kerfuffle;
@@ -106,7 +106,12 @@ void AddTest::testAdding()
QFETCH(QString, archiveName);
const QString archivePath = temporaryDir.path() + QLatin1Char('/') + archiveName;
Q_ASSERT(QFile::copy(QFINDTESTDATA(QStringLiteral("data/") + archiveName), archivePath));
- Archive *archive = Archive::create(archivePath, this);
+
+ auto loadJob = Archive::load(archivePath);
+ QVERIFY(loadJob);
+
+ TestHelper::startAndWaitForResult(loadJob);
+ auto archive = loadJob->archive();
QVERIFY(archive);
if (!archive->isValid()) {
diff --git a/autotests/kerfuffle/addtoarchivetest.cpp b/autotests/kerfuffle/addtoarchivetest.cpp
index 1a443b3..c587af7 100644
--- a/autotests/kerfuffle/addtoarchivetest.cpp
+++ b/autotests/kerfuffle/addtoarchivetest.cpp
@@ -23,11 +23,10 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "kerfuffle/addtoarchive.h"
-#include "kerfuffle/archive_kerfuffle.h"
-#include "kerfuffle/pluginmanager.h"
+#include "addtoarchive.h"
+#include "pluginmanager.h"
+#include "testhelper.h"
-#include <QEventLoop>
#include <QMimeDatabase>
#include <QStandardPaths>
#include <QTest>
@@ -43,7 +42,6 @@ private Q_SLOTS:
void init();
void testCompressHere_data();
void testCompressHere();
- void testCreateEncryptedArchive();
};
void AddToArchiveTest::init()
@@ -55,6 +53,7 @@ void AddToArchiveTest::init()
void AddToArchiveTest::testCompressHere_data()
{
QTest::addColumn<QString>("expectedSuffix");
+ QTest::addColumn<Archive::EncryptionType>("expectedEncryptionType");
QTest::addColumn<QStringList>("inputFiles");
QTest::addColumn<QString>("expectedArchiveName");
QTest::addColumn<qulonglong>("expectedNumberOfFiles");
@@ -62,6 +61,7 @@ void AddToArchiveTest::testCompressHere_data()
QTest::newRow("compress here (as TAR) - dir with files")
<< QStringLiteral("tar.gz")
+ << Archive::Unencrypted
<< QStringList {QFINDTESTDATA("data/testdir")}
<< QStringLiteral("testdir.tar.gz")
<< 2ULL
@@ -69,6 +69,7 @@ void AddToArchiveTest::testCompressHere_data()
QTest::newRow("compress here (as TAR) - dir with subdirs")
<< QStringLiteral("tar.gz")
+ << Archive::Unencrypted
<< QStringList {QFINDTESTDATA("data/testdirwithsubdirs")}
<< QStringLiteral("testdirwithsubdirs.tar.gz")
<< 4ULL
@@ -76,6 +77,7 @@ void AddToArchiveTest::testCompressHere_data()
QTest::newRow("compress here (as TAR) - dir with empty subdir")
<< QStringLiteral("tar.gz")
+ << Archive::Unencrypted
<< QStringList {QFINDTESTDATA("data/testdirwithemptysubdir")}
<< QStringLiteral("testdirwithemptysubdir.tar.gz")
<< 2ULL
@@ -83,6 +85,7 @@ void AddToArchiveTest::testCompressHere_data()
QTest::newRow("compress here (as TAR) - single file")
<< QStringLiteral("tar.gz")
+ << Archive::Unencrypted
<< QStringList {QFINDTESTDATA("data/testfile.txt")}
<< QStringLiteral("testfile.tar.gz")
<< 1ULL
@@ -90,6 +93,7 @@ void AddToArchiveTest::testCompressHere_data()
QTest::newRow("compress here (as TAR) - file + folder")
<< QStringLiteral("tar.gz")
+ << Archive::Unencrypted
<< QStringList {
QFINDTESTDATA("data/testdir"),
QFINDTESTDATA("data/testfile.txt")
@@ -100,6 +104,7 @@ void AddToArchiveTest::testCompressHere_data()
QTest::newRow("compress here (as TAR) - bug #362690")
<< QStringLiteral("tar.gz")
+ << Archive::Unencrypted
<< QStringList {QFINDTESTDATA("data/test-3.4.0")}
<< QStringLiteral("test-3.4.0.tar.gz")
<< 1ULL
@@ -108,6 +113,7 @@ void AddToArchiveTest::testCompressHere_data()
if (!PluginManager().preferredWritePluginsFor(QMimeDatabase().mimeTypeForName(QStringLiteral("application/zip"))).isEmpty()) {
QTest::newRow("compress here (as ZIP) - dir with files")
<< QStringLiteral("zip")
+ << Archive::Unencrypted
<< QStringList {QFINDTESTDATA("data/testdir")}
<< QStringLiteral("testdir.zip")
<< 2ULL
@@ -115,6 +121,7 @@ void AddToArchiveTest::testCompressHere_data()
QTest::newRow("compress here (as ZIP) - dir with subdirs")
<< QStringLiteral("zip")
+ << Archive::Unencrypted
<< QStringList {QFINDTESTDATA("data/testdirwithsubdirs")}
<< QStringLiteral("testdirwithsubdirs.zip")
<< 4ULL
@@ -122,6 +129,7 @@ void AddToArchiveTest::testCompressHere_data()
QTest::newRow("compress here (as ZIP) - dir with empty subdir")
<< QStringLiteral("zip")
+ << Archive::Unencrypted
<< QStringList {QFINDTESTDATA("data/testdirwithemptysubdir")}
<< QStringLiteral("testdirwithemptysubdir.zip")
<< 2ULL
@@ -129,6 +137,7 @@ void AddToArchiveTest::testCompressHere_data()
QTest::newRow("compress here (as ZIP) - single file")
<< QStringLiteral("zip")
+ << Archive::Unencrypted
<< QStringList {QFINDTESTDATA("data/testfile.txt")}
<< QStringLiteral("testfile.zip")
<< 1ULL
@@ -136,6 +145,7 @@ void AddToArchiveTest::testCompressHere_data()
QTest::newRow("compress here (as ZIP) - file + folder")
<< QStringLiteral("zip")
+ << Archive::Unencrypted
<< QStringList {
QFINDTESTDATA("data/testdir"),
QFINDTESTDATA("data/testfile.txt")
@@ -146,6 +156,7 @@ void AddToArchiveTest::testCompressHere_data()
QTest::newRow("compress here (as TAR) - dir with special name (see #365798)")
<< QStringLiteral("tar.gz")
+ << Archive::Unencrypted
<< QStringList {QFINDTESTDATA("data/test%dir")}
<< QStringLiteral("test%dir.tar.gz")
<< 2ULL
@@ -157,6 +168,7 @@ void AddToArchiveTest::testCompressHere_data()
if (!PluginManager().preferredWritePluginsFor(QMimeDatabase().mimeTypeForName(QStringLiteral("application/vnd.rar"))).isEmpty()) {
QTest::newRow("compress here (as RAR) - dir with files")
<< QStringLiteral("rar")
+ << Archive::Unencrypted
<< QStringList {QFINDTESTDATA("data/testdir")}
<< QStringLiteral("testdir.rar")
<< 2ULL
@@ -164,6 +176,7 @@ void AddToArchiveTest::testCompressHere_data()
QTest::newRow("compress here (as RAR) - dir with subdirs")
<< QStringLiteral("rar")
+ << Archive::Unencrypted
<< QStringList {QFINDTESTDATA("data/testdirwithsubdirs")}
<< QStringLiteral("testdirwithsubdirs.rar")
<< 4ULL
@@ -171,6 +184,7 @@ void AddToArchiveTest::testCompressHere_data()
QTest::newRow("compress here (as RAR) - dir with empty subdir")
<< QStringLiteral("rar")
+ << Archive::Unencrypted
<< QStringList {QFINDTESTDATA("data/testdirwithemptysubdir")}
<< QStringLiteral("testdirwithemptysubdir.rar")
<< 2ULL
@@ -178,6 +192,7 @@ void AddToArchiveTest::testCompressHere_data()
QTest::newRow("compress here (as RAR) - single file")
<< QStringLiteral("rar")
+ << Archive::Unencrypted
<< QStringList {QFINDTESTDATA("data/testfile.txt")}
<< QStringLiteral("testfile.rar")
<< 1ULL
@@ -185,6 +200,18 @@ void AddToArchiveTest::testCompressHere_data()
QTest::newRow("compress here (as RAR) - file + folder")
<< QStringLiteral("rar")
+ << Archive::Unencrypted
+ << QStringList {
+ QFINDTESTDATA("data/testdir"),
+ QFINDTESTDATA("data/testfile.txt")
+ }
+ << QStringLiteral("data.rar")
+ << 3ULL
+ << 1ULL;
+
+ QTest::newRow("compress to encrypted RAR - file + folder")
+ << QStringLiteral("rar")
+ << Archive::Encrypted
<< QStringList {
QFINDTESTDATA("data/testdir"),
QFINDTESTDATA("data/testfile.txt")
@@ -205,25 +232,33 @@ void AddToArchiveTest::testCompressHere()
QFETCH(QString, expectedSuffix);
addToArchiveJob->setAutoFilenameSuffix(expectedSuffix);
+ QFETCH(Archive::EncryptionType, expectedEncryptionType);
+ if (expectedEncryptionType == Archive::Encrypted) {
+ addToArchiveJob->setPassword(QLatin1String("1234"));
+ }
+
QFETCH(QStringList, inputFiles);
foreach (const QString &file, inputFiles) {
addToArchiveJob->addInput(QUrl::fromUserInput(file));
}
- // Run the job in the following event loop.
- QEventLoop eventLoop(this);
- connect(addToArchiveJob, &KJob::result, &eventLoop, &QEventLoop::quit);
- addToArchiveJob->start();
- eventLoop.exec(); // krazy:exclude=crashy
+ // Run the job.
+ TestHelper::startAndWaitForResult(addToArchiveJob);
// Check the properties of the generated test archive, then remove it.
QFETCH(QString, expectedArchiveName);
- Archive *archive = Archive::create(QFINDTESTDATA(QStringLiteral("data/%1").arg(expectedArchiveName)));
+ auto loadJob = Archive::load(QFINDTESTDATA(QStringLiteral("data/%1").arg(expectedArchiveName)));
+ QVERIFY(loadJob);
+
+ TestHelper::startAndWaitForResult(loadJob);
+ auto archive = loadJob->archive();
QVERIFY(archive);
QVERIFY(archive->isValid());
QCOMPARE(archive->completeBaseName() + QLatin1Char('.') + expectedSuffix, expectedArchiveName);
+ QCOMPARE(archive->encryptionType(), expectedEncryptionType);
+
QFETCH(qulonglong, expectedNumberOfFiles);
QCOMPARE(archive->numberOfFiles(), expectedNumberOfFiles);
@@ -231,21 +266,6 @@ void AddToArchiveTest::testCompressHere()
QCOMPARE(archive->numberOfFolders(), expectedNumberOfFolders);
QVERIFY(QFile(archive->fileName()).remove());
-}
-
-void AddToArchiveTest::testCreateEncryptedArchive()
-{
- Archive *archive = Archive::create(QStringLiteral("foo.zip"));
- QVERIFY(archive);
-
- if (!archive->isValid()) {
- QSKIP("Could not find a plugin to handle the archive. Skipping test.", SkipSingle);
- }
-
- QCOMPARE(archive->encryptionType(), Archive::Unencrypted);
-
- archive->encrypt(QStringLiteral("1234"), false);
- QCOMPARE(archive->encryptionType(), Archive::Encrypted);
archive->deleteLater();
}
diff --git a/autotests/kerfuffle/copytest.cpp b/autotests/kerfuffle/copytest.cpp
index 3d27dea..b0bcfcd 100644
--- a/autotests/kerfuffle/copytest.cpp
+++ b/autotests/kerfuffle/copytest.cpp
@@ -23,7 +23,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "autotests/testhelper/testhelper.h"
+#include "testhelper.h"
using namespace Kerfuffle;
@@ -173,7 +173,12 @@ void CopyTest::testCopying()
QFETCH(QString, archiveName);
const QString archivePath = temporaryDir.path() + QLatin1Char('/') + archiveName;
Q_ASSERT(QFile::copy(QFINDTESTDATA(QStringLiteral("data/") + archiveName), archivePath));
- Archive *archive = Archive::create(archivePath, this);
+
+ auto loadJob = Archive::load(archivePath);
+ QVERIFY(loadJob);
+
+ TestHelper::startAndWaitForResult(loadJob);
+ auto archive = loadJob->archive();
QVERIFY(archive);
if (!archive->isValid()) {
diff --git a/autotests/kerfuffle/extracttest.cpp b/autotests/kerfuffle/extracttest.cpp
index a4ea991..61e371b 100644
--- a/autotests/kerfuffle/extracttest.cpp
+++ b/autotests/kerfuffle/extracttest.cpp
@@ -24,8 +24,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "kerfuffle/archive_kerfuffle.h"
-#include "kerfuffle/jobs.h"
+#include "testhelper.h"
#include <QDirIterator>
#include <QStandardPaths>
@@ -62,8 +61,8 @@ void ExtractTest::testProperties_data()
QTest::newRow("non-existent tar archive")
<< QStringLiteral("/tmp/foo.tar.gz")
<< QStringLiteral("foo")
- << false << false << false << false << 0 << Archive::Unencrypted
- << QString();
+ << false << false << true << false << 0 << Archive::Unencrypted
+ << QStringLiteral("foo");
// Test non-archive file
QTest::newRow("not an archive")
@@ -195,7 +194,11 @@ void ExtractTest::testProperties_data()
void ExtractTest::testProperties()
{
QFETCH(QString, archivePath);
- Archive *archive = Archive::create(archivePath, this);
+ auto loadJob = Archive::load(archivePath, this);
+ QVERIFY(loadJob);
+
+ TestHelper::startAndWaitForResult(loadJob);
+ auto archive = loadJob->archive();
QVERIFY(archive);
if (!archive->isValid()) {
@@ -218,7 +221,7 @@ void ExtractTest::testProperties()
}
QFETCH(bool, isSingleFolder);
- QCOMPARE(archive->isSingleFolderArchive(), isSingleFolder);
+ QCOMPARE(archive->isSingleFolder(), isSingleFolder);
QFETCH(bool, isMultiVolume);
QCOMPARE(archive->isMultiVolume(), isMultiVolume);
@@ -589,7 +592,12 @@ void ExtractTest::testExtraction_data()
void ExtractTest::testExtraction()
{
QFETCH(QString, archivePath);
- Archive *archive = Archive::create(archivePath, this);
+ auto loadJob = Archive::load(archivePath, this);
+ QVERIFY(loadJob);
+
+ Archive *archive = Q_NULLPTR;
+ TestHelper::startAndWaitForResult(loadJob);
+ archive = loadJob->archive();
QVERIFY(archive);
if (!archive->isValid()) {
@@ -605,10 +613,7 @@ void ExtractTest::testExtraction()
QFETCH(ExtractionOptions, extractionOptions);
auto extractionJob = archive->extractFiles(entriesToExtract, destDir.path(), extractionOptions);
- QEventLoop eventLoop(this);
- connect(extractionJob, &KJob::result, &eventLoop, &QEventLoop::quit);
- extractionJob->start();
- eventLoop.exec(); // krazy:exclude=crashy
+ TestHelper::startAndWaitForResult(extractionJob);
QFETCH(int, expectedExtractedEntriesCount);
int extractedEntriesCount = 0;
diff --git a/autotests/kerfuffle/jobstest.cpp b/autotests/kerfuffle/jobstest.cpp
index 8e8f811..c975b42 100644
--- a/autotests/kerfuffle/jobstest.cpp
+++ b/autotests/kerfuffle/jobstest.cpp
@@ -47,8 +47,8 @@ protected Q_SLOTS:
private Q_SLOTS:
// ListJob-related tests
- void testListJob_data();
- void testListJob();
+ void testLoadJob_data();
+ void testLoadJob();
// ExtractJob-related tests
void testExtractJobAccessors();
@@ -104,11 +104,11 @@ QList<Archive::Entry*> JobsTest::listEntries(JSONArchiveInterface *iface)
{
m_entries.clear();
- ListJob *listJob = new ListJob(iface);
- connect(listJob, &Job::newEntry,
+ auto job = new LoadJob(iface);
+ connect(job, &Job::newEntry,
this, &JobsTest::slotNewEntry);
- startAndWaitForResult(listJob);
+ startAndWaitForResult(job);
return m_entries;
}
@@ -120,7 +120,7 @@ void JobsTest::startAndWaitForResult(KJob *job)
m_eventLoop.exec();
}
-void JobsTest::testListJob_data()
+void JobsTest::testLoadJob_data()
{
QTest::addColumn<QString>("jsonArchive");
QTest::addColumn<qlonglong>("expectedExtractedFilesSize");
@@ -184,24 +184,24 @@ void JobsTest::testListJob_data()
};
}
-void JobsTest::testListJob()
+void JobsTest::testLoadJob()
{
QFETCH(QString, jsonArchive);
JSONArchiveInterface *iface = createArchiveInterface(jsonArchive);
QVERIFY(iface);
- ListJob *listJob = new ListJob(iface);
- listJob->setAutoDelete(false);
- startAndWaitForResult(listJob);
+ auto loadJob = new LoadJob(iface);
+ loadJob->setAutoDelete(false);
+ startAndWaitForResult(loadJob);
QFETCH(qlonglong, expectedExtractedFilesSize);
- QCOMPARE(listJob->extractedFilesSize(), expectedExtractedFilesSize);
+ QCOMPARE(loadJob->extractedFilesSize(), expectedExtractedFilesSize);
QFETCH(bool, isPasswordProtected);
- QCOMPARE(listJob->isPasswordProtected(), isPasswordProtected);
+ QCOMPARE(loadJob->isPasswordProtected(), isPasswordProtected);
QFETCH(bool, isSingleFolder);
- QCOMPARE(listJob->isSingleFolderArchive(), isSingleFolder);
+ QCOMPARE(loadJob->isSingleFolderArchive(), isSingleFolder);
QFETCH(QStringList, expectedEntryNames);
auto archiveEntries = listEntries(iface);
@@ -212,7 +212,7 @@ void JobsTest::testListJob()
QCOMPARE(archiveEntries.at(i)->fullPath(), expectedEntryNames.at(i));
}
- listJob->deleteLater();
+ loadJob->deleteLater();
}
void JobsTest::testExtractJobAccessors()
diff --git a/autotests/kerfuffle/movetest.cpp b/autotests/kerfuffle/movetest.cpp
index 11255d9..fe7dbb4 100644
--- a/autotests/kerfuffle/movetest.cpp
+++ b/autotests/kerfuffle/movetest.cpp
@@ -23,7 +23,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "autotests/testhelper/testhelper.h"
+#include "testhelper.h"
using namespace Kerfuffle;
@@ -151,7 +151,12 @@ void MoveTest::testMoving()
QFETCH(QString, archiveName);
const QString archivePath = temporaryDir.path() + QLatin1Char('/') + archiveName;
Q_ASSERT(QFile::copy(QFINDTESTDATA(QStringLiteral("data/") + archiveName), archivePath));
- Archive *archive = Archive::create(archivePath, this);
+
+ auto loadJob = Archive::load(archivePath);
+ QVERIFY(loadJob);
+
+ TestHelper::startAndWaitForResult(loadJob);
+ auto archive = loadJob->archive();
QVERIFY(archive);
if (!archive->isValid()) {
diff --git a/autotests/plugins/cli7zplugin/cli7ztest.cpp b/autotests/plugins/cli7zplugin/cli7ztest.cpp
index 655980f..503e9ef 100644
--- a/autotests/plugins/cli7zplugin/cli7ztest.cpp
+++ b/autotests/plugins/cli7zplugin/cli7ztest.cpp
@@ -24,6 +24,7 @@
*/
#include "cli7ztest.h"
+#include "testhelper.h"
#include <QFile>
#include <QSignalSpy>
@@ -31,7 +32,6 @@
#include <QTextStream>
#include <KPluginLoader>
-#include <QtCore/QVariant>
QTEST_GUILESS_MAIN(Cli7zTest)
@@ -72,7 +72,11 @@ void Cli7zTest::testArchive()
}
QFETCH(QString, archivePath);
- Archive *archive = Archive::create(archivePath, m_plugin, this);
+ auto loadJob = Archive::load(archivePath, m_plugin, this);
+ QVERIFY(loadJob);
+
+ TestHelper::startAndWaitForResult(loadJob);
+ auto archive = loadJob->archive();
QVERIFY(archive);
if (!archive->isValid()) {
@@ -86,7 +90,7 @@ void Cli7zTest::testArchive()
QCOMPARE(archive->isReadOnly(), isReadOnly);
QFETCH(bool, isSingleFolder);
- QCOMPARE(archive->isSingleFolderArchive(), isSingleFolder);
+ QCOMPARE(archive->isSingleFolder(), isSingleFolder);
QFETCH(Archive::EncryptionType, expectedEncryptionType);
QCOMPARE(archive->encryptionType(), expectedEncryptionType);
diff --git a/autotests/plugins/clirarplugin/clirartest.cpp b/autotests/plugins/clirarplugin/clirartest.cpp
index 5775b2b..945cd7e 100644
--- a/autotests/plugins/clirarplugin/clirartest.cpp
+++ b/autotests/plugins/clirarplugin/clirartest.cpp
@@ -25,15 +25,14 @@
*/
#include "clirartest.h"
-#include "kerfuffle/archiveentry.h"
+
+#include <KPluginLoader>
#include <QFile>
#include <QSignalSpy>
#include <QTest>
#include <QTextStream>
-#include <KPluginLoader>
-
QTEST_GUILESS_MAIN(CliRarTest)
using namespace Kerfuffle;
@@ -73,7 +72,11 @@ void CliRarTest::testArchive()
}
QFETCH(QString, archivePath);
- Archive *archive = Archive::create(archivePath, m_plugin, this);
+ auto loadJob = Archive::load(archivePath, m_plugin, this);
+ QVERIFY(loadJob);
+
+ TestHelper::startAndWaitForResult(loadJob);
+ auto archive = loadJob->archive();
QVERIFY(archive);
if (!archive->isValid()) {
@@ -87,7 +90,7 @@ void CliRarTest::testArchive()
QCOMPARE(archive->isReadOnly(), isReadOnly);
QFETCH(bool, isSingleFolder);
- QCOMPARE(archive->isSingleFolderArchive(), isSingleFolder);
+ QCOMPARE(archive->isSingleFolder(), isSingleFolder);
QFETCH(Archive::EncryptionType, expectedEncryptionType);
QCOMPARE(archive->encryptionType(), expectedEncryptionType);
diff --git a/autotests/plugins/cliunarchiverplugin/cliunarchivertest.cpp b/autotests/plugins/cliunarchiverplugin/cliunarchivertest.cpp
index 5036f5d..e9d7447 100644
--- a/autotests/plugins/cliunarchiverplugin/cliunarchivertest.cpp
+++ b/autotests/plugins/cliunarchiverplugin/cliunarchivertest.cpp
@@ -18,8 +18,9 @@
*/
#include "cliunarchivertest.h"
-#include "jobs.h"
-#include "kerfuffle/archiveentry.h"
+#include "testhelper.h"
+
+#include <KPluginLoader>
#include <QDirIterator>
#include <QFile>
@@ -27,8 +28,6 @@
#include <QTest>
#include <QTextStream>
-#include <KPluginLoader>
-
QTEST_GUILESS_MAIN(CliUnarchiverTest)
using namespace Kerfuffle;
@@ -83,7 +82,11 @@ void CliUnarchiverTest::testArchive()
}
QFETCH(QString, archivePath);
- Archive *archive = Archive::create(archivePath, m_plugin, this);
+ auto loadJob = Archive::load(archivePath, m_plugin, this);
+ QVERIFY(loadJob);
+
+ TestHelper::startAndWaitForResult(loadJob);
+ auto archive = loadJob->archive();
QVERIFY(archive);
if (!archive->isValid()) {
@@ -97,7 +100,7 @@ void CliUnarchiverTest::testArchive()
QCOMPARE(archive->isReadOnly(), isReadOnly);
QFETCH(bool, isSingleFolder);
- QCOMPARE(archive->isSingleFolderArchive(), isSingleFolder);
+ QCOMPARE(archive->isSingleFolder(), isSingleFolder);
QFETCH(Archive::EncryptionType, expectedEncryptionType);
QCOMPARE(archive->encryptionType(), expectedEncryptionType);
@@ -293,7 +296,11 @@ void CliUnarchiverTest::testExtraction()
}
QFETCH(QString, archivePath);
- Archive *archive = Archive::create(archivePath, m_plugin, this);
+ auto loadJob = Archive::load(archivePath, m_plugin, this);
+ QVERIFY(loadJob);
+
+ TestHelper::startAndWaitForResult(loadJob);
+ auto archive = loadJob->archive();
QVERIFY(archive);
if (!archive->isValid()) {
diff --git a/autotests/testhelper/testhelper.cpp b/autotests/testhelper/testhelper.cpp
index d9a2161..b45c809 100644
--- a/autotests/testhelper/testhelper.cpp
+++ b/autotests/testhelper/testhelper.cpp
@@ -31,15 +31,15 @@ void TestHelper::startAndWaitForResult(KJob *job)
{
QObject::connect(job, &KJob::result, &m_eventLoop, &QEventLoop::quit);
job->start();
- m_eventLoop.exec();
+ m_eventLoop.exec(); // krazy:exclude=crashy
}
QList<Archive::Entry*> TestHelper::getEntryList(Archive *archive)
{
QList<Archive::Entry*> list = QList<Archive::Entry*>();
- ListJob *listJob = archive->list();
- QObject::connect(listJob, &Job::newEntry, [&list](Archive::Entry* entry) { list << entry; });
- startAndWaitForResult(listJob);
+ auto loadJob = Archive::load(archive->fileName());
+ QObject::connect(loadJob, &Job::newEntry, [&list](Archive::Entry* entry) { list << entry; });
+ startAndWaitForResult(loadJob);
return list;
}
diff --git a/kerfuffle/addtoarchive.cpp b/kerfuffle/addtoarchive.cpp
index c8f8d50..4b41ec5 100644
--- a/kerfuffle/addtoarchive.cpp
+++ b/kerfuffle/addtoarchive.cpp
@@ -27,8 +27,9 @@
*/
#include "addtoarchive.h"
-#include "ark_debug.h"
+#include "archiveentry.h"
#include "archive_kerfuffle.h"
+#include "ark_debug.h"
#include "createdialog.h"
#include "jobs.h"
@@ -38,7 +39,6 @@
#include <KLocalizedString>
#include <kio/job.h>
-#include <QDebug>
#include <QFileInfo>
#include <QDir>
#include <QMimeDatabase>
@@ -48,7 +48,9 @@
namespace Kerfuffle
{
AddToArchive::AddToArchive(QObject *parent)
- : KJob(parent), m_changeToFirstPath(false)
+ : KJob(parent)
+ , m_changeToFirstPath(false)
+ , m_enableHeaderEncryption(false)
{
}
@@ -134,19 +136,13 @@ void AddToArchive::start()
void AddToArchive::slotStartJob()
{
- Kerfuffle::CompressionOptions options;
-
if (m_entries.isEmpty()) {
KMessageBox::error(NULL, i18n("No input files were given."));
emitResult();
return;
}
- Kerfuffle::Archive *archive;
- if (!m_filename.isEmpty()) {
- archive = Kerfuffle::Archive::create(m_filename, m_mimeType, this);
- qCDebug(ARK) << "Set filename to " << m_filename;
- } else {
+ if (m_filename.isEmpty()) {
if (m_autoFilenameSuffix.isEmpty()) {
KMessageBox::error(Q_NULLPTR, xi18n("You need to either supply a filename for the archive or a suffix (such as rar, tar.gz) with the <command>--autofilename</command> argument."));
emitResult();
@@ -171,32 +167,11 @@ void AddToArchive::slotStartJob()
finalName = base + QLatin1Char( '_' ) + QString::number(appendNumber) + QLatin1Char( '.' ) + m_autoFilenameSuffix;
}
- qCDebug(ARK) << "Autoset filename to "<< finalName;
- archive = Kerfuffle::Archive::create(finalName, m_mimeType, this);
- }
-
- Q_ASSERT(archive);
-
- if (!archive->isValid()) {
- if (archive->error() == NoPlugin) {
- KMessageBox::error(Q_NULLPTR, i18n("Failed to create the new archive. No suitable plugin found."));
- emitResult();
- return;
- }
- if (archive->error() == FailedPlugin) {
- KMessageBox::error(Q_NULLPTR, i18n("Failed to create the new archive. Could not load a suitable plugin."));
- emitResult();
- return;
- }
- } else if (archive->isReadOnly()) {
- KMessageBox::error(Q_NULLPTR, i18n("It is not possible to create archives of this type."));
- emitResult();
- return;
+ qCDebug(ARK) << "Autoset filename to" << finalName;
+ m_filename = finalName;
}
- if (!m_password.isEmpty()) {
- archive->encrypt(m_password, m_enableHeaderEncryption);
- }
+ Kerfuffle::CompressionOptions options;
if (m_changeToFirstPath) {
if (m_firstPath.isEmpty()) {
@@ -215,22 +190,23 @@ void AddToArchive::slotStartJob()
qCDebug(ARK) << "Setting GlobalWorkDir to " << stripDir.path();
}
- Kerfuffle::AddJob *job =
- archive->addFiles(m_entries, new Archive::Entry(this), options);
-
- KIO::getJobTracker()->registerJob(job);
+ auto createJob = Archive::create(m_filename, m_mimeType, m_entries, options, this);
- connect(job, &Kerfuffle::AddJob::result, this, &AddToArchive::slotFinished);
+ if (!m_password.isEmpty()) {
+ createJob->enableEncryption(m_password, m_enableHeaderEncryption);
+ }
- job->start();
+ KIO::getJobTracker()->registerJob(createJob);
+ connect(createJob, &KJob::result, this, &AddToArchive::slotFinished);
+ createJob->start();
}
void AddToArchive::slotFinished(KJob *job)
{
qCDebug(ARK) << "AddToArchive job finished";
- if (job->error() && !job->errorText().isEmpty()) {
- KMessageBox::error(Q_NULLPTR, job->errorText());
+ if (job->error() && !job->errorString().isEmpty()) {
+ KMessageBox::error(Q_NULLPTR, job->errorString());
}
emitResult();
diff --git a/kerfuffle/archive_kerfuffle.cpp b/kerfuffle/archive_kerfuffle.cpp
index 41db04b..7256418 100644
--- a/kerfuffle/archive_kerfuffle.cpp
+++ b/kerfuffle/archive_kerfuffle.cpp
@@ -33,12 +33,12 @@
#include "mimetypes.h"
#include "pluginmanager.h"
-#include <QEventLoop>
-#include <QRegularExpression>
-
+#include <KLocalizedString>
#include <KPluginFactory>
#include <KPluginLoader>
+#include <QRegularExpression>
+
namespace Kerfuffle
{
@@ -101,6 +101,51 @@ Archive *Archive::create(const QString &fileName, Plugin *plugin, QObject *paren
return new Archive(iface, !plugin->isReadWrite(), parent);
}
+BatchExtractJob *Archive::batchExtract(const QString &fileName, const QString &destination, bool autoSubfolder, bool preservePaths, QObject *parent)
+{
+ auto loadJob = load(fileName, parent);
+ auto batchJob = new BatchExtractJob(loadJob, destination, autoSubfolder, preservePaths);
+
+ return batchJob;
+}
+
+CreateJob *Archive::create(const QString &fileName, const QString &mimeType, const QList<Archive::Entry *> &entries, const CompressionOptions &options, QObject *parent)
+{
+ auto archive = create(fileName, mimeType, parent);
+ auto createJob = new CreateJob(archive, entries, options);
+
+ return createJob;
+}
+
+Archive *Archive::createEmpty(const QString &fileName, const QString &mimeType, QObject *parent)
+{
+ auto archive = create(fileName, mimeType, parent);
+ Q_ASSERT(archive->isEmpty());
+
+ return archive;
+}
+
+LoadJob *Archive::load(const QString &fileName, QObject *parent)
+{
+ return load(fileName, QString(), parent);
+}
+
+LoadJob *Archive::load(const QString &fileName, const QString &mimeType, QObject *parent)
+{
+ auto archive = create(fileName, mimeType, parent);
+ auto loadJob = new LoadJob(archive);
+
+ return loadJob;
+}
+
+LoadJob *Archive::load(const QString &fileName, Plugin *plugin, QObject *parent)
+{
+ auto archive = create(fileName, plugin, parent);
+ auto loadJob = new LoadJob(archive);
+
+ return loadJob;
+}
+
Archive::Archive(ArchiveError errorCode, QObject *parent)
: QObject(parent)
, m_iface(Q_NULLPTR)
@@ -112,9 +157,8 @@ Archive::Archive(ArchiveError errorCode, QObject *parent)
Archive::Archive(ReadOnlyArchiveInterface *archiveInterface, bool isReadOnly, QObject *parent)
: QObject(parent)
, m_iface(archiveInterface)
- , m_hasBeenListed(false)
, m_isReadOnly(isReadOnly)
- , m_isSingleFolderArchive(false)
+ , m_isSingleFolder(false)
, m_isMultiVolume(false)
, m_extractedFilesSize(0)
, m_error(NoError)
@@ -124,8 +168,8 @@ Archive::Archive(ReadOnlyArchiveInterface *archiveInterface, bool isReadOnly, QO
{
qCDebug(ARK) << "Created archive instance";
- Q_ASSERT(archiveInterface);
- archiveInterface->setParent(this);
+ Q_ASSERT(m_iface);
+ m_iface->setParent(this);
connect(m_iface, &ReadOnlyArchiveInterface::entry, this, &Archive::onNewEntry);
}
@@ -207,20 +251,24 @@ QMimeType Archive::mimeType()
return m_mimeType;
}
-bool Archive::isReadOnly()
+bool Archive::isEmpty() const
+{
+ return (numberOfFiles() == 0) && (numberOfFolders() == 0);
+}
+
+bool Archive::isReadOnly() const
{
return isValid() ? (m_iface->isReadOnly() || m_isReadOnly ||
- (isMultiVolume() && (m_numberOfFiles > 0 || m_numberOfFolders > 0))) : false;
+ (isMultiVolume() && (numberOfFiles() > 0 || numberOfFolders() > 0))) : false;
}
-bool Archive::isSingleFolderArchive()
+bool Archive::isSingleFolder() const
{
if (!isValid()) {
return false;
}
- listIfNotListed();
- return m_isSingleFolderArchive;
+ return m_isSingleFolder;
}
bool Archive::hasComment() const
@@ -228,12 +276,12 @@ bool Archive::hasComment() const
return isValid() ? !comment().isEmpty() : false;
}
-bool Archive::isMultiVolume()
+bool Archive::isMultiVolume() const
{
if (!isValid()) {
return false;
}
- listIfNotListed();
+
return m_iface->isMultiVolume();
}
@@ -247,13 +295,12 @@ int Archive::numberOfVolumes() const
return m_iface->numberOfVolumes();
}
-Archive::EncryptionType Archive::encryptionType()
+Archive::EncryptionType Archive::encryptionType() const
{
if (!isValid()) {
return Unencrypted;
}
- listIfNotListed();
return m_encryptionType;
}
@@ -262,33 +309,30 @@ QString Archive::password() const
return m_iface->password();
}
-qulonglong Archive::numberOfFiles()
+qulonglong Archive::numberOfFiles() const
{
if (!isValid()) {
return 0;
}
- listIfNotListed();
return m_numberOfFiles;
}
-qulonglong Archive::numberOfFolders()
+qulonglong Archive::numberOfFolders() const
{
if (!isValid()) {
return 0;
}
- listIfNotListed();
return m_numberOfFolders;
}
-qulonglong Archive::unpackedSize()
+qulonglong Archive::unpackedSize() const
{
if (!isValid()) {
return 0;
}
- listIfNotListed();
return m_extractedFilesSize;
}
@@ -297,13 +341,12 @@ qulonglong Archive::packedSize() const
return isValid() ? QFileInfo(fileName()).size() : 0;
}
-QString Archive::subfolderName()
+QString Archive::subfolderName() const
{
if (!isValid()) {
return QString();
}
- listIfNotListed();
return m_subfolderName;
}
@@ -322,38 +365,6 @@ ArchiveError Archive::error() const
return m_error;
}
-KJob* Archive::open()
-{
- return 0;
-}
-
-KJob* Archive::create()
-{
- return 0;
-}
-
-ListJob* Archive::list()
-{
- if (!isValid() || !QFileInfo::exists(fileName())) {
- return Q_NULLPTR;
- }
-
- qCDebug(ARK) << "Going to list files";
-
- ListJob *job = new ListJob(m_iface);
-
- //if this job has not been listed before, we grab the opportunity to
- //collect some information about the archive
- if (!m_hasBeenListed) {
- connect(job, &ListJob::result, this, &Archive::onListFinished);
- }
-
- // FIXME: this is only a temporary workaround. See T3300 for a proper fix.
- m_hasBeenListed = true;
-
- return job;
-}
-
DeleteJob* Archive::deleteFiles(QList<Archive::Entry*> &entries)
{
if (!isValid()) {
@@ -489,42 +500,8 @@ void Archive::onAddFinished(KJob* job)
//folders/files other places than the root.
//TODO: handle the case of creating a new file and singlefolderarchive
//then.
- if (m_isSingleFolderArchive && !job->error()) {
- m_isSingleFolderArchive = false;
- }
-}
-
-void Archive::onListFinished(KJob* job)
-{
- ListJob *ljob = qobject_cast<ListJob*>(job);
- m_extractedFilesSize = ljob->extractedFilesSize();
- m_isSingleFolderArchive = ljob->isSingleFolderArchive();
- m_subfolderName = ljob->subfolderName();
- if (m_subfolderName.isEmpty()) {
- m_subfolderName = completeBaseName();
- }
-
- if (ljob->isPasswordProtected()) {
- // If we already know the password, it means that the archive is header-encrypted.
- m_encryptionType = m_iface->password().isEmpty() ? Encrypted : HeaderEncrypted;
- }
-}
-
-void Archive::listIfNotListed()
-{
- if (!m_hasBeenListed) {
- ListJob *job = list();
- if (!job) {
- return;
- }
-
- connect(job, &ListJob::userQuery, this, &Archive::onUserQuery);
-
- QEventLoop loop(this);
-
- connect(job, &KJob::result, &loop, &QEventLoop::quit);
- job->start();
- loop.exec(); // krazy:exclude=crashy
+ if (m_isSingleFolder && !job->error()) {
+ m_isSingleFolder = false;
}
}
@@ -548,4 +525,9 @@ QString Archive::multiVolumeName() const
return m_iface->multiVolumeName();
}
+ReadOnlyArchiveInterface *Archive::interface()
+{
+ return m_iface;
+}
+
} // namespace Kerfuffle
diff --git a/kerfuffle/archive_kerfuffle.h b/kerfuffle/archive_kerfuffle.h
index e715ced..2f17d73 100644
--- a/kerfuffle/archive_kerfuffle.h
+++ b/kerfuffle/archive_kerfuffle.h
@@ -30,18 +30,18 @@
#include "kerfuffle_export.h"
+#include <KJob>
+#include <KPluginMetaData>
+
#include <QHash>
#include <QMimeType>
-#include <QObject>
#include <QVariant>
-#include <KPluginMetaData>
-
-class KJob;
-
namespace Kerfuffle
{
-class ListJob;
+class LoadJob;
+class BatchExtractJob;
+class CreateJob;
class ExtractJob;
class DeleteJob;
class AddJob;
@@ -81,16 +81,17 @@ class KERFUFFLE_EXPORT Archive : public QObject
Q_PROPERTY(QString fileName READ fileName CONSTANT)
Q_PROPERTY(QString comment READ comment CONSTANT)
Q_PROPERTY(QMimeType mimeType READ mimeType CONSTANT)
+ Q_PROPERTY(bool isEmpty READ isEmpty)
Q_PROPERTY(bool isReadOnly READ isReadOnly CONSTANT)
- Q_PROPERTY(bool isSingleFolderArchive READ isSingleFolderArchive)
+ Q_PROPERTY(bool isSingleFolder MEMBER m_isSingleFolder READ isSingleFolder)
Q_PROPERTY(bool isMultiVolume READ isMultiVolume WRITE setMultiVolume)
Q_PROPERTY(bool numberOfVolumes READ numberOfVolumes)
- Q_PROPERTY(EncryptionType encryptionType READ encryptionType)
+ Q_PROPERTY(EncryptionType encryptionType MEMBER m_encryptionType READ encryptionType)
Q_PROPERTY(qulonglong numberOfFiles READ numberOfFiles)
Q_PROPERTY(qulonglong numberOfFolders READ numberOfFolders)
- Q_PROPERTY(qulonglong unpackedSize READ unpackedSize)
+ Q_PROPERTY(qulonglong unpackedSize MEMBER m_extractedFilesSize READ unpackedSize)
Q_PROPERTY(qulonglong packedSize READ packedSize)
- Q_PROPERTY(QString subfolderName READ subfolderName)
+ Q_PROPERTY(QString subfolderName MEMBER m_subfolderName READ subfolderName)
Q_PROPERTY(QString password READ password)
public:
@@ -109,45 +110,67 @@ public:
QString fileName() const;
QString comment() const;
QMimeType mimeType();
- bool isReadOnly();
- bool isSingleFolderArchive();
- bool isMultiVolume();
+ bool isEmpty() const;
+ bool isReadOnly() const;
+ bool isSingleFolder() const;
+ bool isMultiVolume() const;
void setMultiVolume(bool value);
bool hasComment() const;
int numberOfVolumes() const;
- EncryptionType encryptionType();
+ EncryptionType encryptionType() const;
QString password() const;
- qulonglong numberOfFiles();
- qulonglong numberOfFolders();
- qulonglong unpackedSize();
+ qulonglong numberOfFiles() const;
+ qulonglong numberOfFolders() const;
+ qulonglong unpackedSize() const;
qulonglong packedSize() const;
- QString subfolderName();
+ QString subfolderName() const;
void setCompressionOptions(const CompressionOptions &opts);
CompressionOptions compressionOptions() const;
QString multiVolumeName() const;
+ ReadOnlyArchiveInterface *interface();
- static Archive *create(const QString &fileName, QObject *parent = 0);
- static Archive *create(const QString &fileName, const QString &fixedMimeType, QObject *parent = 0);
+ /**
+ * @return Batch extraction job for @p filename to @p destination.
+ * @param autoSubfolder Whether the job will extract into a subfolder.
+ * @param preservePaths Whether the job will preserve paths.
+ * @param parent The parent for the archive.
+ */
+ static BatchExtractJob *batchExtract(const QString &fileName, const QString &destination, bool autoSubfolder, bool preservePaths, QObject *parent = Q_NULLPTR);
/**
- * Create an archive instance from a given @p plugin.
- * @param fileName The name of the archive.
- * @return A valid archive if the plugin could be loaded, an invalid one otherwise (with the FailedPlugin error set).
+ * @return Job to create an archive for the given @p entries.
+ * @param fileName The name of the new archive.
+ * @param mimeType The mimetype of the new archive.
*/
- static Archive *create(const QString &fileName, Plugin *plugin, QObject *parent = Q_NULLPTR);
+ static CreateJob* create(const QString &fileName, const QString &mimeType, const QList<Archive::Entry*> &entries, const CompressionOptions& options, QObject *parent = Q_NULLPTR);
- ~Archive();
+ /**
+ * @return An empty archive with name @p fileName, mimetype @p mimeType and @p parent as parent.
+ */
+ static Archive *createEmpty(const QString &fileName, const QString &mimeType, QObject *parent = Q_NULLPTR);
- ArchiveError error() const;
- bool isValid() const;
+ /**
+ * @return Job to load the archive @p fileName.
+ * @param parent The parent of the archive that will be loaded.
+ */
+ static LoadJob* load(const QString &fileName, QObject *parent = Q_NULLPTR);
- KJob* open();
- KJob* create();
+ /**
+ * @return Job to load the archive @p fileName with mimetype @p mimeType.
+ * @param parent The parent of the archive that will be loaded.
+ */
+ static LoadJob* load(const QString &fileName, const QString &mimeType, QObject *parent = Q_NULLPTR);
/**
- * @return A ListJob if the archive already exists. A null pointer otherwise.
+ * @return Job to load the archive @p fileName by using @p plugin.
+ * @param parent The parent of the archive that will be loaded.
*/
- ListJob* list();
+ static LoadJob* load(const QString &fileName, Plugin *plugin, QObject *parent = Q_NULLPTR);
+
+ ~Archive();
+
+ ArchiveError error() const;
+ bool isValid() const;
DeleteJob* deleteFiles(QList<Archive::Entry*> &entries);
CommentJob* addComment(const QString &comment);
@@ -195,7 +218,6 @@ public:
void encrypt(const QString &password, bool encryptHeader);
private slots:
- void onListFinished(KJob*);
void onAddFinished(KJob*);
void onUserQuery(Kerfuffle::Query*);
void onNewEntry(const Archive::Entry *entry);
@@ -204,11 +226,19 @@ private:
Archive(ReadOnlyArchiveInterface *archiveInterface, bool isReadOnly, QObject *parent = 0);
Archive(ArchiveError errorCode, QObject *parent = 0);
- void listIfNotListed();
+ static Archive *create(const QString &fileName, QObject *parent = 0);
+ static Archive *create(const QString &fileName, const QString &fixedMimeType, QObject *parent = 0);
+
+ /**
+ * Create an archive instance from a given @p plugin.
+ * @param fileName The name of the archive.
+ * @return A valid archive if the plugin could be loaded, an invalid one otherwise (with the FailedPlugin error set).
+ */
+ static Archive *create(const QString &fileName, Plugin *plugin, QObject *parent = Q_NULLPTR);
+
ReadOnlyArchiveInterface *m_iface;
- bool m_hasBeenListed;
bool m_isReadOnly;
- bool m_isSingleFolderArchive;
+ bool m_isSingleFolder;
bool m_isMultiVolume;
QString m_subfolderName;
diff --git a/kerfuffle/extractiondialog.cpp b/kerfuffle/extractiondialog.cpp
index c87ef20..edaed28 100644
--- a/kerfuffle/extractiondialog.cpp
+++ b/kerfuffle/extractiondialog.cpp
@@ -201,6 +201,21 @@ QString ExtractionDialog::subfolder() const
return m_ui->subfolder->text();
}
+void ExtractionDialog::setBusyGui()
+{
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ fileWidget->setEnabled(false);
+ m_ui->setEnabled(false);
+ // TODO: tell the user why the dialog is busy (e.g. "archive is being loaded").
+}
+
+void ExtractionDialog::setReadyGui()
+{
+ QApplication::restoreOverrideCursor();
+ fileWidget->setEnabled(true);
+ m_ui->setEnabled(true);
+}
+
ExtractionDialog::~ExtractionDialog()
{
delete m_ui;
diff --git a/kerfuffle/extractiondialog.h b/kerfuffle/extractiondialog.h
index c03950c..71e5db3 100644
--- a/kerfuffle/extractiondialog.h
+++ b/kerfuffle/extractiondialog.h
@@ -63,6 +63,8 @@ public:
QString subfolder() const;
public Q_SLOTS:
+ void setBusyGui();
+ void setReadyGui();
void setSubfolder(const QString& subfolder);
void setCurrentUrl(const QUrl &url);
void restoreWindowSize();
diff --git a/kerfuffle/jobs.cpp b/kerfuffle/jobs.cpp
index df28650..75bac3d 100644
--- a/kerfuffle/jobs.cpp
+++ b/kerfuffle/jobs.cpp
@@ -36,7 +36,9 @@
#include <QRegularExpression>
#include <QThread>
#include <QTimer>
+#include <QUrl>
+#include <KIO/RenameDialog>
#include <KLocalizedString>
namespace Kerfuffle
@@ -62,14 +64,23 @@ void Job::Private::run()
q->doWork();
}
-Job::Job(ReadOnlyArchiveInterface *interface)
+Job::Job(Archive *archive, ReadOnlyArchiveInterface *interface)
: KJob()
+ , m_archive(archive)
, m_archiveInterface(interface)
, d(new Private(this))
{
setCapabilities(KJob::Killable);
}
+Job::Job(Archive *archive)
+ : Job(archive, Q_NULLPTR)
+{}
+
+Job::Job(ReadOnlyArchiveInterface *interface)
+ : Job(Q_NULLPTR, interface)
+{}
+
Job::~Job()
{
qDeleteAll(m_archiveEntries);
@@ -84,13 +95,51 @@ Job::~Job()
ReadOnlyArchiveInterface *Job::archiveInterface()
{
+ // Use the archive interface.
+ if (archive()) {
+ return archive()->interface();
+ }
+
+ // Use the interface passed to this job (e.g. JSONArchiveInterface in jobstest.cpp).
return m_archiveInterface;
}
+Archive *Job::archive() const
+{
+ return m_archive;
+}
+
+QString Job::errorString() const
+{
+ if (!errorText().isEmpty()) {
+ return errorText();
+ }
+
+ if (archive()) {
+ if (archive()->error() == NoPlugin) {
+ return i18n("No suitable plugin found. Ark does not seem to support this file type.");
+ }
+
+ if (archive()->error() == FailedPlugin) {
+ return i18n("Failed to load a suitable plugin. Make sure any executables needed to handle the archive type are installed.");
+ }
+ }
+
+ return QString();
+}
+
void Job::start()
{
jobTimer.start();
+ // We have an archive but it's not valid, nothing to do.
+ if (archive() && !archive()->isValid()) {
+ QTimer::singleShot(0, this, [=]() {
+ onFinished(false);
+ });
+ return;
+ }
+
if (archiveInterface()->waitForFinishedSignal()) {
// CLI-based interfaces run a QProcess, no need to use threads.
QTimer::singleShot(0, this, &Job::doWork);
@@ -151,6 +200,10 @@ void Job::onFinished(bool result)
{
qCDebug(ARK) << "Job finished, result:" << result << ", time:" << jobTimer.elapsed() << "ms";
+ if (archive() && !archive()->isValid()) {
+ setError(KJob::UserDefinedError);
+ }
+
emitResult();
}
@@ -173,22 +226,31 @@ bool Job::doKill()
return ret;
}
-ListJob::ListJob(ReadOnlyArchiveInterface *interface)
- : Job(interface)
+LoadJob::LoadJob(Archive *archive, ReadOnlyArchiveInterface *interface)
+ : Job(archive, interface)
, m_isSingleFolderArchive(true)
, m_isPasswordProtected(false)
, m_extractedFilesSize(0)
, m_dirCount(0)
, m_filesCount(0)
{
- qCDebug(ARK) << "ListJob started";
- connect(this, &ListJob::newEntry, this, &ListJob::onNewEntry);
+ qCDebug(ARK) << "LoadJob started";
+ connect(this, &LoadJob::newEntry, this, &LoadJob::onNewEntry);
}
-void ListJob::doWork()
+LoadJob::LoadJob(Archive *archive)
+ : LoadJob(archive, Q_NULLPTR)
+{}
+
+LoadJob::LoadJob(ReadOnlyArchiveInterface *interface)
+ : LoadJob(Q_NULLPTR, interface)
+{}
+
+void LoadJob::doWork()
{
emit description(this, i18n("Loading archive..."));
connectToArchiveInterfaceSignals();
+
bool ret = archiveInterface()->list();
if (!archiveInterface()->waitForFinishedSignal()) {
@@ -196,17 +258,32 @@ void ListJob::doWork()
}
}
-qlonglong ListJob::extractedFilesSize() const
+void LoadJob::onFinished(bool result)
+{
+ if (archive()) {
+ archive()->setProperty("unpackedSize", extractedFilesSize());
+ archive()->setProperty("isSingleFolder", isSingleFolderArchive());
+ const auto name = subfolderName().isEmpty() ? archive()->completeBaseName() : subfolderName();
+ archive()->setProperty("subfolderName", name);
+ if (isPasswordProtected()) {
+ archive()->setProperty("encryptionType", archive()->password().isEmpty() ? Archive::Encrypted : Archive::HeaderEncrypted);
+ }
+ }
+
+ Job::onFinished(result);
+}
+
+qlonglong LoadJob::extractedFilesSize() const
{
return m_extractedFilesSize;
}
-bool ListJob::isPasswordProtected() const
+bool LoadJob::isPasswordProtected() const
{
return m_isPasswordProtected;
}
-bool ListJob::isSingleFolderArchive() const
+bool LoadJob::isSingleFolderArchive() const
{
if (m_filesCount == 1 && m_dirCount == 0) {
return false;
@@ -215,7 +292,7 @@ bool ListJob::isSingleFolderArchive() const
return m_isSingleFolderArchive;
}
-void ListJob::onNewEntry(const Archive::Entry *entry)
+void LoadJob::onNewEntry(const Archive::Entry *entry)
{
m_extractedFilesSize += entry->property("size").toLongLong();
m_isPasswordProtected |= entry->property("isPasswordProtected").toBool();
@@ -243,7 +320,7 @@ void ListJob::onNewEntry(const Archive::Entry *entry)
}
}
-QString ListJob::subfolderName() const
+QString LoadJob::subfolderName() const
{
if (!isSingleFolderArchive()) {
return QString();
@@ -252,6 +329,105 @@ QString ListJob::subfolderName() const
return m_subfolderName;
}
+BatchExtractJob::BatchExtractJob(LoadJob *loadJob, const QString &destination, bool autoSubfolder, bool preservePaths)
+ : Job(loadJob->archive())
+ , m_loadJob(loadJob)
+ , m_destination(destination)
+ , m_autoSubfolder(autoSubfolder)
+ , m_preservePaths(preservePaths)
+{
+ qCDebug(ARK) << "BatchExtractJob created";
+}
+
+void BatchExtractJob::doWork()
+{
+ connect(m_loadJob, &KJob::result, this, &BatchExtractJob::slotLoadingFinished);
+
+ // Forward signals
+ connect(m_loadJob, &Kerfuffle::Job::newEntry, this, &BatchExtractJob::newEntry);
+ connect(m_loadJob, &Kerfuffle::Job::userQuery, this, &BatchExtractJob::userQuery);
+ m_loadJob->start();
+}
+
+void BatchExtractJob::slotLoadingFinished(KJob *job)
+{
+ if (job->error()) {
+ emitResult();
+ return;
+ }
+
+ // Now we can start extraction.
+ setupDestination();
+
+ Kerfuffle::ExtractionOptions options;
+ options[QStringLiteral("PreservePaths")] = m_preservePaths;
+
+ auto extractJob = archive()->extractFiles({}, m_destination, options);
+ if (extractJob) {
+ connect(extractJob, &KJob::result, this, &BatchExtractJob::emitResult);
+ connect(extractJob, &Kerfuffle::Job::userQuery, this, &BatchExtractJob::userQuery);
+ extractJob->start();
+ } else {
+ emitResult();
+ }
+}
+
+void BatchExtractJob::setupDestination()
+{
+ const bool isSingleFolderRPM = (archive()->isSingleFolder() &&
+ (archive()->mimeType().name() == QLatin1String("application/x-rpm")));
+
+ if (m_autoSubfolder && (!archive()->isSingleFolder() || isSingleFolderRPM)) {
+ const QDir d(m_destination);
+ QString subfolderName = archive()->subfolderName();
+
+ // Special case for single folder RPM archives.
+ // We don't want the autodetected folder to have a meaningless "usr" name.
+ if (isSingleFolderRPM && subfolderName == QStringLiteral("usr")) {
+ qCDebug(ARK) << "Detected single folder RPM archive. Using archive basename as subfolder name";
+ subfolderName = QFileInfo(archive()->fileName()).completeBaseName();
+ }
+
+ if (d.exists(subfolderName)) {
+ subfolderName = KIO::suggestName(QUrl::fromUserInput(m_destination, QString(), QUrl::AssumeLocalFile), subfolderName);
+ }
+
+ d.mkdir(subfolderName);
+
+ m_destination += QLatin1Char( '/' ) + subfolderName;
+ }
+}
+
+CreateJob::CreateJob(Archive *archive, const QList<Archive::Entry *> &entries, const CompressionOptions &options)
+ : Job(archive)
+ , m_entries(entries)
+ , m_options(options)
+{
+ qCDebug(ARK) << "CreateJob created";
+}
+
+void CreateJob::enableEncryption(const QString &password, bool encryptHeader)
+{
+ archive()->encrypt(password, encryptHeader);
+}
+
+void CreateJob::setMultiVolume(bool isMultiVolume)
+{
+ archive()->setMultiVolume(isMultiVolume);
+}
+
+void CreateJob::doWork()
+{
+ auto addJob = archive()->addFiles(m_entries, new Archive::Entry(this), m_options);
+
+ if (addJob) {
+ connect(addJob, &KJob::result, this, &CreateJob::emitResult);
+ addJob->start();
+ } else {
+ emitResult();
+ }
+}
+
ExtractJob::ExtractJob(const QList<Archive::Entry*> &entries, const QString &destinationDir, const ExtractionOptions &options, ReadOnlyArchiveInterface *interface)
: Job(interface)
, m_entries(entries)
diff --git a/kerfuffle/jobs.h b/kerfuffle/jobs.h
index da25e9a..c06d41e 100644
--- a/kerfuffle/jobs.h
+++ b/kerfuffle/jobs.h
@@ -48,12 +48,21 @@ class KERFUFFLE_EXPORT Job : public KJob
Q_OBJECT
public:
- void start();
+
+ /**
+ * @return The archive processed by this job.
+ * @warning This method should not be called before start().
+ */
+ Archive *archive() const;
+ QString errorString() const Q_DECL_OVERRIDE;
+ void start() Q_DECL_OVERRIDE;
protected:
+ Job(Archive *archive, ReadOnlyArchiveInterface *interface);
+ Job(Archive *archive);
Job(ReadOnlyArchiveInterface *interface);
virtual ~Job();
- virtual bool doKill();
+ virtual bool doKill() Q_DECL_OVERRIDE;
ReadOnlyArchiveInterface *archiveInterface();
QList<Archive::Entry*> m_archiveEntries;
@@ -80,20 +89,38 @@ signals:
void userQuery(Kerfuffle::Query*);
private:
+ Archive *m_archive;
ReadOnlyArchiveInterface *m_archiveInterface;
-
QElapsedTimer jobTimer;
class Private;
Private * const d;
};
-class KERFUFFLE_EXPORT ListJob : public Job
+/**
+ * Load an existing archive.
+ * Example usage:
+ *
+ * \code
+ *
+ * auto job = Archive::load(filename);
+ * connect(job, &KJob::result, [](KJob *job) {
+ * if (!job->error) {
+ * auto archive = qobject_cast<Archive::LoadJob*>(job)->archive();
+ * // do something with archive.
+ * }
+ * });
+ * job->start();
+ *
+ * \endcode
+ */
+class KERFUFFLE_EXPORT LoadJob : public Job
{
Q_OBJECT
public:
- explicit ListJob(ReadOnlyArchiveInterface *interface);
+ explicit LoadJob(Archive *archive);
+ explicit LoadJob(ReadOnlyArchiveInterface *interface);
qlonglong extractedFilesSize() const;
bool isPasswordProtected() const;
@@ -103,7 +130,12 @@ public:
public slots:
virtual void doWork() Q_DECL_OVERRIDE;
+protected slots:
+ virtual void onFinished(bool result) Q_DECL_OVERRIDE;
+
private:
+ explicit LoadJob(Archive *archive, ReadOnlyArchiveInterface *interface);
+
bool m_isSingleFolderArchive;
bool m_isPasswordProtected;
QString m_subfolderName;
@@ -116,6 +148,66 @@ private slots:
void onNewEntry(const Archive::Entry*);
};
+/**
+ * Perform a batch extraction of an existing archive.
+ * Internally it runs a LoadJob before the actual extraction,
+ * to figure out properties such as the subfolder name.
+ */
+class KERFUFFLE_EXPORT BatchExtractJob : public Job
+{
+ Q_OBJECT
+
+public:
+ explicit BatchExtractJob(LoadJob *loadJob, const QString &destination, bool autoSubfolder, bool preservePaths);
+
+signals:
+ void newEntry(Archive::Entry *entry);
+ void userQuery(Query *query);
+
+public slots:
+ virtual void doWork() Q_DECL_OVERRIDE;
+
+private slots:
+ void slotLoadingFinished(KJob *job);
+
+private:
+ void setupDestination();
+
+ LoadJob *m_loadJob;
+ QString m_destination;
+ bool m_autoSubfolder;
+ bool m_preservePaths;
+};
+
+/**
+ * Create a new archive given a bunch of entries.
+ */
+class KERFUFFLE_EXPORT CreateJob : public Job
+{
+ Q_OBJECT
+
+public:
+ explicit CreateJob(Archive *archive, const QList<Archive::Entry*> &entries, const CompressionOptions& options);
+
+ /**
+ * @param password The password to encrypt the archive with.
+ * @param encryptHeader Whether to encrypt also the list of files.
+ */
+ void enableEncryption(const QString &password, bool encryptHeader);
+
+ /**
+ * Set whether the new archive should be multivolume.
+ */
+ void setMultiVolume(bool isMultiVolume);
+
+public slots:
+ virtual void doWork() Q_DECL_OVERRIDE;
+
+private:
+ QList<Archive::Entry*> m_entries;
+ CompressionOptions m_options;
+};
+
class KERFUFFLE_EXPORT ExtractJob : public Job
{
Q_OBJECT
diff --git a/part/archivemodel.cpp b/part/archivemodel.cpp
index ccf124d..a14bcf7 100644
--- a/part/archivemodel.cpp
+++ b/part/archivemodel.cpp
@@ -23,7 +23,7 @@
*/
#include "archivemodel.h"
-#include "kerfuffle/jobs.h"
+#include "jobs.h"
#include <KLocalizedString>
#include <kio/global.h>
@@ -693,8 +693,11 @@ void ArchiveModel::newEntry(Archive::Entry *receivedEntry, InsertBehaviour behav
void ArchiveModel::slotLoadingFinished(KJob *job)
{
if (!job->error()) {
+
+ m_archive.reset(qobject_cast<LoadJob*>(job)->archive());
QElapsedTimer timer;
timer.start();
+
int i = 0;
foreach(Archive::Entry *entry, m_newArchiveEntries) {
newEntry(entry, DoNotNotifyViews);
@@ -741,33 +744,38 @@ Kerfuffle::Archive* ArchiveModel::archive() const
return m_archive.data();
}
-KJob* ArchiveModel::setArchive(Kerfuffle::Archive *archive)
+void ArchiveModel::reset()
{
- m_archive.reset(archive);
-
+ m_archive.reset(Q_NULLPTR);
m_rootEntry.clear();
s_previousMatch = Q_NULLPTR;
s_previousPieces->clear();
-
- Kerfuffle::ListJob *job = Q_NULLPTR;
-
m_newArchiveEntries.clear();
- if (m_archive) {
- job = m_archive->list(); // TODO: call "open" or "create"?
- if (job) {
- connect(job, &Kerfuffle::ListJob::newEntry, this, &ArchiveModel::slotNewEntryFromSetArchive);
- connect(job, &Kerfuffle::ListJob::result, this, &ArchiveModel::slotLoadingFinished);
- connect(job, &Kerfuffle::ListJob::userQuery, this, &ArchiveModel::slotUserQuery);
- emit loadingStarted();
-
- // TODO: make sure if it's ok to not have calls to beginRemoveColumns here
- m_showColumns.clear();
- }
- }
+ // TODO: make sure if it's ok to not have calls to beginRemoveColumns here
+ m_showColumns.clear();
beginResetModel();
endResetModel();
- return job;
+}
+
+void ArchiveModel::createEmptyArchive(const QString &path, const QString &mimeType, QObject *parent)
+{
+ reset();
+ m_archive.reset(Archive::createEmpty(path, mimeType, parent));
+}
+
+KJob *ArchiveModel::loadArchive(const QString &path, const QString &mimeType, QObject *parent)
+{
+ reset();
+
+ auto loadJob = Archive::load(path, mimeType, parent);
+ connect(loadJob, &KJob::result, this, &ArchiveModel::slotLoadingFinished);
+ connect(loadJob, &Job::newEntry, this, &ArchiveModel::slotNewEntryFromSetArchive);
+ connect(loadJob, &Job::userQuery, this, &ArchiveModel::slotUserQuery);
+
+ emit loadingStarted();
+
+ return loadJob;
}
ExtractJob* ArchiveModel::extractFile(Archive::Entry *file, const QString& destinationDir, const Kerfuffle::ExtractionOptions& options) const
diff --git a/part/archivemodel.h b/part/archivemodel.h
index 0290d8f..58f0b25 100644
--- a/part/archivemodel.h
+++ b/part/archivemodel.h
@@ -23,12 +23,12 @@
#ifndef ARCHIVEMODEL_H
#define ARCHIVEMODEL_H
-#include <QAbstractItemModel>
-#include <QScopedPointer>
+#include "archiveentry.h"
#include <KMessageWidget>
-#include <kjobtrackerinterface.h>
-#include "kerfuffle/archiveentry.h"
+
+#include <QAbstractItemModel>
+#include <QScopedPointer>
using Kerfuffle::Archive;
@@ -62,7 +62,9 @@ public:
QMimeData *mimeData(const QModelIndexList & indexes) const Q_DECL_OVERRIDE;
bool dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent) Q_DECL_OVERRIDE;
- KJob* setArchive(Kerfuffle::Archive *archive);
+ void reset();
+ void createEmptyArchive(const QString &path, const QString &mimeType, QObject *parent);
+ KJob* loadArchive(const QString &path, const QString &mimeType, QObject *parent);
Kerfuffle::Archive *archive() const;
Archive::Entry *entryForIndex(const QModelIndex &index);
diff --git a/part/part.cpp b/part/part.cpp
index 43d43c2..878ff38 100644
--- a/part/part.cpp
+++ b/part/part.cpp
@@ -568,11 +568,44 @@ void Part::slotTestArchive()
job->start();
}
+void Part::createArchive()
+{
+ const QString fixedMimeType = arguments().metaData()[QStringLiteral("fixedMimeType")];
+ m_model->createEmptyArchive(localFilePath(), fixedMimeType, m_model);
+
+ if (arguments().metaData().contains(QStringLiteral("volumeSize"))) {
+ m_model->archive()->setMultiVolume(true);
+ }
+
+ const QString password = arguments().metaData()[QStringLiteral("encryptionPassword")];
+ if (!password.isEmpty()) {
+ m_model->encryptArchive(password,
+ arguments().metaData()[QStringLiteral("encryptHeader")] == QLatin1String("true"));
+ }
+
+ updateActions();
+ m_view->setDropsEnabled(true);
+}
+
+void Part::loadArchive()
+{
+ const QString fixedMimeType = arguments().metaData()[QStringLiteral("fixedMimeType")];
+ auto job = m_model->loadArchive(localFilePath(), fixedMimeType, m_model);
+
+ if (job) {
+ registerJob(job);
+ job->start();
+ } else {
+ updateActions();
+ }
+}
+
void Part::resetGui()
{
m_messageWidget->hide();
m_commentView->clear();
m_commentBox->hide();
+ m_infoPanel->setIndex(QModelIndex());
}
void Part::slotTestingDone(KJob* job)
@@ -687,46 +720,12 @@ bool Part::openFile()
return false;
}
- const QString fixedMimeType = arguments().metaData()[QStringLiteral("fixedMimeType")];
- QScopedPointer<Kerfuffle::Archive> archive(Kerfuffle::Archive::create(localFilePath(), fixedMimeType, m_model));
- Q_ASSERT(archive);
-
- if (archive->error() == NoPlugin) {
- displayMsgWidget(KMessageWidget::Error, xi18nc("@info", "Ark was not able to open <filename>%1</filename>. No suitable plugin found.<nl/>"
- "Ark does not seem to support this file type.",
- QFileInfo(localFilePath()).fileName()));
- return false;
- }
-
- if (archive->error() == FailedPlugin) {
- displayMsgWidget(KMessageWidget::Error, xi18nc("@info", "Ark was not able to open <filename>%1</filename>. Failed to load a suitable plugin.<nl/>"
- "Make sure any executables needed to handle the archive type are installed.",
- QFileInfo(localFilePath()).fileName()));
- return false;
- }
-
- Q_ASSERT(archive->isValid());
-
- if (arguments().metaData().contains(QStringLiteral("volumeSize"))) {
- archive.data()->setMultiVolume(true);
- }
+ const bool creatingNewArchive = arguments().metaData()[QStringLiteral("createNewArchive")] == QLatin1String("true");
- // Plugin loaded successfully.
- KJob *job = m_model->setArchive(archive.take());
- if (job) {
- registerJob(job);
- job->start();
+ if (creatingNewArchive) {
+ createArchive();
} else {
- updateActions();
- m_view->setDropsEnabled(true);
- }
-
- m_infoPanel->setIndex(QModelIndex());
-
- const QString password = arguments().metaData()[QStringLiteral("encryptionPassword")];
- if (!password.isEmpty()) {
- m_model->encryptArchive(password,
- arguments().metaData()[QStringLiteral("encryptHeader")] == QLatin1String("true"));
+ loadArchive();
}
return true;
@@ -828,12 +827,11 @@ void Part::slotLoadingFinished(KJob *job)
if (job->error() != KJob::KilledJobError) {
displayMsgWidget(KMessageWidget::Error, xi18nc("@info", "Loading the archive <filename>%1</filename> failed with the following error:<nl/><message>%2</message>",
localFilePath(),
- job->errorText()));
+ job->errorString()));
}
// The file failed to open, so reset the open archive, info panel and caption.
- m_model->setArchive(Q_NULLPTR);
-
+ m_model->reset();
m_infoPanel->setPrettyFileName(QString());
m_infoPanel->updateWithDefaults();
@@ -1063,7 +1061,7 @@ void Part::slotError(const QString& errorMessage, const QString& details)
bool Part::isSingleFolderArchive() const
{
- return m_model->archive()->isSingleFolderArchive();
+ return m_model->archive()->isSingleFolder();
}
QString Part::detectSubfolder() const
diff --git a/part/part.h b/part/part.h
index 97334db..b7996ca 100644
--- a/part/part.h
+++ b/part/part.h
@@ -164,6 +164,8 @@ signals:
void quit();
private:
+ void createArchive();
+ void loadArchive();
void resetGui();
void setupView();
void setupActions();