Added: Initial commit for Ryzom Installer (WIP)

This commit is contained in:
kervala 2016-02-25 21:19:27 +01:00
parent 4345f54db7
commit d874429b7c
34 changed files with 5900 additions and 0 deletions

View file

@ -3,6 +3,7 @@ IF(WITH_RYZOM_CLIENT)
IF(WITH_QT OR WITH_QT5)
ADD_SUBDIRECTORY(client_config_qt)
ADD_SUBDIRECTORY(ryzom_installer)
ENDIF()
ENDIF()

View file

@ -0,0 +1,51 @@
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR} ${NEL_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/ryzom/client/src/seven_zip ${ZLIB_INCLUDE_DIR})
FILE(GLOB SRC src/*.cpp src/*.h res/*.rc)
FILE(GLOB CLIENT_INSTALL_HDR src/*.h)
FILE(GLOB CLIENT_INSTALL_UIS ui/*.ui)
FILE(GLOB CLIENT_INSTALL_TRANS translations/*.ts)
FILE(GLOB CLIENT_INSTALL_RCS res/*.qrc)
#CONFIGURE_FILE(translations/translations.qrc ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc COPYONLY)
#SET(CLIENT_INSTALL_RCS resources.qrc ${CMAKE_CURRENT_BINARY_DIR}/translations.qrc)
IF(WITH_QT)
INCLUDE_DIRECTORIES(${QT_INCLUDES})
INCLUDE(${QT_USE_FILE})
QT4_ADD_TRANSLATION(CLIENT_INSTALL_QM ${CLIENT_INSTALL_TRANS})
QT4_ADD_RESOURCES(CLIENT_INSTALL_RC_SRCS ${CLIENT_INSTALL_RCS})
QT4_WRAP_CPP(CLIENT_INSTALL_MOC_SRC ${CLIENT_INSTALL_HDR})
QT4_WRAP_UI(CLIENT_INSTALL_UI_HDRS ${CLIENT_INSTALL_UIS})
ADD_DEFINITIONS(${QT_DEFINITIONS})
ELSE()
IF(WIN32)
FIND_PACKAGE(Qt5WinExtras)
SET(QT_LIBRARIES Qt5::WinExtras ${QT_LIBRARIES})
ENDIF()
QT5_ADD_TRANSLATION(CLIENT_INSTALL_QM ${CLIENT_INSTALL_TRANS})
QT5_ADD_RESOURCES(CLIENT_INSTALL_RC_SRCS ${CLIENT_INSTALL_RCS})
QT5_WRAP_CPP(CLIENT_INSTALL_MOC_SRC ${CLIENT_INSTALL_HDR})
QT5_WRAP_UI(CLIENT_INSTALL_UI_HDRS ${CLIENT_INSTALL_UIS})
ENDIF()
SOURCE_GROUP("Source" FILES ${SRC})
SOURCE_GROUP("Resources" FILES ${CLIENT_INSTALL_RCS})
SOURCE_GROUP("Forms" FILES ${CLIENT_INSTALL_UIS})
SOURCE_GROUP("Generated Files" FILES ${CLIENT_INSTALL_UI_HDRS} ${CLIENT_INSTALL_MOC_SRC} ${CLIENT_INSTALL_RC_SRCS})
SOURCE_GROUP("Translation Files" FILES ${CLIENT_INSTALL_TRANS})
ADD_EXECUTABLE(ryzom_installer_qt WIN32 ${SRC} ${CLIENT_INSTALL_MOC_SRC} ${CLIENT_INSTALL_UI_HDRS} ${CLIENT_INSTALL_RC_SRCS} ${CLIENT_INSTALL_TRANS} ${CLIENT_INSTALL_QM})
NL_DEFAULT_PROPS(ryzom_installer_qt "Ryzom, Tools: Ryzom Installer" )
NL_ADD_RUNTIME_FLAGS(ryzom_installer_qt)
NL_ADD_LIB_SUFFIX(ryzom_installer_qt)
TARGET_LINK_LIBRARIES(ryzom_installer_qt nelmisc ryzom_sevenzip ${QT_LIBRARIES})
IF(WITH_PCH)
ADD_NATIVE_PRECOMPILED_HEADER(ryzom_installer_qt ${CMAKE_CURRENT_SOURCE_DIR}/src/stdpch.h ${CMAKE_CURRENT_SOURCE_DIR}/src/stdpch.cpp)
ENDIF()
INSTALL(TARGETS ryzom_installer_qt RUNTIME DESTINATION ${RYZOM_GAMES_PREFIX} COMPONENT client)

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

View file

@ -0,0 +1,8 @@
<RCC>
<qresource prefix="/images">
<file>background.png</file>
</qresource>
<qresource prefix="/icons">
<file>ryzom.ico</file>
</qresource>
</RCC>

View file

@ -0,0 +1,39 @@
#include <windows.h>
#include "config.h"
IDI_MAIN_ICON ICON DISCARDABLE "ryzom.ico"
VS_VERSION_INFO VERSIONINFO
FILEVERSION RYZOM_VERSION_RC
PRODUCTVERSION NL_VERSION_RC
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "FileDescription", "Ryzom Installer"
VALUE "FileVersion", RYZOM_VERSION
VALUE "LegalCopyright", COPYRIGHT
#ifdef _DEBUG
VALUE "OriginalFilename", "ryzom_installer_d.exe"
#else
VALUE "OriginalFilename", "ryzom_installer_r.exe"
#endif
VALUE "ProductName", "Ryzom Core"
VALUE "ProductVersion", NL_VERSION
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

View file

@ -0,0 +1,785 @@
// 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 "archive.h"
#include "utils.h"
#include "nel/misc/big_file.h"
#include "nel/misc/callback.h"
#include "nel/misc/file.h"
#include "nel/misc/path.h"
#include "7z.h"
#include "7zAlloc.h"
#include "7zBuf.h"
#include "7zCrc.h"
#include "qzipreader.h"
#include <sys/stat.h>
#include <Windows.h>
#define FILE_ATTRIBUTE_READONLY 1
#define FILE_ATTRIBUTE_HIDDEN 2
#define FILE_ATTRIBUTE_SYSTEM 4
#define FILE_ATTRIBUTE_DIRECTORY 16
#define FILE_ATTRIBUTE_ARCHIVE 32
#define FILE_ATTRIBUTE_DEVICE 64
#define FILE_ATTRIBUTE_NORMAL 128
#define FILE_ATTRIBUTE_TEMPORARY 256
#define FILE_ATTRIBUTE_SPARSE_FILE 512
#define FILE_ATTRIBUTE_REPARSE_POINT 1024
#define FILE_ATTRIBUTE_COMPRESSED 2048
#define FILE_ATTRIBUTE_OFFLINE 0x1000
#define FILE_ATTRIBUTE_ENCRYPTED 0x4000
#define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000 /* trick for Unix */
bool Set7zFileAttrib(const QString &filename, uint32 fileAttributes)
{
bool attrReadOnly = (fileAttributes & FILE_ATTRIBUTE_READONLY != 0);
bool attrHidden = (fileAttributes & FILE_ATTRIBUTE_HIDDEN != 0);
bool attrSystem = (fileAttributes & FILE_ATTRIBUTE_SYSTEM != 0);
bool attrDir = (fileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0);
bool attrArchive = (fileAttributes & FILE_ATTRIBUTE_ARCHIVE != 0);
bool attrDevice = (fileAttributes & FILE_ATTRIBUTE_DEVICE != 0);
bool attrNormal = (fileAttributes & FILE_ATTRIBUTE_NORMAL != 0);
bool attrTemp = (fileAttributes & FILE_ATTRIBUTE_TEMPORARY != 0);
bool attrSparceFile = (fileAttributes & FILE_ATTRIBUTE_SPARSE_FILE != 0);
bool attrReparsePoint = (fileAttributes & FILE_ATTRIBUTE_REPARSE_POINT != 0);
bool attrCompressed = (fileAttributes & FILE_ATTRIBUTE_COMPRESSED != 0);
bool attrOffline = (fileAttributes & FILE_ATTRIBUTE_OFFLINE != 0);
bool attrEncryoted = (fileAttributes & FILE_ATTRIBUTE_ENCRYPTED != 0);
bool attrUnix = (fileAttributes & FILE_ATTRIBUTE_UNIX_EXTENSION != 0);
qDebug() << "attribs" << QByteArray::fromRawData((const char*)&fileAttributes, 4).toHex();
#ifdef Q_OS_WIN
SetFileAttributesW((wchar_t*)filename.utf16(), fileAttributes);
// QFile::set
// QFileDevice::Permissions::
// attribs "2080ed81"
// QFile::setPermissions(destPath, QFileDevice::Permissions);
#else
const char * name = filename.toUtf8().constData();
struct stat stat_info;
if (lstat(name, &stat_info)!=0)
{
nlwarning("SetFileAttrib(%s,%d) : false-2-1", (const char *)name, fileAttributes);
return false;
}
if (fileAttributes & FILE_ATTRIBUTE_UNIX_EXTENSION)
{
stat_info.st_mode = fileAttributes >> 16;
if (S_ISLNK(stat_info.st_mode))
{
if (convert_to_symlink(name) != 0)
{
nlwarning("SetFileAttrib(%s,%d) : false-3",(const char *)name,fileAttributes);
return false;
}
}
else if (S_ISREG(stat_info.st_mode))
{
nlwarning("##DBG chmod-2(%s,%o)", (const char *)name, (unsigned)stat_info.st_mode & gbl_umask.mask);
chmod(name,stat_info.st_mode & gbl_umask.mask);
}
else if (S_ISDIR(stat_info.st_mode))
{
// user/7za must be able to create files in this directory
stat_info.st_mode |= (S_IRUSR | S_IWUSR | S_IXUSR);
nlwarning("##DBG chmod-3(%s,%o)", (const char *)name, (unsigned)stat_info.st_mode & gbl_umask.mask);
chmod(name,stat_info.st_mode & gbl_umask.mask);
}
}
else if (!S_ISLNK(stat_info.st_mode))
{
// do not use chmod on a link
// Only Windows Attributes
if( S_ISDIR(stat_info.st_mode))
{
// Remark : FILE_ATTRIBUTE_READONLY ignored for directory.
nlwarning("##DBG chmod-4(%s,%o)", (const char *)name, (unsigned)stat_info.st_mode & gbl_umask.mask);
chmod(name,stat_info.st_mode & gbl_umask.mask);
}
else
{
// octal!, clear write permission bits
if (fileAttributes & FILE_ATTRIBUTE_READONLY) stat_info.st_mode &= ~0222;
nlwarning("##DBG chmod-5(%s,%o)", (const char *)name, (unsigned)stat_info.st_mode & gbl_umask.mask);
chmod(name,stat_info.st_mode & gbl_umask.mask);
}
}
#endif
return true;
}
#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif
#define SZ_ERROR_INTERRUPTED 18
class Q7zFile : public ISeekInStream
{
QFile m_file;
public:
Q7zFile(const QString &filename):m_file(filename)
{
Read = readFunc;
Seek = seekFunc;
}
~Q7zFile()
{
}
bool open()
{
return m_file.open(QFile::ReadOnly);
}
// the read function called by 7zip to read data
static SRes readFunc(void *object, void *buffer, size_t *size)
{
Q7zFile *me = (Q7zFile*)object;
qint64 len = *size;
len = me->m_file.read((char*)buffer, len);
if (len == *size)
{
*size = len;
return SZ_OK;
}
else
{
return SZ_ERROR_READ;
}
}
// the seek function called by seven zip to seek inside stream
static SRes seekFunc(void *object, Int64 *pos, ESzSeek origin)
{
Q7zFile *me = (Q7zFile*)object;
qint64 newPos;
switch(origin)
{
case SZ_SEEK_SET: newPos = *pos; break;
case SZ_SEEK_CUR: newPos = me->m_file.pos() + *pos; break;
case SZ_SEEK_END: newPos = me->m_file.size() - *pos; break;
}
if (me->m_file.seek(newPos))
{
*pos = newPos;
return SZ_OK;
}
else
{
return SZ_ERROR_READ;
}
}
};
CArchive::CArchive(QObject *parent):QObject(parent), m_mustStop(false)
{
}
CArchive::~CArchive()
{
}
bool CArchive::extract(const QString &filename, const QString &dest)
{
m_filename = filename;
m_dest = dest;
QFile file(m_filename);
// open archive file to check format
if (!file.open(QFile::ReadOnly)) return false;
// read 2 first bytes
QByteArray header = file.read(2);
// close file
file.close();
// create destination directory
QDir dir;
dir.mkpath(dest);
QFuture<bool> future;
// compare to supported formats and call the appropriate decompressor
if (header == "7z")
{
future = QtConcurrent::run(this, &CArchive::extract7z);
}
else if (header == "PK")
{
future = QtConcurrent::run(this, &CArchive::extractZip);
}
else if (QFileInfo(filename).suffix().toLower() == "bnp")
{
future = QtConcurrent::run(this, &CArchive::extractBnp);
}
else
{
qDebug() << "Unsupported format";
return false;
}
return true;
}
void CArchive::getFilesList(const QString &srcDir, const QString &dstDir, const QStringList &filter, FilesToCopy &files)
{
QDir dir(srcDir);
QFileInfoList entries = dir.entryInfoList(filter);
foreach(const QFileInfo &entry, entries)
{
QString fullPath = entry.absoluteFilePath();
QString dstPath = dstDir + "/" + dir.relativeFilePath(fullPath);
if (entry.isDir())
{
QDir().mkpath(dstPath);
QDir subDir(fullPath);
QDirIterator it(subDir, QDirIterator::Subdirectories);
while (it.hasNext())
{
fullPath = it.next();
if (it.fileName().startsWith('.')) continue;
QFileInfo fileInfo = it.fileInfo();
dstPath = dstDir + "/" + dir.relativeFilePath(fullPath);
if (fileInfo.isDir())
{
QDir().mkpath(dstPath);
}
else
{
FileToCopy file;
file.filename = it.fileName();
file.src = it.filePath();
file.dst = dstPath;
file.size = it.fileInfo().size();
file.date = it.fileInfo().lastModified();
files << file;
}
}
}
else
{
FileToCopy file;
file.filename = entry.fileName();
file.src = entry.filePath();
file.dst = dstPath;
file.size = entry.size();
file.date = entry.lastModified();
files << file;
}
}
}
bool CArchive::copyServerFiles()
{
emit extractPrepare();
FilesToCopy files;
QStringList serverFiles;
serverFiles << "cfg";
serverFiles << "data";
serverFiles << "examples";
serverFiles << "patch";
serverFiles << "unpack";
serverFiles << "client_default.cfg";
CArchive::getFilesList(m_filename, m_dest, serverFiles, files);
return copyFiles(files);
}
bool CArchive::copyConfigurationFiles()
{
emit extractPrepare();
FilesToCopy files;
QStringList configFiles;
configFiles << "cache";
configFiles << "save";
configFiles << "user";
configFiles << "screenshots";
configFiles << "client.cfg";
configFiles << "*.log";
CArchive::getFilesList(m_filename, m_dest, configFiles, files);
return copyFiles(files);
}
bool CArchive::copyServerFiles(const QString &src, const QString &dst)
{
if (src.isEmpty() || dst.isEmpty()) return false;
m_filename = src;
m_dest = dst;
// create destination directory
QDir().mkpath(dst);
QFuture<bool> future = QtConcurrent::run(this, &CArchive::copyServerFiles);
return true;
}
bool CArchive::copyConfigurationFiles(const QString &src, const QString &dst)
{
if (src.isEmpty() || dst.isEmpty()) return false;
m_filename = src;
m_dest = dst;
// create destination directory
QDir().mkpath(dst);
QFuture<bool> future = QtConcurrent::run(this, &CArchive::copyConfigurationFiles);
return true;
}
bool CArchive::copyFiles(const FilesToCopy &files)
{
qint64 totalSize = 0;
foreach(const FileToCopy &file, files)
{
totalSize += file.size;
qDebug() << file.filename;
}
emit extractInit(0, totalSize);
emit extractStart();
qint64 processedSize = 0;
foreach(const FileToCopy &file, files)
{
if (mustStop())
{
emit extractStop();
return true;
}
emit extractProgress(processedSize, file.filename);
QFileInfo dstFileInfo(file.dst);
if (dstFileInfo.size() != file.size || dstFileInfo.lastModified() != file.date)
{
if (!QFile::copy(file.src, file.dst))
{
emit extractFail(tr("Unable to copy file %1").arg(file.src));
return false;
}
if (!NLMISC::CFile::setFileModificationDate(qToUtf8(file.dst), file.date.toTime_t()))
{
qDebug() << "Unable to change date";
}
}
processedSize += file.size;
}
emit extractSuccess(totalSize);
return true;
}
bool CArchive::extract7z()
{
Q7zFile inFile(m_filename);
if (!inFile.open())
{
emit extractFail(tr("Unable to open %1").arg(m_filename));
return false;
}
emit extractPrepare();
UInt16 *temp = NULL;
size_t tempSize = 0;
// register the files read handlers
CLookToRead lookStream;
lookStream.realStream = &inFile;
LookToRead_CreateVTable(&lookStream, False);
LookToRead_Init(&lookStream);
// init CRC table
CrcGenerateTable();
// init 7z
CSzArEx db;
SzArEx_Init(&db);
// register allocators
ISzAlloc allocImp;
allocImp.Alloc = SzAlloc;
allocImp.Free = SzFree;
ISzAlloc allocTempImp;
allocTempImp.Alloc = SzAllocTemp;
allocTempImp.Free = SzFreeTemp;
qint64 total = 0, totalUncompressed = 0;
QString error;
// open 7z acrhive
SRes res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp);
if (res == SZ_OK)
{
// process each file in archive
for (UInt32 i = 0; i < db.NumFiles; ++i)
{
bool isDir = SzArEx_IsDir(&db, i) != 0;
if (!isDir) total += SzArEx_GetFileSize(&db, i);
}
emit extractInit(0, total);
emit extractStart();
// variables used for decompression
UInt32 blockIndex = 0xFFFFFFFF;
Byte *outBuffer = NULL;
size_t outBufferSize = 0;
// process each file in archive
for (UInt32 i = 0; i < db.NumFiles; ++i)
{
if (mustStop())
{
res = SZ_ERROR_INTERRUPTED;
break;
}
size_t offset = 0;
size_t outSizeProcessed = 0;
bool isDir = SzArEx_IsDir(&db, i) != 0;
size_t len = SzArEx_GetFileNameUtf16(&db, i, NULL);
if (len > tempSize)
{
SzFree(NULL, temp);
tempSize = len;
temp = (UInt16 *)SzAlloc(NULL, tempSize * sizeof(temp[0]));
if (!temp)
{
res = SZ_ERROR_MEM;
break;
}
}
SzArEx_GetFileNameUtf16(&db, i, temp);
QString path = QString::fromUtf16(temp);
QString filename = QFileInfo(path).fileName();
if (!isDir)
{
emit extractProgress(totalUncompressed, filename);
res = SzArEx_Extract(&db, &lookStream.s, i, &blockIndex, &outBuffer, &outBufferSize,
&offset, &outSizeProcessed, &allocImp, &allocTempImp);
if (res != SZ_OK) break;
}
QString destPath = m_dest + '/' + path;
QDir dir;
if (isDir)
{
dir.mkpath(destPath);
continue;
}
dir.mkpath(QFileInfo(destPath).absolutePath());
QFile outFile(destPath);
if (!outFile.open(QFile::WriteOnly))
{
error = tr("Unable to open output file");
res = SZ_ERROR_FAIL;
break;
}
size_t processedSize = outFile.write((const char*)(outBuffer + offset), outSizeProcessed);
if (processedSize != outSizeProcessed)
{
error = tr("Unable to write output file");
res = SZ_ERROR_FAIL;
break;
}
outFile.close();
totalUncompressed += SzArEx_GetFileSize(&db, i);
emit extractProgress(totalUncompressed, filename);
if (SzBitWithVals_Check(&db.Attribs, i))
Set7zFileAttrib(destPath, db.Attribs.Vals[i]);
}
IAlloc_Free(&allocImp, outBuffer);
}
SzArEx_Free(&db, &allocImp);
SzFree(NULL, temp);
switch(res)
{
case SZ_OK:
emit extractSuccess(totalUncompressed);
return true;
case SZ_ERROR_INTERRUPTED:
emit extractStop();
return true;
case SZ_ERROR_UNSUPPORTED:
error = tr("7zip decoder doesn't support this archive");
break;
case SZ_ERROR_MEM:
error = tr("Unable to allocate memory");
break;
case SZ_ERROR_CRC:
error = tr("7zip decoder doesn't support this archive");
break;
case SZ_ERROR_FAIL:
// error already defined
break;
default:
error = tr("Error %1").arg(res);
}
emit extractFail(error);
return false;
}
bool CArchive::extractZip()
{
emit extractPrepare();
QZipReader reader(m_filename);
QDir baseDir(m_dest);
// create directories first
QList<QZipReader::FileInfo> allFiles = reader.fileInfoList();
qint64 totalSize = 0, currentSize = 0;
foreach (const QZipReader::FileInfo &fi, allFiles)
{
if (fi.isDir)
{
const QString absPath = m_dest + QDir::separator() + fi.filePath;
if (!baseDir.mkpath(fi.filePath))
{
emit extractFail(tr("Unable to create directory %1").arg(absPath));
return false;
}
if (!QFile::setPermissions(absPath, fi.permissions))
{
emit extractFail(tr("Unable to set permissions of %1").arg(absPath));
return false;
}
}
totalSize += fi.size;
}
emit extractInit(0, totalSize);
emit extractStart();
// client won't use symbolic links so don't process them
foreach (const QZipReader::FileInfo &fi, allFiles)
{
const QString absPath = m_dest + QDir::separator() + fi.filePath;
if (fi.isFile)
{
if (mustStop())
{
emit extractStop();
return true;
}
QFile f(absPath);
if (!f.open(QIODevice::WriteOnly))
{
emit extractFail(tr("Unable to open %1").arg(absPath));
return false;
}
currentSize += f.write(reader.fileData(fi.filePath));
f.setPermissions(fi.permissions);
f.close();
emit extractProgress(currentSize, QFileInfo(absPath).fileName());
}
}
emit extractSuccess(totalSize);
return true;
}
bool CArchive::progress(const std::string &filename, uint32 currentSize, uint32 totalSize)
{
if (mustStop())
{
emit extractStop();
return false;
}
if (currentSize == 0)
{
emit extractInit(0, (qint64)totalSize);
emit extractStart();
}
emit extractProgress((qint64)currentSize, qFromUtf8(filename));
if (currentSize == totalSize)
{
emit extractSuccess((qint64)totalSize);
}
return true;
}
bool CArchive::extractBnp()
{
QString error;
emit extractPrepare();
NLMISC::CBigFile::TUnpackProgressCallback cbMethod = NLMISC::CBigFile::TUnpackProgressCallback(this, &CArchive::progress);
try
{
if (NLMISC::CBigFile::unpack(qToUtf8(m_filename), qToUtf8(m_dest), &cbMethod))
{
return true;
}
if (mustStop())
{
// stopped
return true;
}
error.clear();
}
catch(const NLMISC::EDiskFullError &e)
{
error = tr("disk full");
}
catch(const NLMISC::EWriteError &e)
{
error = tr("unable to write %1").arg(qFromUtf8(e.Filename));
}
catch(const NLMISC::EReadError &e)
{
error = tr("unable to read %1").arg(qFromUtf8(e.Filename));
}
catch(const std::exception &e)
{
error = tr("failed (%1)").arg(qFromUtf8(e.what()));
}
emit extractFail(tr("Unable to unpack %1 to %2: %3").arg(m_filename).arg(m_dest).arg(error));
return false;
}
void CArchive::stop()
{
QMutexLocker locker(&m_mutex);
m_mustStop = true;
}
bool CArchive::mustStop()
{
QMutexLocker locker(&m_mutex);
return m_mustStop;
}

