Skip to content

Commit

Permalink
[layout] Add context menu entries for cutting/copying, and pasting items
Browse files Browse the repository at this point in the history
Fixes #1830
  • Loading branch information
nyalldawson committed Dec 6, 2017
1 parent b03ce04 commit feec186
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 4 deletions.
8 changes: 8 additions & 0 deletions python/gui/layout/qgslayoutview.sip
Expand Up @@ -205,9 +205,17 @@ class QgsLayoutView: QGraphicsView
A list of pasted items is returned.

.. seealso:: copySelectedItems()
.. seealso:: hasItemsInClipboard()
:rtype: list of QgsLayoutItem
%End

bool hasItemsInClipboard() const;
%Docstring
Returns true if the current clipboard contains layout items.
.. seealso:: pasteItems()
:rtype: bool
%End

QPointF deltaForKeyEvent( QKeyEvent *event );
%Docstring
Returns the delta (in layout coordinates) by which to move items
Expand Down
24 changes: 24 additions & 0 deletions src/app/layout/qgslayoutappmenuprovider.cpp
Expand Up @@ -76,6 +76,30 @@ QMenu *QgsLayoutAppMenuProvider::createContextMenu( QWidget *parent, QgsLayout *

if ( addedGroupAction )
menu->addSeparator();

QAction *copyAction = new QAction( tr( "Copy" ), menu );
connect( copyAction, &QAction::triggered, this, [this]()
{
mDesigner->view()->copySelectedItems( QgsLayoutView::ClipboardCopy );
} );
menu->addAction( copyAction );
QAction *cutAction = new QAction( tr( "Cut" ), menu );
connect( cutAction, &QAction::triggered, this, [this]()
{
mDesigner->view()->copySelectedItems( QgsLayoutView::ClipboardCut );
} );
menu->addAction( cutAction );
menu->addSeparator();
}
else if ( mDesigner->view()->hasItemsInClipboard() )
{
QAction *pasteAction = new QAction( tr( "Paste" ), menu );
connect( pasteAction, &QAction::triggered, this, [this]()
{
mDesigner->paste();
} );
menu->addAction( pasteAction );
menu->addSeparator();
}

// is a page under the mouse?
Expand Down
15 changes: 12 additions & 3 deletions src/app/layout/qgslayoutdesignerdialog.h
Expand Up @@ -216,6 +216,18 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
*/
void refreshLayout();

/**
* Pastes items from the clipboard to the current layout.
* \see pasteInPlace()
*/
void paste();

/**
* Pastes item (in place) from the clipboard to the current layout.
* \see paste()
*/
void pasteInPlace();

signals:

/**
Expand Down Expand Up @@ -247,9 +259,6 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
void dockVisibilityChanged( bool visible );
void undoRedoOccurredForItems( const QSet< QString > itemUuids );

void paste();
void pasteInPlace();

private:

static bool sInitializedRegistry;
Expand Down
13 changes: 13 additions & 0 deletions src/gui/layout/qgslayoutview.cpp
Expand Up @@ -365,6 +365,19 @@ QList< QgsLayoutItem * > QgsLayoutView::pasteItems( QgsLayoutView::PasteMode mod
return pastedItems;
}

bool QgsLayoutView::hasItemsInClipboard() const
{
QDomDocument doc;
QClipboard *clipboard = QApplication::clipboard();
if ( doc.setContent( clipboard->mimeData()->data( QStringLiteral( "text/xml" ) ) ) )
{
QDomElement docElem = doc.documentElement();
if ( docElem.tagName() == QLatin1String( "LayoutItemClipboard" ) )
return true;
}
return false;
}

QPointF QgsLayoutView::deltaForKeyEvent( QKeyEvent *event )
{
// increment used for cursor key item movement
Expand Down
7 changes: 7 additions & 0 deletions src/gui/layout/qgslayoutview.h
Expand Up @@ -235,9 +235,16 @@ class GUI_EXPORT QgsLayoutView: public QGraphicsView
* A list of pasted items is returned.
*
* \see copySelectedItems()
* \see hasItemsInClipboard()
*/
QList< QgsLayoutItem * > pasteItems( PasteMode mode );

/**
* Returns true if the current clipboard contains layout items.
* \see pasteItems()
*/
bool hasItemsInClipboard() const;

/**
* Returns the delta (in layout coordinates) by which to move items
* for the given key \a event.
Expand Down
20 changes: 19 additions & 1 deletion tests/src/python/test_qgslayoutview.py
Expand Up @@ -23,8 +23,9 @@
QgsLayoutSize,
QgsLayoutAligner)
from qgis.gui import QgsLayoutView
from qgis.PyQt.QtCore import QRectF
from qgis.PyQt.QtCore import QRectF, QMimeData, QByteArray
from qgis.PyQt.QtGui import QTransform
from qgis.PyQt.QtWidgets import QApplication
from qgis.PyQt.QtTest import QSignalSpy

from qgis.testing import start_app, unittest
Expand Down Expand Up @@ -639,6 +640,12 @@ def testCopyPaste(self):
p = QgsProject()
l = QgsLayout(p)

# clear clipboard
mime_data = QMimeData()
mime_data.setData("text/xml", QByteArray())
clipboard = QApplication.clipboard()
clipboard.setMimeData(mime_data)

# add an item
item1 = QgsLayoutItemLabel(l)
item1.setText('label 1')
Expand All @@ -651,8 +658,11 @@ def testCopyPaste(self):

view = QgsLayoutView()
view.setCurrentLayout(l)
self.assertFalse(view.hasItemsInClipboard())

view.copySelectedItems(QgsLayoutView.ClipboardCopy)
self.assertTrue(view.hasItemsInClipboard())

pasted = view.pasteItems(QgsLayoutView.PasteModeCursor)
self.assertEqual(len(pasted), 2)
self.assertIn(pasted[0], l.items())
Expand All @@ -664,6 +674,12 @@ def testCutPaste(self):
p = QgsProject()
l = QgsLayout(p)

# clear clipboard
mime_data = QMimeData()
mime_data.setData("text/xml", QByteArray())
clipboard = QApplication.clipboard()
clipboard.setMimeData(mime_data)

# add an item
item1 = QgsLayoutItemLabel(l)
item1.setText('label 1')
Expand All @@ -676,9 +692,11 @@ def testCutPaste(self):

view = QgsLayoutView()
view.setCurrentLayout(l)
self.assertFalse(view.hasItemsInClipboard())

len_before = len(l.items())
view.copySelectedItems(QgsLayoutView.ClipboardCut)
self.assertTrue(view.hasItemsInClipboard())
self.assertEqual(len(l.items()), len_before - 2)

pasted = view.pasteItems(QgsLayoutView.PasteModeCursor)
Expand Down

0 comments on commit feec186

Please sign in to comment.