diff --git a/code/ryzom/tools/client/ryzom_installer/res/Info.plist b/code/ryzom/tools/client/ryzom_installer/res/Info.plist
new file mode 100644
index 000000000..0f34722db
--- /dev/null
+++ b/code/ryzom/tools/client/ryzom_installer/res/Info.plist
@@ -0,0 +1,54 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ English
+ CFBundleExecutable
+ shortcut.sh
+ CFBundleGetInfoString
+ $NAME
+ CFBundleIconFile
+ ryzom.icns
+ CFBundleIdentifier
+ $IDENTIFIER
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleLocalizations
+
+ en
+ fr
+ de
+ ru
+ es
+
+ CFBundleLongVersionString
+ $VERSION
+ CFBundleName
+ $NAME
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ $VERSION
+ CFBundleSignature
+ ????
+ CFBundleSupportedPlatforms
+
+ MacOSX
+
+ CFBundleVersion
+ 1.0
+ CSResourcesFileMapped
+
+ LSApplicationCategoryType
+ public.app-category.role-playing-games
+ LSFileQuarantineEnabled
+
+ LSMinimumSystemVersion
+ 10.6
+ LSRequiresCarbon
+
+ NSHumanReadableCopyright
+ $COPYRIGHT
+
+
diff --git a/code/ryzom/tools/client/ryzom_installer/res/PkgInfo b/code/ryzom/tools/client/ryzom_installer/res/PkgInfo
new file mode 100644
index 000000000..bd04210fb
--- /dev/null
+++ b/code/ryzom/tools/client/ryzom_installer/res/PkgInfo
@@ -0,0 +1 @@
+APPL????
\ No newline at end of file
diff --git a/code/ryzom/tools/client/ryzom_installer/res/resources.qrc b/code/ryzom/tools/client/ryzom_installer/res/resources.qrc
index 31622b6c1..6336b61e1 100644
--- a/code/ryzom/tools/client/ryzom_installer/res/resources.qrc
+++ b/code/ryzom/tools/client/ryzom_installer/res/resources.qrc
@@ -4,10 +4,13 @@
ryzom.ico
- ryzom_installer.png
+ ryzom.png
+ ryzom.icns
template.desktop
ryzom_installer.ini
+ Info.plist
+ PkgInfo
diff --git a/code/ryzom/tools/client/ryzom_installer/res/ryzom.icns b/code/ryzom/tools/client/ryzom_installer/res/ryzom.icns
new file mode 100644
index 000000000..45e7bace1
Binary files /dev/null and b/code/ryzom/tools/client/ryzom_installer/res/ryzom.icns differ
diff --git a/code/ryzom/tools/client/ryzom_installer/res/ryzom.png b/code/ryzom/tools/client/ryzom_installer/res/ryzom.png
new file mode 100644
index 000000000..a51ce87ab
Binary files /dev/null and b/code/ryzom/tools/client/ryzom_installer/res/ryzom.png differ
diff --git a/code/ryzom/tools/client/ryzom_installer/res/ryzom_installer.png b/code/ryzom/tools/client/ryzom_installer/res/ryzom_installer.png
deleted file mode 100644
index 67e3034ef..000000000
Binary files a/code/ryzom/tools/client/ryzom_installer/res/ryzom_installer.png and /dev/null differ
diff --git a/code/ryzom/tools/client/ryzom_installer/res/shortcut.sh b/code/ryzom/tools/client/ryzom_installer/res/shortcut.sh
new file mode 100644
index 000000000..014ce6520
--- /dev/null
+++ b/code/ryzom/tools/client/ryzom_installer/res/shortcut.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+# autogenerated file - do not edit
+
+$COMMAND
diff --git a/code/ryzom/tools/client/ryzom_installer/src/configfile.cpp b/code/ryzom/tools/client/ryzom_installer/src/configfile.cpp
index c3eaf3d64..06c525053 100644
--- a/code/ryzom/tools/client/ryzom_installer/src/configfile.cpp
+++ b/code/ryzom/tools/client/ryzom_installer/src/configfile.cpp
@@ -791,15 +791,18 @@ QStringList CConfigFile::getInstallerRequiredFiles() const
// unsupported compiler
#endif
+ // include current executable
+ files << QFileInfo(QApplication::applicationFilePath()).fileName();
#elif defined(Q_OS_MAC)
- // TODO: for OS X
+ // everything is in a directory
+ files << "Ryzom Installer.app";
#else
// icon under Linux
files << "ryzom_installer.png";
-#endif
// include current executable
files << QFileInfo(QApplication::applicationFilePath()).fileName();
+#endif
return files;
}
diff --git a/code/ryzom/tools/client/ryzom_installer/src/installdialog.cpp b/code/ryzom/tools/client/ryzom_installer/src/installdialog.cpp
index 513cf1044..7198962ac 100644
--- a/code/ryzom/tools/client/ryzom_installer/src/installdialog.cpp
+++ b/code/ryzom/tools/client/ryzom_installer/src/installdialog.cpp
@@ -118,16 +118,7 @@ void CInstallDialog::accept()
if (succeedsToWrite)
{
// check if directory is writable by current user
- QFile file(m_dstDirectory + "/writable_test_for_ryzom_installer.txt");
-
- if (file.open(QFile::WriteOnly))
- {
- file.close();
-
- // remove it
- file.remove();
- }
- else
+ if (!isDirectoryWritable(m_dstDirectory))
{
succeedsToWrite = false;
}
diff --git a/code/ryzom/tools/client/ryzom_installer/src/migratedialog.cpp b/code/ryzom/tools/client/ryzom_installer/src/migratedialog.cpp
index 0527bca1f..22e4f0ad2 100644
--- a/code/ryzom/tools/client/ryzom_installer/src/migratedialog.cpp
+++ b/code/ryzom/tools/client/ryzom_installer/src/migratedialog.cpp
@@ -133,16 +133,7 @@ void CMigrateDialog::accept()
if (succeedsToWrite)
{
// check if directory is writable by current user
- QFile file(m_dstDirectory + "/writable_test_for_ryzom_installer.txt");
-
- if (file.open(QFile::WriteOnly))
- {
- file.close();
-
- // remove it
- file.remove();
- }
- else
+ if (!isDirectoryWritable(m_dstDirectory))
{
succeedsToWrite = false;
}
diff --git a/code/ryzom/tools/client/ryzom_installer/src/operationdialog.cpp b/code/ryzom/tools/client/ryzom_installer/src/operationdialog.cpp
index d5e83037c..9c84f46cf 100644
--- a/code/ryzom/tools/client/ryzom_installer/src/operationdialog.cpp
+++ b/code/ryzom/tools/client/ryzom_installer/src/operationdialog.cpp
@@ -788,9 +788,17 @@ void COperationDialog::copyInstaller()
#ifdef Q_OS_WIN32
// under Windows, icon is included in executable
icon = executable;
+#elif defined(Q_OS_MAC)
+ // everything is in bundle
#else
// icon is in the same directory as installer
icon = config->getInstallationDirectory() + "/ryzom_installer.png";
+
+ // create icon if not exists
+ if (!QFile::exists(icon) && !writeResource(":/icons/ryzom.png", icon))
+ {
+ qDebug() << "Unable to create" << icon;
+ }
#endif
createShortcut(shortcut, name, executable, "", icon, "");
@@ -1072,6 +1080,9 @@ void COperationDialog::deleteComponentsServers()
// clear list of all servers to uninstall
m_removeComponents.servers.clear();
+ // delete Ryzom directory if all files have been deleted
+ if (isDirectoryEmpty(config->getInstallationDirectory(), true)) QDir(config->getInstallationDirectory()).removeRecursively();
+
emit done();
}
@@ -1142,6 +1153,9 @@ void COperationDialog::deleteComponentsProfiles()
// clear list of all profiles to uninstall
m_removeComponents.profiles.clear();
+ // delete profiles directory if all files have been deleted
+ if (isDirectoryEmpty(config->getProfileDirectory(), true)) QDir(config->getProfileDirectory()).removeRecursively();
+
emit done();
}
@@ -1190,6 +1204,9 @@ void COperationDialog::deleteComponentsInstaller()
// reset it once it's done
m_removeComponents.installer = false;
+ // delete Ryzom directory if all files have been deleted
+ if (isDirectoryEmpty(config->getInstallationDirectory(), true)) QDir(config->getInstallationDirectory()).removeRecursively();
+
emit success(1);
emit done();
}
@@ -1225,6 +1242,9 @@ void COperationDialog::deleteComponentsDownloadedFiles()
// reset it once it's done
m_removeComponents.downloadedFiles = false;
+ // delete Ryzom directory if all files have been deleted
+ if (isDirectoryEmpty(config->getInstallationDirectory(), true)) QDir(config->getInstallationDirectory()).removeRecursively();
+
emit success(1);
emit done();
}
diff --git a/code/ryzom/tools/client/ryzom_installer/src/utils.cpp b/code/ryzom/tools/client/ryzom_installer/src/utils.cpp
index c2789f180..de967b4f8 100644
--- a/code/ryzom/tools/client/ryzom_installer/src/utils.cpp
+++ b/code/ryzom/tools/client/ryzom_installer/src/utils.cpp
@@ -16,6 +16,7 @@
#include "stdpch.h"
#include "utils.h"
+#include "configfile.h"
#include "nel/misc/path.h"
@@ -40,6 +41,36 @@ QString qBytesToHumanReadable(qint64 bytes)
return QString::fromUtf8(NLMISC::bytesToHumanReadableUnits(bytes, units).c_str());
}
+QString nameToId(const QString &name)
+{
+ QString res;
+
+ // only allows simple characters
+ QRegExp allowedCharacters("^[0-9a-zA-Z-]$");
+
+ for (int i = 0, len = name.length(); i < len; ++i)
+ {
+ if (allowedCharacters.indexIn(name.at(i)) > -1)
+ {
+ // allowed character
+ res += name[i];
+ }
+ else
+ {
+ // not allowed, replace by a space
+ res += " ";
+ }
+ }
+
+ // simplify all spaces
+ res = res.simplified();
+
+ // replace spaces by minus
+ res.replace(" ", "-");
+
+ return res;
+}
+
bool isDirectoryEmpty(const QString &directory, bool recursize)
{
bool res = true;
@@ -71,6 +102,21 @@ bool isDirectoryEmpty(const QString &directory, bool recursize)
return res;
}
+bool isDirectoryWritable(const QString &directory)
+{
+ // check if directory is writable by current user
+ QFile file(directory + "/writable_test_for_ryzom_installer.txt");
+
+ if (!file.open(QFile::WriteOnly)) return false;
+
+ file.close();
+
+ // remove it
+ file.remove();
+
+ return true;
+}
+
qint64 getDirectorySize(const QString &directory, bool recursize)
{
qint64 size = 0;
@@ -250,37 +296,89 @@ bool resolveShortcut(const QWidget &window, const QString &shortcut, QString &pa
return SUCCEEDED(hres);
}
+#elif defined(NL_OS_MAC)
+
+bool createShortcut(const QString &shortcut, const QString &name, const QString &executable, const QString &arguments, const QString &icon, const QString &workingDir)
+{
+ QString appPath(shortcut + ".app");
+
+ // directories
+ QString contentsPath(appPath + "/Contents");
+ QString binaryPath(contentsPath + "/MacOS");
+ QString dataPath(contentsPath + "/Resources");
+
+ // files
+ QString binaryFile(binaryPath + "/shortcut.sh");
+ QString iconFile(dataPath + "/ryzom.icns");
+ QString pkgInfoFile(contentsPath + "/PkgInfo");
+ QString plistFile(contentsPath + "/Info.plist");
+
+ // silently create directories
+ QDir().mkpath(binaryPath);
+ QDir().mkpath(dataPath);
+
+ if (!isDirectoryWritable(binaryPath) || !isDirectoryWritable(dataPath)) return false;
+
+ // write icon
+ if (!writeResource(":/icons/ryzom.icns", iconFile)) return false;
+
+ // write PkgInfo
+ if (!writeResource(":/templates/PkgInfo", pkgInfoFile)) return false;
+
+ // variables
+ QMap strings;
+
+ // build command
+ QString command = QString("open \"%1\"").arg(executable);
+ if (!arguments.isEmpty()) command += " --args " + arguments;
+
+ strings.clear();
+ strings["COMMAND"] = command;
+
+ // write shortcut.sh
+ if (!writeResourceWithTemplates(":/templates/shortcut.sh", binaryFile, strings)) return false;
+
+ // set executable flags to .sh
+ QFile::setPermissions(binaryFile, QFile::permissions(binaryFile) | QFile::ExeGroup | QFile::ExeUser | QFile::ExeOther);
+
+ CConfigFile *config = CConfigFile::getInstance();
+
+ strings.clear();
+ strings["NAME"] = name;
+ strings["COPYRIGHT"] = config->getProductPublisher();
+ strings["VERSION"] = QApplication::applicationVersion();
+ strings["IDENTIFIER"] = "com.winchgate.Ryzom-" + nameToId(name);
+
+ // write Info.plist
+ if (!writeResourceWithTemplates(":/templates/Info.plist", plistFile, strings)) return false;
+
+ return true;
+}
+
+bool resolveShortcut(const QWidget &window, const QString &pathLink, QString &pathObj)
+{
+ return false;
+}
+
#else
bool createShortcut(const QString &shortcut, const QString &name, const QString &executable, const QString &arguments, const QString &icon, const QString &workingDir)
{
- // open template
- QFile file(":/templates/template.desktop");
-
- if (!file.open(QFile::ReadOnly)) return false;
-
- QString data = QString::fromUtf8(file.readAll());
-
- file.close();
-
// build command
QString command = executable;
if (!arguments.isEmpty()) command += " " + arguments;
- // replace strings
- data.replace("$NAME", name);
- data.replace("$COMMAND", command);
- data.replace("$ICON", icon);
+ // variables
+ QMap strings;
+ strings["NAME"] = name;
+ strings["COMMAND"] = command;
+ strings["ICON"] = icon;
+ // destination file
QString path(shortcut + ".desktop");
- // write file
- file.setFileName(path);
-
- if (!file.open(QFile::WriteOnly)) return false;
-
- file.write(data.toUtf8());
- file.close();
+ // replace strings
+ if (!writeResourceWithTemplates(":/templates/template.desktop", path, strings)) return false;
// set executable flags to .desktop
QFile::setPermissions(path, QFile::permissions(path) | QFile::ExeGroup | QFile::ExeUser | QFile::ExeOther);
@@ -307,7 +405,13 @@ bool removeShortcut(const QString &shortcut)
if (!NLMISC::CFile::isExists(qToUtf8(fullPath))) return false;
// remove it
+#if defined(Q_OS_MAC)
+ // under OS X, it's a directory
+ return QDir(fullPath).removeRecursively();
+#else
+ // a file under other platforms
return QFile::remove(fullPath);
+#endif
}
QString appendShortcutExtension(const QString &shortcut)
@@ -317,7 +421,7 @@ QString appendShortcutExtension(const QString &shortcut)
#if defined(Q_OS_WIN32)
extension = ".lnk";
#elif defined(Q_OS_MAC)
- // TODO
+ extension = ".app";
#else
extension = ".desktop";
#endif
@@ -391,6 +495,75 @@ QString getVersionFromExecutable(const QString &path)
return "";
}
+bool writeResource(const QString &resource, const QString &path)
+{
+ // all resources start with :/
+ if (!resource.startsWith(":/")) return false;
+
+ // open resource
+ QFile file(resource);
+
+ // unable to open it
+ if (!file.open(QFile::ReadOnly)) return false;
+
+ QByteArray data(file.readAll());
+
+ file.close();
+
+ // write file
+ file.setFileName(path);
+
+ // unable to write it
+ if (!file.open(QFile::WriteOnly)) return false;
+
+ // problem writting
+ if (file.write(data) != data.length()) return false;
+
+ file.close();
+
+ return true;
+}
+
+bool writeResourceWithTemplates(const QString &resource, const QString &path, const QMap &strings)
+{
+ // all resources start with :/
+ if (!resource.startsWith(":/")) return false;
+
+ // open resource
+ QFile file(resource);
+
+ // unable to open it
+ if (!file.open(QFile::ReadOnly)) return false;
+
+ // data are UTF-8 text
+ QString data = QString::fromUtf8(file.readAll());
+
+ file.close();
+
+ // write file
+ file.setFileName(path);
+
+ // unable to write it
+ if (!file.open(QFile::WriteOnly)) return false;
+
+ // replace strings
+ QMap::ConstIterator it = strings.begin(), iend = strings.end();
+
+ while (it != iend)
+ {
+ // replace variables with their value
+ data.replace("$" + it.key(), it.value());
+
+ ++it;
+ }
+
+ // write
+ file.write(data.toUtf8());
+ file.close();
+
+ return true;
+}
+
CCOMHelper::CCOMHelper()
{
#ifdef Q_OS_WIN
diff --git a/code/ryzom/tools/client/ryzom_installer/src/utils.h b/code/ryzom/tools/client/ryzom_installer/src/utils.h
index 0b0bcb170..296c439fd 100644
--- a/code/ryzom/tools/client/ryzom_installer/src/utils.h
+++ b/code/ryzom/tools/client/ryzom_installer/src/utils.h
@@ -29,8 +29,10 @@
*/
QString qBytesToHumanReadable(qint64 bytes);
+QString nameToId(const QString &name);
bool isDirectoryEmpty(const QString &directory, bool recursize);
+bool isDirectoryWritable(const QString &directory);
qint64 getDirectorySize(const QString &directory, bool recursize);
@@ -57,6 +59,8 @@ bool resolveShortcut(const QWidget &window, const QString &shortcut, QString &pa
QString appendShortcutExtension(const QString &shortcut);
QString getVersionFromExecutable(const QString &path);
+bool writeResource(const QString &resource, const QString &path);
+bool writeResourceWithTemplates(const QString &resource, const QString &path, const QMap &strings);
class CCOMHelper
{