View file

@ -0,0 +1,96 @@
// 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/>.
#ifndef ARCHIVE_H
#define ARCHIVE_H
/**
* Files copy, decompression, extraction
*
* \author Cedric 'Kervala' OCHS
* \date 2016
*/
class CArchive : public QObject
{
Q_OBJECT
public:
CArchive(QObject *parent = NULL);
virtual ~CArchive();
bool extract(const QString &filename, const QString &dest);
bool copyServerFiles(const QString &src, const QString &dst);
bool copyConfigurationFiles(const QString &src, const QString &dst);
void stop();
bool mustStop();
signals:
// emitted when requesting real URL
void extractPrepare();
// emitted when we got the initial (local) and total (remote) size of file
void extractInit(qint64 current, qint64 total);
// emitted when we begin to download
void extractStart();
// emitted when the download stopped
void extractStop();
// emitted when extracting
void extractProgress(qint64 current, const QString &filename);
// emitted when the whole file is downloaded
void extractSuccess(qint64 total);
// emitted when an error occurs
void extractFail(const QString &error);
protected:
struct FileToCopy
{
QString filename;
QString src;
QString dst;
qint64 size;
QDateTime date;
};
typedef QList<FileToCopy> FilesToCopy;
bool extract7z();
bool extractZip();
bool extractBnp();
bool progress(const std::string &filename, uint32 currentFile, uint32 totalFiles);
bool copyServerFiles();
bool copyConfigurationFiles();
bool copyFiles(const FilesToCopy &files);
static void getFilesList(const QString &srcDir, const QString &dstDir, const QStringList &filter, FilesToCopy &files);
QString m_filename;
QString m_dest;
QMutex m_mutex;
bool m_mustStop;
};
#endif

