QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgsqueryresultmodel.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsqueryresultmodel.cpp - QgsQueryResultModel
3
4 ---------------------
5 begin : 24.12.2020
6 copyright : (C) 2020 by Alessandro Pasotti
8 ***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16#include "qgsqueryresultmodel.h"
17
18const int QgsQueryResultModel::FETCH_MORE_ROWS_COUNT = 400;
19
21 : QAbstractTableModel( parent )
22 , mQueryResult( queryResult )
23 , mColumns( queryResult.columns() )
24{
25 qRegisterMetaType< QList<QList<QVariant>>>( "QList<QList<QVariant>>" );
26 mWorker = std::make_unique<QgsQueryResultFetcher>( &mQueryResult );
27 mWorker->moveToThread( &mWorkerThread );
28 // Forward signals to the model
29 connect( mWorker.get(), &QgsQueryResultFetcher::rowsReady, this, &QgsQueryResultModel::rowsReady );
30 connect( mWorker.get(), &QgsQueryResultFetcher::fetchingComplete, this, &QgsQueryResultModel::fetchingComplete );
31 connect( this, &QgsQueryResultModel::fetchMoreRows, mWorker.get(), &QgsQueryResultFetcher::fetchRows );
32 mWorkerThread.start();
33 if ( mQueryResult.rowCount() > 0 )
34 {
35 mRows.reserve( mQueryResult.rowCount() );
36 }
37}
38
39void QgsQueryResultModel::rowsReady( const QList<QList<QVariant>> &rows )
40{
41 beginInsertRows( QModelIndex(), mRows.count( ), mRows.count( ) + rows.count() - 1 );
42 mRows.append( rows );
43 endInsertRows();
44}
45
46
47bool QgsQueryResultModel::canFetchMore( const QModelIndex &parent ) const
48{
49 if ( parent.isValid() )
50 return false;
51 return mQueryResult.rowCount() < 0 || mRows.length() < mQueryResult.rowCount();
52}
53
54
55void QgsQueryResultModel::fetchMore( const QModelIndex &parent )
56{
57 if ( ! parent.isValid() )
58 {
59 emit fetchingStarted();
60 emit fetchMoreRows( FETCH_MORE_ROWS_COUNT );
61 }
62}
63
65{
66 if ( mWorker )
67 {
68 mWorker->stopFetching();
69 }
70}
71
73{
74 return mQueryResult;
75}
76
78{
79 return mColumns;
80}
81
83{
84 if ( mWorker )
85 {
86 mWorker->stopFetching();
87 mWorkerThread.quit();
88 mWorkerThread.wait();
89 }
90 else
91 {
92 emit fetchingComplete();
93 }
94}
95
96int QgsQueryResultModel::rowCount( const QModelIndex &parent ) const
97{
98 if ( parent.isValid() )
99 return 0;
100 return mRows.count();
101}
102
103int QgsQueryResultModel::columnCount( const QModelIndex &parent ) const
104{
105 if ( parent.isValid() )
106 return 0;
107 return mColumns.count();
108}
109
110QVariant QgsQueryResultModel::data( const QModelIndex &index, int role ) const
111{
112 if ( !index.isValid() || index.row() < 0 || index.column() >= mColumns.count() ||
113 index.row() >= mRows.count( ) )
114 return QVariant();
115
116 switch ( role )
117 {
118 case Qt::DisplayRole:
119 {
120 const QList<QVariant> result = mRows.at( index.row() );
121 if ( index.column() < result.count( ) )
122 {
123 return result.at( index.column() );
124 }
125 break;
126 }
127 }
128 return QVariant();
129}
130
131QVariant QgsQueryResultModel::headerData( int section, Qt::Orientation orientation, int role ) const
132{
133 if ( orientation == Qt::Orientation::Horizontal && role == Qt::ItemDataRole::DisplayRole && section < mColumns.count() )
134 {
135 return mColumns.at( section );
136 }
137 return QAbstractTableModel::headerData( section, orientation, role );
138}
139
141
142const int QgsQueryResultFetcher::ROWS_BATCH_COUNT = 200;
143
144void QgsQueryResultFetcher::fetchRows( long long maxRows )
145{
146 long long rowCount { 0 };
147 QList<QList<QVariant>> newRows;
148 newRows.reserve( ROWS_BATCH_COUNT );
149 while ( mStopFetching == 0 && mQueryResult->hasNextRow() && ( maxRows < 0 || rowCount < maxRows ) )
150 {
151 newRows.append( mQueryResult->nextRow() );
152 ++rowCount;
153 if ( rowCount % ROWS_BATCH_COUNT == 0 && mStopFetching == 0 )
154 {
155 emit rowsReady( newRows );
156 newRows.clear();
157 }
158 }
159
160 if ( rowCount % ROWS_BATCH_COUNT && mStopFetching == 0 )
161 {
162 emit rowsReady( newRows );
163 }
164
165 emit fetchingComplete();
166}
167
168void QgsQueryResultFetcher::stopFetching()
169{
170 mStopFetching = 1;
171}
172
173
QgsAbstractDatabaseProviderConnection::QueryResult queryResult() const
Returns the query result.
int rowCount(const QModelIndex &parent) const override
QgsQueryResultModel(const QgsAbstractDatabaseProviderConnection::QueryResult &queryResult, QObject *parent=nullptr)
Constructs a QgsQueryResultModel from a queryResult with optional parent.
void rowsReady(const QList< QList< QVariant > > &rows)
Triggered when newRows have been fetched and can be added to the model.
void fetchingStarted()
Emitted when fetching of rows has started.
QVariant data(const QModelIndex &index, int role) const override
void fetchMore(const QModelIndex &parent) override
void fetchMoreRows(qlonglong maxRows)
Emitted when more rows are requested.
void fetchingComplete()
Emitted when rows have been fetched (all of them or a batch if maxRows was passed to fetchMoreRows() ...
int columnCount(const QModelIndex &parent) const override
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
void cancel()
Cancels the row fetching.
QStringList columns() const
Returns the column names.
bool canFetchMore(const QModelIndex &parent) const override
The QueryResult class represents the result of a query executed by execSql()
long long rowCount() const
Returns the number of rows returned by a SELECT query or Qgis::FeatureCountState::UnknownCount if unk...