Skip to content

Commit

Permalink
[FEATURE][layouts] Support drag and drop of QPT templates onto layout…
Browse files Browse the repository at this point in the history
… windows

To add contents of template onto layout
  • Loading branch information
nyalldawson committed Dec 6, 2017
1 parent eea36c0 commit a64a675
Show file tree
Hide file tree
Showing 17 changed files with 180 additions and 10 deletions.
2 changes: 1 addition & 1 deletion python/core/core_auto.sip
Expand Up @@ -51,7 +51,6 @@
%Include qgsfeaturestore.sip
%Include qgsfieldformatter.sip
%Include qgsfields.sip
%Include qgsfileutils.sip
%Include qgsfontutils.sip
%Include qgsgeometrysimplifier.sip
%Include qgshistogram.sip
Expand Down Expand Up @@ -314,6 +313,7 @@
%Include qgsfieldmodel.sip
%Include qgsfieldproxymodel.sip
%Include qgsfiledownloader.sip
%Include qgsfileutils.sip
%Include qgsfeaturefiltermodel.sip
%Include qgsgeometryvalidator.sip
%Include qgsgml.sip
Expand Down
9 changes: 8 additions & 1 deletion python/gui/layout/qgslayoutcustomdrophandler.sip
Expand Up @@ -8,6 +8,7 @@