View file

@ -0,0 +1,564 @@
// 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 "configfile.h"
#include "utils.h"
#include "nel/misc/path.h"
#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif
const CServer NoServer;
const CConfiguration NoConfiguration;
CConfigFile *CConfigFile::s_instance = NULL;
CConfigFile::CConfigFile(QObject *parent):QObject(parent), m_defaultServer(0), m_defaultConfiguration(0), m_use64BitsClient(false)
{
s_instance = this;
m_defaultConfigPath = QApplication::applicationDirPath() + "/installer.ini";
m_configPath = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + "/installer.ini";
}
CConfigFile::~CConfigFile()
{
s_instance = NULL;
}
bool CConfigFile::load()
{
return load(m_configPath) || load(m_defaultConfigPath);
}
bool CConfigFile::load(const QString &filename)
{
QSettings settings(filename, QSettings::IniFormat);
settings.beginGroup("common");
m_language = settings.value("language").toString();
m_srcDirectory = settings.value("source_directory").toString();
m_installationDirectory = settings.value("installation_directory").toString();
m_use64BitsClient = settings.value("use_64bits_client").toBool();
settings.endGroup();
settings.beginGroup("servers");
int serversCount = settings.value("size").toInt();
m_defaultServer = settings.value("default").toInt();
settings.endGroup();
m_servers.resize(serversCount);
for(int i = 0; i < serversCount; ++i)
{
CServer &server = m_servers[i];
settings.beginGroup(QString("server_%1").arg(i));
server.id = settings.value("id").toString();
server.name = settings.value("name").toString();
server.displayUrl = settings.value("display_url").toString();
server.dataDownloadUrl = settings.value("data_download_url").toString();
server.dataDownloadFilename = settings.value("data_download_filename").toString();
server.dataCompressedSize = settings.value("data_compressed_size").toULongLong();
server.dataUncompressedSize = settings.value("data_uncompressed_size").toULongLong();
server.clientDownloadUrl = settings.value("client_download_url").toString();
server.clientDownloadFilename = settings.value("client_download_filename").toString();
#if defined(Q_OS_WIN)
server.clientFilename = settings.value("client_filename_windows").toString();
#elif defined(Q_OS_MAC)
server.clientFilename = settings.value("client_filename_osx").toString();
#else
server.clientFilename = settings.value("client_filename_linux").toString();
#endif
server.comments = settings.value("comments").toString();
settings.endGroup();
}
settings.beginGroup("configurations");
int configurationsCounts = settings.value("size").toInt();
m_defaultConfiguration = settings.value("default").toInt();
settings.endGroup();
m_configurations.resize(configurationsCounts);
for(int i = 0; i < configurationsCounts; ++i)
{
CConfiguration &configuration = m_configurations[i];
settings.beginGroup(QString("configuration_%1").arg(i));
configuration.id = settings.value("id").toInt();
configuration.name = settings.value("name").toString();
configuration.account = settings.value("account").toString();
configuration.server = settings.value("server").toString();
configuration.executable = settings.value("executable").toString();
configuration.parameters = settings.value("parameters").toString();
configuration.comments = settings.value("comments").toString();
settings.endGroup();
}
return !m_servers.isEmpty();
}
bool CConfigFile::save() const
{
QSettings settings(m_configPath, QSettings::IniFormat);
settings.beginGroup("common");
settings.setValue("language", m_language);
settings.setValue("source_directory", m_srcDirectory);
settings.setValue("installation_directory", m_installationDirectory);
settings.setValue("use_64bits_client", m_use64BitsClient);
settings.endGroup();
settings.beginGroup("servers");
settings.setValue("size", m_servers.size());
settings.setValue("default", m_defaultServer);
settings.endGroup();
for(int i = 0; i < m_servers.size(); ++i)
{
const CServer &server = m_servers[i];
settings.beginGroup(QString("server_%1").arg(i));
settings.setValue("id", server.id);
settings.setValue("name", server.name);
settings.setValue("display_url", server.displayUrl);
settings.setValue("data_download_url", server.dataDownloadUrl);
settings.setValue("data_download_filename", server.dataDownloadFilename);
settings.setValue("data_compressed_size", server.dataCompressedSize);
settings.setValue("data_uncompressed_size", server.dataUncompressedSize);
settings.setValue("client_download_url", server.clientDownloadUrl);
settings.setValue("client_download_filename", server.clientDownloadFilename);
#if defined(Q_OS_WIN)
settings.setValue("client_filename_windows", server.clientFilename);
#elif defined(Q_OS_MAC)
settings.setValue("client_filename_osx", server.clientFilename);
#else
settings.setValue("client_filename_linux", server.clientFilename);
#endif
settings.setValue("comments", server.comments);
settings.endGroup();
}
settings.beginGroup("configurations");
settings.setValue("size", m_configurations.size());
settings.setValue("default", m_defaultConfiguration);
settings.endGroup();
for(int i = 0; i < m_configurations.size(); ++i)
{
const CConfiguration &configuration = m_configurations[i];
settings.beginGroup(QString("configuration_%1").arg(i));
settings.setValue("id", configuration.id);
settings.setValue("name", configuration.name);
settings.setValue("account", configuration.account);
settings.setValue("server", configuration.server);
settings.setValue("executable", configuration.executable);
settings.setValue("parameters", configuration.parameters);
settings.setValue("comments", configuration.comments);
settings.endGroup();
}
return true;
}
CConfigFile* CConfigFile::getInstance()
{
return s_instance;
}
int CConfigFile::getServersCount() const
{
return m_servers.size();
}
const CServer& CConfigFile::getServer(int i) const
{
if (i < 0) i = m_defaultServer;
if (i >= m_servers.size()) return NoServer;
return m_servers.at(i);
}
const CServer& CConfigFile::getServer(const QString &id) const
{
for(int i = 0; i < m_servers.size(); ++i)
{
if (m_servers[i].id == id) return m_servers[i];
}
// default server
return getServer();
}
int CConfigFile::getConfigurationsCount() const
{
return m_configurations.size();
}
CConfiguration CConfigFile::getConfiguration(int i) const
{
if (i < 0) i = m_defaultConfiguration;
if (i >= m_configurations.size()) return NoConfiguration;
return m_configurations.at(i);
}
void CConfigFile::setConfiguration(int i, const CConfiguration &configuration)
{
m_configurations[i] = configuration;
}
int CConfigFile::addConfiguration(const CConfiguration &configuration)
{
m_configurations.append(configuration);
return m_configurations.size()-1;
}
void CConfigFile::removeConfiguration(int i)
{
m_configurations.removeAt(i);
// TODO: decalle all configurations and move files
}
bool CConfigFile::has64bitsOS()
{
return QSysInfo::currentCpuArchitecture() == "x86_64";
}
int CConfigFile::getDefaultConfiguration() const
{
return m_defaultConfiguration;
}
int CConfigFile::getDefaultServer() const
{
return m_defaultServer;
}
bool CConfigFile::isRyzomInstallerConfigured() const
{
return m_configurations.size() > 0;
}
QString CConfigFile::getInstallationDirectory() const
{
return m_installationDirectory;
}
void CConfigFile::setInstallationDirectory(const QString &directory)
{
m_installationDirectory = directory;
}
QString CConfigFile::getSrcServerDirectory() const
{
return m_srcDirectory;
}
void CConfigFile::setSrcServerDirectory(const QString &directory)
{
m_srcDirectory = directory;
}
QString CConfigFile::getConfigurationDirectory() const
{
return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
}
QString CConfigFile::getSrcConfigurationDirectory() const
{
if (QFile::exists(getSrcServerDirectory() + "/client.cfg")) return getSrcServerDirectory();
return qFromUtf8(NLMISC::CPath::getApplicationDirectory("Ryzom"));
}
bool CConfigFile::use64BitsClient() const
{
return m_use64BitsClient;
}
void CConfigFile::setUse64BitsClient(bool on)
{
m_use64BitsClient = on;
}
QString CConfigFile::expandVariables(const QString &str)
{
QString res = str;
res.replace("$TIMESTAMP", QString::number(QDateTime::currentDateTime().toTime_t()));
res.replace("$LANG", m_language);
res.replace("$ARCH", getClientArch());
return res;
}
QString CConfigFile::getClientArch() const
{
#if defined(Q_OS_WIN)
return QString("win%1").arg(m_use64BitsClient ? 64:32);
#elif defined(Q_OS_MAC)
// only 64 bits clients under OS X, becure there not any 32 bits OS X version anymore
return "osx";
#else
return QString("linux%1").arg(m_use64BitsClient ? 64:32);
#endif
}
QString CConfigFile::getCurrentDirectory()
{
return QDir::current().absolutePath();
}
QString CConfigFile::getParentDirectory()
{
QDir current = QDir::current();
current.cdUp();
return current.absolutePath();
}
QString CConfigFile::getApplicationDirectory()
{
return QApplication::applicationDirPath();
}
QString CConfigFile::getOldInstallationDirectory()
{
// HKEY_CURRENT_USER/SOFTWARE/Nevrax/RyzomInstall/InstallId=1917716796 (string)
#if defined(Q_OS_WIN)
// NSIS previous official installer
#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\\Nevrax\\Ryzom", QSettings::NativeFormat);
#else
QSettings settings("HKEY_LOCAL_MACHINE\\Software\\Nevrax\\Ryzom", QSettings::NativeFormat);
#endif
if (settings.contains("Ryzom Install Path"))
{
return QDir::fromNativeSeparators(settings.value("Ryzom Install Path").toString());
}
// check default directory if registry key not found
return CConfigFile::has64bitsOS() ? "C:/Program Files (x86)/Ryzom":"C:/Program Files/Ryzom";
#elif defined(Q_OS_MAC)
return "/Applications/Ryzom.app";
#else
return QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.ryzom";
#endif
}
QString CConfigFile::getNewInstallationDirectory()
{
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
}
bool CConfigFile::isRyzomInstalledIn(const QString &directory) const
{
// check client and data
return isRyzomClientInstalledIn(directory) && areRyzomDataInstalledIn(directory);
}
bool CConfigFile::areRyzomDataInstalledIn(const QString &directory) const
{
QDir dir(directory);
// directory doesn't exist
if (!dir.exists()) return false;
if (!dir.cd("data") && dir.exists()) return false;
// at least 200 BNP in data directory
if (dir.entryList(QStringList() << "*.bnp", QDir::Files).size() < 200) return false;
// TODO: more checks
return true;
}
bool CConfigFile::isRyzomClientInstalledIn(const QString &directory) const
{
QDir dir(directory);
// directory doesn't exist
if (!dir.exists()) return false;
// client_default.cfg doesn't exist
if (!dir.exists("client_default.cfg")) return false;
if (!dir.exists(getServer().clientFilename)) return false;
// TODO: more checks
return true;
}
QString CConfigFile::getClientFullPath() const
{
QString path = getConfiguration().executable;
if (!path.isEmpty()) return path;
return getInstallationDirectory() + "/" + getServer().id + "/" + getServer().clientFilename;
}
QString CConfigFile::getSrcServerClientBNPFullPath() const
{
return QString("%1/unpack/exedll_%2.bnp").arg(getSrcServerDirectory()).arg(getClientArch());
}
CConfigFile::InstallationStep CConfigFile::getNextStep() const
{
// get last used configuration
const CConfiguration &configuration = getConfiguration();
// get server used by it or default server
CServer server = getServer(configuration.server);
// no or wrong configuration
if (server.id.isEmpty())
{
// get last used server
server = getServer();
}
// no or wrong server
if (server.id.isEmpty())
{
// get first server
server = getServer(0);
}
// no server defined, shouldn't happen
if (server.id.isEmpty())
{
return DisplayNoServerError;
}
// only show wizard if installation directory undefined
if (getInstallationDirectory().isEmpty())
{
return ShowWizard;
}
QString serverDirectory = getInstallationDirectory() + "/" + server.id;
if (getSrcServerDirectory().isEmpty())
{
// user decided to download files
// downloaded files are kept in server directory
QString dataFile = getInstallationDirectory() + "/" + server.dataDownloadFilename;
QString clientFile = getInstallationDirectory() + "/" + server.clientDownloadFilename;
// data are not copied
if (!areRyzomDataInstalledIn(serverDirectory))
{
// when file is not finished, it has .part extension
if (!QFile::exists(dataFile))
{
return DownloadData;
}
return ExtractDownloadedData;
}
if (!isRyzomClientInstalledIn(serverDirectory))
{
// when file is not finished, it has .part extension
if (!QFile::exists(clientFile))
{
return DownloadClient;
}
return ExtractDownloadedClient;
}
}
else
{
// user decided to copy files
// selected directory contains Ryzom files (shouldn't fail)
if (!areRyzomDataInstalledIn(getSrcServerDirectory()))
{
return ShowWizard;
}
// data are not copied
if (!areRyzomDataInstalledIn(serverDirectory))
{
return CopyServerFiles;
}
// client is not extracted from BNP
if (!isRyzomClientInstalledIn(serverDirectory))
{
if (QFile::exists(getSrcServerClientBNPFullPath()))
{
return ExtractBnpClient;
}
else
{
QString clientFile = getInstallationDirectory() + "/" + server.clientDownloadFilename;
// when file is not finished, it has .part extension
if (!QFile::exists(clientFile))
{
return DownloadClient;
}
return ExtractDownloadedClient;
}
}
}
// no default configuration
if (configuration.id < 0)
{
return CreateConfiguration;
}
// migration configuration
if (!getSrcServerDirectory().isEmpty() && QFile::exists(getSrcConfigurationDirectory() + "/client.cfg") && !QFile::exists(QString("%1/%2/client.cfg").arg(getConfigurationDirectory()).arg(configuration.name)))
{
return CopyConfigurationFiles;
}
if (!QFile::exists(QStandardPaths::writableLocation(QStandardPaths::DesktopLocation) + "/Ryzom.lnk"))
{
// TODO: check they point to getClientFullPath()
return CreateShortcuts;
}
return Done;
}

