QGIS API Documentation  3.2.0-Bonn (bc43194)
qgsvariableeditorwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvariableeditorwidget.cpp
3  ---------------------------
4  Date : April 2015
5  Copyright : (C) 2015 by Nyall Dawson
6  Email : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 #include "qgsexpressioncontext.h"
18 #include "qgsfeature.h"
19 #include "qgsapplication.h"
20 #include "qgssettings.h"
21 
22 #include <QVBoxLayout>
23 #include <QTreeWidget>
24 #include <QPainter>
25 #include <QKeyEvent>
26 #include <QMouseEvent>
27 #include <QLineEdit>
28 #include <QPushButton>
29 #include <QHeaderView>
30 #include <QMessageBox>
31 
32 
33 //
34 // QgsVariableEditorWidget
35 //
36 
38  : QWidget( parent )
39 {
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();
51  mAddButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyAdd.svg" ) ) );
52  mAddButton->setEnabled( false );
53  mAddButton->setToolTip( tr( "Add variable" ) );
54  horizontalLayout->addWidget( mAddButton );
55  mRemoveButton = new QPushButton();
56  mRemoveButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyRemove.svg" ) ) );
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 );
64  connect( mTreeWidget, &QgsVariableEditorTree::scopeChanged, this, &QgsVariableEditorWidget::scopeChanged );
65 
66  //setContext clones context
68  setContext( context );
69  delete context;
70 }
71 
73 {
74  QgsSettings settings;
75  settings.setValue( saveKey() + "column0width", mTreeWidget->header()->sectionSize( 0 ) );
76 }
77 
78 void QgsVariableEditorWidget::showEvent( QShowEvent *event )
79 {
80  // initialize widget on first show event only
81  if ( mShown )
82  {
83  event->accept();
84  return;
85  }
86 
87  //restore split size
88  QgsSettings settings;
89  QVariant val;
90  val = settings.value( saveKey() + "column0width" );
91  bool ok;
92  int sectionSize = val.toInt( &ok );
93  if ( ok )
94  {
95  mTreeWidget->header()->resizeSection( 0, sectionSize );
96  }
97  mShown = true;
98 
99  QWidget::showEvent( event );
100 }
101 
103 {
104  mContext.reset( new QgsExpressionContext( *context ) );
105  reloadContext();
106 }
107 
109 {
110  mTreeWidget->resetTree();
111  mTreeWidget->setContext( mContext.get() );
112  mTreeWidget->refreshTree();
113 }
114 
116 {
117  mEditableScopeIndex = scopeIndex;
118  if ( mEditableScopeIndex >= 0 )
119  {
120  mAddButton->setEnabled( true );
121  }
122  mTreeWidget->setEditableScopeIndex( scopeIndex );
123  mTreeWidget->refreshTree();
124 }
125 
127 {
128  if ( !mContext || mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
129  {
130  return nullptr;
131  }
132  return mContext->scope( mEditableScopeIndex );
133 }
134 
136 {
137  QVariantMap variables;
138  if ( !mContext || mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
139  {
140  return variables;
141  }
142 
143  QgsExpressionContextScope *scope = mContext->scope( mEditableScopeIndex );
144  Q_FOREACH ( const QString &variable, scope->variableNames() )
145  {
146  if ( scope->isReadOnly( variable ) )
147  continue;
148 
149  variables.insert( variable, scope->variable( variable ) );
150  }
151 
152  return variables;
153 }
154 
155 QString QgsVariableEditorWidget::saveKey() const
156 {
157  // save key for load/save state
158  // currently QgsVariableEditorTree/window()/object
159  QString setGroup = mSettingGroup.isEmpty() ? objectName() : mSettingGroup;
160  QString saveKey = "/QgsVariableEditorTree/" + setGroup + '/';
161  return saveKey;
162 }
163 
164 void QgsVariableEditorWidget::mAddButton_clicked()
165 {
166  if ( mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
167  return;
168 
169  QgsExpressionContextScope *scope = mContext->scope( mEditableScopeIndex );
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 );
176 
177  emit scopeChanged();
178 }
179 
180 void QgsVariableEditorWidget::mRemoveButton_clicked()
181 {
182  if ( mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
183  return;
184 
185  QgsExpressionContextScope *editableScope = mContext->scope( mEditableScopeIndex );
186  QList<QTreeWidgetItem *> selectedItems = mTreeWidget->selectedItems();
187 
188  Q_FOREACH ( QTreeWidgetItem *item, selectedItems )
189  {
190  if ( !( item->flags() & Qt::ItemIsEditable ) )
191  continue;
192 
193  QString name = item->text( 0 );
194  QgsExpressionContextScope *itemScope = mTreeWidget->scopeFromItem( item );
195  if ( itemScope != editableScope )
196  continue;
197 
198  if ( itemScope->isReadOnly( name ) )
199  continue;
200 
201  itemScope->removeVariable( name );
202  mTreeWidget->removeItem( item );
203  }
204  mTreeWidget->refreshTree();
205 }
206 
207 void QgsVariableEditorWidget::selectionChanged()
208 {
209  if ( mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
210  {
211  mRemoveButton->setEnabled( false );
212  return;
213  }
214 
215  QgsExpressionContextScope *editableScope = mContext->scope( mEditableScopeIndex );
216  QList<QTreeWidgetItem *> selectedItems = mTreeWidget->selectedItems();
217 
218  bool removeEnabled = true;
219  Q_FOREACH ( QTreeWidgetItem *item, selectedItems )
220  {
221  if ( !( item->flags() & Qt::ItemIsEditable ) )
222  {
223  removeEnabled = false;
224  break;
225  }
226 
227  QString name = item->text( 0 );
228  QgsExpressionContextScope *itemScope = mTreeWidget->scopeFromItem( item );
229  if ( itemScope != editableScope )
230  {
231  removeEnabled = false;
232  break;
233  }
234 
235  if ( editableScope->isReadOnly( name ) )
236  {
237  removeEnabled = false;
238  break;
239  }
240  }
241  mRemoveButton->setEnabled( removeEnabled );
242 }
243 
244 
246 //
247 // VariableEditorTree
248 //
249 
250 QgsVariableEditorTree::QgsVariableEditorTree( QWidget *parent )
251  : QTreeWidget( parent )
252 {
253  // init icons
254  if ( mExpandIcon.isNull() )
255  {
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 );
262  }
263 
264  setIconSize( QSize( 18, 18 ) );
265  setColumnCount( 2 );
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 );
272 
273  mEditorDelegate = new VariableEditorDelegate( this, this );
274  setItemDelegate( mEditorDelegate );
275 }
276 
277 QgsExpressionContextScope *QgsVariableEditorTree::scopeFromItem( QTreeWidgetItem *item ) const
278 {
279  if ( !item )
280  return nullptr;
281 
282  bool ok;
283  int contextIndex = item->data( 0, ContextIndex ).toInt( &ok );
284  if ( !ok )
285  return nullptr;
286 
287  if ( !mContext )
288  {
289  return nullptr;
290  }
291  else if ( mContext->scopeCount() > contextIndex )
292  {
293  return mContext->scope( contextIndex );
294  }
295  else
296  {
297  return nullptr;
298  }
299 }
300 
301 QTreeWidgetItem *QgsVariableEditorTree::itemFromVariable( QgsExpressionContextScope *scope, const QString &name ) const
302 {
303  int contextIndex = mContext ? mContext->indexOfScope( scope ) : 0;
304  if ( contextIndex < 0 )
305  return nullptr;
306  return mVariableToItem.value( qMakePair( contextIndex, name ) );
307 }
308 
309 QgsExpressionContextScope *QgsVariableEditorTree::editableScope()
310 {
311  if ( !mContext || mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
312  {
313  return nullptr;
314  }
315 
316  return mContext->scope( mEditableScopeIndex );
317 }
318 
319 void QgsVariableEditorTree::refreshTree()
320 {
321  if ( !mContext || mEditableScopeIndex < 0 )
322  {
323  clear();
324  return;
325  }
326 
327  //add all scopes from the context
328  int scopeIndex = 0;
329  Q_FOREACH ( QgsExpressionContextScope *scope, mContext->scopes() )
330  {
331  refreshScopeItems( scope, scopeIndex );
332  scopeIndex++;
333  }
334 }
335 
336 void QgsVariableEditorTree::refreshScopeVariables( QgsExpressionContextScope *scope, int scopeIndex )
337 {
338  QColor baseColor = rowColor( scopeIndex );
339  bool isCurrent = scopeIndex == mEditableScopeIndex;
340  QTreeWidgetItem *scopeItem = mScopeToItem.value( scopeIndex );
341 
342  Q_FOREACH ( const QString &name, scope->filteredVariableNames() )
343  {
344  QTreeWidgetItem *item = mVariableToItem.value( qMakePair( scopeIndex, name ) );
345  if ( !item )
346  {
347  item = new QTreeWidgetItem( scopeItem );
348  mVariableToItem.insert( qMakePair( scopeIndex, name ), item );
349  }
350 
351  bool readOnly = scope->isReadOnly( name );
352  bool isActive = true;
353  QgsExpressionContextScope *activeScope = nullptr;
354  if ( mContext )
355  {
356  activeScope = mContext->activeScopeForVariable( name );
357  isActive = activeScope == scope;
358  }
359 
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 )
366  {
367  font.setItalic( true );
368  item->setFlags( item->flags() ^ Qt::ItemIsEditable );
369  }
370  else
371  {
372  font.setItalic( false );
373  item->setFlags( item->flags() | Qt::ItemIsEditable );
374  }
375  if ( !isActive )
376  {
377  //overridden
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 );
382  }
383  else
384  {
385  font.setStrikeOut( false );
386  item->setToolTip( 0, name );
387  item->setToolTip( 1, value );
388  }
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 );
394  }
395 }
396 
397 void QgsVariableEditorTree::refreshScopeItems( QgsExpressionContextScope *scope, int scopeIndex )
398 {
399  QgsSettings settings;
400 
401  //add top level item
402  bool isCurrent = scopeIndex == mEditableScopeIndex;
403 
404  QTreeWidgetItem *scopeItem = nullptr;
405  if ( mScopeToItem.contains( scopeIndex ) )
406  {
407  //retrieve existing item
408  scopeItem = mScopeToItem.value( scopeIndex );
409  }
410  else
411  {
412  //create new top-level item
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 );
423 
424  addTopLevelItem( scopeItem );
425 
426  //expand by default if current context or context was previously expanded
427  if ( isCurrent || settings.value( "QgsVariableEditor/" + scopeItem->text( 0 ) + "/expanded" ).toBool() )
428  scopeItem->setExpanded( true );
429 
430  scopeItem->setIcon( 0, mExpandIcon );
431  }
432 
433  refreshScopeVariables( scope, scopeIndex );
434 }
435 
436 void QgsVariableEditorTree::removeItem( QTreeWidgetItem *item )
437 {
438  if ( !item )
439  return;
440 
441  mVariableToItem.remove( mVariableToItem.key( item ) );
442  item->parent()->takeChild( item->parent()->indexOfChild( item ) );
443 
444  emit scopeChanged();
445 }
446 
447 void QgsVariableEditorTree::renameItem( QTreeWidgetItem *item, const QString &name )
448 {
449  if ( !item )
450  return;
451 
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 );
456 
457  emit scopeChanged();
458 }
459 
460 void QgsVariableEditorTree::resetTree()
461 {
462  mVariableToItem.clear();
463  mScopeToItem.clear();
464  clear();
465 }
466 
467 void QgsVariableEditorTree::emitChanged()
468 {
469  emit scopeChanged();
470 }
471 
472 void QgsVariableEditorTree::drawRow( QPainter *painter, const QStyleOptionViewItem &option,
473  const QModelIndex &index ) const
474 {
475  QStyleOptionViewItem opt = option;
476  QTreeWidgetItem *item = itemFromIndex( index );
477  if ( index.parent().isValid() )
478  {
479  //not a top-level item, so shade row background by context
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 ) );
483  }
484  QTreeWidget::drawRow( painter, opt, index );
485  QColor color = static_cast<QRgb>( QApplication::style()->styleHint( QStyle::SH_Table_GridLineColor, &opt ) );
486  painter->save();
487  painter->setPen( QPen( color ) );
488  painter->drawLine( opt.rect.x(), opt.rect.bottom(), opt.rect.right(), opt.rect.bottom() );
489  painter->restore();
490 }
491 
492 QColor QgsVariableEditorTree::rowColor( int index ) const
493 {
494  //return some nice (inspired by Qt Designer) background row colors
495  int colorIdx = index % 6;
496  switch ( colorIdx )
497  {
498  case 0:
499  return QColor( 255, 220, 167 );
500  case 1:
501  return QColor( 255, 255, 191 );
502  case 2:
503  return QColor( 191, 255, 191 );
504  case 3:
505  return QColor( 199, 255, 255 );
506  case 4:
507  return QColor( 234, 191, 255 );
508  case 5:
509  default:
510  return QColor( 255, 191, 239 );
511  }
512 }
513 
514 void QgsVariableEditorTree::toggleContextExpanded( QTreeWidgetItem *item )
515 {
516  if ( !item )
517  return;
518 
519  item->setExpanded( !item->isExpanded() );
520 
521  //save expanded state
522  QgsSettings settings;
523  settings.setValue( "QgsVariableEditor/" + item->text( 0 ) + "/expanded", item->isExpanded() );
524 }
525 
526 void QgsVariableEditorTree::editNext( const QModelIndex &index )
527 {
528  if ( !index.isValid() )
529  return;
530 
531  if ( index.column() == 0 )
532  {
533  //switch to next column
534  QModelIndex nextIndex = index.sibling( index.row(), 1 );
535  if ( nextIndex.isValid() )
536  {
537  setCurrentIndex( nextIndex );
538  edit( nextIndex );
539  }
540  }
541  else
542  {
543  QModelIndex nextIndex = model()->index( index.row() + 1, 0, index.parent() );
544  if ( nextIndex.isValid() )
545  {
546  //start editing next row
547  setCurrentIndex( nextIndex );
548  edit( nextIndex );
549  }
550  else
551  {
552  edit( index );
553  }
554  }
555 }
556 
557 QModelIndex QgsVariableEditorTree::moveCursor( QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers )
558 {
559  if ( cursorAction == QAbstractItemView::MoveNext )
560  {
561  QModelIndex index = currentIndex();
562  if ( index.isValid() )
563  {
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 );
568  else
569  return QModelIndex();
570  }
571  }
572  else if ( cursorAction == QAbstractItemView::MovePrevious )
573  {
574  QModelIndex index = currentIndex();
575  if ( index.isValid() )
576  {
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 );
581  else
582  return QModelIndex();
583  }
584  }
585 
586  return QTreeWidget::moveCursor( cursorAction, modifiers );
587 }
588 
589 void QgsVariableEditorTree::keyPressEvent( QKeyEvent *event )
590 {
591  switch ( event->key() )
592  {
593  case Qt::Key_Return:
594  case Qt::Key_Enter:
595  case Qt::Key_Space:
596  {
597  QTreeWidgetItem *item = currentItem();
598  if ( item && !item->parent() )
599  {
600  event->accept();
601  toggleContextExpanded( item );
602  return;
603  }
604  else if ( item && ( item->flags() & Qt::ItemIsEditable ) )
605  {
606  event->accept();
607  editNext( currentIndex() );
608  return;
609  }
610  break;
611  }
612  default:
613  break;
614  }
615  QTreeWidget::keyPressEvent( event );
616 }
617 
618 void QgsVariableEditorTree::mousePressEvent( QMouseEvent *event )
619 {
620  QTreeWidget::mousePressEvent( event );
621  QTreeWidgetItem *item = itemAt( event->pos() );
622  if ( !item )
623  return;
624 
625  if ( item->parent() )
626  {
627  //not a top-level item
628  return;
629  }
630 
631  if ( event->pos().x() + header()->offset() > 20 )
632  {
633  //not clicking on expand icon
634  return;
635  }
636 
637  if ( event->modifiers() & Qt::ShiftModifier )
638  {
639  //shift modifier expands all
640  if ( !item->isExpanded() )
641  {
642  expandAll();
643  }
644  else
645  {
646  collapseAll();
647  }
648  }
649  else
650  {
651  toggleContextExpanded( item );
652  }
653 }
654 
655 //
656 // VariableEditorDelegate
657 //
658 
659 QWidget *VariableEditorDelegate::createEditor( QWidget *parent,
660  const QStyleOptionViewItem &,
661  const QModelIndex &index ) const
662 {
663  if ( !mParentTree )
664  return nullptr;
665 
666  //no editing for top level items
667  if ( !index.parent().isValid() )
668  return nullptr;
669 
670  QTreeWidgetItem *item = mParentTree->indexToItem( index );
671  QgsExpressionContextScope *scope = mParentTree->scopeFromItem( item );
672  if ( !item || !scope )
673  return nullptr;
674 
675  QString variableName = mParentTree->variableNameFromIndex( index );
676 
677  //no editing inherited or read-only variables
678  if ( scope != mParentTree->editableScope() || scope->isReadOnly( variableName ) )
679  return nullptr;
680 
681  QLineEdit *lineEdit = new QLineEdit( parent );
682  lineEdit->setText( index.column() == 0 ? variableName : mParentTree->editableScope()->variable( variableName ).toString() );
683  lineEdit->setAutoFillBackground( true );
684  return lineEdit;
685 }
686 
687 void VariableEditorDelegate::updateEditorGeometry( QWidget *editor,
688  const QStyleOptionViewItem &option,
689  const QModelIndex & ) const
690 {
691  editor->setGeometry( option.rect.adjusted( 0, 0, 0, -1 ) );
692 }
693 
694 QSize VariableEditorDelegate::sizeHint( const QStyleOptionViewItem &option,
695  const QModelIndex &index ) const
696 {
697  return QItemDelegate::sizeHint( option, index ) + QSize( 3, 4 );
698 }
699 
700 void VariableEditorDelegate::setModelData( QWidget *widget, QAbstractItemModel *model,
701  const QModelIndex &index ) const
702 {
703  Q_UNUSED( model );
704 
705  if ( !mParentTree )
706  return;
707 
708  QTreeWidgetItem *item = mParentTree->indexToItem( index );
709  QgsExpressionContextScope *scope = mParentTree->scopeFromItem( item );
710  if ( !item || !scope )
711  return;
712 
713  QLineEdit *lineEdit = qobject_cast< QLineEdit * >( widget );
714  if ( !lineEdit )
715  return;
716 
717  QString variableName = mParentTree->variableNameFromIndex( index );
718  if ( index.column() == 0 )
719  {
720  //edited variable name
721  QString newName = lineEdit->text();
722  newName = newName.trimmed();
723  newName = newName.replace( QStringLiteral( " " ), "_" );
724 
725  //test for validity
726  if ( newName == variableName )
727  {
728  return;
729  }
730  if ( scope->hasVariable( newName ) )
731  {
732  //existing name
733  QMessageBox::warning( mParentTree, tr( "Rename Variable" ), tr( "A variable with the name \"%1\" already exists in this context." ).arg( newName ) );
734  newName.append( "_1" );
735  }
736 
737  QString value = scope->variable( variableName ).toString();
738  mParentTree->renameItem( item, newName );
739  scope->removeVariable( variableName );
740  scope->setVariable( newName, value );
741  mParentTree->emitChanged();
742  }
743  else if ( index.column() == 1 )
744  {
745  //edited variable value
746  QString value = lineEdit->text();
747  if ( scope->variable( variableName ).toString() == value )
748  {
749  return;
750  }
751  scope->setVariable( variableName, value );
752  mParentTree->emitChanged();
753  }
754  mParentTree->refreshTree();
755 }
756 
void setEditableScopeIndex(int scopeIndex)
Sets the editable scope for the widget.
bool hasVariable(const QString &name) const
Tests whether a variable with the specified name exists in the scope.
QgsExpressionContext * context() const
Returns the current expression context for the widget.
void showEvent(QShowEvent *event) override
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
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.
QgsExpressionContextScope * editableScope() const
Returns the current editable scope for the widget.
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.
QgsVariableEditorWidget(QWidget *parent=nullptr)
Constructor for QgsVariableEditorWidget.
void scopeChanged()
Emitted when the user has modified a scope using the widget.
bool removeVariable(const QString &name)
Removes a variable from the context scope, if found.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QVariant variable(const QString &name) const
Retrieves a variable&#39;s value from the scope.
Single scope for storing variables and functions for use within a QgsExpressionContext.
void reloadContext()
Reloads all scopes from the editor&#39;s current context.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
void setContext(QgsExpressionContext *context)
Overwrites the QgsExpressionContext for the widget.
QString name() const
Returns the friendly display name of the context scope.
QVariantMap variablesInActiveScope() const
Returns a map variables set within the editable scope.
QStringList filteredVariableNames() const
Returns a filtered and sorted list of variable names contained within the scope.