jobs.cpp 7.37 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
 *
 * 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.
 */
26

27
#include "jobs.h"
28
#include "threading.h"
29

30
#include <QApplication>
31
#include <QDir>
32
#include <QTimer>
33 34 35

#include <KDebug>
#include <KLocale>
36

37
//#define KERFUFFLE_NOJOBTHREADING
Henrique Pinto's avatar
Henrique Pinto committed
38

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

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

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

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

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

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

80 81
	void Job::onError( const QString & message, const QString & details )
	{
82 83
		Q_UNUSED(details);

84 85 86 87 88 89 90 91 92 93 94 95 96 97
		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 ) );
	}

98 99 100 101 102
	void Job::onInfo( const QString& info )
	{
		emit infoMessage(this, info);
	}

103 104 105 106
	void Job::onEntryRemoved( const QString & path )
	{
		emit entryRemoved( path );
	}
107

108 109 110 111 112 113 114 115
	void Job::onFinished(bool result)
	{
		kDebug(1601);
		m_interface->removeObserver( this );

		setError(!result);

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

		emitResult();
123 124 125 126 127 128
	}

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

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

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

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

		if (!m_interface->waitForFinishedSignal()) m_interface->finished(ret);
156 157
	}

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

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

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

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

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

207
		m_interface->registerObserver( this );
208

209 210
		fillInDefaultValues(m_options);

211 212 213
		kDebug(1601) << "Starting extraction with selected files "
			<< m_files
			<< " Destination dir " << m_destinationDir
214
			<< " And options " << m_options
215
					;
216

217 218
		bool ret = m_interface->copyFiles( m_files, m_destinationDir, m_options );
		if (!m_interface->waitForFinishedSignal()) m_interface->finished(ret);
219

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

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

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

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

		Q_ASSERT(m_writeInterface);
241

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

245
		if (!m_interface->waitForFinishedSignal()) m_interface->finished(ret);
246 247
	}

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

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

257 258 259
		ReadWriteArchiveInterface *m_writeInterface =
			qobject_cast<ReadWriteArchiveInterface*>
			(m_interface);
260

261
		Q_ASSERT(m_writeInterface);
262

263
		m_writeInterface->registerObserver( this );
264 265
		bool ret = m_writeInterface->deleteFiles( m_files );

266
		emitResult();
267
		if (!m_interface->waitForFinishedSignal()) m_interface->finished(ret);
Henrique Pinto's avatar
Henrique Pinto committed
268 269
	}

270
} // namespace Kerfuffle
271 272

#include "jobs.moc"