View file

@ -0,0 +1,166 @@
// 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/>.
#ifndef CONFIGFILE_H
#define CONFIGFILE_H
struct CServer
{
CServer()
{
dataCompressedSize = 0;
dataUncompressedSize = 0;
}
QString id;
QString name;
QString displayUrl;
QString dataDownloadUrl;
QString dataDownloadFilename;
qint64 dataCompressedSize;
qint64 dataUncompressedSize;
QString clientDownloadUrl;
QString clientDownloadFilename;
QString clientFilename;
QString comments;
};
extern const CServer NoServer;
struct CConfiguration
{
CConfiguration()
{
id = -1;
}
int id;
QString account;
QString name;
QString server;
QString executable;
QString parameters;
QString comments;
};
extern const CConfiguration NoConfiguration;
/**
* Config file management and other stuff related to location of files/directories.
*
* \author Cedric 'Kervala' OCHS
* \date 2016
*/
class CConfigFile : public QObject
{
Q_OBJECT
public:
enum InstallationStep
{
DisplayNoServerError,
ShowWizard,
DownloadData,
ExtractDownloadedData,
DownloadClient,
ExtractDownloadedClient,
CopyServerFiles,
CopyConfigurationFiles,
ExtractBnpClient,
CreateConfiguration,
CreateShortcuts,
Done
};
CConfigFile(QObject *parent = NULL);
virtual ~CConfigFile();
bool load();
bool load(const QString &filename);
bool save() const;
static CConfigFile* getInstance();
int getServersCount() const;
const CServer& getServer(int i = -1) const;
const CServer& getServer(const QString &id) const;
int getConfigurationsCount() const;
CConfiguration getConfiguration(int i = -1) const;
void setConfiguration(int i, const CConfiguration &configuration);
int addConfiguration(const CConfiguration &configuration);
void removeConfiguration(int i);
int getDefaultServer() const;
int getDefaultConfiguration() const;
bool isRyzomInstallerConfigured() const;
QString getInstallationDirectory() const;
void setInstallationDirectory(const QString &directory);
QString getSrcServerDirectory() const;
void setSrcServerDirectory(const QString &directory);
QString getConfigurationDirectory() const;
QString getSrcConfigurationDirectory() const;
static bool has64bitsOS();
// default directories
static QString getCurrentDirectory();
static QString getParentDirectory();
static QString getApplicationDirectory();
static QString getOldInstallationDirectory();
static QString getNewInstallationDirectory();
bool isRyzomInstalledIn(const QString &directory) const;
bool areRyzomDataInstalledIn(const QString &directory) const;
bool isRyzomClientInstalledIn(const QString &directory) const;
// installation choices
bool use64BitsClient() const;
void setUse64BitsClient(bool on);
QString expandVariables(const QString &str);
QString getClientArch() const;
QString getClientFullPath() const;
QString getSrcServerClientBNPFullPath() const;
InstallationStep getNextStep() const;
private:
int m_defaultServer;
int m_defaultConfiguration;
QVector<CServer> m_servers;
QVector<CConfiguration> m_configurations;
QString m_installationDirectory;
QString m_srcDirectory;
bool m_use64BitsClient;
QString m_language;
QString m_defaultConfigPath;
QString m_configPath;
static CConfigFile *s_instance;
};
#endif

View file

@ -0,0 +1,38 @@
// 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 "configurationsdialog.h"
#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif
CConfigurationsDialog::CConfigurationsDialog():QDialog()
{
setupUi(this);
}
CConfigurationsDialog::~CConfigurationsDialog()
{
}
void CConfigurationsDialog::accept()
{
// TODO: add save code
QDialog::accept();
}

View file

@ -0,0 +1,34 @@
// 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/>.
#ifndef CONFIGURATIONSDIALOG_H
#define CONFIGURATIONSDIALOG_H
#include "ui_configurations.h"
class CConfigurationsDialog : public QDialog, public Ui::ConfigurationsDialog
{
Q_OBJECT
public:
CConfigurationsDialog();
virtual ~CConfigurationsDialog();
private slots:
void accept();
};
#endif

View file

