32 #include <QMessageBox>
36 static QList<QgsExpressionContextScope *> _globalProjectAtlasMapLayerScopes(
QgsMapCanvas *mapCanvas,
const QgsMapLayer *layer )
38 QList<QgsExpressionContextScope *> scopes;
68 mCopyAction =
new QAction( tr(
"Copy" ),
this );
69 mCopyAction->setShortcut( QKeySequence( QKeySequence::Copy ) );
70 mPasteAction =
new QAction( tr(
"Paste" ),
this );
71 mPasteAction->setShortcut( QKeySequence( QKeySequence::Paste ) );
72 mDeleteAction =
new QAction( tr(
"Remove Rule" ),
this );
73 mDeleteAction->setShortcut( QKeySequence( QKeySequence::Delete ) );
75 viewRules->addAction( mCopyAction );
76 viewRules->addAction( mPasteAction );
77 viewRules->addAction( mDeleteAction );
79 connect( viewRules, &QAbstractItemView::doubleClicked,
this,
static_cast<void (
QgsRuleBasedLabelingWidget::* )(
const QModelIndex & )
>( &QgsRuleBasedLabelingWidget::editRule ) );
81 connect( btnAddRule, &QAbstractButton::clicked,
this, &QgsRuleBasedLabelingWidget::addRule );
82 connect( btnEditRule, &QAbstractButton::clicked,
this,
static_cast<void (
QgsRuleBasedLabelingWidget::* )()
>( &QgsRuleBasedLabelingWidget::editRule ) );
83 connect( btnRemoveRule, &QAbstractButton::clicked,
this, &QgsRuleBasedLabelingWidget::removeRule );
84 connect( mCopyAction, &QAction::triggered,
this, &QgsRuleBasedLabelingWidget::copy );
85 connect( mPasteAction, &QAction::triggered,
this, &QgsRuleBasedLabelingWidget::paste );
86 connect( mDeleteAction, &QAction::triggered,
this, &QgsRuleBasedLabelingWidget::removeRule );
97 std::unique_ptr< QgsPalLayerSettings > newSettings = qgis::make_unique< QgsPalLayerSettings >( mLayer->
labeling()->
settings() );
98 newSettings->drawLabels =
true;
107 viewRules->setModel( mModel );
125 mCopyAction->setShortcut( QKeySequence() );
127 mPasteAction->setShortcut( QKeySequence() );
129 mDeleteAction->setShortcut( QKeySequence() );
134 void QgsRuleBasedLabelingWidget::addRule()
143 QModelIndex currentIndex = viewRules->selectionModel()->currentIndex();
144 mModel->
insertRule( currentIndex.parent(), currentIndex.row() + 1, newrule );
145 QModelIndex newindex = mModel->
index( currentIndex.row() + 1, 0, currentIndex.parent() );
146 viewRules->selectionModel()->setCurrentIndex( newindex, QItemSelectionModel::ClearAndSelect );
152 mModel->
insertRule( QModelIndex(), rows, newrule );
153 QModelIndex newindex = mModel->
index( rows, 0 );
154 viewRules->selectionModel()->setCurrentIndex( newindex, QItemSelectionModel::ClearAndSelect );
159 void QgsRuleBasedLabelingWidget::ruleWidgetPanelAccepted(
QgsPanelWidget *panel )
164 QModelIndex index = viewRules->selectionModel()->currentIndex();
165 mModel->
updateRule( index.parent(), index.row() );
168 void QgsRuleBasedLabelingWidget::liveUpdateRuleFromPanel()
170 ruleWidgetPanelAccepted( qobject_cast<QgsPanelWidget *>( sender() ) );
174 void QgsRuleBasedLabelingWidget::editRule()
176 editRule( viewRules->selectionModel()->currentIndex() );
179 void QgsRuleBasedLabelingWidget::editRule(
const QModelIndex &index )
181 if ( !index.isValid() )
193 void QgsRuleBasedLabelingWidget::removeRule()
195 QItemSelection sel = viewRules->selectionModel()->selection();
196 const auto constSel = sel;
197 for (
const QItemSelectionRange &range : constSel )
199 if ( range.isValid() )
200 mModel->
removeRows( range.top(), range.bottom() - range.top() + 1, range.parent() );
203 viewRules->selectionModel()->clear();
206 void QgsRuleBasedLabelingWidget::copy()
208 QModelIndexList indexlist = viewRules->selectionModel()->selectedRows();
210 if ( indexlist.isEmpty() )
213 QMimeData *mime = mModel->
mimeData( indexlist );
214 QApplication::clipboard()->setMimeData( mime );
217 void QgsRuleBasedLabelingWidget::paste()
219 const QMimeData *mime = QApplication::clipboard()->mimeData();
220 QModelIndexList indexlist = viewRules->selectionModel()->selectedRows();
222 if ( indexlist.isEmpty() )
225 index = indexlist.first();
226 mModel->
dropMimeData( mime, Qt::CopyAction, index.row(), index.column(), index.parent() );
231 QItemSelectionModel *sel = viewRules->selectionModel();
232 QModelIndex idx = sel->currentIndex();
233 if ( !idx.isValid() )
241 : QAbstractItemModel( parent )
242 , mRootRule( rootRule )
248 if ( !
index.isValid() )
249 return Qt::ItemIsDropEnabled;
252 Qt::ItemFlag drop = (
index.column() == 0 ? Qt::ItemIsDropEnabled : Qt::NoItemFlags );
254 Qt::ItemFlag checkable = (
index.column() == 0 ? Qt::ItemIsUserCheckable : Qt::NoItemFlags );
256 return Qt::ItemIsEnabled | Qt::ItemIsSelectable |
257 Qt::ItemIsEditable | checkable |
258 Qt::ItemIsDragEnabled | drop;
263 if ( !
index.isValid() )
268 if ( role == Qt::DisplayRole || role == Qt::ToolTipRole )
270 switch (
index.column() )
293 else if ( role == Qt::DecorationRole &&
index.column() == 0 && rule->
settings() )
298 else if ( role == Qt::TextAlignmentRole )
300 return (
index.column() == 2 ||
index.column() == 3 ) ? Qt::AlignRight : Qt::AlignLeft;
302 else if ( role == Qt::FontRole &&
index.column() == 1 )
307 italicFont.setItalic(
true );
312 else if ( role == Qt::EditRole )
314 switch (
index.column() )
330 else if ( role == Qt::CheckStateRole )
332 if (
index.column() != 0 )
334 return rule->
active() ? Qt::Checked : Qt::Unchecked;
342 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < 5 )
345 lst << tr(
"Label" ) << tr(
"Rule" ) << tr(
"Min. Scale" ) << tr(
"Max. Scale" ) << tr(
"Text" );
354 if (
parent.column() > 0 )
359 return parentRule->
children().count();
369 if ( hasIndex( row, column,
parent ) )
373 return createIndex( row, column, childRule );
375 return QModelIndex();
380 if ( !
index.isValid() )
381 return QModelIndex();
387 return QModelIndex();
392 return createIndex( row, 0, parentRule );
397 if ( !
index.isValid() )
402 if ( role == Qt::CheckStateRole )
404 rule->
setActive( value.toInt() == Qt::Checked );
409 if ( role != Qt::EditRole )
412 switch (
index.column() )
441 return Qt::MoveAction;
447 types << QStringLiteral(
"application/vnd.text.list" );
455 if ( ruleElem.hasAttribute( QStringLiteral(
"label" ) ) )
456 ruleElem.setAttribute( QStringLiteral(
"description" ), ruleElem.attribute( QStringLiteral(
"label" ) ) );
459 QDomElement childRuleElem = ruleElem.firstChildElement( QStringLiteral(
"rule" ) );
460 while ( !childRuleElem.isNull() )
463 childRuleElem = childRuleElem.nextSiblingElement( QStringLiteral(
"rule" ) );
469 QMimeData *
mimeData =
new QMimeData();
470 QByteArray encodedData;
472 QDataStream stream( &encodedData, QIODevice::WriteOnly );
474 const auto constIndexes = indexes;
475 for (
const QModelIndex &
index : constIndexes )
478 if ( !
index.isValid() ||
index.column() != 0 )
486 QDomElement rootElem = doc.createElement( QStringLiteral(
"rule_mime" ) );
487 rootElem.setAttribute( QStringLiteral(
"type" ), QStringLiteral(
"labeling" ) );
489 rootElem.appendChild( rulesElem );
490 doc.appendChild( rootElem );
494 stream << doc.toString( -1 );
497 mimeData->setData( QStringLiteral(
"application/vnd.text.list" ), encodedData );
505 if ( action == Qt::IgnoreAction )
508 if ( !
data->hasFormat( QStringLiteral(
"application/vnd.text.list" ) ) )
511 if (
parent.column() > 0 )
514 QByteArray encodedData =
data->data( QStringLiteral(
"application/vnd.text.list" ) );
515 QDataStream stream( &encodedData, QIODevice::ReadOnly );
524 while ( !stream.atEnd() )
530 if ( !doc.setContent( text ) )
532 QDomElement rootElem = doc.documentElement();
533 if ( rootElem.tagName() != QLatin1String(
"rule_mime" ) )
535 QDomElement ruleElem = rootElem.firstChildElement( QStringLiteral(
"rule" ) );
536 if ( rootElem.attribute( QStringLiteral(
"type" ) ) == QLatin1String(
"renderer" ) )
551 if ( row < 0 || row >= parentRule->
children().count() )
554 beginRemoveRows(
parent, row, row + count - 1 );
556 for (
int i = 0; i < count; i++ )
558 if ( row < parentRule->children().count() )
564 QgsDebugMsg( QStringLiteral(
"trying to remove invalid index - this should not happen!" ) );
575 if (
index.isValid() )
582 beginInsertRows(
parent, before, before );
602 , mSettings( nullptr )
603 , mMapCanvas( mapCanvas )
607 mElseRadio->setChecked( mRule->
isElse() );
608 mFilterRadio->setChecked( !mRule->
isElse() );
612 editDescription->setToolTip( mRule->
description() );
616 groupScale->setChecked(
true );
621 mScaleRangeWidget->setMapCanvas( mMapCanvas );
625 groupSettings->setChecked(
true );
630 groupSettings->setChecked(
false );
634 mLabelingGui =
new QgsLabelingGui(
nullptr, mMapCanvas, *mSettings,
this );
635 mLabelingGui->layout()->setContentsMargins( 0, 0, 0, 0 );
636 QVBoxLayout *l =
new QVBoxLayout;
637 l->addWidget( mLabelingGui );
638 groupSettings->setLayout( l );
640 mLabelingGui->setLabelMode( QgsLabelingGui::Labels );
641 mLabelingGui->setLayer( mLayer );
643 connect( btnExpressionBuilder, &QAbstractButton::clicked,
this, &QgsLabelingRulePropsWidget::buildExpression );
644 connect( btnTestFilter, &QAbstractButton::clicked,
this, &QgsLabelingRulePropsWidget::testFilter );
651 connect( mFilterRadio, &QRadioButton::toggled,
this, [ = ](
bool toggled ) { filterFrame->setEnabled( toggled ) ; } );
652 connect( mElseRadio, &QRadioButton::toggled,
this, [ = ](
bool toggled ) {
if ( toggled ) editFilter->setText( QStringLiteral(
"ELSE" ) );} );
663 mLabelingGui->setDockMode(
dockMode );
666 void QgsLabelingRulePropsWidget::testFilter()
668 if ( !mFilterRadio->isChecked() )
672 if ( filter.hasParserError() )
674 QMessageBox::critical(
this, tr(
"Test Filter" ), tr(
"Filter expression parsing error:\n" ) + filter.parserErrorString() );
680 if ( !filter.prepare( &context ) )
682 QMessageBox::critical(
this, tr(
"Test Filter" ), filter.evalErrorString() );
686 QApplication::setOverrideCursor( Qt::WaitCursor );
694 context.setFeature( f );
696 QVariant value = filter.evaluate( &context );
697 if ( value.toInt() != 0 )
699 if ( filter.hasEvalError() )
703 QApplication::restoreOverrideCursor();
705 QMessageBox::information(
this, tr(
"Test Filter" ), tr(
"Filter returned %n feature(s)",
"number of filtered features", count ) );
709 void QgsLabelingRulePropsWidget::buildExpression()
716 editFilter->setText( dlg.expressionText() );
721 QString filter = mElseRadio->isChecked() ? QStringLiteral(
"ELSE" ) : editFilter->text();
724 mRule->
setMinimumScale( groupScale->isChecked() ? mScaleRangeWidget->minimumScale() : 0 );
725 mRule->
setMaximumScale( groupScale->isChecked() ? mScaleRangeWidget->maximumScale() : 0 );
virtual QgsPalLayerSettings settings(const QString &providerId=QString()) const =0
Gets associated label settings.
virtual QString type() const =0
Unique type string of the labeling configuration implementation.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
A generic dialog for building expression strings.
Single scope for storing variables and functions for use within a QgsExpressionContext.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * atlasScope(const QgsLayoutAtlas *atlas)
Creates a new scope which contains variables and functions relating to a QgsLayoutAtlas.
static QgsExpressionContextScope * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Class for parsing and evaluation of expressions (formerly called "search strings").
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Map canvas is a class for displaying all GIS data types on a canvas.
QgsExpressionContextScope & expressionContextScope()
Returns a reference to the expression context scope for the map canvas.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
Base class for all map layer types.
The QgsMapSettings class contains configuration for rendering of the map.
Contains settings for how a map layer will be labeled.
static QPixmap labelSettingsPreviewPixmap(const QgsPalLayerSettings &settings, QSize size, const QString &previewText=QString(), int padding=0)
Returns a pixmap preview for label settings.
QString fieldName
Name of field (or an expression) to use for label text.
static QgsProject * instance()
Returns the QgsProject singleton instance.
The class is used as a container of context for various read/write operations on other objects.
Model for rule based rendering rules view.
QgsRuleBasedLabelingModel(QgsRuleBasedLabeling::Rule *rootRule, QObject *parent=nullptr)
constructor
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
QStringList mimeTypes() const override
QgsRuleBasedLabeling::Rule * mRootRule
Qt::DropActions supportedDropActions() const override
void insertRule(const QModelIndex &parent, int before, QgsRuleBasedLabeling::Rule *newrule)
Inserts a new rule at the specified position.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
provide model index for parent's child item
QgsRuleBasedLabeling::Rule * ruleForIndex(const QModelIndex &index) const
Returns the rule at the specified index.
void updateRule(const QModelIndex &parent, int row)
Updates the rule at the specified position.
QMimeData * mimeData(const QModelIndexList &indexes) const override
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
QModelIndex parent(const QModelIndex &index) const override
provide parent model index
Qt::ItemFlags flags(const QModelIndex &index) const override
int columnCount(const QModelIndex &=QModelIndex()) const override
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
A child rule for QgsRuleBasedLabeling.
const QgsRuleBasedLabeling::RuleList & children() const
Returns all children rules of this rule.
QgsRuleBasedLabeling::Rule * clone() const
clone this rule, return new instance
void setMaximumScale(double scale)
Sets the maximum map scale (i.e.
double maximumScale() const
Returns the maximum map scale (i.e.
void setDescription(const QString &description)
Set a human readable description for this rule.
bool dependsOnScale() const
Determines if scale based labeling is active.
QgsPalLayerSettings * settings() const
Returns the labeling settings.
QString filterExpression() const
A filter that will check if this rule applies.
bool active() const
Returns if this rule is active.
static QgsRuleBasedLabeling::Rule * create(const QDomElement &ruleElem, const QgsReadWriteContext &context)
Create a rule from an XML definition.
void removeChildAt(int i)
delete child rule
void setActive(bool state)
Sets if this rule is active.
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) const
store labeling info to XML element
void setSettings(QgsPalLayerSettings *settings)
Sets new settings (or nullptr). Deletes old settings if any.
bool isElse() const
Check if this rule is an ELSE rule.
void insertChild(int i, QgsRuleBasedLabeling::Rule *rule)
add child rule, take ownership, sets this as parent
void setMinimumScale(double scale)
Sets the minimum map scale (i.e.
const QgsRuleBasedLabeling::Rule * parent() const
The parent rule.
void setFilterExpression(const QString &filterExp)
Set the expression used to check if a given feature shall be rendered with this rule.
double minimumScale() const
Returns the minimum map scale (i.e.
void appendChild(QgsRuleBasedLabeling::Rule *rule)
add child rule, take ownership, sets this as parent
QString description() const
A human readable description for this rule.
Rule based labeling for a vector layer.
QgsRuleBasedLabeling::Rule * rootRule()
static QString toString(double scale)
Helper function to convert a scale double to scale string.
void widgetChanged()
Emitted when the text format defined by the widget changes.
Represents a vector layer which manages a vector based data sets.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
const QgsAbstractVectorLayerLabeling * labeling() const
Access to const labeling configuration.
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...