Skip to content

Commit a72cec0

Browse files
committedSep 25, 2015
[GRASS] show import progress in browser properties widget
1 parent 2ef38ff commit a72cec0

File tree

5 files changed

+163
-41
lines changed

5 files changed

+163
-41
lines changed
 

‎src/providers/grass/qgis.v.in.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,18 +318,24 @@ int main( int argc, char **argv )
318318
if ( isPolygon )
319319
{
320320
double snapTreshold = 0;
321+
G_message( "Building partial topology" );
321322
Vect_build_partial( map, GV_BUILD_BASE );
322323

323324
if ( snapTreshold > 0 )
324325
{
325326
Vect_snap_lines( map, GV_BOUNDARY, snapTreshold, NULL );
326327
}
328+
G_message( "Breaking polygons" );
327329
Vect_break_polygons( map, GV_BOUNDARY, NULL );
330+
G_message( "Removing duplicates" );
328331
Vect_remove_duplicates( map, GV_BOUNDARY | GV_CENTROID, NULL );
329332
while ( true )
330333
{
334+
G_message( "Breaking lines" );
331335
Vect_break_lines( map, GV_BOUNDARY, NULL );
336+
G_message( "Removing duplicates" );
332337
Vect_remove_duplicates( map, GV_BOUNDARY, NULL );
338+
G_message( "Cleaning small dangles at nodes" );
333339
if ( Vect_clean_small_angles_at_nodes( map, GV_BOUNDARY, NULL ) == 0 )
334340
{
335341
break;
@@ -358,15 +364,19 @@ int main( int argc, char **argv )
358364
}
359365
}
360366

367+
G_message( "Merging lines" );
361368
Vect_merge_lines( map, GV_BOUNDARY, NULL, NULL );
369+
G_message( "Removing bridges" );
362370
#if GRASS_VERSION_MAJOR < 7
363371
Vect_remove_bridges( map, NULL );
364372
#else
365373
int linesRemoved, bridgesRemoved;
366374
Vect_remove_bridges( map, NULL, &linesRemoved, &bridgesRemoved );
367375
#endif
376+
G_message( "Attaching islands" );
368377
Vect_build_partial( map, GV_BUILD_ATTACH_ISLES );
369378

379+
G_message( "Creating centroids" );
370380
QMap<QgsFeatureId, QgsFeature> centroids;
371381
QgsSpatialIndex spatialIndex;
372382
int nAreas = Vect_get_num_areas( map );
@@ -385,6 +395,7 @@ int main( int argc, char **argv )
385395
centroids.insert( area, feature );
386396
spatialIndex.insertFeature( feature );
387397
}
398+
G_message( "Attaching input polygons to cleaned areas" );
388399
// read once more to assign centroids to polygons
389400
while ( true )
390401
{

‎src/providers/grass/qgsgrassimport.cpp

Lines changed: 84 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,11 @@ QgsGrassImport::QgsGrassImport( QgsGrassObject grassObject )
5353
: QObject()
5454
, mGrassObject( grassObject )
5555
, mCanceled( false )
56+
, mProcess( 0 )
5657
, mFutureWatcher( 0 )
58+
, mProgressMin( 0 )
59+
, mProgressMax( 0 )
60+
, mProgressValue( 0 )
5761
{
5862
// QMovie used by QgsAnimatedIcon is using QTimer which cannot be start from another thread
5963
// (it works on Linux however) so we cannot start it connecting from QgsGrassImportItem and
@@ -121,6 +125,28 @@ void QgsGrassImport::cancel()
121125
mCanceled = true;
122126
}
123127

128+
void QgsGrassImport::emitProgressChanged()
129+
{
130+
emit progressChanged( mProgressHtml + mProgressTmpHtml, mProgressMin, mProgressMax, mProgressValue );
131+
132+
}
133+
134+
void QgsGrassImport::onReadyReadStandardError()
135+
{
136+
if ( mProcess )
137+
{
138+
// TODO: should be locked? Lock does not help anyway.
139+
// TODO: parse better progress output
140+
mProgressHtml += QString( mProcess->readAllStandardError() ).replace( "\n", "<br>" );
141+
emitProgressChanged();
142+
}
143+
}
144+
145+
void QgsGrassImport::addProgressRow( QString html )
146+
{
147+
mProgressHtml += html + "<br>";
148+
}
149+
124150
//------------------------------ QgsGrassRasterImport ------------------------------------
125151
QgsGrassRasterImport::QgsGrassRasterImport( QgsRasterPipe* pipe, const QgsGrassObject& grassObject,
126152
const QgsRectangle &extent, int xSize, int ySize )
@@ -170,6 +196,8 @@ bool QgsGrassRasterImport::import()
170196
for ( int band = 1; band <= provider->bandCount(); band++ )
171197
{
172198
QgsDebugMsg( QString( "band = %1" ).arg( band ) );
199+
addProgressRow( tr( "Writing band %1/%2" ).arg( band ).arg( provider->bandCount() ) );
200+
emitProgressChanged();
173201
int colorInterpretation = provider->colorInterpretation( band );
174202
if ( colorInterpretation == QgsRaster::RedBand )
175203
{
@@ -228,18 +256,17 @@ bool QgsGrassRasterImport::import()
228256
}
229257
arguments.append( "output=" + name ); // get list of all output names
230258
QTemporaryFile gisrcFile;
231-
QProcess* process = 0;
232259
try
233260
{
234-
process = QgsGrass::startModule( mGrassObject.gisdbase(), mGrassObject.location(), mGrassObject.mapset(), module, arguments, gisrcFile );
261+
mProcess = QgsGrass::startModule( mGrassObject.gisdbase(), mGrassObject.location(), mGrassObject.mapset(), module, arguments, gisrcFile );
235262
}
236263
catch ( QgsGrass::Exception &e )
237264
{
238265
setError( e.what() );
239266
return false;
240267
}
241268

242-
QDataStream outStream( process );
269+
QDataStream outStream( mProcess );
243270

244271
outStream << mExtent << ( qint32 )mXSize << ( qint32 )mYSize;
245272
outStream << ( qint32 )qgis_out_type;
@@ -264,11 +291,14 @@ bool QgsGrassRasterImport::import()
264291
int iterCols = 0;
265292
int iterRows = 0;
266293
QgsRasterBlock* block = 0;
267-
process->setReadChannel( QProcess::StandardOutput );
294+
mProcess->setReadChannel( QProcess::StandardOutput );
295+
mProgressMax = mYSize;
268296
while ( iter.readNextRasterPart( band, iterCols, iterRows, &block, iterLeft, iterTop ) )
269297
{
270298
for ( int row = 0; row < iterRows; row++ )
271299
{
300+
mProgressValue = iterTop + row;
301+
emitProgressChanged();
272302
if ( !block->convert( qgis_out_type ) )
273303
{
274304
setError( tr( "Cannot convert block (%1) to data type %2" ).arg( block->toString() ).arg( qgis_out_type ) );
@@ -320,11 +350,11 @@ bool QgsGrassRasterImport::import()
320350
outStream << byteArray;
321351

322352
// Without waitForBytesWritten() it does not finish ok on Windows (process timeout)
323-
process->waitForBytesWritten( -1 );
353+
mProcess->waitForBytesWritten( -1 );
324354

325355
#ifndef Q_OS_WIN
326356
// wait until the row is written to allow quick cancel (don't send data to buffer)
327-
process->waitForReadyRead();
357+
mProcess->waitForReadyRead();
328358
bool result;
329359
outStream >> result;
330360
#endif
@@ -339,34 +369,37 @@ bool QgsGrassRasterImport::import()
339369

340370
// TODO: send something back from module and read it here to close map correctly in module
341371

342-
process->closeWriteChannel();
372+
mProcess->closeWriteChannel();
343373
// TODO: best timeout?
344-
process->waitForFinished( 30000 );
374+
mProcess->waitForFinished( 30000 );
345375

346-
QString stdoutString = process->readAllStandardOutput().data();
347-
QString stderrString = process->readAllStandardError().data();
376+
QString stdoutString = mProcess->readAllStandardOutput().data();
377+
QString stderrString = mProcess->readAllStandardError().data();
348378

349379
QString processResult = QString( "exitStatus=%1, exitCode=%2, error=%3, errorString=%4 stdout=%5, stderr=%6" )
350-
.arg( process->exitStatus() ).arg( process->exitCode() )
351-
.arg( process->error() ).arg( process->errorString() )
380+
.arg( mProcess->exitStatus() ).arg( mProcess->exitCode() )
381+
.arg( mProcess->error() ).arg( mProcess->errorString() )
352382
.arg( stdoutString.replace( "\n", ", " ) ).arg( stderrString.replace( "\n", ", " ) );
353383
QgsDebugMsg( "processResult: " + processResult );
354384

355-
if ( process->exitStatus() != QProcess::NormalExit )
385+
if ( mProcess->exitStatus() != QProcess::NormalExit )
356386
{
357-
setError( process->errorString() );
358-
delete process;
387+
setError( mProcess->errorString() );
388+
delete mProcess;
389+
mProcess = 0;
359390
return false;
360391
}
361392

362-
if ( process->exitCode() != 0 )
393+
if ( mProcess->exitCode() != 0 )
363394
{
364395
setError( stderrString );
365-
delete process;
396+
delete mProcess;
397+
mProcess = 0;
366398
return false;
367399
}
368400

369-
delete process;
401+
delete mProcess;
402+
mProcess = 0;
370403
}
371404
QgsDebugMsg( QString( "redBand = %1 greenBand = %2 blueBand = %3" ).arg( redBand ).arg( greenBand ).arg( blueBand ) );
372405
if ( redBand > 0 && greenBand > 0 && blueBand > 0 )
@@ -486,19 +519,20 @@ bool QgsGrassVectorImport::import()
486519
QString name = mGrassObject.name();
487520
arguments.append( "output=" + name );
488521
QTemporaryFile gisrcFile;
489-
QProcess* process = 0;
490522
try
491523
{
492-
process = QgsGrass::startModule( mGrassObject.gisdbase(), mGrassObject.location(), mGrassObject.mapset(), module, arguments, gisrcFile );
524+
mProcess = QgsGrass::startModule( mGrassObject.gisdbase(), mGrassObject.location(), mGrassObject.mapset(), module, arguments, gisrcFile );
493525
}
494526
catch ( QgsGrass::Exception &e )
495527
{
496528
setError( e.what() );
497529
return false;
498530
}
531+
// TODO: connecting readyReadStandardError() is causing hangs or crashes
532+
//connect(mProcess, SIGNAL(readyReadStandardError()), this, SLOT(onReadyReadStandardError()));
499533

500-
QDataStream outStream( process );
501-
process->setReadChannel( QProcess::StandardOutput );
534+
QDataStream outStream( mProcess );
535+
mProcess->setReadChannel( QProcess::StandardOutput );
502536

503537
QGis::WkbType wkbType = mProvider->geometryType();
504538
bool isPolygon = QGis::singleType( QGis::flatType( wkbType ) ) == QGis::WKBPolygon;
@@ -508,9 +542,11 @@ bool QgsGrassVectorImport::import()
508542

509543
QgsFeatureIterator iterator = mProvider->getFeatures();
510544
QgsFeature feature;
545+
mProgressMax = mProvider->featureCount();
511546
for ( int i = 0; i < ( isPolygon ? 2 : 1 ); i++ ) // two cycles with polygons
512547
{
513-
if ( i > 0 )
548+
addProgressRow( tr( "Writing features" ) );
549+
if ( i > 0 ) // second run for polygons
514550
{
515551
//iterator.rewind(); // rewind does not work
516552
iterator = mProvider->getFeatures();
@@ -519,6 +555,9 @@ bool QgsGrassVectorImport::import()
519555
int count = 0;
520556
while ( iterator.nextFeature( feature ) )
521557
{
558+
mProgressTmpHtml = tr( "Feature %1/%2" ).arg( count + 1 ).arg( mProgressMax );
559+
mProgressValue = count + 1;
560+
emitProgressChanged();
522561
if ( !feature.isValid() )
523562
{
524563
continue;
@@ -536,11 +575,11 @@ bool QgsGrassVectorImport::import()
536575
outStream << feature;
537576

538577
// Without waitForBytesWritten() it does not finish ok on Windows (data lost)
539-
process->waitForBytesWritten( -1 );
578+
mProcess->waitForBytesWritten( -1 );
540579

541580
#ifndef Q_OS_WIN
542581
// wait until the feature is written to allow quick cancel (don't send data to buffer)
543-
process->waitForReadyRead();
582+
mProcess->waitForReadyRead();
544583
bool result;
545584
outStream >> result;
546585
#endif
@@ -551,56 +590,61 @@ bool QgsGrassVectorImport::import()
551590
QgsDebugMsg( QString( "%1 features written" ).arg( count ) );
552591
}
553592
}
593+
554594
feature = QgsFeature(); // indicate end by invalid feature
555595
outStream << false; // not canceled
556596
outStream << feature;
557597

558-
process->waitForBytesWritten( -1 );
598+
mProcess->waitForBytesWritten( -1 );
559599
QgsDebugMsg( "features sent" );
560600
#ifndef Q_OS_WIN
561-
process->waitForReadyRead();
601+
mProcess->waitForReadyRead();
562602
bool result;
563603
outStream >> result;
564604
#endif
565605
}
606+
566607
iterator.close();
567608

568609
// Close write channel before waiting for response to avoid stdin buffer problem on Windows
569-
process->closeWriteChannel();
610+
mProcess->closeWriteChannel();
570611

571612
QgsDebugMsg( "waitForReadyRead" );
572613
bool result;
573-
process->waitForReadyRead();
614+
mProcess->waitForReadyRead();
574615
outStream >> result;
575616
QgsDebugMsg( QString( "result = %1" ).arg( result ) );
576617

577618
QgsDebugMsg( "waitForFinished" );
578-
process->waitForFinished( 30000 );
619+
mProcess->waitForFinished( 30000 );
579620

580-
QString stdoutString = process->readAllStandardOutput().data();
581-
QString stderrString = process->readAllStandardError().data();
621+
QString stdoutString = mProcess->readAllStandardOutput().data();
622+
QString stderrString = mProcess->readAllStandardError().data();
582623

583624
QString processResult = QString( "exitStatus=%1, exitCode=%2, error=%3, errorString=%4 stdout=%5, stderr=%6" )
584-
.arg( process->exitStatus() ).arg( process->exitCode() )
585-
.arg( process->error() ).arg( process->errorString() )
625+
.arg( mProcess->exitStatus() ).arg( mProcess->exitCode() )
626+
.arg( mProcess->error() ).arg( mProcess->errorString() )
586627
.arg( stdoutString.replace( "\n", ", " ) ).arg( stderrString.replace( "\n", ", " ) );
587628
QgsDebugMsg( "processResult: " + processResult );
588629

589-
if ( process->exitStatus() != QProcess::NormalExit )
630+
if ( mProcess->exitStatus() != QProcess::NormalExit )
590631
{
591-
setError( process->errorString() );
592-
delete process;
632+
setError( mProcess->errorString() );
633+
delete mProcess;
634+
mProcess = 0;
593635
return false;
594636
}
595637

596-
if ( process->exitCode() != 0 )
638+
if ( mProcess->exitCode() != 0 )
597639
{
598640
setError( stderrString );
599-
delete process;
641+
delete mProcess;
642+
mProcess = 0;
600643
return false;
601644
}
602645

603-
delete process;
646+
delete mProcess;
647+
mProcess = 0;
604648
return true;
605649
}
606650

‎src/providers/grass/qgsgrassimport.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class GRASS_LIB_EXPORT QgsGrassImport : public QObject
5050
QString error();
5151
virtual QStringList names() const;
5252
bool isCanceled() const;
53+
void emitProgressChanged();
5354
public slots:
5455
void onFinished();
5556
// TODO: this is not completely kosher, because QgsGrassImport exist on the main thread
@@ -58,19 +59,31 @@ class GRASS_LIB_EXPORT QgsGrassImport : public QObject
5859
// and thus recieves the signal.
5960
// Most probably however, it will work correctly, even if read/write the bool wasn't atomic
6061
void cancel();
61-
void frameChanged() {};
62+
void frameChanged() {}
63+
64+
void onReadyReadStandardError();
6265

6366
signals:
6467
// sent when process finished
6568
void finished( QgsGrassImport *import );
6669

70+
void progressChanged( QString html, int min, int max, int value );
71+
6772
protected:
6873
static bool run( QgsGrassImport *imp );
6974
void setError( QString error );
75+
void addProgressRow( QString html );
7076
QgsGrassObject mGrassObject;
7177
QString mError;
7278
bool mCanceled;
79+
QProcess* mProcess;
7380
QFutureWatcher<bool>* mFutureWatcher;
81+
QString mProgressHtml;
82+
// temporary part of progress, e.g. number of features written.
83+
QString mProgressTmpHtml;
84+
int mProgressMin;
85+
int mProgressMax;
86+
int mProgressValue;
7487
};
7588

7689
class GRASS_LIB_EXPORT QgsGrassRasterImport : public QgsGrassImport

‎src/providers/grass/qgsgrassprovidermodule.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
#include <QDir>
3333
#include <QLabel>
3434
#include <QObject>
35+
#include <QProgressBar>
36+
#include <QScrollBar>
37+
#include <QTextEdit>
3538

3639
//----------------------- QgsGrassItemActions ------------------------------
3740
QgsGrassItemActions::QgsGrassItemActions( QgsGrassObject grassObject, QObject *parent )
@@ -1071,6 +1074,29 @@ QIcon QgsGrassGroupItem::icon()
10711074
return linkIcon;
10721075
}
10731076

1077+
//----------------------- QgsGrassImportItemWidget ------------------------------
1078+
QgsGrassImportItemWidget::QgsGrassImportItemWidget( QWidget* parent )
1079+
: QWidget( parent )
1080+
{
1081+
QVBoxLayout *layout = new QVBoxLayout( this );
1082+
1083+
mTextEdit = new QTextEdit( this );
1084+
mTextEdit->setReadOnly( true );
1085+
layout->addWidget( mTextEdit );
1086+
1087+
mProgressBar = new QProgressBar( this );
1088+
layout->addWidget( mProgressBar );
1089+
}
1090+
1091+
void QgsGrassImportItemWidget::onProgressChanged( QString html, int min, int max, int value )
1092+
{
1093+
mTextEdit->setHtml( html );
1094+
mTextEdit->verticalScrollBar()->setValue( mTextEdit->verticalScrollBar()->maximum() );
1095+
mProgressBar->setRange( min, max );
1096+
mProgressBar->setValue( value );
1097+
}
1098+
1099+
10741100
//----------------------- QgsGrassImportItem ------------------------------
10751101

10761102
QgsAnimatedIcon *QgsGrassImportItem::mImportIcon = 0;
@@ -1102,6 +1128,16 @@ QList<QAction*> QgsGrassImportItem::actions()
11021128
return lst;
11031129
}
11041130

1131+
QWidget * QgsGrassImportItem::paramWidget()
1132+
{
1133+
QgsDebugMsg( "entered" );
1134+
QgsGrassImportItemWidget *widget = new QgsGrassImportItemWidget();
1135+
connect( mImport, SIGNAL( progressChanged( QString, int, int, int ) ),
1136+
widget, SLOT( onProgressChanged( QString, int, int, int ) ) );
1137+
mImport->emitProgressChanged();
1138+
return widget;
1139+
}
1140+
11051141
void QgsGrassImportItem::cancel()
11061142
{
11071143
QgsDebugMsg( "Entered" );

‎src/providers/grass/qgsgrassprovidermodule.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
#include "qgsgrass.h"
2121
#include "qgsgrassimport.h"
2222

23+
class QTextEdit;
24+
class QProgressBar;
25+
2326
class QgsGrassImportItem;
2427

2528
/* Qt does not allow inheritance from multiple QObjects, that is why we have QgsGrassItemActions
@@ -186,6 +189,20 @@ class QgsGrassGroupItem : public QgsGrassObjectItem
186189

187190
};
188191

192+
class QgsGrassImportItemWidget : public QWidget
193+
{
194+
Q_OBJECT
195+
public:
196+
QgsGrassImportItemWidget( QWidget* parent = 0 );
197+
198+
public slots:
199+
void onProgressChanged( QString html, int min, int max, int value );
200+
201+
private:
202+
QTextEdit *mTextEdit;
203+
QProgressBar *mProgressBar;
204+
};
205+
189206
// item representing a layer being imported
190207
class QgsGrassImportItem : public QgsDataItem, public QgsGrassObjectItemBase
191208
{
@@ -198,6 +215,7 @@ class QgsGrassImportItem : public QgsDataItem, public QgsGrassObjectItemBase
198215
//} // do nothing to keep Populating
199216
virtual QList<QAction*> actions() override;
200217
virtual QIcon icon() override;
218+
virtual QWidget *paramWidget() override;
201219

202220
public slots:
203221
virtual void refresh() override {}

0 commit comments

Comments
 (0)
Please sign in to comment.