1/****************************************************************************
2**
3** Copyright (C) 2010-2011 Ralf Habacker ralf.habacker@freenet.de
4**
5** This file is part of the KDE installer for windows
6**
7** This library is free software; you can redistribute it and/or
8** modify it under the terms of the GNU Library General Public
9** License version 2 as published by the Free Software Foundation.
10**
11** This library is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14** Library General Public License for more details.
15**
16** You should have received a copy of the GNU Library General Public License
17** along with this library; see the file COPYING.LIB. If not, write to
18** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19** Boston, MA 02110-1301, USA.
20**
21****************************************************************************/
22
23#include "installerdialog.h"
24
25#include "../shared/misc.h"
26#include "../shared/debug.h"
27#include "../shared/installercallconfig.h"
28#include "../shared/installerprogress.h"
29#include "../shared/downloader.h"
30#include "../shared/unpacker.h"
31#include "../shared/postprocessing.h"
32
33#include <QCloseEvent>
34#include <QPixmap>
35#include <QTextEdit>
36#include <QTimer>
37
38InstallerDialog::InstallerDialog()
39 : okay(":/images/dialog-ok-apply.png"), next(":/images/go-next.png"), error(":/images/dialog-cancel.png"), m_postProcessing(&m_engine, this), m_log(0)
40{
41 ui.setupUi(this);
42
43 connect(ui.closeButton, SIGNAL(clicked()), this, SLOT(stop()));
44 initItems();
45
46 setMessageHandler("single-package-installer");
47
48 QString setupName;
49
50 if (QCoreApplication::arguments().size() > 1)
51 setupName = QCoreApplication::arguments().at(1);
52
53 InstallerCallConfig config(setupName);
54
55 if (config.isValid())
56 {
57 InstallerEngine::defaultConfigURL = QString("http://download.kde.org/%1/%2").arg(toString(config.releaseType)).arg(config.version);
58 InstallerEngine::fallBackURL = QString("http://www.winkde.org/pub/kde/ports/win32/releases/%1/%2").arg(toString(config.releaseType)).arg(config.version);
59#ifdef Q_OS_WIN
60 QString installRoot = QString("%1/%2-%3-%4-%5%6").arg(QLatin1String(qgetenv("ProgramFiles"))).arg(config.packageName).arg(allCompilers.toString(config.compilerType)).arg(toString(config.releaseType)).arg(config.version).arg(config.hasSDK ? "-sdk" : "");
61#else
62 QString installRoot = QString("%1/%2-%3-%4-%5%6").arg(QLatin1String(qgetenv("HOME"))).arg(config.packageName).arg(allCompilers.toString(config.compilerType)).arg(toString(config.releaseType)).arg(config.version).arg(config.hasSDK ? "-sdk" : "");
63#endif
64 addHint("I'm installing into " + installRoot);
65 Settings::instance().setInstallDir(installRoot, false);
66 m_engine.setRoot(installRoot);
67 m_engine.setWithDevelopmentPackages(config.hasSDK);
68 m_engine.setCurrentCompiler(config.compilerType);
69 ProxySettings ps;
70
71 m_postProcessing.setSingleApplicationMode(true);
72 m_postProcessing.setPackageName(config.packageName);
73
74 QString title = tr("KDE %1 %2 Installer").arg(config.packageName).arg(config.hasSDK ? "SDK" : "Application");
75 setWindowTitle(title);
76 ui.topLabel->setText(title);
77
78 if (ps.from(ProxySettings::AutoDetect))
79 {
80 ps.save();
81 addHint("I'm " + ps.toString());
82 }
83 m_packages << config.packageName.toLower()+'-'+allCompilers.toString(config.compilerType);
84
85 // @TODO: this is a hack, need to be solved by build requirements in the config file
86 if (config.hasSDK && config.packageName.toLower() == "umbrello")
87 m_packages << "automoc" << "boost";
88
89 setItem(0);
90 QTimer::singleShot(250,this,SLOT(setupEngine()));
91 }
92 else
93 {
94 setWindowTitle(tr("KDE Single Application Installer"));
95 ui.topLabel->setText(tr("KDE Single Application Installer"));
96 addHint("I could not find a valid configuration");
97 }
98}
99
100InstallerDialog::~InstallerDialog()
101{
102 delete m_log;
103}
104
105void InstallerDialog::initItems()
106{
107 ui.label1->setText("");
108 ui.label1->setVisible(false);
109 ui.textLabel1->setVisible(false);
110 ui.label2->setText("");
111 ui.label2->setVisible(false);
112 ui.textLabel2->setVisible(false);
113 ui.label3->setText("");
114 ui.label3->setVisible(false);
115 ui.textLabel3->setVisible(false);
116 ui.label4->setText("");
117 ui.label4->setVisible(false);
118 ui.textLabel4->setVisible(false);
119 ui.label5->setText("");
120 ui.label5->setVisible(false);
121 ui.textLabel5->setVisible(false);
122 ui.hintLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
123 ui.logButton->setVisible(false);
124 setSubLabelHint("");
125 connect(ui.logButton, SIGNAL(clicked(bool)), this, SLOT(showLog(bool)));
126}
127
128void InstallerDialog::addHint(const QString &hint)
129{
130 ui.hintLabel->setText(ui.hintLabel->text() + "<br>" + hint);
131 QCoreApplication::processEvents();
132}
133
134void InstallerDialog::setSubLabelHint(const QString &hint)
135{
136 if (hint.isEmpty())
137 {
138 ui.subLabel->setVisible(false);
139 }
140 else
141 {
142 ui.subLabel->setVisible(true);
143 ui.subLabel->setText(hint);
144 }
145 QCoreApplication::processEvents();
146}
147
148void InstallerDialog::showLog(bool checked)
149{
150 m_log = new QTextEdit(*log());
151 m_log->showMaximized();
152}
153
154void InstallerDialog::setItem(int pagenum)
155{
156 switch (pagenum)
157 {
158 case 0:
159 ui.label1->setPixmap(next);
160 ui.label1->setVisible(true);
161 ui.textLabel1->setVisible(true);
162 break;
163
164 case 1:
165 ui.label1->setPixmap(okay);
166 ui.label2->setPixmap(next);
167 ui.label2->setVisible(true);
168 ui.textLabel2->setVisible(true);
169 break;
170
171 case 2:
172 ui.label2->setPixmap(okay);
173 ui.label3->setPixmap(next);
174 ui.label3->setVisible(true);
175 ui.textLabel3->setVisible(true);
176 break;
177
178 case 3:
179 ui.label3->setPixmap(okay);
180 ui.label4->setPixmap(next);
181 ui.label4->setVisible(true);
182 ui.textLabel4->setVisible(true);
183 break;
184
185 case 4:
186 ui.label4->setPixmap(okay);
187 ui.label5->setPixmap(next);
188 ui.label5->setVisible(true);
189 ui.textLabel5->setVisible(true);
190 break;
191
192 case 5:
193 ui.label5->setPixmap(okay);
194 break;
195 }
196 QCoreApplication::processEvents();
197}
198
199void InstallerDialog::setError(int pagenum)
200{
201 switch (pagenum)
202 {
203 case 0:
204 ui.label1->setPixmap(error);
205 break;
206
207 case 1:
208 ui.label2->setPixmap(error);
209 break;
210
211 case 2:
212 ui.label3->setPixmap(error);
213 break;
214
215 case 3:
216 ui.label4->setPixmap(error);
217 break;
218
219 case 4:
220 ui.label5->setPixmap(error);
221 break;
222 }
223 ui.logButton->setVisible(true);
224 QCoreApplication::processEvents();
225}
226
227void InstallerDialog::setupEngine()
228{
229 setItem(1);
230
231 if (m_engine.init())
232 {
233 QStringList urls;
234 foreach(Site *site, *m_engine.globalConfig()->sites())
235 {
236 const QUrl listURL = site->listURL().isEmpty() ? site->url() : site->listURL();
237 urls << site->name() + "&nbsp;:&nbsp;" + listURL.toString();
238 }
239
240 addHint("I'm fetching packages from the following repositories:<br>&nbsp;&nbsp;&nbsp;" + urls.join("<br>&nbsp;&nbsp;&nbsp;"));
241
242 foreach(const QString &package, m_packages)
243 {
244 Package *p = m_engine.getPackageByName(package);
245 if (p)
246 {
247 m_packagesToInstall.append(p);
248 m_engine.setDependencyState(p,m_packagesToInstall);
249 }
250 else
251 {
252 addHint(QString(".... could not find package %1").arg(package));
253 setError(4);
254 }
255 }
256 // the api should provide a method like
257 // m_engine.resolveDependencies(m_packagesToInstall);
258 // @TODO: in sdk mode we should download and install all dependencies but not the requested package
259 QTimer::singleShot(1,this,SLOT(downloadPackages()));
260 }
261 else
262 {
263 addHint(QString(".... initialisation failed"));
264 setError(1);
265 }
266}
267
268void InstallerDialog::downloadPackages()
269{
270 setItem(2);
271 addHint(QString("I will download up to %1 package(s) depending on what has been downloaded earlier").arg(m_packagesToInstall.size()));
272 m_counter = 10;
273 QTimer::singleShot(1,this,SLOT(downloadPackagesStage1()));
274}
275
276void InstallerDialog::downloadPackagesStage1()
277{
278 if (m_counter-- > 0)
279 {
280 setSubLabelHint(QString("%1 seconds left until download starts").arg(m_counter+1));
281 QTimer::singleShot(1000,this,SLOT(downloadPackagesStage1()));
282 }
283 else
284 {
285 setSubLabelHint("");
286 QTimer::singleShot(1,this,SLOT(downloadPackagesStage2()));
287 }
288}
289
290void InstallerDialog::downloadPackagesStage2()
291{
292 setItem(2);
293 addHint(QString("I'm downloading package(s)"));
294 if (m_engine.downloadPackages(m_packagesToInstall))
295 QTimer::singleShot(1,this,SLOT(installPackages()));
296 else
297 {
298 addHint(QString(".... download failed"));
299 setError(2);
300 }
301}
302
303void InstallerDialog::installPackages()
304{
305 setItem(3);
306 addHint(QString("I'm installing %1 package(s)").arg(m_packagesToInstall.size()));
307 if (m_engine.installPackages(m_packagesToInstall))
308 {
309 if (m_engine.withDevelopmentPackages())
310 QTimer::singleShot(1,this,SLOT(finished()));
311 else
312 QTimer::singleShot(1,this,SLOT(postProcessing()));
313 }
314 else
315 {
316 addHint(QString(".... installation failed"));
317 setError(3);
318 }
319}
320
321void InstallerDialog::postProcessing()
322{
323 setItem(4);
324 addHint("I'm running tools:");
325 connect(&m_postProcessing,SIGNAL(finished()),this,SLOT(finished()));
326 connect(&m_postProcessing,SIGNAL(commandStarted(const QString &)),this,SLOT(addHint(const QString &)));
327 ui.closeButton->setEnabled(false);
328 // fetch version from package - it is not sure yet if running a gui app --version returns the version on stdout
329 if(m_packagesToInstall.size() <= 0) {
330 finished();
331 return;
332 }
333
334 m_postProcessing.setVersion(m_packagesToInstall[0]->version().toString());
335 m_postProcessing.start();
336}
337
338void InstallerDialog::finished()
339{
340 setItem(5);
341 ui.closeButton->setEnabled(true);
342 ui.closeButton->setText(tr("Finish"));
343}
344
345void InstallerDialog::stop()
346{
347 close();
348}
349
350void InstallerDialog::closeEvent(QCloseEvent *e)
351{
352 m_postProcessing.stop();
353 if (m_log)
354 m_log->hide();
355 e->accept();
356}
357
358
359