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() )
145 for (
const QString &variable : constVariableNames )
150 variables.insert( variable, scope->
variable( variable ) );
156 QString QgsVariableEditorWidget::saveKey()
const
160 QString setGroup = mSettingGroup.isEmpty() ? objectName() : mSettingGroup;
161 QString saveKey =
"/QgsVariableEditorTree/" + setGroup +
'/';
165 void QgsVariableEditorWidget::mAddButton_clicked()
167 if ( mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
171 scope->
setVariable( QStringLiteral(
"new_variable" ), QVariant() );
172 mTreeWidget->refreshTree();
173 QTreeWidgetItem *item = mTreeWidget->itemFromVariable( scope, QStringLiteral(
"new_variable" ) );
174 QModelIndex index = mTreeWidget->itemToIndex( item );
175 mTreeWidget->selectionModel()->select( index, QItemSelectionModel::ClearAndSelect );
176 mTreeWidget->editItem( item, 0 );
181 void QgsVariableEditorWidget::mRemoveButton_clicked()
183 if ( mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
187 QList<QTreeWidgetItem *> selectedItems = mTreeWidget->selectedItems();
189 const auto constSelectedItems = selectedItems;
190 for ( QTreeWidgetItem *item : constSelectedItems )
192 if ( !( item->flags() & Qt::ItemIsEditable ) )
195 QString name = item->text( 0 );
204 mTreeWidget->removeItem( item );
206 mTreeWidget->refreshTree();
209 void QgsVariableEditorWidget::selectionChanged()
211 if ( mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
213 mRemoveButton->setEnabled(
false );
218 QList<QTreeWidgetItem *> selectedItems = mTreeWidget->selectedItems();
220 bool removeEnabled =
true;
221 const auto constSelectedItems = selectedItems;
222 for ( QTreeWidgetItem *item : constSelectedItems )
224 if ( !( item->flags() & Qt::ItemIsEditable ) )
226 removeEnabled =
false;
230 QString name = item->text( 0 );
234 removeEnabled =
false;
240 removeEnabled =
false;
244 mRemoveButton->setEnabled( removeEnabled );
253 QgsVariableEditorTree::QgsVariableEditorTree( QWidget *parent )
254 : QTreeWidget( parent )
257 if ( mExpandIcon.isNull() )
259 QPixmap pix( 14, 14 );
260 pix.fill( Qt::transparent );
261 mExpandIcon.addPixmap(
QgsApplication::getThemeIcon( QStringLiteral(
"/mIconExpandSmall.svg" ) ).pixmap( 14, 14 ), QIcon::Normal, QIcon::Off );
262 mExpandIcon.addPixmap(
QgsApplication::getThemeIcon( QStringLiteral(
"/mIconExpandSmall.svg" ) ).pixmap( 14, 14 ), QIcon::Selected, QIcon::Off );
263 mExpandIcon.addPixmap(
QgsApplication::getThemeIcon( QStringLiteral(
"/mIconCollapseSmall.svg" ) ).pixmap( 14, 14 ), QIcon::Normal, QIcon::On );
264 mExpandIcon.addPixmap(
QgsApplication::getThemeIcon( QStringLiteral(
"/mIconCollapseSmall.svg" ) ).pixmap( 14, 14 ), QIcon::Selected, QIcon::On );
267 setIconSize( QSize( 18, 18 ) );
269 setHeaderLabels( QStringList() << tr(
"Variable" ) << tr(
"Value" ) );
270 setEditTriggers( QAbstractItemView::AllEditTriggers );
271 setRootIsDecorated(
false );
272 header()->setSectionsMovable(
false );
273 header()->setSectionResizeMode( QHeaderView::Interactive );
275 mEditorDelegate =
new VariableEditorDelegate(
this,
this );
276 setItemDelegate( mEditorDelegate );
285 int contextIndex = item->data( 0, ContextIndex ).toInt( &ok );
293 else if ( mContext->scopeCount() > contextIndex )
295 return mContext->scope( contextIndex );
305 int contextIndex = mContext ? mContext->indexOfScope( scope ) : 0;
306 if ( contextIndex < 0 )
308 return mVariableToItem.value( qMakePair( contextIndex, name ) );
313 if ( !mContext || mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
318 return mContext->scope( mEditableScopeIndex );
321 void QgsVariableEditorTree::refreshTree()
323 if ( !mContext || mEditableScopeIndex < 0 )
331 const auto constScopes = mContext->scopes();
334 refreshScopeItems( scope, scopeIndex );
341 QColor baseColor = rowColor( scopeIndex );
342 bool isCurrent = scopeIndex == mEditableScopeIndex;
343 QTreeWidgetItem *scopeItem = mScopeToItem.value( scopeIndex );
346 for (
const QString &name : names )
348 QTreeWidgetItem *item = mVariableToItem.value( qMakePair( scopeIndex, name ) );
351 item =
new QTreeWidgetItem( scopeItem );
352 mVariableToItem.insert( qMakePair( scopeIndex, name ), item );
356 bool isActive =
true;
360 activeScope = mContext->activeScopeForVariable( name );
361 isActive = activeScope == scope;
364 item->setFlags( item->flags() | Qt::ItemIsEnabled );
365 item->setText( 0, name );
366 const QVariant value = scope->
variable( name );
368 item->setText( 1, previewString );
369 QFont font = item->font( 0 );
370 if ( readOnly || !isCurrent )
372 font.setItalic(
true );
373 item->setFlags( item->flags() ^ Qt::ItemIsEditable );
377 font.setItalic(
false );
378 item->setFlags( item->flags() | Qt::ItemIsEditable );
383 font.setStrikeOut(
true );
384 QString toolTip = tr(
"Overridden by value from %1" ).arg( activeScope->
name() );
385 item->setToolTip( 0, toolTip );
386 item->setToolTip( 1, toolTip );
390 font.setStrikeOut(
false );
391 item->setToolTip( 0, name );
392 item->setToolTip( 1, previewString );
394 item->setFont( 0, font );
395 item->setFont( 1, font );
396 item->setData( 0, RowBaseColor, baseColor );
397 item->setData( 0, ContextIndex, scopeIndex );
398 item->setFirstColumnSpanned(
false );
407 bool isCurrent = scopeIndex == mEditableScopeIndex;
409 QTreeWidgetItem *scopeItem =
nullptr;
410 if ( mScopeToItem.contains( scopeIndex ) )
413 scopeItem = mScopeToItem.
value( scopeIndex );
418 scopeItem =
new QTreeWidgetItem();
419 mScopeToItem.insert( scopeIndex, scopeItem );
420 scopeItem->setFlags( scopeItem->flags() | Qt::ItemIsEnabled );
421 scopeItem->setText( 0, scope->
name() );
422 scopeItem->setFlags( scopeItem->flags() ^ Qt::ItemIsEditable );
423 scopeItem->setFirstColumnSpanned(
true );
424 QFont scopeFont = scopeItem->font( 0 );
425 scopeFont .setBold(
true );
426 scopeItem->setFont( 0, scopeFont );
427 scopeItem->setFirstColumnSpanned(
true );
429 addTopLevelItem( scopeItem );
432 if ( isCurrent || settings.
value(
"QgsVariableEditor/" + scopeItem->text( 0 ) +
"/expanded" ).toBool() )
433 scopeItem->setExpanded(
true );
435 scopeItem->setIcon( 0, mExpandIcon );
438 refreshScopeVariables( scope, scopeIndex );
441 void QgsVariableEditorTree::removeItem( QTreeWidgetItem *item )
446 mVariableToItem.remove( mVariableToItem.key( item ) );
447 item->parent()->takeChild( item->parent()->indexOfChild( item ) );
452 void QgsVariableEditorTree::renameItem( QTreeWidgetItem *item,
const QString &name )
457 int contextIndex = mVariableToItem.key( item ).first;
458 mVariableToItem.remove( mVariableToItem.key( item ) );
459 mVariableToItem.insert( qMakePair( contextIndex, name ), item );
460 item->setText( 0, name );
465 void QgsVariableEditorTree::resetTree()
467 mVariableToItem.clear();
468 mScopeToItem.clear();
472 void QgsVariableEditorTree::emitChanged()
477 void QgsVariableEditorTree::drawRow( QPainter *painter,
const QStyleOptionViewItem &option,
478 const QModelIndex &index )
const
480 QStyleOptionViewItem opt = option;
481 QTreeWidgetItem *item = itemFromIndex( index );
482 if ( index.parent().isValid() )
485 QColor baseColor = item->data( 0, RowBaseColor ).value<QColor>();
486 if ( index.row() % 2 == 1 )
488 baseColor.setAlpha( 59 );
490 painter->fillRect( option.rect, baseColor );
492 QTreeWidget::drawRow( painter, opt, index );
493 QColor color =
static_cast<QRgb
>( QApplication::style()->styleHint( QStyle::SH_Table_GridLineColor, &opt ) );
495 painter->setPen( QPen( color ) );
496 painter->drawLine( opt.rect.x(), opt.rect.bottom(), opt.rect.right(), opt.rect.bottom() );
500 QColor QgsVariableEditorTree::rowColor(
int index )
const
503 int colorIdx = index % 6;
507 return QColor( 255, 163, 0, 89 );
509 return QColor( 255, 255, 77, 89 );
511 return QColor( 0, 255, 77, 89 );
513 return QColor( 0, 255, 255, 89 );
515 return QColor( 196, 125, 255, 89 );
518 return QColor( 255, 125, 225, 89 );
522 void QgsVariableEditorTree::toggleContextExpanded( QTreeWidgetItem *item )
527 item->setExpanded( !item->isExpanded() );
531 settings.
setValue(
"QgsVariableEditor/" + item->text( 0 ) +
"/expanded", item->isExpanded() );
534 void QgsVariableEditorTree::editNext(
const QModelIndex &index )
536 if ( !index.isValid() )
539 if ( index.column() == 0 )
542 QModelIndex nextIndex = index.sibling( index.row(), 1 );
543 if ( nextIndex.isValid() )
545 setCurrentIndex( nextIndex );
551 QModelIndex nextIndex = model()->index( index.row() + 1, 0, index.parent() );
552 if ( nextIndex.isValid() )
555 setCurrentIndex( nextIndex );
565 QModelIndex QgsVariableEditorTree::moveCursor( QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers )
567 if ( cursorAction == QAbstractItemView::MoveNext )
569 QModelIndex index = currentIndex();
570 if ( index.isValid() )
572 if ( index.column() + 1 < model()->columnCount() )
573 return index.sibling( index.row(), index.column() + 1 );
574 else if ( index.row() + 1 < model()->rowCount( index.parent() ) )
575 return index.sibling( index.row() + 1, 0 );
577 return QModelIndex();
580 else if ( cursorAction == QAbstractItemView::MovePrevious )
582 QModelIndex index = currentIndex();
583 if ( index.isValid() )
585 if ( index.column() >= 1 )
586 return index.sibling( index.row(), index.column() - 1 );
587 else if ( index.row() >= 1 )
588 return index.sibling( index.row() - 1, model()->columnCount() - 1 );
590 return QModelIndex();
594 return QTreeWidget::moveCursor( cursorAction, modifiers );
597 void QgsVariableEditorTree::keyPressEvent( QKeyEvent *event )
599 switch ( event->key() )
605 QTreeWidgetItem *item = currentItem();
606 if ( item && !item->parent() )
609 toggleContextExpanded( item );
612 else if ( item && ( item->flags() & Qt::ItemIsEditable ) )
615 editNext( currentIndex() );
624 if ( event == QKeySequence::Copy )
626 QList<QTreeWidgetItem *> selected = selectedItems();
627 if ( selected.size() > 0 )
629 QString text = selected.at( 0 )->text( 0 );
630 QString varName = variableNameFromItem( selected.at( 0 ) );
632 if ( !varName.isEmpty() && scope )
633 text = scope->
variable( varName ).toString();
635 QClipboard *clipboard = QApplication::clipboard();
636 clipboard->setText( text );
642 QTreeWidget::keyPressEvent( event );
645 void QgsVariableEditorTree::mousePressEvent( QMouseEvent *event )
647 QTreeWidget::mousePressEvent( event );
648 QTreeWidgetItem *item = itemAt( event->pos() );
652 if ( item->parent() )
658 if ( event->pos().x() + header()->offset() > 20 )
664 if ( event->modifiers() & Qt::ShiftModifier )
667 if ( !item->isExpanded() )
678 toggleContextExpanded( item );
686 QWidget *VariableEditorDelegate::createEditor( QWidget *parent,
687 const QStyleOptionViewItem &,
688 const QModelIndex &index )
const
694 if ( !index.parent().isValid() )
697 QTreeWidgetItem *item = mParentTree->indexToItem( index );
699 if ( !item || !scope )
702 QString variableName = mParentTree->variableNameFromIndex( index );
705 if ( scope != mParentTree->editableScope() || scope->
isReadOnly( variableName ) )
708 QLineEdit *lineEdit =
new QLineEdit( parent );
709 lineEdit->setText( index.column() == 0 ? variableName : mParentTree->editableScope()->variable( variableName ).toString() );
710 lineEdit->setAutoFillBackground(
true );
714 void VariableEditorDelegate::updateEditorGeometry( QWidget *editor,
715 const QStyleOptionViewItem &option,
716 const QModelIndex & )
const
718 editor->setGeometry( option.rect.adjusted( 0, 0, 0, -1 ) );
721 QSize VariableEditorDelegate::sizeHint(
const QStyleOptionViewItem &option,
722 const QModelIndex &index )
const
724 return QItemDelegate::sizeHint( option, index ) + QSize( 3, 4 );
727 void VariableEditorDelegate::setModelData( QWidget *widget, QAbstractItemModel *model,
728 const QModelIndex &index )
const
735 QTreeWidgetItem *item = mParentTree->indexToItem( index );
737 if ( !item || !scope )
740 QLineEdit *lineEdit = qobject_cast< QLineEdit * >( widget );
744 QString variableName = mParentTree->variableNameFromIndex( index );
745 if ( index.column() == 0 )
748 QString newName = lineEdit->text();
749 newName = newName.trimmed();
750 newName = newName.replace(
' ',
'_' );
753 if ( newName == variableName )
760 QMessageBox::warning( mParentTree, tr(
"Rename Variable" ), tr(
"A variable with the name \"%1\" already exists in this context." ).arg( newName ) );
761 newName.append(
"_1" );
764 QString value = scope->
variable( variableName ).toString();
765 mParentTree->renameItem( item, newName );
768 mParentTree->emitChanged();
770 else if ( index.column() == 1 )
773 QString value = lineEdit->text();
774 if ( scope->
variable( variableName ).toString() == value )
779 mParentTree->emitChanged();
781 mParentTree->refreshTree();