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); } +#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 +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 {