22 #include <QVBoxLayout> 23 #include <QTreeWidget> 26 #include <QMouseEvent> 28 #include <QPushButton> 29 #include <QHeaderView> 30 #include <QMessageBox> 40 QVBoxLayout *verticalLayout =
new QVBoxLayout(
this );
41 verticalLayout->setSpacing( 3 );
42 verticalLayout->setContentsMargins( 3, 3, 3, 3 );
43 mTreeWidget =
new QgsVariableEditorTree(
this );
44 mTreeWidget->setSelectionMode( QAbstractItemView::SingleSelection );
45 verticalLayout->addWidget( mTreeWidget );
46 QHBoxLayout *horizontalLayout =
new QHBoxLayout();
47 horizontalLayout->setSpacing( 6 );
48 QSpacerItem *horizontalSpacer =
new QSpacerItem( 40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum );
49 horizontalLayout->addItem( horizontalSpacer );
50 mAddButton =
new QPushButton();
52 mAddButton->setEnabled(
false );
53 mAddButton->setToolTip( tr(
"Add variable" ) );
54 horizontalLayout->addWidget( mAddButton );
55 mRemoveButton =
new QPushButton();
57 mRemoveButton->setEnabled(
false );
58 mRemoveButton->setToolTip( tr(
"Remove variable" ) );
59 horizontalLayout->addWidget( mRemoveButton );
60 verticalLayout->addLayout( horizontalLayout );
61 connect( mRemoveButton, &QAbstractButton::clicked,
this, &QgsVariableEditorWidget::mRemoveButton_clicked );
62 connect( mAddButton, &QAbstractButton::clicked,
this, &QgsVariableEditorWidget::mAddButton_clicked );
63 connect( mTreeWidget, &QTreeWidget::itemSelectionChanged,
this, &QgsVariableEditorWidget::selectionChanged );
75 settings.
setValue( saveKey() +
"column0width", mTreeWidget->header()->sectionSize( 0 ) );
90 val = settings.
value( saveKey() +
"column0width" );
92 int sectionSize = val.toInt( &ok );
95 mTreeWidget->header()->resizeSection( 0, sectionSize );
99 QWidget::showEvent( event );
110 mTreeWidget->resetTree();
111 mTreeWidget->setContext( mContext.get() );
112 mTreeWidget->refreshTree();
117 mEditableScopeIndex = scopeIndex;
118 if ( mEditableScopeIndex >= 0 )
120 mAddButton->setEnabled(
true );
122 mTreeWidget->setEditableScopeIndex( scopeIndex );
123 mTreeWidget->refreshTree();
128 if ( !mContext || mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
132 return mContext->scope( mEditableScopeIndex );
137 QVariantMap variables;
138 if ( !mContext || mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
144 Q_FOREACH (
const QString &variable, scope->
variableNames() )
149 variables.insert( variable, scope->
variable( variable ) );
155 QString QgsVariableEditorWidget::saveKey()
const 159 QString setGroup = mSettingGroup.isEmpty() ? objectName() : mSettingGroup;
160 QString saveKey =
"/QgsVariableEditorTree/" + setGroup +
'/';
164 void QgsVariableEditorWidget::mAddButton_clicked()
166 if ( mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
170 scope->
setVariable( QStringLiteral(
"new_variable" ), QVariant() );
171 mTreeWidget->refreshTree();
172 QTreeWidgetItem *item = mTreeWidget->itemFromVariable( scope, QStringLiteral(
"new_variable" ) );
173 QModelIndex index = mTreeWidget->itemToIndex( item );
174 mTreeWidget->selectionModel()->select( index, QItemSelectionModel::ClearAndSelect );
175 mTreeWidget->editItem( item, 0 );
180 void QgsVariableEditorWidget::mRemoveButton_clicked()
182 if ( mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
186 QList<QTreeWidgetItem *> selectedItems = mTreeWidget->selectedItems();
188 Q_FOREACH ( QTreeWidgetItem *item, selectedItems )
190 if ( !( item->flags() & Qt::ItemIsEditable ) )
193 QString name = item->text( 0 );
195 if ( itemScope != editableScope )
202 mTreeWidget->removeItem( item );
204 mTreeWidget->refreshTree();
207 void QgsVariableEditorWidget::selectionChanged()
209 if ( mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
211 mRemoveButton->setEnabled(
false );
216 QList<QTreeWidgetItem *> selectedItems = mTreeWidget->selectedItems();
218 bool removeEnabled =
true;
219 Q_FOREACH ( QTreeWidgetItem *item, selectedItems )
221 if ( !( item->flags() & Qt::ItemIsEditable ) )
223 removeEnabled =
false;
227 QString name = item->text( 0 );
229 if ( itemScope != editableScope )
231 removeEnabled =
false;
237 removeEnabled =
false;
241 mRemoveButton->setEnabled( removeEnabled );
250 QgsVariableEditorTree::QgsVariableEditorTree( QWidget *parent )
251 : QTreeWidget( parent )
254 if ( mExpandIcon.isNull() )
256 QPixmap pix( 14, 14 );
257 pix.fill( Qt::transparent );
258 mExpandIcon.addPixmap(
QgsApplication::getThemeIcon( QStringLiteral(
"/mIconExpandSmall.svg" ) ).pixmap( 14, 14 ), QIcon::Normal, QIcon::Off );
259 mExpandIcon.addPixmap(
QgsApplication::getThemeIcon( QStringLiteral(
"/mIconExpandSmall.svg" ) ).pixmap( 14, 14 ), QIcon::Selected, QIcon::Off );
260 mExpandIcon.addPixmap(
QgsApplication::getThemeIcon( QStringLiteral(
"/mIconCollapseSmall.svg" ) ).pixmap( 14, 14 ), QIcon::Normal, QIcon::On );
261 mExpandIcon.addPixmap(
QgsApplication::getThemeIcon( QStringLiteral(
"/mIconCollapseSmall.svg" ) ).pixmap( 14, 14 ), QIcon::Selected, QIcon::On );
264 setIconSize( QSize( 18, 18 ) );
266 setHeaderLabels( QStringList() << tr(
"Variable" ) << tr(
"Value" ) );
267 setAlternatingRowColors(
true );
268 setEditTriggers( QAbstractItemView::AllEditTriggers );
269 setRootIsDecorated(
false );
270 header()->setSectionsMovable(
false );
271 header()->setSectionResizeMode( QHeaderView::Interactive );
273 mEditorDelegate =
new VariableEditorDelegate(
this,
this );
274 setItemDelegate( mEditorDelegate );
283 int contextIndex = item->data( 0, ContextIndex ).toInt( &ok );
291 else if ( mContext->scopeCount() > contextIndex )
293 return mContext->scope( contextIndex );
303 int contextIndex = mContext ? mContext->indexOfScope( scope ) : 0;
304 if ( contextIndex < 0 )
306 return mVariableToItem.value( qMakePair( contextIndex, name ) );
311 if ( !mContext || mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
316 return mContext->scope( mEditableScopeIndex );
319 void QgsVariableEditorTree::refreshTree()
321 if ( !mContext || mEditableScopeIndex < 0 )
331 refreshScopeItems( scope, scopeIndex );
338 QColor baseColor = rowColor( scopeIndex );
339 bool isCurrent = scopeIndex == mEditableScopeIndex;
340 QTreeWidgetItem *scopeItem = mScopeToItem.value( scopeIndex );
344 QTreeWidgetItem *item = mVariableToItem.value( qMakePair( scopeIndex, name ) );
347 item =
new QTreeWidgetItem( scopeItem );
348 mVariableToItem.insert( qMakePair( scopeIndex, name ), item );
352 bool isActive =
true;
356 activeScope = mContext->activeScopeForVariable( name );
357 isActive = activeScope == scope;
360 item->setFlags( item->flags() | Qt::ItemIsEnabled );
361 item->setText( 0, name );
362 QString value = scope->
variable( name ).toString();
363 item->setText( 1, value );
364 QFont font = item->font( 0 );
365 if ( readOnly || !isCurrent )
367 font.setItalic(
true );
368 item->setFlags( item->flags() ^ Qt::ItemIsEditable );
372 font.setItalic(
false );
373 item->setFlags( item->flags() | Qt::ItemIsEditable );
378 font.setStrikeOut(
true );
379 QString toolTip = tr(
"Overridden by value from %1" ).arg( activeScope->
name() );
380 item->setToolTip( 0, toolTip );
381 item->setToolTip( 1, toolTip );
385 font.setStrikeOut(
false );
386 item->setToolTip( 0, name );
387 item->setToolTip( 1, value );
389 item->setFont( 0, font );
390 item->setFont( 1, font );
391 item->setData( 0, RowBaseColor, baseColor );
392 item->setData( 0, ContextIndex, scopeIndex );
393 item->setFirstColumnSpanned(
false );
402 bool isCurrent = scopeIndex == mEditableScopeIndex;
404 QTreeWidgetItem *scopeItem =
nullptr;
405 if ( mScopeToItem.contains( scopeIndex ) )
408 scopeItem = mScopeToItem.value( scopeIndex );
413 scopeItem =
new QTreeWidgetItem();
414 mScopeToItem.insert( scopeIndex, scopeItem );
415 scopeItem->setFlags( scopeItem->flags() | Qt::ItemIsEnabled );
416 scopeItem->setText( 0, scope->
name() );
417 scopeItem->setFlags( scopeItem->flags() ^ Qt::ItemIsEditable );
418 scopeItem->setFirstColumnSpanned(
true );
419 QFont scopeFont = scopeItem->font( 0 );
420 scopeFont .setBold(
true );
421 scopeItem->setFont( 0, scopeFont );
422 scopeItem->setFirstColumnSpanned(
true );
424 addTopLevelItem( scopeItem );
427 if ( isCurrent || settings.
value(
"QgsVariableEditor/" + scopeItem->text( 0 ) +
"/expanded" ).toBool() )
428 scopeItem->setExpanded(
true );
430 scopeItem->setIcon( 0, mExpandIcon );
433 refreshScopeVariables( scope, scopeIndex );
436 void QgsVariableEditorTree::removeItem( QTreeWidgetItem *item )
441 mVariableToItem.remove( mVariableToItem.key( item ) );
442 item->parent()->takeChild( item->parent()->indexOfChild( item ) );
447 void QgsVariableEditorTree::renameItem( QTreeWidgetItem *item,
const QString &name )
452 int contextIndex = mVariableToItem.key( item ).first;
453 mVariableToItem.remove( mVariableToItem.key( item ) );
454 mVariableToItem.insert( qMakePair( contextIndex, name ), item );
455 item->setText( 0, name );
460 void QgsVariableEditorTree::resetTree()
462 mVariableToItem.clear();
463 mScopeToItem.clear();
467 void QgsVariableEditorTree::emitChanged()
472 void QgsVariableEditorTree::drawRow( QPainter *painter,
const QStyleOptionViewItem &option,
473 const QModelIndex &index )
const 475 QStyleOptionViewItem opt = option;
476 QTreeWidgetItem *item = itemFromIndex( index );
477 if ( index.parent().isValid() )
480 const QColor baseColor = item->data( 0, RowBaseColor ).value<QColor>();
481 painter->fillRect( option.rect, baseColor );
482 opt.palette.setColor( QPalette::AlternateBase, baseColor.lighter( 110 ) );
484 QTreeWidget::drawRow( painter, opt, index );
485 QColor color =
static_cast<QRgb
>( QApplication::style()->styleHint( QStyle::SH_Table_GridLineColor, &opt ) );
487 painter->setPen( QPen( color ) );
488 painter->drawLine( opt.rect.x(), opt.rect.bottom(), opt.rect.right(), opt.rect.bottom() );
492 QColor QgsVariableEditorTree::rowColor(
int index )
const 495 int colorIdx = index % 6;
499 return QColor( 255, 220, 167 );
501 return QColor( 255, 255, 191 );
503 return QColor( 191, 255, 191 );
505 return QColor( 199, 255, 255 );
507 return QColor( 234, 191, 255 );
510 return QColor( 255, 191, 239 );
514 void QgsVariableEditorTree::toggleContextExpanded( QTreeWidgetItem *item )
519 item->setExpanded( !item->isExpanded() );
523 settings.
setValue(
"QgsVariableEditor/" + item->text( 0 ) +
"/expanded", item->isExpanded() );
526 void QgsVariableEditorTree::editNext(
const QModelIndex &index )
528 if ( !index.isValid() )
531 if ( index.column() == 0 )
534 QModelIndex nextIndex = index.sibling( index.row(), 1 );
535 if ( nextIndex.isValid() )
537 setCurrentIndex( nextIndex );
543 QModelIndex nextIndex = model()->index( index.row() + 1, 0, index.parent() );
544 if ( nextIndex.isValid() )
547 setCurrentIndex( nextIndex );
557 QModelIndex QgsVariableEditorTree::moveCursor( QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers )
559 if ( cursorAction == QAbstractItemView::MoveNext )
561 QModelIndex index = currentIndex();
562 if ( index.isValid() )
564 if ( index.column() + 1 < model()->columnCount() )
565 return index.sibling( index.row(), index.column() + 1 );
566 else if ( index.row() + 1 < model()->rowCount( index.parent() ) )
567 return index.sibling( index.row() + 1, 0 );
569 return QModelIndex();
572 else if ( cursorAction == QAbstractItemView::MovePrevious )
574 QModelIndex index = currentIndex();
575 if ( index.isValid() )
577 if ( index.column() >= 1 )
578 return index.sibling( index.row(), index.column() - 1 );
579 else if ( index.row() >= 1 )
580 return index.sibling( index.row() - 1, model()->columnCount() - 1 );
582 return QModelIndex();
586 return QTreeWidget::moveCursor( cursorAction, modifiers );
589 void QgsVariableEditorTree::keyPressEvent( QKeyEvent *event )
591 switch ( event->key() )
597 QTreeWidgetItem *item = currentItem();
598 if ( item && !item->parent() )
601 toggleContextExpanded( item );
604 else if ( item && ( item->flags() & Qt::ItemIsEditable ) )
607 editNext( currentIndex() );
615 QTreeWidget::keyPressEvent( event );
618 void QgsVariableEditorTree::mousePressEvent( QMouseEvent *event )
620 QTreeWidget::mousePressEvent( event );
621 QTreeWidgetItem *item = itemAt( event->pos() );
625 if ( item->parent() )
631 if ( event->pos().x() + header()->offset() > 20 )
637 if ( event->modifiers() & Qt::ShiftModifier )
640 if ( !item->isExpanded() )
651 toggleContextExpanded( item );
659 QWidget *VariableEditorDelegate::createEditor( QWidget *parent,
660 const QStyleOptionViewItem &,
661 const QModelIndex &index )
const 667 if ( !index.parent().isValid() )
670 QTreeWidgetItem *item = mParentTree->indexToItem( index );
672 if ( !item || !scope )
675 QString variableName = mParentTree->variableNameFromIndex( index );
678 if ( scope != mParentTree->editableScope() || scope->
isReadOnly( variableName ) )
681 QLineEdit *lineEdit =
new QLineEdit( parent );
682 lineEdit->setText( index.column() == 0 ? variableName : mParentTree->editableScope()->variable( variableName ).toString() );
683 lineEdit->setAutoFillBackground(
true );
687 void VariableEditorDelegate::updateEditorGeometry( QWidget *editor,
688 const QStyleOptionViewItem &option,
689 const QModelIndex & )
const 691 editor->setGeometry( option.rect.adjusted( 0, 0, 0, -1 ) );
694 QSize VariableEditorDelegate::sizeHint(
const QStyleOptionViewItem &option,
695 const QModelIndex &index )
const 697 return QItemDelegate::sizeHint( option, index ) + QSize( 3, 4 );
700 void VariableEditorDelegate::setModelData( QWidget *widget, QAbstractItemModel *model,
701 const QModelIndex &index )
const 708 QTreeWidgetItem *item = mParentTree->indexToItem( index );
710 if ( !item || !scope )
713 QLineEdit *lineEdit = qobject_cast< QLineEdit * >( widget );
717 QString variableName = mParentTree->variableNameFromIndex( index );
718 if ( index.column() == 0 )
721 QString newName = lineEdit->text();
724 if ( newName == variableName )
731 QMessageBox::warning( mParentTree, tr(
"Rename Variable" ), tr(
"A variable with the name \"%1\" already exists in this context." ).arg( newName ) );
732 newName.append(
"_1" );
735 QString value = scope->
variable( variableName ).toString();
736 mParentTree->renameItem( item, newName );
739 mParentTree->emitChanged();
741 else if ( index.column() == 1 )
744 QString value = lineEdit->text();
745 if ( scope->
variable( variableName ).toString() == value )
750 mParentTree->emitChanged();
752 mParentTree->refreshTree();
bool hasVariable(const QString &name) const
Tests whether a variable with the specified name exists in the scope.
This class is a composition of two QSettings instances:
QStringList variableNames() const
Returns a list of variable names contained within the scope.
bool isReadOnly(const QString &name) const
Tests whether the specified variable is read only and should not be editable by users.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
void setVariable(const QString &name, const QVariant &value, bool isStatic=false)
Convenience method for setting a variable in the context scope by name name and value.
bool removeVariable(const QString &name)
Removes a variable from the context scope, if found.
void setValue(const QString &key, const QVariant &value, const QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QVariant variable(const QString &name) const
Retrieves a variable's value from the scope.
Single scope for storing variables and functions for use within a QgsExpressionContext.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
QString name() const
Returns the friendly display name of the context scope.
QStringList filteredVariableNames() const
Returns a filtered and sorted list of variable names contained within the scope.