Refactor edit locally handler management away from application and into own class
authorClaudio Cambra <claudio.cambra@nextcloud.com>
Fri, 28 Oct 2022 17:40:06 +0000 (19:40 +0200)
committerClaudio Cambra <claudio.cambra@gmail.com>
Sat, 29 Oct 2022 11:32:48 +0000 (13:32 +0200)
Signed-off-by: Claudio Cambra <claudio.cambra@nextcloud.com>
src/gui/CMakeLists.txt
src/gui/application.cpp
src/gui/application.h
src/gui/editlocallyhandler.cpp
src/gui/editlocallyhandler.h
src/gui/editlocallymanager.cpp [new file with mode: 0644]
src/gui/editlocallymanager.h [new file with mode: 0644]

index 6aa35f6b625424b711d2b0fc47835834ab16efd1..4995dafcb1805c29b762435a8d3e3e1d5e318434 100644 (file)
@@ -83,6 +83,8 @@ set(client_SRCS
     connectionvalidator.cpp
     editlocallyhandler.h
     editlocallyhandler.cpp
+    editlocallymanager.h
+    editlocallymanager.cpp
     folder.h
     folder.cpp
     foldercreationdialog.h
index 3c53314a62968fbd5ba0bc0b8ae1bcccfcddf983..fafc33a24da59e6bf0e4ccd78964637eae01cc13 100644 (file)
@@ -22,7 +22,7 @@
 #include "config.h"
 #include "account.h"
 #include "accountstate.h"
-#include "editlocallyhandler.h"
+#include "editlocallymanager.h"
 #include "connectionvalidator.h"
 #include "folder.h"
 #include "folderman.h"
@@ -750,43 +750,10 @@ void Application::handleEditLocallyFromOptions()
         return;
     }
 
-    handleEditLocally(_editFileLocallyUrl);
+    EditLocallyManager::instance()->editLocally(_editFileLocallyUrl);
     _editFileLocallyUrl.clear();
 }
 
