QGIS API Documentation 3.43.0-Master (87898417f79)
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
7 email : elpaso@itopen.it
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 && section < mColumns.count() )
147 {
148 switch ( role )
149 {
150 case Qt::ItemDataRole::DisplayRole:
151 case Qt::ItemDataRole::ToolTipRole:
152 return mColumns.at( section );
153
154 default:
155 break;
156 }
157 }
158 return QAbstractTableModel::headerData( section, orientation, role );
159}
160
162
163const int QgsQueryResultFetcher::ROWS_BATCH_COUNT = 200;
164
165void QgsQueryResultFetcher::fetchRows( long long maxRows )
166{
167 long long rowCount { 0 };
168 QList<QList<QVariant>> newRows;
169 newRows.reserve( ROWS_BATCH_COUNT );
170 while ( mStopFetching == 0 && mQueryResult->hasNextRow() && ( maxRows < 0 || rowCount < maxRows ) )
171 {
172 newRows.append( mQueryResult->nextRow() );
173 ++rowCount;
174 if ( rowCount % ROWS_BATCH_COUNT == 0 && mStopFetching == 0 )
175 {
176 emit rowsReady( newRows );
177 newRows.clear();
178 }
179 }
180
181 if ( rowCount % ROWS_BATCH_COUNT && mStopFetching == 0 )
182 {
183 emit rowsReady( newRows );
184 }
185
186 emit fetchingComplete();
187}
188
189void QgsQueryResultFetcher::stopFetching()
190{
191 mStopFetching = 1;
192}
193
194
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()