1 #include "mainwizard.hpp"
2
3 #include <QDebug>
4
5 #include <QTime>
6 #include <QCloseEvent>
7 #include <QMessageBox>
8 #include <QTextCodec>
9 #include <QDir>
10
11 #include "intropage.hpp"
12 #include "methodselectionpage.hpp"
13 #include "languageselectionpage.hpp"
14 #include "existinginstallationpage.hpp"
15 #include "installationtargetpage.hpp"
16 #include "componentselectionpage.hpp"
17 #include "importpage.hpp"
18 #include "conclusionpage.hpp"
19
20 #ifdef OPENMW_USE_UNSHIELD
21 #include "installationpage.hpp"
22 #endif
23
24 using namespace Process;
25
MainWizard(QWidget * parent)26 Wizard::MainWizard::MainWizard(QWidget *parent) :
27 QWizard(parent),
28 mInstallations(),
29 mError(false),
30 mGameSettings(mCfgMgr)
31 {
32 #ifndef Q_OS_MAC
33 setWizardStyle(QWizard::ModernStyle);
34 #else
35 setWizardStyle(QWizard::ClassicStyle);
36 #endif
37
38 setWindowTitle(tr("OpenMW Wizard"));
39 setWindowIcon(QIcon(QLatin1String(":/images/openmw-wizard.png")));
40 setMinimumWidth(550);
41
42 // Set the property for comboboxes to the text instead of index
43 setDefaultProperty("QComboBox", "currentText", "currentIndexChanged");
44
45 setDefaultProperty("ComponentListWidget", "mCheckedItems", "checkedItemsChanged");
46
47 mImporterInvoker = new ProcessInvoker();
48
49 connect(mImporterInvoker->getProcess(), SIGNAL(started()),
50 this, SLOT(importerStarted()));
51
52 connect(mImporterInvoker->getProcess(), SIGNAL(finished(int,QProcess::ExitStatus)),
53 this, SLOT(importerFinished(int,QProcess::ExitStatus)));
54
55 mLogError = tr("<html><head/><body><p><b>Could not open %1 for writing</b></p> \
56 <p>Please make sure you have the right permissions \
57 and try again.</p></body></html>");
58
59 setupLog();
60 setupGameSettings();
61 setupLauncherSettings();
62 setupInstallations();
63 setupPages();
64
65 const boost::filesystem::path& installationPath = mCfgMgr.getInstallPath();
66 if (!installationPath.empty())
67 {
68 const boost::filesystem::path& dataPath = installationPath / "Data Files";
69 addInstallation(toQString(dataPath));
70 }
71 }
72
~MainWizard()73 Wizard::MainWizard::~MainWizard()
74 {
75 delete mImporterInvoker;
76 }
77
setupLog()78 void Wizard::MainWizard::setupLog()
79 {
80 QString logPath(toQString(mCfgMgr.getLogPath()));
81 logPath.append(QLatin1String("wizard.log"));
82
83 QFile file(logPath);
84
85 if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
86 QMessageBox msgBox;
87 msgBox.setWindowTitle(tr("Error opening Wizard log file"));
88 msgBox.setIcon(QMessageBox::Critical);
89 msgBox.setStandardButtons(QMessageBox::Ok);
90 msgBox.setText(mLogError.arg(file.fileName()));
91 msgBox.exec();
92 return qApp->quit();
93 }
94
95 addLogText(QString("Started OpenMW Wizard on %1").arg(QDateTime::currentDateTime().toString()));
96
97 qDebug() << logPath;
98 }
99
addLogText(const QString & text)100 void Wizard::MainWizard::addLogText(const QString &text)
101 {
102 QString logPath(toQString(mCfgMgr.getLogPath()));
103 logPath.append(QLatin1String("wizard.log"));
104
105 QFile file(logPath);
106
107 if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
108 QMessageBox msgBox;
109 msgBox.setWindowTitle(tr("Error opening Wizard log file"));
110 msgBox.setIcon(QMessageBox::Critical);
111 msgBox.setStandardButtons(QMessageBox::Ok);
112 msgBox.setText(mLogError.arg(file.fileName()));
113 msgBox.exec();
114 return qApp->quit();
115 }
116
117 if (!file.isSequential())
118 file.seek(file.size());
119
120 QTextStream out(&file);
121
122 if (!text.isEmpty())
123 {
124 out << text << "\n";
125 out.flush();
126 }
127 }
128
setupGameSettings()129 void Wizard::MainWizard::setupGameSettings()
130 {
131 QString userPath(toQString(mCfgMgr.getUserConfigPath()));
132 QString globalPath(toQString(mCfgMgr.getGlobalPath()));
133 QString message(tr("<html><head/><body><p><b>Could not open %1 for reading</b></p> \
134 <p>Please make sure you have the right permissions \
135 and try again.</p></body></html>"));
136
137 // Load the user config file first, separately
138 // So we can write it properly, uncontaminated
139 QString path(userPath + QLatin1String("openmw.cfg"));
140 QFile file(path);
141
142 qDebug() << "Loading config file:" << path.toUtf8().constData();
143
144 if (file.exists()) {
145 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
146 QMessageBox msgBox;
147 msgBox.setWindowTitle(tr("Error opening OpenMW configuration file"));
148 msgBox.setIcon(QMessageBox::Critical);
149 msgBox.setStandardButtons(QMessageBox::Ok);
150 msgBox.setText(message.arg(file.fileName()));
151 msgBox.exec();
152 return qApp->quit();
153 }
154 QTextStream stream(&file);
155 stream.setCodec(QTextCodec::codecForName("UTF-8"));
156
157 mGameSettings.readUserFile(stream);
158 }
159
160 file.close();
161
162 // Now the rest
163 QStringList paths;
164 paths.append(userPath + QLatin1String("openmw.cfg"));
165 paths.append(QLatin1String("openmw.cfg"));
166 paths.append(globalPath + QLatin1String("openmw.cfg"));
167
168 for (const QString &path2 : paths)
169 {
170 qDebug() << "Loading config file:" << path2.toUtf8().constData();
171
172 file.setFileName(path2);
173 if (file.exists()) {
174 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
175 QMessageBox msgBox;
176 msgBox.setWindowTitle(tr("Error opening OpenMW configuration file"));
177 msgBox.setIcon(QMessageBox::Critical);
178 msgBox.setStandardButtons(QMessageBox::Ok);
179 msgBox.setText(message.arg(file.fileName()));
180
181 return qApp->quit();
182 }
183 QTextStream stream(&file);
184 stream.setCodec(QTextCodec::codecForName("UTF-8"));
185
186 mGameSettings.readFile(stream);
187 }
188 file.close();
189 }
190 }
191
setupLauncherSettings()192 void Wizard::MainWizard::setupLauncherSettings()
193 {
194 QString path(toQString(mCfgMgr.getUserConfigPath()));
195 path.append(QLatin1String(Config::LauncherSettings::sLauncherConfigFileName));
196
197 QString message(tr("<html><head/><body><p><b>Could not open %1 for reading</b></p> \
198 <p>Please make sure you have the right permissions \
199 and try again.</p></body></html>"));
200
201
202 QFile file(path);
203
204 qDebug() << "Loading config file:" << path.toUtf8().constData();
205
206 if (file.exists()) {
207 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
208 QMessageBox msgBox;
209 msgBox.setWindowTitle(tr("Error opening OpenMW configuration file"));
210 msgBox.setIcon(QMessageBox::Critical);
211 msgBox.setStandardButtons(QMessageBox::Ok);
212 msgBox.setText(message.arg(file.fileName()));
213 msgBox.exec();
214 return qApp->quit();
215 }
216 QTextStream stream(&file);
217 stream.setCodec(QTextCodec::codecForName("UTF-8"));
218
219 mLauncherSettings.readFile(stream);
220 }
221
222 file.close();
223
224 }
225
setupInstallations()226 void Wizard::MainWizard::setupInstallations()
227 {
228 // Check if the paths actually contain a Morrowind installation
229 for (const QString& path : mGameSettings.getDataDirs())
230 {
231
232 if (findFiles(QLatin1String("Morrowind"), path))
233 addInstallation(path);
234 }
235 }
236
runSettingsImporter()237 void Wizard::MainWizard::runSettingsImporter()
238 {
239 writeSettings();
240
241 QString path(field(QLatin1String("installation.path")).toString());
242
243 QString userPath(toQString(mCfgMgr.getUserConfigPath()));
244 QFile file(userPath + QLatin1String("openmw.cfg"));
245
246 // Construct the arguments to run the importer
247 QStringList arguments;
248
249 // Import plugin selection?
250 if (field(QLatin1String("installation.retailDisc")).toBool() == true
251 || field(QLatin1String("installation.import-addons")).toBool() == true)
252 arguments.append(QLatin1String("--game-files"));
253
254 arguments.append(QLatin1String("--encoding"));
255
256 // Set encoding
257 QString language(field(QLatin1String("installation.language")).toString());
258
259 if (language == QLatin1String("Polish")) {
260 arguments.append(QLatin1String("win1250"));
261 } else if (language == QLatin1String("Russian")) {
262 arguments.append(QLatin1String("win1251"));
263 } else {
264 arguments.append(QLatin1String("win1252"));
265 }
266
267 // Now the paths
268 arguments.append(QLatin1String("--ini"));
269
270 if (field(QLatin1String("installation.retailDisc")).toBool() == true) {
271 arguments.append(path + QDir::separator() + QLatin1String("Morrowind.ini"));
272 } else {
273 arguments.append(mInstallations[path].iniPath);
274 }
275
276 arguments.append(QLatin1String("--cfg"));
277 arguments.append(userPath + QLatin1String("openmw.cfg"));
278
279 if (!mImporterInvoker->startProcess(QLatin1String("openmw-iniimporter"), arguments, false))
280 return qApp->quit();
281 }
282
addInstallation(const QString & path)283 void Wizard::MainWizard::addInstallation(const QString &path)
284 {
285 qDebug() << "add installation in: " << path;
286 Installation install;// = new Installation();
287
288 install.hasMorrowind = findFiles(QLatin1String("Morrowind"), path);
289 install.hasTribunal = findFiles(QLatin1String("Tribunal"), path);
290 install.hasBloodmoon = findFiles(QLatin1String("Bloodmoon"), path);
291
292 // Try to autodetect the Morrowind.ini location
293 QDir dir(path);
294 QFile file(dir.filePath("Morrowind.ini"));
295
296 // Try the parent directory
297 // In normal Morrowind installations that's where Morrowind.ini is
298 if (!file.exists()) {
299 dir.cdUp();
300 file.setFileName(dir.filePath(QLatin1String("Morrowind.ini")));
301 }
302
303 if (file.exists())
304 install.iniPath = file.fileName();
305
306 mInstallations.insert(QDir::toNativeSeparators(path), install);
307
308 // Add it to the openmw.cfg too
309 if (!mGameSettings.getDataDirs().contains(path)) {
310 mGameSettings.setMultiValue(QLatin1String("data"), path);
311 mGameSettings.addDataDir(path);
312 }
313 }
314
setupPages()315 void Wizard::MainWizard::setupPages()
316 {
317 setPage(Page_Intro, new IntroPage(this));
318 setPage(Page_MethodSelection, new MethodSelectionPage(this));
319 setPage(Page_LanguageSelection, new LanguageSelectionPage(this));
320 setPage(Page_ExistingInstallation, new ExistingInstallationPage(this));
321 setPage(Page_InstallationTarget, new InstallationTargetPage(this, mCfgMgr));
322 setPage(Page_ComponentSelection, new ComponentSelectionPage(this));
323 #ifdef OPENMW_USE_UNSHIELD
324 setPage(Page_Installation, new InstallationPage(this));
325 #endif
326 setPage(Page_Import, new ImportPage(this));
327 setPage(Page_Conclusion, new ConclusionPage(this));
328 setStartId(Page_Intro);
329
330 }
331
importerStarted()332 void Wizard::MainWizard::importerStarted()
333 {
334 }
335
importerFinished(int exitCode,QProcess::ExitStatus exitStatus)336 void Wizard::MainWizard::importerFinished(int exitCode, QProcess::ExitStatus exitStatus)
337 {
338 if (exitCode != 0 || exitStatus == QProcess::CrashExit)
339 return;
340
341 // Re-read the settings
342 setupGameSettings();
343 }
344
accept()345 void Wizard::MainWizard::accept()
346 {
347 writeSettings();
348 QWizard::accept();
349 }
350
reject()351 void Wizard::MainWizard::reject()
352 {
353 QMessageBox msgBox;
354 msgBox.setWindowTitle(tr("Quit Wizard"));
355 msgBox.setIcon(QMessageBox::Question);
356 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
357 msgBox.setText(tr("Are you sure you want to exit the Wizard?"));
358
359 if (msgBox.exec() == QMessageBox::Yes) {
360 QWizard::reject();
361 }
362 }
363
writeSettings()364 void Wizard::MainWizard::writeSettings()
365 {
366 // Write the encoding and language settings
367 QString language(field(QLatin1String("installation.language")).toString());
368 mLauncherSettings.setValue(QLatin1String("Settings/language"), language);
369
370 if (language == QLatin1String("Polish")) {
371 mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1250"));
372 } else if (language == QLatin1String("Russian")) {
373 mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1251"));
374 } else {
375 mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1252"));
376 }
377
378 // Write the installation path so that openmw can find them
379 QString path(field(QLatin1String("installation.path")).toString());
380
381 // Make sure the installation path is the last data= entry
382 mGameSettings.removeDataDir(path);
383 mGameSettings.addDataDir(path);
384
385 QString userPath(toQString(mCfgMgr.getUserConfigPath()));
386 QDir dir(userPath);
387
388 if (!dir.exists()) {
389 if (!dir.mkpath(userPath)) {
390 QMessageBox msgBox;
391 msgBox.setWindowTitle(tr("Error creating OpenMW configuration directory"));
392 msgBox.setIcon(QMessageBox::Critical);
393 msgBox.setStandardButtons(QMessageBox::Ok);
394 msgBox.setText(tr("<html><head/><body><p><b>Could not create %1</b></p> \
395 <p>Please make sure you have the right permissions \
396 and try again.</p></body></html>").arg(userPath));
397 msgBox.exec();
398 return qApp->quit();
399 }
400 }
401
402 // Game settings
403 QFile file(userPath + QLatin1String("openmw.cfg"));
404
405 if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) {
406 // File cannot be opened or created
407 QMessageBox msgBox;
408 msgBox.setWindowTitle(tr("Error writing OpenMW configuration file"));
409 msgBox.setIcon(QMessageBox::Critical);
410 msgBox.setStandardButtons(QMessageBox::Ok);
411 msgBox.setText(tr("<html><head/><body><p><b>Could not open %1 for writing</b></p> \
412 <p>Please make sure you have the right permissions \
413 and try again.</p></body></html>").arg(file.fileName()));
414 msgBox.exec();
415 return qApp->quit();
416 }
417
418 QTextStream stream(&file);
419 stream.setCodec(QTextCodec::codecForName("UTF-8"));
420
421 mGameSettings.writeFile(stream);
422 file.close();
423
424 // Launcher settings
425 file.setFileName(userPath + QLatin1String(Config::LauncherSettings::sLauncherConfigFileName));
426
427 if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) {
428 // File cannot be opened or created
429 QMessageBox msgBox;
430 msgBox.setWindowTitle(tr("Error writing OpenMW configuration file"));
431 msgBox.setIcon(QMessageBox::Critical);
432 msgBox.setStandardButtons(QMessageBox::Ok);
433 msgBox.setText(tr("<html><head/><body><p><b>Could not open %1 for writing</b></p> \
434 <p>Please make sure you have the right permissions \
435 and try again.</p></body></html>").arg(file.fileName()));
436 msgBox.exec();
437 return qApp->quit();
438 }
439
440 stream.setDevice(&file);
441 stream.setCodec(QTextCodec::codecForName("UTF-8"));
442
443 mLauncherSettings.writeFile(stream);
444 file.close();
445 }
446
findFiles(const QString & name,const QString & path)447 bool Wizard::MainWizard::findFiles(const QString &name, const QString &path)
448 {
449 QDir dir(path);
450
451 if (!dir.exists())
452 return false;
453
454 // TODO: add MIME handling to make sure the files are real
455 return (dir.entryList().contains(name + QLatin1String(".esm"), Qt::CaseInsensitive)
456 && dir.entryList().contains(name + QLatin1String(".bsa"), Qt::CaseInsensitive));
457 }
458
toQString(const boost::filesystem::path & path)459 QString Wizard::MainWizard::toQString(const boost::filesystem::path& path)
460 {
461 return QString::fromUtf8(path.string().c_str());
462 }
463