QGIS API Documentation  3.27.0-Master (aef1b1ec20)
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
7  email : [email protected]
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 
18 const 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 
39 void 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 
47 bool 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 
55 void 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 
77 QStringList QgsQueryResultModel::columns() const
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 
96 int QgsQueryResultModel::rowCount( const QModelIndex &parent ) const
97 {
98  if ( parent.isValid() )
99  return 0;
100  return mRows.count();
101 }
102 
103 int QgsQueryResultModel::columnCount( const QModelIndex &parent ) const
104 {
105  if ( parent.isValid() )
106  return 0;
107  return mColumns.count();
108 }
109 
110 QVariant 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 
131 QVariant 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 
142 const int QgsQueryResultFetcher::ROWS_BATCH_COUNT = 200;
143 
144 void 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 
168 void 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...