16#include "moc_qgsrulebasedlabelingwidget.cpp"
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() )
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 | Qt::ItemIsEditable | checkable | Qt::ItemIsDragEnabled | drop;
320 if ( !
index.isValid() )
325 if ( role == Qt::DisplayRole || role == Qt::ToolTipRole )
327 switch (
index.column() )
350 else if ( role == Qt::DecorationRole &&
index.column() == 0 && rule->
settings() )
355 else if ( role == Qt::TextAlignmentRole )
357 return (
index.column() == 2 ||
index.column() == 3 ) ?
static_cast<Qt::Alignment::Int
>( Qt::AlignRight ) :
static_cast<Qt::Alignment::Int
>( Qt::AlignLeft );
359 else if ( role == Qt::FontRole &&
index.column() == 1 )
364 italicFont.setItalic(
true );
369 else if ( role == Qt::EditRole )
371 switch (
index.column() )
387 else if ( role == Qt::CheckStateRole )
389 if (
index.column() != 0 )
391 return rule->
active() ? Qt::Checked : Qt::Unchecked;
399 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < 5 )
402 lst << tr(
"Label" ) << tr(
"Rule" ) << tr(
"Min. Scale" ) << tr(
"Max. Scale" ) << tr(
"Text" );
411 if (
parent.column() > 0 )
416 return parentRule->
children().count();
426 if ( hasIndex( row, column,
parent ) )
430 return createIndex( row, column, childRule );
432 return QModelIndex();
437 if ( !
index.isValid() )
438 return QModelIndex();
444 return QModelIndex();
447 const int row = parentRule->
parent()->
children().indexOf( parentRule );
449 return createIndex( row, 0, parentRule );
454 if ( !
index.isValid() )
459 if ( role == Qt::CheckStateRole )
461 rule->
setActive( value.toInt() == Qt::Checked );
466 if ( role != Qt::EditRole )
469 switch (
index.column() )
498 return Qt::MoveAction;
504 types << QStringLiteral(
"application/vnd.text.list" );
512 if ( ruleElem.hasAttribute( QStringLiteral(
"label" ) ) )
513 ruleElem.setAttribute( QStringLiteral(
"description" ), ruleElem.attribute( QStringLiteral(
"label" ) ) );
516 QDomElement childRuleElem = ruleElem.firstChildElement( QStringLiteral(
"rule" ) );
517 while ( !childRuleElem.isNull() )
520 childRuleElem = childRuleElem.nextSiblingElement( QStringLiteral(
"rule" ) );
526 QMimeData *
mimeData =
new QMimeData();
527 QByteArray encodedData;
529 QDataStream stream( &encodedData, QIODevice::WriteOnly );
531 const auto constIndexes = indexes;
532 for (
const QModelIndex &
index : constIndexes )
535 if ( !
index.isValid() ||
index.column() != 0 )
543 QDomElement rootElem = doc.createElement( QStringLiteral(
"rule_mime" ) );
544 rootElem.setAttribute( QStringLiteral(
"type" ), QStringLiteral(
"labeling" ) );
546 rootElem.appendChild( rulesElem );
547 doc.appendChild( rootElem );
551 stream << doc.toString( -1 );
554 mimeData->setData( QStringLiteral(
"application/vnd.text.list" ), encodedData );
562 if ( action == Qt::IgnoreAction )
565 if ( !
data->hasFormat( QStringLiteral(
"application/vnd.text.list" ) ) )
568 if (
parent.column() > 0 )
571 QByteArray encodedData =
data->data( QStringLiteral(
"application/vnd.text.list" ) );
572 QDataStream stream( &encodedData, QIODevice::ReadOnly );
581 while ( !stream.atEnd() )
587 if ( !doc.setContent( text ) )
589 const QDomElement rootElem = doc.documentElement();
590 if ( rootElem.tagName() != QLatin1String(
"rule_mime" ) )
592 QDomElement ruleElem = rootElem.firstChildElement( QStringLiteral(
"rule" ) );
593 if ( rootElem.attribute( QStringLiteral(
"type" ) ) == QLatin1String(
"renderer" ) )
608 if ( row < 0 || row >= parentRule->
children().count() )
611 beginRemoveRows(
parent, row, row + count - 1 );
613 for (
int i = 0; i < count; i++ )
615 if ( row < parentRule->children().count() )
621 QgsDebugError( QStringLiteral(
"trying to remove invalid index - this should not happen!" ) );
632 if (
index.isValid() )
639 beginInsertRows(
parent, before, before );
658 , mSettings( nullptr )
659 , mMapCanvas( mapCanvas )
663 QButtonGroup *radioGroup =
new QButtonGroup(
this );
664 radioGroup->addButton( mFilterRadio );
665 radioGroup->addButton( mElseRadio );
667 mElseRadio->setChecked( mRule->
isElse() );
668 mFilterRadio->setChecked( !mRule->
isElse() );
672 editDescription->setToolTip( mRule->
description() );
676 groupScale->setChecked(
true );
680 mScaleRangeWidget->setMapCanvas( mMapCanvas );
684 groupSettings->setChecked(
true );
689 groupSettings->setChecked(
false );
693 mLabelingGui =
new QgsLabelingGui( mMapCanvas, *mSettings,
this );
694 mLabelingGui->layout()->setContentsMargins( 0, 0, 0, 0 );
695 QVBoxLayout *l =
new QVBoxLayout;
696 l->addWidget( mLabelingGui );
697 groupSettings->setLayout( l );
699 mLabelingGui->setLabelMode( QgsLabelingGui::Labels );
700 mLabelingGui->setLayer( mLayer );
710 connect( mFilterRadio, &QRadioButton::toggled,
this, [=](
bool toggled ) { filterFrame->setEnabled( toggled ); } );
711 connect( mElseRadio, &QRadioButton::toggled,
this, [=](
bool toggled ) {
if ( toggled ) editFilter->setText( QStringLiteral(
"ELSE" ) ); } );
722 mLabelingGui->setDockMode(
dockMode );
727 if ( !mFilterRadio->isChecked() )
733 QMessageBox::critical(
this, tr(
"Test Filter" ), tr(
"Filter expression parsing error:\n" ) + filter.
parserErrorString() );
739 if ( !filter.
prepare( &context ) )
741 QMessageBox::critical(
this, tr(
"Test Filter" ), filter.
evalErrorString() );
745 QApplication::setOverrideCursor( Qt::WaitCursor );
755 const QVariant value = filter.
evaluate( &context );
756 if ( value.toInt() != 0 )
762 QApplication::restoreOverrideCursor();
764 QMessageBox::information(
this, tr(
"Test Filter" ), tr(
"Filter returned %n feature(s)",
"number of filtered features", count ) );
780 const QString filter = mElseRadio->isChecked() ? QStringLiteral(
"ELSE" ) : editFilter->text().trimmed();
783 mRule->
setMinimumScale( groupScale->isChecked() ? mScaleRangeWidget->minimumScale() : 0 );
784 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