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/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/operationdialog.cpp b/code/ryzom/tools/client/ryzom_installer/src/operationdialog.cpp
index d5e83037c..766d7f9b0 100644
--- a/code/ryzom/tools/client/ryzom_installer/src/operationdialog.cpp
+++ b/code/ryzom/tools/client/ryzom_installer/src/operationdialog.cpp
@@ -788,6 +788,8 @@ 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";
diff --git a/code/ryzom/tools/client/ryzom_installer/src/utils.cpp b/code/ryzom/tools/client/ryzom_installer/src/utils.cpp
index c2789f180..c83ecdd62 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;
@@ -250,37 +281,89 @@ bool resolveShortcut(const QWidget &window, const QString &shortcut, QString &pa
return SUCCEEDED(hres);
}
-#else
+#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)
{
- // open template
- QFile file(":/templates/template.desktop");
+ QString appPath(shortcut + ".app");
- if (!file.open(QFile::ReadOnly)) return false;
+ // directories
+ QString contentsPath(appPath + "/Contents");
+ QString binaryPath(contentsPath + "/MacOS");
+ QString dataPath(contentsPath + "/Resources");
- QString data = QString::fromUtf8(file.readAll());
+ // files
+ QString binaryFile(binaryPath + "/shortcut.sh");
+ QString iconFile(dataPath + "/ryzom.icns");
+ QString pkgInfoFile(contentsPath + "/PkgInfo");
+ QString plistFile(contentsPath + "/Info.plist");
- file.close();
+ // 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)
+{
// 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 +390,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 +406,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 +480,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..f28d923ec 100644
--- a/code/ryzom/tools/client/ryzom_installer/src/utils.h
+++ b/code/ryzom/tools/client/ryzom_installer/src/utils.h
@@ -29,6 +29,7 @@
*/
QString qBytesToHumanReadable(qint64 bytes);
+QString nameToId(const QString &name);
bool isDirectoryEmpty(const QString &directory, bool recursize);
@@ -57,6 +58,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
{