Skip to content

Commit

Permalink
Merge pull request #6268 from pblottiere/dbmanager_stop
Browse files Browse the repository at this point in the history
[FEATURE][needs-docs] dbmanager stop
  • Loading branch information
pblottiere committed Mar 5, 2018
2 parents f2a6780 + e531052 commit 7c3ab9f
Show file tree
Hide file tree
Showing 35 changed files with 891 additions and 61 deletions.
1 change: 1 addition & 0 deletions python/core/core_auto.sip
Expand Up @@ -347,6 +347,7 @@
%Include qgsvectorlayereditbuffer.sip
%Include qgsvectorlayereditpassthrough.sip
%Include qgsvectorlayer.sip
%Include qgsvirtuallayertask.sip
%Include qgsvectorlayerfeaturecounter.sip
%Include qgsvectorlayerjoinbuffer.sip
%Include qgsvectorlayertools.sip
Expand Down
12 changes: 12 additions & 0 deletions python/core/qgsvectordataprovider.sip.in
Expand Up @@ -50,6 +50,7 @@ of feature and attribute information from a spatial datasource.
FastTruncate,
ReadLayerMetadata,
WriteLayerMetadata,
CancelSupport,
};

typedef QFlags<QgsVectorDataProvider::Capability> Capabilities;
Expand Down Expand Up @@ -229,6 +230,17 @@ Providers with the FastTruncate capability will use an optimised method to trunc
.. versionadded:: 3.0

.. seealso:: :py:func:`deleteFeatures`
%End

virtual bool cancelReload();
%Docstring
Cancels the current reloading of data.

:return: true if the reloading has been correctly interrupted, false otherwise

.. versionadded:: 3.2

.. seealso:: :py:func:`reloadData`
%End

virtual bool addAttributes( const QList<QgsField> &attributes );
Expand Down
25 changes: 25 additions & 0 deletions python/core/qgsvirtuallayerdefinition.sip.in
Expand Up @@ -148,6 +148,31 @@ Get the name of the field with unique identifiers
void setUid( const QString &uid );
%Docstring
Set the name of the field with unique identifiers
%End

void setLazy( bool lazy );
%Docstring
Sets the lazy mode. If ``lazy`` is true, then the loading is
delayed until an explicit reloading of the layer.

:param lazy: True to delay the loading, false otherwise

.. versionadded:: 3.2

.. seealso:: :py:func:`QgsDataProvider.reloadData`

.. seealso:: :py:func:`isLazy`
%End

bool isLazy() const;
%Docstring
Returns the lazy mode.

:return: True if the loading is delayed, false otherwise.

.. versionadded:: 3.2

.. seealso:: :py:func:`setLazy`
%End

QString geometryField() const;
Expand Down
71 changes: 71 additions & 0 deletions python/core/qgsvirtuallayertask.sip.in
@@ -0,0 +1,71 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsvirtuallayertask.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/




class QgsVirtualLayerTask : QgsTask
{
%Docstring

Initializes a virtual layer with postpone mode activated and reloads the
data in a separated thread.

.. versionadded:: 3.2
%End

%TypeHeaderCode
#include "qgsvirtuallayertask.h"
%End
public:

QgsVirtualLayerTask( const QgsVirtualLayerDefinition &definition );
%Docstring
Constructor.

:param definition: The definition to use for initializing the virtual layer
%End

QgsVectorLayer *layer();
%Docstring
Returns the underlying virtual layer.
%End

QgsVectorLayer *takeLayer();
%Docstring
Returns the underlying virtual layer and ownership.
%End

QgsVirtualLayerDefinition definition() const;
%Docstring
Returns the virtual layer definition.
%End

virtual bool run();

%Docstring
Reloads the data.

:return: True if the virtual layer is valid, false otherwise.
%End

virtual void cancel();

%Docstring
Cancels the pending query and the parent task.
%End

};

/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsvirtuallayertask.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
3 changes: 3 additions & 0 deletions python/plugins/db_manager/db_plugins/connector.py
Expand Up @@ -42,6 +42,9 @@ def __del__(self):
def uri(self):
return QgsDataSourceUri(self._uri.uri(False))

