summaryrefslogtreecommitdiff
path: root/src/frontend/bookshelfmanager/installpage/btinstallthread.cpp
blob: d2570ffe87f16e16a3b2c41353bea261202f1350 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/*********
*
* This file is part of BibleTime's source code, http://www.bibletime.info/.
*
* Copyright 1999-2008 by the BibleTime developers.
* The BibleTime source code is licensed under the GNU General Public License version 2.0.
*
**********/

#include "btinstallthread.h"

#include "frontend/bookshelfmanager/btinstallmgr.h"
#include "frontend/bookshelfmanager/instbackend.h"
#include "util/cpointers.h"
#include "backend/managers/cswordbackend.h"

#include <QApplication>
#include <QString>
#include <QThread>
#include <QDir>

#include <QDebug>

// sword
#include <filemgr.h>

BtInstallThread::BtInstallThread(QObject* parent, QString moduleName, QString sourceName, QString destinationName)
	: QThread(parent),
	done(false),
	m_module(moduleName),
	m_destination(destinationName),
	m_source(sourceName),
    m_cancelled(false)
{
	m_iMgr = new BtInstallMgr();
}


BtInstallThread::~BtInstallThread()
{
	delete m_iMgr;
}

void BtInstallThread::run()
{
	qDebug() << "****************************************\nBtInstallThread::run, mod:" << m_module << "\n************************************";


	emit preparingInstall(m_module, m_source);

    m_installSource.reset(new sword::InstallSource(instbackend::source(m_source)));
    m_backendForSource.reset(instbackend::backend(*m_installSource));

	//make sure target/mods.d and target/modules exist
	//TODO: move this to some common precondition
	QDir dir(m_destination);
	if (!dir.exists()) {
		dir.mkdir(m_destination);
		qDebug() << "made directory" << m_destination;
	}
	if (!dir.exists("modules")) {
		dir.mkdir("modules");
		qDebug() << "made directory" << m_destination << "/modules";
	}
	if (!dir.exists("mods.d")) {
		dir.mkdir("mods.d");
		qDebug() << "made directory" << m_destination << "/mods.d";
	}

	QObject::connect(m_iMgr, SIGNAL(percentCompleted(int, int)), this, SLOT(slotManagerStatusUpdated(int, int)), Qt::QueuedConnection);
	QObject::connect(m_iMgr, SIGNAL(downloadStarted()), this, SLOT(slotDownloadStarted()), Qt::QueuedConnection);

	//check whether it's an update. If yes, remove existing module first
	//TODO: silently removing without undo if the user cancels the update is WRONG!!!
	removeModule();

	// manager for the destination path
	sword::SWMgr lMgr( m_destination.toLatin1() );

    if (instbackend::isRemote(*m_installSource)) {
		qDebug() << "calling install";
        int status = m_iMgr->installModule(&lMgr, 0, m_module.toLatin1(), m_installSource.get());
		if (status != 0) {
			qWarning() << "Error with install: " << status << "module:" << m_module;
		}
		else {
			done = true;
			emit installCompleted(m_module, m_source, status);
		}
	}
	else { //local source
		emit statusUpdated(m_module, 0);
        int status = m_iMgr->installModule(&lMgr, m_installSource->directory.c_str(), m_module.toLatin1());
		if (status > 0) {
			qWarning() << "Error with install: " << status << "module:" << m_module;
		}
		else if (status == -1) {
			// it was terminated, do nothing
		}
		else {
			emit statusUpdated(m_module, 100);
			done = true;
			emit installCompleted(m_module, m_source, status);
		}
	}
}

void BtInstallThread::slotStopInstall()
{
	qDebug() << "*************************************\nBtInstallThread::slotStopInstall" << m_module << "\n********************************";
	if (!done) {
		done = true;
		qDebug() << "*********************************\nBtInstallThread::slotStopInstall, installing" << m_module << "was cancelled\n**************************************";
		m_iMgr->terminate();
		//this->terminate(); // It's dangerous to forcibly stop, but we will clean up the files
		qDebug() << "BtInstallThread::slotStopInstall 2";
		//qApp->processEvents();
		// wait to terminate for some secs. We rather let the execution go on and cleaning up to fail than the app to freeze
		int notRun = this->wait(200);
		if (notRun) {
			this->terminate();
			this->wait(2);
			qDebug() << "installthread ("<< m_module << ") terminated, delete m_iMgr";
			delete m_iMgr; // this makes sure the ftp library will be cleaned up in the destroyer
			m_iMgr = 0;
		}
		qDebug() << "BtInstallThread::slotStopInstall 3";
		// cleanup: remove the module, remove the temp files
		if (true) {
			qDebug() << "BtInstallThread::slotStopInstall 4";
			// remove the installed module, just to be sure because mgr may
			// have been terminated when copying files
			removeModule();
			removeTempFiles();
			qDebug() << "BtInstallThread::slotStopInstall will emit installStopped...";
			emit installStopped(m_module, m_source);
		}
	}
}

void BtInstallThread::slotManagerStatusUpdated(int totalProgress, int /*fileProgress*/)
{
	//qDebug("BtInstallThread::slotManagerStatusUpdated");
	emit statusUpdated(m_module, totalProgress);
}

void BtInstallThread::slotDownloadStarted()
{
	qDebug("BtInstallThread::slotDownloadStarted");
	emit downloadStarted(m_module);
}

void BtInstallThread::removeModule()
{
	qDebug() << "BtInstallThread::removeModule start";
	CSwordModuleInfo* m;
	m = CPointers::backend()->findModuleByName(m_module);
	if (!m) {
		m = instbackend::backend(instbackend::source(m_destination.toLatin1()))->findModuleByName(m_module);
	}
	if (m) { //module found?
		qDebug() << "BtInstallThread::removeModule, module" << m_module << "found";
		QString prefixPath = m->config(CSwordModuleInfo::AbsoluteDataPath) + "/";
		QString dataPath = m->config(CSwordModuleInfo::DataPath);
		if (dataPath.left(2) == "./") {
			dataPath = dataPath.mid(2);
		}

		if (prefixPath.contains(dataPath)) {
			prefixPath.remove( prefixPath.indexOf(dataPath), dataPath.length() );
		}
		else {
			prefixPath = QString::fromLatin1(CPointers::backend()->prefixPath);
		}

		sword::SWMgr mgr(prefixPath.toLatin1());
		BtInstallMgr iMgr;
		iMgr.removeModule(&mgr, m->name().toLatin1());
	} else {
		qDebug() << "BtInstallThread::removeModule, module" << m_module << "not found";
	}
}

void BtInstallThread::removeTempFiles()
{
	qDebug("BtInstallThread::removeTempFiles start");

	// (take the remote conf file for this module, take DataPath,
	// take the absolute path of the InstallMgr)

	//sword::InstallSource is = instbackend::source(m_source);
    if (instbackend::isRemote(*m_installSource)) {
		// get the path for the module temp files
		CSwordModuleInfo* mInfo = m_backendForSource->findModuleByName(m_module);
		QString dataPath = mInfo->config(CSwordModuleInfo::AbsoluteDataPath);
		qDebug() << "Delete path:" << dataPath;
		// it's easier to use sword than qt
		sword::FileMgr::removeDir(dataPath.toLatin1().data());
	}
}