@ -0,0 +1,394 @@
// 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 "downloader.h"
#include "nel/misc/system_info.h"
#include "nel/misc/path.h"
#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif
CDownloader::CDownloader(QObject *parent):QObject(parent), m_manager(NULL), m_reply(NULL), m_timer(NULL),
m_offset(0), m_size(0), m_supportsAcceptRanges(false), m_supportsContentRange(false),
m_downloadAfterHead(false), m_aborted(false), m_file(NULL)
{
m_manager = new QNetworkAccessManager(this);
m_timer = new QTimer(this);
connect(m_timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
}
CDownloader::~CDownloader()
{
stopTimer();
closeFile();
}
bool CDownloader::getHtmlPageContent(const QString &url)
{
if (url.isEmpty()) return false;
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::UserAgentHeader, "Ryzom Installer/1.0");
QNetworkReply *reply = m_manager->get(request);
connect(reply, SIGNAL(finished()), SLOT(onHtmlPageFinished()));
return true;
}
bool CDownloader::prepareFile(const QString &url, const QString &fullPath)
{
if (url.isEmpty()) return false;
m_downloadAfterHead = false;
emit downloadPrepare();
m_fullPath = fullPath;
m_url = url;
getFileHead();
return true;
}
bool CDownloader::getFile()
{
if (m_fullPath.isEmpty() || m_url.isEmpty())
{
qDebug() << "You forget to call prepareFile before";
return false;
}
m_downloadAfterHead = true;
getFileHead();
return true;
}
bool CDownloader::stop()
{
if (!m_reply) return false;
m_reply->abort();
return true;
}
void CDownloader::startTimer()
{
stopTimer();
m_timer->setInterval(5000);
m_timer->setSingleShot(true);
m_timer->start();
}
void CDownloader::stopTimer()
{
if (m_timer->isActive()) m_timer->stop();
}
bool CDownloader::openFile()
{
closeFile();
m_file = new QFile(m_fullPath);
if (m_file->open(QFile::Append)) return true;
closeFile();
return false;
}
void CDownloader::closeFile()
{
if (m_file)
{
m_file->close();
delete m_file;
m_file = NULL;
}
}
void CDownloader::getFileHead()
{
if (m_supportsAcceptRanges)
{
QFileInfo fileInfo(m_fullPath);
if (fileInfo.exists())
{
m_offset = fileInfo.size();
}
else
{
m_offset = 0;
}
// continue if offset less than size
if (m_offset >= m_size)
{
if (checkDownloadedFile())
{
// file is already downloaded
emit downloadSuccess(m_size);
}
else
{
// or has wrong size
emit downloadFail(tr("File (%1B) is larger than expected (%2B)").arg(m_offset).arg(m_size));
}
return;
}
}
QNetworkRequest request(m_url);
request.setHeader(QNetworkRequest::UserAgentHeader, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:24.0) Gecko/20100101 Firefox/24.0");
if (m_supportsAcceptRanges)
{
request.setRawHeader("Range", QString("bytes=%1-").arg(m_offset).toLatin1());
}
m_reply = m_manager->head(request);
connect(m_reply, SIGNAL(finished()), SLOT(onHeadFinished()));
connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(onError(QNetworkReply::NetworkError)));
startTimer();
}
void CDownloader::downloadFile()
{
qint64 freeSpace = NLMISC::CSystemInfo::availableHDSpace(m_fullPath.toUtf8().constData());
if (freeSpace < m_size - m_offset)
{
// we have not enough free disk space to continue download
emit downloadFail(tr("You only have %1 bytes left on device, but %2 bytes are required.").arg(freeSpace).arg(m_size - m_offset));
return;
}
if (!openFile())
{
emit downloadFail(tr("Unable to write file"));
return;
}
QNetworkRequest request(m_url);
request.setHeader(QNetworkRequest::UserAgentHeader, "Opera/9.80 (Windows NT 6.2; Win64; x64) Presto/2.12.388 Version/12.17");
if (supportsResume())
{
request.setRawHeader("Range", QString("bytes=%1-%2").arg(m_offset).arg(m_size-1).toLatin1());
}
m_reply = m_manager->get(request);
connect(m_reply, SIGNAL(finished()), SLOT(onDownloadFinished()));
connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(onError(QNetworkReply::NetworkError)));
connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), SLOT(onDownloadProgress(qint64, qint64)));
connect(m_reply, SIGNAL(readyRead()), SLOT(onDownloadRead()));
emit downloadStart();
startTimer();
}
bool CDownloader::checkDownloadedFile()
{
QFileInfo file(m_fullPath);
return file.size() == m_size && file.lastModified().toUTC() == m_lastModified;
}
void CDownloader::onTimeout()
{
qDebug() << "Timeout";
emit downloadFail(tr("Timeout"));
}
void CDownloader::onHtmlPageFinished()
{
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QString html = QString::fromUtf8(reply->readAll());
reply->deleteLater();
emit htmlPageContent(html);
}
void CDownloader::onHeadFinished()
{
stopTimer();
int status = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QString redirection = m_reply->header(QNetworkRequest::LocationHeader).toString();
m_size = m_reply->header(QNetworkRequest::ContentLengthHeader).toInt();
m_lastModified = m_reply->header(QNetworkRequest::LastModifiedHeader).toDateTime().toUTC();
QString acceptRanges = QString::fromLatin1(m_reply->rawHeader("Accept-Ranges"));
QString contentRange = QString::fromLatin1(m_reply->rawHeader("Content-Range"));
m_reply->deleteLater();
m_reply = NULL;
// redirection
if (status == 302)
{
if (redirection.isEmpty())
{
emit downloadFail(tr("Redirection URL is not defined"));
return;
}
// redirection on another server, recheck resume
m_supportsAcceptRanges = false;
m_supportsContentRange = false;
m_referer = m_url;
// update real URL
m_url = redirection;
getFileHead();
return;
}
// we requested without range
else if (status == 200)
{
// update size
emit downloadInit(0, m_size);
if (!m_supportsAcceptRanges && acceptRanges == "bytes")
{
// server supports resume, part 1
m_supportsAcceptRanges = true;
// request range
getFileHead();
return;
}
// server doesn't support resume or
// we requested range, but server always returns 200
// download from the beginning
}
// we requested with a range
else if (status == 206)
{
// server supports resume
QRegExp regexp("^bytes ([0-9]+)-([0-9]+)/([0-9]+)$");
if (m_supportsAcceptRanges && regexp.exactMatch(contentRange))
{
m_supportsContentRange = true;
m_offset = regexp.cap(1).toLongLong();
// when resuming, Content-Length is the size of missing parts to download
m_size = regexp.cap(3).toLongLong();
// update offset and size
emit downloadInit(m_offset, m_size);
}
else
{
qDebug() << "Unable to parse";
}
}
// other status
else
{
emit downloadFail(tr("Wrong status code: %1").arg(status));
return;
}
if (m_downloadAfterHead)
{
if (checkDownloadedFile())
{
qDebug() << "same date and size";
}
else
{
downloadFile();
}
}
}
void CDownloader::onDownloadFinished()
{
m_reply->deleteLater();
m_reply = NULL;
closeFile();
if (m_aborted)
{
m_aborted = false;
emit downloadStop();
}
else
{
bool ok = NLMISC::CFile::setFileModificationDate(m_fullPath.toUtf8().constData(), m_lastModified.toTime_t());
emit downloadSuccess(m_size);
}
}
void CDownloader::onError(QNetworkReply::NetworkError error)
{
if (error == QNetworkReply::OperationCanceledError)
{
m_aborted = true;
}
else
{
emit downloadFail(tr("Network error: %1").arg(error));
}
}
void CDownloader::onDownloadProgress(qint64 current, qint64 total)
{
stopTimer();
emit downloadProgress(m_offset + current);
}
void CDownloader::onDownloadRead()
{
if (m_file) m_file->write(m_reply->readAll());
}

View file

@ -0,0 +1,110 @@
// 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/>.
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
/**
* Files downloader, please note that only one file can be downloaded at once.
*
* \author Cedric 'Kervala' OCHS
* \date 2016
*/
class CDownloader : public QObject
{
Q_OBJECT
public:
CDownloader(QObject *parent);
virtual ~CDownloader();
bool getHtmlPageContent(const QString &url);
bool prepareFile(const QString &url, const QString &fullPath);
bool getFile();
bool stop();
bool supportsResume() const { return m_supportsAcceptRanges && m_supportsContentRange; }
bool isDownloading() const { return m_file != NULL; }
signals:
// emitted when requesting real URL
void downloadPrepare();
// emitted when we got the initial (local) and total (remote) size of file
void downloadInit(qint64 current, qint64 total);
// emitted when we begin to download
void downloadStart();
// emitted when the download stopped
void downloadStop();
// emittd when downloading
void downloadProgress(qint64 current);
// emitted when the whole file is downloaded
void downloadSuccess(qint64 total);
// emitted when an error occurs
void downloadFail(const QString &error);
void htmlPageContent(const QString &html);
private slots:
void onTimeout();
void onHtmlPageFinished();
void onHeadFinished();
void onDownloadFinished();
void onError(QNetworkReply::NetworkError error);
void onDownloadProgress(qint64 current, qint64 total);
void onDownloadRead();
protected:
void startTimer();
void stopTimer();
bool openFile();
void closeFile();
void getFileHead();
void downloadFile();
bool checkDownloadedFile();
QNetworkAccessManager *m_manager;
QNetworkReply *m_reply;
QTimer *m_timer;
QString m_url;
QString m_referer;
QString m_fullPath;
qint64 m_offset;
qint64 m_size;
QDateTime m_lastModified;
bool m_supportsAcceptRanges;
bool m_supportsContentRange;
bool m_downloadAfterHead;
bool m_aborted;
QFile *m_file;
};
#endif

View file

@ -0,0 +1,108 @@
// 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 "mainwindow.h"
#include "configfile.h"
#include "wizarddialog.h"
#include "nel/misc/path.h"
#include "nel/misc/ucstring.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef QT_STATICPLUGIN
#include <QtPlugin>
#if defined(Q_OS_WIN32)
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)
#elif defined(Q_OS_MAC)
Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)
#elif defined(Q_OS_UNIX)
Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)
Q_IMPORT_PLUGIN(QXcbGlxIntegrationPlugin)
#endif
Q_IMPORT_PLUGIN(QICOPlugin)
#endif
#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif
int main(int argc, char *argv[])
{
#if defined(_MSC_VER) && defined(_DEBUG)
// _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
NLMISC::CApplicationContext appContext;
QApplication app(argc, argv);
QApplication::setApplicationName("Ryzom");
QApplication::setApplicationVersion(RYZOM_VERSION);
QApplication::setWindowIcon(QIcon(":/icons/ryzom.ico"));
QLocale locale = QLocale::system();
// load application translations
QTranslator localTranslator;
if (localTranslator.load(locale, "ryzom_installer", "_", "translations"))
{
QApplication::installTranslator(&localTranslator);
}
// load Qt default translations
QTranslator qtTranslator;
if (qtTranslator.load(locale, "qt", "_", "translations"))
{
QApplication::installTranslator(&qtTranslator);
}
// instanciate ConfigFile
CConfigFile config;
CConfigFile::InstallationStep step = config.load() ? config.getNextStep():CConfigFile::DisplayNoServerError;
if (step == CConfigFile::DisplayNoServerError)
{
// display error
return 1;
}
bool displayMainWindow = true;
if (step == CConfigFile::ShowWizard)
{
CWizardDialog dialog;
if (!dialog.exec()) displayMainWindow = false;
}
if (displayMainWindow)
{
CMainWindow mainWindow;
mainWindow.show();
return QApplication::exec();
}
return 0;
}

View file

