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 = 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() );
 
  134 void QgsRuleBasedLabelingWidget::addRule()
 
  142     QModelIndex currentIndex = viewRules->selectionModel()->currentIndex();
 
  143     mModel->
insertRule( currentIndex.parent(), currentIndex.row() + 1, newrule );
 
  144     QModelIndex newindex = mModel->
index( currentIndex.row() + 1, 0, currentIndex.parent() );
 
  145     viewRules->selectionModel()->setCurrentIndex( newindex, QItemSelectionModel::ClearAndSelect );
 
  151     mModel->
insertRule( QModelIndex(), rows, newrule );
 
  152     QModelIndex newindex = mModel->
index( rows, 0 );
 
  153     viewRules->selectionModel()->setCurrentIndex( newindex, QItemSelectionModel::ClearAndSelect );
 
  158 void QgsRuleBasedLabelingWidget::ruleWidgetPanelAccepted( 
QgsPanelWidget *panel )
 
  163   QModelIndex index = viewRules->selectionModel()->currentIndex();
 
  164   mModel->
updateRule( index.parent(), index.row() );
 
  167 void QgsRuleBasedLabelingWidget::liveUpdateRuleFromPanel()
 
  169   ruleWidgetPanelAccepted( qobject_cast<QgsPanelWidget *>( sender() ) );
 
  173 void QgsRuleBasedLabelingWidget::editRule()
 
  175   editRule( viewRules->selectionModel()->currentIndex() );
 
  178 void QgsRuleBasedLabelingWidget::editRule( 
const QModelIndex &index )
 
  180   if ( !index.isValid() )
 
  192 void QgsRuleBasedLabelingWidget::removeRule()
 
  194   QItemSelection sel = viewRules->selectionModel()->selection();
 
  195   const auto constSel = sel;
 
  196   for ( 
const QItemSelectionRange &range : constSel )
 
  198     if ( range.isValid() )
 
  199       mModel->
removeRows( range.top(), range.bottom() - range.top() + 1, range.parent() );
 
  202   viewRules->selectionModel()->clear();
 
  205 void QgsRuleBasedLabelingWidget::copy()
 
  207   QModelIndexList indexlist = viewRules->selectionModel()->selectedRows();
 
  209   if ( indexlist.isEmpty() )
 
  212   QMimeData *mime = mModel->
mimeData( indexlist );
 
  213   QApplication::clipboard()->setMimeData( mime );
 
  216 void QgsRuleBasedLabelingWidget::paste()
 
  218   const QMimeData *mime = QApplication::clipboard()->mimeData();
 
  219   QModelIndexList indexlist = viewRules->selectionModel()->selectedRows();
 
  221   if ( indexlist.isEmpty() )
 
  224     index = indexlist.first();
 
  225   mModel->
dropMimeData( mime, Qt::CopyAction, index.row(), index.column(), index.parent() );
 
  230   QItemSelectionModel *sel = viewRules->selectionModel();
 
  231   QModelIndex idx = sel->currentIndex();
 
  232   if ( !idx.isValid() )
 
  240   : QAbstractItemModel( parent )
 
  241   , mRootRule( rootRule )
 
  247   if ( !
index.isValid() )
 
  248     return Qt::ItemIsDropEnabled;
 
  251   Qt::ItemFlag drop = ( 
index.column() == 0 ? Qt::ItemIsDropEnabled : Qt::NoItemFlags );
 
  253   Qt::ItemFlag checkable = ( 
index.column() == 0 ? Qt::ItemIsUserCheckable : Qt::NoItemFlags );
 
  255   return Qt::ItemIsEnabled | Qt::ItemIsSelectable |
 
  256          Qt::ItemIsEditable | checkable |
 
  257          Qt::ItemIsDragEnabled | drop;
 
  262   if ( !
index.isValid() )
 
  267   if ( role == Qt::DisplayRole || role == Qt::ToolTipRole )
 
  269     switch ( 
index.column() )
 
  292   else if ( role == Qt::DecorationRole && 
index.column() == 0 && rule->
settings() )
 
  297   else if ( role == Qt::TextAlignmentRole )
 
  299     return ( 
index.column() == 2 || 
index.column() == 3 ) ? Qt::AlignRight : Qt::AlignLeft;
 
  301   else if ( role == Qt::FontRole && 
index.column() == 1 )
 
  306       italicFont.setItalic( 
true );
 
  311   else if ( role == Qt::EditRole )
 
  313     switch ( 
index.column() )
 
  329   else if ( role == Qt::CheckStateRole )
 
  331     if ( 
index.column() != 0 )
 
  333     return rule->
