QGIS API Documentation  3.27.0-Master (aef1b1ec20)
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 = std::make_unique< QgsFeedback >();
133  std::unique_ptr< QProgressDialog > progressDialog = std::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  // One iteration is actually enough on Windows to get good interactivity
147  // whereas on Linux we must allow for far more iterations.
148  int nIters = 0;
149  while ( ++nIters < 100 )
150 #endif
151  {
152  QCoreApplication::processEvents();
153  }
154 
155  } );
156  connect( progressDialog.get(), &QProgressDialog::canceled, progressDialog.get(), [ & ]
157  {
158  feedback->cancel();
159  } );
160 
161  QgsApplication::taskManager()->addTask( proxyTask );
162 
163  const QList<QgsValidityCheckResult> results = QgsApplication::validityCheckRegistry()->runChecks( type, context, feedback.get() );
164 
165  proxyTask->finalize( true );
166 
167  if ( feedback->isCanceled() )
168  return false;
169 
170  if ( results.empty() )
171  return true;
172 
174  w->setResults( results );
175  w->setDescription( description );
176 
177  bool hasCritical = false;
178  for ( const QgsValidityCheckResult &res : results )
179  {
180  if ( res.type == QgsValidityCheckResult::Critical )
181  {
182  hasCritical = true;
183  break;
184  }
185  }
186 
187  QVBoxLayout *l = new QVBoxLayout();
188  l->addWidget( w );
189 
190  QDialog dlg( parent );
191  dlg.setWindowTitle( title );
192 
193  QDialogButtonBox *buttons = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dlg );
194  connect( buttons, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
195  connect( buttons, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
196  if ( hasCritical )
197  {
198  buttons->button( QDialogButtonBox::Ok )->setEnabled( false );
199  buttons->button( QDialogButtonBox::Ok )->setToolTip( tr( "Critical errors prevent this task from proceeding. Please address these issues and then retry." ) );
200  }
201 
202  l->addWidget( buttons );
203 
204  dlg.setLayout( l );
205 
206  return dlg.exec();
207 }
208 
209 void QgsValidityCheckResultsWidget::selectionChanged( const QModelIndex &current, const QModelIndex & )
210 {
211  const QString desc = mResultsModel->data( current, QgsValidityCheckResultsModel::DescriptionRole ).toString();
212  mDetailedDescriptionTextBrowser->setHtml( desc );
213 }
static QgsValidityCheckRegistry * validityCheckRegistry()
Returns the application's validity check registry, used for managing validity checks.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsTaskManager * taskManager()
Returns the application's task manager, used for managing application wide background task handling.
void progressChanged(double progress)
Emitted when the feedback object reports a progress change.
A QgsTask shell which proxies progress reports.
long addTask(QgsTask *task, int priority=0)
Adds a task to the manager.
Base class for validity check contexts.
QList< QgsValidityCheckResult > runChecks(int type, const QgsValidityCheckContext *context, QgsFeedback *feedback) const
Runs all checks of the specified type and returns a list of results.
Represents an individual result from a validity check run by a QgsAbstractValidityCheck subclass.
@ Critical
Critical error - notify user of result and prevent operation from proceeding.
@ Warning
Warning only, allow operation to proceed but notify user of result.
QString detailedDescription
Detailed description of the result (translated), giving users enough detail for them to resolve the e...
QString title
A short, translated string summarising the result.
A QAbstractItemModel subclass for displaying the results from a QgsAbtractValidityCheck.
QgsValidityCheckResultsModel(const QList< QgsValidityCheckResult > &results, QObject *parent=nullptr)
Constructor for QgsValidityCheckResultsModel, showing the specified list of checks results.
@ DescriptionRole
Result detailed description.
QModelIndex parent(const QModelIndex &child) const override
QModelIndex index(int row, int column, const QModelIndex &parent) const override
int columnCount(const QModelIndex &parent) const override
QVariant data(const QModelIndex &index, int role) const override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
A reusable widget which displays a summary of the results from a QgsAbstractValidityCheck (or checks)...
QgsValidityCheckResultsWidget(QWidget *parent)
Constructor for QgsValidityCheckResultsWidget, with the specified parent widget.
void setDescription(const QString &description)
Sets a description label to show at the top of the widget, e.g.
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...
void setResults(const QList< QgsValidityCheckResult > &results)
Sets the list of check results to show in the dialog.