@ -0,0 +1,389 @@
// 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 "mainwindow.h"
#include "downloader.h"
#include "archive.h"
#include "wizarddialog.h"
#include "configfile.h"
#include "config.h"
#include "seven_zip.h"
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
#include <QtWinExtras/QWinTaskbarProgress>
#include <QtWinExtras/QWinTaskbarButton>
#endif
#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif
CMainWindow::CMainWindow():QMainWindow(), m_archive(NULL), m_statusLabel(NULL)
{
setupUi(this);
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
m_button = new QWinTaskbarButton(this);
#endif
connect(resumeButton, SIGNAL(clicked()), SLOT(onResumeClicked()));
connect(stopButton, SIGNAL(clicked()), SLOT(onStopClicked()));
// downloader
m_downloader = new CDownloader(this);
connect(m_downloader, SIGNAL(downloadPrepare()), SLOT(onDownloadPrepare()));
connect(m_downloader, SIGNAL(downloadInit(qint64, qint64)), SLOT(onDownloadInit(qint64, qint64)));
connect(m_downloader, SIGNAL(downloadStart()), SLOT(onDownloadStart()));
connect(m_downloader, SIGNAL(downloadStop()), SLOT(onDownloadStop()));
connect(m_downloader, SIGNAL(downloadProgress(qint64)), SLOT(onDownloadProgress(qint64)));
connect(m_downloader, SIGNAL(downloadSuccess(qint64)), SLOT(onDownloadSuccess(qint64)));
connect(m_downloader, SIGNAL(downloadFail(QString)), SLOT(onDownloadFail(QString)));
connect(m_downloader, SIGNAL(htmlPageContent(QString)), SLOT(onHtmlPageContent(QString)));
// archive
m_archive = new CArchive(this);
connect(m_archive, SIGNAL(extractPrepare()), SLOT(onExtractPrepare()));
connect(m_archive, SIGNAL(extractInit(qint64, qint64)), SLOT(onExtractInit(qint64, qint64)));
connect(m_archive, SIGNAL(extractStart()), SLOT(onExtractStart()));
connect(m_archive, SIGNAL(extractStop()), SLOT(onExtractStop()));
connect(m_archive, SIGNAL(extractProgress(qint64, QString)), SLOT(onExtractProgress(qint64, QString)));
connect(m_archive, SIGNAL(extractSuccess(qint64)), SLOT(onExtractSuccess(qint64)));
connect(m_archive, SIGNAL(extractFail(QString)), SLOT(onExtractFail(QString)));
connect(actionAboutQt, SIGNAL(triggered()), SLOT(onAboutQt()));
connect(actionAbout, SIGNAL(triggered()), SLOT(onAbout()));
m_statusLabel = new QLabel();
statusBar()->addWidget(m_statusLabel);
// setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
// processNextStep();
m_archive->extract("d:/Ryzom/bonjourx.7z", "");
}
CMainWindow::~CMainWindow()
{
}
void CMainWindow::processNextStep()
{
CConfigFile *config = CConfigFile::getInstance();
// default server
const CServer &server = config->getServer();
// default configuration
const CConfiguration &configuration = config->getConfiguration();
switch(CConfigFile::getInstance()->getNextStep())
{
case CConfigFile::DisplayNoServerError:
break;
case CConfigFile::ShowWizard:
break;
case CConfigFile::DownloadData:
displayProgressBar();
m_downloader->prepareFile(config->expandVariables(server.dataDownloadUrl), config->getInstallationDirectory() + "/" + config->expandVariables(server.dataDownloadFilename) + ".part");
break;
case CConfigFile::ExtractDownloadedData:
displayProgressBar();
break;
case CConfigFile::DownloadClient:
displayProgressBar();
m_downloader->prepareFile(config->expandVariables(server.clientDownloadUrl), config->getInstallationDirectory() + "/" + config->expandVariables(server.clientDownloadFilename) + ".part");
break;
case CConfigFile::ExtractDownloadedClient:
displayProgressBar();
break;
case CConfigFile::CopyServerFiles:
displayProgressBar();
m_archive->copyServerFiles(config->getSrcServerDirectory(), config->getInstallationDirectory() + "/" + server.id);
break;
case CConfigFile::CopyConfigurationFiles:
displayProgressBar();
m_archive->copyConfigurationFiles(config->getSrcConfigurationDirectory(), config->getConfigurationDirectory() + "/0");
break;
case CConfigFile::ExtractBnpClient:
displayProgressBar();
m_archive->extract(config->getSrcServerClientBNPFullPath(), config->getInstallationDirectory() + "/" + server.id);
break;
case CConfigFile::CreateConfiguration:
displayProgressBar();
break;
case CConfigFile::CreateShortcuts:
displayProgressBar();
break;
default:
// cases already managed in main.cpp
displayConfigurationsChoices();
break;
}
m_downloader->getHtmlPageContent(config->expandVariables(server.displayUrl));
}
void CMainWindow::displayProgressBar()
{
downloadFrame->setVisible(true);
configurationFrame->setVisible(false);
resumeButton->setVisible(true);
stopButton->setVisible(false);
}
void CMainWindow::displayConfigurationsChoices()
{
downloadFrame->setVisible(false);
configurationFrame->setVisible(true);
}
void CMainWindow::showEvent(QShowEvent *e)
{
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
m_button->setWindow(windowHandle());
#endif
e->accept();
}
void CMainWindow::closeEvent(QCloseEvent *e)
{
hide();
e->accept();
}
void CMainWindow::onResumeClicked()
{
m_downloader->getFile();
}
void CMainWindow::onStopClicked()
{
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;
}
m_downloader->stop();
}
else
{
m_archive->stop();
}
}
void CMainWindow::onAbout()
{
QString br("<br>");
QMessageBox::about(this,
tr("About %1").arg("Ryzom Installer"),
QString("Ryzom Installer") + QApplication::applicationVersion() + br +
tr("Program to install, download and manage Ryzom configurations.") +
br+br+
tr("Author: %1").arg("Cedric 'Kervala' OCHS") + br +
tr("Copyright: %1").arg(COPYRIGHT) + br +
tr("Support: %1").arg("<a href=\"https://bitbucket.org/ryzom/ryzomcore/issues?status=new&status=open\">Ryzom Core on Bitbucket</a>"));
}
void CMainWindow::onAboutQt()
{
QMessageBox::aboutQt(this);
}
void CMainWindow::onDownloadPrepare()
{
progressBar->setFormat(tr("%p% (%v/%m KiB)"));
progressBar->setMinimum(0);
progressBar->setMaximum(0);
progressBar->setValue(0);
resumeButton->setVisible(false);
stopButton->setVisible(false);
}
void CMainWindow::onDownloadInit(qint64 current, qint64 total)
{
resumeButton->setVisible(true);
stopButton->setVisible(false);
progressBar->setMinimum(0);
progressBar->setMaximum(total / 1024);
progressBar->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 CMainWindow::onDownloadStart()
{
resumeButton->setVisible(false);
stopButton->setVisible(true);
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
m_button->progress()->show();
#endif
}
void CMainWindow::onDownloadStop()
{
resumeButton->setVisible(true);
stopButton->setVisible(false);
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
m_button->progress()->hide();
#endif
}
void CMainWindow::onDownloadProgress(qint64 current)
{
progressBar->setValue(current / 1024);
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
m_button->progress()->setValue(current / 1024);
#endif
}
void CMainWindow::onDownloadSuccess(qint64 total)
{
progressBar->setValue(total / 1024);
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
m_button->progress()->hide();
#endif
resumeButton->setVisible(false);
stopButton->setVisible(false);
}
void CMainWindow::onDownloadFail(const QString &error)
{
resumeButton->setVisible(true);
stopButton->setVisible(false);
}
void CMainWindow::onHtmlPageContent(const QString &html)
{
htmlTextEdit->setHtml(html);
}
void CMainWindow::onExtractPrepare()
{
progressBar->setFormat("%p%");
progressBar->setMinimum(0);
progressBar->setMaximum(0);
progressBar->setValue(0);
resumeButton->setVisible(false);
stopButton->setVisible(false);
}
void CMainWindow::onExtractInit(qint64 current, qint64 total)
{
resumeButton->setVisible(true);
stopButton->setVisible(false);
progressBar->setMinimum(0);
progressBar->setMaximum(total / 1024);
progressBar->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 CMainWindow::onExtractStart()
{
resumeButton->setVisible(false);
stopButton->setVisible(true);
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
m_button->progress()->show();
#endif
}
void CMainWindow::onExtractStop()
{
resumeButton->setVisible(true);
stopButton->setVisible(false);
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
m_button->progress()->hide();
#endif
}
void CMainWindow::onExtractProgress(qint64 current, const QString &filename)
{
m_statusLabel->setText(tr("Extracting %1...").arg(filename));
progressBar->setValue(current / 1024);
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
m_button->progress()->setValue(current / 1024);
#endif
}
void CMainWindow::onExtractSuccess(qint64 total)
{
m_statusLabel->setText(tr("Extraction done"));
progressBar->setValue(total / 1024);
#if defined(Q_OS_WIN32) && defined(QT_WINEXTRAS_LIB)
m_button->progress()->hide();
#endif
resumeButton->setVisible(false);
stopButton->setVisible(false);
processNextStep();
}
void CMainWindow::onExtractFail(const QString &error)
{
resumeButton->setVisible(true);
stopButton->setVisible(false);
}

View file

@ -0,0 +1,81 @@
// 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/>.
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "ui_mainwindow.h"
class QWinTaskbarButton;
class CDownloader;
class CArchive;
/**
* Main window
*
* \author Cedric 'Kervala' OCHS
* \date 2016
*/
class CMainWindow : public QMainWindow, public Ui::MainWindow
{
Q_OBJECT
public:
CMainWindow();
virtual ~CMainWindow();
public slots:
void onResumeClicked();
void onStopClicked();
void onAbout();
void onAboutQt();
void onDownloadPrepare();
void onDownloadInit(qint64 current, qint64 total);
void onDownloadStart();
void onDownloadStop();
void onDownloadProgress(qint64 current);
void onDownloadSuccess(qint64 total);
void onDownloadFail(const QString &error);
void onHtmlPageContent(const QString &html);
void onExtractPrepare();
void onExtractInit(qint64 current, qint64 total);
void onExtractStart();
void onExtractStop();
void onExtractProgress(qint64 current, const QString &filename);
void onExtractSuccess(qint64 total);
void onExtractFail(const QString &error);
protected:
void showEvent(QShowEvent *e);
void closeEvent(QCloseEvent *e);
void processNextStep();
void displayProgressBar();
void displayConfigurationsChoices();
QWinTaskbarButton *m_button;
CDownloader *m_downloader;
CArchive *m_archive;
QLabel *m_statusLabel;
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,117 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QZIPREADER_H
#define QZIPREADER_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of the QZipReader class. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
QT_BEGIN_NAMESPACE
class QZipReaderPrivate;
class QZipReader
{
public:
QZipReader(const QString &fileName, QIODevice::OpenMode mode = QIODevice::ReadOnly );
explicit QZipReader(QIODevice *device);
~QZipReader();
QIODevice* device() const;
bool isReadable() const;
bool exists() const;
struct FileInfo
{
FileInfo();
FileInfo(const FileInfo &other);
~FileInfo();
FileInfo &operator=(const FileInfo &other);
bool isValid() const;
QString filePath;
uint isDir : 1;
uint isFile : 1;
uint isSymLink : 1;
QFile::Permissions permissions;
uint crc32;
qint64 size;
QDateTime lastModified;
void *d;
};
QList<FileInfo> fileInfoList() const;
int count() const;
FileInfo entryInfoAt(int index) const;
QByteArray fileData(const QString &fileName) const;
bool extractAll(const QString &destinationDir) const;
enum Status {
NoError,
FileReadError,
FileOpenError,
FilePermissionsError,
FileError
};
Status status() const;
void close();
private:
QZipReaderPrivate *d;
Q_DISABLE_COPY(QZipReader)
};
QT_END_NAMESPACE
#endif // QZIPREADER_H

View file

@ -0,0 +1,114 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QZIPWRITER_H
#define QZIPWRITER_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of the QZipWriter class. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qstring.h>
#include <QtCore/qfile.h>
QT_BEGIN_NAMESPACE
class QZipWriterPrivate;
class QZipWriter
{
public:
QZipWriter(const QString &fileName, QIODevice::OpenMode mode = (QIODevice::WriteOnly | QIODevice::Truncate) );
explicit QZipWriter(QIODevice *device);
~QZipWriter();
QIODevice* device() const;
bool isWritable() const;
bool exists() const;
enum Status {
NoError,
FileWriteError,
FileOpenError,
FilePermissionsError,
FileError
};
Status status() const;
enum CompressionPolicy {
AlwaysCompress,
NeverCompress,
AutoCompress
};
void setCompressionPolicy(CompressionPolicy policy);
CompressionPolicy compressionPolicy() const;
void setCreationPermissions(QFile::Permissions permissions);
QFile::Permissions creationPermissions() const;
void addFile(const QString &fileName, const QByteArray &data);
void addFile(const QString &fileName, QIODevice *device);
void addDirectory(const QString &dirName);
void addSymLink(const QString &fileName, const QString &destination);
void close();
private:
QZipWriterPrivate *d;
Q_DISABLE_COPY(QZipWriter)
};
QT_END_NAMESPACE
#endif // QZIPWRITER_H

View file

@ -0,0 +1,38 @@
// 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 "settingsdialog.h"
#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif
CSettingsDialog::CSettingsDialog():QDialog()
{
setupUi(this);
}
CSettingsDialog::~CSettingsDialog()
{
}
void CSettingsDialog::accept()
{
// TODO: add save code
QDialog::accept();
}

View file

@ -0,0 +1,34 @@
// 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/>.
#ifndef SETTINGSDIALOG_H
#define SETTINGSDIALOG_H
#include "ui_settings.h"
class CSettingsDialog : public QDialog, public Ui::SettingsDialog
{
Q_OBJECT
public:
CSettingsDialog();
virtual ~CSettingsDialog();
private slots:
void accept();
};
#endif

View file

@ -0,0 +1,17 @@
// 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"

View file

@ -0,0 +1,65 @@
// 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/>.
#ifndef STDPCH_H
#define STDPCH_H
#if defined(_MSC_VER) && defined(_DEBUG)
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#undef realloc
#endif
#include <qt_windows.h>
#include <shlguid.h>
#include <winnls.h>
#include <shobjidl.h>
#include <objbase.h>
#include <objidl.h>
#include <strsafe.h>
#ifndef _DEBUG
#define QT_NO_DEBUG_OUTPUT
#endif
#include <qglobal.h>
#ifdef Q_COMPILER_RVALUE_REFS
#undef Q_COMPILER_RVALUE_REFS
#endif
#include <QtCore/QtCore>
#include <QtGui/QtGui>
#include <QtNetwork/QtNetwork>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
#define USE_QT5
#endif
#ifdef USE_QT5
#include <QtWidgets/QtWidgets>
#include <QtConcurrent/QtConcurrent>
#endif
#include <string>
#include <nel/misc/types_nl.h>
#include <nel/misc/config_file.h>
#endif

View file

@ -0,0 +1,182 @@
// 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 "utils.h"
QString qFromUtf8(const std::string &str)
{
return QString::fromUtf8(str.c_str());
}
std::string qToUtf8(const QString &str)
{
return str.toUtf8().constData();
}
QString qFromUtf16(const ucstring &str)
{
return QString::fromUtf16(str.c_str());
}
ucstring qToUtf16(const QString &str)
{
return ucstring::makeFromUtf8(qToUtf8(str));
}
QString qFromWide(const wchar_t *str)
{
return QString::fromUtf16((ushort*)str);
}
wchar_t* qToWide(const QString &str)
{
return (wchar_t*)str.utf16();
}
// CreateLink - Uses the Shell's IShellLink and IPersistFile interfaces
// to create and store a shortcut to the specified object.
//
// Returns the result of calling the member functions of the interfaces.
//
// Parameters:
// lpszPathObj - Address of a buffer that contains the path of the object,
// including the file name.
// lpszPathLink - Address of a buffer that contains the path where the
// Shell link is to be stored, including the file name.
// lpszDesc - Address of a buffer that contains a description of the
// Shell link, stored in the Comment field of the link
// properties.
HRESULT CreateLink(const QString &pathObj, const QString &pathLink, const QString &desc)
{
IShellLinkW* psl;
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Set the path to the shortcut target and add the description.
psl->SetPath(qToWide(pathObj));
psl->SetDescription(qToWide(desc));
psl->SetArguments(L"--profil ");
psl->SetWorkingDirectory(L"");
// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres))
{
// Add code here to check return value from MultiByteWideChar
// for success.
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(qToWide(pathLink), TRUE);
ppf->Release();
}
psl->Release();
}
return hres;
}
// ResolveIt - Uses the Shell's IShellLink and IPersistFile interfaces
// to retrieve the path and description from an existing shortcut.
//
// Returns the result of calling the member functions of the interfaces.
//
// Parameters:
// hwnd - A handle to the parent window. The Shell uses this window to
// display a dialog box if it needs to prompt the user for more
// information while resolving the link.
// lpszLinkFile - Address of a buffer that contains the path of the link,
// including the file name.
// lpszPath - Address of a buffer that receives the path of the link
// target, including the file name.
// lpszDesc - Address of a buffer that receives the description of the
// Shell link, stored in the Comment field of the link
// properties.
HRESULT ResolveIt(HWND hwnd, const QString &linkFile, QString &path)
{
IShellLinkW* psl;
WIN32_FIND_DATAW wfd;
path.clear(); // Assume failure
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Get a pointer to the IPersistFile interface.
hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf);
if (SUCCEEDED(hres))
{
// Add code here to check return value from MultiByteWideChar
// for success.
// Load the shortcut.
hres = ppf->Load(qToWide(linkFile), STGM_READ);
if (SUCCEEDED(hres))
{
// Resolve the link.
hres = psl->Resolve(hwnd, 0);
if (SUCCEEDED(hres))
{
WCHAR szGotPath[MAX_PATH];
// Get the path to the link target.
hres = psl->GetPath(szGotPath, MAX_PATH, (WIN32_FIND_DATAW*)&wfd, SLGP_SHORTPATH);
if (SUCCEEDED(hres))
{
WCHAR szDescription[MAX_PATH];
// Get the description of the target.
hres = psl->GetDescription(szDescription, MAX_PATH);
if (SUCCEEDED(hres))
{
// Handle success
path = qFromWide(szGotPath);
}
else
{
}
}
}
}
// Release the pointer to the IPersistFile interface.
ppf->Release();
}
// Release the pointer to the IShellLink interface.
psl->Release();
}
return hres;
}

