jobs.cpp 7.71 KB
Newer Older
1 2
/*
 * Copyright (c) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
3
 * Copyright (c) 2008-2009 Harald Hvaal <haraldhv@stud.ntnu.no>
4
 * Copyright (c) 2009-2010 Raphael Kubo da Costa <rakuco@FreeBSD.org>
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ( INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
27

28 29
#include "jobs.h"

30
#include <QThread>
31 32 33

#include <KDebug>
#include <KLocale>
34

35 36
//#define DEBUG_RACECONDITION

37 38
namespace Kerfuffle
{
39

40 41 42
class Job::Private : public QThread
{
public:
43 44 45 46 47 48 49
    Private(Job *job, QObject *parent = 0)
        : QThread(parent)
        , q(job)
    {
        connect(q, SIGNAL(result(KJob*)), SLOT(quit()));
    }

50 51
    virtual void run();

52
private:
53 54 55 56 57
    Job *q;
};

void Job::Private::run()
{
58
    q->doWork();
59

60 61 62
    if (q->isRunning()) {
        exec();
    }
63 64 65 66 67 68

#ifdef DEBUG_RACECONDITION
    QThread::sleep(2);
#endif
}

69
Job::Job(ReadOnlyArchiveInterface *interface, QObject *parent)
70 71
    : KJob(parent)
    , m_interface(interface)
72 73
    , m_isRunning(false)
    , d(new Private(this))
74 75 76 77 78 79 80 81 82 83 84 85
{
    static bool onlyOnce = false;
    if (!onlyOnce) {
        qRegisterMetaType<QPair<QString, QString> >("QPair<QString,QString>");
        onlyOnce = true;
    }

    setCapabilities(KJob::Killable);
}

Job::~Job()
{
86 87
    if (d->isRunning()) {
        d->wait();
88 89
    }

90
    delete d;
91
}
92

93 94 95 96 97
bool Job::isRunning() const
{
    return m_isRunning;
}

98 99
void Job::start()
{
100
    m_isRunning = true;
101
    d->start();
102 103
}

104 105 106 107 108 109
void Job::emitResult()
{
    m_isRunning = false;
    KJob::emitResult();
}

110 111
void Job::onError(const QString & message, const QString & details)
{
112
    Q_UNUSED(details)
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139

    setError(1);
    setErrorText(message);
}

void Job::onEntry(const ArchiveEntry & archiveEntry)
{
    emit newEntry(archiveEntry);
}

void Job::onProgress(double value)
{
    setPercent(static_cast<unsigned long>(100.0*value));
}

void Job::onInfo(const QString& info)
{
    emit infoMessage(this, info);
}

void Job::onEntryRemoved(const QString & path)
{
    emit entryRemoved(path);
}

void Job::onFinished(bool result)
{
140
    kDebug() << result;
141

142
    m_interface->removeObserver(this);
143 144 145 146 147 148 149 150 151 152 153

    emitResult();
}

void Job::onUserQuery(Query *query)
{
    emit userQuery(query);
}

bool Job::doKill()
{
154
    kDebug();
155
    bool ret = m_interface->doKill();
156
    if (!ret) {
157
        kDebug() << "Killing does not seem to be supported here.";
158
    }
159 160 161 162
    return ret;
}

ListJob::ListJob(ReadOnlyArchiveInterface *interface, QObject *parent)
163 164 165 166
    : Job(interface, parent)
    , m_isSingleFolderArchive(true)
    , m_isPasswordProtected(false)
    , m_extractedFilesSize(0)
167
{
Laurent Montel's avatar
Laurent Montel committed
168 169
    connect(this, SIGNAL(newEntry(ArchiveEntry)),
            this, SLOT(onNewEntry(ArchiveEntry)));
170 171 172 173 174 175 176 177
}

void ListJob::doWork()
{
    emit description(this, i18n("Loading archive..."));
    m_interface->registerObserver(this);
    bool ret = m_interface->list();

178 179 180
    if (!m_interface->waitForFinishedSignal()) {
        m_interface->finished(ret);
    }
181 182
}

183
qlonglong ListJob::extractedFilesSize() const
184 185 186 187
{
    return m_extractedFilesSize;
}

188
bool ListJob::isPasswordProtected() const
189 190 191 192
{
    return m_isPasswordProtected;
}

193
bool ListJob::isSingleFolderArchive() const
194 195 196 197
{
    return m_isSingleFolderArchive;
}

198 199 200 201 202
void ListJob::onNewEntry(const ArchiveEntry& entry)
{
    m_extractedFilesSize += entry[ Size ].toLongLong();
    m_isPasswordProtected |= entry [ IsPasswordProtected ].toBool();

203 204
    if (m_isSingleFolderArchive) {
        const QString fileName(entry[FileName].toString());
205
        const QString basePath(fileName.split(QLatin1Char( '/' )).at(0));
206

207 208 209
        if (m_basePath.isEmpty()) {
            m_basePath = basePath;
            m_subfolderName = basePath;
210
        } else {
211 212 213 214
            if (m_basePath != basePath) {
                m_isSingleFolderArchive = false;
                m_subfolderName.clear();
            }
215 216 217 218
        }
    }
}

219
QString ListJob::subfolderName() const
220 221 222 223
{
    return m_subfolderName;
}

224
ExtractJob::ExtractJob(const QVariantList& files, const QString& destinationDir, ExtractionOptions options, ReadOnlyArchiveInterface *interface, QObject *parent)
225 226 227 228
    : Job(interface, parent)
    , m_files(files)
    , m_destinationDir(destinationDir)
    , m_options(options)
229
{
230
    setDefaultOptions();
231 232 233 234 235 236 237 238 239 240 241 242 243 244
}

void ExtractJob::doWork()
{
    QString desc;
    if (m_files.count() == 0) {
        desc = i18n("Extracting all files");
    } else {
        desc = i18np("Extracting one file", "Extracting %1 files", m_files.count());
    }
    emit description(this, desc);

    m_interface->registerObserver(this);

245 246 247 248
    kDebug() << "Starting extraction with selected files:"
             << m_files
             << "Destination dir:" << m_destinationDir
             << "Options:" << m_options;
249 250 251

    bool ret = m_interface->copyFiles(m_files, m_destinationDir, m_options);

252 253 254
    if (!m_interface->waitForFinishedSignal()) {
        m_interface->finished(ret);
    }
255 256
}

257
void ExtractJob::setDefaultOptions()
258
{
259 260 261 262 263 264 265 266 267
    ExtractionOptions defaultOptions;

    defaultOptions[QLatin1String("PreservePaths")] = false;

    ExtractionOptions::const_iterator it = defaultOptions.constBegin();
    for (; it != defaultOptions.constEnd(); ++it) {
        if (!m_options.contains(it.key())) {
            m_options[it.key()] = it.value();
        }
268 269 270
    }
}

271 272 273 274 275
QString ExtractJob::destinationDirectory() const
{
    return m_destinationDir;
}

276 277 278 279 280
ExtractionOptions ExtractJob::extractionOptions() const
{
    return m_options;
}

281
AddJob::AddJob(const QStringList& files, const CompressionOptions& options , ReadWriteArchiveInterface *interface, QObject *parent)
282 283 284
    : Job(interface, parent)
    , m_files(files)
    , m_options(options)
285 286 287 288 289 290 291 292
{
}

void AddJob::doWork()
{
    emit description(this, i18np("Adding a file", "Adding %1 files", m_files.count()));

    ReadWriteArchiveInterface *m_writeInterface =
293
        qobject_cast<ReadWriteArchiveInterface*>(m_interface);
294 295 296 297 298 299

    Q_ASSERT(m_writeInterface);

    m_writeInterface->registerObserver(this);
    bool ret = m_writeInterface->addFiles(m_files, m_options);

300 301 302
    if (!m_interface->waitForFinishedSignal()) {
        m_interface->finished(ret);
    }
303 304
}

305
DeleteJob::DeleteJob(const QVariantList& files, ReadWriteArchiveInterface *interface, QObject *parent)
306 307
    : Job(interface, parent)
    , m_files(files)
308 309 310 311 312 313 314 315
{
}

void DeleteJob::doWork()
{
    emit description(this, i18np("Deleting a file from the archive", "Deleting %1 files", m_files.count()));

    ReadWriteArchiveInterface *m_writeInterface =
316
        qobject_cast<ReadWriteArchiveInterface*>(m_interface);
317 318 319 320 321 322

    Q_ASSERT(m_writeInterface);

    m_writeInterface->registerObserver(this);
    int ret = m_writeInterface->deleteFiles(m_files);

323 324 325
    if (!m_interface->waitForFinishedSignal()) {
        m_interface->finished(ret);
    }
326
}
327

328
} // namespace Kerfuffle
329 330

#include "jobs.moc"