active() ? Qt::Checked : Qt::Unchecked;
 
  341   if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < 5 )
 
  344     lst << tr( 
"Label" ) << tr( 
"Rule" ) << tr( 
"Min. Scale" ) << tr( 
"Max. Scale" ) << tr( 
"Text" ); 
 
  353   if ( 
parent.column() > 0 )
 
  358   return parentRule->
children().count();
 
  368   if ( hasIndex( row, column, 
parent ) )
 
  372     return createIndex( row, column, childRule );
 
  374   return QModelIndex();
 
  379   if ( !
index.isValid() )
 
  380     return QModelIndex();
 
  386     return QModelIndex();
 
  391   return createIndex( row, 0, parentRule );
 
  396   if ( !
index.isValid() )
 
  401   if ( role == Qt::CheckStateRole )
 
  403     rule->
setActive( value.toInt() == Qt::Checked );
 
  408   if ( role != Qt::EditRole )
 
  411   switch ( 
index.column() )
 
  440   return Qt::MoveAction; 
 
  446   types << QStringLiteral( 
"application/vnd.text.list" );
 
  454   if ( ruleElem.hasAttribute( QStringLiteral( 
"label" ) ) )
 
  455     ruleElem.setAttribute( QStringLiteral( 
"description" ), ruleElem.attribute( QStringLiteral( 
"label" ) ) );
 
  458   QDomElement childRuleElem = ruleElem.firstChildElement( QStringLiteral( 
"rule" ) );
 
  459   while ( !childRuleElem.isNull() )
 
  462     childRuleElem = childRuleElem.nextSiblingElement( QStringLiteral( 
"rule" ) );
 
  468   QMimeData *
mimeData = 
new QMimeData();
 
  469   QByteArray encodedData;
 
  471   QDataStream stream( &encodedData, QIODevice::WriteOnly );
 
  473   const auto constIndexes = indexes;
 
  474   for ( 
const QModelIndex &
index : constIndexes )
 
  477     if ( !
index.isValid() || 
index.column() != 0 )
 
  485     QDomElement rootElem = doc.createElement( QStringLiteral( 
"rule_mime" ) );
 
  486     rootElem.setAttribute( QStringLiteral( 
"type" ), QStringLiteral( 
"labeling" ) ); 
 
  488     rootElem.appendChild( rulesElem );
 
  489     doc.appendChild( rootElem );
 
  493     stream << doc.toString( -1 );
 
  496   mimeData->setData( QStringLiteral( 
"application/vnd.text.list" ), encodedData );
 
  504   if ( action == Qt::IgnoreAction )
 
  507   if ( !
data->hasFormat( QStringLiteral( 
"application/vnd.text.list" ) ) )
 
  510   if ( 
parent.column() > 0 )
 
  513   QByteArray encodedData = 
data->data( QStringLiteral( 
"application/vnd.text.list" ) );
 
  514   QDataStream stream( &encodedData, QIODevice::ReadOnly );
 
  523   while ( !stream.atEnd() )
 
  529     if ( !doc.setContent( text ) )
 
  531     QDomElement rootElem = doc.documentElement();
 
  532     if ( rootElem.tagName() != QLatin1String( 
"rule_mime" ) )
 
  534     QDomElement ruleElem = rootElem.firstChildElement( QStringLiteral( 
"rule" ) );
 
  535     if ( rootElem.attribute( QStringLiteral( 
"type" ) ) == QLatin1String( 
"renderer" ) )
 
  550   if ( row < 0 || row >= parentRule->
children().count() )
 
  553   beginRemoveRows( 
parent, row, row + count - 1 );
 
  555   for ( 
int i = 0; i < count; i++ )
 
  557     if ( row < parentRule->children().count() )
 
  563       QgsDebugMsg( QStringLiteral( 
"trying to remove invalid index - this should not happen!" ) );
 
  574   if ( 
index.isValid() )
 
  581   beginInsertRows( 
parent, before, before );
 
  601   , mSettings( nullptr )
 
  602   , mMapCanvas( mapCanvas )
 
  606   QButtonGroup *radioGroup = 
