36 #include <QTextStream> 38 #include <QInputDialog> 40 #include <QGraphicsOpacityEffect> 41 #include <QPropertyAnimation> 49 connect( btnRun, &QToolButton::pressed,
this, &QgsExpressionBuilderWidget::btnRun_pressed );
50 connect( btnNewFile, &QToolButton::pressed,
this, &QgsExpressionBuilderWidget::btnNewFile_pressed );
51 connect( cmbFileNames, &QListWidget::currentItemChanged,
this, &QgsExpressionBuilderWidget::cmbFileNames_currentItemChanged );
52 connect( expressionTree, &QTreeView::doubleClicked,
this, &QgsExpressionBuilderWidget::expressionTree_doubleClicked );
53 connect( txtExpressionString, &QgsCodeEditorExpression::textChanged,
this, &QgsExpressionBuilderWidget::txtExpressionString_textChanged );
54 connect( txtPython, &QgsCodeEditorPython::textChanged,
this, &QgsExpressionBuilderWidget::txtPython_textChanged );
55 connect( txtSearchEditValues, &QgsFilterLineEdit::textChanged,
this, &QgsExpressionBuilderWidget::txtSearchEditValues_textChanged );
56 connect( txtSearchEdit, &QgsFilterLineEdit::textChanged,
this, &QgsExpressionBuilderWidget::txtSearchEdit_textChanged );
57 connect( lblPreview, &QLabel::linkActivated,
this, &QgsExpressionBuilderWidget::lblPreview_linkActivated );
58 connect( mValuesListView, &QListView::doubleClicked,
this, &QgsExpressionBuilderWidget::mValuesListView_doubleClicked );
60 mValueGroupBox->hide();
63 mModel =
new QStandardItemModel();
65 mProxyModel->setDynamicSortFilter(
true );
66 mProxyModel->setSourceModel( mModel );
67 expressionTree->setModel( mProxyModel );
68 expressionTree->setSortingEnabled(
true );
69 expressionTree->sortByColumn( 0, Qt::AscendingOrder );
71 expressionTree->setContextMenuPolicy( Qt::CustomContextMenu );
73 connect( expressionTree, &QWidget::customContextMenuRequested,
this, &QgsExpressionBuilderWidget::showContextMenu );
74 connect( expressionTree->selectionModel(), &QItemSelectionModel::currentChanged,
75 this, &QgsExpressionBuilderWidget::currentChanged );
80 Q_FOREACH ( QPushButton *button, mOperatorsGroupBox->findChildren<QPushButton *>() )
82 connect( button, &QAbstractButton::pressed,
this, &QgsExpressionBuilderWidget::operatorButtonClicked );
85 txtSearchEdit->setShowSearchIcon(
true );
86 txtSearchEdit->setPlaceholderText( tr(
"Search…" ) );
88 mValuesModel =
new QStringListModel();
89 mProxyValues =
new QSortFilterProxyModel();
90 mProxyValues->setSourceModel( mValuesModel );
91 mValuesListView->setModel( mProxyValues );
92 txtSearchEditValues->setShowSearchIcon(
true );
93 txtSearchEditValues->setPlaceholderText( tr(
"Search…" ) );
95 editorSplit->setSizes( QList<int>( {175, 300} ) );
97 functionsplit->setCollapsible( 0,
false );
98 connect( mShowHelpButton, &QPushButton::clicked,
this, [ = ]()
100 functionsplit->setSizes( QList<int>( {mOperationListGroup->width() - mHelpAndValuesWidget->minimumWidth(),
101 mHelpAndValuesWidget->minimumWidth()
103 mShowHelpButton->setEnabled(
false );
105 connect( functionsplit, &QSplitter::splitterMoved,
this, [ = ](
int,
int )
107 mShowHelpButton->setEnabled( functionsplit->sizes().at( 1 ) == 0 );
112 splitter->restoreState( settings.value( QStringLiteral(
"Windows/QgsExpressionBuilderWidget/splitter" ) ).toByteArray() );
113 editorSplit->restoreState( settings.value( QStringLiteral(
"Windows/QgsExpressionBuilderWidget/editorsplitter" ) ).toByteArray() );
114 functionsplit->restoreState( settings.value( QStringLiteral(
"Windows/QgsExpressionBuilderWidget/functionsplitter" ) ).toByteArray() );
116 txtExpressionString->setFoldingVisible(
false );
118 updateFunctionTree();
132 QModelIndex firstItem = mProxyModel->index( 0, 0, QModelIndex() );
133 expressionTree->setCurrentIndex( firstItem );
135 txtExpressionString->setWrapMode( QsciScintilla::WrapWord );
136 lblAutoSave->clear();
144 #if defined(QSCINTILLA_VERSION) && QSCINTILLA_VERSION >= 0x20a00 151 txtExpressionString->setIndicatorForegroundColor( QColor( Qt::red ), -1 );
152 txtExpressionString->setIndicatorHoverForegroundColor( QColor( Qt::red ), -1 );
153 txtExpressionString->setIndicatorOutlineColor( QColor( Qt::red ), -1 );
156 txtExpressionString->indicatorDefine( QgsCodeEditor::HiddenIndicator, FUNCTION_MARKER_ID );
157 txtExpressionString->setIndicatorForegroundColor( QColor( Qt::blue ), FUNCTION_MARKER_ID );
158 txtExpressionString->setIndicatorHoverForegroundColor( QColor( Qt::blue ), FUNCTION_MARKER_ID );
159 txtExpressionString->setIndicatorHoverStyle( QgsCodeEditor::DotsIndicator, FUNCTION_MARKER_ID );
161 connect( txtExpressionString, &QgsCodeEditorExpression::indicatorClicked,
this, &QgsExpressionBuilderWidget::indicatorClicked );
162 txtExpressionString->setAutoCompletionCaseSensitivity(
true );
163 txtExpressionString->setAutoCompletionSource( QsciScintilla::AcsAPIs );
164 txtExpressionString->setCallTipsVisible( 0 );
167 mFunctionBuilderHelp->setMarginVisible(
false );
168 mFunctionBuilderHelp->setEdgeMode( QsciScintilla::EdgeNone );
169 mFunctionBuilderHelp->setEdgeColumn( 0 );
170 mFunctionBuilderHelp->setReadOnly(
true );
171 mFunctionBuilderHelp->setText( tr(
"\"\"\"Define a new function using the @qgsfunction decorator.\n\ 173 The function accepts the following parameters\n\ 175 : param [any]: Define any parameters you want to pass to your function before\n\ 176 the following arguments.\n\ 177 : param feature: The current feature\n\ 178 : param parent: The QgsExpression object\n\ 179 : param context: If there is an argument called ``context`` found at the last\n\ 180 position, this variable will contain a ``QgsExpressionContext``\n\ 181 object, that gives access to various additional information like\n\ 182 expression variables. E.g. ``context.variable( 'layer_id' )``\n\ 183 : returns: The result of the expression.\n\ 187 The @qgsfunction decorator accepts the following arguments:\n\ 190 : param args: Defines the number of arguments. With ``args = 'auto'`` the number of\n\ 191 arguments will automatically be extracted from the signature.\n\ 192 With ``args = -1``, any number of arguments are accepted.\n\ 193 : param group: The name of the group under which this expression function will\n\ 195 : param handlesnull: Set this to True if your function has custom handling for NULL values.\n\ 196 If False, the result will always be NULL as soon as any parameter is NULL.\n\ 197 Defaults to False.\n\ 198 : param usesgeometry : Set this to True if your function requires access to\n\ 199 feature.geometry(). Defaults to False.\n\ 200 : param referenced_columns: An array of attribute names that are required to run\n\ 201 this function. Defaults to [QgsFeatureRequest.ALL_ATTRIBUTES].\n\ 209 settings.
setValue( QStringLiteral(
"Windows/QgsExpressionBuilderWidget/splitter" ), splitter->saveState() );
210 settings.
setValue( QStringLiteral(
"Windows/QgsExpressionBuilderWidget/editorsplitter" ), editorSplit->saveState() );
211 settings.
setValue( QStringLiteral(
"Windows/QgsExpressionBuilderWidget/functionsplitter" ), functionsplit->saveState() );
229 void QgsExpressionBuilderWidget::currentChanged(
const QModelIndex &index,
const QModelIndex & )
231 txtSearchEditValues->clear();
234 QModelIndex idx = mProxyModel->mapToSource( index );
242 if ( mFieldValues.contains( item->text() ) )
244 const QStringList &values = mFieldValues[item->text()];
245 mValuesModel->setStringList( values );
249 mValuesModel->setStringList( QStringList() );
252 mValueGroupBox->setVisible( isField );
253 mShowHelpButton->setText( isField ? tr(
"Show Values" ) : tr(
"Show Help" ) );
256 QString help = loadFunctionHelp( item );
257 txtHelpText->setText( help );
260 void QgsExpressionBuilderWidget::btnRun_pressed()
262 if ( !cmbFileNames->currentItem() )
265 QString file = cmbFileNames->currentItem()->text();
267 runPythonCode( txtPython->text() );
270 void QgsExpressionBuilderWidget::runPythonCode(
const QString &code )
274 QString pythontext = code;
277 updateFunctionTree();
284 QDir myDir( mFunctionsPath );
285 if ( !myDir.exists() )
287 myDir.mkpath( mFunctionsPath );
290 if ( !fileName.endsWith( QLatin1String(
".py" ) ) )
292 fileName.append(
".py" );
295 fileName = mFunctionsPath + QDir::separator() + fileName;
296 QFile myFile( fileName );
297 if ( myFile.open( QIODevice::WriteOnly | QFile::Truncate ) )
299 QTextStream myFileStream( &myFile );
300 myFileStream << txtPython->text() << endl;
307 mFunctionsPath = path;
309 dir.setNameFilters( QStringList() << QStringLiteral(
"*.py" ) );
310 QStringList files = dir.entryList( QDir::Files );
311 cmbFileNames->clear();
312 Q_FOREACH (
const QString &name, files )
314 QFileInfo info( mFunctionsPath + QDir::separator() + name );
315 if ( info.baseName() == QLatin1String(
"__init__" ) )
continue;
316 QListWidgetItem *item =
new QListWidgetItem(
QgsApplication::getThemeIcon( QStringLiteral(
"console/iconTabEditorConsole.svg" ) ), info.baseName() );
317 cmbFileNames->addItem( item );
319 if ( !cmbFileNames->currentItem() )
321 cmbFileNames->setCurrentRow( 0 );
324 if ( cmbFileNames->count() == 0 )
328 txtPython->setText( QString(
"'''\n#Sample custom function file\n " 329 "(uncomment to use and customize or Add button to create a new file) \n%1 \n '''" ).arg( txtPython->text() ) );
336 QList<QListWidgetItem *> items = cmbFileNames->findItems( fileName, Qt::MatchExactly );
337 if ( !items.isEmpty() )
340 QListWidgetItem *item =
new QListWidgetItem(
QgsApplication::getThemeIcon( QStringLiteral(
"console/iconTabEditorConsole.svg" ) ), fileName );
341 cmbFileNames->insertItem( 0, item );
342 cmbFileNames->setCurrentRow( 0 );
346 txtPython->setText( templatetxt );
350 void QgsExpressionBuilderWidget::btnNewFile_pressed()
353 QString text = QInputDialog::getText(
this, tr(
"New File" ),
354 tr(
"New file name:" ), QLineEdit::Normal,
356 if ( ok && !text.isEmpty() )
362 void QgsExpressionBuilderWidget::cmbFileNames_currentItemChanged( QListWidgetItem *item, QListWidgetItem *lastitem )
366 QString filename = lastitem->text();
369 QString path = mFunctionsPath + QDir::separator() + item->text();
375 if ( !path.endsWith( QLatin1String(
".py" ) ) )
376 path.append(
".py" );
378 txtPython->loadScript( path );
383 txtPython->setText( code );
386 void QgsExpressionBuilderWidget::expressionTree_doubleClicked(
const QModelIndex &index )
388 QModelIndex idx = mProxyModel->mapToSource( index );
399 txtExpressionString->setFocus();
418 txtExpressionString->setFields( fields );
420 QStringList fieldNames;
421 fieldNames.reserve( fields.
count() );
422 for (
int i = 0; i < fields.
count(); ++i )
425 QString fieldName = field.
name();
426 fieldNames << fieldName;
436 for (
auto it = fieldValues.constBegin(); it != fieldValues.constEnd(); ++it )
441 mFieldValues = fieldValues;
444 void QgsExpressionBuilderWidget::fillFieldValues(
const QString &fieldName,
int countLimit )
455 if ( fieldIndex < 0 )
458 QStringList strValues;
459 QList<QVariant> values = mLayer->
uniqueValues( fieldIndex, countLimit ).toList();
460 std::sort( values.begin(), values.end() );
461 Q_FOREACH (
const QVariant &value, values )
464 if ( value.isNull() )
465 strValue = QStringLiteral(
"NULL" );
466 else if ( value.type() == QVariant::Int || value.type() == QVariant::Double || value.type() == QVariant::LongLong )
467 strValue = value.toString();
469 strValue =
'\'' + value.toString().replace(
'\'', QLatin1String(
"''" ) ) +
'\'';
470 strValues.append( strValue );
472 mValuesModel->setStringList( strValues );
473 mFieldValues[fieldName] = strValues;
483 return "<head><style>" + helpStylesheet() +
"</style></head><body>" + helpContents +
"</body>";
488 const QString &label,
490 const QString &helpText,
494 item->setData( label, Qt::UserRole );
496 item->setIcon( icon );
499 if ( mExpressionGroups.contains( group ) )
502 groupNode->appendRow( item );
508 newgroupNode->setData( group, Qt::UserRole );
511 newgroupNode->appendRow( item );
512 newgroupNode->setBackground( QBrush( QColor( 238, 238, 238 ) ) );
513 mModel->appendRow( newgroupNode );
514 mExpressionGroups.insert( group, newgroupNode );
517 if ( highlightedItem )
521 topLevelItem->setData( label, Qt::UserRole );
523 QFont font = topLevelItem->font();
524 font.setBold(
true );
525 topLevelItem->setFont( font );
526 mModel->appendRow( topLevelItem );
533 return mExpressionValid;
539 QString location = QStringLiteral(
"/expressions/recent/%1" ).arg( collection );
540 QStringList expressions = settings.
value( location ).toStringList();
545 while ( expressions.count() > 20 )
547 expressions.pop_back();
550 settings.
setValue( location, expressions );
556 mRecentKey = collection;
557 QString name = tr(
"Recent (%1)" ).arg( collection );
558 if ( mExpressionGroups.contains( name ) )
561 node->removeRows( 0, node->rowCount() );
565 QString location = QStringLiteral(
"/expressions/recent/%1" ).arg( collection );
566 QStringList expressions = settings.
value( location ).toStringList();
568 Q_FOREACH (
const QString &expression, expressions )
575 void QgsExpressionBuilderWidget::loadLayers()
580 QMap<QString, QgsMapLayer *> layers = mProject->mapLayers();
581 QMap<QString, QgsMapLayer *>::const_iterator layerIt = layers.constBegin();
582 for ( ; layerIt != layers.constEnd(); ++layerIt )
584 registerItemForAllGroups( QStringList() << tr(
"Map Layers" ), layerIt.value()->name(), QStringLiteral(
"'%1'" ).arg( layerIt.key() ), formatLayerHelp( layerIt.value() ) );
588 void QgsExpressionBuilderWidget::loadRelations()
593 QMap<QString, QgsRelation> relations = mProject->relationManager()->relations();
594 QMap<QString, QgsRelation>::const_iterator relIt = relations.constBegin();
595 for ( ; relIt != relations.constEnd(); ++relIt )
597 registerItemForAllGroups( QStringList() << tr(
"Relations" ), relIt->name(), QStringLiteral(
"'%1'" ).arg( relIt->id() ), formatRelationHelp( relIt.value() ) );
601 void QgsExpressionBuilderWidget::updateFunctionTree()
604 mExpressionGroups.clear();
606 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"+" ), QStringLiteral(
" + " ) );
607 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"-" ), QStringLiteral(
" - " ) );
608 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"*" ), QStringLiteral(
" * " ) );
609 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"/" ), QStringLiteral(
" / " ) );
610 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"%" ), QStringLiteral(
" % " ) );
611 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"^" ), QStringLiteral(
" ^ " ) );
612 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"=" ), QStringLiteral(
" = " ) );
613 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"~" ), QStringLiteral(
" ~ " ) );
614 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
">" ), QStringLiteral(
" > " ) );
615 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"<" ), QStringLiteral(
" < " ) );
616 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"<>" ), QStringLiteral(
" <> " ) );
617 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"<=" ), QStringLiteral(
" <= " ) );
618 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
">=" ), QStringLiteral(
" >= " ) );
619 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"[]" ), QStringLiteral(
"[ ]" ) );
620 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"||" ), QStringLiteral(
" || " ) );
621 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"IN" ), QStringLiteral(
" IN " ) );
622 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"LIKE" ), QStringLiteral(
" LIKE " ) );
623 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"ILIKE" ), QStringLiteral(
" ILIKE " ) );
624 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"IS" ), QStringLiteral(
" IS " ) );
625 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"OR" ), QStringLiteral(
" OR " ) );
626 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"AND" ), QStringLiteral(
" AND " ) );
627 registerItem( QStringLiteral(
"Operators" ), QStringLiteral(
"NOT" ), QStringLiteral(
" NOT " ) );
629 QString casestring = QStringLiteral(
"CASE WHEN condition THEN result END" );
630 registerItem( QStringLiteral(
"Conditionals" ), QStringLiteral(
"CASE" ), casestring );
632 registerItem( QStringLiteral(
"Fields and Values" ), QStringLiteral(
"NULL" ), QStringLiteral(
"NULL" ) );
636 for (
int i = 0; i < count; i++ )
639 QString name = func->
name();
640 if ( name.startsWith(
'_' ) )
650 if ( func->
params() != 0 )
652 else if ( !name.startsWith(
'$' ) )
653 name += QLatin1String(
"()" );
663 loadExpressionContext();
673 return txtExpressionString->text();
678 txtExpressionString->setText( expression );
683 return lblExpected->text();
688 lblExpected->setText( expected );
689 mExpectedOutputFrame->setVisible( !expected.isNull() );
694 mExpressionContext = context;
695 updateFunctionTree();
700 void QgsExpressionBuilderWidget::txtExpressionString_textChanged()
707 if ( text.isEmpty() )
710 lblPreview->setStyleSheet( QString() );
711 txtExpressionString->setToolTip( QString() );
712 lblPreview->setToolTip( QString() );
714 setParserError(
true );
715 setEvalError(
true );
736 QVariant value = exp.
evaluate( &mExpressionContext );
747 tooltip = QStringLiteral(
"<b>%1:</b>" 748 "%2" ).arg( tr(
"Parser Errors" ), errorString );
751 tooltip += QStringLiteral(
"<b>%1:</b> %2" ).arg( tr(
"Eval Error" ), exp.
evalErrorString() );
753 lblPreview->setText( tr(
"Expression is invalid <a href=""more"">(more info)</a>" ) );
754 lblPreview->setStyleSheet( QStringLiteral(
"color: rgba(255, 6, 10, 255);" ) );
755 txtExpressionString->setToolTip( tooltip );
756 lblPreview->setToolTip( tooltip );
765 lblPreview->setStyleSheet( QString() );
766 txtExpressionString->setToolTip( QString() );
767 lblPreview->setToolTip( QString() );
769 setParserError(
false );
770 setEvalError(
false );
776 void QgsExpressionBuilderWidget::loadExpressionContext()
778 txtExpressionString->setExpressionContext( mExpressionContext );
780 Q_FOREACH (
const QString &variable, variableNames )
782 registerItem( QStringLiteral(
"Variables" ), variable,
" @" + variable +
' ',
789 QStringList contextFunctions = mExpressionContext.
functionNames();
790 Q_FOREACH (
const QString &functionName, contextFunctions )
793 QString name = func->
name();
794 if ( name.startsWith(
'_' ) )
796 if ( func->
params() != 0 )
802 void QgsExpressionBuilderWidget::registerItemForAllGroups(
const QStringList &groups,
const QString &label,
const QString &
expressionText,
const QString &helpText,
QgsExpressionItem::ItemType type,
bool highlightedItem,
int sortOrder )
804 Q_FOREACH (
const QString &group, groups )
810 QString QgsExpressionBuilderWidget::formatRelationHelp(
const QgsRelation &relation )
const 812 QString text = QStringLiteral(
"<p>%1</p>" ).arg( tr(
"Inserts the relation ID for the relation named '%1'." ).arg( relation.
name() ) );
813 text.append( QStringLiteral(
"<p>%1</p>" ).arg( tr(
"Current value: '%1'" ).arg( relation.
id() ) ) );
817 QString QgsExpressionBuilderWidget::formatLayerHelp(
const QgsMapLayer *layer )
const 819 QString text = QStringLiteral(
"<p>%1</p>" ).arg( tr(
"Inserts the layer ID for the layer named '%1'." ).arg( layer->
name() ) );
820 text.append( QStringLiteral(
"<p>%1</p>" ).arg( tr(
"Current value: '%1'" ).arg( layer->
id() ) ) );
829 void QgsExpressionBuilderWidget::setParserError(
bool parserError )
831 if ( parserError == mParserError )
843 void QgsExpressionBuilderWidget::setEvalError(
bool evalError )
845 if ( evalError == mEvalError )
865 updateFunctionTree();
870 QWidget::showEvent( e );
871 txtExpressionString->setFocus();
874 void QgsExpressionBuilderWidget::createErrorMarkers( QList<QgsExpression::ParserError> errors )
879 int errorFirstLine = error.firstLine - 1 ;
880 int errorFirstColumn = error.firstColumn - 1;
881 int errorLastColumn = error.lastColumn - 1;
882 int errorLastLine = error.lastLine - 1;
888 errorFirstLine = errorLastLine;
889 errorFirstColumn = errorLastColumn - 1;
891 txtExpressionString->fillIndicatorRange( errorFirstLine,
894 errorLastColumn, error.errorType );
898 void QgsExpressionBuilderWidget::createMarkers(
const QgsExpressionNode *inNode )
902 case QgsExpressionNode::NodeType::ntFunction:
905 txtExpressionString->SendScintilla( QsciScintilla::SCI_SETINDICATORCURRENT, FUNCTION_MARKER_ID );
906 txtExpressionString->SendScintilla( QsciScintilla::SCI_SETINDICATORVALUE, node->
fnIndex() );
909 int start_pos = txtExpressionString->positionFromLineIndex( inNode->
parserFirstLine - 1, start );
910 txtExpressionString->SendScintilla( QsciScintilla::SCI_INDICATORFILLRANGE, start_pos, end - start );
913 const QList< QgsExpressionNode * > nodeList = node->
args()->
list();
921 case QgsExpressionNode::NodeType::ntLiteral:
925 case QgsExpressionNode::NodeType::ntUnaryOperator:
928 createMarkers( node->
operand() );
931 case QgsExpressionNode::NodeType::ntBinaryOperator:
934 createMarkers( node->
opLeft() );
935 createMarkers( node->
opRight() );
938 case QgsExpressionNode::NodeType::ntColumnRef:
942 case QgsExpressionNode::NodeType::ntInOperator:
947 const QList< QgsExpressionNode * > nodeList = node->
list()->
list();
955 case QgsExpressionNode::NodeType::ntCondition:
960 createMarkers( cond->whenExp() );
961 createMarkers( cond->thenExp() );
965 createMarkers( node->
elseExp() );
969 case QgsExpressionNode::NodeType::ntIndexOperator:
976 void QgsExpressionBuilderWidget::clearFunctionMarkers()
978 int lastLine = txtExpressionString->lines() - 1;
979 txtExpressionString->clearIndicatorRange( 0, 0, lastLine, txtExpressionString->text( lastLine ).length() - 1, FUNCTION_MARKER_ID );
982 void QgsExpressionBuilderWidget::clearErrors()
984 int lastLine = txtExpressionString->lines() - 1;
993 void QgsExpressionBuilderWidget::txtSearchEdit_textChanged()
995 mProxyModel->setFilterWildcard( txtSearchEdit->text() );
996 if ( txtSearchEdit->text().isEmpty() )
998 expressionTree->collapseAll();
1002 expressionTree->expandAll();
1003 QModelIndex index = mProxyModel->index( 0, 0 );
1004 if ( mProxyModel->hasChildren( index ) )
1006 QModelIndex child = mProxyModel->index( 0, 0, index );
1007 expressionTree->selectionModel()->setCurrentIndex( child, QItemSelectionModel::ClearAndSelect );
1012 void QgsExpressionBuilderWidget::txtSearchEditValues_textChanged()
1014 mProxyValues->setFilterCaseSensitivity( Qt::CaseInsensitive );
1015 mProxyValues->setFilterWildcard( txtSearchEditValues->text() );
1018 void QgsExpressionBuilderWidget::lblPreview_linkActivated(
const QString &link )
1022 mv->setWindowTitle( tr(
"More Info on Expression Error" ) );
1027 void QgsExpressionBuilderWidget::mValuesListView_doubleClicked(
const QModelIndex &index )
1030 txtExpressionString->insertText(
' ' + index.data( Qt::DisplayRole ).toString() +
' ' );
1031 txtExpressionString->setFocus();
1034 void QgsExpressionBuilderWidget::operatorButtonClicked()
1036 QPushButton *button =
dynamic_cast<QPushButton *
>( sender() );
1039 txtExpressionString->insertText(
' ' + button->text() +
' ' );
1040 txtExpressionString->setFocus();
1043 void QgsExpressionBuilderWidget::showContextMenu( QPoint pt )
1045 QModelIndex idx = expressionTree->indexAt( pt );
1046 idx = mProxyModel->mapToSource( idx );
1053 QMenu *menu =
new QMenu(
this );
1054 menu->addAction( tr(
"Load First 10 Unique Values" ),
this, SLOT(
loadSampleValues() ) );
1055 menu->addAction( tr(
"Load All Unique Values" ),
this, SLOT(
loadAllValues() ) );
1056 menu->popup( expressionTree->mapToGlobal( pt ) );
1062 QModelIndex idx = mProxyModel->mapToSource( expressionTree->currentIndex() );
1066 if ( !mLayer || !item )
1069 mValueGroupBox->show();
1070 fillFieldValues( item->text(), 10 );
1075 QModelIndex idx = mProxyModel->mapToSource( expressionTree->currentIndex() );
1079 if ( !mLayer || !item )
1082 mValueGroupBox->show();
1083 fillFieldValues( item->text(), -1 );
1086 void QgsExpressionBuilderWidget::txtPython_textChanged()
1088 lblAutoSave->setText( tr(
"Saving…" ) );
1098 if ( tabWidget->currentIndex() != 1 )
1101 QListWidgetItem *item = cmbFileNames->currentItem();
1105 QString file = item->text();
1107 lblAutoSave->setText( QStringLiteral(
"Saved" ) );
1108 QGraphicsOpacityEffect *effect =
new QGraphicsOpacityEffect();
1109 lblAutoSave->setGraphicsEffect( effect );
1110 QPropertyAnimation *anim =
new QPropertyAnimation( effect,
"opacity" );
1111 anim->setDuration( 2000 );
1112 anim->setStartValue( 1.0 );
1113 anim->setEndValue( 0.0 );
1114 anim->setEasingCurve( QEasingCurve::OutQuad );
1115 anim->start( QAbstractAnimation::DeleteWhenStopped );
1118 void QgsExpressionBuilderWidget::indicatorClicked(
int line,
int index, Qt::KeyboardModifiers state )
1120 if ( state & Qt::ControlModifier )
1122 int position = txtExpressionString->positionFromLineIndex( line, index );
1123 long fncIndex = txtExpressionString->SendScintilla( QsciScintilla::SCI_INDICATORVALUEAT, FUNCTION_MARKER_ID, static_cast<long int>( position ) );
1125 QString help = getFunctionHelp( func );
1126 txtHelpText->setText( help );
1130 void QgsExpressionBuilderWidget::setExpressionState(
bool state )
1132 mExpressionValid = state;
1135 QString QgsExpressionBuilderWidget::helpStylesheet()
const 1141 style +=
" .functionname {color: #0a6099; font-weight: bold;} " 1142 " .argument {font-family: monospace; color: #bf0c0c; font-style: italic; } " 1143 " td.argument { padding-right: 10px; }";
1148 QString QgsExpressionBuilderWidget::loadFunctionHelp(
QgsExpressionItem *expressionItem )
1150 if ( !expressionItem )
1153 QString helpContents = expressionItem->
getHelpText();
1156 if ( helpContents.isEmpty() )
1158 QString name = expressionItem->data( Qt::UserRole ).toString();
1166 return "<head><style>" + helpStylesheet() +
"</style></head><body>" + helpContents +
"</body>";
1175 setFilterCaseSensitivity( Qt::CaseInsensitive );
1180 QModelIndex index = sourceModel()->index( source_row, 0, source_parent );
1183 int count = sourceModel()->rowCount( index );
1184 bool matchchild =
false;
1185 for (
int i = 0; i < count; ++i )
1187 if ( filterAcceptsRow( i, index ) )
1200 return QSortFilterProxyModel::filterAcceptsRow( source_row, source_parent );
1207 if ( leftSort != rightSort )
1208 return leftSort < rightSort;
1210 QString leftString = sourceModel()->data( left, Qt::DisplayRole ).toString();
1211 QString rightString = sourceModel()->data( right, Qt::DisplayRole ).toString();
1214 if ( leftString.startsWith(
'$' ) )
1215 leftString = leftString.mid( 1 );
1216 if ( rightString.startsWith(
'$' ) )
1217 rightString = rightString.mid( 1 );
1219 return QString::localeAwareCompare( leftString, rightString ) < 0;
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
bool isValid() const
Returns the validity of this feature.
Class for parsing and evaluation of expressions (formerly called "search strings").
int parserFirstColumn
First column in the parser this node was found.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
static QString formatPreviewString(const QVariant &value, bool htmlOutput=true)
Formats an expression result for friendly display to the user.
Base class for all map layer types.
bool isHighlightedFunction(const QString &name) const
Returns true if the specified function name is intended to be highlighted to the user.
QgsExpressionNode::NodeList * args() const
Returns a list of arguments specified for the function.
QStringList filteredVariableNames() const
Returns a filtered list of variables names set by all scopes in the context.
int params() const
The number of parameters this function takes.
QStringList groups() const
Returns a list of the groups the function belongs to.
This class is a composition of two QSettings instances:
static QString group(const QString &group)
Returns the translated name for a function group.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
QIcon iconForField(int fieldIdx) const
Returns an icon corresponding to a field index, based on the field's type and source.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
QgsExpressionNode * opRight() const
Returns the node to the right of the operator.
WhenThenList conditions() const
The list of WHEN THEN expression parts of the expression.
Details about any parser errors that were found when parsing the expression.
QVariant evaluate()
Evaluate the feature and return the result.
An expression node for CASE WHEN clauses.
QString evalErrorString() const
Returns evaluation error.
Container of fields for a vector layer.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
QgsExpressionNode::NodeList * list() const
Returns the list of nodes to search for matching values within.
QList< QgsExpression::ParserError > parserErrors() const
Returns parser error details including location of error.
QgsExpressionNode * opLeft() const
Returns the node to the left of the operator.
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
static QString reportStyleSheet()
Returns a standard css style sheet for reports.
QgsExpressionItemSearchProxy()
int count() const
Returns number of items.
QString parserErrorString() const
Returns parser error.
QVariant variable(const QString &name) const
Fetches a matching variable from the context.
Function was called with invalid args.
Non named function arg used after named arg.
QString description(const QString &name) const
Returns a translated description string for the variable with specified name.
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
void setMessageAsHtml(const QString &msg)
static int functionCount()
Returns the number of functions defined in the parser.
Search proxy used to filter the QgsExpressionBuilderWidget tree.
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
bool isHighlightedVariable(const QString &name) const
Returns true if the specified variable name is intended to be highlighted to the user.
Function was called with the wrong number of args.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
An expression node for value IN or NOT IN clauses.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false) ...
Reads and writes project states.
Abstract base class for all nodes that can appear in an expression.
static const int ITEM_TYPE_ROLE
Item type role.
Encapsulate a field in an attribute table or data source.
An expression node for expression functions.
QgsExpressionNode * elseExp() const
The ELSE expression used for the condition.
static const QList< QgsExpressionFunction * > & Functions()
static QString formatVariableHelp(const QString &description, bool showValue=true, const QVariant &value=QVariant())
Returns formatted help text for a variable.
static bool eval(const QString &command, QString &result)
Eval a Python statement.
QgsExpressionItem::ItemType getItemType() const
Gets the type of expression item, e.g., header, field, ExpressionNode.
static const int CUSTOM_SORT_ROLE
Custom sort order role.
QString name() const
The name of the function.
A general purpose distance and area calculator, capable of performing ellipsoid based calculations...
A abstract base class for defining QgsExpression functions.
An expression item that can be used in the QgsExpressionBuilderWidget tree.
void setGeomCalculator(const QgsDistanceArea *calc)
Sets the geometry calculator used for distance and area calculations in expressions.
QList< QgsExpressionNode * > list()
Gets a list of all the nodes.
int parserFirstLine
First line in the parser this node was found.
QStringList functionNames() const
Retrieves a list of function names contained in the context.
QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const FINAL
Calculates a list of unique values contained within an attribute in the layer.
const QString helpText() const
The help text for the function.
static bool run(const QString &command, const QString &messageOnError=QString())
Execute a Python statement.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
QString getExpressionText() const
const QgsExpressionNode * rootNode() const
Returns root node of the expression. Root node is null is parsing has failed.
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
A unary node is either negative as in boolean (not) or as in numbers (minus).
A binary expression operator, which operates on two values.
A generic message view for displaying QGIS messages.
bool isEmpty() const
Checks whether the container is empty.
static QString helpText(QString name)
Returns the help text for a specified function.
QgsFeature feature() const
Convenience function for retrieving the feature for the context, if set.
QString getHelpText() const
Gets the help text that is associated with this expression item.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Query the layer for features specified in request.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
bool nextFeature(QgsFeature &f)
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
Represents a vector layer which manages a vector based data sets.
virtual bool isDeprecated() const
Returns true if the function is deprecated and should not be presented as a valid option to users in ...
virtual QgsExpressionNode::NodeType nodeType() const =0
Gets the type of this node.
QgsExpressionNode * operand() const
Returns the node the operator will operate upon.
static bool isValid()
Returns true if the runner has an instance (and thus is able to run commands)
Represents a "WHEN... THEN..." portation of a CASE WHEN clause in an expression.
QgsExpressionFunction * function(const QString &name) const
Fetches a matching function from the context.
int parserLastColumn
Last column in the parser this node was found.
bool isContextual() const
Returns whether the function is only available if provided by a QgsExpressionContext object...
int fnIndex() const
Returns the index of the node's function.