khanat-opennel-code/code/ryzom/tools/client/ryzom_installer/src/operationdialog.cpp

1324 lines
32 KiB
C++

// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdpch.h"
#include "operationdialog.h"
#include "downloader.h"
#include "profilesdialog.h"
#include "configfile.h"
#include "config.h"
#include "profilesmodel.h"
#include "utils.h"
#include "nel/misc/path.h"
#include "filescopier.h"
#include "filesextractor.h"
#include "filescleaner.h"
#include "seven_zip.h"
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
#include <QtWinExtras/QWinTaskbarProgress>
#include <QtWinExtras/QWinTaskbarButton>
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif
COperationDialog::COperationDialog(QWidget *parent):QDialog(parent), m_aborting(false), m_operation(OperationNone),
m_operationStep(DisplayNoServerError), m_operationStepCounter(0)
{
setupUi(this);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
m_button = new QWinTaskbarButton(this);
#endif
// downloader
m_downloader = new CDownloader(this, this);
connect(m_downloader, SIGNAL(downloadPrepared()), SLOT(onDownloadPrepared()));
connect(m_downloader, SIGNAL(downloadDone()), SLOT(onDownloadDone()));
connect(operationButtonBox, SIGNAL(clicked(QAbstractButton*)), SLOT(onAbortClicked()));
// operations
connect(this, SIGNAL(prepare()), SLOT(onProgressPrepare()));
connect(this, SIGNAL(init(qint64, qint64)), SLOT(onProgressInit(qint64, qint64)));
connect(this, SIGNAL(start()), SLOT(onProgressStart()));
connect(this, SIGNAL(stop()), SLOT(onProgressStop()));
connect(this, SIGNAL(progress(qint64, QString)), SLOT(onProgressProgress(qint64, QString)));
connect(this, SIGNAL(success(qint64)), SLOT(onProgressSuccess(qint64)));
connect(this, SIGNAL(fail(QString)), SLOT(onProgressFail(QString)));
connect(this, SIGNAL(done()), SLOT(onDone()));
adjustSize();
// fix height
setFixedHeight(height());
raise();
}
COperationDialog::~COperationDialog()
{
}
void COperationDialog::setOperation(OperationType operation)
{
m_operation = operation;
}
void COperationDialog::setUninstallComponents(const SComponents &components)
{
m_removeComponents = components;
}
void COperationDialog::processNextStep()
{
if (operationShouldStop())
{
rejectDelayed();
return;
}
switch (m_operation)
{
case OperationMigrate:
case OperationInstall:
processInstallNextStep();
break;
case OperationUpdateProfiles:
processUpdateProfilesNextStep();
break;
case OperationUninstall:
processUninstallNextStep();
break;
default:
break;
}
}
void COperationDialog::processInstallNextStep()
{
CConfigFile *config = CConfigFile::getInstance();
// default server
const CServer &server = config->getServer();
// default profile
const CProfile &configuration = config->getProfile();
// long operations are done in a thread
OperationStep step = config->getInstallNextStep();
if (step == m_operationStep)
{
++m_operationStepCounter;
}
else
{
m_operationStep = step;
m_operationStepCounter = 0;
}
if (m_operationStepCounter > 10)
{
qDebug() << "possible infinite loop" << m_operationStep << m_operationStepCounter;
}
switch(step)
{
case DownloadData:
downloadData();
break;
case ExtractDownloadedData:
QtConcurrent::run(this, &COperationDialog::extractDownloadedData);
break;
case DownloadClient:
downloadClient();
break;
case ExtractDownloadedClient:
QtConcurrent::run(this, &COperationDialog::extractDownloadedClient);
break;
case CopyDataFiles:
QtConcurrent::run(this, &COperationDialog::copyDataFiles);
break;
case CopyProfileFiles:
QtConcurrent::run(this, &COperationDialog::copyProfileFiles);
break;
case CleanFiles:
QtConcurrent::run(this, &COperationDialog::cleanFiles);
break;
case ExtractBnpClient:
QtConcurrent::run(this, &COperationDialog::extractBnpClient);
break;
case CopyInstaller:
QtConcurrent::run(this, &COperationDialog::copyInstaller);
break;
case UninstallOldClient:
uninstallOldClient();
break;
case CreateProfile:
createDefaultProfile();
break;
case CreateProfileShortcuts:
createProfileShortcuts(0);
break;
case CreateAddRemoveEntry:
createAddRemoveEntry();
break;
case Done:
acceptDelayed();
break;
default:
// cases already managed in main.cpp
qDebug() << "Shouldn't happen, step" << step;
break;
}
}
void COperationDialog::updateAddRemoveComponents()
{
QStringList serversToUpdate;
QStringList profilesToDelete;
QStringList profilesToAdd;
CConfigFile *config = CConfigFile::getInstance();
foreach(const CProfile &profile, config->getProfiles())
{
// append all new profiles
profilesToAdd << profile.id;
}
foreach(const CProfile &profile, config->getBackupProfiles())
{
// append all old profiles
profilesToDelete << profile.id;
// remove profiles that didn't exist
profilesToAdd.removeAll(profile.id);
// delete all shortcuts, we'll recreate them later
profile.deleteShortcuts();
}
const CServer &defaultServer = config->getServer();
foreach(const CProfile &profile, config->getProfiles())
{
const CServer &server = config->getServer(profile.server);
QString serverDirectory = server.getDirectory();
// check if Ryzom is installed in new server directory
if (server.id != defaultServer.id && !config->isRyzomInstalledIn(serverDirectory) && serversToUpdate.indexOf(server.id) == -1)
{
serversToUpdate << server.id;
}
// remove profiles that still exist
profilesToDelete.removeAll(profile.id);
// delete all shortcuts, they'll be recreated later
profile.deleteShortcuts();
}
// update components to remove
m_removeComponents.profiles << profilesToDelete;
m_removeComponents.installer = false;
m_removeComponents.downloadedFiles = false;
// update components to add
m_addComponents.profiles << profilesToAdd;
m_addComponents.servers << serversToUpdate;
m_addComponents.installer = false;
m_addComponents.downloadedFiles = false;
}
void COperationDialog::processUpdateProfilesNextStep()
{
m_currentOperation = tr("Updating profiles...");
// for "update profiles" operations, we set installer to false when components are updated,
// since we're not using this variable
if (m_addComponents.installer && m_removeComponents.installer)
{
updateAddRemoveComponents();
}
// TODO: check all servers are downloaded
// TODO: delete profiles directories that are not used anymore
if (!m_removeComponents.profiles.isEmpty())
{
// delete profiles in another thread
QtConcurrent::run(this, &COperationDialog::deleteComponentsProfiles);
return;
}
if (!m_addComponents.profiles.isEmpty())
{
// add profiles in another thread
QtConcurrent::run(this, &COperationDialog::addComponentsProfiles);
return;
}
CConfigFile *config = CConfigFile::getInstance();
if (!m_addComponents.servers.isEmpty())
{
const CServer &defaultServer = config->getServer();
// servers files to download/update
foreach(const QString &serverId, m_addComponents.servers)
{
const CServer &server = config->getServer(serverId);
// data
if (!config->areRyzomDataInstalledIn(server.getDirectory()))
{
QString dataFile = config->getInstallationDirectory() + "/" + server.dataDownloadFilename;
// archive already downloaded
if (QFile::exists(dataFile))
{
// make server current
m_currentServerId = server.id;
// uncompress it
QtConcurrent::run(this, &COperationDialog::extractDownloadedData);
return;
}
// data download URLs are different, can't copy data from default server
if (server.dataDownloadUrl != defaultServer.dataDownloadUrl)
{
// download it
downloadData();
return;
}
// same data used
// copy them
// TODO
return;
}
// client
if (!config->isRyzomClientInstalledIn(server.getDirectory()))
{
// client download URLs are different, can't copy client from default server
if (server.clientDownloadUrl == defaultServer.clientDownloadUrl)
{
if (QFile::exists(""))
downloadData();
return;
}
}
else
{
QString clientFile = config->getInstallationDirectory() + "/" + config->expandVariables(server.clientDownloadFilename);
}
}
}
// recreate all shortcuts
foreach(const CProfile &profile, config->getProfiles())
{
profile.createShortcuts();
}
updateAddRemoveEntry();
acceptDelayed();
}
void COperationDialog::processUninstallNextStep()
{
CConfigFile *config = CConfigFile::getInstance();
if (!m_removeComponents.servers.isEmpty())
{
QtConcurrent::run(this, &COperationDialog::deleteComponentsServers);
}
else if (!m_removeComponents.profiles.isEmpty())
{
QtConcurrent::run(this, &COperationDialog::deleteComponentsProfiles);
}
else if (m_removeComponents.downloadedFiles)
{
QtConcurrent::run(this, &COperationDialog::deleteComponentsDownloadedFiles);
}
else if (m_removeComponents.installer)
{
QtConcurrent::run(this, &COperationDialog::deleteComponentsInstaller);
}
else
{
// done
acceptDelayed();
}
}
void COperationDialog::showEvent(QShowEvent *e)
{
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
m_button->setWindow(windowHandle());
#endif
e->accept();
processNextStep();
}
void COperationDialog::closeEvent(QCloseEvent *e)
{
if (e->spontaneous())
{
e->ignore();
onAbortClicked();
}
}
void COperationDialog::onAbortClicked()
{
if (m_downloader->isDownloading())
{
if (!m_downloader->supportsResume())
{
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?"));
if (res != QMessageBox::Yes) return;
}
}
QMutexLocker locker(&m_abortingMutex);
m_aborting = true;
}
void COperationDialog::onDownloadPrepared()
{
// actually download the file
m_downloader->getFile();
}
void COperationDialog::onDownloadDone()
{
renamePartFile();
emit done();
}
void COperationDialog::onProgressPrepare()
{
operationProgressBar->setFormat(tr("%p% (%v/%m KiB)"));
operationProgressBar->setMinimum(0);
operationProgressBar->setMaximum(0);
operationProgressBar->setValue(0);
operationLabel->setText(m_currentOperation);
}
void COperationDialog::onProgressInit(qint64 current, qint64 total)
{
operationProgressBar->setMinimum(0);
operationProgressBar->setMaximum(total / 1024);
operationProgressBar->setValue(current / 1024);
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
m_button->progress()->setMinimum(0);
m_button->progress()->setMaximum(total / 1024);
m_button->progress()->setValue(current / 1024);
#endif
}
void COperationDialog::onProgressStart()
{
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
m_button->progress()->show();
#endif
}
void COperationDialog::onProgressStop()
{
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
m_button->progress()->hide();
#endif
rejectDelayed();
}
void COperationDialog::onProgressProgress(qint64 current, const QString &filename)
{
operationProgressLabel->setText(filename);
operationProgressBar->setValue(current / 1024);
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
m_button->progress()->setValue(current / 1024);
#endif
}
void COperationDialog::onProgressSuccess(qint64 total)
{
operationProgressBar->setValue(total / 1024);
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
m_button->progress()->hide();
#endif
}
void COperationDialog::onProgressFail(const QString &error)
{
QMessageBox::critical(this, tr("Error"), error);
{
QMutexLocker locker(&m_abortingMutex);
m_aborting = true;
}
processNextStep();
}
void COperationDialog::onDone()
{
processNextStep();
}
void COperationDialog::downloadData()
{
CConfigFile *config = CConfigFile::getInstance();
const CServer &server = config->getServer(m_currentServerId);
m_currentOperation = tr("Downloading data required by server %1...").arg(server.name);
m_downloader->prepareFile(config->expandVariables(server.dataDownloadUrl), config->getInstallationDirectory() + "/" + config->expandVariables(server.dataDownloadFilename) + ".part");
}
void COperationDialog::extractDownloadedData()
{
CConfigFile *config = CConfigFile::getInstance();
const CServer &server = config->getServer(m_currentServerId);
m_currentOperation = tr("Extracting data required by server %1...").arg(server.name);
QString dest = server.getDirectory();
#ifdef Q_OS_MAC
// under OS X, data should be uncompressed in Ryzom.app/Contents/Resources
dest += "/Ryzom.app/Contents/Resources";
#endif
CFilesExtractor extractor(this);
extractor.setSourceFile(config->getInstallationDirectory() + "/" + server.dataDownloadFilename);
extractor.setDestinationDirectory(dest);
if (extractor.exec())
{
}
else
{
}
emit done();
}
void COperationDialog::downloadClient()
{
CConfigFile *config = CConfigFile::getInstance();
const CServer &server = config->getServer(m_currentServerId);
m_currentOperation = tr("Downloading client required by server %1...").arg(server.name);
m_downloader->prepareFile(config->expandVariables(server.clientDownloadUrl), config->getInstallationDirectory() + "/" + config->expandVariables(server.clientDownloadFilename) + ".part");
}
void COperationDialog::extractDownloadedClient()
{
CConfigFile *config = CConfigFile::getInstance();
const CServer &server = config->getServer(m_currentServerId);
m_currentOperation = tr("Extracting client required by server %1...").arg(server.name);
QString destinationDirectory = server.getDirectory();
CFilesExtractor extractor(this);
extractor.setSourceFile(config->getInstallationDirectory() + "/" + config->expandVariables(server.clientDownloadFilename));
extractor.setDestinationDirectory(destinationDirectory);
if (extractor.exec())
{
}
else
{
}
launchUpgradeScript(destinationDirectory, server.clientFilename);
emit done();
}
void COperationDialog::copyDataFiles()
{
CConfigFile *config = CConfigFile::getInstance();
// default server
const CServer &server = config->getServer(m_currentServerId);
m_currentOperation = tr("Copying data required by server %1...").arg(server.name);
QStringList serverFiles;
serverFiles << "cfg";
serverFiles << "data";
serverFiles << "examples";
serverFiles << "patch";
serverFiles << "unpack";
CFilesCopier copier(this);
copier.setSourceDirectory(config->getSrcServerDirectory());
copier.setDestinationDirectory(server.getDirectory());
copier.setIncludeFilter(serverFiles);
if (copier.exec())
{
}
else
{
}
emit done();
}
void COperationDialog::copyProfileFiles()
{
CConfigFile *config = CConfigFile::getInstance();
// default server
const CServer &server = config->getServer();
// default profile
const CProfile &profile = config->getProfile();
m_currentOperation = tr("Copying old profile to new location...");
QStringList profileFiles;
profileFiles << "cache";
profileFiles << "save";
profileFiles << "user";
profileFiles << "screenshots";
profileFiles << "client.cfg";
profileFiles << "*.log";
CFilesCopier copier(this);
copier.setSourceDirectory(config->getSrcProfileDirectory());
copier.setDestinationDirectory(profile.getDirectory());
copier.setIncludeFilter(profileFiles);
if (copier.exec())
{
}
else
{
}
// correct path to client_default.cfg
profile.createClientConfig();
emit done();
}
void COperationDialog::extractBnpClient()
{
CConfigFile *config = CConfigFile::getInstance();
// default server
const CServer &server = config->getServer();
m_currentOperation = tr("Extracting client to new location...");
QString destinationDirectory = server.getDirectory();
CFilesExtractor extractor(this);
extractor.setSourceFile(config->getSrcServerClientBNPFullPath());
extractor.setDestinationDirectory(destinationDirectory);
extractor.exec();
launchUpgradeScript(destinationDirectory, server.clientFilename);
emit done();
}
void COperationDialog::launchUpgradeScript(const QString &directory, const QString &executable)
{
QString upgradeScript = directory + "/upgd_nl.";
#ifdef Q_OS_WIN
upgradeScript += "bat";
#else
upgradeScript += "sh";
#endif
if (QFile::exists(upgradeScript))
{
QProcess process;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert("RYZOM_CLIENT", QDir::toNativeSeparators(directory + "/" + executable));
env.insert("UNPACKPATH", QDir::toNativeSeparators(directory + "/unpack"));
env.insert("ROOTPATH", QDir::toNativeSeparators(directory));
env.insert("STARTUPPATH", "");
process.setProcessEnvironment(env);
// permissions to execute script
QFileDevice::Permissions permissions;
permissions |= QFileDevice::ExeOther;
permissions |= QFileDevice::ExeOwner;
permissions |= QFileDevice::ExeUser;
permissions |= QFileDevice::ReadOther;
permissions |= QFileDevice::ReadOwner;
permissions |= QFileDevice::ReadUser;
permissions |= QFileDevice::WriteOwner;
if (!QFile::setPermissions(upgradeScript, permissions))
{
qDebug() << "Unable to set executable flag to" << upgradeScript;
}
process.start(upgradeScript);
while (process.waitForFinished())
{
qDebug() << "waiting";
}
}
}
void COperationDialog::copyInstaller()
{
CConfigFile *config = CConfigFile::getInstance();
m_currentOperation = tr("Copying installer to new location...");
QString destinationDirectory = config->getInstallationDirectory();
// rename old client to installer
QString newInstallerFilename = config->getInstallerFilename();
if (!newInstallerFilename.isEmpty())
{
QString oldInstallerFullPath = QApplication::applicationFilePath();
QString newInstallerFullPath = config->getInstallationDirectory() + "/" + newInstallerFilename;
// always copy new installers
CFilesCopier copier(this);
copier.setIncludeFilter(config->getInstallerRequiredFiles());
copier.addFile(oldInstallerFullPath);
copier.setSourceDirectory(config->getSrcServerDirectory().isEmpty() ? QApplication::applicationDirPath():config->getSrcServerDirectory());
copier.setDestinationDirectory(config->getInstallationDirectory());
copier.exec();
// copied file
oldInstallerFullPath = config->getInstallationDirectory() + "/" + QFileInfo(oldInstallerFullPath).fileName();
// rename old filename if different
if (oldInstallerFullPath != newInstallerFullPath)
{
// delete previous installer
QFile::remove(newInstallerFullPath);
// rename new installer with final name
QFile::rename(oldInstallerFullPath, newInstallerFullPath);
}
// create menu directory if defined
QString path = config->getMenuDirectory();
if (!path.isEmpty() && !QDir().mkpath(path))
{
qDebug() << "Unable to create directory" << path;
}
// create installer link in menu
QString executable = newInstallerFullPath;
QString shortcut = config->getInstallerMenuShortcutFullPath();
QString name = "Ryzom Installer";
QString icon;
#ifdef Q_OS_WIN32
// under Windows, icon is included in executable
icon = executable;
#elif defined(Q_OS_MAC)
// everything is in bundle
#else
// icon is in the same directory as installer
icon = config->getInstallationDirectory() + "/ryzom_installer.png";
// create icon if not exists
if (!QFile::exists(icon) && !writeResource(":/icons/ryzom.png", icon))
{
qDebug() << "Unable to create" << icon;
}
#endif
createShortcut(shortcut, name, executable, "", icon, "");
}
emit done();
}
void COperationDialog::uninstallOldClient()
{
#ifdef Q_OS_WIN
#ifdef Q_OS_WIN64
// use WOW6432Node in 64 bits (64 bits OS and 64 bits Installer) because Ryzom old installer was in 32 bits
QSettings settings("HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Ryzom", QSettings::NativeFormat);
#else
QSettings settings("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Ryzom", QSettings::NativeFormat);
#endif
// check if Ryzom 2.1.0 is installed
if (settings.contains("UninstallString"))
{
QString uninstaller = settings.value("UninstallString").toString();
if (!uninstaller.isEmpty() && QFile::exists(uninstaller))
{
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?"));
if (button == QMessageBox::Yes)
{
// to not ask twice
CConfigFile::getInstance()->setUninstallingOldClient(true);
// remember the choice
CConfigFile::getInstance()->setShouldUninstallOldClient(true);
// launch old uninstaller
QDesktopServices::openUrl(QUrl::fromLocalFile(uninstaller));
}
else
{
// don't ask this question anymore
CConfigFile::getInstance()->setShouldUninstallOldClient(false);
}
// save the choice
CConfigFile::getInstance()->save();
}
}
#endif
emit done();
}
void COperationDialog::cleanFiles()
{
CConfigFile *config = CConfigFile::getInstance();
// default server
const CServer &server = config->getServer();
m_currentOperation = tr("Cleaning obsolete files...");
CFilesCleaner cleaner(this);
cleaner.setDirectory(server.getDirectory());
cleaner.exec();
emit done();
}
bool COperationDialog::createDefaultProfile()
{
CConfigFile *config = CConfigFile::getInstance();
CServer server = config->getServer();
m_currentOperation = tr("Creating default profile...");
CProfile profile;
profile.id = "0";
profile.name = QString("Ryzom (%1)").arg(server.name);
profile.server = server.id;
profile.comments = "Default profile created by Ryzom Installer";
profile.desktopShortcut = false;
profile.menuShortcut = false;
#ifdef Q_OS_WIN32
QStringList paths;
// desktop
// Windows XP
paths << "C:/Documents and Settings/All Users/Desktop";
// since Windows Vista
paths << "C:/Users/Public/Desktop";
// new location
paths << QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
foreach(const QString &path, paths)
{
if (QFile::exists(path + "/Ryzom.lnk")) profile.desktopShortcut = true;
}
paths.clear();
// start menu
// Windows XP
paths << "C:/Documents and Settings/All Users/Start Menu/Programs";
// since Windows Vista
paths << "C:/ProgramData/Microsoft/Windows/Start Menu/Programs";
// new location
paths << QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
foreach(const QString &path, paths)
{
if (QFile::exists(path + "/Ryzom/Ryzom.lnk")) profile.menuShortcut = true;
}
#endif
config->addProfile(profile);
config->save();
emit done();
return true;
}
bool COperationDialog::createProfileShortcuts(const QString &profileId)
{
CConfigFile *config = CConfigFile::getInstance();
const CProfile &profile = config->getProfile(profileId);
m_currentOperation = tr("Creating shortcuts for profile %1...").arg(profile.id);
profile.createShortcuts();
emit done();
return true;
}
bool COperationDialog::createAddRemoveEntry()
{
CConfigFile *config = CConfigFile::getInstance();
QString newInstallerFilename = config->getInstallerFilename();
if (!newInstallerFilename.isEmpty())
{
QString newInstallerFullPath = config->getInstallationDirectory() + "/" + newInstallerFilename;
if (QFile::exists(newInstallerFullPath))
{
#ifdef Q_OS_WIN
QSettings settings("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Ryzom", QSettings::NativeFormat);
QString nativeFullPath = QDir::toNativeSeparators(newInstallerFullPath);
settings.setValue("Comments", config->getProductComments());
settings.setValue("DisplayIcon", nativeFullPath + ",0");
settings.setValue("DisplayName", QApplication::applicationName());
settings.setValue("InstallDate", QDateTime::currentDateTime().toString("Ymd"));
settings.setValue("InstallLocation", config->getInstallationDirectory());
settings.setValue("NoModify", 0);
settings.setValue("NoRemove", 0);
settings.setValue("NoRepair", 0);
if (!config->getProductPublisher().isEmpty()) settings.setValue("Publisher", config->getProductPublisher());
settings.setValue("QuietUninstallString", nativeFullPath + " -u -s");
settings.setValue("UninstallString", nativeFullPath + " -u");
if (!config->getProductUpdateUrl().isEmpty()) settings.setValue("URLUpdateInfo", config->getProductUpdateUrl());
if (!config->getProductAboutUrl().isEmpty()) settings.setValue("URLInfoAbout", config->getProductAboutUrl());
if (!config->getProductHelpUrl().isEmpty()) settings.setValue("HelpLink", config->getProductHelpUrl());
// ModifyPath
#endif
}
}
updateAddRemoveEntry();
emit done();
return true;
}
bool COperationDialog::updateAddRemoveEntry()
{
CConfigFile *config = CConfigFile::getInstance();
QString newInstallerFilename = config->getInstallerFilename();
if (!newInstallerFilename.isEmpty())
{
QString newInstallerFullPath = config->getInstallationDirectory() + "/" + newInstallerFilename;
if (QFile::exists(newInstallerFullPath))
{
#ifdef Q_OS_WIN
QSettings settings("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Ryzom", QSettings::NativeFormat);
QString version = QApplication::applicationVersion();
settings.setValue("DisplayVersion", version);
settings.setValue("EstimatedSize", (quint32)(getDirectorySize(config->getInstallationDirectory(), true) / 1024)); // size if in KiB
QStringList versionTokens = version.split('.');
settings.setValue("MajorVersion", versionTokens[0].toInt());
settings.setValue("MinorVersion", versionTokens[1].toInt());
#endif
}
}
return true;
}
bool COperationDialog::deleteAddRemoveEntry()
{
#ifdef Q_OS_WIN
QSettings settings("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Ryzom", QSettings::NativeFormat);
settings.remove("");
#endif
return true;
}
void COperationDialog::deleteComponentsServers()
{
m_currentOperation = tr("Deleting client...");
emit prepare();
emit init(0, m_removeComponents.servers.size());
emit start();
CConfigFile *config = CConfigFile::getInstance();
int i = 0;
foreach(const QString &serverId, m_removeComponents.servers)
{
if (operationShouldStop())
{
emit stop();
return;
}
const CServer &server = config->getServer(serverId);
emit progress(i++, server.name);
QString path = server.getDirectory();
if (!path.isEmpty())
{
QDir dir(path);
if (dir.exists() && !dir.removeRecursively())
{
emit fail(tr("Unable to delete files for client %1").arg(server.name));
return;
}
}
// delete all links to clients
for (int i = 0; i < config->getProfilesCount(); ++i)
{
const CProfile &profile = config->getProfile(i);
if (profile.server == serverId)
{
profile.deleteShortcuts();
}
}
}
emit success(m_removeComponents.servers.size());
// clear list of all servers to uninstall
m_removeComponents.servers.clear();
// delete Ryzom directory if all files have been deleted
if (isDirectoryEmpty(config->getInstallationDirectory(), true)) QDir(config->getInstallationDirectory()).removeRecursively();
emit done();
}
void COperationDialog::addComponentsProfiles()
{
m_currentOperation = tr("Adding profiles...");
CConfigFile *config = CConfigFile::getInstance();
foreach(const QString &profileId, m_addComponents.profiles)
{
const CProfile &profile = config->getProfile(profileId);
profile.createShortcuts();
profile.createClientConfig();
}
// clear list of all servers to uninstall
m_addComponents.profiles.clear();
emit done();
}
void COperationDialog::deleteComponentsProfiles()
{
m_currentOperation = tr("Deleting profiles...");
emit prepare();
emit init(0, m_removeComponents.servers.size());
CConfigFile *config = CConfigFile::getInstance();
int i = 0;
foreach(const QString &profileId, m_removeComponents.profiles)
{
if (operationShouldStop())
{
emit stop();
return;
}
const CProfile &profile = config->getProfile(profileId);
emit progress(i++, profile.name);
QString path = profile.getDirectory();
if (!path.isEmpty())
{
QDir dir(path);
if (dir.exists() && !dir.removeRecursively())
{
emit fail(tr("Unable to delete files for profile %1").arg(profile.name));
return;
}
}
profile.deleteShortcuts();
// delete profile
config->removeProfile(profileId);
}
emit success(m_removeComponents.profiles.size());
// clear list of all profiles to uninstall
m_removeComponents.profiles.clear();
// delete profiles directory if all files have been deleted
if (isDirectoryEmpty(config->getProfileDirectory(), true)) QDir(config->getProfileDirectory()).removeRecursively();
emit done();
}
void COperationDialog::deleteComponentsInstaller()
{
m_currentOperation = tr("Deleting installer...");
CConfigFile *config = CConfigFile::getInstance();
deleteAddRemoveEntry();
// delete menu
QString path = config->getMenuDirectory();
if (!path.isEmpty())
{
QDir dir(path);
dir.removeRecursively();
}
path = config->getInstallerOriginalDirPath();
QStringList files = config->getInstallerRequiredFiles();
foreach(const QString &file, files)
{
QString fullPath = path + "/" + file;
// delete file
if (QFile::exists(fullPath) && !QFile::remove(fullPath))
{
#ifdef Q_OS_WIN32
// under Windows, a running executable is locked, so we need to delete it later
MoveFileExW(qToWide(QDir::toNativeSeparators(fullPath)), NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
#endif
}
}
// delete installer shortcuts
removeShortcut(config->getInstallerMenuShortcutFullPath());
removeShortcut(config->getInstallerDesktopShortcutFullPath());
// delete configuration file
config->remove();
// reset it once it's done
m_removeComponents.installer = false;
// delete Ryzom directory if all files have been deleted
if (isDirectoryEmpty(config->getInstallationDirectory(), true)) QDir(config->getInstallationDirectory()).removeRecursively();
emit success(1);
emit done();
}
void COperationDialog::deleteComponentsDownloadedFiles()
{
m_currentOperation = tr("Deleting downloaded files...");
CConfigFile *config = CConfigFile::getInstance();
QString path = config->getInstallationDirectory();
QDir dir(path);
QStringList filter;
filter << "*.log";
filter << "*.7z";
filter << "*.bnp";
filter << "*.zip";
filter << "*.part";
filter << "ryzom_installer_uninstalling_old_client";
QStringList files = dir.entryList(filter, QDir::Files);
foreach(const QString &file, files)
{
if (!QFile::remove(dir.filePath(file)))
{
qDebug() << "Unable to delete" << file;
}
}
// reset it once it's done
m_removeComponents.downloadedFiles = false;
// delete Ryzom directory if all files have been deleted
if (isDirectoryEmpty(config->getInstallationDirectory(), true)) QDir(config->getInstallationDirectory()).removeRecursively();
emit success(1);
emit done();
}
void COperationDialog::operationPrepare()
{
emit prepare();
}
void COperationDialog::operationInit(qint64 current, qint64 total)
{
emit init(current, total);
}
void COperationDialog::operationStart()
{
emit start();
}
void COperationDialog::operationStop()
{
emit stop();
}
void COperationDialog::operationProgress(qint64 current, const QString &filename)
{
emit progress(current, filename);
}
void COperationDialog::operationSuccess(qint64 total)
{
emit success(total);
}
void COperationDialog::operationFail(const QString &error)
{
emit fail(error);
}
bool COperationDialog::operationShouldStop()
{
QMutexLocker locker(&m_abortingMutex);
return m_aborting;
}
void COperationDialog::renamePartFile()
{
QString partFile = m_downloader->getFileFullPath();
QString finalFile = partFile;
finalFile.remove(".part");
if (partFile != finalFile)
{
QFile::rename(partFile, finalFile);
}
}
void COperationDialog::acceptDelayed()
{
// wait 500ms before to call accept()
QTimer::singleShot(500, this, SLOT(accept()));
}
void COperationDialog::rejectDelayed()
{
// wait 500ms before to call reject()
QTimer::singleShot(500, this, SLOT(reject()));
}