QGIS API Documentation 3.41.0-Master (fda2aa46e9a)
Loading...
Searching...
No Matches
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#include "moc_qgsqueryresultmodel.cpp"
18#include "qgsexpression.h"
19
20const int QgsQueryResultModel::FETCH_MORE_ROWS_COUNT = 400;
21
22QgsQueryResultModel::QgsQueryResultModel( const QgsAbstractDatabaseProviderConnection::QueryResult &queryResult, QObject *parent )
23 : QAbstractTableModel( parent )
24 , mQueryResult( queryResult )
25 , mColumns( queryResult.columns() )
26{
27 qRegisterMetaType< QList<QList<QVariant>>>( "QList<QList<QVariant>>" );
28 mWorker = std::make_unique<QgsQueryResultFetcher>( &mQueryResult );
29 mWorker->moveToThread( &mWorkerThread );
30 // Forward signals to the model
31 connect( mWorker.get(), &QgsQueryResultFetcher::rowsReady, this, &QgsQueryResultModel::rowsReady );
32 connect( mWorker.get(), &QgsQueryResultFetcher::fetchingComplete, this, &QgsQueryResultModel::fetchingComplete );
33 connect( this, &QgsQueryResultModel::fetchMoreRows, mWorker.get(), &QgsQueryResultFetcher::fetchRows );
34 mWorkerThread.start();
35 if ( mQueryResult.rowCount() > 0 )
36 {
37 mRows.reserve( mQueryResult.rowCount() );
38 }
39}
40
41void QgsQueryResultModel::rowsReady( const QList<QList<QVariant>> &rows )
42{
43 beginInsertRows( QModelIndex(), mRows.count( ), mRows.count( ) + rows.count() - 1 );
44 mRows.append( rows );
45 endInsertRows();
46}
47
48
49bool QgsQueryResultModel::canFetchMore( const QModelIndex &parent ) const
50{
51 if ( parent.isValid() )
52 return false;
53 return mQueryResult.rowCount() < 0 || mRows.length() < mQueryResult.rowCount();
54}
55
56
57void QgsQueryResultModel::fetchMore( const QModelIndex &parent )
58{
59 if ( ! parent.isValid() )
60 {
61 emit fetchingStarted();
62 emit fetchMoreRows( FETCH_MORE_ROWS_COUNT );
63 }
64}
65
66void QgsQueryResultModel::cancel()
67{
68 if ( mWorker )
69 {
70 mWorker->stopFetching();
71 }
72}
73
74QgsAbstractDatabaseProviderConnection::QueryResult QgsQueryResultModel::queryResult() const
75{
76 return mQueryResult;
77}
78
79QStringList QgsQueryResultModel::columns() const
80{
81 return mColumns;
82}
83
84QgsQueryResultModel::~QgsQueryResultModel()
85{
86 if ( mWorker )
87 {
88 mWorker->stopFetching();
89 mWorkerThread.quit();
90 mWorkerThread.wait();
91 }
92 else
93 {
94 emit fetchingComplete();
95 }
96}
97
98int QgsQueryResultModel::rowCount( const QModelIndex &parent ) const
99{
100 if ( parent.isValid() )
101 return 0;
102 return mRows.count();
103}
104
105int QgsQueryResultModel::columnCount( const QModelIndex &parent ) const
106{
107 if ( parent.isValid() )
108 return 0;
109 return mColumns.count();
110}
111
112QVariant QgsQueryResultModel::data( const QModelIndex &index, int role ) const
113{
114 if ( !index.isValid() || index.row() < 0 || index.column() >= mColumns.count() ||
115 index.row() >= mRows.count( ) )
116 return QVariant();
117
118 switch ( role )
119 {
120 case Qt::DisplayRole:
121 {
122 const QList<QVariant> result = mRows.at( index.row() );
123 if ( index.column() < result.count( ) )
124 {
125 return result.at( index.column() );
126 }
127 break;
128 }
129
130 case Qt::ToolTipRole:
131 {
132 const QList<QVariant> result = mRows.at( index.row() );
133 if ( index.column() < result.count( ) )
134 {
135 const QVariant value = result.at( index.column() );
136 return QgsExpression::formatPreviewString( value, true, 255 );
137 }
138 break;
139 }
140 }
141 return QVariant();
142}
143
144QVariant QgsQueryResultModel::headerData( int section, Qt::Orientation orientation, int role ) const
145{
146 if ( orientation == Qt::Orientation::Horizontal && role == Qt::ItemDataRole::DisplayRole && section < mColumns.count() )
147 {
148 return mColumns.at( section );
149 }
150 return QAbstractTableModel::headerData( section, orientation, role );
151}
152
154
155const int QgsQueryResultFetcher::ROWS_BATCH_COUNT = 200;
156
157void QgsQueryResultFetcher::fetchRows( long long maxRows )
158{
159 long long rowCount { 0 };
160 QList<QList<QVariant>> newRows;
161 newRows.reserve( ROWS_BATCH_COUNT );
162 while ( mStopFetching == 0 && mQueryResult->hasNextRow() && ( maxRows < 0 || rowCount < maxRows ) )
163 {
164 newRows.append( mQueryResult->nextRow() );
165 ++rowCount;
166 if ( rowCount % ROWS_BATCH_COUNT == 0 && mStopFetching == 0 )
167 {
168 emit rowsReady( newRows );
169 newRows.clear();
170 }
171 }
172
173 if ( rowCount % ROWS_BATCH_COUNT && mStopFetching == 0 )
174 {
175 emit rowsReady( newRows );
176 }
177
178 emit fetchingComplete();
179}
180
181void QgsQueryResultFetcher::stopFetching()
182{
183 mStopFetching = 1;
184}
185
186
static QString formatPreviewString(const QVariant &value, bool htmlOutput=true, int maximumPreviewLength=60)
Formats an expression result for friendly display to the user.
The QueryResult class represents the result of a query executed by execSql()