class QgsLayoutCustomDropHandler : QObject
{
%Docstring
Expand All @@ -20,9 +21,15 @@ class QgsLayoutCustomDropHandler : QObject
#include "qgslayoutcustomdrophandler.h"
%End
public:

QgsLayoutCustomDropHandler( QObject *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsLayoutCustomDropHandler.
%End

virtual ~QgsLayoutCustomDropHandler();

virtual bool handleFileDrop( const QString &file );
virtual bool handleFileDrop( QgsLayoutDesignerInterface *iface, const QString &file );
%Docstring
Called when the specified ``file`` has been dropped onto a QGIS layout. If true
is returned, then the handler has accepted this file and it should not
Expand Down
5 changes: 5 additions & 0 deletions python/gui/layout/qgslayoutdesignerinterface.sip
Expand Up @@ -48,6 +48,11 @@ class QgsLayoutDesignerInterface: QObject
:rtype: QgsLayoutView
%End

virtual void selectItems( const QList< QgsLayoutItem * > items ) = 0;
%Docstring
Selects the specified ``items``.
%End

public slots:

virtual void close() = 0;
Expand Down
2 changes: 2 additions & 0 deletions python/gui/layout/qgslayoutview.sip
Expand Up @@ -468,6 +468,8 @@ class QgsLayoutView: QGraphicsView

virtual void scrollContentsBy( int dx, int dy );

virtual void dragEnterEvent( QDragEnterEvent *e );


};

Expand Down
2 changes: 2 additions & 0 deletions src/app/CMakeLists.txt
Expand Up @@ -195,6 +195,7 @@ SET(QGIS_APP_SRCS
layout/qgslayoutpolygonwidget.cpp
layout/qgslayoutpolylinewidget.cpp
layout/qgslayoutpropertieswidget.cpp
layout/qgslayoutqptdrophandler.cpp
layout/qgslayoutscalebarwidget.cpp
layout/qgslayoutshapewidget.cpp
layout/qgslayouttablebackgroundcolorsdialog.cpp
Expand Down Expand Up @@ -408,6 +409,7 @@ SET (QGIS_APP_MOC_HDRS
layout/qgslayoutpolygonwidget.h
layout/qgslayoutpolylinewidget.h
layout/qgslayoutpropertieswidget.h
layout/qgslayoutqptdrophandler.h
layout/qgslayoutscalebarwidget.h
layout/qgslayoutshapewidget.h
layout/qgslayouttablebackgroundcolorsdialog.h
Expand Down
2 changes: 2 additions & 0 deletions src/app/layout/qgslayoutapputils.h
Expand Up @@ -33,4 +33,6 @@ class QgsLayoutAppUtils

};



#endif // QGSLAYOUTAPPUTILS_H
16 changes: 15 additions & 1 deletion src/app/layout/qgslayoutdesignerdialog.cpp
Expand Up @@ -83,6 +83,11 @@ QgsLayoutView *QgsAppLayoutDesignerInterface::view()
return mDesigner->view();
}

void QgsAppLayoutDesignerInterface::selectItems( const QList<QgsLayoutItem *> items )
{
mDesigner->selectItems( items );
}

void QgsAppLayoutDesignerInterface::close()
{
mDesigner->close();
Expand All @@ -105,6 +110,7 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla

setupUi( this );
setWindowTitle( tr( "QGIS Layout Designer" ) );
setAcceptDrops( true );

setAttribute( Qt::WA_DeleteOnClose );
#if QT_VERSION >= 0x050600
Expand Down Expand Up @@ -977,7 +983,7 @@ void QgsLayoutDesignerDialog::dropEvent( QDropEvent *event )
const QVector<QPointer<QgsLayoutCustomDropHandler >> handlers = QgisApp::instance()->customLayoutDropHandlers();
for ( QgsLayoutCustomDropHandler *handler : handlers )
{
if ( handler && handler->handleFileDrop( file ) )
if ( handler && handler->handleFileDrop( iface(), file ) )
{
break;
}
Expand All @@ -991,6 +997,14 @@ void QgsLayoutDesignerDialog::dropEvent( QDropEvent *event )
timer->start();
}

void QgsLayoutDesignerDialog::dragEnterEvent( QDragEnterEvent *event )
{
if ( event->mimeData()->hasUrls() )
{
event->acceptProposedAction();
}
}

void QgsLayoutDesignerDialog::itemTypeAdded( int id )
{
if ( QgsGui::layoutItemGuiRegistry()->itemMetadata( id )->flags() & QgsLayoutItemAbstractGuiMetadata::FlagNoCreationTools )
Expand Down
13 changes: 9 additions & 4 deletions src/app/layout/qgslayoutdesignerdialog.h
Expand Up @@ -50,6 +50,7 @@ class QgsAppLayoutDesignerInterface : public QgsLayoutDesignerInterface
QgsAppLayoutDesignerInterface( QgsLayoutDesignerDialog *dialog );
QgsLayout *layout() override;
QgsLayoutView *view() override;
void selectItems( const QList< QgsLayoutItem * > items ) override;

public slots:

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

/**
* Selects the specified \a items.
*/
void selectItems( const QList< QgsLayoutItem * > items );

public slots:

/**
Expand Down Expand Up @@ -237,8 +243,9 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner

protected:

virtual void closeEvent( QCloseEvent * ) override;
virtual void dropEvent( QDropEvent *event ) override;
void closeEvent( QCloseEvent * ) override;
void dropEvent( QDropEvent *event ) override;
void dragEnterEvent( QDragEnterEvent *event ) override;

private slots:

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

void initializeRegistry();

void selectItems( const QList< QgsLayoutItem * > items );

};

#endif // QGSLAYOUTDESIGNERDIALOG_H
Expand Down
63 changes: 63 additions & 0 deletions src/app/layout/qgslayoutqptdrophandler.cpp
@@ -0,0 +1,63 @@
/***************************************************************************
qgslayoutqptdrophandler.cpp
------------------------------
begin : December 2017
copyright : (C) 2017 by nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgslayoutqptdrophandler.h"
#include "qgslayoutdesignerinterface.h"
#include "qgslayout.h"
#include "qgsreadwritecontext.h"
#include "qgsproject.h"
#include "qgslayoutview.h"
#include <QMessageBox>

QgsLayoutQptDropHandler::QgsLayoutQptDropHandler( QObject *parent )
: QgsLayoutCustomDropHandler( parent )
{

}

bool QgsLayoutQptDropHandler::handleFileDrop( QgsLayoutDesignerInterface *iface, const QString &file )
{
QFileInfo fi( file );
if ( !fi.suffix().compare( QLatin1String( "qpt" ), Qt::CaseInsensitive ) == 0 )
return false;

QFile templateFile( file );
if ( !templateFile.open( QIODevice::ReadOnly ) )
{
QMessageBox::warning( iface->view(), tr( "Load from template" ), tr( "Could not read template file." ) );
return true;
}

QDomDocument templateDoc;
QgsReadWriteContext context;
context.setPathResolver( QgsProject::instance()->pathResolver() );
if ( templateDoc.setContent( &templateFile ) )
{
bool ok = false;
QList< QgsLayoutItem * > items = iface->layout()->loadFromTemplate( templateDoc, context, false, &ok );
if ( !ok )
{
QMessageBox::warning( iface->view(), tr( "Load from template" ), tr( "Could not read template file." ) );
return true;
}
else
{
whileBlocking( iface->layout() )->deselectAll();
iface->selectItems( items );
}
}

return true;
}
32 changes: 32 additions & 0 deletions src/app/layout/qgslayoutqptdrophandler.h
@@ -0,0 +1,32 @@
/***************************************************************************
qgslayoutqptdrophandler.h
-------------------------
begin : December 2017
copyright : (C) 2017 by nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSLAYOUTQPTDROPHANDLER_H
#define QGSLAYOUTQPTDROPHANDLER_H

#include "qgslayoutcustomdrophandler.h"

class QgsLayoutQptDropHandler : public QgsLayoutCustomDropHandler
{
Q_OBJECT

public:

QgsLayoutQptDropHandler( QObject *parent = nullptr );

virtual bool handleFileDrop( QgsLayoutDesignerInterface *iface, const QString &file );
};

#endif // QGSLAYOUTQPTDROPHANDLER_H
6 changes: 6 additions & 0 deletions src/app/qgisapp.cpp
Expand Up @@ -208,6 +208,7 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
#include "qgslayoutcustomdrophandler.h"
#include "qgslayoutdesignerdialog.h"
#include "qgslayoutmanager.h"
#include "qgslayoutqptdrophandler.h"
#include "qgslayoutapputils.h"
#include "qgslocatorwidget.h"
#include "qgslocator.h"
Expand Down Expand Up @@ -1397,6 +1398,8 @@ QgisApp::~QgisApp()
// cancel request for FileOpen events
QgsApplication::setFileOpenEventReceiver( nullptr );

unregisterCustomLayoutDropHandler( mLayoutQptDropHandler );

delete mPythonUtils;
delete mTray;
delete mDataSourceManagerDialog;
Expand Down Expand Up @@ -10245,6 +10248,9 @@ void QgisApp::initNativeProcessing()
void QgisApp::initLayouts()
{
QgsLayoutAppUtils::registerGuiForKnownItemTypes();

mLayoutQptDropHandler = new QgsLayoutQptDropHandler( this );
registerCustomLayoutDropHandler( mLayoutQptDropHandler );
}

void QgisApp::new3DMapCanvas()
Expand Down
3 changes: 3 additions & 0 deletions src/app/qgisapp.h
Expand Up @@ -129,6 +129,7 @@ class QgsLocatorWidget;
class QgsDataSourceManagerDialog;
class QgsBrowserModel;
class QgsGeoCmsProviderRegistry;
class QgsLayoutQptDropHandler;


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

QgsLayoutQptDropHandler *mLayoutQptDropHandler = nullptr;

QDateTime mProjectLastModified;

QgsWelcomePage *mWelcomePage = nullptr;
Expand Down
9 changes: 7 additions & 2 deletions src/gui/layout/qgslayoutcustomdrophandler.cpp
Expand Up @@ -15,8 +15,13 @@

#include "qgslayoutcustomdrophandler.h"

bool QgsLayoutCustomDropHandler::handleFileDrop( const QString &file )
QgsLayoutCustomDropHandler::QgsLayoutCustomDropHandler( QObject *parent )
: QObject( parent )
{

}

bool QgsLayoutCustomDropHandler::handleFileDrop( QgsLayoutDesignerInterface *, const QString & )
{
Q_UNUSED( file );
return false;
}
11 changes: 10 additions & 1 deletion src/gui/layout/qgslayoutcustomdrophandler.h
Expand Up @@ -17,8 +17,11 @@
#define QGSLAYOUTCUSTOMDROPHANDLER_H

#include "qgis_gui.h"
#include "qgis_sip.h"
#include <QObject>

class QgsLayoutDesignerInterface;

/**
* \ingroup gui
* Abstract base class that may be implemented to handle new types of data to be dropped in QGIS layouts.
Expand All @@ -30,6 +33,12 @@ class GUI_EXPORT QgsLayoutCustomDropHandler : public QObject
Q_OBJECT

public:

/**
* Constructor for QgsLayoutCustomDropHandler.
*/
QgsLayoutCustomDropHandler( QObject *parent SIP_TRANSFERTHIS = nullptr );

virtual ~QgsLayoutCustomDropHandler() = default;

/**
Expand All @@ -39,7 +48,7 @@ class GUI_EXPORT QgsLayoutCustomDropHandler : public QObject
*
* The base class implementation does nothing.
*/
virtual bool handleFileDrop( const QString &file );
virtual bool handleFileDrop( QgsLayoutDesignerInterface *iface, const QString &file );
};

#endif // QGSLAYOUTCUSTOMDROPHANDLER_H
6 changes: 6 additions & 0 deletions src/gui/layout/qgslayoutdesignerinterface.h
Expand Up @@ -22,6 +22,7 @@

class QgsLayout;
class QgsLayoutView;
class QgsLayoutItem;

/**
* \ingroup gui
Expand Down Expand Up @@ -62,6 +63,11 @@ class GUI_EXPORT QgsLayoutDesignerInterface: public QObject
*/
virtual QgsLayoutView *view() = 0;

/**
* Selects the specified \a items.
*/
virtual void selectItems( const QList< QgsLayoutItem * > items ) = 0;

public slots:

/**
Expand Down
8 changes: 8 additions & 0 deletions src/gui/layout/qgslayoutview.cpp
Expand Up @@ -972,6 +972,14 @@ void QgsLayoutView::scrollContentsBy( int dx, int dy )
viewChanged();
}

void QgsLayoutView::dragEnterEvent( QDragEnterEvent *e )
{
// By default graphics view delegates the drag events to graphics items.
// But we do not want that and by ignoring the drag enter we let the
// parent (e.g. QgsLayoutDesignerDialog) to handle drops of files.
e->ignore();
}

void QgsLayoutView::invalidateCachedRenders()
{
if ( !currentLayout() )
Expand Down

0 comments on commit a64a675

Please sign in to comment.