Skip to content

Commit

Permalink
Allow accessing selection in all commands
Browse files Browse the repository at this point in the history
Also makes selections more consistent and safer.

The downside is that this potentially breaks some existing scripts.

Fixes hluk/copyq-commands#97
  • Loading branch information
hluk committed Apr 24, 2024
1 parent b8edcb5 commit 51b440c
Show file tree
Hide file tree
Showing 9 changed files with 224 additions and 103 deletions.
40 changes: 25 additions & 15 deletions docs/scripting-api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -873,16 +873,14 @@ unlike in GUI, where row numbers start from 1 by default.

Returns tab that was selected when script was executed.

:returns: Currently selected tab name, empty if called outside the main
window context (see `Selected Items`_).
:returns: Currently selected tab name (see `Selected Items`_).
:rtype: string

.. js:function:: selectedItems()

Returns selected rows in current tab.

:returns: Currently selected rows, empty if called outside the main
window context (see `Selected Items`_).
:returns: Currently selected rows (see `Selected Items`_).
:rtype: array of ints

.. js:function:: selectedItemData(index)
Expand All @@ -892,8 +890,7 @@ unlike in GUI, where row numbers start from 1 by default.
The data can empty if the item was removed during execution of the
script.

:returns: Currently selected items, empty if called outside the main
window context (see `Selected Items`_).
:returns: Currently selected items (see `Selected Items`_).
:rtype: array of :js:class:`Item`

.. js:function:: setSelectedItemData(index, Item)
Expand All @@ -915,8 +912,7 @@ unlike in GUI, where row numbers start from 1 by default.
Some data can be empty if the item was removed during execution of the
script.

:returns: Currently selected item data, empty if called outside the main
window context (see `Selected Items`_).
:returns: Currently selected item data (see `Selected Items`_).
:rtype: array of :js:class:`Item`

.. js:function:: setSelectedItemsData(Item[])
Expand All @@ -935,8 +931,7 @@ unlike in GUI, where row numbers start from 1 by default.

See `Selected Items`_.

:returns: Current row, ``-1`` if called outside the main
window context (see `Selected Items`_).
:returns: Current row (see `Selected Items`_).
:rtype: int

.. js:function:: escapeHtml(text)
Expand Down Expand Up @@ -2247,12 +2242,27 @@ These MIME types values are assigned to global variables prefixed with
Selected Items
--------------

Functions that get and set data for selected items and current tab are
only available if called from Action dialog or from a command which is
in menu.
The internal state for currently evaluated script/command stores references
(not rows or item data) to the current and selected items and it do not change
after the state is retrieved from GUI.

Selected items are indexed from top to bottom as they appeared in the
current tab at the time the command is executed.
The state is retrieved before the script/command starts if it is invoked from
the application with a shortcut, from menu, toolbar or the Action dialog.
Otherwise, the state is retrieved when needed (for example the first
``selectedItems()`` call) for scripts/commands run externally (for example from
command line or from automatic commands on clipboard content change).

If a selected or current item is moved, script functions will return the new
rows. For example ``selectedItems()`` returning ``[0,1]`` will return ``[1,0]``
after the items are swapped. Same goes for selected item data.

If a selected or current item is removed, their references in the internal
state are invalidated. These references will return -1 for row and empty object
for item data. For example ``selectedItems()`` returning ``[0,1]`` will return
``[0,-1]`` after the item on the second row is removed.

If tab is renamed, all references to current and selected items are invalidated
because the tab data need to be initiated again.

Linux Mouse Selection
---------------------
Expand Down
57 changes: 5 additions & 52 deletions src/gui/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "gui/logdialog.h"
#include "gui/notification.h"
#include "gui/notificationdaemon.h"
#include "gui/selectiondata.h"
#include "gui/tabdialog.h"
#include "gui/tabicons.h"
#include "gui/tabwidget.h"
Expand Down Expand Up @@ -180,54 +181,6 @@ void disableActionWhenTabGroupSelected(WidgetOrAction *action, MainWindow *windo
action, &WidgetOrAction::setDisabled );
}

void addSelectionData(
QVariantMap *result,
const QList<QPersistentModelIndex> &selectedIndexes)
{
result->insert(mimeSelectedItems, QVariant::fromValue(selectedIndexes));
}

void addSelectionData(
QVariantMap *result,
const QModelIndexList &selectedIndexes)
{
QList<QPersistentModelIndex> selected;
selected.reserve(selectedIndexes.size());
for (const auto &index : selectedIndexes)
selected.append(index);
std::sort(selected.begin(), selected.end());
addSelectionData(result, selected);
}

