QGIS API Documentation  3.6.0-Noosa (5873452)
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 "qgsapplication.h"
19 #include "qgssettings.h"
20 #include "qgsexpression.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  setEditTriggers( QAbstractItemView::AllEditTriggers );
268  setRootIsDecorated( false );
269  header()->setSectionsMovable( false );
270  header()->setSectionResizeMode( QHeaderView::Interactive );
271 
272  mEditorDelegate = new VariableEditorDelegate( this, this );
273  setItemDelegate( mEditorDelegate );
274 }
275 
276 QgsExpressionContextScope *QgsVariableEditorTree::scopeFromItem( QTreeWidgetItem *item ) const
277 {
278  if ( !item )
279  return nullptr;
280 
281  bool ok;
282  int contextIndex = item->data( 0, ContextIndex ).toInt( &ok );
283  if ( !ok )
284  return nullptr;
285 
286  if ( !mContext )
287  {
288  return nullptr;
289  }
290  else if ( mContext->scopeCount() > contextIndex )
291  {
292  return mContext->scope( contextIndex );
293  }
294  else
295  {
296  return nullptr;
297  }
298 }
299 
300 QTreeWidgetItem *QgsVariableEditorTree::itemFromVariable( QgsExpressionContextScope *scope, const QString &name ) const
301 {
302  int contextIndex = mContext ? mContext->indexOfScope( scope ) : 0;
303  if ( contextIndex < 0 )
304  return nullptr;
305  return mVariableToItem.value( qMakePair( contextIndex, name ) );
306 }
307 
308 QgsExpressionContextScope *QgsVariableEditorTree::editableScope()
309 {
310  if ( !mContext || mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
311  {
312  return nullptr;
313  }
314 
315  return mContext->scope( mEditableScopeIndex );
316 }
317 
318 void QgsVariableEditorTree::refreshTree()
319 {
320  if ( !mContext || mEditableScopeIndex < 0 )
321  {
322  clear();
323  return;
324  }
325 
326  //add all scopes from the context
327  int scopeIndex = 0;
328  Q_FOREACH ( QgsExpressionContextScope *scope, mContext->scopes() )
329  {
330  refreshScopeItems( scope, scopeIndex );
331  scopeIndex++;
332  }
333 }
334 
335 void QgsVariableEditorTree::refreshScopeVariables( QgsExpressionContextScope *scope, int scopeIndex )
336 {
337  QColor baseColor = rowColor( scopeIndex );
338  bool isCurrent = scopeIndex == mEditableScopeIndex;
339  QTreeWidgetItem *scopeItem = mScopeToItem.value( scopeIndex );
340 
341  const QStringList names = scope->filteredVariableNames();
342  for ( const QString &name : names )
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  const QVariant value = scope->variable( name );
363  const QString previewString = QgsExpression::formatPreviewString( value, false );
364  item->setText( 1, previewString );
365  QFont font = item->font( 0 );
366  if ( readOnly || !isCurrent )
367  {
368  font.setItalic( true );
369  item->setFlags( item->flags() ^ Qt::ItemIsEditable );
370  }
371  else
372  {
373  font.setItalic( false );
374  item->setFlags( item->flags() | Qt::ItemIsEditable );
375  }
376  if ( !isActive )
377  {
378  //overridden
379  font.setStrikeOut( true );
380  QString toolTip = tr( "Overridden by value from %1" ).arg( activeScope->name() );
381  item->setToolTip( 0, toolTip );
382  item->setToolTip( 1, toolTip );
383  }
384  else
385  {
386  font.setStrikeOut( false );
387  item->setToolTip( 0, name );
388  item->setToolTip( 1, previewString );
389  }
390  item->setFont( 0, font );
391  item->setFont( 1, font );
392  item->setData( 0, RowBaseColor, baseColor );
393  item->setData( 0, ContextIndex, scopeIndex );
394  item->setFirstColumnSpanned( false );
395  }
396 }
397 
398 void QgsVariableEditorTree::refreshScopeItems( QgsExpressionContextScope *scope, int scopeIndex )
399 {
400  QgsSettings settings;
401 
402  //add top level item
403  bool isCurrent = scopeIndex == mEditableScopeIndex;
404 
405  QTreeWidgetItem *scopeItem = nullptr;
406  if ( mScopeToItem.contains( scopeIndex ) )
407  {
408  //retrieve existing item
409  scopeItem = mScopeToItem.value( scopeIndex );
410  }
411  else
412  {
413  //create new top-level item
414  scopeItem = new QTreeWidgetItem();
415  mScopeToItem.insert( scopeIndex, scopeItem );
416  scopeItem->setFlags( scopeItem->flags() | Qt::ItemIsEnabled );
417  scopeItem->setText( 0, scope->name() );
418  scopeItem->setFlags( scopeItem->flags() ^ Qt::ItemIsEditable );
419  scopeItem->setFirstColumnSpanned( true );
420  QFont scopeFont = scopeItem->font( 0 );
421  scopeFont .setBold( true );
422  scopeItem->setFont( 0, scopeFont );
423  scopeItem->setFirstColumnSpanned( true );
424 
425  addTopLevelItem( scopeItem );
426 
427  //expand by default if current context or context was previously expanded
428  if ( isCurrent || settings.value( "QgsVariableEditor/" + scopeItem->text( 0 ) + "/expanded" ).toBool() )
429  scopeItem->setExpanded( true );
430 
431  scopeItem->setIcon( 0, mExpandIcon );
432  }
433 
434  refreshScopeVariables( scope, scopeIndex );
435 }
436 
437 void QgsVariableEditorTree::removeItem( QTreeWidgetItem *item )
438 {
439  if ( !item )
440  return;
441 
442  mVariableToItem.remove( mVariableToItem.key( item ) );
443  item->parent()->takeChild( item->parent()->indexOfChild( item ) );
444 
445  emit scopeChanged();
446 }
447 
448 void QgsVariableEditorTree::renameItem( QTreeWidgetItem *item, const QString &name )
449 {
450  if ( !item )
451  return;
452 
453  int contextIndex = mVariableToItem.key( item ).first;
454  mVariableToItem.remove( mVariableToItem.key( item ) );
455  mVariableToItem.insert( qMakePair( contextIndex, name ), item );
456  item->setText( 0, name );
457 
458  emit scopeChanged();
459 }
460 
461 void QgsVariableEditorTree::resetTree()
462 {
463  mVariableToItem.clear();
464  mScopeToItem.clear();
465  clear();
466 }
467 
468 void QgsVariableEditorTree::emitChanged()
469 {
470  emit scopeChanged();
471 }
472 
473 void QgsVariableEditorTree::drawRow( QPainter *painter, const QStyleOptionViewItem &option,
474  const QModelIndex &index ) const
475 {
476  QStyleOptionViewItem opt = option;
477  QTreeWidgetItem *item = itemFromIndex( index );
478  if ( index.parent().isValid() )
479  {
480  //not a top-level item, so shade row background by context
481  QColor baseColor = item->data( 0, RowBaseColor ).value<QColor>();
482  if ( index.row() % 2 == 1 )
483  {
484  baseColor = baseColor.lighter( 110 );
485  }
486  painter->fillRect( option.rect, baseColor );
487 
488  //declare custom text color since we've overwritten default background color
489  QPalette pal = opt.palette;
490  pal.setColor( QPalette::Active, QPalette::Text, Qt::black );
491  pal.setColor( QPalette::Inactive, QPalette::Text, Qt::black );
492  pal.setColor( QPalette::Disabled, QPalette::Text, Qt::gray );
493  opt.palette = pal;
494  }
495  QTreeWidget::drawRow( painter, opt, index );
496  QColor color = static_cast<QRgb>( QApplication::style()->styleHint( QStyle::SH_Table_GridLineColor, &opt ) );
497  painter->save();
498  painter->setPen( QPen( color ) );
499  painter->drawLine( opt.rect.x(), opt.rect.bottom(), opt.rect.right(), opt.rect.bottom() );
500  painter->restore();
501 }
502 
503 QColor QgsVariableEditorTree::rowColor( int index ) const
504 {
505  //return some nice (inspired by Qt Designer) background row colors
506  int colorIdx = index % 6;
507  switch ( colorIdx )
508  {
509  case 0:
510  return QColor( 255, 220, 167 );
511  case 1:
512  return QColor( 255, 255, 191 );
513  case 2:
514  return QColor( 191, 255, 191 );
515  case 3:
516  return QColor( 199, 255, 255 );
517  case 4:
518  return QColor( 234, 191, 255 );
519  case 5:
520  default:
521  return QColor( 255, 191, 239 );
522  }
523 }
524 
525 void QgsVariableEditorTree::toggleContextExpanded( QTreeWidgetItem *item )
526 {
527  if ( !item )
528  return;
529 
530  item->setExpanded( !item->isExpanded() );
531 
532  //save expanded state
533  QgsSettings settings;
534  settings.setValue( "QgsVariableEditor/" + item->text( 0 ) + "/expanded", item->isExpanded() );
535 }
536 
537 void QgsVariableEditorTree::editNext( const QModelIndex &index )
538 {
539  if ( !index.isValid() )
540  return;
541 
542  if ( index.column() == 0 )
543  {
544  //switch to next column
545  QModelIndex nextIndex = index.sibling( index.row(), 1 );
546  if ( nextIndex.isValid() )
547  {
548  setCurrentIndex( nextIndex );
549  edit( nextIndex );
550  }
551  }
552  else
553  {
554  QModelIndex nextIndex = model()->index( index.row() + 1, 0, index.parent() );
555  if ( nextIndex.isValid() )
556  {
557  //start editing next row
558  setCurrentIndex( nextIndex );
559  edit( nextIndex );
560  }
561  else
562  {
563  edit( index );
564  }
565  }
566 }
567 
568 QModelIndex QgsVariableEditorTree::moveCursor( QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers )
569 {
570  if ( cursorAction == QAbstractItemView::MoveNext )
571  {
572  QModelIndex index = currentIndex();
573  if ( index.isValid() )
574  {
575  if ( index.column() + 1 < model()->columnCount() )
576  return index.sibling( index.row(), index.column() + 1 );
577  else if ( index.row() + 1 < model()->rowCount( index.parent() ) )
578  return index.sibling( index.row() + 1, 0 );
579  else
580  return QModelIndex();
581  }
582  }
583  else if ( cursorAction == QAbstractItemView::MovePrevious )
584  {
585  QModelIndex index = currentIndex();
586  if ( index.isValid() )
587  {
588  if ( index.column() >= 1 )
589  return index.sibling( index.row(), index.column() - 1 );
590  else if ( index.row() >= 1 )
591  return index.sibling( index.row() - 1, model()->columnCount() - 1 );
592  else
593  return QModelIndex();
594  }
595  }
596 
597  return QTreeWidget::moveCursor( cursorAction, modifiers );
598 }
599 
600 void QgsVariableEditorTree::keyPressEvent( QKeyEvent *event )
601 {
602  switch ( event->key() )
603  {
604  case Qt::Key_Return:
605  case Qt::Key_Enter:
606  case Qt::Key_Space:
607  {
608  QTreeWidgetItem *item = currentItem();
609  if ( item && !item->parent() )
610  {
611  event->accept();
612  toggleContextExpanded( item );
613  return;
614  }
615  else if ( item && ( item->flags() & Qt::ItemIsEditable ) )
616  {
617  event->accept();
618  editNext( currentIndex() );
619  return;
620  }
621  break;
622  }
623  default:
624  break;
625  }
626  QTreeWidget::keyPressEvent( event );
627 }
628 
629 void QgsVariableEditorTree::mousePressEvent( QMouseEvent *event )
630 {
631  QTreeWidget::mousePressEvent( event );
632  QTreeWidgetItem *item = itemAt( event->pos() );
633  if ( !item )
634  return;
635 
636  if ( item->parent() )
637  {
638  //not a top-level item
639  return;
640  }
641 
642  if ( event->pos().x() + header()->offset() > 20 )
643  {
644  //not clicking on expand icon
645  return;
646  }
647 
648  if ( event->modifiers() & Qt::ShiftModifier )
649  {
650  //shift modifier expands all
651  if ( !item->isExpanded() )
652  {
653  expandAll();
654  }
655  else
656  {
657  collapseAll();
658  }
659  }
660  else
661  {
662  toggleContextExpanded( item );
663  }
664 }
665 
666 //
667 // VariableEditorDelegate
668 //
669 
670 QWidget *VariableEditorDelegate::createEditor( QWidget *parent,
671  const QStyleOptionViewItem &,
672  const QModelIndex &index ) const
673 {
674  if ( !mParentTree )
675  return nullptr;
676 
677  //no editing for top level items
678  if ( !index.parent().isValid() )
679  return nullptr;
680 
681  QTreeWidgetItem *item = mParentTree->indexToItem( index );
682  QgsExpressionContextScope *scope = mParentTree->scopeFromItem( item );
683  if ( !item || !scope )
684  return nullptr;
685 
686  QString variableName = mParentTree->variableNameFromIndex( index );
687 
688  //no editing inherited or read-only variables
689  if ( scope != mParentTree->editableScope() || scope->isReadOnly( variableName ) )
690  return nullptr;
691 
692  QLineEdit *lineEdit = new QLineEdit( parent );
693  lineEdit->setText( index.column() == 0 ? variableName : mParentTree->editableScope()->variable( variableName ).toString() );
694  lineEdit->setAutoFillBackground( true );
695  return lineEdit;
696 }
697 
698 void VariableEditorDelegate::updateEditorGeometry( QWidget *editor,
699  const QStyleOptionViewItem &option,
700  const QModelIndex & ) const
701 {
702  editor->setGeometry( option.rect.adjusted( 0, 0, 0, -1 ) );
703 }
704 
705 QSize VariableEditorDelegate::sizeHint( const QStyleOptionViewItem &option,
706  const QModelIndex &index ) const
707 {
708  return QItemDelegate::sizeHint( option, index ) + QSize( 3, 4 );
709 }
710 
711 void VariableEditorDelegate::setModelData( QWidget *widget, QAbstractItemModel *model,
712  const QModelIndex &index ) const
713 {
714  Q_UNUSED( model );
715 
716  if ( !mParentTree )
717  return;
718 
719  QTreeWidgetItem *item = mParentTree->indexToItem( index );
720  QgsExpressionContextScope *scope = mParentTree->scopeFromItem( item );
721  if ( !item || !scope )
722  return;
723 
724  QLineEdit *lineEdit = qobject_cast< QLineEdit * >( widget );
725  if ( !lineEdit )
726  return;
727 
728  QString variableName = mParentTree->variableNameFromIndex( index );
729  if ( index.column() == 0 )
730  {
731  //edited variable name
732  QString newName = lineEdit->text();
733  newName = newName.trimmed();
734  newName = newName.replace( ' ', '_' );
735 
736  //test for validity
737  if ( newName == variableName )
738  {
739  return;
740  }
741  if ( scope->hasVariable( newName ) )
742  {
743  //existing name
744  QMessageBox::warning( mParentTree, tr( "Rename Variable" ), tr( "A variable with the name \"%1\" already exists in this context." ).arg( newName ) );
745  newName.append( "_1" );
746  }
747 
748  QString value = scope->variable( variableName ).toString();
749  mParentTree->renameItem( item, newName );
750  scope->removeVariable( variableName );
751  scope->setVariable( newName, value );
752  mParentTree->emitChanged();
753  }
754  else if ( index.column() == 1 )
755  {
756  //edited variable value
757  QString value = lineEdit->text();
758  if ( scope->variable( variableName ).toString() == value )
759  {
760  return;
761  }
762  scope->setVariable( variableName, value );
763  mParentTree->emitChanged();
764  }
765  mParentTree->refreshTree();
766 }
767 
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.
static QString formatPreviewString(const QVariant &value, bool htmlOutput=true)
Formats an expression result for friendly display to the user.
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.