SocketAPI: Make it easier to add or remove item in the action menu

By making it dynamic.
So far only the dolphin shell extension have been ported
This commit is contained in:
Olivier Goffart 2018-01-18 15:17:29 +01:00 коммит произвёл Olivier Goffart
Родитель 59f2e0634e
Коммит 1782ae3c08
5 изменённых файлов: 120 добавлений и 21 удалений

Просмотреть файл

@ -17,8 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
******************************************************************************/
#include <KPluginFactory>
#include <KPluginLoader>
#include <KCoreAddons/KPluginFactory>
#include <KCoreAddons/KPluginLoader>
#include <KIOWidgets/kabstractfileitemactionplugin.h>
#include <QtNetwork/QLocalSocket>
#include <KIOCore/kfileitem.h>
@ -27,6 +27,7 @@
#include <QtWidgets/QMenu>
#include <QtCore/QDir>
#include <QtCore/QTimer>
#include <QtCore/QEventLoop>
#include "ownclouddolphinpluginhelper.h"
class OwncloudDolphinPluginAction : public KAbstractFileItemActionPlugin
@ -39,22 +40,70 @@ public:
QList<QAction*> actions(const KFileItemListProperties& fileItemInfos, QWidget* parentWidget) Q_DECL_OVERRIDE
{
auto helper = OwncloudDolphinPluginHelper::instance();
QList<QUrl> urls = fileItemInfos.urlList();
if (urls.count() != 1 || !helper->isConnected())
if (!helper->isConnected() || !fileItemInfos.isLocal())
return {};
auto url = urls.first();
if (!url.isLocalFile())
return {};
QDir localPath(url.toLocalFile());
auto localFile = localPath.canonicalPath();
// If any of the url is outside of a sync folder, return an empty menu.
const QList<QUrl> urls = fileItemInfos.urlList();
const auto paths = helper->paths();
if (!std::any_of(paths.begin(), paths.end(), [&](const QString &s) {
return localFile.startsWith(s);
} ))
return {};
QByteArray files;
for (const auto &url : urls) {
QDir localPath(url.toLocalFile());
auto localFile = localPath.canonicalPath();
if (!std::any_of(paths.begin(), paths.end(), [&](const QString &s) {
return localFile.startsWith(s);
}))
return {};
if (!files.isEmpty())
files += '\x1e'; // Record separator
files += localFile.toUtf8();
}
if (helper->version() < "1.1") { // in this case, lexicographic order works
return legacyActions(fileItemInfos, parentWidget);
}
auto menu = new QMenu(parentWidget);
QEventLoop loop;
auto con = connect(helper, &OwncloudDolphinPluginHelper::commandRecieved, this, [&](const QByteArray &cmd) {
if (cmd.startsWith("GET_MENU_ITEMS:END")) {
loop.quit();
} else if (cmd.startsWith("MENU_ITEM:")) {
auto args = QString::fromUtf8(cmd).split(QLatin1Char(':'));
if (args.size() < 3)
return;
auto action = menu->addAction(args.mid(2).join(QLatin1Char(':')));
auto call = args.value(1).toLatin1();
connect(action, &QAction::triggered, [helper, call, files] {
helper->sendCommand(QByteArray(call + ":" + files + "\n"));
});
}
});
QTimer::singleShot(100, &loop, SLOT(quit())); // add a timeout to be sure we don't freeze dolphin
helper->sendCommand(QByteArray("GET_MENU_ITEMS:" + files + "\n"));
loop.exec(QEventLoop::ExcludeUserInputEvents);
disconnect(con);
if (menu->actions().isEmpty()) {
delete menu;
return {};
}
auto menuaction = new QAction(parentWidget);
menuaction->setText(helper->contextMenuTitle());
menuaction->setMenu(menu);
return { menuaction };
}
QList<QAction *> legacyActions(const KFileItemListProperties &fileItemInfos, QWidget *parentWidget)
{
QList<QUrl> urls = fileItemInfos.urlList();
if (urls.count() != 1)
return {};
QDir localPath(urls.first().toLocalFile());
auto localFile = localPath.canonicalPath();
auto helper = OwncloudDolphinPluginHelper::instance();
auto menuaction = new QAction(parentWidget);
menuaction->setText(helper->contextMenuTitle());
auto menu = new QMenu(parentWidget);
@ -62,8 +111,8 @@ public:
auto shareAction = menu->addAction(helper->shareActionTitle());
connect(shareAction, &QAction::triggered, this, [localFile, helper] {
helper->sendCommand(QByteArray("SHARE:"+localFile.toUtf8()+"\n"));
} );
helper->sendCommand(QByteArray("SHARE:" + localFile.toUtf8() + "\n"));
});
if (!helper->copyPrivateLinkTitle().isEmpty()) {
auto copyPrivateLinkAction = menu->addAction(helper->copyPrivateLinkTitle());
@ -78,7 +127,6 @@ public:
helper->sendCommand(QByteArray("EMAIL_PRIVATE_LINK:" + localFile.toUtf8() + "\n"));
});
}
return { menuaction };
}

Просмотреть файл

