18 #include <QTextStream>
20 #include <QInputDialog>
22 #include <QGraphicsOpacityEffect>
23 #include <QPropertyAnimation>
24 #include <QMessageBox>
25 #include <QVersionNumber>
27 #include <QJsonDocument>
28 #include <QJsonObject>
30 #include <QFileDialog>
44 #include "qgssettings.h"
61 if ( fieldIndex != -1 )
79 connect( btnRun, &QToolButton::pressed,
this, &QgsExpressionBuilderWidget::btnRun_pressed );
80 connect( btnNewFile, &QPushButton::pressed,
this, &QgsExpressionBuilderWidget::btnNewFile_pressed );
81 connect( btnRemoveFile, &QPushButton::pressed,
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, &QPushButton::pressed,
this, &QgsExpressionBuilderWidget::importUserExpressions_pressed );
91 connect( btnExportExpressions, &QPushButton::pressed,
this, &QgsExpressionBuilderWidget::exportUserExpressions_pressed );
92 connect( btnClearEditor, &QPushButton::pressed, 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::pressed,
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 );
157 QgsSettings settings;
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\
247 QgsSettings settings;
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() );
294 void QgsExpressionBuilderWidget::expressionContextUpdated()
296 txtExpressionString->setExpressionContext( mExpressionContext );
297 mExpressionTreeView->setExpressionContext( mExpressionContext );
298 mExpressionPreviewWidget->setExpressionContext( mExpressionContext );
306 void 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 );
335 void QgsExpressionBuilderWidget::btnRun_pressed()
337 if ( !cmbFileNames->currentItem() )
340 QString file = cmbFileNames->currentItem()->text();
342 runPythonCode( txtPython->text() );
345 void QgsExpressionBuilderWidget::runPythonCode(
const QString &code )
349 QString pythontext = code;
352 mExpressionTreeView->refresh();
357 QDir myDir( mFunctionsPath );
358 if ( !myDir.exists() )
360 myDir.mkpath( mFunctionsPath );
363 if ( !fileName.endsWith( QLatin1String(
".py" ) ) )
365 fileName.append(
".py" );
368 fileName = mFunctionsPath + QDir::separator() + fileName;
369 QFile myFile( fileName );
370 if ( myFile.open( QIODevice::WriteOnly | QFile::Truncate ) )
372 QTextStream myFileStream( &myFile );
373 myFileStream << txtPython->text() << endl;
380 mFunctionsPath = path;
382 dir.setNameFilters( QStringList() << QStringLiteral(
"*.py" ) );
383 QStringList files = dir.entryList( QDir::Files );
384 cmbFileNames->clear();
385 const auto constFiles = files;
386 for (
const QString &name : constFiles )
388 QFileInfo info( mFunctionsPath + QDir::separator() + name );
389 if ( info.baseName() == QLatin1String(
"__init__" ) )
continue;
390 QListWidgetItem *item =
new QListWidgetItem(
QgsApplication::getThemeIcon( QStringLiteral(
"console/iconTabEditorConsole.svg" ) ), info.baseName() );
391 cmbFileNames->addItem( item );
393 if ( !cmbFileNames->currentItem() )
395 cmbFileNames->setCurrentRow( 0 );
398 if ( cmbFileNames->count() == 0 )
402 txtPython->setText( QStringLiteral(
"'''\n#Sample custom function file\n"
403 "#(uncomment to use and customize or Add button to create a new file) \n%1 \n '''" ).arg( txtPython->text() ) );
410 QList<QListWidgetItem *> items = cmbFileNames->findItems( fileName, Qt::MatchExactly );
411 if ( !items.isEmpty() )
414 QListWidgetItem *item =
new QListWidgetItem(
QgsApplication::getThemeIcon( QStringLiteral(
"console/iconTabEditorConsole.svg" ) ), fileName );
415 cmbFileNames->insertItem( 0, item );
416 cmbFileNames->setCurrentRow( 0 );
420 txtPython->setText( templatetxt );
424 void QgsExpressionBuilderWidget::btnNewFile_pressed()
427 QString text = QInputDialog::getText(
this, tr(
"New File" ),
428 tr(
"New file name:" ), QLineEdit::Normal,
430 if ( ok && !text.isEmpty() )
436 void QgsExpressionBuilderWidget::btnRemoveFile_pressed()
438 if ( QMessageBox::question(
this, tr(
"Remove File" ),
439 tr(
"Are you sure you want to remove current functions file?" ),
440 QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) == QMessageBox::No )
443 int currentRow = cmbFileNames->currentRow();
444 QString fileName = cmbFileNames->currentItem()->text();
445 if ( QFile::remove( mFunctionsPath + QDir::separator() + fileName.append(
".py" ) ) )
448 QListWidgetItem *itemToRemove =
whileBlocking( cmbFileNames )->takeItem( currentRow );
452 if ( cmbFileNames->count() > 0 )
454 cmbFileNames->setCurrentRow( currentRow > 0 ? currentRow - 1 : 0 );
455 loadCodeFromFile( mFunctionsPath + QDir::separator() + cmbFileNames->currentItem()->text() );
459 btnRemoveFile->setEnabled(
false );
465 QMessageBox::warning(
this, tr(
"Remove file" ), tr(
"Failed to remove function file '%1'." ).arg( fileName ) );
469 void QgsExpressionBuilderWidget::cmbFileNames_currentItemChanged( QListWidgetItem *item, QListWidgetItem *lastitem )
473 QString filename = lastitem->text();
476 QString path = mFunctionsPath + QDir::separator() + item->text();
482 if ( !path.endsWith( QLatin1String(
".py" ) ) )
483 path.append(
".py" );
485 txtPython->loadScript( path );
490 txtPython->setText( code );
493 void QgsExpressionBuilderWidget::insertExpressionText(
const QString &text )
496 txtExpressionString->insertText( text );
497 txtExpressionString->setFocus();
502 Q_UNUSED( fieldValues )
506 void QgsExpressionBuilderWidget::fillFieldValues(
const QString &fieldName,
int countLimit,
bool forceUsedValues )
518 if ( fieldIndex < 0 )
525 if ( cbxValuesInUse->isVisible() && !cbxValuesInUse->isChecked() && !forceUsedValues )
529 values =
formatter->availableValues( setup.
config(), countLimit, fieldFormatterContext );
533 values = qgis::setToList( mLayer->
uniqueValues( fieldIndex, countLimit ) );
535 std::sort( values.begin(), values.end() );
537 mValuesModel->clear();
538 for (
const QVariant &value : std::as_const( values ) )
541 if ( value.isNull() )
542 strValue = QStringLiteral(
"NULL" );
543 else if ( value.type() == QVariant::Int || value.type() == QVariant::Double || value.type() == QVariant::LongLong )
544 strValue = value.toString();
546 strValue =
'\'' + value.toString().replace(
'\'', QLatin1String(
"''" ) ) +
'\'';
548 QString representedValue =
formatter->representValue( mLayer, fieldIndex, setup.
config(), QVariant(), value );
549 if ( representedValue != value.toString() )
550 representedValue = representedValue + QStringLiteral(
" [" ) + strValue +
']';
552 QStandardItem *item =
new QStandardItem( representedValue );
553 item->setData( strValue );
554 mValuesModel->appendRow( item );
565 return QStringLiteral(
"<head><style>" ) + helpStylesheet() + QStringLiteral(
"</style></head><body>" ) + helpContents + QStringLiteral(
"</body>" );
573 return mExpressionValid;
578 mExpressionTreeView->saveToRecent(
expressionText(), collection );
583 mExpressionTreeView->loadRecent( collection );
588 return mExpressionTreeView;
594 mExpressionTreeView->loadUserExpressions();
599 mExpressionTreeView->saveToUserExpressions( label, expression, helpText );
604 mExpressionTreeView->removeFromUserExpressions( label );
610 mExpressionPreviewWidget->setGeomCalculator( da );
615 return txtExpressionString->text();
620 txtExpressionString->setText( expression );
625 return lblExpected->text();
630 lblExpected->setText( expected );
631 mExpectedOutputFrame->setVisible( !expected.isNull() );
636 mExpressionContext = context;
637 expressionContextUpdated();
640 void QgsExpressionBuilderWidget::txtExpressionString_textChanged()
644 btnClearEditor->setEnabled( ! txtExpressionString->text().isEmpty() );
645 btnSaveExpression->setEnabled(
false );
647 mExpressionPreviewWidget->setExpressionText( text );
652 return mExpressionPreviewWidget->parserError();
657 return mExpressionPreviewWidget->evalError();
663 return mExpressionTreeView->model();
675 mExpressionTreeView->setProject(
project );
680 QWidget::showEvent( e );
681 txtExpressionString->setFocus();
684 void QgsExpressionBuilderWidget::createErrorMarkers( QList<QgsExpression::ParserError> errors )
689 int errorFirstLine = error.firstLine - 1 ;
690 int errorFirstColumn = error.firstColumn - 1;
691 int errorLastColumn = error.lastColumn - 1;
692 int errorLastLine = error.lastLine - 1;
698 errorFirstLine = errorLastLine;
699 errorFirstColumn = errorLastColumn - 1;
701 txtExpressionString->fillIndicatorRange( errorFirstLine,
704 errorLastColumn, error.errorType );
708 void QgsExpressionBuilderWidget::createMarkers(
const QgsExpressionNode *inNode )
712 case QgsExpressionNode::NodeType::ntFunction:
715 txtExpressionString->SendScintilla( QsciScintilla::SCI_SETINDICATORCURRENT, FUNCTION_MARKER_ID );
716 txtExpressionString->SendScintilla( QsciScintilla::SCI_SETINDICATORVALUE, node->
fnIndex() );
719 int start_pos = txtExpressionString->positionFromLineIndex( inNode->
parserFirstLine - 1, start );
720 txtExpressionString->SendScintilla( QsciScintilla::SCI_INDICATORFILLRANGE, start_pos, end - start );
723 const QList< QgsExpressionNode * > nodeList = node->
args()->
list();
731 case QgsExpressionNode::NodeType::ntLiteral:
735 case QgsExpressionNode::NodeType::ntUnaryOperator:
738 createMarkers( node->
operand() );
741 case QgsExpressionNode::NodeType::ntBinaryOperator:
744 createMarkers( node->
opLeft() );
745 createMarkers( node->
opRight() );
748 case QgsExpressionNode::NodeType::ntColumnRef:
752 case QgsExpressionNode::NodeType::ntInOperator:
757 const QList< QgsExpressionNode * > nodeList = node->
list()->
list();
765 case QgsExpressionNode::NodeType::ntCondition:
770 createMarkers( cond->whenExp() );
771 createMarkers( cond->thenExp() );
775 createMarkers( node->
elseExp() );
779 case QgsExpressionNode::NodeType::ntIndexOperator:
786 void QgsExpressionBuilderWidget::clearFunctionMarkers()
788 int lastLine = txtExpressionString->lines() - 1;
789 txtExpressionString->clearIndicatorRange( 0, 0, lastLine, txtExpressionString->text( lastLine ).length() - 1, FUNCTION_MARKER_ID );
792 void QgsExpressionBuilderWidget::clearErrors()
794 int lastLine = txtExpressionString->lines() - 1;
803 void QgsExpressionBuilderWidget::txtSearchEditValues_textChanged()
805 mProxyValues->setFilterCaseSensitivity( Qt::CaseInsensitive );
806 mProxyValues->setFilterWildcard( txtSearchEditValues->text() );
809 void QgsExpressionBuilderWidget::mValuesListView_doubleClicked(
const QModelIndex &index )
812 txtExpressionString->insertText(
' ' + index.data( Qt::UserRole + 1 ).toString() +
' ' );
813 txtExpressionString->setFocus();
816 void QgsExpressionBuilderWidget::operatorButtonClicked()
818 QPushButton *button = qobject_cast<QPushButton *>( sender() );
821 txtExpressionString->insertText(
' ' + button->text() +
' ' );
822 txtExpressionString->setFocus();
830 if ( !mLayer || !item )
833 mValueGroupBox->show();
842 if ( !mLayer || !item )
845 mValueGroupBox->show();
854 if ( !mLayer || !item )
857 mValueGroupBox->show();
866 if ( !mLayer || !item )
869 mValueGroupBox->show();
873 void QgsExpressionBuilderWidget::txtPython_textChanged()
875 lblAutoSave->setText( tr(
"Saving…" ) );
885 if ( tabWidget->currentIndex() != 1 )
888 QListWidgetItem *item = cmbFileNames->currentItem();
892 QString file = item->text();
894 lblAutoSave->setText( QStringLiteral(
"Saved" ) );
895 QGraphicsOpacityEffect *effect =
new QGraphicsOpacityEffect();
896 lblAutoSave->setGraphicsEffect( effect );
897 QPropertyAnimation *anim =
new QPropertyAnimation( effect,
"opacity" );
898 anim->setDuration( 2000 );
899 anim->setStartValue( 1.0 );
900 anim->setEndValue( 0.0 );
901 anim->setEasingCurve( QEasingCurve::OutQuad );
902 anim->start( QAbstractAnimation::DeleteWhenStopped );
909 if ( dlg.exec() == QDialog::DialogCode::Accepted )
911 mExpressionTreeView->saveToUserExpressions( dlg.label(), dlg.expression(), dlg.helpText() );
925 ( item->parent() && item->parent()->text() != mUserExpressionsGroupName ) )
928 QgsSettings settings;
929 QString helpText = settings.value( QStringLiteral(
"user/%1/helpText" ).arg( item->text() ),
"", QgsSettings::Section::Expressions ).toString();
932 if ( dlg.exec() == QDialog::DialogCode::Accepted )
935 if ( dlg.label() != item->text() )
937 mExpressionTreeView->removeFromUserExpressions( item->text() );
940 mExpressionTreeView->saveToUserExpressions( dlg.label(), dlg.expression(), dlg.helpText() );
955 ( item->parent() && item->parent()->text() != mUserExpressionsGroupName ) )
958 if ( QMessageBox::Yes == QMessageBox::question(
this, tr(
"Remove Stored Expression" ),
959 tr(
"Do you really want to remove stored expressions '%1'?" ).arg( item->text() ),
960 QMessageBox::Yes | QMessageBox::No ) )
962 mExpressionTreeView->removeFromUserExpressions( item->text() );
967 void QgsExpressionBuilderWidget::exportUserExpressions_pressed()
969 QgsSettings settings;
970 QString lastSaveDir = settings.value( QStringLiteral(
"lastExportExpressionsDir" ), QDir::homePath(), QgsSettings::App ).toString();
971 QString saveFileName = QFileDialog::getSaveFileName(
973 tr(
"Export User Expressions" ),
975 tr(
"User expressions" ) +
" (*.json)" );
977 if ( saveFileName.isEmpty() )
980 QFileInfo saveFileInfo( saveFileName );
982 if ( saveFileInfo.suffix().isEmpty() )
984 QString saveFileNameWithSuffix = saveFileName.append(
".json" );
985 saveFileInfo = QFileInfo( saveFileNameWithSuffix );
988 settings.setValue( QStringLiteral(
"lastExportExpressionsDir" ), saveFileInfo.absolutePath(), QgsSettings::App );
990 QJsonDocument exportJson = mExpressionTreeView->exportUserExpressions();
991 QFile jsonFile( saveFileName );
993 if ( !jsonFile.open( QFile::WriteOnly | QIODevice::Truncate ) )
994 QMessageBox::warning(
this, tr(
"Export user expressions" ), tr(
"Error while creating the expressions file." ) );
996 if ( ! jsonFile.write( exportJson.toJson() ) )
997 QMessageBox::warning(
this, tr(
"Export user expressions" ), tr(
"Error while creating the expressions file." ) );
1002 void QgsExpressionBuilderWidget::importUserExpressions_pressed()
1004 QgsSettings settings;
1005 QString lastImportDir = settings.value( QStringLiteral(
"lastImportExpressionsDir" ), QDir::homePath(), QgsSettings::App ).toString();
1006 QString loadFileName = QFileDialog::getOpenFileName(
1008 tr(
"Import User Expressions" ),
1010 tr(
"User expressions" ) +
" (*.json)" );
1012 if ( loadFileName.isEmpty() )
1015 QFileInfo loadFileInfo( loadFileName );
1017 settings.setValue( QStringLiteral(
"lastImportExpressionsDir" ), loadFileInfo.absolutePath(), QgsSettings::App );
1019 QFile jsonFile( loadFileName );
1021 if ( !jsonFile.open( QFile::ReadOnly ) )
1022 QMessageBox::warning(
this, tr(
"Import User Expressions" ), tr(
"Error while reading the expressions file." ) );
1024 QTextStream jsonStream( &jsonFile );
1025 QString jsonString = jsonFile.readAll();
1028 QJsonDocument importJson = QJsonDocument::fromJson( jsonString.toUtf8() );
1030 if ( importJson.isNull() )
1032 QMessageBox::warning(
this, tr(
"Import User Expressions" ), tr(
"Error while reading the expressions file." ) );
1036 mExpressionTreeView->loadExpressionsFromJson( importJson );
1042 return mExpressionTreeView->findExpressions( label );
1045 void QgsExpressionBuilderWidget::indicatorClicked(
int line,
int index, Qt::KeyboardModifiers state )
1047 if ( state & Qt::ControlModifier )
1049 int position = txtExpressionString->positionFromLineIndex( line, index );
1050 long fncIndex = txtExpressionString->SendScintilla( QsciScintilla::SCI_INDICATORVALUEAT, FUNCTION_MARKER_ID,
static_cast<long int>( position ) );
1052 QString help = getFunctionHelp( func );
1053 txtHelpText->setText( help );
1057 void QgsExpressionBuilderWidget::onExpressionParsed(
bool state )
1061 mExpressionValid = state;
1064 createMarkers( mExpressionPreviewWidget->rootNode() );
1068 createErrorMarkers( mExpressionPreviewWidget->parserErrors() );
1072 QString QgsExpressionBuilderWidget::helpStylesheet()
const
1078 style +=
" .functionname {color: #0a6099; font-weight: bold;} "
1079 " .argument {font-family: monospace; color: #bf0c0c; font-style: italic; } "
1080 " td.argument { padding-right: 10px; }";
1085 QString QgsExpressionBuilderWidget::loadFunctionHelp(
QgsExpressionItem *expressionItem )
1087 if ( !expressionItem )
1090 QString helpContents = expressionItem->
getHelpText();
1093 if ( helpContents.isEmpty() )
1095 QString name = expressionItem->data( Qt::UserRole ).toString();
1103 return "<head><style>" + helpStylesheet() +
"</style></head><body>" + helpContents +
"</body>";
1110 QMenu *QgsExpressionBuilderWidget::ExpressionTreeMenuProvider::createContextMenu(
QgsExpressionItem *item )
1112 QMenu *menu =
nullptr;
1116 menu =
new QMenu( mExpressionBuilderWidget );
1122 menu->addAction( tr(
"Load First 10 Unique Used Values" ), mExpressionBuilderWidget, SLOT( loadSampleUsedValues() ) );
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.
An expression item that can be used in the QgsExpressionBuilderWidget tree.
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.
A binary expression operator, which operates on two values.
QgsExpressionNode * opRight() const
Returns the node to the right of the operator.
QgsExpressionNode * opLeft() const
Returns the node to the left 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 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)
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.