def cancel(self):
pass

def publicUri(self):
publicUri = QgsDataSourceUri.removePassword(self._uri.uri(False))
return QgsDataSourceUri(publicUri)
Expand Down
55 changes: 51 additions & 4 deletions python/plugins/db_manager/db_plugins/data_model.py
Expand Up @@ -22,11 +22,20 @@
from builtins import str
from builtins import range

from qgis.PyQt.QtCore import Qt, QTime, QRegExp, QAbstractTableModel
from qgis.PyQt.QtGui import QFont, QStandardItemModel, QStandardItem
from qgis.PyQt.QtCore import (Qt,
QTime,
QRegExp,
QAbstractTableModel,
pyqtSignal,
QObject)
from qgis.PyQt.QtGui import (QFont,
QStandardItemModel,
QStandardItem)
from qgis.PyQt.QtWidgets import QApplication

from .plugin import DbError
from qgis.core import QgsTask

from .plugin import DbError, BaseError


class BaseTableModel(QAbstractTableModel):
Expand Down Expand Up @@ -139,6 +148,44 @@ def rowCount(self, index=None):
return self.table.rowCount if self.table.rowCount is not None and self.columnCount(index) > 0 else 0


class SqlResultModelAsync(QObject):

done = pyqtSignal()

def __init__(self):
super().__init__()
self.error = BaseError('')
self.status = None
self.model = None
self.task = None
self.canceled = False

def cancel(self):
self.canceled = True
if self.task:
self.task.cancel()

def modelDone(self):
if self.task:
self.status = self.task.status
self.model = self.task.model
self.error = self.task.error
self.task = None

self.done.emit()


class SqlResultModelTask(QgsTask):

def __init__(self, db, sql, parent):
super().__init__()
self.db = db
self.sql = sql
self.parent = parent
self.error = BaseError('')
self.model = None


class SqlResultModel(BaseTableModel):

def __init__(self, db, sql, parent=None):
Expand All @@ -165,7 +212,7 @@ def __init__(self, db, sql, parent=None):
data = []
header = []

BaseTableModel.__init__(self, header, data, parent)
super().__init__(header, data, parent)

# commit before closing the cursor to make sure that the changes are stored
self.db._commit()
Expand Down
4 changes: 4 additions & 0 deletions python/plugins/db_manager/db_plugins/gpkg/connector.py
Expand Up @@ -165,6 +165,10 @@ def _commit(self):
self._rollback()
raise DbError(e)

def cancel(self):
if self.connection:
self.connection.interrupt()