@ -59,6 +59,7 @@ void OwncloudDolphinPluginHelper::sendCommand(const char* data)
void OwncloudDolphinPluginHelper::slotConnected()
{
sendCommand("VERSION:\n");
sendCommand("GET_STRINGS:\n");
}
@ -98,6 +99,16 @@ void OwncloudDolphinPluginHelper::slotReadyRead()
_strings[args[1]] = args.mid(2).join(QLatin1Char(':'));
}
continue;
} else if (line.startsWith("VERSION:")) {
auto args = line.split(':');
auto version = args.value(2);
_version = version;
if (!version.startsWith("1.")) {
// Incompatible version, disconnect forever
_connectTimer.stop();
_socket.disconnectFromServer();
return;
}
}
emit commandRecieved(line);
}

Просмотреть файл

@ -21,6 +21,7 @@
#include <QObject>
#include <QBasicTimer>
#include <QLocalSocket>
#include <QRegularExpression>
#include "ownclouddolphinpluginhelper_export.h"
class OWNCLOUDDOLPHINPLUGINHELPER_EXPORT OwncloudDolphinPluginHelper : public QObject {
@ -44,6 +45,8 @@ public:
QString copyPrivateLinkTitle() const { return _strings["COPY_PRIVATE_LINK_MENU_TITLE"]; }
QString emailPrivateLinkTitle() const { return _strings["EMAIL_PRIVATE_LINK_MENU_TITLE"]; }
QByteArray version() { return _version; }
signals:
void commandRecieved(const QByteArray &cmd);
@ -61,4 +64,5 @@ private:
QBasicTimer _connectTimer;
QMap<QString, QString> _strings;
QByteArray _version;
};

Просмотреть файл

@ -54,7 +54,7 @@
// This is the version that is returned when the client asks for the VERSION.
// The first number should be changed if there is an incompatible change that breaks old clients.
// The second number should be changed when there are new features.
#define MIRALL_SOCKET_API_VERSION "1.0"
#define MIRALL_SOCKET_API_VERSION "1.1"
static inline QString removeTrailingSlash(QString path)
{
@ -535,7 +535,7 @@ void SocketApi::emailPrivateLink(const QString &link) const
0);
}
void SocketApi::command_GET_STRINGS(const QString &, SocketListener *listener)
void SocketApi::command_GET_STRINGS(const QString &argument, SocketListener *listener)
{
static std::array<std::pair<const char *, QString>, 5> strings { {
{ "SHARE_MENU_TITLE", tr("Share...") },
@ -545,11 +545,37 @@ void SocketApi::command_GET_STRINGS(const QString &, SocketListener *listener)
} };
listener->sendMessage(QString("GET_STRINGS:BEGIN"));
for (auto key_value : strings) {
listener->sendMessage(QString("STRING:%1:%2").arg(key_value.first, key_value.second));
if (argument.isEmpty() || argument == QLatin1String(key_value.first)) {
listener->sendMessage(QString("STRING:%1:%2").arg(key_value.first, key_value.second));
}
}
listener->sendMessage(QString("GET_STRINGS:END"));
}
void SocketApi::command_GET_MENU_ITEMS(const QString &argument, OCC::SocketListener *listener)
{
listener->sendMessage(QString("GET_MENU_ITEMS:BEGIN"));
bool hasSeveralFiles = argument.contains(QLatin1Char('\x1e')); // Record Separator
Folder *syncFolder = hasSeveralFiles ? nullptr : FolderMan::instance()->folderForPath(argument);
if (syncFolder) {
QString systemPath = QDir::cleanPath(argument);
if (systemPath.endsWith(QLatin1Char('/'))) {
systemPath.truncate(systemPath.length() - 1);
}
QString relativePath = systemPath.mid(syncFolder->cleanPath().length() + 1);
SyncJournalFileRecord rec;
if (syncFolder->accountState()->isConnected() && syncFolder->journalDb()->getFileRecord(relativePath, &rec) && rec.isValid()) {
// If the file is on the DB, it is on the server
// TODO: check if sharing is allowed
listener->sendMessage(QLatin1String("MENU_ITEM:SHARE:") + tr("Share..."));
listener->sendMessage(QLatin1String("MENU_ITEM:COPY_PRIVATE_LINK:") + tr("Copy private link to clipboard"));
listener->sendMessage(QLatin1String("MENU_ITEM:EMAIL_PRIVATE_LINK:") + tr("Send private link by email..."));
}
}
listener->sendMessage(QString("GET_MENU_ITEMS:END"));
}
QString SocketApi::buildRegisterPathMessage(const QString &path)
{
QFileInfo fi(path);

Просмотреть файл

@ -83,9 +83,19 @@ private:
Q_INVOKABLE void command_COPY_PRIVATE_LINK(const QString &localFile, SocketListener *listener);
Q_INVOKABLE void command_EMAIL_PRIVATE_LINK(const QString &localFile, SocketListener *listener);
/** Sends translated/branded strings that may be useful to the integration */
/** Sends translated/branded strings that may be useful to the integration
* Note: Deprecated, only used for compatibility with older shell_integrations (version 1.0)
*/
Q_INVOKABLE void command_GET_STRINGS(const QString &argument, SocketListener *listener);
/** Send the list of menu item. (added in version 1.1)
* argument is a list of files for which the menu should be shown, separated by '\x1e'
* Reply with GET_MENU_ITEMS:BEGIN
* followed by several MENU_ITEM:[Action]::[Text]
* and ends with GET_MENU_ITEMS:END
*/
Q_INVOKABLE void command_GET_MENU_ITEMS(const QString &argument, SocketListener *listener);
QString buildRegisterPathMessage(const QString &path);
QSet<QString> _registeredAliases;