QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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  mDescriptionLabel->hide();
114 }
115 
116 void QgsValidityCheckResultsWidget::setDescription( const QString &description )
117 {
118  mDescriptionLabel->setText( description );
119  mDescriptionLabel->setVisible( !description.isEmpty() );
120 }
121 
122 bool QgsValidityCheckResultsWidget::runChecks( int type, const QgsValidityCheckContext *context, const QString &title, const QString &description, QWidget *parent )
123 {
124  std::unique_ptr< QgsFeedback > feedback = qgis::make_unique< QgsFeedback >();
125  std::unique_ptr< QProgressDialog > progressDialog = qgis::make_unique< QProgressDialog >( tr( "Running Checks…" ), tr( "Abort" ), 0, 100, parent );
126  progressDialog->setWindowTitle( title );
127 
128  QgsProxyProgressTask *proxyTask = new QgsProxyProgressTask( tr( "Running Checks" ) );
129 
130  connect( feedback.get(), &QgsFeedback::progressChanged, progressDialog.get(), [ & ]( double progress )
131  {
132  progressDialog->setValue( static_cast< int >( progress ) );
133  progressDialog->setLabelText( feedback->property( "progress" ).toString() ) ;
134 
135  proxyTask->setProxyProgress( progress );
136 
137 #ifdef Q_OS_LINUX
138  // For some reason on Windows hasPendingEvents() always return true,
139  // but one iteration is actually enough on Windows to get good interactivity
140  // whereas on Linux we must allow for far more iterations.
141  // For safety limit the number of iterations
142  int nIters = 0;
143  while ( QCoreApplication::hasPendingEvents() && ++nIters < 100 )
144 #endif
145  {
146  QCoreApplication::processEvents();
147  }
148 
149  } );
150  connect( progressDialog.get(), &QProgressDialog::canceled, progressDialog.get(), [ & ]
151  {
152  feedback->cancel();
153  } );
154 
155  QgsApplication::taskManager()->addTask( proxyTask );
156 
157  const QList<QgsValidityCheckResult> results = QgsApplication::validityCheckRegistry()->runChecks( type, context, feedback.get() );
158 
159  proxyTask->finalize( true );
160 
161  if ( feedback->isCanceled() )
162  return false;
163 
164  if ( results.empty() )
165  return true;
166 
168  w->setResults( results );
169  w->setDescription( description );
170 
171  bool hasCritical = false;
172  for ( const QgsValidityCheckResult &res : results )
173  {
174  if ( res.type == QgsValidityCheckResult::Critical )
175  {
176  hasCritical = true;
177  break;
178  }
179  }
180 
181  QVBoxLayout *l = new QVBoxLayout();
182  l->addWidget( w );
183 
184  QDialog dlg( parent );
185  dlg.setWindowTitle( title );
186 
187  QDialogButtonBox *buttons = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dlg );
188  connect( buttons, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
189  connect( buttons, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
190  if ( hasCritical )
191  {
192  buttons->button( QDialogButtonBox::Ok )->setEnabled( false );
193  buttons->button( QDialogButtonBox::Ok )->setToolTip( tr( "Critical errors prevent this task from proceeding. Please address these issues and then retry." ) );
194  }
195 
196  l->addWidget( buttons );
197 
198  dlg.setLayout( l );
199 
200  return dlg.exec();
201 }
202 
203 void QgsValidityCheckResultsWidget::selectionChanged( const QModelIndex &current, const QModelIndex & )
204 {
205  const QString desc = mResultsModel->data( current, QgsValidityCheckResultsModel::DescriptionRole ).toString();
206  mDetailedDescriptionTextBrowser->setHtml( desc );
207 }
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.