-void Application::handleEditLocally(const QUrl &url) const
-{
-    auto pathSplit = url.path().split('/', Qt::SkipEmptyParts);
-
-    if (pathSplit.size() < 2) {
-        qCWarning(lcApplication) << "Invalid URL for file local editing: " + pathSplit.join('/');
-        return;
-    }
-
-    // for a sample URL "nc://open/admin@nextcloud.lan:8080/Photos/lovely.jpg", QUrl::path would return "admin@nextcloud.lan:8080/Photos/lovely.jpg"
-    const auto userId = pathSplit.takeFirst();
-    const auto fileRemotePath = pathSplit.join('/');
-    const auto urlQuery = QUrlQuery{url};
-
-    auto token = QString{};
-    if (urlQuery.hasQueryItem(QStringLiteral("token"))) {
-        token = urlQuery.queryItemValue(QStringLiteral("token"));
-    } else {
-        qCWarning(lcApplication) << "Invalid URL for file local editing: missing token";
-    }
-
-    // We need to make sure the handler sticks around until it is finished
-    const auto editLocallyHandler = new EditLocallyHandler(userId, fileRemotePath, token);
-    const auto editLocallyHandlerDeleter = [editLocallyHandler]{ delete editLocallyHandler; };
-    connect(editLocallyHandler, &EditLocallyHandler::error, this, editLocallyHandlerDeleter);
-    connect(editLocallyHandler, &EditLocallyHandler::fileOpened, this, editLocallyHandlerDeleter);
-
-    connect(editLocallyHandler, &EditLocallyHandler::setupFinished,
-            editLocallyHandler, [editLocallyHandler]{ editLocallyHandler->startEditLocally(); });
-    editLocallyHandler->startSetup();
-
-}
-
 QString substLang(const QString &lang)
 {
     // Map the more appropriate script codes
@@ -927,7 +894,7 @@ bool Application::event(QEvent *event)
             // On macOS, Qt does not handle receiving a custom URI as it does on other systems (as an application argument).
             // Instead, it sends out a QFileOpenEvent. We therefore need custom handling for our URI handling on macOS.
             qCInfo(lcApplication) << "macOS: Opening local file for editing: " << openEvent->url();
-            handleEditLocally(openEvent->url());
+            EditLocallyManager::instance()->editLocally(openEvent->url());
         } else {
             const auto errorParsingLocalFileEditingUrl = QStringLiteral("The supplied url for local file editing '%1' is invalid!").arg(openEvent->url().toString());
             qCInfo(lcApplication) << errorParsingLocalFileEditingUrl;
index 6c00f6a506c58f8c7fb94cb112787ea6ba0320cf..a485eea895067e1ea3b54e0f44299701783d3ee5 100644 (file)
@@ -87,8 +87,6 @@ public slots:
     /// Attempt to show() the tray icon again. Used if no systray was available initially.
     void tryTrayAgain();
 
-    void handleEditLocally(const QUrl &url) const;
-
 protected:
     void parseOptions(const QStringList &);
     void setupTranslations();
index 80d38b07c3245c2e9af2bea82bd582cbfdc82d3a..64210a7ff21abc47054d0dc398c8c2b87f063309 100644 (file)
@@ -19,6 +19,7 @@
 #include <QtConcurrent>
 
 #include "accountmanager.h"
+#include "editlocallymanager.h"
 #include "folder.h"
 #include "folderman.h"
 #include "syncengine.h"
@@ -28,8 +29,6 @@ namespace OCC {
 
 Q_LOGGING_CATEGORY(lcEditLocallyHandler, "nextcloud.gui.editlocallyhandler", QtInfoMsg)
 
-static QHash<QString, QMetaObject::Connection> editLocallySyncFinishedConnections;
-
 EditLocallyHandler::EditLocallyHandler(const QString &userId,
                                        const QString &relPath,
                                        const QString &token,
@@ -277,7 +276,9 @@ void EditLocallyHandler::startEditLocally()
     _folderForFile->startSync();
     const auto syncFinishedConnection = connect(_folderForFile, &Folder::syncFinished,
                                                 this, &EditLocallyHandler::folderSyncFinished);
-    editLocallySyncFinishedConnections.insert(_localFilePath, syncFinishedConnection);
+
+    EditLocallyManager::instance()->folderSyncFinishedConnections.insert(_localFilePath,
+                                                                         syncFinishedConnection);
 }
 
 void EditLocallyHandler::folderSyncFinished(const OCC::SyncResult &result)
@@ -293,9 +294,11 @@ void EditLocallyHandler::disconnectSyncFinished() const
         return;
     }
 
-    if (const auto existingConnection = editLocallySyncFinishedConnections.value(_localFilePath)) {
+    const auto manager = EditLocallyManager::instance();
+
+    if (const auto existingConnection = manager->folderSyncFinishedConnections.value(_localFilePath)) {
         disconnect(existingConnection);
-        editLocallySyncFinishedConnections.remove(_localFilePath);
+        manager->folderSyncFinishedConnections.remove(_localFilePath);
     }
 }
 
index 04791ce93e0314b254ee4488f43a76d41c025c70..f7b27b71a2fffb97a5a1bffde367c1d0a28eb6e2 100644 (file)
 
 #include <QObject>
 
-#include "accountmanager.h"
-#include "folder.h"
+#include "accountstate.h"
 
 namespace OCC {
 
+class EditLocallyHandler;
+using EditLocallyHandlerPtr = QSharedPointer<EditLocallyHandler>;
+
+class Folder;
+class SyncResult;
+
 class EditLocallyHandler : public QObject
 {
     Q_OBJECT
diff --git a/src/gui/editlocallymanager.cpp b/src/gui/editlocallymanager.cpp
new file mode 100644 (file)
index 0000000..1d8bea8
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) by Claudio Cambra <claudio.cambra@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License
+ * for more details.
+ */
+
+#include "editlocallymanager.h"
+
+#include <QUrl>
+#include <QLoggingCategory>
+
+#include "editlocallyhandler.h"
+
+namespace OCC {
+
+Q_LOGGING_CATEGORY(lcEditLocallyManager, "nextcloud.gui.editlocallymanager", QtInfoMsg)
+
+EditLocallyManager *EditLocallyManager::_instance = nullptr;
+
+EditLocallyManager::EditLocallyManager(QObject *parent)
+    : QObject{parent}
+{
+}
+
+EditLocallyManager *EditLocallyManager::instance()
+{
+    if (!_instance) {
+        _instance = new EditLocallyManager();
+    }
+    return _instance;
+}
+
+void EditLocallyManager::editLocally(const QUrl &url)
+{
+    const auto inputs = parseEditLocallyUrl(url);
+    createHandler(inputs.userId, inputs.relPath, inputs.token);
+}
+
+EditLocallyManager::EditLocallyInputData EditLocallyManager::parseEditLocallyUrl(const QUrl &url)
+{
+    const auto separator = QChar::fromLatin1('/');
+    auto pathSplit = url.path().split(separator, Qt::SkipEmptyParts);
+
+    if (pathSplit.size() < 2) {
+        qCWarning(lcEditLocallyManager) << "Invalid URL for file local editing: " + pathSplit.join(separator);
+        return {};
+    }
+
+    // for a sample URL "nc://open/admin@nextcloud.lan:8080/Photos/lovely.jpg", QUrl::path would return "admin@nextcloud.lan:8080/Photos/lovely.jpg"
+    const auto userId = pathSplit.takeFirst();
+    const auto fileRemotePath = pathSplit.join(separator);
+    const auto urlQuery = QUrlQuery{url};
+
+    auto token = QString{};
+    if (urlQuery.hasQueryItem(QStringLiteral("token"))) {
+        token = urlQuery.queryItemValue(QStringLiteral("token"));
+    } else {
+        qCWarning(lcEditLocallyManager) << "Invalid URL for file local editing: missing token";
+    }
+
+    return {userId, fileRemotePath, token};
+}
+
+void EditLocallyManager::createHandler(const QString &userId,
+                                       const QString &relPath,
+                                       const QString &token)
+{
+    const EditLocallyHandlerPtr handler(new EditLocallyHandler(userId, relPath, token));
+    // We need to make sure the handler sticks around until it is finished
+    _handlers.insert(token, handler);
+
+    const auto removeHandler = [this, token] { _handlers.remove(token); };
+    const auto setupHandler = [handler] { handler->startEditLocally(); };
+
+    connect(handler.data(), &EditLocallyHandler::error,
+            this, removeHandler);
+    connect(handler.data(), &EditLocallyHandler::fileOpened,
+            this, removeHandler);
+    connect(handler.data(), &EditLocallyHandler::setupFinished,
+            handler.data(), setupHandler);
+
+    handler->startSetup();
+}
+
+}
diff --git a/src/gui/editlocallymanager.h b/src/gui/editlocallymanager.h
new file mode 100644 (file)
index 0000000..3ba414f
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) by Claudio Cambra <claudio.cambra@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License
+ * for more details.
+ */
+
+#pragma once
+
+#include <QObject>
+#include <QHash>
+
+#include "editlocallyhandler.h"
+
+namespace OCC {
+
+class EditLocallyManager : public QObject
+{
+    Q_OBJECT
+
+public:
+    [[nodiscard]] static EditLocallyManager *instance();
+
+    QHash<QString, QMetaObject::Connection> folderSyncFinishedConnections;
+
+public slots:
+    void editLocally(const QUrl &url);
+
+private slots:
+    void createHandler(const QString &userId,
+                       const QString &relPath,
+                       const QString &token);
+
+private:
+    explicit EditLocallyManager(QObject *parent = nullptr);
+    static EditLocallyManager *_instance;
+
+    struct EditLocallyInputData {
+        QString userId;
+        QString relPath;
+        QString token;
+    };
+
+    [[nodiscard]] static EditLocallyInputData parseEditLocallyUrl(const QUrl &url);
+
+    QHash<QString, EditLocallyHandlerPtr> _handlers;
+};
+
+}