|
QGIS API Documentation
master-3f58142
|
00001 /*************************************************************************** 00002 qgsrulebasedrendererv2widget.cpp - Settings widget for rule-based renderer 00003 --------------------- 00004 begin : May 2010 00005 copyright : (C) 2010 by Martin Dobias 00006 email : wonder dot sk at gmail dot com 00007 *************************************************************************** 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 ***************************************************************************/ 00015 00016 #include "qgsrulebasedrendererv2widget.h" 00017 00018 #include "qgsrulebasedrendererv2.h" 00019 #include "qgssymbollayerv2utils.h" 00020 #include "qgssymbolv2.h" 00021 #include "qgsvectorlayer.h" 00022 #include "qgsapplication.h" 00023 #include "qgsexpression.h" 00024 #include "qgssymbolv2selectordialog.h" 00025 #include "qgslogger.h" 00026 #include "qstring.h" 00027 00028 #include <QMenu> 00029 #include <QProgressDialog> 00030 #include <QSettings> 00031 #include <QTreeWidgetItem> 00032 #include <QVBoxLayout> 00033 #include <QMessageBox> 00034 00035 //#include "modeltest.h" 00036 00037 QgsRendererV2Widget* QgsRuleBasedRendererV2Widget::create( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer ) 00038 { 00039 return new QgsRuleBasedRendererV2Widget( layer, style, renderer ); 00040 } 00041 00042 QgsRuleBasedRendererV2Widget::QgsRuleBasedRendererV2Widget( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer ) 00043 : QgsRendererV2Widget( layer, style ) 00044 { 00045 00046 // try to recognize the previous renderer 00047 // (null renderer means "no previous renderer") 00048 if ( !renderer || renderer->type() != "RuleRenderer" ) 00049 { 00050 // we're not going to use it - so let's delete the renderer 00051 delete renderer; 00052 00053 // some default options 00054 QgsSymbolV2* symbol = QgsSymbolV2::defaultSymbol( mLayer->geometryType() ); 00055 00056 mRenderer = new QgsRuleBasedRendererV2( symbol ); 00057 } 00058 else 00059 { 00060 mRenderer = static_cast<QgsRuleBasedRendererV2*>( renderer ); 00061 } 00062 00063 setupUi( this ); 00064 00065 mModel = new QgsRuleBasedRendererV2Model( mRenderer ); 00066 //new ModelTest( mModel, this ); // for model validity checking 00067 viewRules->setModel( mModel ); 00068 00069 mRefineMenu = new QMenu( "Refine current rule", btnRefineRule ); 00070 mRefineMenu->addAction( tr( "Add scales to rule" ), this, SLOT( refineRuleScales() ) ); 00071 mRefineMenu->addAction( tr( "Add categories to rule" ), this, SLOT( refineRuleCategories() ) ); 00072 mRefineMenu->addAction( tr( "Add ranges to rule" ), this, SLOT( refineRuleRanges() ) ); 00073 btnRefineRule->setMenu( mRefineMenu ); 00074 contextMenu->addMenu( mRefineMenu ); 00075 00076 btnAddRule->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.png" ) ) ); 00077 btnEditRule->setIcon( QIcon( QgsApplication::iconPath( "symbologyEdit.png" ) ) ); 00078 btnRemoveRule->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.png" ) ) ); 00079 00080 connect( viewRules, SIGNAL( doubleClicked( const QModelIndex & ) ), this, SLOT( editRule( const QModelIndex & ) ) ); 00081 00082 // support for context menu (now handled generically) 00083 connect( viewRules, SIGNAL( customContextMenuRequested( const QPoint& ) ), this, SLOT( contextMenuViewCategories( const QPoint& ) ) ); 00084 00085 connect( viewRules->selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ), this, SLOT( currentRuleChanged( QModelIndex, QModelIndex ) ) ); 00086 00087 connect( btnAddRule, SIGNAL( clicked() ), this, SLOT( addRule() ) ); 00088 connect( btnEditRule, SIGNAL( clicked() ), this, SLOT( editRule() ) ); 00089 connect( btnRemoveRule, SIGNAL( clicked() ), this, SLOT( removeRule() ) ); 00090 connect( btnCountFeatures, SIGNAL( clicked() ), this, SLOT( countFeatures() ) ); 00091 00092 connect( btnRenderingOrder, SIGNAL( clicked() ), this, SLOT( setRenderingOrder() ) ); 00093 00094 currentRuleChanged(); 00095 00096 // store/restore header section widths 00097 connect( viewRules->header(), SIGNAL( sectionResized( int, int, int ) ), this, SLOT( saveSectionWidth( int, int, int ) ) ); 00098 00099 restoreSectionWidths(); 00100 00101 } 00102 00103 QgsRuleBasedRendererV2Widget::~QgsRuleBasedRendererV2Widget() 00104 { 00105 delete mRenderer; 00106 } 00107 00108 QgsFeatureRendererV2* QgsRuleBasedRendererV2Widget::renderer() 00109 { 00110 return mRenderer; 00111 } 00112 00113 void QgsRuleBasedRendererV2Widget::addRule() 00114 { 00115 QgsSymbolV2* s = QgsSymbolV2::defaultSymbol( mLayer->geometryType() ); 00116 QgsRuleBasedRendererV2::Rule* newrule = new QgsRuleBasedRendererV2::Rule( s ); 00117 00118 QgsRendererRulePropsDialog dlg( newrule, mLayer, mStyle, this ); 00119 if ( dlg.exec() ) 00120 { 00121 QgsRuleBasedRendererV2::Rule* current = currentRule(); 00122 if ( current ) 00123 { 00124 // add after this rule 00125 QModelIndex currentIndex = viewRules->selectionModel()->currentIndex(); 00126 mModel->insertRule( currentIndex.parent(), currentIndex.row() + 1, newrule ); 00127 } 00128 else 00129 { 00130 // append to root rule 00131 int rows = mModel->rowCount(); 00132 mModel->insertRule( QModelIndex(), rows, newrule ); 00133 } 00134 mModel->clearFeatureCounts(); 00135 } 00136 else 00137 { 00138 delete newrule; 00139 } 00140 } 00141 00142 QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2Widget::currentRule() 00143 { 00144 QItemSelectionModel* sel = viewRules->selectionModel(); 00145 QModelIndex idx = sel->currentIndex(); 00146 if ( !idx.isValid() ) 00147 return NULL; 00148 return mModel->ruleForIndex( idx ); 00149 } 00150 00151 void QgsRuleBasedRendererV2Widget::editRule() 00152 { 00153 editRule( viewRules->selectionModel()->currentIndex() ); 00154 } 00155 00156 void QgsRuleBasedRendererV2Widget::editRule( const QModelIndex& index ) 00157 { 00158 if ( !index.isValid() ) 00159 return; 00160 QgsRuleBasedRendererV2::Rule* rule = mModel->ruleForIndex( index ); 00161 00162 QgsRendererRulePropsDialog dlg( rule, mLayer, mStyle, this ); 00163 if ( dlg.exec() ) 00164 { 00165 // model should know about the change and emit dataChanged signal for the view 00166 mModel->updateRule( index.parent(), index.row() ); 00167 mModel->clearFeatureCounts(); 00168 } 00169 } 00170 00171 void QgsRuleBasedRendererV2Widget::removeRule() 00172 { 00173 QItemSelection sel = viewRules->selectionModel()->selection(); 00174 QgsDebugMsg( QString( "REMOVE RULES!!! ranges: %1" ).arg( sel.count() ) ); 00175 foreach ( QItemSelectionRange range, sel ) 00176 { 00177 QgsDebugMsg( QString( "RANGE: r %1 - %2" ).arg( range.top() ).arg( range.bottom() ) ); 00178 if ( range.isValid() ) 00179 mModel->removeRows( range.top(), range.bottom() - range.top() + 1, range.parent() ); 00180 } 00181 // make sure that the selection is gone 00182 viewRules->selectionModel()->clear(); 00183 mModel->clearFeatureCounts(); 00184 } 00185 00186 void QgsRuleBasedRendererV2Widget::currentRuleChanged( const QModelIndex& current, const QModelIndex& previous ) 00187 { 00188 Q_UNUSED( previous ); 00189 btnRefineRule->setEnabled( current.isValid() ); 00190 } 00191 00192 00193 #include "qgscategorizedsymbolrendererv2.h" 00194 #include "qgscategorizedsymbolrendererv2widget.h" 00195 #include "qgsgraduatedsymbolrendererv2.h" 00196 #include "qgsgraduatedsymbolrendererv2widget.h" 00197 #include "qgsexpressionbuilderdialog.h" 00198 #include <QDialogButtonBox> 00199 #include <QInputDialog> 00200 00201 void QgsRuleBasedRendererV2Widget::refineRule( int type ) 00202 { 00203 QModelIndexList indexlist = viewRules->selectionModel()->selectedRows(); 00204 00205 if ( indexlist.isEmpty() ) 00206 return; 00207 00208 00209 if ( type == 0 ) // categories 00210 refineRuleCategoriesGui( indexlist ); 00211 else if ( type == 1 ) // ranges 00212 refineRuleRangesGui( indexlist ); 00213 else // scales 00214 refineRuleScalesGui( indexlist ); 00215 00216 // TODO: set initial rule's symbol to NULL (?) 00217 00218 // show the newly added rules 00219 foreach ( QModelIndex index, indexlist ) 00220 viewRules->expand( index ); 00221 } 00222 00223 void QgsRuleBasedRendererV2Widget::refineRuleCategories() 00224 { 00225 refineRule( 0 ); 00226 } 00227 00228 void QgsRuleBasedRendererV2Widget::refineRuleRanges() 00229 { 00230 refineRule( 1 ); 00231 } 00232 00233 void QgsRuleBasedRendererV2Widget::refineRuleScales() 00234 { 00235 refineRule( 2 ); 00236 } 00237 00238 void QgsRuleBasedRendererV2Widget::refineRuleCategoriesGui( const QModelIndexList& indexList ) 00239 { 00240 QDialog dlg; 00241 dlg.setWindowTitle( tr( "Refine a rule to categories" ) ); 00242 QVBoxLayout* l = new QVBoxLayout(); 00243 QgsCategorizedSymbolRendererV2Widget* w = new QgsCategorizedSymbolRendererV2Widget( mLayer, mStyle, NULL ); 00244 l->addWidget( w ); 00245 QDialogButtonBox* bb = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel ); 00246 l->addWidget( bb ); 00247 connect( bb, SIGNAL( accepted() ), &dlg, SLOT( accept() ) ); 00248 connect( bb, SIGNAL( rejected() ), &dlg, SLOT( reject() ) ); 00249 dlg.setLayout( l ); 00250 00251 if ( !dlg.exec() ) 00252 return; 00253 00254 // create new rules 00255 QgsCategorizedSymbolRendererV2* r = static_cast<QgsCategorizedSymbolRendererV2*>( w->renderer() ); 00256 foreach ( QModelIndex index, indexList ) 00257 { 00258 QgsRuleBasedRendererV2::Rule* initialRule = mModel->ruleForIndex( index ); 00259 mModel->willAddRules( index, r->categories().count() ); 00260 QgsRuleBasedRendererV2::refineRuleCategories( initialRule, r ); 00261 } 00262 mModel->finishedAddingRules(); 00263 } 00264 00265 00266 void QgsRuleBasedRendererV2Widget::refineRuleRangesGui( const QModelIndexList& indexList ) 00267 { 00268 00269 00270 QDialog dlg; 00271 dlg.setWindowTitle( tr( "Refine a rule to ranges" ) ); 00272 QVBoxLayout* l = new QVBoxLayout(); 00273 QgsGraduatedSymbolRendererV2Widget* w = new QgsGraduatedSymbolRendererV2Widget( mLayer, mStyle, NULL ); 00274 l->addWidget( w ); 00275 QDialogButtonBox* bb = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel ); 00276 l->addWidget( bb ); 00277 connect( bb, SIGNAL( accepted() ), &dlg, SLOT( accept() ) ); 00278 connect( bb, SIGNAL( rejected() ), &dlg, SLOT( reject() ) ); 00279 dlg.setLayout( l ); 00280 00281 if ( !dlg.exec() ) 00282 return; 00283 00284 // create new rules 00285 QgsGraduatedSymbolRendererV2* r = static_cast<QgsGraduatedSymbolRendererV2*>( w->renderer() ); 00286 foreach ( QModelIndex index, indexList ) 00287 { 00288 QgsRuleBasedRendererV2::Rule* initialRule = mModel->ruleForIndex( index ); 00289 mModel->willAddRules( index, r->ranges().count() ); 00290 QgsRuleBasedRendererV2::refineRuleRanges( initialRule, r ); 00291 } 00292 mModel->finishedAddingRules(); 00293 } 00294 00295 void QgsRuleBasedRendererV2Widget::refineRuleScalesGui( const QModelIndexList& indexList ) 00296 { 00297 foreach ( QModelIndex index, indexList ) 00298 { 00299 QgsRuleBasedRendererV2::Rule* initialRule = mModel->ruleForIndex( index ); 00300 00301 // If any of the rules don't have a symbol let the user know and exit. 00302 if ( initialRule->symbol() == NULL ) 00303 { 00304 QMessageBox::warning( this, tr( "Scale refinement" ), tr( "Parent rule %1 must have a symbol for this operation." ).arg( initialRule->label() ) ); 00305 return; 00306 } 00307 } 00308 00309 QString txt = QInputDialog::getText( this, 00310 tr( "Scale refinement" ), 00311 tr( "Please enter scale denominators at which will split the rule, separate them by commas (e.g. 1000,5000):" ) ); 00312 if ( txt.isEmpty() ) 00313 return; 00314 00315 QList<int> scales; 00316 bool ok; 00317 foreach ( QString item, txt.split( ',' ) ) 00318 { 00319 int scale = item.toInt( &ok ); 00320 if ( ok ) 00321 scales.append( scale ); 00322 else 00323 QMessageBox::information( this, tr( "Error" ), QString( tr( "\"%1\" is not valid scale denominator, ignoring it." ) ).arg( item ) ); 00324 } 00325 00326 foreach ( QModelIndex index, indexList ) 00327 { 00328 QgsRuleBasedRendererV2::Rule* initialRule = mModel->ruleForIndex( index ); 00329 mModel->willAddRules( index, scales.count() + 1 ); 00330 QgsRuleBasedRendererV2::refineRuleScales( initialRule, scales ); 00331 } 00332 mModel->finishedAddingRules(); 00333 } 00334 00335 QList<QgsSymbolV2*> QgsRuleBasedRendererV2Widget::selectedSymbols() 00336 { 00337 QList<QgsSymbolV2*> symbolList; 00338 00339 if ( !mRenderer ) 00340 { 00341 return symbolList; 00342 } 00343 00344 QItemSelection sel = viewRules->selectionModel()->selection(); 00345 foreach ( QItemSelectionRange range, sel ) 00346 { 00347 QModelIndex parent = range.parent(); 00348 QgsRuleBasedRendererV2::Rule* parentRule = mModel->ruleForIndex( parent ); 00349 QgsRuleBasedRendererV2::RuleList& children = parentRule->children(); 00350 for ( int row = range.top(); row <= range.bottom(); row++ ) 00351 { 00352 symbolList.append( children[row]->symbol() ); 00353 } 00354 } 00355 00356 return symbolList; 00357 } 00358 00359 void QgsRuleBasedRendererV2Widget::refreshSymbolView() 00360 { 00361 // TODO: model/view 00362 /* 00363 if ( treeRules ) 00364 { 00365 treeRules->populateRules(); 00366 } 00367 */ 00368 } 00369 00370 #include "qgssymbollevelsv2dialog.h" 00371 00372 void QgsRuleBasedRendererV2Widget::setRenderingOrder() 00373 { 00374 QgsLegendSymbolList lst = mRenderer->legendSymbolItems(); 00375 00376 QgsSymbolLevelsV2Dialog dlg( lst, true, this ); 00377 dlg.setForceOrderingEnabled( true ); 00378 00379 dlg.exec(); 00380 } 00381 00382 void QgsRuleBasedRendererV2Widget::saveSectionWidth( int section, int oldSize, int newSize ) 00383 { 00384 Q_UNUSED( oldSize ); 00385 // skip last section, as it stretches 00386 if ( section == 5 ) 00387 return; 00388 QSettings settings; 00389 QString path = "/Windows/RuleBasedTree/sectionWidth/" + QString::number( section ); 00390 settings.setValue( path, newSize ); 00391 } 00392 00393 void QgsRuleBasedRendererV2Widget::restoreSectionWidths() 00394 { 00395 QSettings settings; 00396 QString path = "/Windows/RuleBasedTree/sectionWidth/"; 00397 QHeaderView* head = viewRules->header(); 00398 head->resizeSection( 0, settings.value( path + QString::number( 0 ), 150 ).toInt() ); 00399 head->resizeSection( 1, settings.value( path + QString::number( 1 ), 150 ).toInt() ); 00400 head->resizeSection( 2, settings.value( path + QString::number( 2 ), 80 ).toInt() ); 00401 head->resizeSection( 3, settings.value( path + QString::number( 3 ), 80 ).toInt() ); 00402 head->resizeSection( 4, settings.value( path + QString::number( 4 ), 50 ).toInt() ); 00403 head->resizeSection( 5, settings.value( path + QString::number( 5 ), 50 ).toInt() ); 00404 } 00405 00406 void QgsRuleBasedRendererV2Widget::countFeatures() 00407 { 00408 if ( !mLayer || !mRenderer || !mRenderer->rootRule() ) 00409 { 00410 return; 00411 } 00412 QMap<QgsRuleBasedRendererV2::Rule*, QgsRuleBasedRendererV2Count> countMap; 00413 00414 QgsRuleBasedRendererV2::RuleList ruleList = mRenderer->rootRule()->descendants(); 00415 // insert all so that we have counts 0 00416 foreach ( QgsRuleBasedRendererV2::Rule* rule, ruleList ) 00417 { 00418 countMap[rule].count = 0; 00419 countMap[rule].duplicateCount = 0; 00420 } 00421 00422 QgsFeatureIterator fit = mLayer->getFeatures( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ) ); 00423 00424 QgsRenderContext renderContext; 00425 renderContext.setRendererScale( 0 ); // ignore scale 00426 mRenderer->startRender( renderContext, mLayer ); 00427 00428 int nFeatures = mLayer->pendingFeatureCount(); 00429 QProgressDialog p( tr( "Calculating feature count." ), tr( "Abort" ), 0, nFeatures ); 00430 p.setWindowModality( Qt::WindowModal ); 00431 int featuresCounted = 0; 00432 00433 QgsFeature f; 00434 while ( fit.nextFeature( f ) ) 00435 { 00436 QgsRuleBasedRendererV2::RuleList featureRuleList = mRenderer->rootRule()->rulesForFeature( f ); 00437 00438 foreach ( QgsRuleBasedRendererV2::Rule* rule, featureRuleList ) 00439 { 00440 countMap[rule].count++; 00441 if ( featureRuleList.size() > 1 ) 00442 { 00443 countMap[rule].duplicateCount++; 00444 } 00445 foreach ( QgsRuleBasedRendererV2::Rule* duplicateRule, featureRuleList ) 00446 { 00447 if ( duplicateRule == rule ) continue; 00448 countMap[rule].duplicateCountMap[duplicateRule] += 1; 00449 } 00450 } 00451 ++featuresCounted; 00452 if ( featuresCounted % 50 == 0 ) 00453 { 00454 if ( featuresCounted > nFeatures ) //sometimes the feature count is not correct 00455 { 00456 p.setMaximum( 0 ); 00457 } 00458 p.setValue( featuresCounted ); 00459 if ( p.wasCanceled() ) 00460 { 00461 return; 00462 } 00463 } 00464 } 00465 p.setValue( nFeatures ); 00466 00467 mRenderer->stopRender( renderContext ); 00468 00469 #ifdef QGISDEBUG 00470 foreach ( QgsRuleBasedRendererV2::Rule *rule, countMap.keys() ) 00471 { 00472 QgsDebugMsg( QString( "rule: %1 count %2" ).arg( rule->label() ).arg( countMap[rule].count ) ); 00473 } 00474 #endif 00475 00476 mModel->setFeatureCounts( countMap ); 00477 } 00478 00480 00481 QgsRendererRulePropsDialog::QgsRendererRulePropsDialog( QgsRuleBasedRendererV2::Rule* rule, QgsVectorLayer* layer, QgsStyleV2* style, QWidget* parent ) 00482 : QDialog( parent ), mRule( rule ), mLayer( layer ), mSymbolSelector( NULL ), mSymbol( NULL ) 00483 { 00484 setupUi( this ); 00485 #ifdef Q_WS_MAC 00486 setWindowModality( Qt::WindowModal ); 00487 #endif 00488 00489 connect( buttonBox, SIGNAL( accepted() ), this, SLOT( accept() ) ); 00490 connect( buttonBox, SIGNAL( rejected() ), this, SLOT( reject() ) ); 00491 00492 editFilter->setText( mRule->filterExpression() ); 00493 editFilter->setToolTip( mRule->filterExpression() ); 00494 editLabel->setText( mRule->label() ); 00495 editDescription->setText( mRule->description() ); 00496 editDescription->setToolTip( mRule->description() ); 00497 00498 if ( mRule->dependsOnScale() ) 00499 { 00500 groupScale->setChecked( true ); 00501 spinMinScale->setValue( rule->scaleMinDenom() ); 00502 spinMaxScale->setValue( rule->scaleMaxDenom() ); 00503 } 00504 00505 if ( mRule->symbol() ) 00506 { 00507 groupSymbol->setChecked( true ); 00508 mSymbol = mRule->symbol()->clone(); // use a clone! 00509 } 00510 else 00511 { 00512 groupSymbol->setChecked( false ); 00513 mSymbol = QgsSymbolV2::defaultSymbol( mLayer->geometryType() ); 00514 } 00515 00516 mSymbolSelector = new QgsSymbolV2SelectorDialog( mSymbol, style, mLayer, this, true ); 00517 QVBoxLayout* l = new QVBoxLayout; 00518 l->addWidget( mSymbolSelector ); 00519 groupSymbol->setLayout( l ); 00520 00521 connect( btnExpressionBuilder, SIGNAL( clicked() ), this, SLOT( buildExpression() ) ); 00522 connect( btnTestFilter, SIGNAL( clicked() ), this, SLOT( testFilter() ) ); 00523 } 00524 00525 QgsRendererRulePropsDialog::~QgsRendererRulePropsDialog() 00526 { 00527 delete mSymbol; 00528 } 00529 00530 void QgsRendererRulePropsDialog::buildExpression() 00531 { 00532 QgsExpressionBuilderDialog dlg( mLayer, editFilter->text(), this ); 00533 00534 if ( dlg.exec() ) 00535 editFilter->setText( dlg.expressionText() ); 00536 } 00537 00538 void QgsRendererRulePropsDialog::testFilter() 00539 { 00540 QgsExpression filter( editFilter->text() ); 00541 if ( filter.hasParserError() ) 00542 { 00543 QMessageBox::critical( this, tr( "Error" ), tr( "Filter expression parsing error:\n" ) + filter.parserErrorString() ); 00544 return; 00545 } 00546 00547 const QgsFields& fields = mLayer->pendingFields(); 00548 00549 if ( !filter.prepare( fields ) ) 00550 { 00551 QMessageBox::critical( this, tr( "Evaluation error" ), filter.evalErrorString() ); 00552 return; 00553 } 00554 00555 QApplication::setOverrideCursor( Qt::WaitCursor ); 00556 00557 QgsFeatureIterator fit = mLayer->getFeatures( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ) ); 00558 00559 int count = 0; 00560 QgsFeature f; 00561 while ( fit.nextFeature( f ) ) 00562 { 00563 QVariant value = filter.evaluate( &f ); 00564 if ( value.toInt() != 0 ) 00565 count++; 00566 if ( filter.hasEvalError() ) 00567 break; 00568 } 00569 00570 QApplication::restoreOverrideCursor(); 00571 00572 QMessageBox::information( this, tr( "Filter" ), tr( "Filter returned %n feature(s)", "number of filtered features", count ) ); 00573 } 00574 00575 void QgsRendererRulePropsDialog::accept() 00576 { 00577 mRule->setFilterExpression( editFilter->text() ); 00578 mRule->setLabel( editLabel->text() ); 00579 mRule->setDescription( editDescription->text() ); 00580 mRule->setScaleMinDenom( groupScale->isChecked() ? spinMinScale->value() : 0 ); 00581 mRule->setScaleMaxDenom( groupScale->isChecked() ? spinMaxScale->value() : 0 ); 00582 mRule->setSymbol( groupSymbol->isChecked() ? mSymbol->clone() : NULL ); 00583 00584 QDialog::accept(); 00585 } 00586 00588 00589 /* 00590 setDragEnabled(true); 00591 viewport()->setAcceptDrops(true); 00592 setDropIndicatorShown(true); 00593 setDragDropMode(QAbstractItemView::InternalMove); 00594 */ 00595 00596 static QString _formatScale( int denom ) 00597 { 00598 if ( denom != 0 ) 00599 { 00600 QString txt = QString( "1:%L1" ).arg( denom ); 00601 return txt; 00602 } 00603 else 00604 return QString(); 00605 } 00606 00608 00609 QgsRuleBasedRendererV2Model::QgsRuleBasedRendererV2Model( QgsRuleBasedRendererV2* r ) 00610 : mR( r ) 00611 { 00612 } 00613 00614 Qt::ItemFlags QgsRuleBasedRendererV2Model::flags( const QModelIndex &index ) const 00615 { 00616 if ( !index.isValid() ) 00617 return Qt::ItemIsDropEnabled; 00618 00619 // allow drop only at first column 00620 Qt::ItemFlag drop = ( index.column() == 0 ? Qt::ItemIsDropEnabled : Qt::NoItemFlags ); 00621 00622 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | 00623 Qt::ItemIsEditable | 00624 Qt::ItemIsDragEnabled | drop; 00625 } 00626 00627 QVariant QgsRuleBasedRendererV2Model::data( const QModelIndex &index, int role ) const 00628 { 00629 if ( !index.isValid() ) 00630 return QVariant(); 00631 00632 QgsRuleBasedRendererV2::Rule* rule = ruleForIndex( index ); 00633 00634 if ( role == Qt::DisplayRole || role == Qt::ToolTipRole ) 00635 { 00636 switch ( index.column() ) 00637 { 00638 case 0: return rule->label(); 00639 case 1: return rule->filterExpression().isEmpty() ? tr( "(no filter)" ) : rule->filterExpression(); 00640 case 2: return rule->dependsOnScale() ? _formatScale( rule->scaleMinDenom() ) : QVariant(); 00641 case 3: return rule->dependsOnScale() ? _formatScale( rule->scaleMaxDenom() ) : QVariant(); 00642 case 4: 00643 if ( mFeatureCountMap.count( rule ) == 1 ) 00644 { 00645 return QVariant( mFeatureCountMap[rule].count ); 00646 } 00647 return QVariant(); 00648 case 5: 00649 if ( mFeatureCountMap.count( rule ) == 1 ) 00650 { 00651 if ( role == Qt::DisplayRole ) 00652 { 00653 return QVariant( mFeatureCountMap[rule].duplicateCount ); 00654 } 00655 else // tooltip - detailed info about duplicates 00656 { 00657 if ( mFeatureCountMap[rule].duplicateCount > 0 ) 00658 { 00659 QString tip = "<p style='margin:0px;'><ul>"; 00660 foreach ( QgsRuleBasedRendererV2::Rule* duplicateRule, mFeatureCountMap[rule].duplicateCountMap.keys() ) 00661 { 00662 QString label = duplicateRule->label().replace( "&", "&" ).replace( ">", ">" ).replace( "<", "<" ); 00663 tip += tr( "<li><nobr>%1 features also in rule %2</nobr></li>" ).arg( mFeatureCountMap[rule].duplicateCountMap[duplicateRule] ).arg( label ); 00664 } 00665 tip += "</ul>"; 00666 return tip; 00667 } 00668 else 00669 { 00670 return 0; 00671 } 00672 } 00673 } 00674 return QVariant(); 00675 default: return QVariant(); 00676 } 00677 } 00678 else if ( role == Qt::DecorationRole && index.column() == 0 && rule->symbol() ) 00679 { 00680 return QgsSymbolLayerV2Utils::symbolPreviewIcon( rule->symbol(), QSize( 16, 16 ) ); 00681 } 00682 else if ( role == Qt::TextAlignmentRole ) 00683 { 00684 return ( index.column() == 2 || index.column() == 3 ) ? Qt::AlignRight : Qt::AlignLeft; 00685 } 00686 else if ( role == Qt::EditRole ) 00687 { 00688 switch ( index.column() ) 00689 { 00690 case 0: return rule->label(); 00691 case 1: return rule->filterExpression(); 00692 case 2: return rule->scaleMinDenom(); 00693 case 3: return rule->scaleMaxDenom(); 00694 default: return QVariant(); 00695 } 00696 } 00697 else 00698 return QVariant(); 00699 } 00700 00701 QVariant QgsRuleBasedRendererV2Model::headerData( int section, Qt::Orientation orientation, int role ) const 00702 { 00703 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < 7 ) 00704 { 00705 QStringList lst; lst << tr( "Label" ) << tr( "Rule" ) << tr( "Min. scale" ) << tr( "Max.scale" ) << tr( "Count" ) << tr( "Duplicate count" ); 00706 return lst[section]; 00707 } 00708 else if ( orientation == Qt::Horizontal && role == Qt::ToolTipRole ) 00709 { 00710 if ( section == 4 ) // Count 00711 { 00712 return tr( "Number of features in this rule." ); 00713 } 00714 else if ( section == 5 ) // Duplicate count 00715 { 00716 return tr( "Number of features in this rule which are also present in other rule(s)." ); 00717 } 00718 } 00719 00720 return QVariant(); 00721 } 00722 00723 int QgsRuleBasedRendererV2Model::rowCount( const QModelIndex &parent ) const 00724 { 00725 if ( parent.column() > 0 ) 00726 return 0; 00727 00728 QgsRuleBasedRendererV2::Rule* parentRule = ruleForIndex( parent ); 00729 00730 return parentRule->children().count(); 00731 } 00732 00733 int QgsRuleBasedRendererV2Model::columnCount( const QModelIndex & ) const 00734 { 00735 return 6; 00736 } 00737 00738 QModelIndex QgsRuleBasedRendererV2Model::index( int row, int column, const QModelIndex &parent ) const 00739 { 00740 if ( hasIndex( row, column, parent ) ) 00741 { 00742 QgsRuleBasedRendererV2::Rule* parentRule = ruleForIndex( parent ); 00743 QgsRuleBasedRendererV2::Rule* childRule = parentRule->children()[row]; 00744 return createIndex( row, column, childRule ); 00745 } 00746 return QModelIndex(); 00747 } 00748 00749 QModelIndex QgsRuleBasedRendererV2Model::parent( const QModelIndex &index ) const 00750 { 00751 if ( !index.isValid() ) 00752 return QModelIndex(); 00753 00754 QgsRuleBasedRendererV2::Rule* childRule = ruleForIndex( index ); 00755 QgsRuleBasedRendererV2::Rule* parentRule = childRule->parent(); 00756 00757 if ( parentRule == mR->rootRule() ) 00758 return QModelIndex(); 00759 00760 // this is right: we need to know row number of our parent (in our grandparent) 00761 int row = parentRule->parent()->children().indexOf( parentRule ); 00762 00763 return createIndex( row, 0, parentRule ); 00764 } 00765 00766 bool QgsRuleBasedRendererV2Model::setData( const QModelIndex & index, const QVariant & value, int role ) 00767 { 00768 if ( !index.isValid() || role != Qt::EditRole ) 00769 return false; 00770 00771 QgsRuleBasedRendererV2::Rule* rule = ruleForIndex( index ); 00772 00773 switch ( index.column() ) 00774 { 00775 case 0: // label 00776 rule->setLabel( value.toString() ); 00777 break; 00778 case 1: // filter 00779 rule->setFilterExpression( value.toString() ); 00780 break; 00781 case 2: // scale min 00782 rule->setScaleMinDenom( value.toInt() ); 00783 break; 00784 case 3: // scale max 00785 rule->setScaleMaxDenom( value.toInt() ); 00786 break; 00787 default: 00788 return false; 00789 } 00790 00791 emit dataChanged( index, index ); 00792 return true; 00793 } 00794 00795 Qt::DropActions QgsRuleBasedRendererV2Model::supportedDropActions() const 00796 { 00797 return Qt::MoveAction; // | Qt::CopyAction 00798 } 00799 00800 QStringList QgsRuleBasedRendererV2Model::mimeTypes() const 00801 { 00802 QStringList types; 00803 types << "application/vnd.text.list"; 00804 return types; 00805 } 00806 00807 QMimeData *QgsRuleBasedRendererV2Model::mimeData( const QModelIndexList &indexes ) const 00808 { 00809 QMimeData *mimeData = new QMimeData(); 00810 QByteArray encodedData; 00811 00812 QDataStream stream( &encodedData, QIODevice::WriteOnly ); 00813 00814 foreach ( const QModelIndex &index, indexes ) 00815 { 00816 // each item consists of several columns - let's add it with just first one 00817 if ( !index.isValid() || index.column() != 0 ) 00818 continue; 00819 00820 QgsRuleBasedRendererV2::Rule* rule = ruleForIndex( index ); 00821 QDomDocument doc; 00822 QgsSymbolV2Map symbols; 00823 00824 QDomElement rootElem = doc.createElement( "rule_mime" ); 00825 QDomElement rulesElem = rule->save( doc, symbols ); 00826 rootElem.appendChild( rulesElem ); 00827 QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc ); 00828 rootElem.appendChild( symbolsElem ); 00829 doc.appendChild( rootElem ); 00830 00831 stream << doc.toString( -1 ); 00832 } 00833 00834 mimeData->setData( "application/vnd.text.list", encodedData ); 00835 return mimeData; 00836 } 00837 00838 bool QgsRuleBasedRendererV2Model::dropMimeData( const QMimeData *data, 00839 Qt::DropAction action, int row, int column, const QModelIndex &parent ) 00840 { 00841 Q_UNUSED( column ); 00842 00843 if ( action == Qt::IgnoreAction ) 00844 return true; 00845 00846 if ( !data->hasFormat( "application/vnd.text.list" ) ) 00847 return false; 00848 00849 if ( parent.column() > 0 ) 00850 return false; 00851 00852 QByteArray encodedData = data->data( "application/vnd.text.list" ); 00853 QDataStream stream( &encodedData, QIODevice::ReadOnly ); 00854 int rows = 0; 00855 00856 if ( row == -1 ) 00857 { 00858 // the item was dropped at a parent - we may decide where to put the items - let's append them 00859 row = rowCount( parent ); 00860 } 00861 00862 while ( !stream.atEnd() ) 00863 { 00864 QString text; 00865 stream >> text; 00866 00867 QDomDocument doc; 00868 if ( !doc.setContent( text ) ) 00869 continue; 00870 QDomElement rootElem = doc.documentElement(); 00871 if ( rootElem.tagName() != "rule_mime" ) 00872 continue; 00873 QDomElement symbolsElem = rootElem.firstChildElement( "symbols" ); 00874 if ( symbolsElem.isNull() ) 00875 continue; 00876 QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem ); 00877 QDomElement ruleElem = rootElem.firstChildElement( "rule" ); 00878 QgsRuleBasedRendererV2::Rule* rule = QgsRuleBasedRendererV2::Rule::create( ruleElem, symbolMap ); 00879 00880 insertRule( parent, row + rows, rule ); 00881 00882 ++rows; 00883 } 00884 return true; 00885 } 00886 00887 QgsRuleBasedRendererV2::Rule* QgsRuleBasedRendererV2Model::ruleForIndex( const QModelIndex& index ) const 00888 { 00889 if ( index.isValid() ) 00890 return static_cast<QgsRuleBasedRendererV2::Rule*>( index.internalPointer() ); 00891 return mR->rootRule(); 00892 } 00893 00894 bool QgsRuleBasedRendererV2Model::removeRows( int row, int count, const QModelIndex & parent ) 00895 { 00896 QgsRuleBasedRendererV2::Rule* parentRule = ruleForIndex( parent ); 00897 00898 if ( row < 0 || row >= parentRule->children().count() ) 00899 return false; 00900 00901 QgsDebugMsg( QString( "Called: row %1 count %2 parent ~~%3~~" ).arg( row ).arg( count ).arg( parentRule->dump() ) ); 00902 00903 beginRemoveRows( parent, row, row + count - 1 ); 00904 00905 for ( int i = 0; i < count; i++ ) 00906 { 00907 if ( row < parentRule->children().count() ) 00908 { 00909 //QgsRuleBasedRendererV2::Rule* r = parentRule->children()[row]; 00910 parentRule->removeChildAt( row ); 00911 //parentRule->takeChildAt( row ); 00912 } 00913 else 00914 { 00915 QgsDebugMsg( "trying to remove invalid index - this should not happen!" ); 00916 } 00917 } 00918 00919 endRemoveRows(); 00920 00921 return true; 00922 } 00923 00924 00925 void QgsRuleBasedRendererV2Model::insertRule( const QModelIndex& parent, int before, QgsRuleBasedRendererV2::Rule* newrule ) 00926 { 00927 beginInsertRows( parent, before, before ); 00928 00929 QgsDebugMsg( QString( "insert before %1 rule: %2" ).arg( before ).arg( newrule->dump() ) ); 00930 00931 QgsRuleBasedRendererV2::Rule* parentRule = ruleForIndex( parent ); 00932 parentRule->insertChild( before, newrule ); 00933 00934 endInsertRows(); 00935 } 00936 00937 void QgsRuleBasedRendererV2Model::updateRule( const QModelIndex& parent, int row ) 00938 { 00939 emit dataChanged( index( row, 0, parent ), 00940 index( row, columnCount( parent ), parent ) ); 00941 } 00942 00943 void QgsRuleBasedRendererV2Model::updateRule( const QModelIndex& idx ) 00944 { 00945 emit dataChanged( index( 0, 0, idx ), 00946 index( rowCount( idx ) - 1, columnCount( idx ) - 1, idx ) ); 00947 00948 for ( int i = 0; i < rowCount( idx ); i++ ) 00949 { 00950 updateRule( index( i, 0, idx ) ); 00951 } 00952 } 00953 00954 00955 void QgsRuleBasedRendererV2Model::removeRule( const QModelIndex& index ) 00956 { 00957 if ( !index.isValid() ) 00958 return; 00959 00960 beginRemoveRows( index.parent(), index.row(), index.row() ); 00961 00962 QgsRuleBasedRendererV2::Rule* rule = ruleForIndex( index ); 00963 rule->parent()->removeChild( rule ); 00964 00965 endRemoveRows(); 00966 } 00967 00968 void QgsRuleBasedRendererV2Model::willAddRules( const QModelIndex& parent, int count ) 00969 { 00970 int row = rowCount( parent ); // only consider appending 00971 beginInsertRows( parent, row, row + count - 1 ); 00972 } 00973 00974 void QgsRuleBasedRendererV2Model::finishedAddingRules() 00975 { 00976 emit endInsertRows(); 00977 } 00978 00979 void QgsRuleBasedRendererV2Model::setFeatureCounts( QMap<QgsRuleBasedRendererV2::Rule*, QgsRuleBasedRendererV2Count> theCountMap ) 00980 { 00981 mFeatureCountMap = theCountMap; 00982 updateRule( QModelIndex() ); 00983 } 00984 00985 void QgsRuleBasedRendererV2Model::clearFeatureCounts() 00986 { 00987 mFeatureCountMap.clear(); 00988 updateRule( QModelIndex() ); 00989 }