QGIS API Documentation  2.12.0-Lyon
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 <QVBoxLayout>
21 #include <QTreeWidget>
22 #include <QPainter>
23 #include <QKeyEvent>
24 #include <QMouseEvent>
25 #include <QLineEdit>
26 #include <QPushButton>
27 #include <QHeaderView>
28 #include <QMessageBox>
29 #include <QSettings>
30 
32 
33 class VariableEditorDelegate : public QItemDelegate
34 {
35 
36  public:
37  VariableEditorDelegate( QObject *parent = 0, QgsVariableEditorTree *tree = 0 )
38  : QItemDelegate( parent )
39  , mParentTree( tree )
40  {}
41 
42  QWidget *createEditor( QWidget *parent, const QStyleOptionViewItem &option,
43  const QModelIndex &index ) const override;
44  void updateEditorGeometry( QWidget *editor, const QStyleOptionViewItem &option,
45  const QModelIndex &index ) const override;
46  QSize sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const override;
47  void setModelData( QWidget* widget, QAbstractItemModel* model,
48  const QModelIndex & index ) const override;
49  void setEditorData( QWidget *, const QModelIndex & ) const override {}
50 
51  private:
52  QgsVariableEditorTree *mParentTree;
53 };
54 
55 QIcon QgsVariableEditorTree::mExpandIcon;
56 
57 //
58 // QgsVariableEditorWidget
59 //
60 
62  : QWidget( parent )
63  , mContext( 0 )
64  , mEditableScopeIndex( -1 )
65  , mShown( false )
66 {
67  QVBoxLayout* verticalLayout = new QVBoxLayout( this );
68  verticalLayout->setSpacing( 3 );
69  verticalLayout->setContentsMargins( 3, 3, 3, 3 );
70  mTreeWidget = new QgsVariableEditorTree( this );
71  mTreeWidget->setSelectionMode( QAbstractItemView::SingleSelection );
72  verticalLayout->addWidget( mTreeWidget );
73  QHBoxLayout* horizontalLayout = new QHBoxLayout();
74  horizontalLayout->setSpacing( 6 );
75  QSpacerItem* horizontalSpacer = new QSpacerItem( 40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum );
76  horizontalLayout->addItem( horizontalSpacer );
77  mAddButton = new QPushButton();
78  mAddButton->setIcon( QgsApplication::getThemeIcon( "/symbologyAdd.svg" ) );
79  mAddButton->setEnabled( false );
80  horizontalLayout->addWidget( mAddButton );
81  mRemoveButton = new QPushButton();
82  mRemoveButton->setIcon( QgsApplication::getThemeIcon( "/symbologyRemove.svg" ) );
83  mRemoveButton->setEnabled( false );
84  horizontalLayout->addWidget( mRemoveButton );
85  verticalLayout->addLayout( horizontalLayout );
86  connect( mRemoveButton, SIGNAL( clicked() ), this, SLOT( on_mRemoveButton_clicked() ) );
87  connect( mAddButton, SIGNAL( clicked() ), this, SLOT( on_mAddButton_clicked() ) );
88  connect( mTreeWidget, SIGNAL( itemSelectionChanged() ), this, SLOT( selectionChanged() ) );
89  connect( mTreeWidget, SIGNAL( scopeChanged() ), this, SIGNAL( scopeChanged() ) );
90 
91  //setContext clones context
93  setContext( context );
94  delete context;
95 }
96 
98 {
99  QSettings settings;
100  settings.setValue( saveKey() + "column0width", mTreeWidget->header()->sectionSize( 0 ) );
101 }
102 
104 {
105  // initialise widget on first show event only
106  if ( mShown )
107  {
108  event->accept();
109  return;
110  }
111 
112  //restore split size
113  QSettings settings;
114  QVariant val;
115  val = settings.value( saveKey() + "column0width" );
116  bool ok;
117  int sectionSize = val.toInt( &ok );
118  if ( ok )
119  {
120  mTreeWidget->header()->resizeSection( 0, sectionSize );
121  }
122  mShown = true;
123 
124  QWidget::showEvent( event );
125 }
126 
128 {
129  mContext.reset( new QgsExpressionContext( *context ) );
130  reloadContext();
131 }
132 
134 {
135  mTreeWidget->resetTree();
136  mTreeWidget->setContext( mContext.data() );
137  mTreeWidget->refreshTree();
138 }
139 
141 {
142  mEditableScopeIndex = scopeIndex;
143  if ( mEditableScopeIndex >= 0 )
144  {
145  mAddButton->setEnabled( true );
146  }
147  mTreeWidget->setEditableScopeIndex( scopeIndex );
148  mTreeWidget->refreshTree();
149 }
150 
152 {
153  if ( !mContext || mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
154  {
155  return 0;
156  }
157  return mContext->scope( mEditableScopeIndex );
158 }
159 
161 {
162  QgsStringMap variables;
163  if ( !mContext || mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
164  {
165  return variables;
166  }
167 
168  QgsExpressionContextScope* scope = mContext->scope( mEditableScopeIndex );
169  Q_FOREACH ( const QString& variable, scope->variableNames() )
170  {
171  if ( scope->isReadOnly( variable ) )
172  continue;
173 
174  variables.insert( variable, scope->variable( variable ).toString() );
175  }
176 
177  return variables;
178 }
179 
180 QString QgsVariableEditorWidget::saveKey() const
181 {
182  // save key for load/save state
183  // currently QgsVariableEditorTree/window()/object
184  QString setGroup = mSettingGroup.isEmpty() ? objectName() : mSettingGroup;
185  QString saveKey = "/QgsVariableEditorTree/" + setGroup + "/";
186  return saveKey;
187 }
188 
189 void QgsVariableEditorWidget::on_mAddButton_clicked()
190 {
191  if ( mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
192  return;
193 
194  QgsExpressionContextScope* scope = mContext->scope( mEditableScopeIndex );
195  scope->setVariable( "new_variable", QVariant() );
196  mTreeWidget->refreshTree();
197  QTreeWidgetItem* item = mTreeWidget->itemFromVariable( scope, "new_variable" );
198  QModelIndex index = mTreeWidget->itemToIndex( item );
199  mTreeWidget->selectionModel()->select( index, QItemSelectionModel::ClearAndSelect );
200  mTreeWidget->editItem( item, 0 );
201 
202  emit scopeChanged();
203 }
204 
205 void QgsVariableEditorWidget::on_mRemoveButton_clicked()
206 {
207  if ( mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
208  return;
209 
210  QgsExpressionContextScope* editableScope = mContext->scope( mEditableScopeIndex );
211  QList<QTreeWidgetItem*> selectedItems = mTreeWidget->selectedItems();
212 
213  Q_FOREACH ( QTreeWidgetItem* item, selectedItems )
214  {
215  if ( !( item->flags() & Qt::ItemIsEditable ) )
216  continue;
217 
218  QString name = item->text( 0 );
219  QgsExpressionContextScope* itemScope = mTreeWidget->scopeFromItem( item );
220  if ( itemScope != editableScope )
221  continue;
222 
223  if ( itemScope->isReadOnly( name ) )
224  continue;
225 
226  itemScope->removeVariable( name );
227  mTreeWidget->removeItem( item );
228  }
229  mTreeWidget->refreshTree();
230 }
231 
232 void QgsVariableEditorWidget::selectionChanged()
233 {
234  if ( mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
235  {
236  mRemoveButton->setEnabled( false );
237  return;
238  }
239 
240  QgsExpressionContextScope* editableScope = mContext->scope( mEditableScopeIndex );
241  QList<QTreeWidgetItem*> selectedItems = mTreeWidget->selectedItems();
242 
243  bool removeEnabled = true;
244  Q_FOREACH ( QTreeWidgetItem* item, selectedItems )
245  {
246  if ( !( item->flags() & Qt::ItemIsEditable ) )
247  {
248  removeEnabled = false;
249  break;
250  }
251 
252  QString name = item->text( 0 );
253  QgsExpressionContextScope* itemScope = mTreeWidget->scopeFromItem( item );
254  if ( itemScope != editableScope )
255  {
256  removeEnabled = false;
257  break;
258  }
259 
260  if ( editableScope->isReadOnly( name ) )
261  {
262  removeEnabled = false;
263  break;
264  }
265  }
266  mRemoveButton->setEnabled( removeEnabled );
267 }
268 
269 
270 //
271 // VariableEditorTree
272 //
273 
274 QgsVariableEditorTree::QgsVariableEditorTree( QWidget *parent )
275  : QTreeWidget( parent )
276  , mEditorDelegate( 0 )
277  , mEditableScopeIndex( -1 )
278  , mContext( 0 )
279 {
280  // init icons
281  if ( mExpandIcon.isNull() )
282  {
283  QPixmap pix( 14, 14 );
284  pix.fill( Qt::transparent );
285  mExpandIcon.addPixmap( QgsApplication::getThemeIcon( "/mIconExpandSmall.svg" ).pixmap( 14, 14 ), QIcon::Normal, QIcon::Off );
286  mExpandIcon.addPixmap( QgsApplication::getThemeIcon( "/mIconExpandSmall.svg" ).pixmap( 14, 14 ), QIcon::Selected, QIcon::Off );
287  mExpandIcon.addPixmap( QgsApplication::getThemeIcon( "/mIconCollapseSmall.svg" ).pixmap( 14, 14 ), QIcon::Normal, QIcon::On );
288  mExpandIcon.addPixmap( QgsApplication::getThemeIcon( "/mIconCollapseSmall.svg" ).pixmap( 14, 14 ), QIcon::Selected, QIcon::On );
289  }
290 
291  setIconSize( QSize( 18, 18 ) );
292  setColumnCount( 2 );
293  setHeaderLabels( QStringList() << tr( "Variable" ) << tr( "Value" ) );
294  setAlternatingRowColors( true );
295  setEditTriggers( QAbstractItemView::AllEditTriggers );
296  setRootIsDecorated( false );
297  header()->setMovable( false );
298  header()->setResizeMode( QHeaderView::Interactive );
299 
300  mEditorDelegate = new VariableEditorDelegate( this, this );
301  setItemDelegate( mEditorDelegate );
302 }
303 
304 QgsExpressionContextScope* QgsVariableEditorTree::scopeFromItem( QTreeWidgetItem *item ) const
305 {
306  if ( !item )
307  return 0;
308 
309  bool ok;
310  int contextIndex = item->data( 0, ContextIndex ).toInt( &ok );
311  if ( !ok )
312  return 0;
313 
314  if ( !mContext )
315  {
316  return 0;
317  }
318  else if ( mContext->scopeCount() > contextIndex )
319  {
320  return mContext->scope( contextIndex );
321  }
322  else
323  {
324  return 0;
325  }
326 }
327 
328 QTreeWidgetItem* QgsVariableEditorTree::itemFromVariable( QgsExpressionContextScope *scope, const QString &name ) const
329 {
330  int contextIndex = mContext ? mContext->indexOfScope( scope ) : 0;
331  if ( contextIndex < 0 )
332  return 0;
333  return mVariableToItem.value( qMakePair( contextIndex, name ) );
334 }
335 
336 QgsExpressionContextScope* QgsVariableEditorTree::editableScope()
337 {
338  if ( !mContext || mEditableScopeIndex < 0 || mEditableScopeIndex >= mContext->scopeCount() )
339  {
340  return 0;
341  }
342 
343  return mContext->scope( mEditableScopeIndex );
344 }
345 
346 void QgsVariableEditorTree::refreshTree()
347 {
348  if ( !mContext || mEditableScopeIndex < 0 )
349  {
350  clear();
351  return;
352  }
353 
354  //add all scopes from the context
355  int scopeIndex = 0;
356  Q_FOREACH ( QgsExpressionContextScope* scope, mContext->scopes() )
357  {
358  refreshScopeItems( scope, scopeIndex );
359  scopeIndex++;
360  }
361 }
362 
363 void QgsVariableEditorTree::refreshScopeVariables( QgsExpressionContextScope* scope, int scopeIndex )
364 {
365  QColor baseColor = rowColor( scopeIndex );
366  bool isCurrent = scopeIndex == mEditableScopeIndex;
367  QTreeWidgetItem* scopeItem = mScopeToItem.value( scopeIndex );
368 
369  Q_FOREACH ( const QString& name, scope->filteredVariableNames() )
370  {
371  QTreeWidgetItem* item;
372  if ( mVariableToItem.contains( qMakePair( scopeIndex, name ) ) )
373  {
374  item = mVariableToItem.value( qMakePair( scopeIndex, name ) );
375  }
376  else
377  {
378  item = new QTreeWidgetItem( scopeItem );
379  mVariableToItem.insert( qMakePair( scopeIndex, name ), item );
380  }
381 
382  bool readOnly = scope->isReadOnly( name );
383  bool isActive = true;
384  QgsExpressionContextScope* activeScope = 0;
385  if ( mContext )
386  {
387  activeScope = mContext->activeScopeForVariable( name );
388  isActive = activeScope == scope;
389  }
390 
391  item->setFlags( item->flags() | Qt::ItemIsEnabled );
392  item->setText( 0, name );
393  QString value = scope->variable( name ).toString();
394  item->setText( 1, value );
395  QFont font = item->font( 0 );
396  if ( readOnly || !isCurrent )
397  {
398  font.setItalic( true );
399  item->setFlags( item->flags() ^ Qt::ItemIsEditable );
400  }
401  else
402  {
403  font.setItalic( false );
404  item->setFlags( item->flags() | Qt::ItemIsEditable );
405  }
406  if ( !isActive )
407  {
408  //overridden
409  font.setStrikeOut( true );
410  QString toolTip = tr( "Overridden by value from %1" ).arg( activeScope->name() );
411  item->setToolTip( 0, toolTip );
412  item->setToolTip( 1, toolTip );
413  }
414  else
415  {
416  font.setStrikeOut( false );
417  item->setToolTip( 0, name );
418  item->setToolTip( 1, value );
419  }
420  item->setFont( 0, font );
421  item->setFont( 1, font );
422  item->setData( 0, RowBaseColor, baseColor );
423  item->setData( 0, ContextIndex, scopeIndex );
424  item->setFirstColumnSpanned( false );
425  }
426 }
427 
428 void QgsVariableEditorTree::refreshScopeItems( QgsExpressionContextScope* scope, int scopeIndex )
429 {
430  QSettings settings;
431 
432  //add top level item
433  bool isCurrent = scopeIndex == mEditableScopeIndex;
434 
435  QTreeWidgetItem* scopeItem;
436  if ( mScopeToItem.contains( scopeIndex ) )
437  {
438  //retrieve existing item
439  scopeItem = mScopeToItem.value( scopeIndex );
440  }
441  else
442  {
443  //create new top-level item
444  scopeItem = new QTreeWidgetItem();
445  mScopeToItem.insert( scopeIndex, scopeItem );
446  scopeItem->setFlags( scopeItem->flags() | Qt::ItemIsEnabled );
447  scopeItem->setText( 0, scope->name() );
448  scopeItem->setFlags( scopeItem->flags() ^ Qt::ItemIsEditable );
449  scopeItem->setFirstColumnSpanned( true );
450  QFont scopeFont = scopeItem->font( 0 );
451  scopeFont .setBold( true );
452  scopeItem->setFont( 0, scopeFont );
453  scopeItem->setFirstColumnSpanned( true );
454 
455  addTopLevelItem( scopeItem );
456 
457  //expand by default if current context or context was previously expanded
458  if ( isCurrent || settings.value( "QgsVariableEditor/" + scopeItem->text( 0 ) + "/expanded" ).toBool() )
459  scopeItem->setExpanded( true );
460 
461  scopeItem->setIcon( 0, mExpandIcon );
462  }
463 
464  refreshScopeVariables( scope, scopeIndex );
465 }
466 
467 void QgsVariableEditorTree::removeItem( QTreeWidgetItem *item )
468 {
469  if ( !item )
470  return;
471 
472  mVariableToItem.remove( mVariableToItem.key( item ) );
473  item->parent()->takeChild( item->parent()->indexOfChild( item ) );
474 
475  emit scopeChanged();
476 }
477 
478 void QgsVariableEditorTree::renameItem( QTreeWidgetItem *item, const QString& name )
479 {
480  if ( !item )
481  return;
482 
483  int contextIndex = mVariableToItem.key( item ).first;
484  mVariableToItem.remove( mVariableToItem.key( item ) );
485  mVariableToItem.insert( qMakePair( contextIndex, name ), item );
486  item->setText( 0, name );
487 
488  emit scopeChanged();
489 }
490 
491 void QgsVariableEditorTree::resetTree()
492 {
493  mVariableToItem.clear();
494  mScopeToItem.clear();
495  clear();
496 }
497 
498 void QgsVariableEditorTree::emitChanged()
499 {
500  emit scopeChanged();
501 }
502 
503 void QgsVariableEditorTree::drawRow( QPainter* painter, const QStyleOptionViewItem& option,
504  const QModelIndex& index ) const
505 {
506  QStyleOptionViewItemV3 opt = option;
507  QTreeWidgetItem* item = itemFromIndex( index );
508  if ( index.parent().isValid() )
509  {
510  //not a top-level item, so shade row background by context
511  const QColor baseColor = item->data( 0, RowBaseColor ).value<QColor>();
512  painter->fillRect( option.rect, baseColor );
513  opt.palette.setColor( QPalette::AlternateBase, baseColor.lighter( 110 ) );
514  }
515  QTreeWidget::drawRow( painter, opt, index );
516  QColor color = static_cast<QRgb>( QApplication::style()->styleHint( QStyle::SH_Table_GridLineColor, &opt ) );
517  painter->save();
518  painter->setPen( QPen( color ) );
519  painter->drawLine( opt.rect.x(), opt.rect.bottom(), opt.rect.right(), opt.rect.bottom() );
520  painter->restore();
521 }
522 
523 QColor QgsVariableEditorTree::rowColor( int index ) const
524 {
525  //return some nice (inspired by Qt Designer) background row colors
526  int colorIdx = index % 6;
527  switch ( colorIdx )
528  {
529  case 0:
530  return QColor( 255, 220, 167 );
531  case 1:
532  return QColor( 255, 255, 191 );
533  case 2:
534  return QColor( 191, 255, 191 );
535  case 3:
536  return QColor( 199, 255, 255 );
537  case 4:
538  return QColor( 234, 191, 255 );
539  case 5:
540  default:
541  return QColor( 255, 191, 239 );
542  }
543 }
544 
545 void QgsVariableEditorTree::toggleContextExpanded( QTreeWidgetItem* item )
546 {
547  if ( !item )
548  return;
549 
550  item->setExpanded( !item->isExpanded() );
551 
552  //save expanded state
553  QSettings settings;
554  settings.setValue( "QgsVariableEditor/" + item->text( 0 ) + "/expanded", item->isExpanded() );
555 }
556 
557 void QgsVariableEditorTree::editNext( const QModelIndex& index )
558 {
559  if ( !index.isValid() )
560  return;
561 
562  if ( index.column() == 0 )
563  {
564  //switch to next column
565  QModelIndex nextIndex = index.sibling( index.row(), 1 );
566  if ( nextIndex.isValid() )
567  {
568  setCurrentIndex( nextIndex );
569  edit( nextIndex );
570  }
571  }
572  else
573  {
574  QModelIndex nextIndex = model()->index( index.row() + 1, 0, index.parent() );
575  if ( nextIndex.isValid() )
576  {
577  //start editing next row
578  setCurrentIndex( nextIndex );
579  edit( nextIndex );
580  }
581  else
582  {
583  edit( index );
584  }
585  }
586 }
587 
588 QModelIndex QgsVariableEditorTree::moveCursor( QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers )
589 {
590  if ( cursorAction == QAbstractItemView::MoveNext )
591  {
592  QModelIndex index = currentIndex();
593  if ( index.isValid() )
594  {
595  if ( index.column() + 1 < model()->columnCount() )
596  return index.sibling( index.row(), index.column() + 1 );
597  else if ( index.row() + 1 < model()->rowCount( index.parent() ) )
598  return index.sibling( index.row() + 1, 0 );
599  else
600  return QModelIndex();
601  }
602  }
603  else if ( cursorAction == QAbstractItemView::MovePrevious )
604  {
605  QModelIndex index = currentIndex();
606  if ( index.isValid() )
607  {
608  if ( index.column() >= 1 )
609  return index.sibling( index.row(), index.column() - 1 );
610  else if ( index.row() >= 1 )
611  return index.sibling( index.row() - 1, model()->columnCount() - 1 );
612  else
613  return QModelIndex();
614  }
615  }
616 
617  return QTreeWidget::moveCursor( cursorAction, modifiers );
618 }
619 
620 void QgsVariableEditorTree::keyPressEvent( QKeyEvent *event )
621 {
622  switch ( event->key() )
623  {
624  case Qt::Key_Return:
625  case Qt::Key_Enter:
626  case Qt::Key_Space:
627  {
628  QTreeWidgetItem *item = currentItem();
629  if ( item && !item->parent() )
630  {
631  event->accept();
632  toggleContextExpanded( item );
633  return;
634  }
635  else if ( item && ( item->flags() & Qt::ItemIsEditable ) )
636  {
637  event->accept();
638  editNext( currentIndex() );
639  return;
640  }
641  break;
642  }
643  default:
644  break;
645  }
647 }
648 
649 void QgsVariableEditorTree::mousePressEvent( QMouseEvent *event )
650 {
652  QTreeWidgetItem* item = itemAt( event->pos() );
653  if ( !item )
654  return;
655 
656  if ( item->parent() )
657  {
658  //not a top-level item
659  return;
660  }
661 
662  if ( event->pos().x() + header()->offset() > 20 )
663  {
664  //not clicking on expand icon
665  return;
666  }
667 
668  if ( event->modifiers() & Qt::ShiftModifier )
669  {
670  //shift modifier expands all
671  if ( !item->isExpanded() )
672  {
673  expandAll();
674  }
675  else
676  {
677  collapseAll();
678  }
679  }
680  else
681  {
682  toggleContextExpanded( item );
683  }
684 }
685 
686 
687 //
688 // VariableEditorDelegate
689 //
690 
691 QWidget* VariableEditorDelegate::createEditor( QWidget *parent,
692  const QStyleOptionViewItem&,
693  const QModelIndex &index ) const
694 {
695  if ( !mParentTree )
696  return 0;
697 
698  //no editing for top level items
699  if ( !index.parent().isValid() )
700  return 0;
701 
702  QTreeWidgetItem *item = mParentTree->indexToItem( index );
703  QgsExpressionContextScope* scope = mParentTree->scopeFromItem( item );
704  if ( !item || !scope )
705  return 0;
706 
707  QString variableName = mParentTree->variableNameFromIndex( index );
708 
709  //no editing inherited or read-only variables
710  if ( scope != mParentTree->editableScope() || scope->isReadOnly( variableName ) )
711  return 0;
712 
713  QLineEdit *lineEdit = new QLineEdit( parent );
714  lineEdit->setText( index.column() == 0 ? variableName : mParentTree->editableScope()->variable( variableName ).toString() );
715  lineEdit->setAutoFillBackground( true );
716  return lineEdit;
717 }
718 
719 void VariableEditorDelegate::updateEditorGeometry( QWidget *editor,
720  const QStyleOptionViewItem &option,
721  const QModelIndex & ) const
722 {
723  editor->setGeometry( option.rect.adjusted( 0, 0, 0, -1 ) );
724 }
725 
726 QSize VariableEditorDelegate::sizeHint( const QStyleOptionViewItem &option,
727  const QModelIndex &index ) const
728 {
729  return QItemDelegate::sizeHint( option, index ) + QSize( 3, 4 );
730 }
731 
732 void VariableEditorDelegate::setModelData( QWidget* widget, QAbstractItemModel *model,
733  const QModelIndex& index ) const
734 {
735  Q_UNUSED( model );
736 
737  if ( !mParentTree )
738  return;
739 
740  QTreeWidgetItem *item = mParentTree->indexToItem( index );
741  QgsExpressionContextScope *scope = mParentTree->scopeFromItem( item );
742  if ( !item || !scope )
743  return;
744 
745  QLineEdit* lineEdit = qobject_cast< QLineEdit* >( widget );
746  if ( !lineEdit )
747  return;
748 
749  QString variableName = mParentTree->variableNameFromIndex( index );
750  if ( index.column() == 0 )
751  {
752  //edited variable name
753  QString newName = lineEdit->text();
754 
755  //test for validity
756  if ( newName == variableName )
757  {
758  return;
759  }
760  if ( scope->hasVariable( newName ) )
761  {
762  //existing name
763  QMessageBox::warning( mParentTree, tr( "Rename variable" ), tr( "A variable with the name \"%1\" already exists in this context." ).arg( newName ) );
764  newName.append( "_1" );
765  }
766 
767  QString value = scope->variable( variableName ).toString();
768  mParentTree->renameItem( item, newName );
769  scope->removeVariable( variableName );
770  scope->setVariable( newName, value );
771  mParentTree->emitChanged();
772  }
773  else if ( index.column() == 1 )
774  {
775  //edited variable value
776  QString value = lineEdit->text();
777  if ( scope->variable( variableName ).toString() == value )
778  {
779  return;
780  }
781  scope->setVariable( variableName, value );
782  mParentTree->emitChanged();
783  }
784  mParentTree->refreshTree();
785 }
786 
void setEditableScopeIndex(int scopeIndex)
Sets the editable scope for the widget.
static unsigned index
void showEvent(QShowEvent *event) override
QString & append(QChar ch)
void setContentsMargins(int left, int top, int right, int bottom)
void fillRect(const QRectF &rectangle, const QBrush &brush)
virtual QModelIndex moveCursor(CursorAction cursorAction, QFlags< Qt::KeyboardModifier > modifiers)
void setText(const QString &)
void setToolTip(int column, const QString &toolTip)
void setFont(int column, const QFont &font)
static QIcon getThemeIcon(const QString &theName)
Helper to get a theme icon.
void setIcon(int column, const QIcon &icon)
void save()
T value() const
void setFirstColumnSpanned(bool span)
virtual void setData(int column, int role, const QVariant &value)
bool hasVariable(const QString &name) const
Tests whether a variable with the specified name exists in the scope.
void drawLine(const QLineF &line)
virtual QVariant data(int column, int role) const
bool isExpanded() const
QString tr(const char *sourceText, const char *disambiguation, int n)
void setVariable(const QString &name, const QVariant &value)
Convenience method for setting a variable in the context scope by name and value. ...
int x() const
void setGeometry(int x, int y, int w, int h)
void reset(T *other)
QString name() const
Returns the friendly display name of the context scope.
void setBold(bool enable)
void scopeChanged()
Emitted when the user has modified a scope using the widget.
void setValue(const QString &key, const QVariant &value)
void setFlags(QFlags< Qt::ItemFlag > flags)
const char * name() const
bool isValid() const
bool removeVariable(const QString &name)
Removes a variable from the context scope, if found.
void setEnabled(bool)
void addWidget(QWidget *widget, int stretch, QFlags< Qt::AlignmentFlag > alignment)
virtual void showEvent(QShowEvent *event)
virtual void setEditorData(QWidget *editor, const QModelIndex &index) const
QStringList filteredVariableNames() const
Returns a fitlered and sorted list of variable names contained within the scope.
int toInt(bool *ok) const
void setPen(const QColor &color)
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
virtual void addItem(QLayoutItem *item)
QString objectName() const
bool isEmpty() const
virtual int styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const =0
int row() const
QFont font(int column) const
virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
Single scope for storing variables and functions for use within a QgsExpressionContext.
QModelIndex parent() const
QVariant variable(const QString &name) const
Retrieves a variable's value from the scope.
Qt::KeyboardModifiers modifiers() const
T * data() const
int key() const
QgsStringMap variablesInActiveScope() const
Returns a map variables set within the editable scope.
QColor lighter(int factor) const
QTreeWidgetItem * parent() const
void setItalic(bool enable)
int indexOfChild(QTreeWidgetItem *child) const
void restore()
QgsVariableEditorWidget(QWidget *parent=0)
Constructor for QgsVariableEditorWidget.
virtual QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
QVariant value(const QString &key, const QVariant &defaultValue) const
void setExpanded(bool expand)
QgsExpressionContextScope * editableScope() const
Returns the current editable scope for the widget.
Qt::ItemFlags flags() const
void reloadContext()
Reloads all scopes from the editor's current context.
QStyle * style()
QModelIndex sibling(int row, int column) const
void setText(int column, const QString &text)
void setContext(QgsExpressionContext *context)
Overwrites the QgsExpressionContext for the widget.
int column() const
void setStrikeOut(bool enable)
StandardButton warning(QWidget *parent, const QString &title, const QString &text, QFlags< QMessageBox::StandardButton > buttons, StandardButton defaultButton)
virtual void mousePressEvent(QMouseEvent *event)
iterator insert(const Key &key, const T &value)
void setAutoFillBackground(bool enabled)
const QPoint & pos() const
virtual void keyPressEvent(QKeyEvent *event)
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
bool isReadOnly(const QString &name) const
Tests whether the specified variable is read only and should not be editable by users.
QString toString() const
QString text(int column) const
void setSpacing(int spacing)
virtual void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
QStringList variableNames() const
Returns a list of variable names contained within the scope.
void addLayout(QLayout *layout, int stretch)
QTreeWidgetItem * takeChild(int index)
#define tr(sourceText)
typedef KeyboardModifiers