67 mCopyAction =
new QAction( tr(
"Copy" ),
this );
68 mCopyAction->setShortcut( QKeySequence( QKeySequence::Copy ) );
69 mPasteAction =
new QAction( tr(
"Paste" ),
this );
70 mPasteAction->setShortcut( QKeySequence( QKeySequence::Paste ) );
71 mDeleteAction =
new QAction( tr(
"Remove Rule" ),
this );
72 mDeleteAction->setShortcut( QKeySequence( QKeySequence::Delete ) );
74 viewRules->addAction( mCopyAction );
75 viewRules->addAction( mPasteAction );
76 viewRules->addAction( mDeleteAction );
78 connect( viewRules, &QAbstractItemView::doubleClicked,
this,
static_cast<void (
QgsRuleBasedLabelingWidget::* )(
const QModelIndex & )
>( &QgsRuleBasedLabelingWidget::editRule ) );
80 connect( btnAddRule, &QAbstractButton::clicked,
this, &QgsRuleBasedLabelingWidget::addRule );
81 connect( btnEditRule, &QAbstractButton::clicked,
this,
static_cast<void (
QgsRuleBasedLabelingWidget::* )()
>( &QgsRuleBasedLabelingWidget::editRule ) );
82 connect( btnRemoveRule, &QAbstractButton::clicked,
this, &QgsRuleBasedLabelingWidget::removeRule );
83 connect( mCopyAction, &QAction::triggered,
this, &QgsRuleBasedLabelingWidget::copy );
84 connect( mPasteAction, &QAction::triggered,
this, &QgsRuleBasedLabelingWidget::paste );
85 connect( mDeleteAction, &QAction::triggered,
this, &QgsRuleBasedLabelingWidget::removeRule );
96 std::unique_ptr< QgsPalLayerSettings > newSettings = std::make_unique< QgsPalLayerSettings >( mLayer->
labeling()->
settings() );
97 newSettings->drawLabels =
true;
106 viewRules->setModel( mModel );
124 mCopyAction->setShortcut( QKeySequence() );
126 mPasteAction->setShortcut( QKeySequence() );
128 mDeleteAction->setShortcut( QKeySequence() );
133void QgsRuleBasedLabelingWidget::addRule()
141 const QModelIndex currentIndex = viewRules->selectionModel()->currentIndex();
142 mModel->
insertRule( currentIndex.parent(), currentIndex.row() + 1, newrule );
143 const QModelIndex newindex = mModel->
index( currentIndex.row() + 1, 0, currentIndex.parent() );
144 viewRules->selectionModel()->setCurrentIndex( newindex, QItemSelectionModel::ClearAndSelect );
149 const int rows = mModel->
rowCount();
150 mModel->
insertRule( QModelIndex(), rows, newrule );
151 const QModelIndex newindex = mModel->
index( rows, 0 );
152 viewRules->selectionModel()->setCurrentIndex( newindex, QItemSelectionModel::ClearAndSelect );
157void QgsRuleBasedLabelingWidget::ruleWidgetPanelAccepted(
QgsPanelWidget *panel )
162 const QModelIndex index = viewRules->selectionModel()->currentIndex();
163 mModel->
updateRule( index.parent(), index.row() );
166void QgsRuleBasedLabelingWidget::liveUpdateRuleFromPanel()
168 ruleWidgetPanelAccepted( qobject_cast<QgsPanelWidget *>( sender() ) );
172void QgsRuleBasedLabelingWidget::editRule()
174 editRule( viewRules->selectionModel()->currentIndex() );
177void QgsRuleBasedLabelingWidget::editRule(
const QModelIndex &index )
179 if ( !index.isValid() )
198 mModel->
updateRule( index.parent(), index.row() );
203void QgsRuleBasedLabelingWidget::removeRule()
205 const QItemSelection sel = viewRules->selectionModel()->selection();
206 const auto constSel = sel;
207 for (
const QItemSelectionRange &range : constSel )
209 if ( range.isValid() )
210 mModel->
removeRows( range.top(), range.bottom() - range.top() + 1, range.parent() );
213 viewRules->selectionModel()->clear();
216void QgsRuleBasedLabelingWidget::copy()
218 const QModelIndexList indexlist = viewRules->selectionModel()->selectedRows();
220 if ( indexlist.isEmpty() )
223 QMimeData *mime = mModel->
mimeData( indexlist );
224 QApplication::clipboard()->setMimeData( mime );
227void QgsRuleBasedLabelingWidget::paste()
229 const QMimeData *mime = QApplication::clipboard()->mimeData();
230 QModelIndexList indexlist = viewRules->selectionModel()->selectedRows();
232 if ( indexlist.isEmpty() )
235 index = indexlist.first();
236 mModel->
dropMimeData( mime, Qt::CopyAction, index.row(), index.column(), index.parent() );
241 QItemSelectionModel *sel = viewRules->selectionModel();
242 const QModelIndex idx = sel->currentIndex();
243 if ( !idx.isValid() )
255 setWindowModality( Qt::WindowModal );
258 QVBoxLayout *layout =
new QVBoxLayout(
this );
260 scrollArea->setFrameShape( QFrame::NoFrame );
261 layout->addWidget( scrollArea );
263 buttonBox =
new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok );
266 scrollArea->setWidget( mPropsWidget );
267 layout->addWidget( buttonBox );
268 this->setWindowTitle(
"Edit Rule" );
272 connect( buttonBox, &QDialogButtonBox::rejected,
this, &QDialog::reject );
273 connect( buttonBox, &QDialogButtonBox::helpRequested,
this, &QgsLabelingRulePropsDialog::showHelp );
288 mPropsWidget->
apply();
292void QgsLabelingRulePropsDialog::showHelp()
294 QgsHelp::openHelp( QStringLiteral(
"working_with_vector/vector_properties.html#rule-based-labeling" ) );
300 : QAbstractItemModel( parent )
301 , mRootRule( rootRule )
307 if ( !
index.isValid() )
308 return Qt::ItemIsDropEnabled;
311 const Qt::ItemFlag drop = (
index.column() == 0 ? Qt::ItemIsDropEnabled : Qt::NoItemFlags );
313 const Qt::ItemFlag checkable = (
index.column() == 0 ? Qt::ItemIsUserCheckable : Qt::NoItemFlags );
315 return Qt::ItemIsEnabled | Qt::ItemIsSelectable |
316 Qt::ItemIsEditable | checkable |
317 Qt::ItemIsDragEnabled | drop;
322 if ( !
index.isValid() )
327 if ( role == Qt::DisplayRole || role == Qt::ToolTipRole )
329 switch (
index.column() )
352 else if ( role == Qt::DecorationRole &&
index.column() == 0 && rule->
settings() )
357 else if ( role == Qt::TextAlignmentRole )
359 return (
index.column() == 2 ||
index.column() == 3 ) ?
static_cast<Qt::Alignment::Int
>( Qt::AlignRight ) :
static_cast<Qt::Alignment::Int
>( Qt::AlignLeft );
361 else if ( role == Qt::FontRole &&
index.column() == 1 )
366 italicFont.setItalic(
true );
371 else if ( role == Qt::EditRole )
373 switch (
index.column() )
389 else if ( role == Qt::CheckStateRole )
391 if (
index.column() != 0 )
393 return rule->
active() ? Qt::Checked : Qt::Unchecked;
401 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < 5 )
404 lst << tr(
"Label" ) << tr(
"Rule" ) << tr(
"Min. Scale" ) << tr(
"Max. Scale" ) << tr(
"Text" );
413 if (
parent.column() > 0 )
418 return parentRule->
children().count();
428 if ( hasIndex( row, column,
parent ) )
432 return createIndex( row, column, childRule );
434 return QModelIndex();
439 if ( !
index.isValid() )
440 return QModelIndex();
446 return QModelIndex();
449 const int row = parentRule->
parent()->
children().indexOf( parentRule );
451 return createIndex( row, 0, parentRule );
456 if ( !
index.isValid() )
461 if ( role == Qt::CheckStateRole )
463 rule->
setActive( value.toInt() == Qt::Checked );
468 if ( role != Qt::EditRole )
471 switch (
index.column() )
500 return Qt::MoveAction;
506 types << QStringLiteral(
"application/vnd.text.list" );
514 if ( ruleElem.hasAttribute( QStringLiteral(
"label" ) ) )
515 ruleElem.setAttribute( QStringLiteral(
"description" ), ruleElem.attribute( QStringLiteral(
"label" ) ) );
518 QDomElement childRuleElem = ruleElem.firstChildElement( QStringLiteral(
"rule" ) );
519 while ( !childRuleElem.isNull() )
522 childRuleElem = childRuleElem.nextSiblingElement( QStringLiteral(
"rule" ) );
528 QMimeData *
mimeData =
new QMimeData();
529 QByteArray encodedData;
531 QDataStream stream( &encodedData, QIODevice::WriteOnly );
533 const auto constIndexes = indexes;
534 for (
const QModelIndex &
index : constIndexes )
537 if ( !
index.isValid() ||
index.column() != 0 )
545 QDomElement rootElem = doc.createElement( QStringLiteral(
"rule_mime" ) );
546 rootElem.setAttribute( QStringLiteral(
"type" ), QStringLiteral(
"labeling" ) );
548 rootElem.appendChild( rulesElem );
549 doc.appendChild( rootElem );
553 stream << doc.toString( -1 );
556 mimeData->setData( QStringLiteral(
"application/vnd.text.list" ), encodedData );
564 if ( action == Qt::IgnoreAction )
567 if ( !
data->hasFormat( QStringLiteral(
"application/vnd.text.list" ) ) )
570 if (
parent.column() > 0 )
573 QByteArray encodedData =
data->data( QStringLiteral(
"application/vnd.text.list" ) );
574 QDataStream stream( &encodedData, QIODevice::ReadOnly );
583 while ( !stream.atEnd() )
589 if ( !doc.setContent( text ) )
591 const QDomElement rootElem = doc.documentElement();
592 if ( rootElem.tagName() != QLatin1String(
"rule_mime" ) )
594 QDomElement ruleElem = rootElem.firstChildElement( QStringLiteral(
"rule" ) );
595 if ( rootElem.attribute( QStringLiteral(
"type" ) ) == QLatin1String(
"renderer" ) )
610 if ( row < 0 || row >= parentRule->
children().count() )
613 beginRemoveRows(
parent, row, row + count - 1 );
615 for (
int i = 0; i < count; i++ )
617 if ( row < parentRule->children().count() )
623 QgsDebugError( QStringLiteral(
"trying to remove invalid index - this should not happen!" ) );
634 if (
index.isValid() )
641 beginInsertRows(
parent, before, before );
661 , mSettings( nullptr )
662 , mMapCanvas( mapCanvas )
666 QButtonGroup *radioGroup =
new QButtonGroup(
this );
667 radioGroup->addButton( mFilterRadio );
668 radioGroup->addButton( mElseRadio );
670 mElseRadio->setChecked( mRule->
isElse() );
671 mFilterRadio->setChecked( !mRule->
isElse() );
675 editDescription->setToolTip( mRule->
description() );
679 groupScale->setChecked(
true );
684 mScaleRangeWidget->setMapCanvas( mMapCanvas );
688 groupSettings->setChecked(
true );
693 groupSettings->setChecked(
false );
697 mLabelingGui =
new QgsLabelingGui(
nullptr, mMapCanvas, *mSettings,
this );
698 mLabelingGui->layout()->setContentsMargins( 0, 0, 0, 0 );
699 QVBoxLayout *l =
new QVBoxLayout;
700 l->addWidget( mLabelingGui );
701 groupSettings->setLayout( l );
703 mLabelingGui->setLabelMode( QgsLabelingGui::Labels );
704 mLabelingGui->setLayer( mLayer );
714 connect( mFilterRadio, &QRadioButton::toggled,
this, [ = ](
bool toggled ) { filterFrame->setEnabled( toggled ) ; } );
715 connect( mElseRadio, &QRadioButton::toggled,
this, [ = ](
bool toggled ) {
if ( toggled ) editFilter->setText( QStringLiteral(
"ELSE" ) );} );
726 mLabelingGui->setDockMode(
dockMode );
731 if ( !mFilterRadio->isChecked() )
737 QMessageBox::critical(
this, tr(
"Test Filter" ), tr(
"Filter expression parsing error:\n" ) + filter.
parserErrorString() );
743 if ( !filter.
prepare( &context ) )
745 QMessageBox::critical(
this, tr(
"Test Filter" ), filter.
evalErrorString() );
749 QApplication::setOverrideCursor( Qt::WaitCursor );
759 const QVariant value = filter.
evaluate( &context );
760 if ( value.toInt() != 0 )
766 QApplication::restoreOverrideCursor();
768 QMessageBox::information(
this, tr(
"Test Filter" ), tr(
"Filter returned %n feature(s)",
"number of filtered features", count ) );
784 const QString filter = mElseRadio->isChecked() ? QStringLiteral(
"ELSE" ) : editFilter->text().trimmed();
787 mRule->
setMinimumScale( groupScale->isChecked() ? mScaleRangeWidget->minimumScale() : 0 );
788 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.
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)
Fetch next feature and stores in f, returns true on success.
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.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
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