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();
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 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
389 myFileStream << txtPython->text() << endl;
391 myFileStream << txtPython->text() << Qt::endl;
399 mFunctionsPath = path;
401 dir.setNameFilters( QStringList() << QStringLiteral(
"*.py" ) );
402 QStringList files = dir.entryList( QDir::Files );
403 cmbFileNames->clear();
404 const auto constFiles = files;
405 for (
const QString &name : constFiles )
407 QFileInfo info( mFunctionsPath + QDir::separator() + name );
408 if ( info.baseName() == QLatin1String(
"__init__" ) )
continue;
409 QListWidgetItem *item =
new QListWidgetItem(
QgsApplication::getThemeIcon( QStringLiteral(
"console/iconTabEditorConsole.svg" ) ), info.baseName() );
410 cmbFileNames->addItem( item );
412 if ( !cmbFileNames->currentItem() )
414 cmbFileNames->setCurrentRow( 0 );
417 if ( cmbFileNames->count() == 0 )
421 txtPython->setText( QStringLiteral(
"'''\n#Sample custom function file\n"
422 "#(uncomment to use and customize or Add button to create a new file) \n%1 \n '''" ).arg( txtPython->text() ) );
429 QList<QListWidgetItem *> items = cmbFileNames->findItems( fileName, Qt::MatchExactly );
430 if ( !items.isEmpty() )
433 QListWidgetItem *item =
new QListWidgetItem(
QgsApplication::getThemeIcon( QStringLiteral(
"console/iconTabEditorConsole.svg" ) ), fileName );
434 cmbFileNames->insertItem( 0, item );
435 cmbFileNames->setCurrentRow( 0 );
439 txtPython->setText( templatetxt );
443 void QgsExpressionBuilderWidget::btnNewFile_pressed()
446 QString text = QInputDialog::getText(
this, tr(
"New File" ),
447 tr(
"New file name:" ), QLineEdit::Normal,
449 if ( ok && !text.isEmpty() )
455 void QgsExpressionBuilderWidget::btnRemoveFile_pressed()
457 if ( QMessageBox::question(
this, tr(
"Remove File" ),
458 tr(
"Are you sure you want to remove current functions file?" ),
459 QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) == QMessageBox::No )
462 int currentRow = cmbFileNames->currentRow();
463 QString fileName = cmbFileNames->currentItem()->text();
464 if ( QFile::remove( mFunctionsPath + QDir::separator() + fileName.append(
".py" ) ) )
467 QListWidgetItem *itemToRemove =
whileBlocking( cmbFileNames )->takeItem( currentRow );
471 if ( cmbFileNames->count() > 0 )
473 cmbFileNames->setCurrentRow( currentRow > 0 ? currentRow - 1 : 0 );
474 loadCodeFromFile( mFunctionsPath + QDir::separator() + cmbFileNames->currentItem()->text() );
478 btnRemoveFile->setEnabled(
false );
484 QMessageBox::warning(
this, tr(
"Remove file" ), tr(
"Failed to remove function file '%1'." ).arg( fileName ) );
488 void QgsExpressionBuilderWidget::cmbFileNames_currentItemChanged( QListWidgetItem *item, QListWidgetItem *lastitem )
492 QString filename = lastitem->text();
495 QString path = mFunctionsPath + QDir::separator() + item->text();
501 if ( !path.endsWith( QLatin1String(
".py" ) ) )
502 path.append(
".py" );
504 txtPython->loadScript( path );
509 txtPython->setText( code );
512 void QgsExpressionBuilderWidget::insertExpressionText(
const QString &text )
515 txtExpressionString->insertText( text );
516 txtExpressionString->setFocus();
521 Q_UNUSED( fieldValues )
525 void QgsExpressionBuilderWidget::fillFieldValues(
const QString &fieldName,
QgsVectorLayer *layer,
int countLimit,
bool forceUsedValues )
537 if ( fieldIndex < 0 )
544 if ( cbxValuesInUse->isVisible() && !cbxValuesInUse->isChecked() && !forceUsedValues )
548 values =
formatter->availableValues( setup.
config(), countLimit, fieldFormatterContext );
554 std::sort( values.begin(), values.end() );
556 mValuesModel->clear();
557 for (
const QVariant &value : std::as_const( values ) )
560 bool forceRepresentedValue =
false;
561 if ( value.isNull() )
562 strValue = QStringLiteral(
"NULL" );
563 else if ( value.type() == QVariant::Int || value.type() == QVariant::Double || value.type() == QVariant::LongLong )
564 strValue = value.toString();
565 else if ( value.type() == QVariant::StringList )
568 const QStringList strList = value.toStringList();
569 for ( QString
str : strList )
571 if ( !result.isEmpty() )
572 result.append( QStringLiteral(
", " ) );
574 result.append(
'\'' +
str.replace(
'\'', QLatin1String(
"''" ) ) +
'\'' );
576 strValue = QStringLiteral(
"array(%1)" ).arg( result );
577 forceRepresentedValue =
true;
579 else if ( value.type() == QVariant::List )
582 const QList list = value.toList();
583 for (
const QVariant &item : list )
585 if ( !result.isEmpty() )
586 result.append( QStringLiteral(
", " ) );
588 result.append( item.toString() );
590 strValue = QStringLiteral(
"array(%1)" ).arg( result );
591 forceRepresentedValue =
true;
594 strValue =
'\'' + value.toString().replace(
'\'', QLatin1String(
"''" ) ) +
'\'';
596 QString representedValue =
formatter->representValue(
layer, fieldIndex, setup.
config(), QVariant(), value );
597 if ( forceRepresentedValue || representedValue != value.toString() )
598 representedValue = representedValue + QStringLiteral(
" [" ) + strValue +
']';
600 QStandardItem *item =
new QStandardItem( representedValue );
601 item->setData( strValue );
602 mValuesModel->appendRow( item );
613 return QStringLiteral(
"<head><style>" ) + helpStylesheet() + QStringLiteral(
"</style></head><body>" ) + helpContents + QStringLiteral(
"</body>" );
621 return mExpressionValid;
626 mExpressionTreeView->saveToRecent(
expressionText(), collection );
631 mExpressionTreeView->loadRecent( collection );
636 return mExpressionTreeView;
642 mExpressionTreeView->loadUserExpressions();
647 mExpressionTreeView->saveToUserExpressions( label, expression, helpText );
652 mExpressionTreeView->removeFromUserExpressions( label );
658 mExpressionPreviewWidget->setGeomCalculator( da );
663 return txtExpressionString->text();
668 txtExpressionString->setText( expression );
673 return lblExpected->text();
678 lblExpected->setText( expected );
679 mExpectedOutputFrame->setVisible( !expected.isNull() );
684 mExpressionContext = context;
685 expressionContextUpdated();
688 void QgsExpressionBuilderWidget::txtExpressionString_textChanged()
692 btnClearEditor->setEnabled( ! txtExpressionString->text().isEmpty() );
693 btnSaveExpression->setEnabled(
false );
695 mExpressionPreviewWidget->setExpressionText( text );
700 return mExpressionPreviewWidget->parserError();
705 mExpressionPreviewWidget->setVisible( isVisible );
710 return mExpressionPreviewWidget->evalError();
716 return mExpressionTreeView->model();
728 mExpressionTreeView->setProject(
project );
733 QWidget::showEvent( e );
734 txtExpressionString->setFocus();
737 void QgsExpressionBuilderWidget::createErrorMarkers(
const QList<QgsExpression::ParserError> &errors )
742 int errorFirstLine = error.firstLine - 1 ;
743 int errorFirstColumn = error.firstColumn - 1;
744 int errorLastColumn = error.lastColumn - 1;
745 int errorLastLine = error.lastLine - 1;
751 errorFirstLine = errorLastLine;
752 errorFirstColumn = errorLastColumn - 1;
754 txtExpressionString->fillIndicatorRange( errorFirstLine,
757 errorLastColumn, error.errorType );
761 void QgsExpressionBuilderWidget::createMarkers(
const QgsExpressionNode *inNode )
765 case QgsExpressionNode::NodeType::ntFunction:
768 txtExpressionString->SendScintilla( QsciScintilla::SCI_SETINDICATORCURRENT, FUNCTION_MARKER_ID );
769 txtExpressionString->SendScintilla( QsciScintilla::SCI_SETINDICATORVALUE, node->
fnIndex() );
772 int start_pos = txtExpressionString->positionFromLineIndex( inNode->
parserFirstLine - 1, start );
773 txtExpressionString->SendScintilla( QsciScintilla::SCI_INDICATORFILLRANGE, start_pos, end - start );
776 const QList< QgsExpressionNode * > nodeList = node->
args()->
list();
784 case QgsExpressionNode::NodeType::ntLiteral:
788 case QgsExpressionNode::NodeType::ntUnaryOperator:
791 createMarkers( node->
operand() );
794 case QgsExpressionNode::NodeType::ntBinaryOperator:
797 createMarkers( node->
opLeft() );
798 createMarkers( node->
opRight() );
801 case QgsExpressionNode::NodeType::ntColumnRef:
805 case QgsExpressionNode::NodeType::ntInOperator:
810 const QList< QgsExpressionNode * > nodeList = node->
list()->
list();
818 case QgsExpressionNode::NodeType::ntCondition:
821 const QList<QgsExpressionNodeCondition::WhenThen *> conditions = node->
conditions();
824 createMarkers( cond->whenExp() );
825 createMarkers( cond->thenExp() );
829 createMarkers( node->
elseExp() );
833 case QgsExpressionNode::NodeType::ntIndexOperator:
840 void QgsExpressionBuilderWidget::clearFunctionMarkers()
842 int lastLine = txtExpressionString->lines() - 1;
843 txtExpressionString->clearIndicatorRange( 0, 0, lastLine, txtExpressionString->text( lastLine ).length() - 1, FUNCTION_MARKER_ID );
846 void QgsExpressionBuilderWidget::clearErrors()
848 int lastLine = txtExpressionString->lines() - 1;
857 void QgsExpressionBuilderWidget::txtSearchEditValues_textChanged()
859 mProxyValues->setFilterCaseSensitivity( Qt::CaseInsensitive );
860 mProxyValues->setFilterWildcard( txtSearchEditValues->text() );
863 void QgsExpressionBuilderWidget::mValuesListView_doubleClicked(
const QModelIndex &index )
866 txtExpressionString->insertText(
' ' + index.data( Qt::UserRole + 1 ).toString() +
' ' );
867 txtExpressionString->setFocus();
870 void QgsExpressionBuilderWidget::operatorButtonClicked()
872 QPushButton *button = qobject_cast<QPushButton *>( sender() );
875 txtExpressionString->insertText(
' ' + button->text() +
' ' );
876 txtExpressionString->setFocus();
895 mValueGroupBox->show();
915 mValueGroupBox->show();
935 mValueGroupBox->show();
955 mValueGroupBox->show();
959 void QgsExpressionBuilderWidget::txtPython_textChanged()
961 lblAutoSave->setText( tr(
"Saving…" ) );
971 if ( tabWidget->currentIndex() != 1 )
974 QListWidgetItem *item = cmbFileNames->currentItem();
978 QString file = item->text();
980 lblAutoSave->setText( QStringLiteral(
"Saved" ) );
981 QGraphicsOpacityEffect *effect =
new QGraphicsOpacityEffect();
982 lblAutoSave->setGraphicsEffect( effect );
983 QPropertyAnimation *anim =
new QPropertyAnimation( effect,
"opacity" );
984 anim->setDuration( 2000 );
985 anim->setStartValue( 1.0 );
986 anim->setEndValue( 0.0 );
987 anim->setEasingCurve( QEasingCurve::OutQuad );
988 anim->start( QAbstractAnimation::DeleteWhenStopped );
995 if ( dlg.exec() == QDialog::DialogCode::Accepted )
997 mExpressionTreeView->saveToUserExpressions( dlg.label().simplified(), dlg.expression(), dlg.helpText() );
1011 ( item->parent() && item->parent()->text() != mUserExpressionsGroupName ) )
1015 QString helpText = settings.
value( QStringLiteral(
"user/%1/helpText" ).arg( item->text() ),
"", QgsSettings::Section::Expressions ).toString();
1018 if ( dlg.exec() == QDialog::DialogCode::Accepted )
1021 if ( dlg.isLabelModified() )
1023 mExpressionTreeView->removeFromUserExpressions( item->text() );
1026 mExpressionTreeView->saveToUserExpressions( dlg.label().simplified(), dlg.expression(), dlg.helpText() );
1041 ( item->parent() && item->parent()->text() != mUserExpressionsGroupName ) )
1044 if ( QMessageBox::Yes == QMessageBox::question(
this, tr(
"Remove Stored Expression" ),
1045 tr(
"Do you really want to remove stored expressions '%1'?" ).arg( item->text() ),
1046 QMessageBox::Yes | QMessageBox::No ) )
1048 mExpressionTreeView->removeFromUserExpressions( item->text() );
1053 void QgsExpressionBuilderWidget::exportUserExpressions_pressed()
1056 QString lastSaveDir = settings.
value( QStringLiteral(
"lastExportExpressionsDir" ), QDir::homePath(),
QgsSettings::App ).toString();
1057 QString saveFileName = QFileDialog::getSaveFileName(
1059 tr(
"Export User Expressions" ),
1061 tr(
"User expressions" ) +
" (*.json)" );
1063 if ( saveFileName.isEmpty() )
1066 QFileInfo saveFileInfo( saveFileName );
1068 if ( saveFileInfo.suffix().isEmpty() )
1070 QString saveFileNameWithSuffix = saveFileName.append(
".json" );
1071 saveFileInfo = QFileInfo( saveFileNameWithSuffix );
1076 QJsonDocument exportJson = mExpressionTreeView->exportUserExpressions();
1077 QFile jsonFile( saveFileName );
1079 if ( !jsonFile.open( QFile::WriteOnly | QIODevice::Truncate ) )
1080 QMessageBox::warning(
this, tr(
"Export user expressions" ), tr(
"Error while creating the expressions file." ) );
1082 if ( ! jsonFile.write( exportJson.toJson() ) )
1083 QMessageBox::warning(
this, tr(
"Export user expressions" ), tr(
"Error while creating the expressions file." ) );
1088 void QgsExpressionBuilderWidget::importUserExpressions_pressed()
1091 QString lastImportDir = settings.
value( QStringLiteral(
"lastImportExpressionsDir" ), QDir::homePath(),
QgsSettings::App ).toString();
1092 QString loadFileName = QFileDialog::getOpenFileName(
1094 tr(
"Import User Expressions" ),
1096 tr(
"User expressions" ) +
" (*.json)" );
1098 if ( loadFileName.isEmpty() )
1101 QFileInfo loadFileInfo( loadFileName );
1105 QFile jsonFile( loadFileName );
1107 if ( !jsonFile.open( QFile::ReadOnly ) )
1108 QMessageBox::warning(
this, tr(
"Import User Expressions" ), tr(
"Error while reading the expressions file." ) );
1110 QTextStream jsonStream( &jsonFile );
1111 QString jsonString = jsonFile.readAll();
1114 QJsonDocument importJson = QJsonDocument::fromJson( jsonString.toUtf8() );
1116 if ( importJson.isNull() )
1118 QMessageBox::warning(
this, tr(
"Import User Expressions" ), tr(
"Error while reading the expressions file." ) );
1122 mExpressionTreeView->loadExpressionsFromJson( importJson );
1128 return mExpressionTreeView->findExpressions( label );
1131 void QgsExpressionBuilderWidget::indicatorClicked(
int line,
int index, Qt::KeyboardModifiers state )
1133 if ( state & Qt::ControlModifier )
1135 int position = txtExpressionString->positionFromLineIndex( line, index );
1136 long fncIndex = txtExpressionString->SendScintilla( QsciScintilla::SCI_INDICATORVALUEAT, FUNCTION_MARKER_ID,
static_cast<long int>( position ) );
1138 QString help = getFunctionHelp( func );
1139 txtHelpText->setText( help );
1143 void QgsExpressionBuilderWidget::onExpressionParsed(
bool state )
1147 mExpressionValid = state;
1150 createMarkers( mExpressionPreviewWidget->rootNode() );
1154 createErrorMarkers( mExpressionPreviewWidget->parserErrors() );
1158 QString QgsExpressionBuilderWidget::helpStylesheet()
const
1164 style +=
" .functionname {color: #0a6099; font-weight: bold;} "
1165 " .argument {font-family: monospace; color: #bf0c0c; font-style: italic; } "
1166 " td.argument { padding-right: 10px; }";
1171 QString QgsExpressionBuilderWidget::loadFunctionHelp(
QgsExpressionItem *expressionItem )
1173 if ( !expressionItem )
1176 QString helpContents = expressionItem->
getHelpText();
1179 if ( helpContents.isEmpty() )
1181 QString name = expressionItem->data( Qt::UserRole ).toString();
1189 return "<head><style>" + helpStylesheet() +
"</style></head><body>" + helpContents +
"</body>";
1196 QMenu *QgsExpressionBuilderWidget::ExpressionTreeMenuProvider::createContextMenu(
QgsExpressionItem *item )
1198 QMenu *menu =
nullptr;
1202 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.
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.
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 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.
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.