Skip to content

Commit a64a675

Browse files
committed
[FEATURE][layouts] Support drag and drop of QPT templates onto layout windows
To add contents of template onto layout
1 parent eea36c0 commit a64a675

17 files changed

+180
-10
lines changed

python/core/core_auto.sip

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
%Include qgsfeaturestore.sip
5252
%Include qgsfieldformatter.sip
5353
%Include qgsfields.sip
54-
%Include qgsfileutils.sip
5554
%Include qgsfontutils.sip
5655
%Include qgsgeometrysimplifier.sip
5756
%Include qgshistogram.sip
@@ -314,6 +313,7 @@
314313
%Include qgsfieldmodel.sip
315314
%Include qgsfieldproxymodel.sip
316315
%Include qgsfiledownloader.sip
316+
%Include qgsfileutils.sip
317317
%Include qgsfeaturefiltermodel.sip
318318
%Include qgsgeometryvalidator.sip
319319
%Include qgsgml.sip

python/gui/layout/qgslayoutcustomdrophandler.sip

+8-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99

1010

11+
1112
class QgsLayoutCustomDropHandler : QObject
1213
{
1314
%Docstring
@@ -20,9 +21,15 @@ class QgsLayoutCustomDropHandler : QObject
2021
#include "qgslayoutcustomdrophandler.h"
2122
%End
2223
public:
24+
25+
QgsLayoutCustomDropHandler( QObject *parent /TransferThis/ = 0 );
26+
%Docstring
27+
Constructor for QgsLayoutCustomDropHandler.
28+
%End
29+
2330
virtual ~QgsLayoutCustomDropHandler();
2431

25-
virtual bool handleFileDrop( const QString &file );
32+
virtual bool handleFileDrop( QgsLayoutDesignerInterface *iface, const QString &file );
2633
%Docstring
2734
Called when the specified ``file`` has been dropped onto a QGIS layout. If true
2835
is returned, then the handler has accepted this file and it should not

python/gui/layout/qgslayoutdesignerinterface.sip

+5
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ class QgsLayoutDesignerInterface: QObject
4848
:rtype: QgsLayoutView
4949
%End
5050

51+
virtual void selectItems( const QList< QgsLayoutItem * > items ) = 0;
52+
%Docstring
53+
Selects the specified ``items``.
54+
%End
55+
5156
public slots:
5257

5358
virtual void close() = 0;

python/gui/layout/qgslayoutview.sip

+2
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,8 @@ class QgsLayoutView: QGraphicsView
468468

469469
virtual void scrollContentsBy( int dx, int dy );
470470

471+
virtual void dragEnterEvent( QDragEnterEvent *e );
472+
471473

472474
};
473475

src/app/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ SET(QGIS_APP_SRCS
195195
layout/qgslayoutpolygonwidget.cpp
196196
layout/qgslayoutpolylinewidget.cpp
197197
layout/qgslayoutpropertieswidget.cpp
198+
layout/qgslayoutqptdrophandler.cpp
198199
layout/qgslayoutscalebarwidget.cpp
199200
layout/qgslayoutshapewidget.cpp
200201
layout/qgslayouttablebackgroundcolorsdialog.cpp
@@ -408,6 +409,7 @@ SET (QGIS_APP_MOC_HDRS
408409
layout/qgslayoutpolygonwidget.h
409410
layout/qgslayoutpolylinewidget.h
410411
layout/qgslayoutpropertieswidget.h
412+
layout/qgslayoutqptdrophandler.h
411413
layout/qgslayoutscalebarwidget.h
412414
layout/qgslayoutshapewidget.h
413415
layout/qgslayouttablebackgroundcolorsdialog.h

src/app/layout/qgslayoutapputils.h

+2
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,6 @@ class QgsLayoutAppUtils
3333

3434
};
3535

36+
37+
3638
#endif // QGSLAYOUTAPPUTILS_H

src/app/layout/qgslayoutdesignerdialog.cpp

+15-1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ QgsLayoutView *QgsAppLayoutDesignerInterface::view()
8383
return mDesigner->view();
8484
}
8585