@classmethod
def isValidDatabase(cls, path):
if hasattr(gdal, 'OpenEx'):
Expand Down
37 changes: 36 additions & 1 deletion python/plugins/db_manager/db_plugins/gpkg/data_model.py
Expand Up @@ -20,7 +20,13 @@
***************************************************************************/
"""

from ..data_model import TableDataModel, SqlResultModel
from qgis.core import QgsMessageLog

from ..data_model import (TableDataModel,
SqlResultModel,
SqlResultModelAsync,
SqlResultModelTask)
from ..plugin import BaseError


class GPKGTableDataModel(TableDataModel):
Expand All @@ -47,5 +53,34 @@ def rowCount(self, index=None):
return self.fetchedCount


class GPKGSqlResultModelTask(SqlResultModelTask):

def __init__(self, db, sql, parent):
super().__init__(db, sql, parent)

def run(self):
try:
self.model = GPKGSqlResultModel(self.db, self.sql, None)
except BaseError as e:
self.error = e
QgsMessageLog.logMessage(e.msg)
return False
return True

def cancel(self):
self.db.connector.cancel()
SqlResultModelTask.cancel(self)


class GPKGSqlResultModelAsync(SqlResultModelAsync):

def __init__(self, db, sql, parent):
super().__init__()

self.task = GPKGSqlResultModelTask(db, sql, parent)
self.task.taskCompleted.connect(self.modelDone)
self.task.taskTerminated.connect(self.modelDone)


class GPKGSqlResultModel(SqlResultModel):
pass
5 changes: 5 additions & 0 deletions python/plugins/db_manager/db_plugins/gpkg/plugin.py
Expand Up @@ -132,6 +132,11 @@ def sqlResultModel(self, sql, parent):

return GPKGSqlResultModel(self, sql, parent)

def sqlResultModelAsync(self, sql, parent):
from .data_model import GPKGSqlResultModelAsync

return GPKGSqlResultModelAsync(self, sql, parent)

def registerDatabaseActions(self, mainWindow):
action = QAction(self.tr("Run &Vacuum"), self)
mainWindow.registerAction(action, self.tr("&Database"), self.runVacuumActionSlot)
Expand Down
5 changes: 5 additions & 0 deletions python/plugins/db_manager/db_plugins/plugin.py
Expand Up @@ -256,6 +256,11 @@ def sqlResultModel(self, sql, parent):

return SqlResultModel(self, sql, parent)

def sqlResultModelAsync(self, sql, parent):
from .data_model import SqlResultModelAsync

return SqlResultModelAsync(self, sql, parent)

def columnUniqueValuesModel(self, col, table, limit=10):
l = ""
if limit is not None:
Expand Down
4 changes: 4 additions & 0 deletions python/plugins/db_manager/db_plugins/postgis/connector.py
Expand Up @@ -186,6 +186,10 @@ def _checkRasterColumnsTable(self):
self.has_raster_columns_access = self.getTablePrivileges('raster_columns')[0]
return self.has_raster_columns

def cancel(self):
if self.connection:
self.connection.cancel()

def getInfo(self):
c = self._execute(None, u"SELECT version()")
res = self._fetchone(c)
Expand Down
37 changes: 35 additions & 2 deletions python/plugins/db_manager/db_plugins/postgis/data_model.py
Expand Up @@ -20,8 +20,12 @@
***************************************************************************/
"""


from ..data_model import TableDataModel, SqlResultModel
from qgis.core import QgsMessageLog
from ..plugin import BaseError
from ..data_model import (TableDataModel,
SqlResultModel,
SqlResultModelAsync,
SqlResultModelTask)


class PGTableDataModel(TableDataModel):
Expand Down Expand Up @@ -79,5 +83,34 @@ def fetchMoreData(self, row_start):
self.fetchedFrom = row_start


class PGSqlResultModelTask(SqlResultModelTask):

def __init__(self, db, sql, parent):
super().__init__(db, sql, parent)

def run(self):
try:
self.model = PGSqlResultModel(self.db, self.sql, None)
except BaseError as e:
self.error = e
QgsMessageLog.logMessage(e.msg)
return False
return True

def cancel(self):
self.db.connector.cancel()
SqlResultModelTask.cancel(self)


class PGSqlResultModelAsync(SqlResultModelAsync):

def __init__(self, db, sql, parent):
super().__init__()

self.task = PGSqlResultModelTask(db, sql, parent)
self.task.taskCompleted.connect(self.modelDone)
self.task.taskTerminated.connect(self.modelDone)


class PGSqlResultModel(SqlResultModel):
pass
5 changes: 5 additions & 0 deletions python/plugins/db_manager/db_plugins/postgis/plugin.py
Expand Up @@ -134,6 +134,11 @@ def sqlResultModel(self, sql, parent):

return PGSqlResultModel(self, sql, parent)

def sqlResultModelAsync(self, sql, parent):
from .data_model import PGSqlResultModelAsync

return PGSqlResultModelAsync(self, sql, parent)

def registerDatabaseActions(self, mainWindow):
Database.registerDatabaseActions(self, mainWindow)

Expand Down
6 changes: 6 additions & 0 deletions python/plugins/db_manager/db_plugins/spatialite/connector.py
Expand Up @@ -59,6 +59,12 @@ def __init__(self, uri):
def _connectionInfo(self):
return str(self.dbname)

def cancel(self):
# https://www.sqlite.org/c3ref/interrupt.html
# This function causes any pending database operation to abort and return at its earliest opportunity.
if self.connection:
self.connection.interrupt()

@classmethod
def isValidDatabase(self, path):
if not QFile.exists(path):
Expand Down

0 comments on commit 7c3ab9f

Please sign in to comment.