Use configured resolution for login/outgame/ingame
[ryzomcore.git] / ryzom / tools / client / ryzom_installer / src / operationdialog.cpp
blob2a1eac76ab158cd2f8f3b7221f6f641caf414244
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2020 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "stdpch.h"
18 #include "operationdialog.h"
19 #include "downloader.h"
20 #include "profilesdialog.h"
21 #include "configfile.h"
22 #include "config.h"
23 #include "profilesmodel.h"
24 #include "utils.h"
25 #include "nel/misc/path.h"
27 #include "filescopier.h"
28 #include "filesextractor.h"
29 #include "filescleaner.h"
31 #include "nel/misc/seven_zip.h"
33 #if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
34 #include <QtWinExtras/QWinTaskbarProgress>
35 #include <QtWinExtras/QWinTaskbarButton>
36 #endif
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
42 #ifdef DEBUG_NEW
43 #define new DEBUG_NEW
44 #endif
46 COperationDialog::COperationDialog(QWidget *parent):QDialog(parent), m_aborting(false), m_operation(OperationNone),
47 m_operationStep(DisplayNoServerError), m_operationStepCounter(0)
49 setupUi(this);
51 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
53 #if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
54 m_button = new QWinTaskbarButton(this);
55 #endif
57 // downloader
58 m_downloader = new CDownloader(this, this);
60 connect(m_downloader, SIGNAL(downloadPrepared()), SLOT(onDownloadPrepared()));
61 connect(m_downloader, SIGNAL(downloadDone()), SLOT(onDownloadDone()));
63 connect(operationButtonBox, SIGNAL(clicked(QAbstractButton*)), SLOT(onAbortClicked()));
65 // operations
66 connect(this, SIGNAL(prepare()), SLOT(onProgressPrepare()));
67 connect(this, SIGNAL(init(qint64, qint64)), SLOT(onProgressInit(qint64, qint64)));
68 connect(this, SIGNAL(start()), SLOT(onProgressStart()));
69 connect(this, SIGNAL(stop()), SLOT(onProgressStop()));
70 connect(this, SIGNAL(progress(qint64, QString)), SLOT(onProgressProgress(qint64, QString)));
71 connect(this, SIGNAL(success(qint64)), SLOT(onProgressSuccess(qint64)));
72 connect(this, SIGNAL(fail(QString)), SLOT(onProgressFail(QString)));
73 connect(this, SIGNAL(operationDone()), SLOT(onDone()));
75 adjustSize();
77 // fix height
78 setFixedHeight(height());
80 raise();
83 COperationDialog::~COperationDialog()
87 void COperationDialog::setOperation(OperationType operation)
89 m_operation = operation;
92 void COperationDialog::setUninstallComponents(const SComponents &components)
94 m_removeComponents = components;
97 void COperationDialog::processNextStep()
99 if (operationShouldStop())
101 rejectDelayed();
102 return;
105 switch (m_operation)
107 case OperationMigrate:
108 case OperationInstall:
109 processInstallNextStep();
110 break;
112 case OperationUpdateProfiles:
113 processUpdateProfilesNextStep();
114 break;
116 case OperationUninstall:
117 processUninstallNextStep();
118 break;
120 default:
121 break;
125 void COperationDialog::processInstallNextStep()
127 CConfigFile *config = CConfigFile::getInstance();
129 // long operations are done in a thread
130 OperationStep step = config->getInstallNextStep();
132 if (step == m_operationStep)
134 ++m_operationStepCounter;
136 else
138 m_operationStep = step;
139 m_operationStepCounter = 0;
142 if (m_operationStepCounter > 10)
144 nlwarning("Possible infinite loop, step %s %d times", Q2C(stepToString(m_operationStep)), m_operationStepCounter);
147 switch(step)
149 case DownloadData:
150 downloadData();
151 break;
153 case ExtractDownloadedData:
154 QtConcurrent::run(this, &COperationDialog::extractDownloadedData);
155 break;
157 case DownloadClient:
158 downloadClient();
159 break;
161 case ExtractDownloadedClient:
162 QtConcurrent::run(this, &COperationDialog::extractDownloadedClient);
163 break;
165 case CopyDataFiles:
166 QtConcurrent::run(this, &COperationDialog::copyDataFiles);
167 break;
169 case CopyProfileFiles:
170 QtConcurrent::run(this, &COperationDialog::copyProfileFiles);
171 break;
173 case CleanFiles:
174 QtConcurrent::run(this, &COperationDialog::cleanFiles);
175 break;
177 case ExtractBnpClient:
178 QtConcurrent::run(this, &COperationDialog::extractBnpClient);
179 break;
181 case CopyInstaller:
182 QtConcurrent::run(this, &COperationDialog::copyInstaller);
183 break;
185 case UninstallOldClient:
186 uninstallOldClient();
187 break;
189 case CreateProfile:
190 createDefaultProfile();
191 break;
193 case CreateProfileShortcuts:
194 createProfileShortcuts(0);
195 break;
197 case CreateAddRemoveEntry:
198 createAddRemoveEntry();
199 break;
201 case Done:
202 case LaunchInstalledInstaller:
203 acceptDelayed();
204 break;
206 default:
207 // cases already managed in main.cpp
208 nlwarning("Shouldn't happen, step %s", Q2C(stepToString(step)));
210 break;
214 void COperationDialog::updateAddRemoveComponents()
216 QStringList serversToUpdate;
218 QStringList profilesToDelete;
219 QStringList profilesToAdd;
221 CConfigFile *config = CConfigFile::getInstance();
223 foreach(const CProfile &profile, config->getProfiles())
225 // append all new profiles
226 profilesToAdd << profile.id;
229 foreach(const CProfile &profile, config->getBackupProfiles())
231 // append all old profiles
232 profilesToDelete << profile.id;
234 // remove profiles that didn't exist
235 profilesToAdd.removeAll(profile.id);
237 // delete all shortcuts, we'll recreate them later
238 profile.deleteShortcuts();
241 const CServer &defaultServer = config->getServer();
243 foreach(const CProfile &profile, config->getProfiles())
245 const CServer &server = config->getServer(profile.server);
247 QString serverDirectory = server.getDirectory();
249 // check if Ryzom is installed in new server directory
250 if (server.id != defaultServer.id && !config->isRyzomInstalledIn(serverDirectory) && serversToUpdate.indexOf(server.id) == -1)
252 serversToUpdate << server.id;
255 // remove profiles that still exist
256 profilesToDelete.removeAll(profile.id);
258 // delete all shortcuts, they'll be recreated later
259 profile.deleteShortcuts();
262 // update components to remove
263 m_removeComponents.profiles << profilesToDelete;
264 m_removeComponents.installer = false;
265 m_removeComponents.downloadedFiles = false;
267 // update components to add
268 m_addComponents.profiles << profilesToAdd;
269 m_addComponents.servers << serversToUpdate;
270 m_addComponents.installer = false;
271 m_addComponents.downloadedFiles = false;
274 void COperationDialog::processUpdateProfilesNextStep()
276 m_currentOperation = tr("Updating profiles...");
278 // for "update profiles" operations, we set installer to false when components are updated,
279 // since we're not using this variable
280 if (m_addComponents.installer && m_removeComponents.installer)
282 updateAddRemoveComponents();
285 // TODO: check all servers are downloaded
286 // TODO: delete profiles directories that are not used anymore
288 if (!m_removeComponents.profiles.isEmpty())
290 // delete profiles in another thread
291 QtConcurrent::run(this, &COperationDialog::deleteComponentsProfiles);
292 return;
295 if (!m_addComponents.profiles.isEmpty())
297 // add profiles in another thread
298 QtConcurrent::run(this, &COperationDialog::addComponentsProfiles);
299 return;
302 CConfigFile *config = CConfigFile::getInstance();
304 if (!m_addComponents.servers.isEmpty())
306 const CServer &defaultServer = config->getServer();
308 // servers files to download/update
309 foreach(const QString &serverId, m_addComponents.servers)
311 const CServer &server = config->getServer(serverId);
313 // data
314 if (!config->areRyzomDataInstalledIn(server.getDirectory()))
316 QString dataFile = config->getInstallationDirectory() + "/" + server.dataDownloadFilename;
318 // archive already downloaded
319 if (QFile::exists(dataFile))
321 // make server current
322 m_currentServerId = server.id;
324 // uncompress it
325 QtConcurrent::run(this, &COperationDialog::extractDownloadedData);
326 return;
329 // data download URLs are different, can't copy data from default server
330 if (server.dataDownloadUrl != defaultServer.dataDownloadUrl)
332 // download it
333 downloadData();
334 return;
337 // same data used
339 // copy them
340 // TODO
341 return;
344 // client
345 if (!config->isRyzomClientInstalledIn(server.getDirectory()))
347 // client download URLs are different, can't copy client from default server
348 if (server.clientDownloadUrl == defaultServer.clientDownloadUrl)
350 if (QFile::exists(""))
352 downloadData();
353 return;
357 else
359 QString clientFile = config->getInstallationDirectory() + "/" + config->expandVariables(server.clientDownloadFilename);
364 // recreate all shortcuts
365 foreach(const CProfile &profile, config->getProfiles())
367 profile.createShortcuts();
370 updateAddRemoveEntry();
372 acceptDelayed();
375 void COperationDialog::processUninstallNextStep()
377 CConfigFile *config = CConfigFile::getInstance();
379 if (!m_removeComponents.servers.isEmpty())
381 QtConcurrent::run(this, &COperationDialog::deleteComponentsServers);
383 else if (!m_removeComponents.profiles.isEmpty())
385 QtConcurrent::run(this, &COperationDialog::deleteComponentsProfiles);
387 else if (m_removeComponents.downloadedFiles)
389 QtConcurrent::run(this, &COperationDialog::deleteComponentsDownloadedFiles);
391 else if (m_removeComponents.installer)
393 QtConcurrent::run(this, &COperationDialog::deleteComponentsInstaller);
395 else
397 // done
398 acceptDelayed();
402 void COperationDialog::showEvent(QShowEvent *e)
404 #if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
405 m_button->setWindow(windowHandle());
406 #endif
408 e->accept();
410 processNextStep();
413 void COperationDialog::closeEvent(QCloseEvent *e)
415 if (e->spontaneous())
417 e->ignore();
419 onAbortClicked();
423 void COperationDialog::onAbortClicked()
425 if (m_downloader->isDownloading())
427 if (!m_downloader->supportsResume())
429 QMessageBox::StandardButton res = QMessageBox::question(this, tr("Confirmation"), tr("Warning, this server doesn't support resume! If you stop download now, you won't be able to resume it later.\nAre you sure to abort download?"));
431 if (res != QMessageBox::Yes) return;
435 QMutexLocker locker(&m_abortingMutex);
436 m_aborting = true;
439 void COperationDialog::onDownloadPrepared()
441 // actually download the file
442 m_downloader->getFile();
445 void COperationDialog::onDownloadDone()
447 renamePartFile();
449 emit operationDone();
452 void COperationDialog::onProgressPrepare()
454 operationProgressBar->setFormat(tr("%p% (%v/%m KiB)"));
456 operationProgressBar->setMinimum(0);
457 operationProgressBar->setMaximum(0);
458 operationProgressBar->setValue(0);
460 operationLabel->setText(m_currentOperation);
463 void COperationDialog::onProgressInit(qint64 current, qint64 total)
465 operationProgressBar->setMinimum(0);
466 operationProgressBar->setMaximum(total / 1024);
467 operationProgressBar->setValue(current / 1024);
469 #if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
470 m_button->progress()->setMinimum(0);
471 m_button->progress()->setMaximum(total / 1024);
472 m_button->progress()->setValue(current / 1024);
473 #endif
476 void COperationDialog::onProgressStart()
478 #if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
479 m_button->progress()->show();
480 #endif
483 void COperationDialog::onProgressStop()
485 #if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
486 m_button->progress()->hide();
487 #endif
489 rejectDelayed();
492 void COperationDialog::onProgressProgress(qint64 current, const QString &filename)
494 operationProgressLabel->setText(filename);
496 operationProgressBar->setValue(current / 1024);
498 #if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
499 m_button->progress()->setValue(current / 1024);
500 #endif
503 void COperationDialog::onProgressSuccess(qint64 total)
505 operationProgressBar->setValue(total / 1024);
507 #if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
508 m_button->progress()->hide();
509 #endif
512 void COperationDialog::onProgressFail(const QString &error)
514 QMessageBox::critical(this, tr("Error"), error);
517 QMutexLocker locker(&m_abortingMutex);
518 m_aborting = true;
521 processNextStep();
524 void COperationDialog::onDone()
526 processNextStep();
529 void COperationDialog::downloadData()
531 CConfigFile *config = CConfigFile::getInstance();
533 const CServer &server = config->getServer(m_currentServerId);
535 m_currentOperation = tr("Downloading data required by server %1...").arg(server.name);
537 m_downloader->prepareFile(config->expandVariables(server.dataDownloadUrl), config->getInstallationDirectory() + "/" + config->expandVariables(server.dataDownloadFilename) + ".part");
540 void COperationDialog::extractDownloadedData()
542 CConfigFile *config = CConfigFile::getInstance();
544 const CServer &server = config->getServer(m_currentServerId);
546 m_currentOperation = tr("Extracting data required by server %1...").arg(server.name);
548 QString dest = server.getDirectory();
550 #ifdef Q_OS_MAC
551 // under OS X, data should be uncompressed in Ryzom.app/Contents/Resources
552 dest += "/Ryzom.app/Contents/Resources";
553 #endif
555 CFilesExtractor extractor(this);
556 extractor.setSourceFile(config->getInstallationDirectory() + "/" + server.dataDownloadFilename);
557 extractor.setDestinationDirectory(dest);
559 if (!extractor.exec()) return;
561 emit operationDone();
564 void COperationDialog::downloadClient()
566 CConfigFile *config = CConfigFile::getInstance();
568 const CServer &server = config->getServer(m_currentServerId);
570 m_currentOperation = tr("Downloading client required by server %1...").arg(server.name);
572 m_downloader->prepareFile(config->expandVariables(server.clientDownloadUrl), config->getInstallationDirectory() + "/" + config->expandVariables(server.clientDownloadFilename) + ".part");
575 void COperationDialog::extractDownloadedClient()
577 CConfigFile *config = CConfigFile::getInstance();
579 const CServer &server = config->getServer(m_currentServerId);
581 m_currentOperation = tr("Extracting client required by server %1...").arg(server.name);
583 QString destinationDirectory = server.getDirectory();
585 CFilesExtractor extractor(this);
586 extractor.setSourceFile(config->getInstallationDirectory() + "/" + config->expandVariables(server.clientDownloadFilename));
587 extractor.setDestinationDirectory(destinationDirectory);
589 if (!extractor.exec()) return;
591 launchUpgradeScript(destinationDirectory, server.clientFilename);
593 emit operationDone();
596 void COperationDialog::copyDataFiles()
598 CConfigFile *config = CConfigFile::getInstance();
600 // default server
601 const CServer &server = config->getServer(m_currentServerId);
603 m_currentOperation = tr("Copying data required by server %1...").arg(server.name);
605 QStringList serverFiles;
606 serverFiles << "cfg";
607 serverFiles << "data";
608 serverFiles << "examples";
609 serverFiles << "patch";
610 serverFiles << "unpack";
612 CFilesCopier copier(this);
613 copier.setSourceDirectory(config->getSrcServerDirectory());
614 copier.setDestinationDirectory(server.getDirectory());
615 copier.setIncludeFilter(serverFiles);
617 if (!copier.exec()) return;
619 emit operationDone();
622 void COperationDialog::copyProfileFiles()
624 CConfigFile *config = CConfigFile::getInstance();
626 // default server
627 const CServer &server = config->getServer();
629 // default profile
630 const CProfile &profile = config->getProfile();
632 m_currentOperation = tr("Copying old profile to new location...");
634 QStringList profileFiles;
635 profileFiles << "cache";
636 profileFiles << "save";
637 profileFiles << "user";
638 profileFiles << "screenshots";
639 profileFiles << "client.cfg";
640 profileFiles << "*.log";
642 CFilesCopier copier(this);
643 copier.setSourceDirectory(config->getSrcProfileDirectory());
644 copier.setDestinationDirectory(profile.getDirectory());
645 copier.setIncludeFilter(profileFiles);
647 if (!copier.exec()) return;
649 // correct path to client_default.cfg
650 profile.createClientConfig();
652 emit operationDone();
655 void COperationDialog::extractBnpClient()
657 CConfigFile *config = CConfigFile::getInstance();
659 // default server
660 const CServer &server = config->getServer();
662 m_currentOperation = tr("Extracting client to new location...");
664 QString destinationDirectory = server.getDirectory();
666 CFilesExtractor extractor(this);
667 extractor.setSourceFile(config->getSrcServerClientBNPFullPath());
668 extractor.setDestinationDirectory(destinationDirectory);
670 if (!extractor.exec()) return;
672 launchUpgradeScript(destinationDirectory, server.clientFilename);
674 emit operationDone();
677 void COperationDialog::launchUpgradeScript(const QString &directory, const QString &executable)
679 QString upgradeScript = directory + "/upgd_nl.";
681 #ifdef Q_OS_WIN
682 upgradeScript += "bat";
683 #else
684 upgradeScript += "sh";
685 #endif
687 if (QFile::exists(upgradeScript))
689 QProcess process;
691 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
692 env.insert("RYZOM_CLIENT", QDir::toNativeSeparators(directory + "/" + executable));
693 env.insert("UNPACKPATH", QDir::toNativeSeparators(directory + "/unpack"));
694 env.insert("ROOTPATH", QDir::toNativeSeparators(directory));
695 env.insert("STARTUPPATH", "");
696 process.setProcessEnvironment(env);
698 // permissions to execute script
699 QFileDevice::Permissions permissions;
700 permissions |= QFileDevice::ExeOther;
701 permissions |= QFileDevice::ExeOwner;
702 permissions |= QFileDevice::ExeUser;
703 permissions |= QFileDevice::ReadOther;
704 permissions |= QFileDevice::ReadOwner;
705 permissions |= QFileDevice::ReadUser;
706 permissions |= QFileDevice::WriteOwner;
708 if (!QFile::setPermissions(upgradeScript, permissions))
710 nlwarning("Unable to set executable flag to %s", Q2C(upgradeScript));
713 process.start(upgradeScript);
715 while (process.waitForFinished())
717 nlwarning("Waiting end of %s", Q2C(upgradeScript));
723 void COperationDialog::copyInstaller()
725 CConfigFile *config = CConfigFile::getInstance();
727 m_currentOperation = tr("Copying installer to new location...");
729 QString newInstallerFullPath = config->getInstallerInstalledFilePath();
731 if (!newInstallerFullPath.isEmpty())
733 QString destinationDirectory = config->getInstallationDirectory();
734 QString oldInstallerFullPath = config->getInstallerCurrentFilePath();
735 QString srcDir = config->getInstallerCurrentDirPath();
737 // always copy new installers
738 CFilesCopier copier(this);
739 copier.setIncludeFilter(config->getInstallerRequiredFiles());
740 #ifndef Q_OS_MAC
741 copier.addFile(oldInstallerFullPath);
742 #endif
743 copier.setSourceDirectory(srcDir);
744 copier.setDestinationDirectory(config->getInstallationDirectory());
746 if (!copier.exec()) return;
748 #ifndef Q_OS_MAC
749 // copied file
750 oldInstallerFullPath = config->getInstallationDirectory() + "/" + QFileInfo(oldInstallerFullPath).fileName();
752 // rename old filename if different
753 if (oldInstallerFullPath != newInstallerFullPath)
755 // delete previous installer
756 QFile::remove(newInstallerFullPath);
758 // rename new installer with final name
759 QFile::rename(oldInstallerFullPath, newInstallerFullPath);
761 #endif
763 // create menu directory if defined
764 QString path = config->getMenuDirectory();
766 if (!path.isEmpty() && !QDir().mkpath(path))
768 nlwarning("Unable to create directory %s", Q2C(path));
771 // create installer link in menu
772 QString executable = newInstallerFullPath;
773 QString shortcut = config->getInstallerMenuShortcutFullPath();
774 QString name = "Ryzom Installer";
775 QString icon;
777 #ifdef Q_OS_WIN32
778 // under Windows, icon is included in executable
779 icon = executable;
780 #elif defined(Q_OS_MAC)
781 // everything is in bundle
782 #else
783 // icon is in the same directory as installer
784 icon = config->getInstallationDirectory() + "/ryzom_installer.png";
786 // create icon if not exists
787 if (!QFile::exists(icon) && !writeResource(":/icons/ryzom.png", icon))
789 nlwarning("Unable to create icon %s", Q2C(icon));
791 #endif
793 createShortcut(shortcut, name, executable, "", icon, "");
795 // installer already copied, don't need to copy it again
796 config->setInstallerCopied(true);
799 emit operationDone();
802 void COperationDialog::uninstallOldClient()
804 #ifdef Q_OS_WIN
806 #ifdef Q_OS_WIN64
807 // use WOW6432Node in 64 bits (64 bits OS and 64 bits Installer) because Ryzom old installer was in 32 bits
808 QSettings settings("HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Ryzom", QSettings::NativeFormat);
809 #else
810 QSettings settings("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Ryzom", QSettings::NativeFormat);
811 #endif
813 // check if Ryzom 2.1.0 is installed
814 if (settings.contains("UninstallString"))
816 QString uninstaller = settings.value("UninstallString").toString();
818 if (!uninstaller.isEmpty() && QFile::exists(uninstaller))
820 QMessageBox::StandardButtons button = QMessageBox::question(this, tr("Uninstall old client"), tr("An old version of Ryzom has been detected on this system, would you like to uninstall it to save space disk?"));
822 if (button == QMessageBox::Yes)
824 // to not ask twice
825 CConfigFile::getInstance()->setUninstallingOldClient(true);
827 // remember the choice
828 CConfigFile::getInstance()->setShouldUninstallOldClient(true);
830 // launch old uninstaller
831 QDesktopServices::openUrl(QUrl::fromLocalFile(uninstaller));
833 else
835 // don't ask this question anymore
836 CConfigFile::getInstance()->setShouldUninstallOldClient(false);
839 // save the choice
840 CConfigFile::getInstance()->save();
843 #endif
845 emit operationDone();
848 void COperationDialog::cleanFiles()
850 CConfigFile *config = CConfigFile::getInstance();
852 // default server
853 const CServer &server = config->getServer();
855 m_currentOperation = tr("Cleaning obsolete files...");
857 CFilesCleaner cleaner(this);
858 cleaner.setDirectory(server.getDirectory());
859 cleaner.exec();
861 emit operationDone();
864 bool COperationDialog::createDefaultProfile()
866 CConfigFile *config = CConfigFile::getInstance();
868 CServer server = config->getServer();
870 m_currentOperation = tr("Creating default profile...");
872 CProfile profile;
874 profile.id = "0";
875 profile.name = QString("Ryzom (%1)").arg(server.name);
876 profile.server = server.id;
877 profile.comments = "Default profile created by Ryzom Installer";
878 profile.desktopShortcut = false;
879 profile.menuShortcut = false;
880 // default use locale
881 profile.language = config->getLanguage();
883 #ifdef Q_OS_WIN32
884 QStringList paths;
886 // desktop
888 // Windows XP
889 paths << "C:/Documents and Settings/All Users/Desktop";
890 // since Windows Vista
891 paths << "C:/Users/Public/Desktop";
892 // new location
893 paths << QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
895 foreach(const QString &path, paths)
897 if (QFile::exists(path + "/Ryzom.lnk")) profile.desktopShortcut = true;
900 paths.clear();
902 // start menu
904 // Windows XP
905 paths << "C:/Documents and Settings/All Users/Start Menu/Programs";
906 // since Windows Vista
907 paths << "C:/ProgramData/Microsoft/Windows/Start Menu/Programs";
908 // new location
909 paths << QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
911 foreach(const QString &path, paths)
913 if (QFile::exists(path + "/Ryzom/Ryzom.lnk")) profile.menuShortcut = true;
915 #endif
917 config->addProfile(profile);
918 config->save();
920 emit operationDone();
922 return true;
925 bool COperationDialog::createProfileShortcuts(const QString &profileId)
927 CConfigFile *config = CConfigFile::getInstance();
929 const CProfile &profile = config->getProfile(profileId);
931 // wrong profile
932 if (profile.id.isEmpty()) return false;
934 m_currentOperation = tr("Creating shortcuts for profile %1...").arg(profile.id);
936 profile.createShortcuts();
938 emit operationDone();
940 return true;
943 bool COperationDialog::createAddRemoveEntry()
945 CConfigFile *config = CConfigFile::getInstance();
947 QString newInstallerFullPath = config->getInstallerInstalledFilePath();
949 if (!newInstallerFullPath.isEmpty() && QFile::exists(newInstallerFullPath))
951 #ifdef Q_OS_WIN
952 QSettings settings("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Ryzom", QSettings::NativeFormat);
954 QString nativeFullPath = QDir::toNativeSeparators(newInstallerFullPath);
956 settings.setValue("Comments", config->getProductComments());
957 settings.setValue("DisplayIcon", nativeFullPath + ",0");
958 settings.setValue("DisplayName", QApplication::applicationName());
959 settings.setValue("InstallDate", QDateTime::currentDateTime().toString("Ymd"));
960 settings.setValue("InstallLocation", config->getInstallationDirectory());
961 settings.setValue("NoModify", 0);
962 settings.setValue("NoRemove", 0);
963 settings.setValue("NoRepair", 0);
964 if (!config->getProductPublisher().isEmpty()) settings.setValue("Publisher", config->getProductPublisher());
965 settings.setValue("QuietUninstallString", nativeFullPath + " -u -s");
966 settings.setValue("UninstallString", nativeFullPath + " -u");
967 if (!config->getProductUpdateUrl().isEmpty()) settings.setValue("URLUpdateInfo", config->getProductUpdateUrl());
968 if (!config->getProductAboutUrl().isEmpty()) settings.setValue("URLInfoAbout", config->getProductAboutUrl());
969 if (!config->getProductHelpUrl().isEmpty()) settings.setValue("HelpLink", config->getProductHelpUrl());
970 // ModifyPath
971 #endif
974 updateAddRemoveEntry();
976 emit operationDone();
978 return true;
981 bool COperationDialog::updateAddRemoveEntry()
983 CConfigFile *config = CConfigFile::getInstance();
985 QString newInstallerFullPath = config->getInstallerInstalledFilePath();
987 if (!newInstallerFullPath.isEmpty() && QFile::exists(newInstallerFullPath))
989 QString newInstallerFilename = config->getInstallerFilename();
991 #ifdef Q_OS_WIN
992 QSettings settings("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Ryzom", QSettings::NativeFormat);
994 QString version = QApplication::applicationVersion();
996 settings.setValue("DisplayVersion", version);
997 settings.setValue("EstimatedSize", (quint32)(getDirectorySize(config->getInstallationDirectory(), true) / 1024)); // size if in KiB
999 QStringList versionTokens = version.split('.');
1000 settings.setValue("MajorVersion", versionTokens[0].toInt());
1001 settings.setValue("MinorVersion", versionTokens[1].toInt());
1002 #endif
1005 return true;
1008 bool COperationDialog::deleteAddRemoveEntry()
1010 #ifdef Q_OS_WIN
1011 QSettings settings("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Ryzom", QSettings::NativeFormat);
1012 settings.remove("");
1013 #endif
1015 return true;
1018 void COperationDialog::deleteComponentsServers()
1020 m_currentOperation = tr("Deleting client...");
1022 emit prepare();
1023 emit init(0, m_removeComponents.servers.size());
1024 emit start();
1026 CConfigFile *config = CConfigFile::getInstance();
1028 int i = 0;
1030 foreach(const QString &serverId, m_removeComponents.servers)
1032 if (operationShouldStop())
1034 emit stop();
1035 return;
1038 const CServer &server = config->getServer(serverId);
1040 emit progress(i++, server.name);
1042 QString path = server.getDirectory();
1044 if (!path.isEmpty())
1046 QDir dir(path);
1048 if (dir.exists() && !dir.removeRecursively())
1050 emit fail(tr("Unable to delete files for client %1").arg(server.name));
1051 return;
1055 // delete all links to clients
1056 for (int i = 0; i < config->getProfilesCount(); ++i)
1058 const CProfile &profile = config->getProfile(i);
1060 if (profile.server == serverId)
1062 profile.deleteShortcuts();
1067 emit success(m_removeComponents.servers.size());
1069 // clear list of all servers to uninstall
1070 m_removeComponents.servers.clear();
1072 // delete Ryzom directory if all files have been deleted
1073 if (isDirectoryEmpty(config->getInstallationDirectory(), true)) QDir(config->getInstallationDirectory()).removeRecursively();
1075 emit operationDone();
1078 void COperationDialog::addComponentsProfiles()
1080 m_currentOperation = tr("Adding profiles...");
1082 CConfigFile *config = CConfigFile::getInstance();
1084 foreach(const QString &profileId, m_addComponents.profiles)
1086 const CProfile &profile = config->getProfile(profileId);
1088 // wrong profile
1089 if (profile.id.isEmpty()) continue;
1091 profile.createShortcuts();
1092 profile.createClientConfig();
1095 // clear list of all servers to uninstall
1096 m_addComponents.profiles.clear();
1098 emit operationDone();
1101 void COperationDialog::deleteComponentsProfiles()
1103 m_currentOperation = tr("Deleting profiles...");
1105 emit prepare();
1106 emit init(0, m_removeComponents.servers.size());
1108 CConfigFile *config = CConfigFile::getInstance();
1110 // some profiles have been removed, use backup profiles
1111 bool useBackup = !config->getBackupProfiles().isEmpty();
1113 int i = 0;
1115 foreach(const QString &profileId, m_removeComponents.profiles)
1117 if (operationShouldStop())
1119 emit stop();
1120 return;
1123 // only search in backup profiles, because they are already deleted in profiles
1124 const CProfile &profile = useBackup ? config->getBackupProfile(profileId):config->getProfile(profileId);
1126 // already deleted profile
1127 if (profile.id.isEmpty()) continue;
1129 emit progress(i++, profile.name);
1131 QString path = profile.getDirectory();
1133 if (!path.isEmpty())
1135 QDir dir(path);
1137 if (dir.exists() && !dir.removeRecursively())
1139 emit fail(tr("Unable to delete files for profile %1").arg(profile.name));
1140 return;
1144 profile.deleteShortcuts();
1146 // delete profile if still used
1147 if (!useBackup) config->removeProfile(profileId);
1150 emit success(m_removeComponents.profiles.size());
1152 // clear list of all profiles to uninstall
1153 m_removeComponents.profiles.clear();
1155 // delete profiles directory if all files have been deleted
1156 if (isDirectoryEmpty(config->getProfileDirectory(), true)) QDir(config->getProfileDirectory()).removeRecursively();
1158 emit operationDone();
1161 void COperationDialog::deleteComponentsInstaller()
1163 m_currentOperation = tr("Deleting installer...");
1165 CConfigFile *config = CConfigFile::getInstance();
1167 deleteAddRemoveEntry();
1169 // delete menu
1170 QString path = config->getMenuDirectory();
1172 if (!path.isEmpty())
1174 QDir dir(path);
1176 dir.removeRecursively();
1179 path = config->getInstallerInstalledDirPath();
1180 QStringList files = config->getInstallerRequiredFiles();
1182 foreach(const QString &file, files)
1184 QString fullPath = path + "/" + file;
1186 // delete file
1187 if (QFile::exists(fullPath) && !QFile::remove(fullPath))
1189 #ifdef Q_OS_WIN32
1190 // under Windows, a running executable is locked, so we need to delete it later
1191 MoveFileExW(qToWide(QDir::toNativeSeparators(fullPath)), NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
1192 #endif
1196 // delete installer shortcuts
1197 removeShortcut(config->getInstallerMenuShortcutFullPath());
1198 removeShortcut(config->getInstallerDesktopShortcutFullPath());
1200 // delete configuration file
1201 config->remove();
1203 // reset it once it's done
1204 m_removeComponents.installer = false;
1206 // delete Ryzom directory if all files have been deleted
1207 if (isDirectoryEmpty(config->getInstallationDirectory(), true)) QDir(config->getInstallationDirectory()).removeRecursively();
1209 emit success(1);
1210 emit operationDone();
1213 void COperationDialog::deleteComponentsDownloadedFiles()
1215 m_currentOperation = tr("Deleting downloaded files...");
1217 CConfigFile *config = CConfigFile::getInstance();
1219 QString path = config->getInstallationDirectory();
1221 QDir dir(path);
1223 QStringList filter;
1224 filter << "*.log";
1225 filter << "*.7z";
1226 filter << "*.bnp";
1227 filter << "*.zip";
1228 filter << "*.part";
1229 filter << "ryzom_installer_uninstalling_old_client";
1231 QStringList files = dir.entryList(filter, QDir::Files);
1233 foreach(const QString &file, files)
1235 if (!QFile::remove(dir.filePath(file)))
1237 nlwarning("Unable to delete file %s", Q2C(file));
1241 // reset it once it's done
1242 m_removeComponents.downloadedFiles = false;
1244 // delete Ryzom directory if all files have been deleted
1245 if (isDirectoryEmpty(config->getInstallationDirectory(), true)) QDir(config->getInstallationDirectory()).removeRecursively();
1247 emit success(1);
1248 emit operationDone();
1251 void COperationDialog::operationPrepare()
1253 emit prepare();
1256 void COperationDialog::operationInit(qint64 current, qint64 total)
1258 emit init(current, total);
1261 void COperationDialog::operationStart()
1263 emit start();
1266 void COperationDialog::operationStop()
1268 emit stop();
1271 void COperationDialog::operationProgress(qint64 current, const QString &filename)
1273 emit progress(current, filename);
1276 void COperationDialog::operationSuccess(qint64 total)
1278 emit success(total);
1281 void COperationDialog::operationFail(const QString &error)
1283 emit fail(error);
1286 void COperationDialog::operationContinue()
1288 emit operationDone();
1291 bool COperationDialog::operationShouldStop()
1293 QMutexLocker locker(&m_abortingMutex);
1295 return m_aborting;
1298 void COperationDialog::renamePartFile()
1300 QString partFile = m_downloader->getFileFullPath();
1302 QString finalFile = partFile;
1303 finalFile.remove(".part");
1305 if (partFile != finalFile)
1307 QFile::rename(partFile, finalFile);
1311 void COperationDialog::acceptDelayed()
1313 // wait 500ms before to call accept()
1314 QTimer::singleShot(500, this, SLOT(accept()));
1317 void COperationDialog::rejectDelayed()
1319 // wait 500ms before to call reject()
1320 QTimer::singleShot(500, this, SLOT(reject()));