Skip to content

Commit

Permalink
Apply display commands to tray menu items too
Browse files Browse the repository at this point in the history
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
  • Loading branch information
hluk committed Dec 10, 2023
1 parent 6ebfa1b commit 8cf4dab
Show file tree
Hide file tree
Showing 12 changed files with 109 additions and 21 deletions.
7 changes: 7 additions & 0 deletions docs/scripting-api.rst
Expand Up @@ -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
--------------

Expand Down
1 change: 1 addition & 0 deletions src/common/mimetypes.cpp
Expand Up @@ -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");
1 change: 1 addition & 0 deletions src/common/mimetypes.h
Expand Up @@ -22,3 +22,4 @@ extern const QLatin1String mimeHidden;
extern const QLatin1String mimeShortcut;
extern const QLatin1String mimeColor;
extern const QLatin1String mimeOutputTab;
extern const QLatin1String mimeDisplayItemInMenu;
1 change: 1 addition & 0 deletions src/gui/commandcompleterdocumentation.h
Expand Up @@ -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).");
Expand Down
10 changes: 8 additions & 2 deletions src/gui/mainwindow.cpp
Expand Up @@ -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;
}
}
Expand Down
43 changes: 30 additions & 13 deletions src/gui/traymenu.cpp
Expand Up @@ -20,6 +20,8 @@

namespace {

const char propertyTextFormat[] = "CopyQ_text_format";

const QIcon iconClipboard() { return getIcon("clipboard", IconPaste); }

bool canActivate(const QAction &action)
Expand Down Expand Up @@ -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() )
Expand All @@ -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);
Expand All @@ -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()
Expand Down
5 changes: 4 additions & 1 deletion src/gui/traymenu.h
Expand Up @@ -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();

Expand Down
25 changes: 20 additions & 5 deletions src/item/persistentdisplayitem.cpp
Expand Up @@ -2,8 +2,11 @@

#include "persistentdisplayitem.h"

#include "gui/traymenu.h"
#include "item/itemdelegate.h"

#include <QAction>

PersistentDisplayItem::PersistentDisplayItem(ItemDelegate *delegate,
const QVariantMap &data,
QWidget *widget)
Expand All @@ -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);
}
}
4 changes: 4 additions & 0 deletions src/item/persistentdisplayitem.h
Expand Up @@ -9,6 +9,7 @@
#include <QVariantMap>

class ItemDelegate;
class QAction;
class QModelIndex;
class QWidget;
class QString;
Expand All @@ -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.
*
Expand All @@ -48,6 +51,7 @@ class PersistentDisplayItem final
private:
QVariantMap m_data;
QPointer<QWidget> m_widget;
QPointer<QAction> m_action;
QPointer<ItemDelegate> m_delegate;
};

Expand Down
2 changes: 2 additions & 0 deletions src/scriptable/scriptable.h
Expand Up @@ -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)

Expand Down Expand Up @@ -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();

Expand Down
30 changes: 30 additions & 0 deletions src/tests/tests.cpp
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/tests/tests.h
Expand Up @@ -250,6 +250,7 @@ private slots:
void scriptCommandEndingWithComment();
void scriptCommandWithError();
void displayCommand();
void displayCommandForMenu();

void synchronizeInternalCommands();

Expand Down

0 comments on commit 8cf4dab

Please sign in to comment.