QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
qgsvaliditycheckresultswidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvaliditycheckresultswidget.cpp
3  ----------------------------------
4  begin : November 2018
5  copyright : (C) 2018 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
18 #include "qgsapplication.h"
19 #include "qgsfeedback.h"
20 #include "qgsproxyprogresstask.h"
21 #include <QProgressDialog>
22 #include <QDialogButtonBox>
23 #include <QPushButton>
24 
25 //
26 // QgsValidityCheckResultsModel
27 //
28 
29 QgsValidityCheckResultsModel::QgsValidityCheckResultsModel( const QList<QgsValidityCheckResult> &results, QObject *parent )
30  : QAbstractItemModel( parent )
31  , mResults( results )
32 {
33 
34 }
35 
36 QModelIndex QgsValidityCheckResultsModel::index( int row, int column, const QModelIndex &parent ) const
37 {
38  Q_UNUSED( parent )
39  return createIndex( row, column );
40 }
41 
42 QModelIndex QgsValidityCheckResultsModel::parent( const QModelIndex &child ) const
43 {
44  Q_UNUSED( child )
45  return QModelIndex();
46 }
47 
48 int QgsValidityCheckResultsModel::rowCount( const QModelIndex &parent ) const
49 {
50  Q_UNUSED( parent )
51  return mResults.count();
52 }
53 
54 int QgsValidityCheckResultsModel::columnCount( const QModelIndex &parent ) const
55 {
56  Q_UNUSED( parent )
57  return 1;
58 }
59 
60 QVariant QgsValidityCheckResultsModel::data( const QModelIndex &index, int role ) const
61 {
62  if ( index.row() >= mResults.count() || index.row() < 0 )
63  return QVariant();
64 
65  const QgsValidityCheckResult &res = mResults.at( index.row() );
66  switch ( role )
67  {
68  case Qt::DisplayRole:
69  case Qt::ToolTipRole:
70  return res.title;
71 
73  return res.detailedDescription;
74 
75  case Qt::DecorationRole:
76  switch ( res.type )
77  {
79  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconCritical.svg" ) );
80 
82  return QgsApplication::getThemeIcon( QStringLiteral( "/mIconWarning.svg" ) );
83  }
84  break;
85 
86  default:
87  return QVariant();
88  }
89  return QVariant();
90 }
91 
92 //
93 // QgsValidityCheckResultsWidget
94 //
95 
97  : QWidget( parent )
98 {
99  setupUi( this );
100 
101 }
102 
103 void QgsValidityCheckResultsWidget::setResults( const QList<QgsValidityCheckResult> &results )
104 {
105  if ( mResultsModel )
106  mResultsModel->deleteLater();
107 
108  mResultsModel = new QgsValidityCheckResultsModel( results, this );
109  mResultsListView->setModel( mResultsModel );
110 
111  connect( mResultsListView->selectionModel(), &QItemSelectionModel::currentChanged, this, &QgsValidityCheckResultsWidget::selectionChanged );
112 
113  if ( mResultsModel->rowCount() > 0 )
114  {
115  // auto select first result in list
116  const QModelIndex firstResult( mResultsModel->index( 0, 0, QModelIndex() ) );
117  mResultsListView->selectionModel()->select( firstResult, QItemSelectionModel::ClearAndSelect );
118  selectionChanged( firstResult, QModelIndex() );
119  }
120 
121  mDescriptionLabel->hide();
122 }
123 
124 void QgsValidityCheckResultsWidget::setDescription( const QString &description )
125 {
126  mDescriptionLabel->setText( description );
127  mDescriptionLabel->setVisible( !description.isEmpty() );
128 }
129 
130 bool QgsValidityCheckResultsWidget::runChecks( int type, const QgsValidityCheckContext *context, const QString &title, const QString &description, QWidget *parent )
131 {
132  std::unique_ptr< QgsFeedback > feedback = qgis::make_unique< QgsFeedback >();
133  std::unique_ptr< QProgressDialog > progressDialog = qgis::make_unique< QProgressDialog >( tr( "Running Checks…" ), tr( "Abort" ), 0, 100, parent );
134  progressDialog->setWindowTitle( title );
135 
136  QgsProxyProgressTask *proxyTask = new QgsProxyProgressTask( tr( "Running Checks" ) );
137 
138  connect( feedback.get(), &QgsFeedback::progressChanged, progressDialog.get(), [ & ]( double progress )
139  {
140  progressDialog->setValue( static_cast< int >( progress ) );
141  progressDialog->setLabelText( feedback->property( "progress" ).toString() ) ;
142 
143  proxyTask->setProxyProgress( progress );
144 
145 #ifdef Q_OS_LINUX
146  // For some reason on Windows hasPendingEvents() always return true,
147  // but one iteration is actually enough on Windows to get good interactivity
148  // whereas on Linux we must allow for far more iterations.
149  // For safety limit the number of iterations
150  int nIters = 0;
151  while ( QCoreApplication::hasPendingEvents() && ++nIters < 100 )
152 #endif
153  {
154  QCoreApplication::processEvents();
155  }
156 
157  } );
158  connect( progressDialog.get(), &QProgressDialog::canceled, progressDialog.get(), [ & ]
159  {
160  feedback->cancel();
161  } );
162 
163  QgsApplication::taskManager()->addTask( proxyTask );
164 
165  const QList<QgsValidityCheckResult> results = QgsApplication::validityCheckRegistry()->runChecks( type, context, feedback.get() );
166 
167  proxyTask->finalize( true );
168 
169  if ( feedback->isCanceled() )
170  return false;
171 
172  if ( results.empty() )
173  return true;
174 
176  w->setResults( results );
177  w->setDescription( description );
178 
179  bool hasCritical = false;
180  for ( const QgsValidityCheckResult &res : results )
181  {
182  if ( res.type == QgsValidityCheckResult::Critical )
183  {
184  hasCritical = true;
185  break;
186  }
187  }
188 
189  QVBoxLayout *l = new QVBoxLayout();
190  l->addWidget( w );
191 
192  QDialog dlg( parent );
193  dlg.setWindowTitle( title );
194 
195  QDialogButtonBox *buttons = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dlg );
196  connect( buttons, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
197  connect( buttons, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
198  if ( hasCritical )
199  {
200  buttons->button( QDialogButtonBox::Ok )->setEnabled( false );
201  buttons->button( QDialogButtonBox::Ok )->setToolTip( tr( "Critical errors prevent this task from proceeding. Please address these issues and then retry." ) );
202  }
203 
204  l->addWidget( buttons );
205 
206  dlg.setLayout( l );
207 
208  return dlg.exec();
209 }
210 
211 void QgsValidityCheckResultsWidget::selectionChanged( const QModelIndex &current, const QModelIndex & )
212 {
213  const QString desc = mResultsModel->data( current, QgsValidityCheckResultsModel::DescriptionRole ).toString();
214  mDetailedDescriptionTextBrowser->setHtml( desc );
215 }
QModelIndex parent(const QModelIndex &child) const override
Represents an individual result from a validity check run by a QgsAbstractValidityCheck subclass...
QString detailedDescription
Detailed description of the result (translated), giving users enough detail for them to resolve the e...
QVariant data(const QModelIndex &index, int role) const override
Warning only, allow operation to proceed but notify user of result.
static QgsValidityCheckRegistry * validityCheckRegistry()
Returns the application&#39;s validity check registry, used for managing validity checks.
A QAbstractItemModel subclass for displaying the results from a QgsAbtractValidityCheck.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
void setProxyProgress(double progress)
Sets the progress (from 0 to 100) for the proxied operation.
void setDescription(const QString &description)
Sets a description label to show at the top of the widget, e.g.
QModelIndex index(int row, int column, const QModelIndex &parent) const override
QList< QgsValidityCheckResult > runChecks(int type, const QgsValidityCheckContext *context, QgsFeedback *feedback) const
Runs all checks of the specified type and returns a list of results.
static QgsTaskManager * taskManager()
Returns the application&#39;s task manager, used for managing application wide background task handling...
A reusable widget which displays a summary of the results from a QgsAbstractValidityCheck (or checks)...
void progressChanged(double progress)
Emitted when the feedback object reports a progress change.
static bool runChecks(int type, const QgsValidityCheckContext *context, const QString &title, const QString &description, QWidget *parent=nullptr)
Runs all registered validity checks of the given type, and if any warnings or critical errors are enc...
QgsValidityCheckResultsWidget(QWidget *parent)
Constructor for QgsValidityCheckResultsWidget, with the specified parent widget.
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
int columnCount(const QModelIndex &parent) const override
Critical error - notify user of result and prevent operation from proceeding.
Base class for validity check contexts.
A QgsTask shell which proxies progress reports.
void finalize(bool result)
Finalizes the task, with the specified result.
void setResults(const QList< QgsValidityCheckResult > &results)
Sets the list of check results to show in the dialog.
QgsValidityCheckResultsModel(const QList< QgsValidityCheckResult > &results, QObject *parent=nullptr)
Constructor for QgsValidityCheckResultsModel, showing the specified list of checks results...
QString title
A short, translated string summarising the result.