new QButtonGroup( 
this );
 
  607   radioGroup->addButton( mFilterRadio );
 
  608   radioGroup->addButton( mElseRadio );
 
  610   mElseRadio->setChecked( mRule->
isElse() );
 
  611   mFilterRadio->setChecked( !mRule->
isElse() );
 
  615   editDescription->setToolTip( mRule->
description() );
 
  619     groupScale->setChecked( 
true );
 
  624   mScaleRangeWidget->setMapCanvas( mMapCanvas );
 
  628     groupSettings->setChecked( 
true );
 
  633     groupSettings->setChecked( 
false );
 
  637   mLabelingGui = 
new QgsLabelingGui( 
nullptr, mMapCanvas, *mSettings, 
this );
 
  638   mLabelingGui->layout()->setContentsMargins( 0, 0, 0, 0 );
 
  639   QVBoxLayout *l = 
new QVBoxLayout;
 
  640   l->addWidget( mLabelingGui );
 
  641   groupSettings->setLayout( l );
 
  643   mLabelingGui->setLabelMode( QgsLabelingGui::Labels );
 
  644   mLabelingGui->setLayer( mLayer );
 
  646   connect( btnExpressionBuilder, &QAbstractButton::clicked, 
this, &QgsLabelingRulePropsWidget::buildExpression );
 
  647   connect( btnTestFilter, &QAbstractButton::clicked, 
this, &QgsLabelingRulePropsWidget::testFilter );
 
  654   connect( mFilterRadio, &QRadioButton::toggled, 
this, [ = ]( 
bool toggled ) { filterFrame->setEnabled( toggled ) ; } );
 
  655   connect( mElseRadio, &QRadioButton::toggled, 
this, [ = ]( 
bool toggled ) { 
if ( toggled ) editFilter->setText( QStringLiteral( 
"ELSE" ) );} );
 
  666   mLabelingGui->setDockMode( 
dockMode );
 
  669 void QgsLabelingRulePropsWidget::testFilter()
 
  671   if ( !mFilterRadio->isChecked() )
 
  675   if ( filter.hasParserError() )
 
  677     QMessageBox::critical( 
this, tr( 
"Test Filter" ),  tr( 
"Filter expression parsing error:\n" ) + filter.parserErrorString() );
 
  683   if ( !filter.prepare( &context ) )
 
  685     QMessageBox::critical( 
this, tr( 
"Test Filter" ), filter.evalErrorString() );
 
  689   QApplication::setOverrideCursor( Qt::WaitCursor );
 
  697     context.setFeature( f );
 
  699     QVariant value = filter.evaluate( &context );
 
  700     if ( value.toInt() != 0 )
 
  702     if ( filter.hasEvalError() )
 
  706   QApplication::restoreOverrideCursor();
 
  708   QMessageBox::information( 
this, tr( 
"Test Filter" ), tr( 
"Filter returned %n feature(s)", 
"number of filtered features", count ) );
 
  712 void QgsLabelingRulePropsWidget::buildExpression()
 
  719     editFilter->setText( dlg.expressionText() );
 
  724   QString filter = mElseRadio->isChecked() ? QStringLiteral( 
"ELSE" ) : editFilter->text();
 
  727   mRule->
setMinimumScale( groupScale->isChecked() ? mScaleRangeWidget->minimumScale() : 0 );
 
  728   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...
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 unique ID, geometry and a list of field...
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,...