Skip to content

Commit

Permalink
Defer processing of dropped files
Browse files Browse the repository at this point in the history
On Windows (and maybe other platforms) Qt locks the dragging
application for the duration of dropEvent. This means that
dropping large files or projects onto QGIS results in
Explorer windows being locked and unresponsive until
the entire file/project is loaded.

There does not seem to be any Qt method for releasing this lock
early, so instead we return from dropEvent as quickly as possible
and defer the actual file loading to a slot which is fired up
immediately after dropEvent concludes.

(cherry-picked from bd81edc)
  • Loading branch information
nyalldawson committed Oct 19, 2016
1 parent ff99816 commit 4cc7623
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 4 deletions.
40 changes: 36 additions & 4 deletions src/app/qgisapp.cpp
Expand Up @@ -1277,10 +1277,17 @@ void QgisApp::dragEnterEvent( QDragEnterEvent *event )

void QgisApp::dropEvent( QDropEvent *event )
{
mMapCanvas->freeze();
// 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();
Expand Down Expand Up @@ -1333,13 +1340,37 @@ void QgisApp::dropEvent( QDropEvent *event )
// so we test for length to make sure we have something
if ( !fileName.isEmpty() )
{
openFile( fileName );
files << fileName;
}
}
timer->setProperty( "files", files );

QgsMimeDataUtils::UriList lst;
if ( QgsMimeDataUtils::isUriList( event->mimeData() ) )
{
QgsMimeDataUtils::UriList lst = QgsMimeDataUtils::decodeUriList( event->mimeData() );
lst = QgsMimeDataUtils::decodeUriList( event->mimeData() );
}
timer->setProperty( "uris", QVariant::fromValue( lst ) );

connect( timer, SIGNAL( timeout() ), this, SLOT( dropEventTimeout() ) );

event->acceptProposedAction();
timer->start();
}

void QgisApp::dropEventTimeout()
{
mMapCanvas->freeze();
QStringList files = sender()->property( "files" ).toStringList();

Q_FOREACH ( const QString& file, files )
{
openFile( file );
}

QgsMimeDataUtils::UriList lst = sender()->property( "uris" ).value<QgsMimeDataUtils::UriList>();
if ( !lst.isEmpty() )
{
Q_FOREACH ( const QgsMimeDataUtils::Uri& u, lst )
{
QString uri = crsAndFormatAdjustedLayerUri( u.uri, u.supportedCrs, u.supportedFormats );
Expand All @@ -1358,9 +1389,10 @@ void QgisApp::dropEvent( QDropEvent *event )
}
}
}
sender()->deleteLater();

mMapCanvas->freeze( false );
mMapCanvas->refresh();
event->acceptProposedAction();
}

bool QgisApp::event( QEvent * event )
Expand Down
3 changes: 3 additions & 0 deletions src/app/qgisapp.h
Expand Up @@ -1322,6 +1322,9 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
/** Set the layer for the map style dock. Doesn't show the style dock */
void setMapStyleDockLayer( QgsMapLayer *layer );

//! Handles processing of dropped mimedata
void dropEventTimeout();

signals:
/** Emitted when a key is pressed and we want non widget sublasses to be able
to pick up on this (e.g. maplayer) */
Expand Down
2 changes: 2 additions & 0 deletions src/core/qgsmimedatautils.h
Expand Up @@ -55,5 +55,7 @@ class CORE_EXPORT QgsMimeDataUtils

};

Q_DECLARE_METATYPE( QgsMimeDataUtils::UriList );

#endif // QGSMIMEDATAUTILS_H

0 comments on commit 4cc7623

Please sign in to comment.