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>
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() );
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 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
374 myFileStream << txtPython->text() << endl;
376 myFileStream << txtPython->text() << Qt::endl;
384 mFunctionsPath = path;
386 dir.setNameFilters( QStringList() << QStringLiteral(
"*.py" ) );
387 QStringList files = dir.entryList( QDir::Files );
388 cmbFileNames->clear();
389 const auto constFiles = files;
390 for (
const QString &name : constFiles )
392 QFileInfo info( mFunctionsPath + QDir::separator() + name );
393 if ( info.baseName() == QLatin1String(
"__init__" ) )
continue;
394 QListWidgetItem *item =
new QListWidgetItem(
QgsApplication::getThemeIcon( QStringLiteral(
"console/iconTabEditorConsole.svg" ) ), info.baseName() );
395 cmbFileNames->addItem( item );
397 if ( !cmbFileNames->currentItem() )
399 cmbFileNames->setCurrentRow( 0 );
402 if ( cmbFileNames->count() == 0 )
406 txtPython->setText( QStringLiteral(
"'''\n#Sample custom function file\n"
407 "#(uncomment to use and customize or Add button to create a new file) \n%1 \n '''" ).arg( txtPython->text() ) );
414 QList<QListWidgetItem *> items = cmbFileNames->findItems( fileName, Qt::MatchExactly );
415 if ( !items.isEmpty() )
418 QListWidgetItem *item =
new QListWidgetItem(
QgsApplication::getThemeIcon( QStringLiteral(
"console/iconTabEditorConsole.svg" ) ), fileName );
419 cmbFileNames->insertItem( 0, item );
420 cmbFileNames->setCurrentRow( 0 );
424 txtPython->setText( templatetxt );
428 void QgsExpressionBuilderWidget::btnNewFile_pressed()
431 QString text = QInputDialog::getText(
this, tr(
"New File" ),
432 tr(
"New file name:" ), QLineEdit::Normal,
434 if ( ok && !text.isEmpty() )
440 void QgsExpressionBuilderWidget::btnRemoveFile_pressed()
442 if ( QMessageBox::question(
this, tr(
"Remove File" ),
443 tr(
"Are you sure you want to remove current functions file?" ),
444 QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) == QMessageBox::No )
447 int currentRow = cmbFileNames->currentRow();
448 QString fileName = cmbFileNames->currentItem()->text();
449 if ( QFile::remove( mFunctionsPath + QDir::separator() + fileName.append(
".py" ) ) )
452 QListWidgetItem *itemToRemove =
whileBlocking( cmbFileNames )->takeItem( currentRow );
456 if ( cmbFileNames->count() > 0 )
458 cmbFileNames->setCurrentRow( currentRow > 0 ? currentRow - 1 : 0 );
459 loadCodeFromFile( mFunctionsPath + QDir::separator() + cmbFileNames->currentItem()->text() );
463 btnRemoveFile->setEnabled(
false );
469 QMessageBox::warning(
this, tr(
"Remove file" ), tr(
"Failed to remove function file '%1'." ).arg( fileName ) );
473 void QgsExpressionBuilderWidget::cmbFileNames_currentItemChanged( QListWidgetItem *item, QListWidgetItem *lastitem )
477 QString filename = lastitem->text();
480 QString path = mFunctionsPath + QDir::separator() + item->text();
486 if ( !path.endsWith( QLatin1String(
".py" ) ) )
487 path.append(
".py" );
489 txtPython->loadScript( path );
494 txtPython->setText( code );
497 void QgsExpressionBuilderWidget::insertExpressionText(
const QString &text )
500 txtExpressionString->insertText( text );
501 txtExpressionString->setFocus();
506 Q_UNUSED( fieldValues )
510 void QgsExpressionBuilderWidget::fillFieldValues(
const QString &fieldName,
int countLimit,
bool forceUsedValues )
522 if ( fieldIndex < 0 )
529 if ( cbxValuesInUse->isVisible() && !cbxValuesInUse->isChecked() && !forceUsedValues )
533 values =
formatter->availableValues( setup.
config(), countLimit, fieldFormatterContext );
537 values = qgis::setToList( mLayer->
uniqueValues( fieldIndex, countLimit ) );
539 std::sort( values.begin(), values.end() );
541 mValuesModel->clear();
542 for (
const QVariant &value : std::as_const( values ) )
545 bool forceRepresentedValue =
false;
546 if ( value.isNull() )
547 strValue = QStringLiteral(
"NULL" );
548 else if ( value.type() == QVariant::Int || value.type() == QVariant::Double || value.type() == QVariant::LongLong )
549 strValue = value.toString();
550 else if ( value.type() == QVariant::StringList )
553 const QStringList strList = value.toStringList();
554 for ( QString
str : strList )
556 if ( !result.isEmpty() )
557 result.append( QStringLiteral(
", " ) );
559 result.append(
'\'' +
str.replace(
'\'', QLatin1String(
"''" ) ) +
'\'' );
561 strValue = QStringLiteral(
"array(%1)" ).arg( result );
562 forceRepresentedValue =
true;
565 strValue =
'\'' + value.toString().replace(
'\'', QLatin1String(
"''" ) ) +
'\'';
567 QString representedValue =
formatter->representValue( mLayer, fieldIndex, setup.
config(), QVariant(), value );
568 if ( forceRepresentedValue || representedValue != value.toString() )
569 representedValue = representedValue + QStringLiteral(
" [" ) + strValue +
']';
571 QStandardItem *item =
new QStandardItem( representedValue );
572 item->setData( strValue );
573 mValuesModel->appendRow( item );
584 return QStringLiteral(
"<head><style>" ) + helpStylesheet() + QStringLiteral(
"</style></head><body>" ) + helpContents + QStringLiteral(
"</body>" );
592 return mExpressionValid;
597 mExpressionTreeView->saveToRecent(
expressionText(), collection );
602 mExpressionTreeView->loadRecent( collection );
607 return mExpressionTreeView;
613 mExpressionTreeView->loadUserExpressions();
618 mExpressionTreeView->saveToUserExpressions( label, expression, helpText );
623 mExpressionTreeView->removeFromUserExpressions( label );
629 mExpressionPreviewWidget->setGeomCalculator( da );
634 return txtExpressionString->text();
639 txtExpressionString->setText( expression );
644 return lblExpected->text();
649 lblExpected->setText( expected );
650 mExpectedOutputFrame->setVisible( !expected.isNull() );
655 mExpressionContext = context;
656 expressionContextUpdated();
659 void QgsExpressionBuilderWidget::txtExpressionString_textChanged()
663 btnClearEditor->setEnabled( ! txtExpressionString->text().isEmpty() );
664 btnSaveExpression->setEnabled(
false );
666 mExpressionPreviewWidget->setExpressionText( text );
671 return mExpressionPreviewWidget->parserError();
676 mExpressionPreviewWidget->setVisible( isVisible );
681 return mExpressionPreviewWidget->evalError();
687 return mExpressionTreeView->model();
699 mExpressionTreeView->setProject(
project );
704 QWidget::showEvent( e );
705 txtExpressionString->setFocus();
708 void QgsExpressionBuilderWidget::createErrorMarkers(
const QList<QgsExpression::ParserError> &errors )
713 int errorFirstLine = error.firstLine - 1 ;
714 int errorFirstColumn = error.firstColumn - 1;
715 int errorLastColumn = error.lastColumn - 1;
716 int errorLastLine = error.lastLine - 1;
722 errorFirstLine = errorLastLine;
723 errorFirstColumn = errorLastColumn - 1;
725 txtExpressionString->fillIndicatorRange( errorFirstLine,
728 errorLastColumn, error.errorType );
732 void QgsExpressionBuilderWidget::createMarkers(
const QgsExpressionNode *inNode )
736 case QgsExpressionNode::NodeType::ntFunction:
739 txtExpressionString->SendScintilla( QsciScintilla::SCI_SETINDICATORCURRENT, FUNCTION_MARKER_ID );
740 txtExpressionString->SendScintilla( QsciScintilla::SCI_SETINDICATORVALUE, node->
fnIndex() );
743 int start_pos = txtExpressionString->positionFromLineIndex( inNode->
parserFirstLine - 1, start );
744 txtExpressionString->SendScintilla( QsciScintilla::SCI_INDICATORFILLRANGE, start_pos, end - start );
747 const QList< QgsExpressionNode * > nodeList = node->
args()->
list();
755 case QgsExpressionNode::NodeType::ntLiteral:
759 case QgsExpressionNode::NodeType::ntUnaryOperator:
762 createMarkers( node->
operand() );
765 case QgsExpressionNode::NodeType::ntBinaryOperator:
768 createMarkers( node->
opLeft() );
769 createMarkers( node->
opRight() );
772 case QgsExpressionNode::NodeType::ntColumnRef:
776 case QgsExpressionNode::NodeType::ntInOperator:
781 const QList< QgsExpressionNode * > nodeList = node->
list()->
list();
789 case QgsExpressionNode::NodeType::ntCondition:
792 const QList<QgsExpressionNodeCondition::WhenThen *> conditions = node->
conditions();
795 createMarkers( cond->whenExp() );
796 createMarkers( cond->thenExp() );
800 createMarkers( node->
elseExp() );
804 case QgsExpressionNode::NodeType::ntIndexOperator:
811 void QgsExpressionBuilderWidget::clearFunctionMarkers()
813 int lastLine = txtExpressionString->lines() - 1;
814 txtExpressionString->clearIndicatorRange( 0, 0, lastLine, txtExpressionString->text( lastLine ).length() - 1, FUNCTION_MARKER_ID );
817 void QgsExpressionBuilderWidget::clearErrors()
819 int lastLine = txtExpressionString->lines() - 1;
828 void QgsExpressionBuilderWidget::txtSearchEditValues_textChanged()
830 mProxyValues->setFilterCaseSensitivity( Qt::CaseInsensitive );
831 mProxyValues->setFilterWildcard( txtSearchEditValues->text() );
834 void QgsExpressionBuilderWidget::mValuesListView_doubleClicked(
const QModelIndex &index )
837 txtExpressionString->insertText(
' ' + index.data( Qt::UserRole + 1 ).toString() +
' ' );
838 txtExpressionString->setFocus();
841 void QgsExpressionBuilderWidget::operatorButtonClicked()
843 QPushButton *button = qobject_cast<QPushButton *>( sender() );
846 txtExpressionString->insertText(
' ' + button->text() +
' ' );
847 txtExpressionString->setFocus();
855 if ( !mLayer || !item )
858 mValueGroupBox->show();
867 if ( !mLayer || !item )
870 mValueGroupBox->show();
879 if ( !mLayer || !item )
882 mValueGroupBox->show();
891 if ( !mLayer || !item )
894 mValueGroupBox->show();
898 void QgsExpressionBuilderWidget::txtPython_textChanged()
900 lblAutoSave->setText( tr(
"Saving…" ) );
910 if ( tabWidget->currentIndex() != 1 )
913 QListWidgetItem *item = cmbFileNames->currentItem();
917 QString file = item->text();
919 lblAutoSave->setText( QStringLiteral(
"Saved" ) );
920 QGraphicsOpacityEffect *effect =
new QGraphicsOpacityEffect();
921 lblAutoSave->setGraphicsEffect( effect );
922 QPropertyAnimation *anim =
new QPropertyAnimation( effect,
"opacity" );
923 anim->setDuration( 2000 );
924 anim->setStartValue( 1.0 );
925 anim->setEndValue( 0.0 );
926 anim->setEasingCurve( QEasingCurve::OutQuad );
927 anim->start( QAbstractAnimation::DeleteWhenStopped );
934 if ( dlg.exec() == QDialog::DialogCode::Accepted )
936 mExpressionTreeView->saveToUserExpressions( dlg.label().simplified(), dlg.expression(), dlg.helpText() );
950 ( item->parent() && item->parent()->text() != mUserExpressionsGroupName ) )
954 QString helpText = settings.
value( QStringLiteral(
"user/%1/helpText" ).arg( item->text() ),
"", QgsSettings::Section::Expressions ).toString();
957 if ( dlg.exec() == QDialog::DialogCode::Accepted )
960 if ( dlg.isLabelModified() )
962 mExpressionTreeView->removeFromUserExpressions( item->text() );
965 mExpressionTreeView->saveToUserExpressions( dlg.label().simplified(), dlg.expression(), dlg.helpText() );
980 ( item->parent() && item->parent()->text() != mUserExpressionsGroupName ) )
983 if ( QMessageBox::Yes == QMessageBox::question(
this, tr(
"Remove Stored Expression" ),
984 tr(
"Do you really want to remove stored expressions '%1'?" ).arg( item->text() ),
985 QMessageBox::Yes | QMessageBox::No ) )
987 mExpressionTreeView->removeFromUserExpressions( item->text() );
992 void QgsExpressionBuilderWidget::exportUserExpressions_pressed()
995 QString lastSaveDir = settings.
value( QStringLiteral(
"lastExportExpressionsDir" ), QDir::homePath(),
QgsSettings::App ).toString();
996 QString saveFileName = QFileDialog::getSaveFileName(
998 tr(
"Export User Expressions" ),
1000 tr(
"User expressions" ) +
" (*.json)" );
1002 if ( saveFileName.isEmpty() )
1005 QFileInfo saveFileInfo( saveFileName );
1007 if ( saveFileInfo.suffix().isEmpty() )
1009 QString saveFileNameWithSuffix = saveFileName.append(
".json" );
1010 saveFileInfo = QFileInfo( saveFileNameWithSuffix );
1015 QJsonDocument exportJson = mExpressionTreeView->exportUserExpressions();
1016 QFile jsonFile( saveFileName );
1018 if ( !jsonFile.open( QFile::WriteOnly | QIODevice::Truncate ) )
1019 QMessageBox::warning(
this, tr(
"Export user expressions" ), tr(
"Error while creating the expressions file." ) );
1021 if ( ! jsonFile.write( exportJson.toJson() ) )
1022 QMessageBox::warning(
this, tr(
"Export user expressions" ), tr(
"Error while creating the expressions file." ) );
1027 void QgsExpressionBuilderWidget::importUserExpressions_pressed()
1030 QString lastImportDir = settings.
value( QStringLiteral(
"lastImportExpressionsDir" ), QDir::homePath(),
QgsSettings::App ).toString();
1031 QString loadFileName = QFileDialog::getOpenFileName(
1033 tr(
"Import User Expressions" ),
1035 tr(
"User expressions" ) +
" (*.json)" );
1037 if ( loadFileName.isEmpty() )
1040 QFileInfo loadFileInfo( loadFileName );
1044 QFile jsonFile( loadFileName );
1046 if ( !jsonFile.open( QFile::ReadOnly ) )
1047 QMessageBox::warning(
this, tr(
"Import User Expressions" ), tr(
"Error while reading the expressions file." ) );
1049 QTextStream jsonStream( &jsonFile );
1050 QString jsonString = jsonFile.readAll();
1053 QJsonDocument importJson = QJsonDocument::fromJson( jsonString.toUtf8() );
1055 if ( importJson.isNull() )
1057 QMessageBox::warning(
this, tr(
"Import User Expressions" ), tr(
"Error while reading the expressions file." ) );
1061 mExpressionTreeView->loadExpressionsFromJson( importJson );
1067 return mExpressionTreeView->findExpressions( label );
1070 void QgsExpressionBuilderWidget::indicatorClicked(
int line,
int index, Qt::KeyboardModifiers state )
1072 if ( state & Qt::ControlModifier )
1074 int position = txtExpressionString->positionFromLineIndex( line, index );
1075 long fncIndex = txtExpressionString->SendScintilla( QsciScintilla::SCI_INDICATORVALUEAT, FUNCTION_MARKER_ID,
static_cast<long int>( position ) );
1077 QString help = getFunctionHelp( func );
1078 txtHelpText->setText( help );
1082 void QgsExpressionBuilderWidget::onExpressionParsed(
bool state )
1086 mExpressionValid = state;
1089 createMarkers( mExpressionPreviewWidget->rootNode() );
1093 createErrorMarkers( mExpressionPreviewWidget->parserErrors() );
1097 QString QgsExpressionBuilderWidget::helpStylesheet()
const
1103 style +=
" .functionname {color: #0a6099; font-weight: bold;} "
1104 " .argument {font-family: monospace; color: #bf0c0c; font-style: italic; } "
1105 " td.argument { padding-right: 10px; }";
1110 QString QgsExpressionBuilderWidget::loadFunctionHelp(
QgsExpressionItem *expressionItem )
1112 if ( !expressionItem )
1115 QString helpContents = expressionItem->
getHelpText();
1118 if ( helpContents.isEmpty() )
1120 QString name = expressionItem->data( Qt::UserRole ).toString();
1128 return "<head><style>" + helpStylesheet() +
"</style></head><body>" + helpContents +
"</body>";
1135 QMenu *QgsExpressionBuilderWidget::ExpressionTreeMenuProvider::createContextMenu(
QgsExpressionItem *item )
1137 QMenu *menu =
nullptr;
1141 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.
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)
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.
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.