View file

@ -0,0 +1,47 @@
// 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/>.
#ifndef UTILS_H
#define UTILS_H
#include <nel/misc/ucstring.h>
#include <string>
/**
* Utils functions
*
* \author Cedric 'Kervala' OCHS
* \date 2016
*/
// Convert a UTF-8 string to QString
QString qFromUtf8(const std::string &str);
// Convert a QString to UTF-8 string
std::string qToUtf8(const QString &str);
// Convert a UTF-16 string to QString
QString qFromUtf16(const ucstring &str);
// Convert a QString to UTF-16 string
ucstring qToUtf16(const QString &str);
QString qFromWide(const wchar_t *str);
wchar_t* qToWide(const QString &str);
#endif

View file

@ -0,0 +1,219 @@
// 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 "wizarddialog.h"
#include "configfile.h"
#include "nel/misc/system_info.h"
#include "nel/misc/common.h"
#ifdef DEBUG_NEW
#define new DEBUG_NEW
#endif
QString qBytesToHumanReadable(qint64 bytes)
{
static std::vector<std::string> units;
if (units.empty())
{
units.push_back(QObject::tr("B").toUtf8().constData());
units.push_back(QObject::tr("KiB").toUtf8().constData());
units.push_back(QObject::tr("MiB").toUtf8().constData());
units.push_back(QObject::tr("GiB").toUtf8().constData());
units.push_back(QObject::tr("TiB").toUtf8().constData());
units.push_back(QObject::tr("PiB").toUtf8().constData());
}
return QString::fromUtf8(NLMISC::bytesToHumanReadable(bytes).c_str());
}
CWizardDialog::CWizardDialog():QDialog()
{
setupUi(this);
currentDirectoryRadioButton->setVisible(false);
oldDirectoryRadioButton->setVisible(false);
// enable download radio button by default
internetRadioButton->setChecked(true);
// if launched from current directory, it means we just patched files
m_currentDirectory = CConfigFile::getInstance()->getCurrentDirectory();
if (!CConfigFile::getInstance()->isRyzomInstalledIn(m_currentDirectory))
{
// current directory is a child of Ryzom root directory
m_currentDirectory = CConfigFile::getInstance()->getParentDirectory();
if (!CConfigFile::getInstance()->isRyzomInstalledIn(m_currentDirectory))
{
// Ryzom is in the same directory as Ryzom Installer
m_currentDirectory = CConfigFile::getInstance()->getApplicationDirectory();
if (!CConfigFile::getInstance()->isRyzomInstalledIn(m_currentDirectory))
{
m_currentDirectory.clear();
}
}
}
// display found directory
if (!m_currentDirectory.isEmpty())
{
currentDirectoryRadioButton->setText(tr("Current directory: %1").arg(m_currentDirectory));
currentDirectoryRadioButton->setVisible(true);
currentDirectoryRadioButton->setChecked(true);
}
m_oldDirectory = CConfigFile::getInstance()->getOldInstallationDirectory();
// found a previous installation
if (CConfigFile::getInstance()->areRyzomDataInstalledIn(m_oldDirectory))
{
oldDirectoryRadioButton->setText(tr("Old installation: %1").arg(m_oldDirectory));
oldDirectoryRadioButton->setVisible(true);
if (m_currentDirectory.isEmpty()) oldDirectoryRadioButton->setChecked(true);
}
updateAnotherLocationText();
m_dstDirectory = CConfigFile::getNewInstallationDirectory();
updateDestinationText();
// check whether OS architecture is 32 or 64 bits
// TODO: 64 bits client only supported under Vista+
if (CConfigFile::has64bitsOS())
{
clientArchGroupBox->setVisible(true);
clientArch64RadioButton->setChecked(true);
}
else
{
clientArchGroupBox->setVisible(false);
clientArch32RadioButton->setChecked(true);
}
const CServer &server = CConfigFile::getInstance()->getServer();
internetRadioButton->setText(tr("Internet (%1 to download)").arg(qBytesToHumanReadable(server.dataCompressedSize)));
destinationGroupBox->setTitle(tr("Files will be installed to (requires %1):").arg(qBytesToHumanReadable(server.dataUncompressedSize)));
connect(anotherLocationBrowseButton, SIGNAL(clicked()), SLOT(onAnotherLocationBrowseButtonClicked()));
connect(destinationBrowseButton, SIGNAL(clicked()), SLOT(onDestinationBrowseButtonClicked()));
// TODO: if found a folder with initial data, get its total size and check if at least that size is free on the disk
// by default, advanced parameters are hidden
onShowAdvancedParameters(Qt::Unchecked);
connect(advancedCheckBox, SIGNAL(stateChanged(int)), SLOT(onShowAdvancedParameters(int)));
}
CWizardDialog::~CWizardDialog()
{
}
void CWizardDialog::onShowAdvancedParameters(int state)
{
advancedFrame->setVisible(state != Qt::Unchecked);
adjustSize();
}
void CWizardDialog::onAnotherLocationBrowseButtonClicked()
{
QString directory;
for(;;)
{
directory = QFileDialog::getExistingDirectory(this, tr("Please choose directory where is installed Ryzom"));
if (directory.isEmpty()) return;
if (CConfigFile::getInstance()->isRyzomInstalledIn(directory)) break;
QMessageBox::StandardButton res = QMessageBox::warning(this, tr("Unable to find Ryzom"), tr("Unable to find Ryzom in selected directory. Please choose another one or cancel."));
}
m_anotherDirectory = directory;
// if we browse to a Ryzom installation, we want to use it
anotherLocationRadioButton->setChecked(true);
updateAnotherLocationText();
}
void CWizardDialog::onDestinationBrowseButtonClicked()
{
QString directory = QFileDialog::getExistingDirectory(this, tr("Please choose directory where to install Ryzom"));
if (directory.isEmpty()) return;
m_dstDirectory = directory;
updateDestinationText();
}
void CWizardDialog::updateAnotherLocationText()
{
anotherLocationRadioButton->setText(tr("Another location: %1").arg(m_anotherDirectory.isEmpty() ? tr("Undefined"):m_anotherDirectory));
}
void CWizardDialog::updateDestinationText()
{
destinationLabel->setText(m_dstDirectory);
}
void CWizardDialog::accept()
{
// check free disk space
qint64 freeSpace = NLMISC::CSystemInfo::availableHDSpace(m_dstDirectory.toUtf8().constData());
const CServer &server = CConfigFile::getInstance()->getServer();
if (freeSpace < server.dataUncompressedSize)
{
QMessageBox::StandardButton res = QMessageBox::warning(this, tr("Not enough free disk space"), tr("You don't have enough free space on this disk, please make more space or choose a directory on another disk."));
return;
}
if (currentDirectoryRadioButton->isChecked())
{
CConfigFile::getInstance()->setSrcServerDirectory(m_currentDirectory);
}
else if (oldDirectoryRadioButton->isChecked())
{
CConfigFile::getInstance()->setSrcServerDirectory(m_oldDirectory);
}
else if (anotherLocationRadioButton->isChecked())
{
CConfigFile::getInstance()->setSrcServerDirectory(m_anotherDirectory);
}
else
{
CConfigFile::getInstance()->setSrcServerDirectory("");
}
CConfigFile::getInstance()->setInstallationDirectory(m_dstDirectory);
CConfigFile::getInstance()->setUse64BitsClient(clientArch64RadioButton->isChecked());
CConfigFile::getInstance()->save();
QDialog::accept();
}

