26#include <QDialogButtonBox>
30#include "moc_qgslabelingengineruleswidget.cpp"
37 : QAbstractItemModel(
parent )
45 return Qt::ItemFlags();
47 Qt::ItemFlags res = Qt::ItemIsSelectable;
50 res |= Qt::ItemIsEnabled | Qt::ItemIsEditable;
53 if (
index.column() == 0 )
55 res |= Qt::ItemIsUserCheckable;
73 return static_cast<int>( mRules.size() );
99 return tr(
"This rule is not available for use on this system." );
104 case Qt::CheckStateRole:
106 if (
index.column() != 0 )
108 return rule->
active() ? Qt::Checked : Qt::Unchecked;
120 if ( hasIndex( row, column,
parent ) )
122 return createIndex( row, column, row );
125 return QModelIndex();
130 if ( row < 0 || row >=
static_cast<int>( mRules.size() ) )
133 beginRemoveRows(
parent, row, row + count - 1 );
134 for (
int i = 0; i < count; i++ )
136 if ( row <
static_cast<int>( mRules.size() ) )
138 mRules.erase( mRules.begin() + row );
147 if ( !
index.isValid() )
156 case Qt::CheckStateRole:
158 rule->
setActive( value.toInt() == Qt::Checked );
165 if (
index.column() == 0 )
167 rule->
setName( value.toString() );
187 mRules.emplace_back( rule->clone() );
194 beginInsertRows( QModelIndex(),
static_cast<int>( mRules.size() ),
static_cast<int>( mRules.size() ) );
195 mRules.emplace_back( std::move( rule ) );
201 if ( !
index.isValid() )
204 if (
index.row() < 0 ||
index.row() >=
static_cast<int>( mRules.size() ) )
207 return mRules[
index.row()].get();
212 if ( !
index.isValid() )
215 if (
index.row() < 0 ||
index.row() >=
static_cast<int>( mRules.size() ) )
218 mRules[
index.row()] = std::move( rule );
224 QList<QgsAbstractLabelingEngineRule *> res;
225 res.reserve(
static_cast<int>( mRules.size() ) );
226 for (
auto &it : mRules )
228 res.append( it->clone() );
246 viewRules->setModel( mModel );
247 viewRules->setHeaderHidden(
true );
249 mAddRuleMenu =
new QMenu(
this );
250 connect( mAddRuleMenu, &QMenu::aboutToShow,
this, &QgsLabelingEngineRulesWidget::createTypesMenu );
252 btnAddRule->setMenu( mAddRuleMenu );
253 btnAddRule->setPopupMode( QToolButton::InstantPopup );
255 connect( btnEditRule, &QToolButton::clicked,
this, &QgsLabelingEngineRulesWidget::editSelectedRule );
256 connect( btnRemoveRule, &QToolButton::clicked,
this, &QgsLabelingEngineRulesWidget::removeRules );
258 connect( viewRules, &QAbstractItemView::doubleClicked,
this, &QgsLabelingEngineRulesWidget::editRule );
263 mModel->setRules(
rules );
268 return mModel->rules();
271void QgsLabelingEngineRulesWidget::createTypesMenu()
273 mAddRuleMenu->clear();
276 QList<QAction *> actions;
277 for (
const QString &
id : ruleIds )
283 connect( action, &QAction::triggered,
this, [
this,
id] {
288 std::sort( actions.begin(), actions.end(), [](
const QAction *a,
const QAction *b ) ->
bool {
289 return QString::localeAwareCompare( a->text(), b->text() ) < 0;
291 mAddRuleMenu->addActions( actions );
294void QgsLabelingEngineRulesWidget::createRule(
const QString &
id )
299 rule->setName( rule->displayType() );
300 mModel->addRule( rule );
301 const QModelIndex newRuleIndex = mModel->index( mModel->rowCount() - 1, 0, QModelIndex() );
302 viewRules->selectionModel()->setCurrentIndex( newRuleIndex, QItemSelectionModel::SelectionFlag::ClearAndSelect );
303 editRule( newRuleIndex );
307void QgsLabelingEngineRulesWidget::editSelectedRule()
309 const QItemSelection selection = viewRules->selectionModel()->selection();
310 for (
const QItemSelectionRange &range : selection )
312 if ( range.isValid() )
314 const QModelIndex index = range.indexes().value( 0 );
321void QgsLabelingEngineRulesWidget::editRule(
const QModelIndex &index )
323 const QgsAbstractLabelingEngineRule *rule = mModel->ruleAtIndex( index );
328 QgsLabelingEngineRuleWidget *widget =
nullptr;
329 if ( rule->
id() ==
"minimumDistanceLabelToFeature" )
331 widget =
new QgsLabelingEngineRuleMinimumDistanceLabelToFeatureWidget();
333 else if ( rule->
id() ==
"minimumDistanceLabelToLabel" )
335 widget =
new QgsLabelingEngineRuleMinimumDistanceLabelToLabelWidget();
337 else if ( rule->
id() ==
"maximumDistanceLabelToFeature" )
339 widget =
new QgsLabelingEngineRuleMaximumDistanceLabelToFeatureWidget();
341 else if ( rule->
id() ==
"avoidLabelOverlapWithFeature" )
343 widget =
new QgsLabelingEngineRuleAvoidLabelOverlapWithFeatureWidget();
355 std::unique_ptr<QgsAbstractLabelingEngineRule> updatedRule( widget->
rule() );
356 mModel->changeRule( index, updatedRule );
363 QgsLabelingEngineRuleDialog dialog( widget,
this );
364 dialog.setRule( rule );
367 std::unique_ptr<QgsAbstractLabelingEngineRule> updatedRule( dialog.rule() );
368 mModel->changeRule( index, updatedRule );
374void QgsLabelingEngineRulesWidget::removeRules()
376 const QItemSelection selection = viewRules->selectionModel()->selection();
378 for (
const QItemSelectionRange &range : selection )
380 if ( range.isValid() )
382 for (
int row = range.top(); row <= range.bottom(); ++row )
384 if ( !rows.contains( row ) )
390 std::sort( rows.begin(), rows.end() );
391 std::reverse( rows.begin(), rows.end() );
392 for (
int row : std::as_const( rows ) )
394 mModel->removeRow( row );
404 : QDialog( parent, flags )
406 setWindowTitle( tr(
"Configure Rules" ) );
407 setObjectName( QStringLiteral(
"QgsLabelingEngineRulesDialog" ) );
411 QVBoxLayout *layout =
new QVBoxLayout(
this );
412 layout->addWidget( mWidget );
414 mButtonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help, Qt::Horizontal,
this );
415 layout->addWidget( mButtonBox );
420 connect( mButtonBox->button( QDialogButtonBox::Ok ), &QAbstractButton::clicked,
this, &QDialog::accept );
421 connect( mButtonBox->button( QDialogButtonBox::Cancel ), &QAbstractButton::clicked,
this, &QDialog::reject );
422 connect( mButtonBox, &QDialogButtonBox::helpRequested,
this, [] {
423 QgsHelp::openHelp( QStringLiteral(
"working_with_vector/vector_properties.html#labeling-rules" ) );
429 mWidget->setRules(
rules );
434 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.