26#include <QDialogButtonBox>
31#include "moc_qgslabelingengineruleswidget.cpp"
33using namespace Qt::StringLiterals;
40 : QAbstractItemModel(
parent )
48 return Qt::ItemFlags();
50 Qt::ItemFlags res = Qt::ItemIsSelectable;
53 res |= Qt::ItemIsEnabled | Qt::ItemIsEditable;
56 if (
index.column() == 0 )
58 res |= Qt::ItemIsUserCheckable;
76 return static_cast<int>( mRules.size() );
102 return tr(
"This rule is not available for use on this system." );
107 case Qt::CheckStateRole:
109 if (
index.column() != 0 )
111 return rule->
active() ? Qt::Checked : Qt::Unchecked;
123 if ( hasIndex( row, column,
parent ) )
125 return createIndex( row, column, row );
128 return QModelIndex();
133 if ( row < 0 || row >=
static_cast<int>( mRules.size() ) )
136 beginRemoveRows(
parent, row, row + count - 1 );
137 for (
int i = 0; i < count; i++ )
139 if ( row <
static_cast<int>( mRules.size() ) )
141 mRules.erase( mRules.begin() + row );
150 if ( !
index.isValid() )
159 case Qt::CheckStateRole:
161 rule->
setActive( value.toInt() == Qt::Checked );
168 if (
index.column() == 0 )
170 rule->
setName( value.toString() );
190 mRules.emplace_back( rule->clone() );
197 beginInsertRows( QModelIndex(),
static_cast<int>( mRules.size() ),
static_cast<int>( mRules.size() ) );
198 mRules.emplace_back( std::move( rule ) );
204 if ( !
index.isValid() )
207 if (
index.row() < 0 ||
index.row() >=
static_cast<int>( mRules.size() ) )
210 return mRules[
index.row()].get();
215 if ( !
index.isValid() )
218 if (
index.row() < 0 ||
index.row() >=
static_cast<int>( mRules.size() ) )
221 mRules[
index.row()] = std::move( rule );
227 QList<QgsAbstractLabelingEngineRule *> res;
228 res.reserve(
static_cast<int>( mRules.size() ) );
229 for (
auto &it : mRules )
231 res.append( it->clone() );
249 viewRules->setModel( mModel );
250 viewRules->setHeaderHidden(
true );
252 mAddRuleMenu =
new QMenu(
this );
253 connect( mAddRuleMenu, &QMenu::aboutToShow,
this, &QgsLabelingEngineRulesWidget::createTypesMenu );
255 btnAddRule->setMenu( mAddRuleMenu );
256 btnAddRule->setPopupMode( QToolButton::InstantPopup );
258 connect( btnEditRule, &QToolButton::clicked,
this, &QgsLabelingEngineRulesWidget::editSelectedRule );
259 connect( btnRemoveRule, &QToolButton::clicked,
this, &QgsLabelingEngineRulesWidget::removeRules );
261 connect( viewRules, &QAbstractItemView::doubleClicked,
this, &QgsLabelingEngineRulesWidget::editRule );
266 mModel->setRules(
rules );
271 return mModel->rules();
274void QgsLabelingEngineRulesWidget::createTypesMenu()
276 mAddRuleMenu->clear();
279 QList<QAction *> actions;
280 for (
const QString &
id : ruleIds )
286 connect( action, &QAction::triggered,
this, [
this,
id] {
291 std::sort( actions.begin(), actions.end(), [](
const QAction *a,
const QAction *b ) ->
bool {
292 return QString::localeAwareCompare( a->text(), b->text() ) < 0;
294 mAddRuleMenu->addActions( actions );
297void QgsLabelingEngineRulesWidget::createRule(
const QString &
id )
302 rule->setName( rule->displayType() );
303 mModel->addRule( rule );
304 const QModelIndex newRuleIndex = mModel->index( mModel->rowCount() - 1, 0, QModelIndex() );
305 viewRules->selectionModel()->setCurrentIndex( newRuleIndex, QItemSelectionModel::SelectionFlag::ClearAndSelect );
306 editRule( newRuleIndex );
310void QgsLabelingEngineRulesWidget::editSelectedRule()
312 const QItemSelection selection = viewRules->selectionModel()->selection();
313 for (
const QItemSelectionRange &range : selection )
315 if ( range.isValid() )
317 const QModelIndex index = range.indexes().value( 0 );
324void QgsLabelingEngineRulesWidget::editRule(
const QModelIndex &index )
326 const QgsAbstractLabelingEngineRule *rule = mModel->ruleAtIndex( index );
331 QgsLabelingEngineRuleWidget *widget =
nullptr;
332 if ( rule->
id() ==
"minimumDistanceLabelToFeature" )
334 widget =
new QgsLabelingEngineRuleMinimumDistanceLabelToFeatureWidget();
336 else if ( rule->
id() ==
"minimumDistanceLabelToLabel" )
338 widget =
new QgsLabelingEngineRuleMinimumDistanceLabelToLabelWidget();
340 else if ( rule->
id() ==
"maximumDistanceLabelToFeature" )
342 widget =
new QgsLabelingEngineRuleMaximumDistanceLabelToFeatureWidget();
344 else if ( rule->
id() ==
"avoidLabelOverlapWithFeature" )
346 widget =
new QgsLabelingEngineRuleAvoidLabelOverlapWithFeatureWidget();
358 std::unique_ptr<QgsAbstractLabelingEngineRule> updatedRule( widget->
rule() );
359 mModel->changeRule( index, updatedRule );
366 QgsLabelingEngineRuleDialog dialog( widget,
this );
367 dialog.setRule( rule );
370 std::unique_ptr<QgsAbstractLabelingEngineRule> updatedRule( dialog.rule() );
371 mModel->changeRule( index, updatedRule );
377void QgsLabelingEngineRulesWidget::removeRules()
379 const QItemSelection selection = viewRules->selectionModel()->selection();
381 for (
const QItemSelectionRange &range : selection )
383 if ( range.isValid() )
385 for (
int row = range.top(); row <= range.bottom(); ++row )
387 if ( !rows.contains( row ) )
393 std::sort( rows.begin(), rows.end() );
394 std::reverse( rows.begin(), rows.end() );
395 for (
int row : std::as_const( rows ) )
397 mModel->removeRow( row );
407 : QDialog( parent, flags )
409 setWindowTitle( tr(
"Configure Rules" ) );
410 setObjectName( u
"QgsLabelingEngineRulesDialog"_s );
414 QVBoxLayout *layout =
new QVBoxLayout(
this );
415 layout->addWidget( mWidget );
417 mButtonBox =
new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help, Qt::Horizontal,
this );
418 layout->addWidget( mButtonBox );
423 connect( mButtonBox->button( QDialogButtonBox::Ok ), &QAbstractButton::clicked,
this, &QDialog::accept );
424 connect( mButtonBox->button( QDialogButtonBox::Cancel ), &QAbstractButton::clicked,
this, &QDialog::reject );
425 connect( mButtonBox, &QDialogButtonBox::helpRequested,
this, [] {
426 QgsHelp::openHelp( u
"working_with_vector/vector_properties.html#labeling-rules"_s );
432 mWidget->setRules(
rules );
437 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.