35 #include <QTextStream> 37 #include <QInputDialog> 39 #include <QGraphicsOpacityEffect> 40 #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 txtHelpText->setOpenExternalLinks(
true );
62 mValueGroupBox->hide();
65 mModel =
new QStandardItemModel();
67 mProxyModel->setDynamicSortFilter(
true );
68 mProxyModel->setSourceModel( mModel );
69 expressionTree->setModel( mProxyModel );
70 expressionTree->setSortingEnabled(
true );
71 expressionTree->sortByColumn( 0, Qt::AscendingOrder );
73 expressionTree->setContextMenuPolicy( Qt::CustomContextMenu );
75 connect( expressionTree, &QWidget::customContextMenuRequested,
this, &QgsExpressionBuilderWidget::showContextMenu );
76 connect( expressionTree->selectionModel(), &QItemSelectionModel::currentChanged,
77 this, &QgsExpressionBuilderWidget::currentChanged );
82 Q_FOREACH ( QPushButton *button, mOperatorsGroupBox->findChildren<QPushButton *>() )
84 connect( button, &QAbstractButton::pressed,
this, &QgsExpressionBuilderWidget::operatorButtonClicked );
87 txtSearchEdit->setShowSearchIcon(
true );
88 txtSearchEdit->setPlaceholderText( tr(
"Search…" ) );
90 mValuesModel =
new QStringListModel();
91 mProxyValues =
new QSortFilterProxyModel();
92 mProxyValues->setSourceModel( mValuesModel );
93 mValuesListView->setModel( mProxyValues );
94 txtSearchEditValues->setShowSearchIcon(
true );
95 txtSearchEditValues->setPlaceholderText( tr(
"Search…" ) );
97 editorSplit->setSizes( QList<int>( {175, 300} ) );
99 functionsplit->setCollapsible( 0,
false );
100 connect( mShowHelpButton, &QPushButton::clicked,
this, [ = ]()
102 functionsplit->setSizes( QList<int>( {mOperationListGroup->width() - mHelpAndValuesWidget->minimumWidth(),
103 mHelpAndValuesWidget->minimumWidth()} ) );
104 mShowHelpButton->setEnabled(
false );
106 connect( functionsplit, &QSplitter::splitterMoved,
this, [ = ](
int,
int )
108 mShowHelpButton->setEnabled( functionsplit->sizes().at( 1 ) == 0 );
113 splitter->restoreState( settings.value( QStringLiteral(
"Windows/QgsExpressionBuilderWidget/splitter" ) ).toByteArray() );
114 editorSplit->restoreState( settings.value( QStringLiteral(
"Windows/QgsExpressionBuilderWidget/editorsplitter" ) ).toByteArray() );
115 functionsplit->restoreState( settings.value( QStringLiteral(
"Windows/QgsExpressionBuilderWidget/functionsplitter" ) ).toByteArray() );
117 txtExpressionString->setFoldingVisible(
false );
119 updateFunctionTree();
133 QModelIndex firstItem = mProxyModel->index( 0, 0, QModelIndex() );
134 expressionTree->setCurrentIndex( firstItem );
136 txtExpressionString->setWrapMode( QsciScintilla::WrapWord );
137 lblAutoSave->clear();
145 #if defined(QSCINTILLA_VERSION) && QSCINTILLA_VERSION >= 0x20a00 152 txtExpressionString->setIndicatorForegroundColor( QColor( Qt::red ), -1 );
153 txtExpressionString->setIndicatorHoverForegroundColor( QColor( Qt::red ), -1 );
154 txtExpressionString->setIndicatorOutlineColor( QColor( Qt::red ), -1 );
157 txtExpressionString->indicatorDefine( QgsCodeEditor::HiddenIndicator, FUNCTION_MARKER_ID );
158 txtExpressionString->setIndicatorForegroundColor( QColor( Qt::blue ), FUNCTION_MARKER_ID );
159 txtExpressionString->setIndicatorHoverForegroundColor( QColor( Qt::blue ), FUNCTION_MARKER_ID );
160 txtExpressionString->setIndicatorHoverStyle( QgsCodeEditor::DotsIndicator, FUNCTION_MARKER_ID );
162 connect( txtExpressionString, &QgsCodeEditorExpression::indicatorClicked,
this, &QgsExpressionBuilderWidget::indicatorClicked );
163 txtExpressionString->setAutoCompletionCaseSensitivity(
true );
164 txtExpressionString->setAutoCompletionSource( QsciScintilla::AcsAPIs );
165 txtExpressionString->setCallTipsVisible( 0 );
168 mFunctionBuilderHelp->setMarginVisible(
false );
169 mFunctionBuilderHelp->setEdgeMode( QsciScintilla::EdgeNone );
170 mFunctionBuilderHelp->setEdgeColumn( 0 );
171 mFunctionBuilderHelp->setReadOnly(
true );
172 mFunctionBuilderHelp->setText( tr(
"\"\"\"Define a new function using the @qgsfunction decorator.\n\ 174 The function accepts the following parameters\n\ 176 : param [any]: Define any parameters you want to pass to your function before\n\ 177 the following arguments.\n\ 178 : param feature: The current feature\n\ 179 : param parent: The QgsExpression object\n\ 180 : param context: If there is an argument called ``context`` found at the last\n\ 181 position, this variable will contain a ``QgsExpressionContext``\n\ 182 object, that gives access to various additional information like\n\ 183 expression variables. E.g. ``context.variable( 'layer_id' )``\n\ 184 : returns: The result of the expression.\n\ 188 The @qgsfunction decorator accepts the following arguments:\n\ 191 : param args: Defines the number of arguments. With ``args = 'auto'`` the number of\n\ 192 arguments will automatically be extracted from the signature.\n\ 193 With ``args = -1``, any number of arguments are accepted.\n\ 194 : param group: The name of the group under which this expression function will\n\ 196 : param handlesnull: Set this to True if your function has custom handling for NULL values.\n\ 197 If False, the result will always be NULL as soon as any parameter is NULL.\n\ 198 Defaults to False.\n\ 199 : param usesgeometry : Set this to True if your function requires access to\n\ 200 feature.geometry(). Defaults to False.\n\ 201 : param referenced_columns: An array of attribute names that are required to run\n\ 202 this function. Defaults to [QgsFeatureRequest.ALL_ATTRIBUTES].\n\ 210 settings.
setValue( QStringLiteral(
"Windows/QgsExpressionBuilderWidget/splitter" ), splitter->saveState() );
211 settings.
setValue( QStringLiteral(
"Windows/QgsExpressionBuilderWidget/editorsplitter" ), editorSplit->saveState() );
212 settings.
setValue( QStringLiteral(
"Windows/QgsExpressionBuilderWidget/functionsplitter" ), functionsplit->saveState() );
230 void QgsExpressionBuilderWidget::currentChanged(
const QModelIndex &index,
const QModelIndex & )
232 txtSearchEditValues->clear();
235 QModelIndex idx = mProxyModel->mapToSource( index );
243 if ( mFieldValues.contains( item->text() ) )
245 const QStringList &values = mFieldValues[item->text()];
246 mValuesModel->setStringList( values );
250 mValuesModel->setStringList( QStringList() );
253 mValueGroupBox->setVisible( isField );
254 mShowHelpButton->setText( isField ? tr(
"Show Values" ) : tr(
"Show Help" ) );
257 QString help = loadFunctionHelp( item );
258 txtHelpText->setText( help );
261 void QgsExpressionBuilderWidget::btnRun_pressed()
263 if ( !cmbFileNames->currentItem() )
266 QString file = cmbFileNames->currentItem()->text();
268 runPythonCode( txtPython->text() );
271 void QgsExpressionBuilderWidget::runPythonCode(
const QString &code )
275 QString pythontext = code;
278 updateFunctionTree();
285 QDir myDir( mFunctionsPath );
286 if ( !myDir.exists() )
288 myDir.mkpath( mFunctionsPath );
291 if ( !fileName.endsWith( QLatin1String(
".py" ) ) )
293 fileName.append(
".py" );
296 fileName = mFunctionsPath + QDir::separator() + fileName;
297 QFile myFile( fileName );
298 if ( myFile.open( QIODevice::WriteOnly | QFile::Truncate ) )
300 QTextStream myFileStream( &myFile );
301 myFileStream << txtPython->text() << endl;
308 mFunctionsPath = path;
310 dir.setNameFilters( QStringList() << QStringLiteral(
"*.py" ) );
311 QStringList files = dir.entryList( QDir::Files );
312 cmbFileNames->clear();
313 Q_FOREACH (
const QString &name, files )
315 QFileInfo info( mFunctionsPath + QDir::separator() + name );
316 if ( info.baseName() == QLatin1String(
"__init__" ) )
continue;
317 QListWidgetItem *item =
new QListWidgetItem(
QgsApplication::getThemeIcon( QStringLiteral(
"console/iconTabEditorConsole.svg" ) ), info.baseName() );
318 cmbFileNames->addItem( item );
320 if ( !cmbFileNames->currentItem() )
322 cmbFileNames->setCurrentRow( 0 );
325 if ( cmbFileNames->count() == 0 )
329 txtPython->setText( QString(
"'''\n#Sample custom function file\n " 330 "(uncomment to use and customize or Add button to create a new file) \n%1 \n '''" ).arg( txtPython->text() ) );
337 QList<QListWidgetItem *> items = cmbFileNames->findItems( fileName, Qt::MatchExactly );
338 if ( !items.isEmpty() )
341 QListWidgetItem *item =
new QListWidgetItem(
QgsApplication::getThemeIcon( QStringLiteral(
"console/iconTabEditorConsole.svg" ) ), fileName );
342 cmbFileNames->insertItem( 0, item );
343 cmbFileNames->setCurrentRow( 0 );
347 txtPython->setText( templatetxt );
351 void QgsExpressionBuilderWidget::btnNewFile_pressed()
354 QString text = QInputDialog::getText(
this, tr(
"New File" ),
355 tr(
"New file name:" ), QLineEdit::Normal,
357 if ( ok && !text.isEmpty() )
363 void QgsExpressionBuilderWidget::cmbFileNames_currentItemChanged( QListWidgetItem *item, QListWidgetItem *lastitem )
367 QString filename = lastitem->text();
370 QString path = mFunctionsPath + QDir::separator() + item->text();
376 if ( !path.endsWith( QLatin1String(
".py" ) ) )
377 path.append(
".py" );
379 txtPython->loadScript( path );
384 txtPython->setText( code );
387 void QgsExpressionBuilderWidget::expressionTree_doubleClicked(
const QModelIndex &index )
389 QModelIndex idx = mProxyModel->mapToSource( index );
400 txtExpressionString->setFocus();
419 txtExpressionString->setFields( fields );
421 QStringList fieldNames;
422 fieldNames.reserve( fields.
count() );
423 for (
int i = 0; i < fields.
count(); ++i )
426 QString fieldName = field.
name();
427 fieldNames << fieldName;
437 for (
auto it = fieldValues.constBegin(); it != fieldValues.constEnd(); ++it )
442 mFieldValues = fieldValues;
445 void QgsExpressionBuilderWidget::fillFieldValues(
const QString &fieldName,
int countLimit )
456 if ( fieldIndex < 0 )
459 QStringList strValues;
460 QList<QVariant> values = mLayer->
uniqueValues( fieldIndex, countLimit ).toList();
461 std::sort( values.begin(), values.end() );
462 Q_FOREACH (
const QVariant &value, values )
465 if ( value.isNull() )
466 strValue = QStringLiteral(
"NULL" );
467 else if ( value.type() == QVariant::Int || value.type() == QVariant::Double || value.type() == QVariant::LongLong )
468 strValue = value.toString();
470 strValue =
'\'' + value.toString().replace(
'\'', QLatin1String(
"''" ) ) +
'\'';
471 strValues.append( strValue );
473 mValuesModel->setStringList( strValues );
474 mFieldValues[fieldName] = strValues;
484 return "<head><style>" + helpStylesheet() +
"</style></head><body>" + helpContents +
"</body>";
489 const QString &label,
491 const QString &helpText,
495 item->setData( label, Qt::UserRole );
497 item->setIcon( icon );
500 if ( mExpressionGroups.contains( group ) )
503 groupNode->appendRow( item );
509 newgroupNode->setData( group, Qt::UserRole );
512 newgroupNode->appendRow( item );
513 newgroupNode->setBackground( QBrush( QColor( 238, 238, 238 ) ) );
514 mModel->appendRow( newgroupNode );
515 mExpressionGroups.insert( group, newgroupNode );
518 if ( highlightedItem )
522 topLevelItem->setData( label, Qt::UserRole );
524 QFont font = topLevelItem->font();
525 font.setBold(
true );
526 topLevelItem->setFont( font );
527 mModel->appendRow( topLevelItem );
534 return mExpressionValid;
540 QString location = QStringLiteral(
"/expressions/recent/%1" ).arg( collection );
541 QStringList expressions = settings.
value( location ).toStringList();
546 while ( expressions.count() > 20 )
548 expressions.pop_back();
551 settings.
setValue( location, expressions );
557 mRecentKey = collection;
558 QString name = tr(
"Recent (%1)" ).arg( collection );
559 if ( mExpressionGroups.contains( name ) )
562 node->removeRows( 0, node->rowCount() );
566 QString location = QStringLiteral(
"/expressions/recent/%1" ).arg( collection );
567 QStringList expressions = settings.
value( location ).toStringList();
569 Q_FOREACH (
const QString &expression, expressions )
576 void QgsExpressionBuilderWidget::loadLayers()
581 QMap<QString, QgsMapLayer *> layers = mProject->mapLayers();
582 QMap<QString, QgsMapLayer *>::const_iterator layerIt = layers.constBegin();
583 for ( ; layerIt != layers.constEnd(); ++layerIt )
585 registerItemForAllGroups( QStringList() << tr(
"Map Layers" ), layerIt.value()->name(), QStringLiteral(
"'%1'" ).arg( layerIt.key() ), formatLayerHelp( layerIt.value() ) );
589 void QgsExpressionBuilderWidget::loadRelations()
594 QMap<QString, QgsRelation> relations = mProject->relationManager()->relations();
595 QMap<QString, QgsRelation>::const_iterator relIt = relations.constBegin();
596 for ( ; relIt != relations.constEnd(); ++relIt )
598 registerItemForAllGroups( QStringList() << tr(
"Relations" ), relIt->name(), QStringLiteral(
"'%1'" ).arg( relIt->id() ), formatRelationHelp( relIt.value() ) );
602 void QgsExpressionBuilderWidget::updateFunctionTree()
605 mExpressionGroups.clear();
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 );
637 for (
int i = 0; i < count; i++ )
640 QString name = func->
name();
641 if ( name.startsWith(
'_' ) )
651 if ( func->
params() != 0 )
653 else if ( !name.startsWith(
'$' ) )
654 name += QLatin1String(
"()" );
664 loadExpressionContext();
674 return txtExpressionString->text();
679 txtExpressionString->setText( expression );
684 return lblExpected->text();
689 lblExpected->setText( expected );
690 mExpectedOutputFrame->setVisible( !expected.isNull() );
695 mExpressionContext = context;
696 updateFunctionTree();
701 void QgsExpressionBuilderWidget::txtExpressionString_textChanged()
708 if ( text.isEmpty() )
711 lblPreview->setStyleSheet( QString() );
712 txtExpressionString->setToolTip( QString() );
713 lblPreview->setToolTip( QString() );
715 setParserError(
true );
716 setEvalError(
true );
737 QVariant value = exp.
evaluate( &mExpressionContext );
748 tooltip = QStringLiteral(
"<b>%1:</b>" 749 "%2" ).arg( tr(
"Parser Errors" ), errorString );
752 tooltip += QStringLiteral(
"<b>%1:</b> %2" ).arg( tr(
"Eval Error" ), exp.
evalErrorString() );
754 lblPreview->setText( tr(
"Expression is invalid <a href=""more"">(more info)</a>" ) );
755 lblPreview->setStyleSheet( QStringLiteral(
"color: rgba(255, 6, 10, 255);" ) );
756 txtExpressionString->setToolTip( tooltip );
757 lblPreview->setToolTip( tooltip );
766 lblPreview->setStyleSheet( QString() );
767 txtExpressionString->setToolTip( QString() );
768 lblPreview->setToolTip( QString() );
770 setParserError(
false );
771 setEvalError(
false );
777 void QgsExpressionBuilderWidget::loadExpressionContext()
779 txtExpressionString->setExpressionContext( mExpressionContext );
781 Q_FOREACH (
const QString &variable, variableNames )
783 registerItem( QStringLiteral(
"Variables" ), variable,
" @" + variable +
' ',
790 QStringList contextFunctions = mExpressionContext.
functionNames();
791 Q_FOREACH (
const QString &functionName, contextFunctions )
794 QString name = func->
name();
795 if ( name.startsWith(
'_' ) )
797 if ( func->
params() != 0 )
803 void QgsExpressionBuilderWidget::registerItemForAllGroups(
const QStringList &groups,
const QString &label,
const QString &
expressionText,
const QString &helpText,
QgsExpressionItem::ItemType type,
bool highlightedItem,
int sortOrder )
805 Q_FOREACH (
const QString &group, groups )
811 QString QgsExpressionBuilderWidget::formatRelationHelp(
const QgsRelation &relation )
const 813 QString text = QStringLiteral(
"<p>%1</p>" ).arg( tr(
"Inserts the relation ID for the relation named '%1'." ).arg( relation.
name() ) );
814 text.append( QStringLiteral(
"<p>%1</p>" ).arg( tr(
"Current value: '%1'" ).arg( relation.
id() ) ) );
818 QString QgsExpressionBuilderWidget::formatLayerHelp(
const QgsMapLayer *layer )
const 820 QString text = QStringLiteral(
"<p>%1</p>" ).arg( tr(
"Inserts the layer ID for the layer named '%1'." ).arg( layer->
name() ) );
821 text.append( QStringLiteral(
"<p>%1</p>" ).arg( tr(
"Current value: '%1'" ).arg( layer->
id() ) ) );
830 void QgsExpressionBuilderWidget::setParserError(
bool parserError )
832 if ( parserError == mParserError )
844 void QgsExpressionBuilderWidget::setEvalError(
bool evalError )
846 if ( evalError == mEvalError )
866 updateFunctionTree();
871 QWidget::showEvent( e );
872 txtExpressionString->setFocus();
875 void QgsExpressionBuilderWidget::createErrorMarkers( QList<QgsExpression::ParserError> errors )
880 int errorFirstLine = error.firstLine - 1 ;
881 int errorFirstColumn = error.firstColumn - 1;
882 int errorLastColumn = error.lastColumn - 1;
883 int errorLastLine = error.lastLine - 1;
889 errorFirstLine = errorLastLine;
890 errorFirstColumn = errorLastColumn - 1;
892 txtExpressionString->fillIndicatorRange( errorFirstLine,
895 errorLastColumn, error.errorType );
899 void QgsExpressionBuilderWidget::createMarkers(
const QgsExpressionNode *inNode )
903 case QgsExpressionNode::NodeType::ntFunction:
906 txtExpressionString->SendScintilla( QsciScintilla::SCI_SETINDICATORCURRENT, FUNCTION_MARKER_ID );
907 txtExpressionString->SendScintilla( QsciScintilla::SCI_SETINDICATORVALUE, node->
fnIndex() );
910 int start_pos = txtExpressionString->positionFromLineIndex( inNode->
parserFirstLine - 1, start );
911 txtExpressionString->SendScintilla( QsciScintilla::SCI_INDICATORFILLRANGE, start_pos, end - start );
914 const QList< QgsExpressionNode * > nodeList = node->
args()->
list();
922 case QgsExpressionNode::NodeType::ntLiteral:
926 case QgsExpressionNode::NodeType::ntUnaryOperator:
929 createMarkers( node->
operand() );
932 case QgsExpressionNode::NodeType::ntBinaryOperator:
935 createMarkers( node->
opLeft() );
936 createMarkers( node->
opRight() );
939 case QgsExpressionNode::NodeType::ntColumnRef:
943 case QgsExpressionNode::NodeType::ntInOperator:
948 const QList< QgsExpressionNode * > nodeList = node->
list()->
list();
956 case QgsExpressionNode::NodeType::ntCondition:
961 createMarkers( cond->whenExp() );
962 createMarkers( cond->thenExp() );
966 createMarkers( node->
elseExp() );
973 void QgsExpressionBuilderWidget::clearFunctionMarkers()
975 int lastLine = txtExpressionString->lines() - 1;
976 txtExpressionString->clearIndicatorRange( 0, 0, lastLine, txtExpressionString->text( lastLine ).length() - 1, FUNCTION_MARKER_ID );
979 void QgsExpressionBuilderWidget::clearErrors()
981 int lastLine = txtExpressionString->lines() - 1;
990 void QgsExpressionBuilderWidget::txtSearchEdit_textChanged()
992 mProxyModel->setFilterWildcard( txtSearchEdit->text() );
993 if ( txtSearchEdit->text().isEmpty() )
995 expressionTree->collapseAll();
999 expressionTree->expandAll();
1000 QModelIndex index = mProxyModel->index( 0, 0 );
1001 if ( mProxyModel->hasChildren( index ) )
1003 QModelIndex child = mProxyModel->index( 0, 0, index );
1004 expressionTree->selectionModel()->setCurrentIndex( child, QItemSelectionModel::ClearAndSelect );
1009 void QgsExpressionBuilderWidget::txtSearchEditValues_textChanged()
1011 mProxyValues->setFilterCaseSensitivity( Qt::CaseInsensitive );
1012 mProxyValues->setFilterWildcard( txtSearchEditValues->text() );
1015 void QgsExpressionBuilderWidget::lblPreview_linkActivated(
const QString &link )
1019 mv->setWindowTitle( tr(
"More Info on Expression Error" ) );
1024 void QgsExpressionBuilderWidget::mValuesListView_doubleClicked(
const QModelIndex &index )
1027 txtExpressionString->insertText(
' ' + index.data( Qt::DisplayRole ).toString() +
' ' );
1028 txtExpressionString->setFocus();
1031 void QgsExpressionBuilderWidget::operatorButtonClicked()
1033 QPushButton *button =
dynamic_cast<QPushButton *
>( sender() );
1036 txtExpressionString->insertText(
' ' + button->text() +
' ' );
1037 txtExpressionString->setFocus();
1040 void QgsExpressionBuilderWidget::showContextMenu( QPoint pt )
1042 QModelIndex idx = expressionTree->indexAt( pt );
1043 idx = mProxyModel->mapToSource( idx );
1050 QMenu *menu =
new QMenu(
this );
1051 menu->addAction( tr(
"Load First 10 Unique Values" ),
this, SLOT(
loadSampleValues() ) );
1052 menu->addAction( tr(
"Load All Unique Values" ),
this, SLOT(
loadAllValues() ) );
1053 menu->popup( expressionTree->mapToGlobal( pt ) );
1059 QModelIndex idx = mProxyModel->mapToSource( expressionTree->currentIndex() );
1063 if ( !mLayer || !item )
1066 mValueGroupBox->show();
1067 fillFieldValues( item->text(), 10 );
1072 QModelIndex idx = mProxyModel->mapToSource( expressionTree->currentIndex() );
1076 if ( !mLayer || !item )
1079 mValueGroupBox->show();
1080 fillFieldValues( item->text(), -1 );
1083 void QgsExpressionBuilderWidget::txtPython_textChanged()
1085 lblAutoSave->setText( tr(
"Saving…" ) );
1095 if ( tabWidget->currentIndex() != 1 )
1098 QListWidgetItem *item = cmbFileNames->currentItem();
1102 QString file = item->text();
1104 lblAutoSave->setText( QStringLiteral(
"Saved" ) );
1105 QGraphicsOpacityEffect *effect =
new QGraphicsOpacityEffect();
1106 lblAutoSave->setGraphicsEffect( effect );
1107 QPropertyAnimation *anim =
new QPropertyAnimation( effect,
"opacity" );
1108 anim->setDuration( 2000 );
1109 anim->setStartValue( 1.0 );
1110 anim->setEndValue( 0.0 );
1111 anim->setEasingCurve( QEasingCurve::OutQuad );
1112 anim->start( QAbstractAnimation::DeleteWhenStopped );
1115 void QgsExpressionBuilderWidget::indicatorClicked(
int line,
int index, Qt::KeyboardModifiers state )
1117 if ( state & Qt::ControlModifier )
1119 int position = txtExpressionString->positionFromLineIndex( line, index );
1120 long fncIndex = txtExpressionString->SendScintilla( QsciScintilla::SCI_INDICATORVALUEAT, FUNCTION_MARKER_ID, static_cast<long int>( position ) );
1122 QString help = getFunctionHelp( func );
1123 txtHelpText->setText( help );
1127 void QgsExpressionBuilderWidget::setExpressionState(
bool state )
1129 mExpressionValid = state;
1132 QString QgsExpressionBuilderWidget::helpStylesheet()
const 1138 style +=
" .functionname {color: #0a6099; font-weight: bold;} " 1139 " .argument {font-family: monospace; color: #bf0c0c; font-style: italic; } " 1140 " td.argument { padding-right: 10px; }";
1145 QString QgsExpressionBuilderWidget::loadFunctionHelp(
QgsExpressionItem *expressionItem )
1147 if ( !expressionItem )
1150 QString helpContents = expressionItem->
getHelpText();
1153 if ( helpContents.isEmpty() )
1155 QString name = expressionItem->data( Qt::UserRole ).toString();
1163 return "<head><style>" + helpStylesheet() +
"</style></head><body>" + helpContents +
"</body>";
1172 setFilterCaseSensitivity( Qt::CaseInsensitive );
1177 QModelIndex index = sourceModel()->index( source_row, 0, source_parent );
1180 int count = sourceModel()->rowCount( index );
1181 bool matchchild =
false;
1182 for (
int i = 0; i < count; ++i )
1184 if ( filterAcceptsRow( i, index ) )
1197 return QSortFilterProxyModel::filterAcceptsRow( source_row, source_parent );
1204 if ( leftSort != rightSort )
1205 return leftSort < rightSort;
1207 QString leftString = sourceModel()->data( left, Qt::DisplayRole ).toString();
1208 QString rightString = sourceModel()->data( right, Qt::DisplayRole ).toString();
1211 if ( leftString.startsWith(
'$' ) )
1212 leftString = leftString.mid( 1 );
1213 if ( rightString.startsWith(
'$' ) )
1214 rightString = rightString.mid( 1 );
1216 return QString::localeAwareCompare( leftString, rightString ) < 0;
Class for parsing and evaluation of expressions (formerly called "search strings").
int parserFirstColumn
First column in the parser this node was found.
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
static QString formatPreviewString(const QVariant &value, bool htmlOutput=true)
Formats an expression result for friendly display to the user.
bool isHighlightedVariable(const QString &name) const
Returns true if the specified variable name is intended to be highlighted to the user.
Base class for all map layer types.
QString getExpressionText() const
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
QIcon iconForField(int fieldIdx) const
Returns an icon corresponding to a field index, based on the field's type and source.
QString getHelpText() const
Gets the help text that is associated with this expression item.
bool isValid() const
Returns the validity of this feature.
This class is a composition of two QSettings instances:
static QString group(const QString &group)
Returns the translated name for a function group.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Details about any parser errors that were found when parsing the expression.
int fnIndex() const
Returns the index of the node's function.
QVariant evaluate()
Evaluate the feature and return the result.
An expression node for CASE WHEN clauses.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Container of fields for a vector layer.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
QgsExpressionNode * elseExp() const
The ELSE expression used for the condition.
QString name() const
The name of the function.
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()
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
QgsExpressionNode::NodeList * list() const
Returns the list of nodes to search for matching values within.
Function was called with invalid args.
QVariant variable(const QString &name) const
Fetches a matching variable from the context.
QgsExpressionNode::NodeList * args() const
Returns a list of arguments specified for the function.
Non named function arg used after named arg.
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.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
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)...
QgsFeature feature() const
Convenience function for retrieving the feature for the context, if set.
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) ...
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
QStringList groups() const
Returns a list of the groups the function belongs to.
Reads and writes project states.
int count() const
Returns number of items.
QStringList functionNames() const
Retrieves a list of function names contained in the context.
Abstract base class for all nodes that can appear in an expression.
static const int ITEM_TYPE_ROLE
Item type role.
QList< QgsExpression::ParserError > parserErrors() const
Returns parser error details including location of error.
Encapsulate a field in an attribute table or data source.
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
An expression node for expression functions.
const QString helpText() const
The help text for the function.
WhenThenList conditions() const
The list of WHEN THEN expression parts of the expression.
QString description(const QString &name) const
Returns a translated description string for the variable with specified name.
QgsExpressionNode * operand() const
Returns the node the operator will operate upon.
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.
int params() const
The number of parameters this function takes.
virtual bool isDeprecated() const
Returns true if the function is deprecated and should not be presented as a valid option to users in ...
static bool eval(const QString &command, QString &result)
Eval a Python statement.
static const int CUSTOM_SORT_ROLE
Custom sort order role.
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.
QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const FINAL
Calculates a list of unique values contained within an attribute in the layer.
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.
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).
QgsExpressionNode * opLeft() const
Returns the node to the left of the operator.
QStringList filteredVariableNames() const
Returns a filtered list of variables names set by all scopes in the context.
A binary expression operator, which operates on two values.
A generic message view for displaying QGIS messages.
bool isHighlightedFunction(const QString &name) const
Returns true if the specified function name is intended to be highlighted to the user.
QgsExpressionFunction * function(const QString &name) const
Fetches a matching function from the context.
const QgsExpressionNode * rootNode() const
Returns root node of the expression. Root node is null is parsing has failed.
static QString helpText(QString name)
Returns the help text for a specified function.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Query the layer for features specified in request.
QgsExpressionNode * opRight() const
Returns the node to the right of the operator.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
bool nextFeature(QgsFeature &f)
Represents a vector layer which manages a vector based data sets.
bool isEmpty() const
Checks whether the container is empty.
bool isContextual() const
Returns whether the function is only available if provided by a QgsExpressionContext object...
QString parserErrorString() const
Returns parser error.
virtual QgsExpressionNode::NodeType nodeType() const =0
Gets the type of this node.
QString evalErrorString() const
Returns evaluation error.
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.
int parserLastColumn
Last column in the parser this node was found.
QgsExpressionItem::ItemType getItemType() const
Gets the type of expression item, e.g., header, field, ExpressionNode.