jobs.cpp 7.31 KB
Newer Older
1 2
/*
 * Copyright (c) 2007 Henrique Pinto <henrique.pinto@kdemail.net>
3
 * Copyright (c) 2008 Harald Hvaal <haraldhv )@@@( stud(dot)ntnu.no>
4 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.
 */
#include "jobs.h"
27
#include "threading.h"
28

Andreas Pakulat's avatar
Andreas Pakulat committed
29
#include <kdebug.h>
Henrique Pinto's avatar
Henrique Pinto committed
30
#include <KLocale>
31
#include <QDir>
32
#include <QTimer>
33 34
#include <QApplication>

35
//#define KERFUFFLE_NOJOBTHREADING
Henrique Pinto's avatar
Henrique Pinto committed
36

37 38
namespace Kerfuffle
{
39 40

	Job::Job(ReadOnlyArchiveInterface *interface, QObject *parent)
41 42 43
		: KJob(NULL)
		, m_interface(interface)
		, m_workerThread(0)
44
	{
45 46 47 48 49
		static bool onlyOnce = false;
		if (!onlyOnce) {
			qRegisterMetaType<QPair<QString, QString> >("QPair<QString,QString>");
			onlyOnce = true;
		}
50

51
		setCapabilities(KJob::Killable);
52 53
	}

54 55 56 57 58 59
	Job::~Job()
	{
		delete m_workerThread;
		m_workerThread = 0;
	}

60 61
	void Job::start()
	{
62 63 64
#ifdef KERFUFFLE_NOJOBTHREADING
		QTimer::singleShot(0, this, SLOT(doWork()));
#else
65
		m_workerThread = new ThreadExecution(this);
66 67 68

		//we want the event handling to happen in the work thread to avoid
		//unsafe data access due to events while work is being done
69
		kDebug() << "Moving from " << QObject::thread() << " to " << m_workerThread;
70 71
		m_previousInterfaceParent = m_interface->parent();
		m_interface->setParent(NULL);
72 73
		m_interface->moveToThread(m_workerThread);
		moveToThread(m_workerThread);
74

75
		m_workerThread->start();
76
#endif
77 78
	}

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
	void Job::onError( const QString & message, const QString & details )
	{
		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 ) );
	}

95 96 97 98 99
	void Job::onInfo( const QString& info )
	{
		emit infoMessage(this, info);
	}

100 101 102 103
	void Job::onEntryRemoved( const QString & path )
	{
		emit entryRemoved( path );
	}
104

105 106 107 108 109 110 111 112
	void Job::onFinished(bool result)
	{
		kDebug(1601);
		m_interface->removeObserver( this );

		setError(!result);

#ifndef KERFUFFLE_NOJOBTHREADING
113 114 115
		kDebug() << "Moving from " << QObject::thread()<< " to " << QApplication::instance()->thread();
		m_interface->moveToThread(QApplication::instance()->thread());
		m_interface->setParent(m_previousInterfaceParent);
116 117
		moveToThread(QApplication::instance()->thread());
#endif
118 119

		emitResult();
120 121 122 123 124 125
	}

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

127 128 129 130 131 132 133 134 135
	bool Job::doKill()
	{
		kDebug(1601);
		bool ret = m_interface->doKill();
		if (!ret)
			kDebug(1601) << "Killing does not seem to be supported here.";
		return ret;
	}

136
	ListJob::ListJob( ReadOnlyArchiveInterface *interface, QObject *parent )
137
		: Job( interface, parent ),
138
		m_isSingleFolderArchive(true),
139 140
		m_isPasswordProtected(false),
		m_extractedFilesSize(0)
141
	{
142 143
		connect(this, SIGNAL(newEntry( const ArchiveEntry&)),
				this, SLOT(onNewEntry( const ArchiveEntry&)));
144 145
	}

146
	void ListJob::doWork()
147
	{
148
		emit description( this, i18n( "Loading archive..." ) );
149
		m_interface->registerObserver( this );
150 151 152
		bool ret = m_interface->list();

		if (!m_interface->waitForFinishedSignal()) m_interface->finished(ret);
153 154
	}

