Skip to content

Commit feec186

Browse files
committedDec 6, 2017
[layout] Add context menu entries for cutting/copying, and pasting items
Fixes #1830
1 parent b03ce04 commit feec186

File tree

6 files changed

+83
-4
lines changed

6 files changed

+83
-4
lines changed
 

‎python/gui/layout/qgslayoutview.sip

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,17 @@ class QgsLayoutView: QGraphicsView
205205
A list of pasted items is returned.
206206

207207
.. seealso:: copySelectedItems()
208+
.. seealso:: hasItemsInClipboard()
208209
:rtype: list of QgsLayoutItem
209210
%End
210211

212+
bool hasItemsInClipboard() const;
213+
%Docstring
214+
Returns true if the current clipboard contains layout items.
215+
.. seealso:: pasteItems()
216+
:rtype: bool
217+
%End
218+
211219
QPointF deltaForKeyEvent( QKeyEvent *event );
212220
%Docstring
213221
Returns the delta (in layout coordinates) by which to move items

‎src/app/layout/qgslayoutappmenuprovider.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,30 @@ QMenu *QgsLayoutAppMenuProvider::createContextMenu( QWidget *parent, QgsLayout *
7676

7777
if ( addedGroupAction )
7878
menu->addSeparator();
79+
80+
QAction *copyAction = new QAction( tr( "Copy" ), menu );
81+
connect( copyAction, &QAction::triggered, this, [this]()
82+
{
83+
mDesigner->view()->copySelectedItems( QgsLayoutView::ClipboardCopy );
84+
} );
85+
menu->addAction( copyAction );
86+
QAction *cutAction = new QAction( tr( "Cut" ), menu );
87+
connect( cutAction, &QAction::triggered, this, [this]()
88+
{
89+
mDesigner->view()->copySelectedItems( QgsLayoutView::ClipboardCut );
90+
} );
91+
menu->addAction( cutAction );
92+
menu->addSeparator();
93+
}
94+
else if ( mDesigner->view()->hasItemsInClipboard() )
95+
{
96+
QAction *pasteAction = new QAction( tr( "Paste" ), menu );
97+
connect( pasteAction, &QAction::triggered, this, [this]()
98+
{
99+
mDesigner->paste();
100+
} );
101+
menu->addAction( pasteAction );
102+
menu->addSeparator();
79103
}
80104

81105
// is a page under the mouse?

‎src/app/layout/qgslayoutdesignerdialog.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,18 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
216216
*/
217217
void refreshLayout();
218218

219+
/**
220+
* Pastes items from the clipboard to the current layout.
221+
* \see pasteInPlace()
222+
*/
223+
void paste();
224+
225+
/**
226+
* Pastes item (in place) from the clipboard to the current layout.
227+
* \see paste()
228+
*/
229+
void pasteInPlace();
230+
219231
signals:
220232

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

250-
void paste();
251-
void pasteInPlace();
252-
253262
private:
254263

255264
static bool sInitializedRegistry;

‎src/gui/layout/qgslayoutview.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,19 @@ QList< QgsLayoutItem * > QgsLayoutView::pasteItems( QgsLayoutView::PasteMode mod
365365
return pastedItems;
366366
}
367367

368+
bool QgsLayoutView::hasItemsInClipboard() const
369+
{
370+
QDomDocument doc;
371+
QClipboard *clipboard = QApplication::clipboard();
372+
if ( doc.setContent( clipboard->mimeData()->data( QStringLiteral( "text/xml" ) ) ) )
373+
{
374+
QDomElement docElem = doc.documentElement();
375+
if ( docElem.tagName() == QLatin1String( "LayoutItemClipboard" ) )
376+
return true;
377+
}
378+
return false;
379+
}
380+
368381
QPointF QgsLayoutView::deltaForKeyEvent( QKeyEvent *event )
369382
{
370383
// increment used for cursor key item movement

‎src/gui/layout/qgslayoutview.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,9 +235,16 @@ class GUI_EXPORT QgsLayoutView: public QGraphicsView
235235
* A list of pasted items is returned.
236236
*
237237
* \see copySelectedItems()
238+
* \see hasItemsInClipboard()
238239
*/
239240
QList< QgsLayoutItem * > pasteItems( PasteMode mode );
240241

242+
/**
243+
* Returns true if the current clipboard contains layout items.
244+
* \see pasteItems()
245+
*/
246+
bool hasItemsInClipboard() const;
247+
241248
/**
242249
* Returns the delta (in layout coordinates) by which to move items
243250
* for the given key \a event.

‎tests/src/python/test_qgslayoutview.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@
2323
QgsLayoutSize,
2424
QgsLayoutAligner)
2525
from qgis.gui import QgsLayoutView
26-
from qgis.PyQt.QtCore import QRectF
26+
from qgis.PyQt.QtCore import QRectF, QMimeData, QByteArray
2727
from qgis.PyQt.QtGui import QTransform
28+
from qgis.PyQt.QtWidgets import QApplication
2829
from qgis.PyQt.QtTest import QSignalSpy
2930

3031
from qgis.testing import start_app, unittest
@@ -639,6 +640,12 @@ def testCopyPaste(self):
639640
p = QgsProject()
640641
l = QgsLayout(p)
641642

643+
# clear clipboard
644+
mime_data = QMimeData()
645+
mime_data.setData("text/xml", QByteArray())
646+
clipboard = QApplication.clipboard()
647+
clipboard.setMimeData(mime_data)
648+
642649
# add an item
643650
item1 = QgsLayoutItemLabel(l)
644651
item1.setText('label 1')
@@ -651,8 +658,11 @@ def testCopyPaste(self):
651658

652659
view = QgsLayoutView()
653660
view.setCurrentLayout(l)
661+
self.assertFalse(view.hasItemsInClipboard())
654662

655663
view.copySelectedItems(QgsLayoutView.ClipboardCopy)
664+
self.assertTrue(view.hasItemsInClipboard())
665+
656666
pasted = view.pasteItems(QgsLayoutView.PasteModeCursor)
657667
self.assertEqual(len(pasted), 2)
658668
self.assertIn(pasted[0], l.items())
@@ -664,6 +674,12 @@ def testCutPaste(self):
664674
p = QgsProject()
665675
l = QgsLayout(p)
666676

677+
# clear clipboard
678+
mime_data = QMimeData()
679+
mime_data.setData("text/xml", QByteArray())
680+
clipboard = QApplication.clipboard()
681+
clipboard.setMimeData(mime_data)
682+
667683
# add an item
668684
item1 = QgsLayoutItemLabel(l)
669685
item1.setText('label 1')
@@ -676,9 +692,11 @@ def testCutPaste(self):
676692

677693
view = QgsLayoutView()
678694
view.setCurrentLayout(l)
695+
self.assertFalse(view.hasItemsInClipboard())
679696

680697
len_before = len(l.items())
681698
view.copySelectedItems(QgsLayoutView.ClipboardCut)
699+
self.assertTrue(view.hasItemsInClipboard())
682700
self.assertEqual(len(l.items()), len_before - 2)
683701

684702
pasted = view.pasteItems(QgsLayoutView.PasteModeCursor)

0 commit comments

Comments
 (0)