36static 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 = std::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() );
134void QgsRuleBasedLabelingWidget::addRule()
142 const QModelIndex currentIndex = viewRules->selectionModel()->currentIndex();
143 mModel->
insertRule( currentIndex.parent(), currentIndex.row() + 1, newrule );
144 const QModelIndex newindex = mModel->
index( currentIndex.row() + 1, 0, currentIndex.parent() );
145 viewRules->selectionModel()->setCurrentIndex( newindex, QItemSelectionModel::ClearAndSelect );
150 const int rows = mModel->
rowCount();
151 mModel->
insertRule( QModelIndex(), rows, newrule );
152 const QModelIndex newindex = mModel->
index( rows, 0 );
153 viewRules->selectionModel()->setCurrentIndex( newindex, QItemSelectionModel::ClearAndSelect );
158void QgsRuleBasedLabelingWidget::ruleWidgetPanelAccepted(
QgsPanelWidget *panel )
163 const QModelIndex index = viewRules->selectionModel()->currentIndex();
164 mModel->
updateRule( index.parent(), index.row() );
167void QgsRuleBasedLabelingWidget::liveUpdateRuleFromPanel()
169 ruleWidgetPanelAccepted( qobject_cast<QgsPanelWidget *>( sender() ) );
173void QgsRuleBasedLabelingWidget::editRule()
175 editRule( viewRules->selectionModel()->currentIndex() );
178void QgsRuleBasedLabelingWidget::editRule(
const QModelIndex &index )
180 if ( !index.isValid() )
199 mModel->
updateRule( index.parent(), index.row() );
204void QgsRuleBasedLabelingWidget::removeRule()
206 const QItemSelection sel = viewRules->selectionModel()->selection();
207 const auto constSel = sel;
208 for (
const QItemSelectionRange &range : constSel )
210 if ( range.isValid() )
211 mModel->
removeRows( range.top(), range.bottom() - range.top() + 1, range.parent() );
214 viewRules->selectionModel()->clear();
217void QgsRuleBasedLabelingWidget::copy()
219 const QModelIndexList indexlist = viewRules->selectionModel()->selectedRows();
221 if ( indexlist.isEmpty() )
224 QMimeData *mime = mModel->
mimeData( indexlist );
225 QApplication::clipboard()->setMimeData( mime );
228void QgsRuleBasedLabelingWidget::paste()
230 const QMimeData *mime = QApplication::clipboard()->mimeData();
231 QModelIndexList indexlist = viewRules->selectionModel()->selectedRows();
233 if ( indexlist.isEmpty() )
236 index = indexlist.first();
237 mModel->
dropMimeData( mime, Qt::CopyAction, index.row(), index.column(), index.parent() );
242 QItemSelectionModel *sel = viewRules->selectionModel();
243 const QModelIndex idx = sel->currentIndex();
244 if ( !idx.isValid() )
256 setWindowModality( Qt::WindowModal );
259 QVBoxLayout *layout =
new QVBoxLayout(
this );
261 scrollArea->setFrameShape( QFrame::NoFrame );
262 layout->addWidget( scrollArea );
264 buttonBox =
new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok );
267 scrollArea->setWidget( mPropsWidget );
268 layout->addWidget( buttonBox );
269 this->setWindowTitle(
"Edit Rule" );
273 connect( buttonBox, &QDialogButtonBox::rejected,
this, &QDialog::reject );
274 connect( buttonBox, &QDialogButtonBox::helpRequested,
this, &QgsLabelingRulePropsDialog::showHelp );
289 mPropsWidget->
apply();
293void QgsLabelingRulePropsDialog::showHelp()
295 QgsHelp::openHelp( QStringLiteral(
"working_with_vector/vector_properties.html#rule-based-labeling" ) );
301 : QAbstractItemModel( parent )
302 , mRootRule( rootRule )
308 if ( !
index.isValid() )
309 return Qt::ItemIsDropEnabled;
312 const Qt::ItemFlag drop = (
index.column() == 0 ? Qt::ItemIsDropEnabled : Qt::NoItemFlags );
314 const Qt::ItemFlag checkable = (
index.column() == 0 ? Qt::ItemIsUserCheckable : Qt::NoItemFlags );
316 return Qt::ItemIsEnabled | Qt::ItemIsSelectable |
317 Qt::ItemIsEditable | checkable |
318 Qt::ItemIsDragEnabled | drop;
323 if ( !
index.isValid() )
328 if ( role == Qt::DisplayRole || role == Qt::ToolTipRole )
330 switch (
index.column() )
353 else if ( role == Qt::DecorationRole &&
index.column() == 0 && rule->
settings() )
358 else if ( role == Qt::TextAlignmentRole )
360 return (
index.column() == 2 ||
index.column() == 3 ) ?
static_cast<Qt::Alignment::Int
>( Qt::AlignRight ) :
static_cast<Qt::Alignment::Int
>( Qt::AlignLeft );
362 else if ( role == Qt::FontRole &&
index.column() == 1 )
367 italicFont.setItalic(
true );
372 else if ( role == Qt::EditRole )
374 switch (
index.column() )
390 else if ( role == Qt::CheckStateRole )
392 if (
index.column() != 0 )
394 return rule->
active() ? Qt::Checked : Qt::Unchecked;
402 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < 5 )
405 lst << tr(
"Label" ) << tr(
"Rule" ) << tr(
"Min. Scale" ) << tr(
"Max. Scale" ) << tr(
"Text" );
414 if (
parent.column() > 0 )
419 return parentRule->
children().count();
429 if ( hasIndex( row, column,
parent ) )
433 return createIndex( row, column, childRule );
435 return QModelIndex();
440 if ( !
index.isValid() )
441 return QModelIndex();
447 return QModelIndex();
450 const int row = parentRule->
parent()->
children().indexOf( parentRule );
452 return createIndex( row, 0, parentRule );
457 if ( !
index.isValid() )
462 if ( role == Qt::CheckStateRole )
464 rule->
setActive( value.toInt() == Qt::Checked );
469 if ( role != Qt::EditRole )
472 switch (
index.column() )
501 return Qt::MoveAction;
507 types << QStringLiteral(
"application/vnd.text.list" );
515 if ( ruleElem.hasAttribute( QStringLiteral(
"label" ) ) )
516 ruleElem.setAttribute( QStringLiteral(
"description" ), ruleElem.attribute( QStringLiteral(
"label" ) ) );
519 QDomElement childRuleElem = ruleElem.firstChildElement( QStringLiteral(
"rule" ) );
520 while ( !childRuleElem.isNull() )
523 childRuleElem = childRuleElem.nextSiblingElement( QStringLiteral(
"rule" ) );
529 QMimeData *
mimeData =
new QMimeData();
530 QByteArray encodedData;
532 QDataStream stream( &encodedData, QIODevice::WriteOnly );
534 const auto constIndexes = indexes;
535 for (
const QModelIndex &
index : constIndexes )
538 if ( !
index.isValid() ||
index.column() != 0 )
546 QDomElement rootElem = doc.createElement( QStringLiteral(
"rule_mime" ) );
547 rootElem.setAttribute( QStringLiteral(
"type" ), QStringLiteral(
"labeling" ) );
549 rootElem.appendChild( rulesElem );
550 doc.appendChild( rootElem );
554 stream << doc.toString( -1 );
557 mimeData->setData( QStringLiteral(
"application/vnd.text.list" ), encodedData );
565 if ( action == Qt::IgnoreAction )
568 if ( !
data->hasFormat( QStringLiteral(
"application/vnd.text.list" ) ) )
571 if (
parent.column() > 0 )
574 QByteArray encodedData =
data->data( QStringLiteral(
"application/vnd.text.list" ) );
575 QDataStream stream( &encodedData, QIODevice::ReadOnly );
584 while ( !stream.atEnd() )
590 if ( !doc.setContent( text ) )
592 const QDomElement rootElem = doc.documentElement();
593 if ( rootElem.tagName() != QLatin1String(
"rule_mime" ) )
595 QDomElement ruleElem = rootElem.firstChildElement( QStringLiteral(
"rule" ) );
596 if ( rootElem.attribute( QStringLiteral(
"type" ) ) == QLatin1String(
"renderer" ) )
611 if ( row < 0 || row >= parentRule->
children().count() )
614 beginRemoveRows(
parent, row, row + count - 1 );
616 for (
int i = 0; i < count; i++ )
618 if ( row < parentRule->children().count() )
624 QgsDebugError( QStringLiteral(
"trying to remove invalid index - this should not happen!" ) );
635 if (
index.isValid() )
642 beginInsertRows(
parent, before, before );
662 , mSettings( nullptr )
663 , mMapCanvas( mapCanvas )
667 QButtonGroup *radioGroup =
new QButtonGroup(
this );
668 radioGroup->addButton( mFilterRadio );
669 radioGroup->addButton( mElseRadio );
671 mElseRadio->setChecked( mRule->
isElse() );
672 mFilterRadio->setChecked( !mRule->
isElse() );
676 editDescription->setToolTip( mRule->
description() );
680 groupScale->setChecked(
true );
685 mScaleRangeWidget->setMapCanvas( mMapCanvas );
689 groupSettings->setChecked(
true );
694 groupSettings->setChecked(
false );
698 mLabelingGui =
new QgsLabelingGui(
nullptr, mMapCanvas, *mSettings,
this );
699 mLabelingGui->layout()->setContentsMargins( 0, 0, 0, 0 );
700 QVBoxLayout *l =
new QVBoxLayout;
701 l->addWidget( mLabelingGui );
702 groupSettings->setLayout( l );
704 mLabelingGui->setLabelMode( QgsLabelingGui::Labels );
705 mLabelingGui->setLayer( mLayer );
715 connect( mFilterRadio, &QRadioButton::toggled,
this, [ = ](
bool toggled ) { filterFrame->setEnabled( toggled ) ; } );
716 connect( mElseRadio, &QRadioButton::toggled,
this, [ = ](
bool toggled ) {
if ( toggled ) editFilter->setText( QStringLiteral(
"ELSE" ) );} );
727 mLabelingGui->setDockMode(
dockMode );
732 if ( !mFilterRadio->isChecked() )
738 QMessageBox::critical(
this, tr(
"Test Filter" ), tr(
"Filter expression parsing error:\n" ) + filter.
parserErrorString() );
744 if ( !filter.
prepare( &context ) )
746 QMessageBox::critical(
this, tr(
"Test Filter" ), filter.
evalErrorString() );
750 QApplication::setOverrideCursor( Qt::WaitCursor );
760 const QVariant value = filter.
evaluate( &context );
761 if ( value.toInt() != 0 )
767 QApplication::restoreOverrideCursor();
769 QMessageBox::information(
this, tr(
"Test Filter" ), tr(
"Filter returned %n feature(s)",
"number of filtered features", count ) );
785 const QString filter = mElseRadio->isChecked() ? QStringLiteral(
"ELSE" ) : editFilter->text().trimmed();
788 mRule->
setMinimumScale( groupScale->isChecked() ? mScaleRangeWidget->minimumScale() : 0 );
789 mRule->
setMaximumScale( groupScale->isChecked() ? mScaleRangeWidget->maximumScale() : 0 );
virtual QgsPalLayerSettings settings(const QString &providerId=QString()) const =0
Gets associated label settings.
static QgsPalLayerSettings defaultSettingsForLayer(const QgsVectorLayer *layer)
Returns the default layer settings to use for the specified vector layer.
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...
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
QString evalErrorString() const
Returns evaluation error.
QString parserErrorString() const
Returns parser error.
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
QVariant evaluate()
Evaluate the feature and return the result.
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 unique ID, geometry and a list of field...
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Dialog for editing labeling rule.
void buildExpression()
Open the expression builder widget.
QgsLabelingRulePropsDialog(QgsRuleBasedLabeling::Rule *rule, QgsVectorLayer *layer, QWidget *parent=nullptr, QgsMapCanvas *mapCanvas=nullptr)
Constructor for QgsLabelingRulePropsDialog.
void testFilter()
Test the filter that is set in the widget.
QgsRuleBasedLabeling::Rule * rule()
Returns the current set rule.
void accept() override
Apply any changes from the widget to the set rule.
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.
QString fieldName
Name of field (or an expression) to use for label text.
static QPixmap labelSettingsPreviewPixmap(const QgsPalLayerSettings &settings, QSize size, const QString &previewText=QString(), int padding=0, const QgsScreenProperties &screen=QgsScreenProperties())
Returns a pixmap preview for label settings.
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.
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.
const QgsRuleBasedLabeling::RuleList & children() const
Returns all children rules of this rule.
QString filterExpression() const
A filter that will check if this rule applies.
const QgsRuleBasedLabeling::Rule * parent() const
The parent rule.
bool active() const
Returns if this rule is active.
QgsPalLayerSettings * settings() const
Returns the labeling settings.
void removeChildAt(int i)
delete child rule
void setActive(bool state)
Sets if this rule is active.
static QgsRuleBasedLabeling::Rule * create(const QDomElement &ruleElem, const QgsReadWriteContext &context, bool reuseId=true)
Create a rule from an XML definition.
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.
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.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
#define QgsDebugError(str)
const double ICON_PADDING_FACTOR