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