26#include <QDialogButtonBox>
31#include "moc_qgslabelingengineruleswidget.cpp"
33using namespace Qt::StringLiterals;
40 : QAbstractItemModel(
parent )
47 return Qt::ItemFlags();
49 Qt::ItemFlags res = Qt::ItemIsSelectable;
52 res |= Qt::ItemIsEnabled | Qt::ItemIsEditable;
55 if (
index.column() == 0 )
57 res |= Qt::ItemIsUserCheckable;
75 return static_cast<int>( mRules.size() );
101 return tr(
"This rule is not available for use on this system." );
106 case Qt::CheckStateRole:
108 if (
index.column() != 0 )
110 return rule->
active() ? Qt::Checked : Qt::Unchecked;
122 if ( hasIndex( row, column,
parent ) )
124 return createIndex( row, column, row );
127 return QModelIndex();
132 if ( row < 0 || row >=
static_cast<int>( mRules.size() ) )
135 beginRemoveRows(
parent, row, row + count - 1 );
136 for (
int i = 0; i < count; i++ )
138 if ( row <
static_cast<int>( mRules.size() ) )
140 mRules.erase( mRules.begin() + row );
149 if ( !
index.isValid() )
158 case Qt::CheckStateRole:
160 rule->
setActive( value.toInt() == Qt::Checked );
167 if (
index.column() == 0 )
169 rule->
setName( value.toString() );
189 mRules.emplace_back( rule->clone() );
196 beginInsertRows( QModelIndex(),
static_cast<int>( mRules.size() ),
static_cast<int>( mRules.size() ) );
197 mRules.emplace_back( std::move( rule ) );
203 if ( !
index.isValid() )
206 if (
index.row() < 0 ||
index.row() >=
static_cast<int>( mRules.size() ) )
209 return mRules[
index.row()].get();
214 if ( !
index.isValid() )
217 if (
index.row() < 0 ||
index.row() >=
static_cast<int>( mRules.size() ) )
220 mRules[
index.row()] = std::move( rule );
226 QList<QgsAbstractLabelingEngineRule *> res;
227 res.reserve(
static_cast<int>( mRules.size() ) );
228 for (
auto &it : mRules )
230 res.append( it->clone() );
248 viewRules->setModel( mModel );
249 viewRules->setHeaderHidden(
true );
251 mAddRuleMenu =
new QMenu(
this );
252 connect( mAddRuleMenu, &QMenu::aboutToShow,
this, &QgsLabelingEngineRulesWidget::createTypesMenu );
254 btnAddRule->setMenu( mAddRuleMenu );
255 btnAddRule->setPopupMode( QToolButton::InstantPopup );
257 connect( btnEditRule, &QToolButton::clicked,
this, &QgsLabelingEngineRulesWidget::editSelectedRule );
258 connect( btnRemoveRule, &QToolButton::clicked,
this, &QgsLabelingEngineRulesWidget::removeRules );
260 connect( viewRules, &QAbstractItemView::doubleClicked,
this, &QgsLabelingEngineRulesWidget::editRule );
265 mModel->setRules(
rules );
270 return mModel->rules();
273void QgsLabelingEngineRulesWidget::createTypesMenu()
275 mAddRuleMenu->clear();
278 QList<QAction *> actions;
279 for (
const QString &
id : ruleIds )
285 connect( action, &QAction::triggered,
this, [
this,
id] { createRule(
id ); } );
288 std::sort( actions.begin(), actions.end(), [](
const QAction *a,
const QAction *b ) ->
bool { return QString::localeAwareCompare( a->text(), b->text() ) < 0; } );
289 mAddRuleMenu->addActions( actions );
292void QgsLabelingEngineRulesWidget::createRule(
const QString &
id )
297 rule->setName( rule->displayType() );
298 mModel->addRule( rule );
299 const QModelIndex newRuleIndex = mModel->index( mModel->rowCount() - 1, 0, QModelIndex() );
300 viewRules->selectionModel()->setCurrentIndex( newRuleIndex, QItemSelectionModel::SelectionFlag::ClearAndSelect );
301 editRule( newRuleIndex );
305void QgsLabelingEngineRulesWidget::editSelectedRule()
307 const QItemSelection selection = viewRules->selectionModel()->selection();
308 for (
const QItemSelectionRange &range : selection )
310 if ( range.isValid() )
312 const QModelIndex index = range.indexes().value( 0 );
319void QgsLabelingEngineRulesWidget::editRule(
const QModelIndex &index )
321 const QgsAbstractLabelingEngineRule *rule = mModel->ruleAtIndex( index );
326 QgsLabelingEngineRuleWidget *widget =
nullptr;
327 if ( rule->
id() ==
"minimumDistanceLabelToFeature" )
329 widget =
new QgsLabelingEngineRuleMinimumDistanceLabelToFeatureWidget();
331 else if ( rule->
id() ==
"minimumDistanceLabelToLabel" )
333 widget =
new QgsLabelingEngineRuleMinimumDistanceLabelToLabelWidget();
335 else if ( rule->
id() ==
"maximumDistanceLabelToFeature" )
337 widget =
new QgsLabelingEngineRuleMaximumDistanceLabelToFeatureWidget();
339 else if ( rule->
id() ==
"avoidLabelOverlapWithFeature" )
341 widget =
new QgsLabelingEngineRuleAvoidLabelOverlapWithFeatureWidget();
353 std::unique_ptr<QgsAbstractLabelingEngineRule> updatedRule( widget->
rule() );
354 mModel->changeRule( index, updatedRule );
361 QgsLabelingEngineRuleDialog dialog( widget,
this );
362 dialog.setRule( rule );
365 std::unique_ptr<QgsAbstractLabelingEngineRule> updatedRule( dialog.rule() );
366 mModel->changeRule( index, updatedRule );
372void QgsLabelingEngineRulesWidget::removeRules()
374 const QItemSelection selection = viewRules->selectionModel()->selection();
376 for (
const QItemSelectionRange &range : selection )
378 if ( range.isValid() )
380 for (
int row = range.top(); row <= range.bottom(); ++row )
382 if ( !rows.contains( row ) )
388 std::sort( rows.begin(), rows.end() );
389 std::reverse( rows.begin(), rows.end() );
390 for (
int row : std::as_const( rows ) )
392 mModel->removeRow( row );
402 : QDialog( parent, flags )
404 setWindowTitle( tr(
"Configure Rules" ) );
405 setObjectName( u
"QgsLabelingEngineRulesDialog"_s );
409 QVBoxLayout *layout =
new QVBoxLayout(
this );
410 layout->addWidget( mWidget );
412 mButtonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help, Qt::Horizontal,
this );
413 layout->addWidget( mButtonBox );
418 connect( mButtonBox->button( QDialogButtonBox::Ok ), &QAbstractButton::clicked,
this, &QDialog::accept );
419 connect( mButtonBox->button( QDialogButtonBox::Cancel ), &QAbstractButton::clicked,
this, &QDialog::reject );
420 connect( mButtonBox, &QDialogButtonBox::helpRequested,
this, [] {
QgsHelp::openHelp( u
"working_with_vector/vector_properties.html#labeling-rules"_s ); } );
425 mWidget->setRules(
rules );
430 return mWidget->rules();
Abstract base class for labeling engine rules.
void setActive(bool active)
Sets whether the rule is active.
virtual bool isAvailable() const
Returns true if the rule is available for use within the current QGIS environment.
bool active() const
Returns true if the rule is active.
QString name() const
Returns the name for this instance of the rule.
virtual QString displayType() const =0
Returns a user-friendly, translated string representing the rule type.
virtual QString description() const
Returns a user-friendly description of the rule.
void setName(const QString &name)
Sets the name for this instance of the rule.
virtual QString id() const =0
Returns a string uniquely identifying the rule subclass.
static QgsLabelingEngineRuleRegistry * labelingEngineRuleRegistry()
Gets the registry of available labeling engine rules.
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.
QStringList ruleIds() const
Returns a list of the rule IDs for rules present in the registry.
QList< QgsAbstractLabelingEngineRule * > rules() const
Returns the rules shown in the dialog.
void setRules(const QList< QgsAbstractLabelingEngineRule * > &rules)
Sets the rules to show in the dialog.
QgsLabelingEngineRulesDialog(QWidget *parent=nullptr, Qt::WindowFlags flags=QgsGuiUtils::ModalDialogFlags)
Constructor for QgsLabelingEngineRulesDialog.
A model for configuration of a list of labeling engine rules.
QModelIndex index(int row, int column, const QModelIndex &parent) const override
int columnCount(const QModelIndex &parent=QModelIndex()) const override
void setRules(const QList< QgsAbstractLabelingEngineRule * > &rules)
Sets the rules to include in the model.
QModelIndex parent(const QModelIndex &child) const override
QgsLabelingEngineRulesModel(QObject *parent=nullptr)
Constructor for QgsLabelingEngineRulesModel.
QList< QgsAbstractLabelingEngineRule * > rules() const
Returns the rules shown in the widget.
QgsAbstractLabelingEngineRule * ruleAtIndex(const QModelIndex &index) const
Returns the rule at the specified model index.
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
void addRule(std::unique_ptr< QgsAbstractLabelingEngineRule > &rule)
Adds a rule to the model.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Qt::ItemFlags flags(const QModelIndex &index) const override
~QgsLabelingEngineRulesModel() override
void changeRule(const QModelIndex &index, std::unique_ptr< QgsAbstractLabelingEngineRule > &rule)
Swaps the rule at the specified index for a new rule.