Add custom drop handlers for layout windows

This commit is contained in:
Nyall Dawson 2017-12-04 13:09:58 +10:00
parent b0dea08bbe
commit eea36c0212
13 changed files with 281 additions and 3 deletions

View File

@ -290,6 +290,7 @@
%Include layertree/qgslayertreemapcanvasbridge.sip
%Include layertree/qgslayertreeview.sip
%Include layertree/qgslayertreeviewdefaultactions.sip
%Include layout/qgslayoutcustomdrophandler.sip
%Include layout/qgslayoutdesignerinterface.sip
%Include layout/qgslayoutitemcombobox.sip
%Include layout/qgslayoutitemguiregistry.sip

View File

@ -0,0 +1,42 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/layout/qgslayoutcustomdrophandler.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsLayoutCustomDropHandler : QObject
{
%Docstring
Abstract base class that may be implemented to handle new types of data to be dropped in QGIS layouts.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgslayoutcustomdrophandler.h"
%End
public:
virtual ~QgsLayoutCustomDropHandler();
virtual bool handleFileDrop( 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
be further processed (e.g. by other QgsLayoutCustomDropHandler).
The base class implementation does nothing.
:rtype: bool
%End
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/layout/qgslayoutcustomdrophandler.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -1116,6 +1116,24 @@ Unregister a previously registered action. (e.g. when plugin is going to be unlo
.. seealso:: :py:func:`registerCustomDropHandler()`
%End
virtual void registerCustomLayoutDropHandler( QgsLayoutCustomDropHandler *handler ) = 0;
%Docstring
Register a new custom drop ``handler`` for layout windows.
.. versionadded:: 3.0
.. note::
Ownership of the factory is not transferred, and the factory must
be unregistered when plugin is unloaded.
.. seealso:: unregisterCustomLayoutDropHandler() *
%End
virtual void unregisterCustomLayoutDropHandler( QgsLayoutCustomDropHandler *handler ) = 0;
%Docstring
Unregister a previously registered custom drop ``handler`` for layout windows.
.. versionadded:: 3.0
.. seealso:: registerCustomLayoutDropHandler() *
%End
virtual void openURL( const QString &url, bool useQgisDocDirectory = true ) = 0 /Deprecated/;
%Docstring

View File

@ -22,6 +22,7 @@
#include "qgslogger.h"
#include "qgslayout.h"
#include "qgslayoutappmenuprovider.h"
#include "qgslayoutcustomdrophandler.h"
#include "qgslayoutview.h"
#include "qgslayoutviewtooladditem.h"
#include "qgslayoutviewtooladdnodeitem.h"
@ -900,6 +901,96 @@ void QgsLayoutDesignerDialog::closeEvent( QCloseEvent * )
saveWindowState();
}
void QgsLayoutDesignerDialog::dropEvent( QDropEvent *event )
{
// dragging app is locked for the duration of dropEvent. This causes explorer windows to hang
// while large projects/layers are loaded. So instead we return from dropEvent as quickly as possible
// and do the actual handling of the drop after a very short timeout
QTimer *timer = new QTimer( this );
timer->setSingleShot( true );
timer->setInterval( 50 );
// get the file list
QList<QUrl>::iterator i;
QList<QUrl>urls = event->mimeData()->urls();
QStringList files;
for ( i = urls.begin(); i != urls.end(); ++i )
{
QString fileName = i->toLocalFile();
#ifdef Q_OS_MAC
// Mac OS X 10.10, under Qt4.8 ,changes dropped URL format
// https://bugreports.qt.io/browse/QTBUG-40449
// [pzion 20150805] Work around
if ( fileName.startsWith( "/.file/id=" ) )
{
QgsDebugMsg( "Mac dropped URL with /.file/id= (converting)" );
CFStringRef relCFStringRef =
CFStringCreateWithCString(
kCFAllocatorDefault,
fileName.toUtf8().constData(),
kCFStringEncodingUTF8
);
CFURLRef relCFURL =
CFURLCreateWithFileSystemPath(
kCFAllocatorDefault,
relCFStringRef,
kCFURLPOSIXPathStyle,
false // isDirectory
);
CFErrorRef error = 0;
CFURLRef absCFURL =
CFURLCreateFilePathURL(
kCFAllocatorDefault,
relCFURL,
&error
);
if ( !error )
{
static const CFIndex maxAbsPathCStrBufLen = 4096;
char absPathCStr[maxAbsPathCStrBufLen];
if ( CFURLGetFileSystemRepresentation(
absCFURL,
true, // resolveAgainstBase
reinterpret_cast<UInt8 *>( &absPathCStr[0] ),
maxAbsPathCStrBufLen ) )
{
fileName = QString( absPathCStr );
}
}
CFRelease( absCFURL );
CFRelease( relCFURL );
CFRelease( relCFStringRef );
}
#endif
// seems that some drag and drop operations include an empty url
// so we test for length to make sure we have something
if ( !fileName.isEmpty() )
{
files << fileName;
}
}
connect( timer, &QTimer::timeout, this, [this, timer, files]
{
for ( const QString &file : qgis::as_const( files ) )
{
const QVector<QPointer<QgsLayoutCustomDropHandler >> handlers = QgisApp::instance()->customLayoutDropHandlers();
for ( QgsLayoutCustomDropHandler *handler : handlers )
{
if ( handler && handler->handleFileDrop( file ) )
{
break;
}
}
}
timer->deleteLater();
} );
event->acceptProposedAction();
timer->start();
}
void QgsLayoutDesignerDialog::itemTypeAdded( int id )
{
if ( QgsGui::layoutItemGuiRegistry()->itemMetadata( id )->flags() & QgsLayoutItemAbstractGuiMetadata::FlagNoCreationTools )

View File

@ -238,6 +238,7 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
protected:
virtual void closeEvent( QCloseEvent * ) override;
virtual void dropEvent( QDropEvent *event ) override;
private slots:

View File

@ -205,6 +205,7 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
#include "qgslayertreeutils.h"
#include "qgslayertreeview.h"
#include "qgslayertreeviewdefaultactions.h"
#include "qgslayoutcustomdrophandler.h"
#include "qgslayoutdesignerdialog.h"
#include "qgslayoutmanager.h"
#include "qgslayoutapputils.h"
@ -1400,6 +1401,7 @@ QgisApp::~QgisApp()
delete mTray;
delete mDataSourceManagerDialog;
qDeleteAll( mCustomDropHandlers );
qDeleteAll( mCustomLayoutDropHandlers );
// This function *MUST* be the last one called, as it destroys in
// particular GDAL. As above objects can hold GDAL/OGR objects, it is not
@ -1560,6 +1562,22 @@ void QgisApp::unregisterCustomDropHandler( QgsCustomDropHandler *handler )
mCustomDropHandlers.removeOne( handler );
}
void QgisApp::registerCustomLayoutDropHandler( QgsLayoutCustomDropHandler *handler )
{
if ( !mCustomLayoutDropHandlers.contains( handler ) )
mCustomLayoutDropHandlers << handler;
}
void QgisApp::unregisterCustomLayoutDropHandler( QgsLayoutCustomDropHandler *handler )
{
mCustomLayoutDropHandlers.removeOne( handler );
}
QVector<QPointer<QgsLayoutCustomDropHandler> > QgisApp::customLayoutDropHandlers() const
{
return mCustomLayoutDropHandlers;
}
void QgisApp::handleDropUriList( const QgsMimeDataUtils::UriList &lst )
{
// insert items in reverse order as each one is inserted on top of previous one

View File

@ -62,6 +62,7 @@ class QgsGeometry;
class QgsLayerTreeMapCanvasBridge;
class QgsLayerTreeView;
class QgsLayout;
class QgsLayoutCustomDropHandler;
class QgsLayoutDesignerDialog;
class QgsLayoutDesignerInterface;
class QgsMapCanvas;
@ -644,6 +645,15 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
//! Unregister a previously registered custom drop handler.
void unregisterCustomDropHandler( QgsCustomDropHandler *handler );
//! Register a new custom layout drop handler.
void registerCustomLayoutDropHandler( QgsLayoutCustomDropHandler *handler );
//! Unregister a previously registered custom layout drop handler.
void unregisterCustomLayoutDropHandler( QgsLayoutCustomDropHandler *handler );
//! Returns a list of registered custom layout drop handlers.
QVector<QPointer<QgsLayoutCustomDropHandler >> customLayoutDropHandlers() const;
//! Returns the active map layer.
QgsMapLayer *activeLayer();
@ -2119,6 +2129,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QList<QPointer<QgsOptionsWidgetFactory>> mOptionsWidgetFactories;
QVector<QPointer<QgsCustomDropHandler>> mCustomDropHandlers;
QVector<QPointer<QgsLayoutCustomDropHandler>> mCustomLayoutDropHandlers;
QDateTime mProjectLastModified;

View File

@ -584,6 +584,16 @@ void QgisAppInterface::registerCustomDropHandler( QgsCustomDropHandler *handler
qgis->registerCustomDropHandler( handler );
}
void QgisAppInterface::registerCustomLayoutDropHandler( QgsLayoutCustomDropHandler *handler )
{
qgis->registerCustomLayoutDropHandler( handler );
}
void QgisAppInterface::unregisterCustomLayoutDropHandler( QgsLayoutCustomDropHandler *handler )
{
qgis->unregisterCustomLayoutDropHandler( handler );
}
void QgisAppInterface::unregisterCustomDropHandler( QgsCustomDropHandler *handler )
{
qgis->unregisterCustomDropHandler( handler );

View File

@ -24,7 +24,6 @@
class QgisApp;
/**
* \class QgisAppInterface
* \brief Interface class to provide access to private methods in QgisApp
@ -330,7 +329,7 @@ class APP_EXPORT QgisAppInterface : public QgisInterface
virtual void unregisterOptionsWidgetFactory( QgsOptionsWidgetFactory *factory ) override;
/**
* Register a new custom drop handler.
* Register a new custom drop \a handler.
* \since QGIS 3.0
* \note Ownership of the factory is not transferred, and the factory must
* be unregistered when plugin is unloaded.
@ -338,11 +337,14 @@ class APP_EXPORT QgisAppInterface : public QgisInterface
virtual void registerCustomDropHandler( QgsCustomDropHandler *handler ) override;
/**
* Unregister a previously registered custom drop handler.
* Unregister a previously registered custom drop \a handler.
* \since QGIS 3.0
* \see registerCustomDropHandler() */
virtual void unregisterCustomDropHandler( QgsCustomDropHandler *handler ) override;
void registerCustomLayoutDropHandler( QgsLayoutCustomDropHandler *handler ) override;
void unregisterCustomLayoutDropHandler( QgsLayoutCustomDropHandler *handler ) override;
/**
* Accessors for inserting items into menus and toolbars.
* An item can be inserted before any existing action.

View File

@ -160,6 +160,7 @@ SET(QGIS_GUI_SRCS
layertree/qgslayertreeview.cpp
layertree/qgslayertreeviewdefaultactions.cpp
layout/qgslayoutcustomdrophandler.cpp
layout/qgslayoutitemguiregistry.cpp
layout/qgslayoutitemcombobox.cpp
layout/qgslayoutitemwidget.cpp
@ -678,6 +679,7 @@ SET(QGIS_GUI_MOC_HDRS
layertree/qgslayertreeview.h
layertree/qgslayertreeviewdefaultactions.h
layout/qgslayoutcustomdrophandler.h
layout/qgslayoutdesignerinterface.h
layout/qgslayoutitemcombobox.h
layout/qgslayoutitemguiregistry.h

View File

@ -0,0 +1,22 @@
/***************************************************************************
qgslayoutcustomdrophandler.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 "qgslayoutcustomdrophandler.h"
bool QgsLayoutCustomDropHandler::handleFileDrop( const QString &file )
{
Q_UNUSED( file );
return false;
}

View File

@ -0,0 +1,45 @@
/***************************************************************************
qgslayoutcustomdrophandler.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 QGSLAYOUTCUSTOMDROPHANDLER_H
#define QGSLAYOUTCUSTOMDROPHANDLER_H
#include "qgis_gui.h"
#include <QObject>
/**
* \ingroup gui
* Abstract base class that may be implemented to handle new types of data to be dropped in QGIS layouts.
*
* \since QGIS 3.0
*/
class GUI_EXPORT QgsLayoutCustomDropHandler : public QObject
{
Q_OBJECT
public:
virtual ~QgsLayoutCustomDropHandler() = default;
/**
* Called when the specified \a file has been dropped onto a QGIS layout. If true
* is returned, then the handler has accepted this file and it should not
* be further processed (e.g. by other QgsLayoutCustomDropHandler).
*
* The base class implementation does nothing.
*/
virtual bool handleFileDrop( const QString &file );
};
#endif // QGSLAYOUTCUSTOMDROPHANDLER_H

View File

@ -29,6 +29,7 @@ class QgsAdvancedDigitizingDockWidget;
class QgsAttributeDialog;
class QgsComposerInterface;
class QgsCustomDropHandler;
class QgsLayoutCustomDropHandler;
class QgsFeature;
class QgsLayerTreeMapCanvasBridge;
class QgsLayerTreeView;
@ -679,6 +680,20 @@ class GUI_EXPORT QgisInterface : public QObject
* \see registerCustomDropHandler() */
virtual void unregisterCustomDropHandler( QgsCustomDropHandler *handler ) = 0;
/**
* Register a new custom drop \a handler for layout windows.
* \since QGIS 3.0
* \note Ownership of the factory is not transferred, and the factory must
* be unregistered when plugin is unloaded.
* \see unregisterCustomLayoutDropHandler() */
virtual void registerCustomLayoutDropHandler( QgsLayoutCustomDropHandler *handler ) = 0;
/**
* Unregister a previously registered custom drop \a handler for layout windows.
* \since QGIS 3.0
* \see registerCustomLayoutDropHandler() */
virtual void unregisterCustomLayoutDropHandler( QgsLayoutCustomDropHandler *handler ) = 0;
// @todo is this deprecated in favour of QgsContextHelp?
/**