/// Adds information about current tab and selection if command is triggered by user.
QVariantMap addSelectionData(
const ClipboardBrowser &c,
const QModelIndex &currentIndex,
const QModelIndexList &selectedIndexes)
{
auto result = c.copyIndexes(selectedIndexes);

result.insert(mimeCurrentTab, c.tabName());

if ( currentIndex.isValid() ) {
const QPersistentModelIndex current = currentIndex;
result.insert(mimeCurrentItem, QVariant::fromValue(current));
}

if ( !selectedIndexes.isEmpty() ) {
addSelectionData(&result, selectedIndexes);
}

return result;
}

QVariantMap addSelectionData(const ClipboardBrowser &c)
{
const QModelIndexList selectedIndexes = c.selectionModel()->selectedIndexes();
const auto current = c.selectionModel()->currentIndex();
return addSelectionData(c, current, selectedIndexes);
}

QMenu *findSubMenu(const QString &name, const QMenu &menu)
{
for (auto action : menu.actions()) {
Expand Down Expand Up @@ -1118,13 +1071,13 @@ void MainWindow::onItemCommandActionTriggered(CommandAction *commandAction, cons
if ( !command.cmd.isEmpty() ) {
if (command.transform) {
for (const auto &index : selected) {
auto actionData = addSelectionData(*c, index, {index});
auto actionData = selectionData(*c, index, {index});
if ( !triggeredShortcut.isEmpty() )
actionData.insert(mimeShortcut, triggeredShortcut);
action(actionData, command, index);
}
} else {
auto actionData = addSelectionData(*c);
auto actionData = selectionData(*c);
if ( !triggeredShortcut.isEmpty() )
actionData.insert(mimeShortcut, triggeredShortcut);
action(actionData, command, QModelIndex());
Expand Down Expand Up @@ -1580,7 +1533,7 @@ void MainWindow::addCommandsToItemMenu(ClipboardBrowser *c)
return;
}

auto data = addSelectionData(*c);
auto data = selectionData(*c);
const auto commands = commandsForMenu(data, c->tabName(), m_menuCommands);

for (const auto &command : commands) {
Expand Down Expand Up @@ -3692,7 +3645,7 @@ ActionDialog *MainWindow::openActionDialog(const QVariantMap &data)
void MainWindow::openActionDialog()
{
auto c = browser();
const auto data = c ? addSelectionData(*c) : QVariantMap();
const auto data = c ? selectionData(*c) : QVariantMap();
openActionDialog(data);
}

Expand Down
53 changes: 53 additions & 0 deletions src/gui/selectiondata.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "selectiondata.h"

#include "common/mimetypes.h"
#include "gui/clipboardbrowser.h"

void addSelectionData(
QVariantMap *result,
const QList<QPersistentModelIndex> &selectedIndexes)
{
result->insert(mimeSelectedItems, QVariant::fromValue(selectedIndexes));
}

void addSelectionData(
QVariantMap *result,
const QModelIndexList &selectedIndexes)
{
QList<QPersistentModelIndex> selected;
selected.reserve(selectedIndexes.size());
for (const auto &index : selectedIndexes)
selected.append(index);
std::sort(selected.begin(), selected.end());
addSelectionData(result, selected);
}

/// Adds information about current tab and selection if command is triggered by user.
QVariantMap selectionData(
const ClipboardBrowser &c,
const QModelIndex &currentIndex,
const QModelIndexList &selectedIndexes)
{
auto result = c.copyIndexes(selectedIndexes);

result.insert(mimeCurrentTab, c.tabName());

if ( currentIndex.isValid() ) {
const QPersistentModelIndex current = currentIndex;
result.insert(mimeCurrentItem, QVariant::fromValue(current));
}

if ( !selectedIndexes.isEmpty() ) {
addSelectionData(&result, selectedIndexes);
}

return result;
}

QVariantMap selectionData(const ClipboardBrowser &c)
{
const QModelIndexList selectedIndexes = c.selectionModel()->selectedIndexes();
const auto current = c.selectionModel()->currentIndex();
return selectionData(c, current, selectedIndexes);
}
24 changes: 24 additions & 0 deletions src/gui/selectiondata.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once

#include <QModelIndexList>
#include <QVariantMap>
#include <QtContainerFwd>

class ClipboardBrowser;

void addSelectionData(
QVariantMap *result,
const QList<QPersistentModelIndex> &selectedIndexes);

void addSelectionData(
QVariantMap *result,
const QModelIndexList &selectedIndexes);

/// Adds information about current tab and selection if command is triggered by user.
QVariantMap selectionData(
const ClipboardBrowser &c,
const QModelIndex &currentIndex,
const QModelIndexList &selectedIndexes);

QVariantMap selectionData(const ClipboardBrowser &c);
2 changes: 1 addition & 1 deletion src/scriptable/scriptable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1780,7 +1780,7 @@ QJSValue Scriptable::selectItems()
QJSValue Scriptable::selectedTab()
{
m_skipArguments = 0;
return m_data.value(mimeCurrentTab).toString();
return m_proxy->selectedTab();
}

QJSValue Scriptable::selectedItems()
Expand Down

0 comments on commit 51b440c

Please sign in to comment.