View file

@ -0,0 +1,53 @@
// 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/>.
#ifndef WIZARDDIALOG_H
#define WIZARDDIALOG_H
#include "ui_wizard.h"
/**
* Wizard displayed at first launch, that asks user to choose source and destination directories.
*
* \author Cedric 'Kervala' OCHS
* \date 2016
*/
class CWizardDialog : public QDialog, public Ui::WizardDialog
{
Q_OBJECT
public:
CWizardDialog();
virtual ~CWizardDialog();
private slots:
void onShowAdvancedParameters(int state);
void onAnotherLocationBrowseButtonClicked();
void onDestinationBrowseButtonClicked();
void accept();
private:
void updateAnotherLocationText();
void updateDestinationText();
QString m_currentDirectory;
QString m_oldDirectory;
QString m_anotherDirectory;
QString m_dstDirectory;
};
#endif

View file

@ -0,0 +1,305 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConfigurationsDialog</class>
<widget class="QDialog" name="ConfigurationsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>501</width>
<height>351</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="mainLayout">
<item>
<layout class="QVBoxLayout" name="configurationsLayout" stretch="0,1,0">
<item>
<widget class="QLabel" name="configurationsLabel">
<property name="text">
<string>List of configurations:</string>
</property>
</widget>
</item>
<item>
<widget class="QListView" name="configurationsListView">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="configurationsActionsLayout" stretch="0,0">
<item>
<widget class="QPushButton" name="addButton">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="deleteButton">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="configurationLabel">
<property name="text">
<string>Configuration:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="configurationIdLabel">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="accountLabel">
<property name="text">
<string>Account:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="accountEdit"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="nameLabel">
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="nameEdit"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="serverLabel">
<property name="text">
<string>Server:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="serverComboBox">
<item>
<property name="text">
<string>Atys</string>
</property>
</item>
<item>
<property name="text">
<string>Yubo</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="executableLabel">
<property name="text">
<string>Executable:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<layout class="QHBoxLayout" name="executableLayout" stretch="1,0">
<item>
<widget class="QLabel" name="executablePathLabel">
<property name="text">
<string>ryzom_client_r.exe</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="executableBrowseButton">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0">
<widget class="QLabel" name="argumentsLabel">
<property name="text">
<string>Arguments:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="argumentsEdit"/>
</item>
<item row="7" column="0">
<widget class="QLabel" name="commentsLabel">
<property name="text">
<string>Comments:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QPlainTextEdit" name="commentsEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="directoryLabel">
<property name="text">
<string>Directory:</string>
</property>
</widget>
</item>
<item row="8" column="1">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
<item>
<widget class="QLabel" name="directoryPathLabel">
<property name="text">
<string>~/.ryzom/0</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="directoryButton">
<property name="text">
<string>Open</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="9" column="0">
<widget class="QLabel" name="shortcutsLabel">
<property name="text">
<string>Create shortcuts:</string>
</property>
</widget>
</item>
<item row="9" column="1">
<layout class="QHBoxLayout" name="shortcutsLayout">
<item>
<widget class="QPushButton" name="shortcutsDesktopButton">
<property name="text">
<string>Desktop</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="shortcutsMenuButton">
<property name="text">
<string>Start Menu</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="1">
<widget class="QLabel" name="clientVersionStringLabel">
<property name="text">
<string>FV 3.0.0</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="clientVersionLabel">
<property name="text">
<string>Client version:</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>configurationsListView</tabstop>
<tabstop>addButton</tabstop>
<tabstop>deleteButton</tabstop>
<tabstop>accountEdit</tabstop>
<tabstop>nameEdit</tabstop>
<tabstop>serverComboBox</tabstop>
<tabstop>executableBrowseButton</tabstop>
<tabstop>argumentsEdit</tabstop>
<tabstop>commentsEdit</tabstop>
<tabstop>directoryButton</tabstop>
<tabstop>shortcutsDesktopButton</tabstop>
<tabstop>shortcutsMenuButton</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ConfigurationsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ConfigurationsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -0,0 +1,212 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>627</width>
<height>539</height>
</rect>
</property>
<property name="windowTitle">
<string>Ryzom Installer</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="image">
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../res/resources.qrc">:/images/background.png</pixmap>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="htmlTextEdit">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QFrame" name="downloadFrame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="downloadLayout" stretch="1,0,0">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="maximum">
<number>0</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="format">
<string>%p%</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="resumeButton">
<property name="text">
<string>Resume</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="stopButton">
<property name="text">
<string>Stop</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="configurationFrame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="configurationLayout" stretch="1,0,0">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QComboBox" name="configurationsComboBox">
<item>
<property name="text">
<string>Atys</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QPushButton" name="playButton">
<property name="text">
<string>Play</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="configureButton">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>627</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">
<property name="title">
<string>&amp;Settings</string>
</property>
<addaction name="action_Configurations"/>
<addaction name="action_Directories"/>
<addaction name="separator"/>
<addaction name="action_Quit"/>
</widget>
<widget class="QMenu" name="menu_Help">
<property name="title">
<string>&amp;Help</string>
</property>
<addaction name="actionAboutQt"/>
<addaction name="actionAbout"/>
</widget>
<addaction name="menu_File"/>
<addaction name="menu_Help"/>
</widget>
<widget class="QStatusBar" name="statusbar">
<property name="sizeGripEnabled">
<bool>false</bool>
</property>
</widget>
<action name="actionAboutQt">
<property name="text">
<string>About Qt</string>
</property>
</action>
<action name="actionAbout">
<property name="text">
<string>About...</string>
</property>
</action>
<action name="action_Configurations">
<property name="text">
<string>&amp;Configurations</string>
</property>
</action>
<action name="action_Directories">
<property name="text">
<string>&amp;Directories</string>
</property>
</action>
<action name="action_Quit">
<property name="text">
<string>&amp;Quit</string>
</property>
</action>
</widget>
<resources>
<include location="../res/resources.qrc"/>
</resources>
<connections/>
</ui>

View file

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsDialog</class>
<widget class="QDialog" name="SettingsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>150</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Language</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBox"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Base location of Ryzom files: %1</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Location of source Ryzom files: %1</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBox">
<property name="text">
<string>Use 64 bits client</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SettingsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SettingsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -0,0 +1,260 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>WizardDialog</class>
<widget class="QDialog" name="WizardDialog">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>402</width>
<height>464</height>
</rect>
</property>
<property name="windowTitle">
<string>Ryzom Installer</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="mainlLayout" stretch="1,0,0,0">
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
<item>
<widget class="QLabel" name="messageLabel">
<property name="text">
<string>Welcome to Ryzom Installer!
This program will allow you to download, install, migrate, configure or manage Ryzom on your computer.
Just follow the different steps and make your choice between the different propositions.</string>
</property>
<property name="alignment">
<set>Qt::AlignJustify|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="advancedLayout">
<item>
<spacer name="advancedHorizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="advancedCheckBox">
<property name="text">
<string>Show advanced parameters (expert)</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QFrame" name="advancedFrame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="advancedMainLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="sourceGroupBox">
<property name="title">
<string>Files will be installed from:</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QRadioButton" name="currentDirectoryRadioButton">
<property name="text">
<string>Current directory</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="oldDirectoryRadioButton">
<property name="text">
<string>Old installation: %1</string>
</property>
<property name="autoExclusive">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="anotherLocationLayout" stretch="1,0">
<property name="spacing">
<number>6</number>
</property>
<item>
<widget class="QRadioButton" name="anotherLocationRadioButton">
<property name="text">
<string>Another location: %1</string>
</property>
<property name="autoExclusive">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="anotherLocationBrowseButton">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QRadioButton" name="internetRadioButton">
<property name="text">
<string>Internet (%1 GiB to download)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="destinationGroupBox">
<property name="title">
<string>Files will be installed to (requires 10 GiB):</string>
</property>
<layout class="QHBoxLayout" name="destinationLayout" stretch="1,0">
<item>
<widget class="QLabel" name="destinationLabel">
<property name="text">
<string>c:\</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="destinationBrowseButton">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="clientArchGroupBox">
<property name="title">
<string>Do you prefer to use a 64 or 32 bits client?</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QRadioButton" name="clientArch64RadioButton">
<property name="text">
<string>64 bits (recommended)</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="clientArch32RadioButton">
<property name="text">
<string>32 bits</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>currentDirectoryRadioButton</tabstop>
<tabstop>oldDirectoryRadioButton</tabstop>
<tabstop>anotherLocationRadioButton</tabstop>
<tabstop>anotherLocationBrowseButton</tabstop>
<tabstop>internetRadioButton</tabstop>
<tabstop>destinationBrowseButton</tabstop>
<tabstop>clientArch64RadioButton</tabstop>
<tabstop>clientArch32RadioButton</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>WizardDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>227</x>
<y>406</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>WizardDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>295</x>
<y>412</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>