QGIS API Documentation  3.14.0-Pi (9f7028fd23)
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 #include <QClipboard>
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
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  const auto constVariableNames = scope->variableNames();
145  for ( const QString &variable : constVariableNames )
146  {
147  if ( scope->isReadOnly( variable ) )
148  continue;
149 
150  variables.insert( variable, scope->variable( variable ) );
151  }
152 
153  return variables;
154 }
155 
156 QString QgsVariableEditorWidget::saveKey() const
157 {
158  // save key for load/save state
159  // currently QgsVariableEditorTree/window()/object
160  QString setGroup = mSettingGroup.isEmpty() ? objectName() : mSettingGroup;
161  QString saveKey = "/QgsVariableEditorTree/" + setGroup + '/';
162  return saveKey;
163 }
164 
165 void QgsVariableEditorWidget::mAddButton_clicked()
166 {
167  if ( mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
168  return;
169 
170  QgsExpressionContextScope *scope = mContext->scope( mEditableScopeIndex );
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 );
177 
178  emit scopeChanged();
179 }
180 
181 void QgsVariableEditorWidget::mRemoveButton_clicked()
182 {
183  if ( mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
184  return;
185 
186  QgsExpressionContextScope *editableScope = mContext->scope( mEditableScopeIndex );
187  QList<QTreeWidgetItem *> selectedItems = mTreeWidget->selectedItems();
188 
189  const auto constSelectedItems = selectedItems;
190  for ( QTreeWidgetItem *item : constSelectedItems )
191  {
192  if ( !( item->flags() & Qt::ItemIsEditable ) )
193  continue;
194 
195  QString name = item->text( 0 );
196  QgsExpressionContextScope *itemScope = mTreeWidget->scopeFromItem( item );
197  if ( itemScope != editableScope )
198  continue;
199 
200  if ( itemScope->isReadOnly( name ) )
201  continue;
202 
203  itemScope->removeVariable( name );
204  mTreeWidget->removeItem( item );
205  }
206  mTreeWidget->refreshTree();
207 }
208 
209 void QgsVariableEditorWidget::selectionChanged()
210 {
211  if ( mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
212  {
213  mRemoveButton->setEnabled( false );
214  return;
215  }
216 
217  QgsExpressionContextScope *editableScope = mContext->scope( mEditableScopeIndex );
218  QList<QTreeWidgetItem *> selectedItems = mTreeWidget->selectedItems();
219 
220  bool removeEnabled = true;
221  const auto constSelectedItems = selectedItems;
222  for ( QTreeWidgetItem *item : constSelectedItems )
223  {
224  if ( !( item->flags() & Qt::ItemIsEditable ) )
225  {
226  removeEnabled = false;
227  break;
228  }
229 
230  QString name = item->text( 0 );
231  QgsExpressionContextScope *itemScope = mTreeWidget->scopeFromItem( item );
232  if ( itemScope != editableScope )
233  {
234  removeEnabled = false;
235  break;
236  }
237 
238  if ( editableScope->isReadOnly( name ) )
239  {
240  removeEnabled = false;
241  break;
242  }
243  }
244  mRemoveButton->setEnabled( removeEnabled );
245 }
246 
247 
249 //
250 // VariableEditorTree
251 //
252 
253 QgsVariableEditorTree::QgsVariableEditorTree( QWidget *parent )
254  : QTreeWidget( parent )
255 {
256  // init icons
257  if ( mExpandIcon.isNull() )
258  {
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 );
265  }
266 
267  setIconSize( QSize( 18, 18 ) );
268  setColumnCount( 2 );
269  setHeaderLabels( QStringList() << tr( "Variable" ) << tr( "Value" ) );
270  setEditTriggers( QAbstractItemView::AllEditTriggers );
271  setRootIsDecorated( false );
272  header()->setSectionsMovable( false );
273  header()->setSectionResizeMode( QHeaderView::Interactive );
274 
275  mEditorDelegate = new VariableEditorDelegate( this, this );
276  setItemDelegate( mEditorDelegate );
277 }
278 
279 QgsExpressionContextScope *QgsVariableEditorTree::scopeFromItem( QTreeWidgetItem *item ) const
280 {
281  if ( !item )
282  return nullptr;
283 
284  bool ok;
285  int contextIndex = item->data( 0, ContextIndex ).toInt( &ok );
286  if ( !ok )
287  return nullptr;
288 
289  if ( !mContext )
290  {
291  return nullptr;
292  }
293  else if ( mContext->scopeCount() > contextIndex )
294  {
295  return mContext->scope( contextIndex );
296  }
297  else
298  {
299  return nullptr;
300  }
301 }
302 
303 QTreeWidgetItem *QgsVariableEditorTree::itemFromVariable( QgsExpressionContextScope *scope, const QString &name ) const
304 {
305  int contextIndex = mContext ? mContext->indexOfScope( scope ) : 0;
306  if ( contextIndex < 0 )
307  return nullptr;
308  return mVariableToItem.value( qMakePair( contextIndex, name ) );
309 }
310 
311 QgsExpressionContextScope *QgsVariableEditorTree::editableScope()
312 {
313  if ( !mContext || mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
314  {
315  return nullptr;
316  }
317 
318  return mContext->scope( mEditableScopeIndex );
319 }
320 
321 void QgsVariableEditorTree::refreshTree()
322 {
323  if ( !mContext || mEditableScopeIndex < 0 )
324  {
325  clear();
326  return;
327  }
328 
329  //add all scopes from the context
330  int scopeIndex = 0;
331  const auto constScopes = mContext->scopes();
332  for ( QgsExpressionContextScope *scope : constScopes )
333  {
334  refreshScopeItems( scope, scopeIndex );
335  scopeIndex++;
336  }
337 }
338 
339 void QgsVariableEditorTree::refreshScopeVariables( QgsExpressionContextScope *scope, int scopeIndex )
340 {
341  QColor baseColor = rowColor( scopeIndex );
342  bool isCurrent = scopeIndex == mEditableScopeIndex;
343  QTreeWidgetItem *scopeItem = mScopeToItem.value( scopeIndex );
344 
345  const QStringList names = scope->filteredVariableNames();
346  for ( const QString &name : names )
347  {
348  QTreeWidgetItem *item = mVariableToItem.value( qMakePair( scopeIndex, name ) );
349  if ( !item )
350  {
351  item = new QTreeWidgetItem( scopeItem );
352  mVariableToItem.insert( qMakePair( scopeIndex, name ), item );
353  }
354 
355  bool readOnly = scope->isReadOnly( name );
356  bool isActive = true;
357  QgsExpressionContextScope *activeScope = nullptr;
358  if ( mContext )
359  {
360  activeScope = mContext->activeScopeForVariable( name );
361  isActive = activeScope == scope;
362  }
363 
364  item->setFlags( item->flags() | Qt::ItemIsEnabled );
365  item->setText( 0, name );
366  const QVariant value = scope->variable( name );
367  const QString previewString = QgsExpression::formatPreviewString( value, false );
368  item->setText( 1, previewString );
369  QFont font = item->font( 0 );
370  if ( readOnly || !isCurrent )
371  {
372  font.setItalic( true );
373  item->setFlags( item->flags() ^ Qt::ItemIsEditable );
374  }
375  else
376  {
377  font.setItalic( false );
378  item->setFlags( item->flags() | Qt::ItemIsEditable );
379  }
380  if ( !isActive )
381  {
382  //overridden
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 );
387  }
388  else
389  {
390  font.setStrikeOut( false );
391  item->setToolTip( 0, name );
392  item->setToolTip( 1, previewString );
393  }
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 );
399  }
400 }
401 
402 void QgsVariableEditorTree::refreshScopeItems( QgsExpressionContextScope *scope, int scopeIndex )
403 {
404  QgsSettings settings;
405 
406  //add top level item
407  bool isCurrent = scopeIndex == mEditableScopeIndex;
408 
409  QTreeWidgetItem *scopeItem = nullptr;
410  if ( mScopeToItem.contains( scopeIndex ) )
411  {
412  //retrieve existing item
413  scopeItem = mScopeToItem.value( scopeIndex );
414  }
415  else
416  {
417  //create new top-level item
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 );
428 
429  addTopLevelItem( scopeItem );
430 
431  //expand by default if current context or context was previously expanded
432  if ( isCurrent || settings.value( "QgsVariableEditor/" + scopeItem->text( 0 ) + "/expanded" ).toBool() )
433  scopeItem->setExpanded( true );
434 
435  scopeItem->setIcon( 0, mExpandIcon );
436  }
437 
438  refreshScopeVariables( scope, scopeIndex );
439 }
440 
441 void QgsVariableEditorTree::removeItem( QTreeWidgetItem *item )
442 {
443  if ( !item )
444  return;
445 
446  mVariableToItem.remove( mVariableToItem.key( item ) );
447  item->parent()->takeChild( item->parent()->indexOfChild( item ) );
448 
449  emit scopeChanged();
450 }
451 
452 void QgsVariableEditorTree::renameItem( QTreeWidgetItem *item, const QString &name )
453 {
454  if ( !item )
455  return;
456 
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 );
461 
462  emit scopeChanged();
463 }
464 
465 void QgsVariableEditorTree::resetTree()
466 {
467  mVariableToItem.clear();
468  mScopeToItem.clear();
469  clear();
470 }
471 
472 void QgsVariableEditorTree::emitChanged()
473 {
474  emit scopeChanged();
475 }
476 
477 void QgsVariableEditorTree::drawRow( QPainter *painter, const QStyleOptionViewItem &option,
478  const QModelIndex &index ) const
479 {
480  QStyleOptionViewItem opt = option;
481  QTreeWidgetItem *item = itemFromIndex( index );
482  if ( index.parent().isValid() )
483  {
484  //not a top-level item, so shade row background by context
485  QColor baseColor = item->data( 0, RowBaseColor ).value<QColor>();
486  if ( index.row() % 2 == 1 )
487  {
488  baseColor.setAlpha( 59 );
489  }
490  painter->fillRect( option.rect, baseColor );
491  }
492  QTreeWidget::drawRow( painter, opt, index );
493  QColor color = static_cast<QRgb>( QApplication::style()->styleHint( QStyle::SH_Table_GridLineColor, &opt ) );
494  painter->save();
495  painter->setPen( QPen( color ) );
496  painter->drawLine( opt.rect.x(), opt.rect.bottom(), opt.rect.right(), opt.rect.bottom() );
497  painter->restore();
498 }
499 
500 QColor QgsVariableEditorTree::rowColor( int index ) const
501 {
502  //return some nice (inspired by Qt Designer) background row colors
503  int colorIdx = index % 6;
504  switch ( colorIdx )
505  {
506  case 0:
507  return QColor( 255, 163, 0, 89 );
508  case 1:
509  return QColor( 255, 255, 77, 89 );
510  case 2:
511  return QColor( 0, 255, 77, 89 );
512  case 3:
513  return QColor( 0, 255, 255, 89 );
514  case 4:
515  return QColor( 196, 125, 255, 89 );
516  case 5:
517  default:
518  return QColor( 255, 125, 225, 89 );
519  }
520 }
521 
522 void QgsVariableEditorTree::toggleContextExpanded( QTreeWidgetItem *item )
523 {
524  if ( !item )
525  return;
526 
527  item->setExpanded( !item->isExpanded() );
528 
529  //save expanded state
530  QgsSettings settings;
531  settings.setValue( "QgsVariableEditor/" + item->text( 0 ) + "/expanded", item->isExpanded() );
532 }
533 
534 void QgsVariableEditorTree::editNext( const QModelIndex &index )
535 {
536  if ( !index.isValid() )
537  return;
538 
539  if ( index.column() == 0 )
540  {
541  //switch to next column
542  QModelIndex nextIndex = index.sibling( index.row(), 1 );
543  if ( nextIndex.isValid() )
544  {
545  setCurrentIndex( nextIndex );
546  edit( nextIndex );
547  }
548  }
549  else
550  {
551  QModelIndex nextIndex = model()->index( index.row() + 1, 0, index.parent() );
552  if ( nextIndex.isValid() )
553  {
554  //start editing next row
555  setCurrentIndex( nextIndex );
556  edit( nextIndex );
557  }
558  else
559  {
560  edit( index );
561  }
562  }
563 }
564 
565 QModelIndex QgsVariableEditorTree::moveCursor( QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers )
566 {
567  if ( cursorAction == QAbstractItemView::MoveNext )
568  {
569  QModelIndex index = currentIndex();
570  if ( index.isValid() )
571  {
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 );
576  else
577  return QModelIndex();
578  }
579  }
580  else if ( cursorAction == QAbstractItemView::MovePrevious )
581  {
582  QModelIndex index = currentIndex();
583  if ( index.isValid() )
584  {
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 );
589  else
590  return QModelIndex();
591  }
592  }
593 
594  return QTreeWidget::moveCursor( cursorAction, modifiers );
595 }
596 
597 void QgsVariableEditorTree::keyPressEvent( QKeyEvent *event )
598 {
599  switch ( event->key() )
600  {
601  case Qt::Key_Return:
602  case Qt::Key_Enter:
603  case Qt::Key_Space:
604  {
605  QTreeWidgetItem *item = currentItem();
606  if ( item && !item->parent() )
607  {
608  event->accept();
609  toggleContextExpanded( item );
610  return;
611  }
612  else if ( item && ( item->flags() & Qt::ItemIsEditable ) )
613  {
614  event->accept();
615  editNext( currentIndex() );
616  return;
617  }
618  break;
619  }
620  default:
621  break;
622  }
623 
624  if ( event == QKeySequence::Copy )
625  {
626  QList<QTreeWidgetItem *> selected = selectedItems();
627  if ( selected.size() > 0 )
628  {
629  QString text = selected.at( 0 )->text( 0 );
630  QString varName = variableNameFromItem( selected.at( 0 ) );
631  QgsExpressionContextScope *scope = scopeFromItem( selected.at( 0 ) );
632  if ( !varName.isEmpty() && scope )
633  text = scope->variable( varName ).toString();
634 
635  QClipboard *clipboard = QApplication::clipboard();
636  clipboard->setText( text );
637  event->accept();
638  return;
639  }
640  }
641 
642  QTreeWidget::keyPressEvent( event );
643 }
644 
645 void QgsVariableEditorTree::mousePressEvent( QMouseEvent *event )
646 {
647  QTreeWidget::mousePressEvent( event );
648  QTreeWidgetItem *item = itemAt( event->pos() );
649  if ( !item )
650  return;
651 
652  if ( item->parent() )
653  {
654  //not a top-level item
655  return;
656  }
657 
658  if ( event->pos().x() + header()->offset() > 20 )
659  {
660  //not clicking on expand icon
661  return;
662  }
663 
664  if ( event->modifiers() & Qt::ShiftModifier )
665  {
666  //shift modifier expands all
667  if ( !item->isExpanded() )
668  {
669  expandAll();
670  }
671  else
672  {
673  collapseAll();
674  }
675  }
676  else
677  {
678  toggleContextExpanded( item );
679  }
680 }
681 
682 //
683 // VariableEditorDelegate
684 //
685 
686 QWidget *VariableEditorDelegate::createEditor( QWidget *parent,
687  const QStyleOptionViewItem &,
688  const QModelIndex &index ) const
689 {
690  if ( !mParentTree )
691  return nullptr;
692 
693  //no editing for top level items
694  if ( !index.parent().isValid() )
695  return nullptr;
696 
697  QTreeWidgetItem *item = mParentTree->indexToItem( index );
698  QgsExpressionContextScope *scope = mParentTree->scopeFromItem( item );
699  if ( !item || !scope )
700  return nullptr;
701 
702  QString variableName = mParentTree->variableNameFromIndex( index );
703 
704  //no editing inherited or read-only variables
705  if ( scope != mParentTree->editableScope() || scope->isReadOnly( variableName ) )
706  return nullptr;
707 
708  QLineEdit *lineEdit = new QLineEdit( parent );
709  lineEdit->setText( index.column() == 0 ? variableName : mParentTree->editableScope()->variable( variableName ).toString() );
710  lineEdit->setAutoFillBackground( true );
711  return lineEdit;
712 }
713 
714 void VariableEditorDelegate::updateEditorGeometry( QWidget *editor,
715  const QStyleOptionViewItem &option,
716  const QModelIndex & ) const
717 {
718  editor->setGeometry( option.rect.adjusted( 0, 0, 0, -1 ) );
719 }
720 
721 QSize VariableEditorDelegate::sizeHint( const QStyleOptionViewItem &option,
722  const QModelIndex &index ) const
723 {
724  return QItemDelegate::sizeHint( option, index ) + QSize( 3, 4 );
725 }
726 
727 void VariableEditorDelegate::setModelData( QWidget *widget, QAbstractItemModel *model,
728  const QModelIndex &index ) const
729 {
730  Q_UNUSED( model )
731 
732  if ( !mParentTree )
733  return;
734 
735  QTreeWidgetItem *item = mParentTree->indexToItem( index );
736  QgsExpressionContextScope *scope = mParentTree->scopeFromItem( item );
737  if ( !item || !scope )
738  return;
739 
740  QLineEdit *lineEdit = qobject_cast< QLineEdit * >( widget );
741  if ( !lineEdit )
742  return;
743 
744  QString variableName = mParentTree->variableNameFromIndex( index );
745  if ( index.column() == 0 )
746  {
747  //edited variable name
748  QString newName = lineEdit->text();
749  newName = newName.trimmed();
750  newName = newName.replace( ' ', '_' );
751 
752  //test for validity
753  if ( newName == variableName )
754  {
755  return;
756  }
757  if ( scope->hasVariable( newName ) )
758  {
759  //existing name
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" );
762  }
763 
764  QString value = scope->variable( variableName ).toString();
765  mParentTree->renameItem( item, newName );
766  scope->removeVariable( variableName );
767  scope->setVariable( newName, value );
768  mParentTree->emitChanged();
769  }
770  else if ( index.column() == 1 )
771  {
772  //edited variable value
773  QString value = lineEdit->text();
774  if ( scope->variable( variableName ).toString() == value )
775  {
776  return;
777  }
778  scope->setVariable( variableName, value );
779  mParentTree->emitChanged();
780  }
781  mParentTree->refreshTree();
782 }
783 
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:369
QgsVariableEditorWidget::variablesInActiveScope
QVariantMap variablesInActiveScope() const
Returns a map variables set within the editable scope.
Definition: qgsvariableeditorwidget.cpp:135
QgsVariableEditorWidget::context
QgsExpressionContext * context() const
Returns the current expression context for the widget.
Definition: qgsvariableeditorwidget.h:72
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Definition: qgsapplication.cpp:605
QgsExpressionContextScope::setVariable
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.
Definition: qgsexpressioncontext.cpp:78
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:174
QgsVariableEditorWidget::showEvent
void showEvent(QShowEvent *event) override
Definition: qgsvariableeditorwidget.cpp:78
qgsexpression.h
QgsVariableEditorWidget::setEditableScopeIndex
void setEditableScopeIndex(int scopeIndex)
Sets the editable scope for the widget.
Definition: qgsvariableeditorwidget.cpp:115
QgsVariableEditorWidget::editableScope
QgsExpressionContextScope * editableScope() const
Returns the current editable scope for the widget.
Definition: qgsvariableeditorwidget.cpp:126
QgsSettings
Definition: qgssettings.h:61
QgsExpressionContextScope::hasVariable
bool hasVariable(const QString &name) const
Tests whether a variable with the specified name exists in the scope.
Definition: qgsexpressioncontext.cpp:103
QgsVariableEditorWidget::~QgsVariableEditorWidget
~QgsVariableEditorWidget() override
Definition: qgsvariableeditorwidget.cpp:72
QgsVariableEditorWidget::scopeChanged
void scopeChanged()
Emitted when the user has modified a scope using the widget.
QgsExpressionContextScope::variableNames
QStringList variableNames() const
Returns a list of variable names contained within the scope.
Definition: qgsexpressioncontext.cpp:113
qgsapplication.h
QgsExpression::formatPreviewString
static QString formatPreviewString(const QVariant &value, bool htmlOutput=true)
Formats an expression result for friendly display to the user.
Definition: qgsexpression.cpp:941
qgsexpressioncontext.h
QgsVariableEditorWidget::QgsVariableEditorWidget
QgsVariableEditorWidget(QWidget *parent=nullptr)
Constructor for QgsVariableEditorWidget.
Definition: qgsvariableeditorwidget.cpp:37
QgsSettings::setValue
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Definition: qgssettings.cpp:289
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext....
Definition: qgsexpressioncontext.h:111
QgsVariableEditorWidget::setContext
void setContext(QgsExpressionContext *context)
Overwrites the QgsExpressionContext for the widget.
Definition: qgsvariableeditorwidget.cpp:102
QgsExpressionContextScope::filteredVariableNames
QStringList filteredVariableNames() const
Returns a filtered and sorted list of variable names contained within the scope.
Definition: qgsexpressioncontext.cpp:141
QgsExpressionContextScope::variable
QVariant variable(const QString &name) const
Retrieves a variable's value from the scope.
Definition: qgsexpressioncontext.cpp:108
qgssettings.h
qgsvariableeditorwidget.h
QgsExpressionContextScope::isReadOnly
bool isReadOnly(const QString &name) const
Tests whether the specified variable is read only and should not be editable by users.
Definition: qgsexpressioncontext.cpp:159
QgsVariableEditorWidget::reloadContext
void reloadContext()
Reloads all scopes from the editor's current context.
Definition: qgsvariableeditorwidget.cpp:108
QgsExpressionContextScope::name
QString name() const
Returns the friendly display name of the context scope.
Definition: qgsexpressioncontext.h:171
QgsExpressionContextScope::removeVariable
bool removeVariable(const QString &name)
Removes a variable from the context scope, if found.
Definition: qgsexpressioncontext.cpp:98