155 156 157
	void ListJob::onNewEntry(const ArchiveEntry& entry)
	{
		m_extractedFilesSize += entry[ Size ].toLongLong();
Harald Hvaal's avatar
Harald Hvaal committed
158
		m_isPasswordProtected |= entry [ IsPasswordProtected ].toBool();
159 160 161 162 163

		QString filename = entry[ FileName ].toString();
		QString fileBaseRoot = filename.split(QDir::separator()).first();

		if (m_previousEntry.isEmpty()) // Set the root path of the filename
164
		{
165 166 167 168 169 170 171 172 173 174
			m_previousEntry = fileBaseRoot;
			m_subfolderName = fileBaseRoot;
			m_isSingleFolderArchive = entry[ IsDirectory ].toBool();
		}
		else
		{
			if (m_previousEntry != fileBaseRoot)
			{
				m_isSingleFolderArchive = false;
				m_subfolderName.clear();
175
			}
176 177 178 179 180
			else
			{
				// The state may change only if the folder's files were added before itself
				if (entry[ IsDirectory ].toBool())
					m_isSingleFolderArchive = true;
181 182 183 184
			}
		}
	}

185
	ExtractJob::ExtractJob( const QList<QVariant>& files, const QString& destinationDir,
186
				ExtractionOptions options, ReadOnlyArchiveInterface *interface, QObject *parent )
187
		: Job(interface,  parent ), m_files( files ), m_destinationDir( destinationDir ), m_options(options)
188 189 190
	{
	}

191
	void ExtractJob::doWork()
192
	{
193
		QString desc;
Henrique Pinto's avatar
Henrique Pinto committed
194 195
		if ( m_files.count() == 0 )
		{
196
			desc = i18n( "Extracting all files" );
Henrique Pinto's avatar
Henrique Pinto committed
197 198 199
		}
		else
		{
200
			desc = i18np( "Extracting one file", "Extracting %1 files", m_files.count() );
Henrique Pinto's avatar
Henrique Pinto committed
201
		}
202
		emit description( this, desc );
203

204
		m_interface->registerObserver( this );
205

206 207
		fillInDefaultValues(m_options);

208 209 210
		kDebug(1601) << "Starting extraction with selected files "
			<< m_files
			<< " Destination dir " << m_destinationDir
211
			<< " And options " << m_options
212
					;
213

214 215
		bool ret = m_interface->copyFiles( m_files, m_destinationDir, m_options );
		if (!m_interface->waitForFinishedSignal()) m_interface->finished(ret);
216

217
	}
218 219 220 221
	void ExtractJob::fillInDefaultValues(ExtractionOptions& options)
	{
		if (!options.contains("PreservePaths")) options["PreservePaths"] = false;
	}
222

223 224
	AddJob::AddJob( const QStringList& files, const CompressionOptions& options , ReadWriteArchiveInterface *interface, QObject *parent )
		: Job( interface, parent ), m_files( files ), m_options(options)
225
	{
226
		kDebug( 1601 );
227 228
	}

229
	void AddJob::doWork()
230
	{
231
		emit description( this, i18np( "Adding a file", "Adding %1 files", m_files.count() ) );
232 233 234 235 236 237

		ReadWriteArchiveInterface *m_writeInterface =
			qobject_cast<ReadWriteArchiveInterface*>
			(m_interface);

		Q_ASSERT(m_writeInterface);
238

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

242
		if (!m_interface->waitForFinishedSignal()) m_interface->finished(ret);
243 244
	}

Henrique Pinto's avatar
Henrique Pinto committed
245
	DeleteJob::DeleteJob( const QList<QVariant>& files, ReadWriteArchiveInterface *interface, QObject *parent )
246
		: Job( interface, parent ), m_files( files )
Henrique Pinto's avatar
Henrique Pinto committed
247 248 249
	{
	}

250
	void DeleteJob::doWork()
Henrique Pinto's avatar
Henrique Pinto committed
251
	{
252
		emit description( this, i18np( "Deleting a file from the archive", "Deleting %1 files", m_files.count() ) );
253

254 255 256
		ReadWriteArchiveInterface *m_writeInterface =
			qobject_cast<ReadWriteArchiveInterface*>
			(m_interface);
257

258
		Q_ASSERT(m_writeInterface);
259

260
		m_writeInterface->registerObserver( this );
261 262 263
		bool ret = m_writeInterface->deleteFiles( m_files );

		if (!m_interface->waitForFinishedSignal()) m_interface->finished(ret);
Henrique Pinto's avatar
Henrique Pinto committed
264 265
	}

266
} // namespace Kerfuffle