86+
void QgsAppLayoutDesignerInterface::selectItems( const QList<QgsLayoutItem *> items )
87+
{
88+
mDesigner->selectItems( items );
89+
}
90+
8691
void QgsAppLayoutDesignerInterface::close()
8792
{
8893
mDesigner->close();
@@ -105,6 +110,7 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
105110

106111
setupUi( this );
107112
setWindowTitle( tr( "QGIS Layout Designer" ) );
113+
setAcceptDrops( true );
108114

109115
setAttribute( Qt::WA_DeleteOnClose );
110116
#if QT_VERSION >= 0x050600
@@ -977,7 +983,7 @@ void QgsLayoutDesignerDialog::dropEvent( QDropEvent *event )
977983
const QVector<QPointer<QgsLayoutCustomDropHandler >> handlers = QgisApp::instance()->customLayoutDropHandlers();
978984
for ( QgsLayoutCustomDropHandler *handler : handlers )
979985
{
980-
if ( handler && handler->handleFileDrop( file ) )
986+
if ( handler && handler->handleFileDrop( iface(), file ) )
981987
{
982988
break;
983989
}
@@ -991,6 +997,14 @@ void QgsLayoutDesignerDialog::dropEvent( QDropEvent *event )
991997
timer->start();
992998
}
993999

1000+
void QgsLayoutDesignerDialog::dragEnterEvent( QDragEnterEvent *event )
1001+
{
1002+
if ( event->mimeData()->hasUrls() )
1003+
{
1004+
event->acceptProposedAction();
1005+
}
1006+
}
1007+
9941008
void QgsLayoutDesignerDialog::itemTypeAdded( int id )
9951009
{
9961010
if ( QgsGui::layoutItemGuiRegistry()->itemMetadata( id )->flags() & QgsLayoutItemAbstractGuiMetadata::FlagNoCreationTools )

src/app/layout/qgslayoutdesignerdialog.h

+9-4
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class QgsAppLayoutDesignerInterface : public QgsLayoutDesignerInterface
5050
QgsAppLayoutDesignerInterface( QgsLayoutDesignerDialog *dialog );
5151
QgsLayout *layout() override;
5252
QgsLayoutView *view() override;
53+
void selectItems( const QList< QgsLayoutItem * > items ) override;
5354

5455
public slots:
5556

@@ -107,6 +108,11 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
107108
*/
108109
void showItemOptions( QgsLayoutItem *item, bool bringPanelToFront = true );
109110

111+
/**
112+
* Selects the specified \a items.
113+
*/
114+
void selectItems( const QList< QgsLayoutItem * > items );
115+
110116
public slots:
111117

112118
/**
@@ -237,8 +243,9 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
237243

238244
protected:
239245

240-
virtual void closeEvent( QCloseEvent * ) override;
241-
virtual void dropEvent( QDropEvent *event ) override;
246+
void closeEvent( QCloseEvent * ) override;
247+
void dropEvent( QDropEvent *event ) override;
248+
void dragEnterEvent( QDragEnterEvent *event ) override;
242249

243250
private slots:
244251

@@ -347,8 +354,6 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
347354

348355
void initializeRegistry();
349356

350-
void selectItems( const QList< QgsLayoutItem * > items );
351-
352357
};
353358

354359
#endif // QGSLAYOUTDESIGNERDIALOG_H
+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/***************************************************************************
2+
qgslayoutqptdrophandler.cpp
3+
------------------------------
4+
begin : December 2017
5+
copyright : (C) 2017 by nyall Dawson
6+
email : nyall dot dawson at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgslayoutqptdrophandler.h"
17+
#include "qgslayoutdesignerinterface.h"
18+
#include "qgslayout.h"
19+
#include "qgsreadwritecontext.h"
20+
#include "qgsproject.h"
21+
#include "qgslayoutview.h"
22+
#include <QMessageBox>
23+
24+
QgsLayoutQptDropHandler::QgsLayoutQptDropHandler( QObject *parent )
25+
: QgsLayoutCustomDropHandler( parent )
26+
{
27+
28+
}
29+
30+
bool QgsLayoutQptDropHandler::handleFileDrop( QgsLayoutDesignerInterface *iface, const QString &file )
31+
{
32+
QFileInfo fi( file );
33+
if ( !fi.suffix().compare( QLatin1String( "qpt" ), Qt::CaseInsensitive ) == 0 )
34+
return false;
35+
36+
QFile templateFile( file );
37+
if ( !templateFile.open( QIODevice::ReadOnly ) )
38+
{
39+
QMessageBox::warning( iface->view(), tr( "Load from template" ), tr( "Could not read template file." ) );
40+
return true;
41+
}
42+
43+
QDomDocument templateDoc;
44+
QgsReadWriteContext context;
45+
context.setPathResolver( QgsProject::instance()->pathResolver() );
46+
if ( templateDoc.setContent( &templateFile ) )
47+
{
48+
bool ok = false;
49+
QList< QgsLayoutItem * > items = iface->layout()->loadFromTemplate( templateDoc, context, false, &ok );
50+
if ( !ok )
51+
{
52+
QMessageBox::warning( iface->view(), tr( "Load from template" ), tr( "Could not read template file." ) );
53+
return true;
54+
}
55+
else
56+
{
57+
whileBlocking( iface->layout() )->deselectAll();
58+
iface->selectItems( items );
59+
}
60+
}
61+
62+
return true;
63+
}
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/***************************************************************************
2+
qgslayoutqptdrophandler.h
3+
-------------------------
4+
begin : December 2017
5+
copyright : (C) 2017 by nyall Dawson
6+
email : nyall dot dawson at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSLAYOUTQPTDROPHANDLER_H
17+
#define QGSLAYOUTQPTDROPHANDLER_H
18+
19+
#include "qgslayoutcustomdrophandler.h"
20+
21+
class QgsLayoutQptDropHandler : public QgsLayoutCustomDropHandler
22+
{
23+
Q_OBJECT
24+
25+
public:
26+
27+
QgsLayoutQptDropHandler( QObject *parent = nullptr );
28+
29+
virtual bool handleFileDrop( QgsLayoutDesignerInterface *iface, const QString &file );
30+
};
31+
32+
#endif // QGSLAYOUTQPTDROPHANDLER_H

src/app/qgisapp.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
208208
#include "qgslayoutcustomdrophandler.h"
209209
#include "qgslayoutdesignerdialog.h"
210210
#include "qgslayoutmanager.h"
211+
#include "qgslayoutqptdrophandler.h"
211212
#include "qgslayoutapputils.h"
212213
#include "qgslocatorwidget.h"
213214
#include "qgslocator.h"
@@ -1397,6 +1398,8 @@ QgisApp::~QgisApp()
13971398
// cancel request for FileOpen events
13981399
QgsApplication::setFileOpenEventReceiver( nullptr );
13991400

1401+
unregisterCustomLayoutDropHandler( mLayoutQptDropHandler );
1402+
14001403
delete mPythonUtils;
14011404
delete mTray;
14021405
delete mDataSourceManagerDialog;
@@ -10245,6 +10248,9 @@ void QgisApp::initNativeProcessing()
1024510248
void QgisApp::initLayouts()
1024610249
{
1024710250
QgsLayoutAppUtils::registerGuiForKnownItemTypes();
10251+
10252+
mLayoutQptDropHandler = new QgsLayoutQptDropHandler( this );
10253+
registerCustomLayoutDropHandler( mLayoutQptDropHandler );
1024810254
}
1024910255

1025010256
void QgisApp::new3DMapCanvas()

src/app/qgisapp.h

+3
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ class QgsLocatorWidget;
129129
class QgsDataSourceManagerDialog;
130130
class QgsBrowserModel;
131131
class QgsGeoCmsProviderRegistry;
132+
class QgsLayoutQptDropHandler;
132133

133134

134135
#include <QMainWindow>
@@ -2131,6 +2132,8 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
21312132
QVector<QPointer<QgsCustomDropHandler>> mCustomDropHandlers;
21322133
QVector<QPointer<QgsLayoutCustomDropHandler>> mCustomLayoutDropHandlers;
21332134

2135+
QgsLayoutQptDropHandler *mLayoutQptDropHandler = nullptr;
2136+
21342137
QDateTime mProjectLastModified;
21352138

21362139
QgsWelcomePage *mWelcomePage = nullptr;

src/gui/layout/qgslayoutcustomdrophandler.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,13 @@
1515

1616
#include "qgslayoutcustomdrophandler.h"
1717

18-
bool QgsLayoutCustomDropHandler::handleFileDrop( const QString &file )
18+
QgsLayoutCustomDropHandler::QgsLayoutCustomDropHandler( QObject *parent )
19+
: QObject( parent )
20+
{
21+
22+
}
23+
24+
bool QgsLayoutCustomDropHandler::handleFileDrop( QgsLayoutDesignerInterface *, const QString & )
1925
{
20-
Q_UNUSED( file );
2126
return false;
2227
}

src/gui/layout/qgslayoutcustomdrophandler.h

+10-1
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@
1717
#define QGSLAYOUTCUSTOMDROPHANDLER_H
1818

1919
#include "qgis_gui.h"
20+
#include "qgis_sip.h"
2021
#include <QObject>
2122

23+
class QgsLayoutDesignerInterface;
24+
2225
/**
2326
* \ingroup gui
2427
* Abstract base class that may be implemented to handle new types of data to be dropped in QGIS layouts.
@@ -30,6 +33,12 @@ class GUI_EXPORT QgsLayoutCustomDropHandler : public QObject
3033
Q_OBJECT
3134

3235
public:
36+
37+
/**
38+
* Constructor for QgsLayoutCustomDropHandler.
39+
*/
40+
QgsLayoutCustomDropHandler( QObject *parent SIP_TRANSFERTHIS = nullptr );
41+
3342
virtual ~QgsLayoutCustomDropHandler() = default;
3443

3544
/**
@@ -39,7 +48,7 @@ class GUI_EXPORT QgsLayoutCustomDropHandler : public QObject
3948
*
4049
* The base class implementation does nothing.
4150
*/
42-
virtual bool handleFileDrop( const QString &file );
51+
virtual bool handleFileDrop( QgsLayoutDesignerInterface *iface, const QString &file );
4352
};
4453

4554
#endif // QGSLAYOUTCUSTOMDROPHANDLER_H

src/gui/layout/qgslayoutdesignerinterface.h

+6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
class QgsLayout;
2424
class QgsLayoutView;
25+
class QgsLayoutItem;
2526

2627
/**
2728
* \ingroup gui
@@ -62,6 +63,11 @@ class GUI_EXPORT QgsLayoutDesignerInterface: public QObject
6263
*/
6364
virtual QgsLayoutView *view() = 0;
6465

66+
/**
67+
* Selects the specified \a items.
68+
*/
69+
virtual void selectItems( const QList< QgsLayoutItem * > items ) = 0;
70+
6571
public slots:
6672

6773
/**

src/gui/layout/qgslayoutview.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,14 @@ void QgsLayoutView::scrollContentsBy( int dx, int dy )
972972
viewChanged();
973973
}
974974

975+
void QgsLayoutView::dragEnterEvent( QDragEnterEvent *e )
976+
{
977+
// By default graphics view delegates the drag events to graphics items.
978+
// But we do not want that and by ignoring the drag enter we let the
979+
// parent (e.g. QgsLayoutDesignerDialog) to handle drops of files.
980+
e->ignore();
981+
}
982+
975983
void QgsLayoutView::invalidateCachedRenders()
976984
{
977985
if ( !currentLayout() )

0 commit comments

Comments
 (0)