31 #include <QProgressDialog>
33 #include <QTreeWidgetItem>
34 #include <QVBoxLayout>
35 #include <QMessageBox>
37 #ifdef ENABLE_MODELTEST
38 #include "modeltest.h"
69 #ifdef ENABLE_MODELTEST
70 new ModelTest(
mModel,
this );
72 viewRules->setModel(
mModel );
75 mDeleteAction->setShortcut( QKeySequence( QKeySequence::Delete ) );
81 mRefineMenu =
new QMenu(
tr(
"Refine current rule" ), btnRefineRule );
92 connect( viewRules, SIGNAL( doubleClicked(
const QModelIndex & ) ),
this, SLOT(
editRule(
const QModelIndex & ) ) );
95 connect( viewRules, SIGNAL( customContextMenuRequested(
const QPoint& ) ),
this, SLOT(
contextMenuViewCategories(
const QPoint& ) ) );
97 connect( viewRules->selectionModel(), SIGNAL( currentChanged( QModelIndex, QModelIndex ) ),
this, SLOT(
currentRuleChanged( QModelIndex, QModelIndex ) ) );
99 connect( btnAddRule, SIGNAL( clicked() ),
this, SLOT(
addRule() ) );
100 connect( btnEditRule, SIGNAL( clicked() ),
this, SLOT(
editRule() ) );
101 connect( btnRemoveRule, SIGNAL( clicked() ),
this, SLOT(
removeRule() ) );
103 connect( btnCountFeatures, SIGNAL( clicked() ),
this, SLOT(
countFeatures() ) );
105 connect( btnRenderingOrder, SIGNAL( clicked() ),
this, SLOT(
setRenderingOrder() ) );
110 connect( viewRules->header(), SIGNAL( sectionResized(
int,
int,
int ) ),
this, SLOT(
saveSectionWidth(
int,
int,
int ) ) );
139 QModelIndex currentIndex = viewRules->selectionModel()->currentIndex();
140 mModel->
insertRule( currentIndex.parent(), currentIndex.row() + 1, newrule );
158 QItemSelectionModel* sel = viewRules->selectionModel();
159 QModelIndex idx = sel->currentIndex();
160 if ( !idx.isValid() )
167 editRule( viewRules->selectionModel()->currentIndex() );
172 if ( !index.isValid() )
187 QItemSelection sel = viewRules->selectionModel()->selection();
188 QgsDebugMsg( QString(
"REMOVE RULES!!! ranges: %1" ).arg( sel.count() ) );
189 foreach ( QItemSelectionRange range, sel )
191 QgsDebugMsg( QString(
"RANGE: r %1 - %2" ).arg( range.top() ).arg( range.bottom() ) );
192 if ( range.isValid() )
193 mModel->
removeRows( range.top(), range.bottom() - range.top() + 1, range.parent() );
196 viewRules->selectionModel()->clear();
202 Q_UNUSED( previous );
203 btnRefineRule->setEnabled( current.isValid() );
212 #include <QDialogButtonBox>
213 #include <QInputDialog>
215 #include <QClipboard>
219 QModelIndexList indexlist = viewRules->selectionModel()->selectedRows();
221 if ( indexlist.isEmpty() )
227 else if ( type == 1 )
235 foreach ( QModelIndex
index, indexlist )
236 viewRules->expand( index );
257 dlg.setWindowTitle(
tr(
"Refine a rule to categories" ) );
258 QVBoxLayout* l =
new QVBoxLayout();
261 QDialogButtonBox* bb =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
263 connect( bb, SIGNAL( accepted() ), &dlg, SLOT( accept() ) );
264 connect( bb, SIGNAL( rejected() ), &dlg, SLOT( reject() ) );
272 foreach ( QModelIndex
index, indexList )
287 dlg.setWindowTitle(
tr(
"Refine a rule to ranges" ) );
288 QVBoxLayout* l =
new QVBoxLayout();
291 QDialogButtonBox* bb =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
293 connect( bb, SIGNAL( accepted() ), &dlg, SLOT( accept() ) );
294 connect( bb, SIGNAL( rejected() ), &dlg, SLOT( reject() ) );
302 foreach ( QModelIndex
index, indexList )
313 foreach ( QModelIndex
index, indexList )
318 if ( initialRule->
symbol() == NULL )
320 QMessageBox::warning(
this,
tr(
"Scale refinement" ),
tr(
"Parent rule %1 must have a symbol for this operation." ).arg( initialRule->
label() ) );
325 QString txt = QInputDialog::getText(
this,
326 tr(
"Scale refinement" ),
327 tr(
"Please enter scale denominators at which will split the rule, separate them by commas (e.g. 1000,5000):" ) );
333 foreach ( QString item, txt.split(
',' ) )
335 int scale = item.toInt( &ok );
337 scales.append( scale );
339 QMessageBox::information(
this,
tr(
"Error" ), QString(
tr(
"\"%1\" is not valid scale denominator, ignoring it." ) ).arg( item ) );
342 foreach ( QModelIndex index, indexList )
353 QList<QgsSymbolV2*> symbolList;
360 QItemSelection sel = viewRules->selectionModel()->selection();
361 foreach ( QItemSelectionRange range, sel )
363 QModelIndex parent = range.parent();
366 for (
int row = range.top(); row <= range.bottom(); row++ )
368 symbolList.append( children[row]->symbol() );
378 QItemSelection sel = viewRules->selectionModel()->selection();
379 foreach ( QItemSelectionRange range, sel )
381 QModelIndex parent = range.parent();
384 for (
int row = range.top(); row <= range.bottom(); row++ )
386 rl.append( children[row]->clone() );
410 if ( event->key() == Qt::Key_C &&
event->modifiers() == Qt::ControlModifier )
416 else if ( event->key() == Qt::Key_V &&
event->modifiers() == Qt::ControlModifier )
418 QgsRuleBasedRendererV2::RuleList::const_iterator rIt =
mCopyBuffer.constBegin();
446 QString path =
"/Windows/RuleBasedTree/sectionWidth/" + QString::number( section );
447 settings.setValue( path, newSize );
453 QString path =
"/Windows/RuleBasedTree/sectionWidth/";
454 QHeaderView* head = viewRules->header();
455 head->resizeSection( 0, settings.value( path + QString::number( 0 ), 150 ).toInt() );
456 head->resizeSection( 1, settings.value( path + QString::number( 1 ), 150 ).toInt() );
457 head->resizeSection( 2, settings.value( path + QString::number( 2 ), 80 ).toInt() );
458 head->resizeSection( 3, settings.value( path + QString::number( 3 ), 80 ).toInt() );
459 head->resizeSection( 4, settings.value( path + QString::number( 4 ), 50 ).toInt() );
460 head->resizeSection( 5, settings.value( path + QString::number( 5 ), 50 ).toInt() );
465 QModelIndexList indexlist = viewRules->selectionModel()->selectedRows();
466 QgsDebugMsg( QString(
"%1" ).arg( indexlist.count() ) );
468 if ( indexlist.isEmpty() )
472 QApplication::clipboard()->setMimeData( mime );
477 const QMimeData* mime = QApplication::clipboard()->mimeData();
478 QModelIndexList indexlist = viewRules->selectionModel()->selectedRows();
480 if ( indexlist.isEmpty() )
483 index = indexlist.first();
484 mModel->
dropMimeData( mime, Qt::CopyAction, index.row(), index.column(), index.parent() );
494 QMap<QgsRuleBasedRendererV2::Rule*, QgsRuleBasedRendererV2Count> countMap;
500 countMap[rule].count = 0;
501 countMap[rule].duplicateCount = 0;
511 QProgressDialog p(
tr(
"Calculating feature count." ),
tr(
"Abort" ), 0, nFeatures );
512 p.setWindowModality( Qt::WindowModal );
513 int featuresCounted = 0;
522 countMap[rule].count++;
523 if ( featureRuleList.size() > 1 )
525 countMap[rule].duplicateCount++;
529 if ( duplicateRule == rule )
continue;
530 countMap[rule].duplicateCountMap[duplicateRule] += 1;
534 if ( featuresCounted % 50 == 0 )
536 if ( featuresCounted > nFeatures )
540 p.setValue( featuresCounted );
541 if ( p.wasCanceled() )
547 p.setValue( nFeatures );
554 QgsDebugMsg( QString(
"rule: %1 count %2" ).arg( rule->
label() ).arg( countMap[rule].count ) );
564 : QDialog( parent ), mRule( rule ), mLayer( layer ), mSymbolSelector( NULL ), mSymbol( NULL )
568 setWindowModality( Qt::WindowModal );
571 connect( buttonBox, SIGNAL( accepted() ),
this, SLOT(
accept() ) );
572 connect( buttonBox, SIGNAL( rejected() ),
this, SLOT( reject() ) );
582 groupScale->setChecked(
true );
585 mScaleRangeWidget->setMaximumScale( 1.0 / rule->
scaleMinDenom() );
587 mScaleRangeWidget->setMinimumScale( 1.0 / rule->
scaleMaxDenom() );
592 groupSymbol->setChecked(
true );
597 groupSymbol->setChecked(
false );
602 QVBoxLayout* l =
new QVBoxLayout;
604 groupSymbol->setLayout( l );
606 connect( btnExpressionBuilder, SIGNAL( clicked() ),
this, SLOT(
buildExpression() ) );
607 connect( btnTestFilter, SIGNAL( clicked() ),
this, SLOT(
testFilter() ) );
610 restoreGeometry( settings.value(
"/Windows/QgsRendererRulePropsDialog/geometry" ).toByteArray() );
617 settings.setValue(
"/Windows/QgsRendererRulePropsDialog/geometry", saveGeometry() );
625 editFilter->setText( dlg.expressionText() );
631 if ( filter.hasParserError() )
633 QMessageBox::critical(
this,
tr(
"Error" ),
tr(
"Filter expression parsing error:\n" ) + filter.parserErrorString() );
639 if ( !filter.prepare( fields ) )
641 QMessageBox::critical(
this,
tr(
"Evaluation error" ), filter.evalErrorString() );
645 QApplication::setOverrideCursor( Qt::WaitCursor );
653 QVariant value = filter.evaluate( &f );
654 if ( value.toInt() != 0 )
656 if ( filter.hasEvalError() )
660 QApplication::restoreOverrideCursor();
662 QMessageBox::information(
this,
tr(
"Filter" ),
tr(
"Filter returned %n feature(s)",
"number of filtered features", count ) );
691 QString txt = QString(
"1:%L1" ).arg( denom );
707 if ( !index.isValid() )
708 return Qt::ItemIsDropEnabled;
711 Qt::ItemFlag drop = ( index.column() == 0 ? Qt::ItemIsDropEnabled : Qt::NoItemFlags );
713 Qt::ItemFlag checkable = ( index.column() == 0 ? Qt::ItemIsUserCheckable : Qt::NoItemFlags );
715 return Qt::ItemIsEnabled | Qt::ItemIsSelectable |
716 Qt::ItemIsEditable | checkable |
717 Qt::ItemIsDragEnabled | drop;
722 if ( !index.isValid() )
727 if ( role == Qt::DisplayRole || role == Qt::ToolTipRole )
729 switch ( index.column() )
731 case 0:
return rule->
label();
752 if ( role == Qt::DisplayRole )
760 QString tip =
"<p style='margin:0px;'><ul>";
763 QString label = duplicateRule->
label().replace(
"&",
"&" ).replace(
">",
">" ).replace(
"<",
"<" );
764 tip +=
tr(
"<li><nobr>%1 features also in rule %2</nobr></li>" ).arg(
mFeatureCountMap[rule].duplicateCountMap[duplicateRule] ).arg( label );
776 default:
return QVariant();
779 else if ( role == Qt::DecorationRole && index.column() == 0 && rule->
symbol() )
783 else if ( role == Qt::TextAlignmentRole )
785 return ( index.column() == 2 || index.column() == 3 ) ? Qt::AlignRight : Qt::AlignLeft;
787 else if ( role == Qt::FontRole && index.column() == 1 )
792 italicFont.setItalic(
true );
797 else if ( role == Qt::EditRole )
799 switch ( index.column() )
801 case 0:
return rule->
label();
805 default:
return QVariant();
808 else if ( role == Qt::CheckStateRole )
810 if ( index.column() != 0 )
812 return rule->
checkState() ? Qt::Checked : Qt::Unchecked;
820 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < 7 )
822 QStringList lst; lst <<
tr(
"Label" ) <<
tr(
"Rule" ) <<
tr(
"Min. scale" ) <<
tr(
"Max. scale" ) <<
tr(
"Count" ) <<
tr(
"Duplicate count" );
825 else if ( orientation == Qt::Horizontal && role == Qt::ToolTipRole )
829 return tr(
"Number of features in this rule." );
831 else if ( section == 5 )
833 return tr(
"Number of features in this rule which are also present in other rule(s)." );
842 if ( parent.column() > 0 )
847 return parentRule->
children().count();
857 if ( hasIndex( row, column, parent ) )
861 return createIndex( row, column, childRule );
863 return QModelIndex();
868 if ( !index.isValid() )
869 return QModelIndex();
875 return QModelIndex();
880 return createIndex( row, 0, parentRule );
885 if ( !index.isValid() )
890 if ( role == Qt::CheckStateRole )
893 emit dataChanged( index, index );
897 if ( role != Qt::EditRole )
900 switch ( index.column() )
918 emit dataChanged( index, index );
924 return Qt::MoveAction;
930 types <<
"application/vnd.text.list";
936 QMimeData *
mimeData =
new QMimeData();
937 QByteArray encodedData;
939 QDataStream stream( &encodedData, QIODevice::WriteOnly );
941 foreach (
const QModelIndex &
index, indexes )
944 if ( !index.isValid() || index.column() != 0 )
953 QDomElement rootElem = doc.createElement(
"rule_mime" );
954 QDomElement rulesElem = rule->
save( doc, symbols );
955 rootElem.appendChild( rulesElem );
957 rootElem.appendChild( symbolsElem );
958 doc.appendChild( rootElem );
962 stream << doc.toString( -1 );
965 mimeData->setData(
"application/vnd.text.list", encodedData );
970 Qt::DropAction action,
int row,
int column,
const QModelIndex &parent )
974 if ( action == Qt::IgnoreAction )
977 if ( !data->hasFormat(
"application/vnd.text.list" ) )
980 if ( parent.column() > 0 )
983 QByteArray encodedData = data->data(
"application/vnd.text.list" );
984 QDataStream stream( &encodedData, QIODevice::ReadOnly );
993 while ( !stream.atEnd() )
999 if ( !doc.setContent( text ) )
1001 QDomElement rootElem = doc.documentElement();
1002 if ( rootElem.tagName() !=
"rule_mime" )
1004 QDomElement symbolsElem = rootElem.firstChildElement(
"symbols" );
1005 if ( symbolsElem.isNull() )
1008 QDomElement ruleElem = rootElem.firstChildElement(
"rule" );
1020 if ( index.isValid() )
1021 return static_cast<QgsRuleBasedRendererV2::Rule*>( index.internalPointer() );
1029 if ( row < 0 || row >= parentRule->
children().count() )
1032 QgsDebugMsg( QString(
"Called: row %1 count %2 parent ~~%3~~" ).arg( row ).arg( count ).arg( parentRule->
dump() ) );
1034 beginRemoveRows( parent, row, row + count - 1 );
1036 for (
int i = 0; i < count; i++ )
1038 if ( row < parentRule->children().count() )
1046 QgsDebugMsg(
"trying to remove invalid index - this should not happen!" );
1058 beginInsertRows( parent, before, before );
1060 QgsDebugMsg( QString(
"insert before %1 rule: %2" ).arg( before ).arg( newrule->
dump() ) );
1070 emit dataChanged(
index( row, 0, parent ),
1076 emit dataChanged(
index( 0, 0, idx ),
1079 for (
int i = 0; i <
rowCount( idx ); i++ )
1088 if ( !index.isValid() )
1091 beginRemoveRows( index.parent(), index.row(), index.row() );
1094 rule->parent()->removeChild( rule );
1102 beginInsertRows( parent, row, row + count - 1 );
1107 emit endInsertRows();