20#include <QInputDialog>
22#include <QGraphicsOpacityEffect>
23#include <QPropertyAnimation>
25#include <QVersionNumber>
27#include <QJsonDocument>
61 if ( fieldIndex != -1 )
79 connect( btnRun, &QToolButton::pressed,
this, &QgsExpressionBuilderWidget::btnRun_pressed );
80 connect( btnNewFile, &QPushButton::clicked,
this, &QgsExpressionBuilderWidget::btnNewFile_pressed );
81 connect( btnRemoveFile, &QPushButton::clicked,
this, &QgsExpressionBuilderWidget::btnRemoveFile_pressed );
82 connect( cmbFileNames, &QListWidget::currentItemChanged,
this, &QgsExpressionBuilderWidget::cmbFileNames_currentItemChanged );
83 connect( txtExpressionString, &QgsCodeEditorExpression::textChanged,
this, &QgsExpressionBuilderWidget::txtExpressionString_textChanged );
84 connect( txtPython, &QgsCodeEditorPython::textChanged,
this, &QgsExpressionBuilderWidget::txtPython_textChanged );
85 connect( txtSearchEditValues, &QgsFilterLineEdit::textChanged,
this, &QgsExpressionBuilderWidget::txtSearchEditValues_textChanged );
86 connect( mValuesListView, &QListView::doubleClicked,
this, &QgsExpressionBuilderWidget::mValuesListView_doubleClicked );
90 connect( btnImportExpressions, &QToolButton::clicked,
this, &QgsExpressionBuilderWidget::importUserExpressions_pressed );
91 connect( btnExportExpressions, &QToolButton::clicked,
this, &QgsExpressionBuilderWidget::exportUserExpressions_pressed );
92 connect( btnClearEditor, &QToolButton::clicked, txtExpressionString, &QgsCodeEditorExpression::clear );
105 mExpressionTreeMenuProvider =
new ExpressionTreeMenuProvider(
this );
106 mExpressionTreeView->setMenuProvider( mExpressionTreeMenuProvider );
108 txtHelpText->setOpenExternalLinks(
true );
109 mValueGroupBox->hide();
126 const auto pushButtons { mOperatorsGroupBox->findChildren<QPushButton *>() };
127 for ( QPushButton *button : pushButtons )
129 connect( button, &QAbstractButton::clicked,
this, &QgsExpressionBuilderWidget::operatorButtonClicked );
132 txtSearchEdit->setShowSearchIcon(
true );
133 txtSearchEdit->setPlaceholderText( tr(
"Search…" ) );
135 mValuesModel = std::make_unique<QStandardItemModel>();
136 mProxyValues = std::make_unique<QSortFilterProxyModel>();
137 mProxyValues->setSourceModel( mValuesModel.get() );
138 mValuesListView->setModel( mProxyValues.get() );
139 txtSearchEditValues->setShowSearchIcon(
true );
140 txtSearchEditValues->setPlaceholderText( tr(
"Search…" ) );
142 editorSplit->setSizes( QList<int>( {175, 300} ) );
144 functionsplit->setCollapsible( 0,
false );
145 connect( mShowHelpButton, &QPushButton::clicked,
this, [ = ]()
147 functionsplit->setSizes( QList<int>( {mOperationListGroup->width() - mHelpAndValuesWidget->minimumWidth(),
148 mHelpAndValuesWidget->minimumWidth()
150 mShowHelpButton->setEnabled(
false );
152 connect( functionsplit, &QSplitter::splitterMoved,
this, [ = ](
int,
int )
154 mShowHelpButton->setEnabled( functionsplit->sizes().at( 1 ) == 0 );
158 splitter->restoreState( settings.value( QStringLiteral(
"Windows/QgsExpressionBuilderWidget/splitter" ) ).toByteArray() );
159 editorSplit->restoreState( settings.value( QStringLiteral(
"Windows/QgsExpressionBuilderWidget/editorsplitter" ) ).toByteArray() );
160 functionsplit->restoreState( settings.value( QStringLiteral(
"Windows/QgsExpressionBuilderWidget/functionsplitter" ) ).toByteArray() );
161 mShowHelpButton->setEnabled( functionsplit->sizes().at( 1 ) == 0 );
167 btnRemoveFile->setEnabled( cmbFileNames->count() > 0 );
174 txtExpressionString->setWrapMode( QsciScintilla::WrapWord );
175 lblAutoSave->clear();
182#if defined(QSCINTILLA_VERSION) && QSCINTILLA_VERSION >= 0x20a00
189 txtExpressionString->setIndicatorForegroundColor( QColor( Qt::red ), -1 );
190 txtExpressionString->setIndicatorHoverForegroundColor( QColor( Qt::red ), -1 );
191 txtExpressionString->setIndicatorOutlineColor( QColor( Qt::red ), -1 );
194 txtExpressionString->indicatorDefine( QgsCodeEditor::HiddenIndicator, FUNCTION_MARKER_ID );
195 txtExpressionString->setIndicatorForegroundColor( QColor( Qt::blue ), FUNCTION_MARKER_ID );
196 txtExpressionString->setIndicatorHoverForegroundColor( QColor( Qt::blue ), FUNCTION_MARKER_ID );
197 txtExpressionString->setIndicatorHoverStyle( QgsCodeEditor::DotsIndicator, FUNCTION_MARKER_ID );
199 connect( txtExpressionString, &QgsCodeEditorExpression::indicatorClicked,
this, &QgsExpressionBuilderWidget::indicatorClicked );
200 txtExpressionString->setAutoCompletionCaseSensitivity(
false );
201 txtExpressionString->setAutoCompletionSource( QsciScintilla::AcsAPIs );
202 txtExpressionString->setCallTipsVisible( 0 );
205 mFunctionBuilderHelp->setLineNumbersVisible(
false );
206 mFunctionBuilderHelp->setFoldingVisible(
false );
207 mFunctionBuilderHelp->setEdgeMode( QsciScintilla::EdgeNone );
208 mFunctionBuilderHelp->setEdgeColumn( 0 );
209 mFunctionBuilderHelp->setReadOnly(
true );
210 mFunctionBuilderHelp->setText( tr(
"\"\"\"Define a new function using the @qgsfunction decorator.\n\
212 The function accepts the following parameters\n\
214 : param [any]: Define any parameters you want to pass to your function before\n\
215 the following arguments.\n\
216 : param feature: The current feature\n\
217 : param parent: The QgsExpression object\n\
218 : param context: If there is an argument called ``context`` found at the last\n\
219 position, this variable will contain a ``QgsExpressionContext``\n\
220 object, that gives access to various additional information like\n\
221 expression variables. E.g. ``context.variable( 'layer_id' )``\n\
222 : returns: The result of the expression.\n\
226 The @qgsfunction decorator accepts the following arguments:\n\
229 : param args: Defines the number of arguments. With ``args = 'auto'`` the number of\n\
230 arguments will automatically be extracted from the signature.\n\
231 With ``args = -1``, any number of arguments are accepted.\n\
232 : param group: The name of the group under which this expression function will\n\
234 : param handlesnull: Set this to True if your function has custom handling for NULL values.\n\
235 If False, the result will always be NULL as soon as any parameter is NULL.\n\
236 Defaults to False.\n\
237 : param usesgeometry : Set this to True if your function requires access to\n\
238 feature.geometry(). Defaults to False.\n\
239 : param referenced_columns: An array of attribute names that are required to run\n\
240 this function. Defaults to [QgsFeatureRequest.ALL_ATTRIBUTES].\n\
248 settings.
setValue( QStringLiteral(
"Windows/QgsExpressionBuilderWidget/splitter" ), splitter->saveState() );
249 settings.
setValue( QStringLiteral(
"Windows/QgsExpressionBuilderWidget/editorsplitter" ), editorSplit->saveState() );
250 settings.
setValue( QStringLiteral(
"Windows/QgsExpressionBuilderWidget/functionsplitter" ), functionsplit->saveState() );
251 delete mExpressionTreeMenuProvider;
259 mExpressionTreeView->loadRecent( recentCollection );
262 mExpressionTreeView->loadUserExpressions();
267 init( context, recentCollection, flags );
273 init( context, recentCollection, flags );
274 mExpressionTreeView->loadFieldNames( fields );
281 mExpressionTreeView->setLayer( mLayer );
282 mExpressionPreviewWidget->setLayer( mLayer );
289 expressionContextUpdated();
290 txtExpressionString->setFields( mLayer->
fields() );
294void QgsExpressionBuilderWidget::expressionContextUpdated()
296 txtExpressionString->setExpressionContext( mExpressionContext );
297 mExpressionTreeView->setExpressionContext( mExpressionContext );
298 mExpressionPreviewWidget->setExpressionContext( mExpressionContext );
306void QgsExpressionBuilderWidget::expressionTreeItemChanged(
QgsExpressionItem *item )
308 txtSearchEditValues->clear();
316 mValuesModel->clear();
319 cbxValuesInUse->setChecked(
false );
321 mValueGroupBox->setVisible( isField );
323 mShowHelpButton->setText( isField ? tr(
"Show Values" ) : tr(
"Show Help" ) );
326 QString help = loadFunctionHelp( item );
327 txtHelpText->setText( help );
329 bool isUserExpression = item->parent() && item->parent()->text() == mUserExpressionsGroupName;
331 btnRemoveExpression->setEnabled( isUserExpression );
332 btnEditExpression->setEnabled( isUserExpression );
335void QgsExpressionBuilderWidget::btnRun_pressed()
337 if ( !cmbFileNames->currentItem() )
340 QString file = cmbFileNames->currentItem()->text();
342 runPythonCode( txtPython->text() );
345void QgsExpressionBuilderWidget::runPythonCode(
const QString &code )
349 QString pythontext = code;
352 mExpressionTreeView->refresh();
372 QDir myDir( mFunctionsPath );
373 if ( !myDir.exists() )
375 myDir.mkpath( mFunctionsPath );
378 if ( !fileName.endsWith( QLatin1String(
".py" ) ) )
380 fileName.append(
".py" );
383 fileName = mFunctionsPath + QDir::separator() + fileName;
384 QFile myFile( fileName );
385 if ( myFile.open( QIODevice::WriteOnly | QFile::Truncate ) )
387 QTextStream myFileStream( &myFile );
388 myFileStream << txtPython->text() << Qt::endl;
395 mFunctionsPath = path;
397 dir.setNameFilters( QStringList() << QStringLiteral(
"*.py" ) );
398 QStringList files = dir.entryList( QDir::Files );
399 cmbFileNames->clear();
400 const auto constFiles = files;
401 for (
const QString &name : constFiles )
403 QFileInfo info( mFunctionsPath + QDir::separator() + name );
404 if ( info.baseName() == QLatin1String(
"__init__" ) )
continue;
405 QListWidgetItem *item =
new QListWidgetItem(
QgsApplication::getThemeIcon( QStringLiteral(
"console/iconTabEditorConsole.svg" ) ), info.baseName() );
406 cmbFileNames->addItem( item );
408 if ( !cmbFileNames->currentItem() )
410 cmbFileNames->setCurrentRow( 0 );
413 if ( cmbFileNames->count() == 0 )
417 txtPython->setText( QStringLiteral(
"'''\n#Sample custom function file\n"
418 "#(uncomment to use and customize or Add button to create a new file) \n%1 \n '''" ).arg( txtPython->text() ) );
425 QList<QListWidgetItem *> items = cmbFileNames->findItems( fileName, Qt::MatchExactly );
426 if ( !items.isEmpty() )
429 QListWidgetItem *item =
new QListWidgetItem(
QgsApplication::getThemeIcon( QStringLiteral(
"console/iconTabEditorConsole.svg" ) ), fileName );
430 cmbFileNames->insertItem( 0, item );
431 cmbFileNames->setCurrentRow( 0 );
435 txtPython->setText( templatetxt );
439void QgsExpressionBuilderWidget::btnNewFile_pressed()
442 QString text = QInputDialog::getText(
this, tr(
"New File" ),
443 tr(
"New file name:" ), QLineEdit::Normal,
445 if ( ok && !text.isEmpty() )
451void QgsExpressionBuilderWidget::btnRemoveFile_pressed()
453 if ( QMessageBox::question(
this, tr(
"Remove File" ),
454 tr(
"Are you sure you want to remove current functions file?" ),
455 QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) == QMessageBox::No )
458 int currentRow = cmbFileNames->currentRow();
459 QString fileName = cmbFileNames->currentItem()->text();
460 if ( QFile::remove( mFunctionsPath + QDir::separator() + fileName.append(
".py" ) ) )
463 QListWidgetItem *itemToRemove =
whileBlocking( cmbFileNames )->takeItem( currentRow );
467 if ( cmbFileNames->count() > 0 )
469 cmbFileNames->setCurrentRow( currentRow > 0 ? currentRow - 1 : 0 );
470 loadCodeFromFile( mFunctionsPath + QDir::separator() + cmbFileNames->currentItem()->text() );
474 btnRemoveFile->setEnabled(
false );
480 QMessageBox::warning(
this, tr(
"Remove file" ), tr(
"Failed to remove function file '%1'." ).arg( fileName ) );
484void QgsExpressionBuilderWidget::cmbFileNames_currentItemChanged( QListWidgetItem *item, QListWidgetItem *lastitem )
488 QString filename = lastitem->text();
491 QString path = mFunctionsPath + QDir::separator() + item->text();
497 if ( !path.endsWith( QLatin1String(
".py" ) ) )
498 path.append(
".py" );
500 txtPython->loadScript( path );
505 txtPython->setText( code );
508void QgsExpressionBuilderWidget::insertExpressionText(
const QString &text )
511 txtExpressionString->insertText( text );
512 txtExpressionString->setFocus();
517 Q_UNUSED( fieldValues )
521void QgsExpressionBuilderWidget::fillFieldValues(
const QString &fieldName,
QgsVectorLayer *layer,
int countLimit,
bool forceUsedValues )
533 if ( fieldIndex < 0 )
540 if ( cbxValuesInUse->isVisible() && !cbxValuesInUse->isChecked() && !forceUsedValues )
544 values =
formatter->availableValues( setup.
config(), countLimit, fieldFormatterContext );
550 std::sort( values.begin(), values.end() );
552 mValuesModel->clear();
553 for (
const QVariant &value : std::as_const( values ) )
556 bool forceRepresentedValue =
false;
558 strValue = QStringLiteral(
"NULL" );
559 else if ( value.type() == QVariant::Int || value.type() == QVariant::Double || value.type() == QVariant::LongLong )
560 strValue = value.toString();
561 else if ( value.type() == QVariant::StringList )
564 const QStringList strList = value.toStringList();
565 for ( QString
str : strList )
567 if ( !result.isEmpty() )
568 result.append( QStringLiteral(
", " ) );
570 result.append(
'\'' +
str.replace(
'\'', QLatin1String(
"''" ) ) +
'\'' );
572 strValue = QStringLiteral(
"array(%1)" ).arg( result );
573 forceRepresentedValue =
true;
575 else if ( value.type() == QVariant::List )
578 const QList list = value.toList();
579 for (
const QVariant &item : list )
581 if ( !result.isEmpty() )
582 result.append( QStringLiteral(
", " ) );
584 result.append( item.toString() );
586 strValue = QStringLiteral(
"array(%1)" ).arg( result );
587 forceRepresentedValue =
true;
590 strValue =
'\'' + value.toString().replace(
'\'', QLatin1String(
"''" ) ) +
'\'';
592 QString representedValue =
formatter->representValue(
layer, fieldIndex, setup.
config(), QVariant(), value );
593 if ( forceRepresentedValue || representedValue != value.toString() )
594 representedValue = representedValue + QStringLiteral(
" [" ) + strValue +
']';
596 QStandardItem *item =
new QStandardItem( representedValue );
597 item->setData( strValue );
598 mValuesModel->appendRow( item );
609 return QStringLiteral(
"<head><style>" ) + helpStylesheet() + QStringLiteral(
"</style></head><body>" ) + helpContents + QStringLiteral(
"</body>" );
617 return mExpressionValid;
622 mExpressionTreeView->saveToRecent(
expressionText(), collection );
627 mExpressionTreeView->loadRecent( collection );
632 return mExpressionTreeView;
638 mExpressionTreeView->loadUserExpressions();
643 mExpressionTreeView->saveToUserExpressions( label, expression, helpText );
648 mExpressionTreeView->removeFromUserExpressions( label );
654 mExpressionPreviewWidget->setGeomCalculator( da );
659 return txtExpressionString->text();
664 txtExpressionString->setText( expression );
669 return lblExpected->text();
674 lblExpected->setText( expected );
675 mExpectedOutputFrame->setVisible( !expected.isNull() );
680 mExpressionContext = context;
681 expressionContextUpdated();
684void QgsExpressionBuilderWidget::txtExpressionString_textChanged()
688 btnClearEditor->setEnabled( ! txtExpressionString->text().isEmpty() );
689 btnSaveExpression->setEnabled(
false );
691 mExpressionPreviewWidget->setExpressionText( text );
696 return mExpressionPreviewWidget->parserError();
701 mExpressionPreviewWidget->setVisible( isVisible );
706 return mExpressionPreviewWidget->evalError();
712 return mExpressionTreeView->model();
724 mExpressionTreeView->setProject(
project );
729 QWidget::showEvent( e );
730 txtExpressionString->setFocus();
733void QgsExpressionBuilderWidget::createErrorMarkers(
const QList<QgsExpression::ParserError> &errors )
738 int errorFirstLine = error.firstLine - 1 ;
739 int errorFirstColumn = error.firstColumn - 1;
740 int errorLastColumn = error.lastColumn - 1;
741 int errorLastLine = error.lastLine - 1;
747 errorFirstLine = errorLastLine;
748 errorFirstColumn = errorLastColumn - 1;
750 txtExpressionString->fillIndicatorRange( errorFirstLine,
753 errorLastColumn, error.errorType );
761 case QgsExpressionNode::NodeType::ntFunction:
764 txtExpressionString->SendScintilla( QsciScintilla::SCI_SETINDICATORCURRENT, FUNCTION_MARKER_ID );
765 txtExpressionString->SendScintilla( QsciScintilla::SCI_SETINDICATORVALUE, node->
fnIndex() );
768 int start_pos = txtExpressionString->positionFromLineIndex( inNode->
parserFirstLine - 1, start );
769 txtExpressionString->SendScintilla( QsciScintilla::SCI_INDICATORFILLRANGE, start_pos, end - start );
772 const QList< QgsExpressionNode * > nodeList = node->
args()->
list();
780 case QgsExpressionNode::NodeType::ntLiteral:
784 case QgsExpressionNode::NodeType::ntUnaryOperator:
787 createMarkers( node->
operand() );
790 case QgsExpressionNode::NodeType::ntBetweenOperator:
797 case QgsExpressionNode::NodeType::ntBinaryOperator:
800 createMarkers( node->
opLeft() );
801 createMarkers( node->
opRight() );
804 case QgsExpressionNode::NodeType::ntColumnRef:
808 case QgsExpressionNode::NodeType::ntInOperator:
813 const QList< QgsExpressionNode * > nodeList = node->
list()->
list();
821 case QgsExpressionNode::NodeType::ntCondition:
824 const QList<QgsExpressionNodeCondition::WhenThen *> conditions = node->
conditions();
827 createMarkers( cond->whenExp() );
828 createMarkers( cond->thenExp() );
832 createMarkers( node->
elseExp() );
836 case QgsExpressionNode::NodeType::ntIndexOperator:
843void QgsExpressionBuilderWidget::clearFunctionMarkers()
845 int lastLine = txtExpressionString->lines() - 1;
846 txtExpressionString->clearIndicatorRange( 0, 0, lastLine, txtExpressionString->text( lastLine ).length() - 1, FUNCTION_MARKER_ID );
849void QgsExpressionBuilderWidget::clearErrors()
851 int lastLine = txtExpressionString->lines() - 1;
860void QgsExpressionBuilderWidget::txtSearchEditValues_textChanged()
862 mProxyValues->setFilterCaseSensitivity( Qt::CaseInsensitive );
863 mProxyValues->setFilterWildcard( txtSearchEditValues->text() );
866void QgsExpressionBuilderWidget::mValuesListView_doubleClicked(
const QModelIndex &index )
869 txtExpressionString->insertText(
' ' + index.data( Qt::UserRole + 1 ).toString() +
' ' );
870 txtExpressionString->setFocus();
873void QgsExpressionBuilderWidget::operatorButtonClicked()
875 QPushButton *button = qobject_cast<QPushButton *>( sender() );
878 txtExpressionString->insertText(
' ' + button->text() +
' ' );
879 txtExpressionString->setFocus();
898 mValueGroupBox->show();
918 mValueGroupBox->show();
938 mValueGroupBox->show();
958 mValueGroupBox->show();
962void QgsExpressionBuilderWidget::txtPython_textChanged()
964 lblAutoSave->setText( tr(
"Saving…" ) );
974 if ( tabWidget->currentIndex() != 1 )
977 QListWidgetItem *item = cmbFileNames->currentItem();
981 QString file = item->text();
983 lblAutoSave->setText( QStringLiteral(
"Saved" ) );
984 QGraphicsOpacityEffect *effect =
new QGraphicsOpacityEffect();
985 lblAutoSave->setGraphicsEffect( effect );
986 QPropertyAnimation *anim =
new QPropertyAnimation( effect,
"opacity" );
987 anim->setDuration( 2000 );
988 anim->setStartValue( 1.0 );
989 anim->setEndValue( 0.0 );
990 anim->setEasingCurve( QEasingCurve::OutQuad );
991 anim->start( QAbstractAnimation::DeleteWhenStopped );
998 if ( dlg.exec() == QDialog::DialogCode::Accepted )
1000 mExpressionTreeView->saveToUserExpressions( dlg.label().simplified(), dlg.expression(), dlg.helpText() );
1014 ( item->parent() && item->parent()->text() != mUserExpressionsGroupName ) )
1018 QString helpText = settings.
value( QStringLiteral(
"user/%1/helpText" ).arg( item->text() ),
"", QgsSettings::Section::Expressions ).toString();
1021 if ( dlg.exec() == QDialog::DialogCode::Accepted )
1024 if ( dlg.isLabelModified() )
1026 mExpressionTreeView->removeFromUserExpressions( item->text() );
1029 mExpressionTreeView->saveToUserExpressions( dlg.label().simplified(), dlg.expression(), dlg.helpText() );
1044 ( item->parent() && item->parent()->text() != mUserExpressionsGroupName ) )
1047 if ( QMessageBox::Yes == QMessageBox::question(
this, tr(
"Remove Stored Expression" ),
1048 tr(
"Do you really want to remove stored expressions '%1'?" ).arg( item->text() ),
1049 QMessageBox::Yes | QMessageBox::No ) )
1051 mExpressionTreeView->removeFromUserExpressions( item->text() );
1056void QgsExpressionBuilderWidget::exportUserExpressions_pressed()
1059 QString lastSaveDir = settings.
value( QStringLiteral(
"lastExportExpressionsDir" ), QDir::homePath(),
QgsSettings::App ).toString();
1060 QString saveFileName = QFileDialog::getSaveFileName(
1062 tr(
"Export User Expressions" ),
1064 tr(
"User expressions" ) +
" (*.json)" );
1066 if ( saveFileName.isEmpty() )
1069 QFileInfo saveFileInfo( saveFileName );
1071 if ( saveFileInfo.suffix().isEmpty() )
1073 QString saveFileNameWithSuffix = saveFileName.append(
".json" );
1074 saveFileInfo = QFileInfo( saveFileNameWithSuffix );
1079 QJsonDocument exportJson = mExpressionTreeView->exportUserExpressions();
1080 QFile jsonFile( saveFileName );
1082 if ( !jsonFile.open( QFile::WriteOnly | QIODevice::Truncate ) )
1083 QMessageBox::warning(
this, tr(
"Export user expressions" ), tr(
"Error while creating the expressions file." ) );
1085 if ( ! jsonFile.write( exportJson.toJson() ) )
1086 QMessageBox::warning(
this, tr(
"Export user expressions" ), tr(
"Error while creating the expressions file." ) );
1091void QgsExpressionBuilderWidget::importUserExpressions_pressed()
1094 QString lastImportDir = settings.
value( QStringLiteral(
"lastImportExpressionsDir" ), QDir::homePath(),
QgsSettings::App ).toString();
1095 QString loadFileName = QFileDialog::getOpenFileName(
1097 tr(
"Import User Expressions" ),
1099 tr(
"User expressions" ) +
" (*.json)" );
1101 if ( loadFileName.isEmpty() )
1104 QFileInfo loadFileInfo( loadFileName );
1108 QFile jsonFile( loadFileName );
1110 if ( !jsonFile.open( QFile::ReadOnly ) )
1111 QMessageBox::warning(
this, tr(
"Import User Expressions" ), tr(
"Error while reading the expressions file." ) );
1113 QTextStream jsonStream( &jsonFile );
1114 QString jsonString = jsonFile.readAll();
1117 QJsonDocument importJson = QJsonDocument::fromJson( jsonString.toUtf8() );
1119 if ( importJson.isNull() )
1121 QMessageBox::warning(
this, tr(
"Import User Expressions" ), tr(
"Error while reading the expressions file." ) );
1125 mExpressionTreeView->loadExpressionsFromJson( importJson );
1131 return mExpressionTreeView->findExpressions( label );
1134void QgsExpressionBuilderWidget::indicatorClicked(
int line,
int index, Qt::KeyboardModifiers state )
1136 if ( state & Qt::ControlModifier )
1138 int position = txtExpressionString->positionFromLineIndex( line, index );
1139 long fncIndex = txtExpressionString->SendScintilla( QsciScintilla::SCI_INDICATORVALUEAT, FUNCTION_MARKER_ID,
static_cast<long int>( position ) );
1141 QString help = getFunctionHelp( func );
1142 txtHelpText->setText( help );
1146void QgsExpressionBuilderWidget::onExpressionParsed(
bool state )
1150 mExpressionValid = state;
1153 createMarkers( mExpressionPreviewWidget->rootNode() );
1157 createErrorMarkers( mExpressionPreviewWidget->parserErrors() );
1161QString QgsExpressionBuilderWidget::helpStylesheet()
const
1167 style +=
" .functionname {color: #0a6099; font-weight: bold;} "
1168 " .argument {font-family: monospace; color: #bf0c0c; font-style: italic; } "
1169 " td.argument { padding-right: 10px; }";
1174QString QgsExpressionBuilderWidget::loadFunctionHelp(
QgsExpressionItem *expressionItem )
1176 if ( !expressionItem )
1179 QString helpContents = expressionItem->
getHelpText();
1182 if ( helpContents.isEmpty() )
1184 QString name = expressionItem->data( Qt::UserRole ).toString();
1192 return "<head><style>" + helpStylesheet() +
"</style></head><body>" + helpContents +
"</body>";
1199QMenu *QgsExpressionBuilderWidget::ExpressionTreeMenuProvider::createContextMenu(
QgsExpressionItem *item )
1201 QMenu *menu =
nullptr;
1205 menu =
new QMenu( mExpressionBuilderWidget );
static QString reportStyleSheet(QgsApplication::StyleSheetType styleSheetType=QgsApplication::StyleSheetType::Qt)
Returns a css style sheet for reports, the styleSheetType argument determines what type of stylesheet...
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsFieldFormatterRegistry * fieldFormatterRegistry()
Gets the registry of available field formatters.
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
A abstract base class for defining QgsExpression functions.
QString name() const
The name of the function.
An expression item that can be used in the QgsExpressionBuilderWidget tree.
static const int LAYER_ID_ROLE
Layer ID role.
QString getExpressionText() const
QgsExpressionItem::ItemType getItemType() const
Gets the type of expression item, e.g., header, field, ExpressionNode.
QString getHelpText() const
Gets the help text that is associated with this expression item.
static const int ITEM_NAME_ROLE
Item name role.
SQL-like BETWEEN and NOT BETWEEN predicates.
QgsExpressionNode * lowerBound() const
Returns the lower bound expression node of the range.
QgsExpressionNode * higherBound() const
Returns the higher bound expression node of the range.
A binary expression operator, which operates on two values.
QgsExpressionNode * opLeft() const
Returns the node to the left of the operator.
QgsExpressionNode * opRight() const
Returns the node to the right of the operator.
Represents a "WHEN... THEN..." portation of a CASE WHEN clause in an expression.
An expression node for CASE WHEN clauses.
QgsExpressionNode * elseExp() const
The ELSE expression used for the condition.
WhenThenList conditions() const
The list of WHEN THEN expression parts of the expression.
An expression node for expression functions.
int fnIndex() const
Returns the index of the node's function.
QgsExpressionNode::NodeList * args() const
Returns a list of arguments specified for the function.
An expression node for value IN or NOT IN clauses.
QgsExpressionNode::NodeList * list() const
Returns the list of nodes to search for matching values within.
A unary node is either negative as in boolean (not) or as in numbers (minus).
QgsExpressionNode * operand() const
Returns the node the operator will operate upon.
QList< QgsExpressionNode * > list()
Gets a list of all the nodes.
Abstract base class for all nodes that can appear in an expression.
virtual QgsExpressionNode::NodeType nodeType() const =0
Gets the type of this node.
int parserFirstLine
First line in the parser this node was found.
int parserLastColumn
Last column in the parser this node was found.
int parserFirstColumn
First column in the parser this node was found.
A generic dialog for editing expression text, label and help text.
QgsExpressionTreeView is a tree view to list all expressions functions, variables and fields that can...
void expressionItemDoubleClicked(const QString &text)
Emitted when a expression item is double clicked.
void currentExpressionItemChanged(QgsExpressionItem *item)
Emitter when the current expression item changed.
void setSearchText(const QString &text)
Sets the text to filter the expression tree.
static const QList< QgsExpressionFunction * > & Functions()
static QString helpText(QString name)
Returns the help text for a specified function.
static QString group(const QString &group)
Returns the translated name for a function group.
A context for field formatter containing information like the project.
void setProject(QgsProject *project)
Sets the project used in field formatter.
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Container of fields for a vector layer.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
static QgsProject * instance()
Returns the QgsProject singleton instance.
static bool run(const QString &command, const QString &messageOnError=QString())
Execute a Python statement.
static bool eval(const QString &command, QString &result)
Eval a Python statement.
static bool isValid()
Returns true if the runner has an instance (and thus is able to run commands)
This class is a composition of two QSettings instances:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static bool isNull(const QVariant &variant)
Returns true if the specified variant should be considered a NULL value.
Represents a vector layer which manages a vector based data sets.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const FINAL
Calculates a list of unique values contained within an attribute in the layer.
#define Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_PUSH
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Details about any parser errors that were found when parsing the expression.
@ FunctionInvalidParams
Function was called with invalid args.
@ Unknown
Unknown error type.
@ FunctionUnknown
Function was unknown.
@ FunctionNamedArgsError
Non named function arg used after named arg.
@ FunctionWrongArgs
Function was called with the wrong number of args.