mirror of
https://github.com/nextcloud/desktop.git
synced 2025-10-26 11:17:43 +00:00
feat(utility): migrate fav links.
Add helper function to get path to links folder. Signed-off-by: Camila Ayres <hello@camilasan.com>
This commit is contained in:
parent
4b7ef6eab7
commit
1cc9f689c4
@ -54,11 +54,25 @@ namespace Utility {
|
||||
OCSYNC_EXPORT void usleep(int usec);
|
||||
OCSYNC_EXPORT QString formatFingerprint(const QByteArray &, bool colonSeparated = true);
|
||||
/**
|
||||
* @brief Creates the Desktop.ini file which contains the folder IconResource shown as a favorite link
|
||||
* @brief Create favorite link for sync folder with application name and icon
|
||||
*
|
||||
* @param folder absolute file path to folder
|
||||
*/
|
||||
OCSYNC_EXPORT void setupFavLink(const QString &folder);
|
||||
/**
|
||||
* @brief Migrate favorite link for sync folder with new application name and icon
|
||||
*
|
||||
* @param folder absolute file path to folder
|
||||
* @param lnkName the new name of the lnk file
|
||||
*/
|
||||
OCSYNC_EXPORT void migrateFavLink(const QString &folder, const QString &lnkName = QString());
|
||||
/**
|
||||
* @brief Creates or overwrite the Desktop.ini file to use new folder IconResource shown as a favorite link
|
||||
*
|
||||
* @param folder absolute file path to folder
|
||||
* @param overwrite boolean to create or overwrite ini file
|
||||
*/
|
||||
OCSYNC_EXPORT void setupDesktopIni(const QString &folder, bool overwrite = false);
|
||||
/**
|
||||
* @brief Removes the Desktop.ini file which contains the folder IconResource shown as a favorite link
|
||||
*
|
||||
@ -66,6 +80,9 @@ namespace Utility {
|
||||
*/
|
||||
OCSYNC_EXPORT void removeFavLink(const QString &folder);
|
||||
|
||||
// convenience system path to links folder
|
||||
OCSYNC_EXPORT QString systemPathToLinks();
|
||||
|
||||
OCSYNC_EXPORT bool writeRandomFile(const QString &fname, int size = -1);
|
||||
OCSYNC_EXPORT QString octetsToString(const qint64 octets);
|
||||
OCSYNC_EXPORT QByteArray userAgentString();
|
||||
@ -350,6 +367,5 @@ inline constexpr bool Utility::isBSD()
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
#endif // UTILITY_H
|
||||
|
||||
@ -56,6 +56,18 @@ void Utility::removeFavLink(const QString &folder)
|
||||
Q_UNUSED(folder)
|
||||
}
|
||||
|
||||
void Utility::migrateFavLink(const QString &folder)
|
||||
{
|
||||
Q_UNUSED(folder)
|
||||
}
|
||||
|
||||
QString Utility::syncFolderDisplayName(const QString &folder, const QString &displayName)
|
||||
{
|
||||
Q_UNUSED(folder)
|
||||
Q_UNUSED(displayName)
|
||||
return {};
|
||||
}
|
||||
|
||||
static Result<void, QString> writePlistToFile(NSString *plistFile, NSDictionary *plist)
|
||||
{
|
||||
NSError *error = nil;
|
||||
|
||||
@ -65,6 +65,18 @@ bool Utility::hasLaunchOnStartup(const QString &appName)
|
||||
return QFile::exists(desktopFileLocation);
|
||||
}
|
||||
|
||||
void Utility::migrateFavLink(const QString &folder)
|
||||
{
|
||||
Q_UNUSED(folder)
|
||||
}
|
||||
|
||||
QString Utility::syncFolderDisplayName(const QString &folder, const QString &displayName)
|
||||
{
|
||||
Q_UNUSED(folder)
|
||||
Q_UNUSED(displayName)
|
||||
return {};
|
||||
}
|
||||
|
||||
void Utility::setLaunchOnStartup(const QString &appName, const QString &guiName, bool enable)
|
||||
{
|
||||
const auto userAutoStartPath = getUserAutostartDir();
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include "asserts.h"
|
||||
#include "utility.h"
|
||||
#include "gui/configgui.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <comdef.h>
|
||||
#include <Lmcons.h>
|
||||
@ -99,55 +100,128 @@ QVector<Utility::ProcessInfosForOpenFile> Utility::queryProcessInfosKeepingFileO
|
||||
return results;
|
||||
}
|
||||
|
||||
void Utility::setupFavLink(const QString &folder)
|
||||
QString Utility::systemPathToLinks()
|
||||
{
|
||||
static const QString pathToLinks = [] {
|
||||
PWSTR path = nullptr;
|
||||
if (SHGetKnownFolderPath(FOLDERID_Links, 0, nullptr, &path) != S_OK) {
|
||||
qCWarning(lcUtility) << "SHGetKnownFolderPath failed.";
|
||||
CoTaskMemFree(path);
|
||||
return QString();
|
||||
}
|
||||
|
||||
const auto links = QDir::fromNativeSeparators(QString::fromWCharArray(path));
|
||||
CoTaskMemFree(path);
|
||||
return links;
|
||||
}();
|
||||
|
||||
return pathToLinks;
|
||||
}
|
||||
|
||||
void Utility::setupDesktopIni(const QString &folder, bool overwrite)
|
||||
{
|
||||
// First create a Desktop.ini so that the folder and favorite link show our application's icon.
|
||||
QFile desktopIni(folder + QLatin1String("/Desktop.ini"));
|
||||
if (desktopIni.exists()) {
|
||||
if (!overwrite && desktopIni.exists()) {
|
||||
qCWarning(lcUtility) << desktopIni.fileName() << "already exists, not overwriting it to set the folder icon.";
|
||||
} else {
|
||||
qCInfo(lcUtility) << "Creating" << desktopIni.fileName() << "to set a folder icon in Explorer.";
|
||||
desktopIni.open(QFile::WriteOnly);
|
||||
desktopIni.write("[.ShellClassInfo]\r\nIconResource=");
|
||||
desktopIni.write(QDir::toNativeSeparators(qApp->applicationFilePath()).toUtf8());
|
||||
#ifdef APPLICATION_FOLDER_ICON_INDEX
|
||||
const auto iconIndex = APPLICATION_FOLDER_ICON_INDEX;
|
||||
#else
|
||||
const auto iconIndex = "0";
|
||||
#endif
|
||||
desktopIni.write(",");
|
||||
desktopIni.write(iconIndex);
|
||||
desktopIni.write("\r\n");
|
||||
desktopIni.close();
|
||||
|
||||
// Set the folder as system and Desktop.ini as hidden+system for explorer to pick it.
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/cc144102
|
||||
DWORD folderAttrs = GetFileAttributesW((wchar_t *)folder.utf16());
|
||||
SetFileAttributesW((wchar_t *)folder.utf16(), folderAttrs | FILE_ATTRIBUTE_SYSTEM);
|
||||
SetFileAttributesW((wchar_t *)desktopIni.fileName().utf16(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Use new WINAPI functions */
|
||||
PWSTR path;
|
||||
if (!SHGetKnownFolderPath(FOLDERID_Links, 0, nullptr, &path) == S_OK) {
|
||||
qCDebug(lcUtility) << "Creating" << desktopIni.fileName() << "to set a folder icon in Explorer.";
|
||||
desktopIni.open(QFile::WriteOnly);
|
||||
desktopIni.write("[.ShellClassInfo]\r\nIconResource=");
|
||||
desktopIni.write(QDir::toNativeSeparators(qApp->applicationFilePath()).toUtf8());
|
||||
#ifdef APPLICATION_FOLDER_ICON_INDEX
|
||||
const auto iconIndex = APPLICATION_FOLDER_ICON_INDEX;
|
||||
#else
|
||||
const auto iconIndex = "0";
|
||||
#endif
|
||||
desktopIni.write(",");
|
||||
desktopIni.write(iconIndex);
|
||||
desktopIni.write("\r\n");
|
||||
desktopIni.close();
|
||||
|
||||
// Set the folder as system and Desktop.ini as hidden+system for explorer to pick it.
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/cc144102
|
||||
DWORD folderAttrs = GetFileAttributesW((wchar_t *)folder.utf16());
|
||||
SetFileAttributesW((wchar_t *)folder.utf16(), folderAttrs | FILE_ATTRIBUTE_SYSTEM);
|
||||
SetFileAttributesW((wchar_t *)desktopIni.fileName().utf16(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
|
||||
}
|
||||
|
||||
void Utility::setupFavLink(const QString &folder)
|
||||
{
|
||||
// create Desktop.ini
|
||||
setupDesktopIni(folder);
|
||||
|
||||
const auto pathToLinks = systemPathToLinks();
|
||||
if (pathToLinks.isEmpty()) {
|
||||
qCWarning(lcUtility) << "SHGetKnownFolderPath for " << folder << "has failed.";
|
||||
return;
|
||||
}
|
||||
|
||||
// Windows Explorer: Place under "Favorites" (Links)
|
||||
const auto links = QDir::fromNativeSeparators(QString::fromWCharArray(path));
|
||||
CoTaskMemFree(path);
|
||||
|
||||
const QDir folderDir(QDir::fromNativeSeparators(folder));
|
||||
const QString filePath = folderDir.dirName() + QLatin1String(".lnk");
|
||||
const auto linkName = QDir(links).filePath(filePath);
|
||||
const auto linkName = QDir().filePath(filePath);
|
||||
|
||||
qCInfo(lcUtility) << "Creating favorite link from" << folder << "to" << linkName;
|
||||
qCDebug(lcUtility) << "Creating favorite link from" << folder << "to" << linkName;
|
||||
if (!QFile::link(folder, linkName)) {
|
||||
qCWarning(lcUtility) << "linking" << folder << "to" << linkName << "failed!";
|
||||
}
|
||||
}
|
||||
|
||||
QString Utility::syncFolderDisplayName(const QString ¤tDisplayName, const QString &newName)
|
||||
{
|
||||
const auto nextcloud = QStringLiteral("Nextcloud");
|
||||
if (!currentDisplayName.startsWith(nextcloud)) {
|
||||
qCWarning(lcUtility) << "Nothings needs to be rename for" << currentDisplayName;
|
||||
return currentDisplayName;
|
||||
}
|
||||
|
||||
QString digits;
|
||||
for (auto letter = std::crbegin(currentDisplayName); letter != std::crend(currentDisplayName); ++letter) {
|
||||
if (!letter->isDigit()) {
|
||||
break;
|
||||
}
|
||||
digits.prepend(*letter);
|
||||
}
|
||||
|
||||
return newName + digits;
|
||||
}
|
||||
|
||||
void Utility::migrateFavLink(const QString &folder)
|
||||
{
|
||||
//overwrite Desktop.ini, update icon
|
||||
setupDesktopIni(folder, true);
|
||||
|
||||
const QDir folderDir(QDir::fromNativeSeparators(folder));
|
||||
const auto oldDirName = folderDir.dirName();
|
||||
const auto nextcloud = QStringLiteral("Nextcloud");
|
||||
if (!oldDirName.startsWith(nextcloud)) {
|
||||
qCWarning(lcUtility) << "Link name does not need to change for" << folder;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto pathToLinks = systemPathToLinks();
|
||||
if (pathToLinks.isEmpty()) {
|
||||
qCWarning(lcUtility) << "SHGetKnownFolderPath for links has failed.";
|
||||
return;
|
||||
}
|
||||
|
||||
const QDir dirPathToLinks(pathToLinks);
|
||||
const auto oldLnkFilename = dirPathToLinks.filePath(oldDirName + QLatin1String(".lnk"));
|
||||
const auto newLnkFilename = dirPathToLinks.filePath(syncFolderDisplayName(oldDirName, QStringLiteral(APPLICATION_NAME)) + QLatin1String(".lnk"));
|
||||
|
||||
if (QFile::exists(newLnkFilename)) {
|
||||
qCWarning(lcUtility) << "New lnk file already exists" << newLnkFilename;
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(lcUtility) << "Renaming favorite link from" << oldLnkFilename << "to" << newLnkFilename;
|
||||
if (QFile::rename(oldLnkFilename, newLnkFilename) && !QFile::rename(oldLnkFilename, newLnkFilename)) {
|
||||
qCWarning(lcUtility) << "renaming" << oldLnkFilename << "to" << newLnkFilename << "failed!";
|
||||
}
|
||||
}
|
||||
|
||||
void Utility::removeFavLink(const QString &folder)
|
||||
{
|
||||
const QDir folderDir(folder);
|
||||
@ -176,7 +250,7 @@ void Utility::removeFavLink(const QString &folder)
|
||||
|
||||
const auto linkName = QDir(links).absoluteFilePath(folderDir.dirName() + QLatin1String(".lnk"));
|
||||
|
||||
qCInfo(lcUtility) << "Removing favorite link from" << folder << "to" << linkName;
|
||||
qCDebug(lcUtility) << "Removing favorite link from" << folder << "to" << linkName;
|
||||
if (!QFile::remove(linkName)) {
|
||||
qCWarning(lcUtility) << "Removing a favorite link from" << folder << "to" << linkName << "failed.";
|
||||
}
|
||||
|
||||
@ -536,6 +536,7 @@ void FolderMan::setupLegacyFolder(const QString &fileNamePath, AccountState *acc
|
||||
const auto journalPath = settings.value(QLatin1String("journalPath")).toString();
|
||||
const auto paused = settings.value(QLatin1String("paused"), false).toBool();
|
||||
const auto ignoreHiddenFiles = settings.value(QLatin1String("ignoreHiddenFiles"), false).toBool();
|
||||
const auto virtualFilesMode = settings.value(QLatin1String("virtualFilesMode"), false).toString();
|
||||
|
||||
if (path.isEmpty()) {
|
||||
qCDebug(lcFolderMan) << "localPath is empty";
|
||||
@ -565,7 +566,21 @@ void FolderMan::setupLegacyFolder(const QString &fileNamePath, AccountState *acc
|
||||
folderDefinition.paused = paused;
|
||||
folderDefinition.ignoreHiddenFiles = ignoreHiddenFiles;
|
||||
|
||||
if (const auto folder = addFolderInternal(folderDefinition, accountState, std::make_unique<VfsOff>())) {
|
||||
if (const auto vfsMode = Vfs::modeFromString(virtualFilesMode)) {
|
||||
folderDefinition.virtualFilesMode = *vfsMode;
|
||||
} else {
|
||||
qCWarning(lcFolderMan) << "Unknown virtualFilesMode:" << virtualFilesMode << "assuming 'off'";
|
||||
}
|
||||
|
||||
qCDebug(lcFolderMan) << "folderDefinition.alias" << folderDefinition.alias;
|
||||
qCDebug(lcFolderMan) << "folderDefinition.virtualFilesMode" << folderDefinition.virtualFilesMode;
|
||||
|
||||
auto vfs = createVfsFromPlugin(folderDefinition.virtualFilesMode);
|
||||
if (!vfs && folderDefinition.virtualFilesMode != Vfs::Off) {
|
||||
qCWarning(lcFolderMan) << "Could not load plugin for mode" << folderDefinition.virtualFilesMode;
|
||||
}
|
||||
|
||||
if (const auto folder = addFolderInternal(folderDefinition, accountState, std::move(vfs))) {
|
||||
auto ok = true;
|
||||
auto legacyBlacklist = folder->journalDb()->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList,
|
||||
&ok);
|
||||
@ -593,6 +608,10 @@ void FolderMan::setupLegacyFolder(const QString &fileNamePath, AccountState *acc
|
||||
|
||||
scheduleFolder(folder);
|
||||
emit folderSyncStateChange(folder);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
Utility::migrateFavLink(folder->cleanPath());
|
||||
#endif
|
||||
}
|
||||
settings.endGroup(); // folder alias
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user