From 8cf4dab51fb88940d2d6821a9fc0ff0a11ac80d8 Mon Sep 17 00:00:00 2001 From: Lukas Holecek Date: Sat, 9 Dec 2023 11:02:50 +0100 Subject: [PATCH] Apply display commands to tray menu items too In the display command, the format stored in `mimeDisplayItemInMenu` indicates whether the display item data are related to a menu item instead of an item list. Fixes hluk/copyq-commands#79 --- docs/scripting-api.rst | 7 ++++ src/common/mimetypes.cpp | 1 + src/common/mimetypes.h | 1 + src/gui/commandcompleterdocumentation.h | 1 + src/gui/mainwindow.cpp | 10 ++++-- src/gui/traymenu.cpp | 43 +++++++++++++++++-------- src/gui/traymenu.h | 5 ++- src/item/persistentdisplayitem.cpp | 25 +++++++++++--- src/item/persistentdisplayitem.h | 4 +++ src/scriptable/scriptable.h | 2 ++ src/tests/tests.cpp | 30 +++++++++++++++++ src/tests/tests.h | 1 + 12 files changed, 109 insertions(+), 21 deletions(-) diff --git a/docs/scripting-api.rst b/docs/scripting-api.rst index 1f2d06bd48..537a2870d8 100644 --- a/docs/scripting-api.rst +++ b/docs/scripting-api.rst @@ -2161,6 +2161,13 @@ These MIME types values are assigned to global variables prefixed with Valid only in automatic commands. +.. js:data:: mimeDisplayItemInMenu + + Indicates if display commands run for a menu. Value: 'application/x-copyq-display-item-in-menu'. + + Set to "1" for display commands if the item data is related to a menu item + instead of an item list. + Selected Items -------------- diff --git a/src/common/mimetypes.cpp b/src/common/mimetypes.cpp index 1da4dc4869..07c832af93 100644 --- a/src/common/mimetypes.cpp +++ b/src/common/mimetypes.cpp @@ -21,3 +21,4 @@ const QLatin1String mimeHidden(COPYQ_MIME_PREFIX "hidden"); const QLatin1String mimeShortcut(COPYQ_MIME_PREFIX "shortcut"); const QLatin1String mimeColor(COPYQ_MIME_PREFIX "color"); const QLatin1String mimeOutputTab(COPYQ_MIME_PREFIX "output-tab"); +const QLatin1String mimeDisplayItemInMenu(COPYQ_MIME_PREFIX "display-item-in-menu"); diff --git a/src/common/mimetypes.h b/src/common/mimetypes.h index 8d0643a7ed..b1dbbe4a3b 100644 --- a/src/common/mimetypes.h +++ b/src/common/mimetypes.h @@ -22,3 +22,4 @@ extern const QLatin1String mimeHidden; extern const QLatin1String mimeShortcut; extern const QLatin1String mimeColor; extern const QLatin1String mimeOutputTab; +extern const QLatin1String mimeDisplayItemInMenu; diff --git a/src/gui/commandcompleterdocumentation.h b/src/gui/commandcompleterdocumentation.h index e93071c1a9..8727574154 100644 --- a/src/gui/commandcompleterdocumentation.h +++ b/src/gui/commandcompleterdocumentation.h @@ -200,6 +200,7 @@ void addDocumentation(AddDocumentationCallback addDocumentation) addDocumentation("mimeShortcut", "mimeShortcut", "Application or global shortcut which activated the command. Value: 'application/x-copyq-shortcut'."); addDocumentation("mimeColor", "mimeColor", "Item color (same as the one used by themes). Value: 'application/x-copyq-color'."); addDocumentation("mimeOutputTab", "mimeOutputTab", "Name of the tab where to store new item. Value: 'application/x-copyq-output-tab'."); + addDocumentation("mimeDisplayItemInMenu", "mimeDisplayItemInMenu", "Indicates if display commands run for a menu. Value: 'application/x-copyq-display-item-in-menu'."); addDocumentation("plugins.itemsync.selectedTabPath", "plugins.itemsync.selectedTabPath()", "Returns synchronization path for current tab (mimeCurrentTab)."); addDocumentation("plugins.itemsync.tabPaths", "plugins.itemsync.tabPaths", "Object that maps tab name to synchronization path."); addDocumentation("plugins.itemsync.mimeBaseName", "plugins.itemsync.mimeBaseName", "MIME type for accessing base name (without full path)."); diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index 88ab14ad98..7d8ea4d796 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -1836,8 +1836,14 @@ void MainWindow::addMenuItems(TrayMenu *menu, ClipboardBrowserPlaceholder *place const QModelIndex index = c->model()->index(i, 0); if ( !searchText.isEmpty() && !menuItemMatches(index, searchText) ) continue; - const QVariantMap data = index.data(contentType::data).toMap(); - menu->addClipboardItemAction(data, m_options.trayImages); + QVariantMap data = index.data(contentType::data).toMap(); + QAction *act = menu->addClipboardItemAction(data, m_options.trayImages); + if ( !m_displayCommands.isEmpty() ) { + data.insert(mimeCurrentTab, c->tabName()); + data.insert(mimeDisplayItemInMenu, QByteArrayLiteral("1")); + PersistentDisplayItem item(act, data); + onItemWidgetCreated(item); + } ++itemCount; } } diff --git a/src/gui/traymenu.cpp b/src/gui/traymenu.cpp index 0d012eb107..5923ae8145 100644 --- a/src/gui/traymenu.cpp +++ b/src/gui/traymenu.cpp @@ -20,6 +20,8 @@ namespace { +const char propertyTextFormat[] = "CopyQ_text_format"; + const QIcon iconClipboard() { return getIcon("clipboard", IconPaste); } bool canActivate(const QAction &action) @@ -65,7 +67,29 @@ TrayMenu::TrayMenu(QWidget *parent) setAttribute(Qt::WA_InputMethodEnabled); } -void TrayMenu::addClipboardItemAction(const QVariantMap &data, bool showImages) +void TrayMenu::updateTextFromData(QAction *act, const QVariantMap &data) +{ + const QString format = act->property(propertyTextFormat).toString(); + const QString label = textLabelForData( data, act->font(), format, true ); + act->setText(label); +} + +bool TrayMenu::updateIconFromData(QAction *act, const QVariantMap &data) +{ + if ( !act->parentWidget() ) + return false; + + const QString icon = data.value(mimeIcon).toString(); + const QString tag = data.value(COPYQ_MIME_PREFIX "item-tag").toString(); + if ( icon.isEmpty() && tag.isEmpty() ) + return false; + + const QColor color = getDefaultIconColor(*act->parentWidget()); + act->setIcon( iconFromFile(icon, tag, color) ); + return true; +} + +QAction *TrayMenu::addClipboardItemAction(const QVariantMap &data, bool showImages) { // Show search text at top of the menu. if ( m_clipboardItemActionCount == 0 && m_searchText.isEmpty() ) @@ -86,15 +110,15 @@ void TrayMenu::addClipboardItemAction(const QVariantMap &data, bool showImages) format = tr("&%1. %2", "Key hint (number shortcut) for items in tray menu (%1 is number, %2 is item label)") .arg(rowNumber); + act->setProperty(propertyTextFormat, format); } m_clipboardItemActionCount++; - const QString label = textLabelForData( data, act->font(), format, true ); - act->setText(label); + updateTextFromData(act, data); // Menu item icon from image. - if (showImages) { + if (!updateIconFromData(act, data) && showImages) { const QStringList formats = data.keys(); static const QRegularExpression reImage("^image/.*"); const int imageIndex = formats.indexOf(reImage); @@ -117,16 +141,9 @@ void TrayMenu::addClipboardItemAction(const QVariantMap &data, bool showImages) } } - if ( act->icon().isNull() ) { - const QString icon = data.value(mimeIcon).toString(); - if ( !icon.isEmpty() ) { - const QColor color = getDefaultIconColor(*this); - const QString tag = data.value(COPYQ_MIME_PREFIX "item-tag").toString(); - act->setIcon( iconFromFile(icon, tag, color) ); - } - } - connect(act, &QAction::triggered, this, &TrayMenu::onClipboardItemActionTriggered); + + return act; } void TrayMenu::clearClipboardItems() diff --git a/src/gui/traymenu.h b/src/gui/traymenu.h index e53e7fbfa7..3ed68f0d2b 100644 --- a/src/gui/traymenu.h +++ b/src/gui/traymenu.h @@ -16,12 +16,15 @@ class TrayMenu final : public QMenu public: explicit TrayMenu(QWidget *parent = nullptr); + static void updateTextFromData(QAction *act, const QVariantMap &data); + static bool updateIconFromData(QAction *act, const QVariantMap &data); + /** * Add clipboard item action with number key hint. * * Triggering this action emits clipboardItemActionTriggered() signal. */ - void addClipboardItemAction(const QVariantMap &data, bool showImages); + QAction *addClipboardItemAction(const QVariantMap &data, bool showImages); void clearClipboardItems(); diff --git a/src/item/persistentdisplayitem.cpp b/src/item/persistentdisplayitem.cpp index 994bb0f9c1..a69ba79ad0 100644 --- a/src/item/persistentdisplayitem.cpp +++ b/src/item/persistentdisplayitem.cpp @@ -2,8 +2,11 @@ #include "persistentdisplayitem.h" +#include "gui/traymenu.h" #include "item/itemdelegate.h" +#include + PersistentDisplayItem::PersistentDisplayItem(ItemDelegate *delegate, const QVariantMap &data, QWidget *widget) @@ -13,16 +16,28 @@ PersistentDisplayItem::PersistentDisplayItem(ItemDelegate *delegate, { } -bool PersistentDisplayItem::isValid() +PersistentDisplayItem::PersistentDisplayItem(QAction *action, const QVariantMap &data) + : m_data(data) + , m_action(action) { - if ( m_widget.isNull() || m_delegate.isNull() ) - return false; +} - return !m_delegate->invalidateHidden( m_widget.data() ); +bool PersistentDisplayItem::isValid() +{ + return !m_action.isNull() || ( + !m_widget.isNull() && !m_delegate.isNull() + && !m_delegate->invalidateHidden(m_widget.data()) ); } void PersistentDisplayItem::setData(const QVariantMap &data) { - if ( !data.isEmpty() && isValid() && m_delegate && data != m_data ) + if ( data.isEmpty() || data == m_data ) + return; + + if ( !m_action.isNull() ) { + TrayMenu::updateTextFromData(m_action, data); + TrayMenu::updateIconFromData(m_action, data); + } else if ( !m_widget.isNull() && !m_delegate.isNull() ) { m_delegate->updateWidget(m_widget, data); + } } diff --git a/src/item/persistentdisplayitem.h b/src/item/persistentdisplayitem.h index afcea0d6ff..b4fa9b9b87 100644 --- a/src/item/persistentdisplayitem.h +++ b/src/item/persistentdisplayitem.h @@ -9,6 +9,7 @@ #include class ItemDelegate; +class QAction; class QModelIndex; class QWidget; class QString; @@ -26,6 +27,8 @@ class PersistentDisplayItem final PersistentDisplayItem( ItemDelegate *delegate, const QVariantMap &data, QWidget *widget); + PersistentDisplayItem(QAction *action, const QVariantMap &data); + /** * Returns display data of the item. * @@ -48,6 +51,7 @@ class PersistentDisplayItem final private: QVariantMap m_data; QPointer m_widget; + QPointer m_action; QPointer m_delegate; }; diff --git a/src/scriptable/scriptable.h b/src/scriptable/scriptable.h index 8e24758012..8c21f45c5e 100644 --- a/src/scriptable/scriptable.h +++ b/src/scriptable/scriptable.h @@ -50,6 +50,7 @@ class Scriptable final : public QObject Q_PROPERTY(QJSValue mimeShortcut READ getMimeShortcut CONSTANT) Q_PROPERTY(QJSValue mimeColor READ getMimeColor CONSTANT) Q_PROPERTY(QJSValue mimeOutputTab READ getMimeOutputTab CONSTANT) + Q_PROPERTY(QJSValue mimeDisplayItemInMenu READ getMimeDisplayItemInMenu CONSTANT) Q_PROPERTY(QJSValue plugins READ getPlugins CONSTANT) @@ -134,6 +135,7 @@ class Scriptable final : public QObject QJSValue getMimeShortcut() const { return mimeShortcut; } QJSValue getMimeColor() const { return mimeColor; } QJSValue getMimeOutputTab() const { return mimeOutputTab; } + QJSValue getMimeDisplayItemInMenu() const { return mimeDisplayItemInMenu; } QJSValue getPlugins(); diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp index fed9e97971..4a59273e80 100644 --- a/src/tests/tests.cpp +++ b/src/tests/tests.cpp @@ -3986,6 +3986,36 @@ void Tests::displayCommand() .toUtf8() ); } +void Tests::displayCommandForMenu() +{ + const auto tab = testTab(1); + const auto args = Args("tab") << tab << "separator" << ","; + const auto script = QString(R"( + setCommands([{ + display: true, + cmd: 'copyq:' + + 'currentTab = str(data(mimeCurrentTab));' + + 'inMenu = str(data(mimeDisplayItemInMenu));' + + 'if (inMenu != "1" || currentTab != "%1") abort();' + + 'text = str(data(mimeText));' + + 'setData(mimeText, "display:" + text);' + + 'setData(mimeIcon, String.fromCharCode(0xF328));' + + 'setData("application/x-copyq-item-tag", "TAG");' + + 'tab(tab()[0]);' + + 'old = str(read(0));' + + 'add(old + "|" + text);' + }]) + )").arg(tab); + + RUN("config" << "tray_tab" << tab, tab + "\n"); + RUN("config" << "tray_tab_is_current" << "false", "false\n"); + RUN(script, ""); + + RUN(args << "add(1,2,3,4,5)", ""); + RUN("menu", ""); + WAIT_ON_OUTPUT("read(0)", "|5|4|3|2|1"); +} + void Tests::synchronizeInternalCommands() { // Keep internal commands synced with the latest version diff --git a/src/tests/tests.h b/src/tests/tests.h index fcb8e9a70f..bf668600c0 100644 --- a/src/tests/tests.h +++ b/src/tests/tests.h @@ -250,6 +250,7 @@ private slots: void scriptCommandEndingWithComment(); void scriptCommandWithError(); void displayCommand(); + void displayCommandForMenu(); void synchronizeInternalCommands();