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::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 = qgis::make_unique<QStandardItemModel>();
136 mProxyValues = qgis::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 );
290 txtExpressionString->setFields( mLayer->
fields() );
299 void QgsExpressionBuilderWidget::expressionTreeItemChanged(
QgsExpressionItem *item )
301 txtSearchEditValues->clear();
309 mValuesModel->clear();
312 cbxValuesInUse->setChecked(
false );
314 mValueGroupBox->setVisible( isField );
316 mShowHelpButton->setText( isField ? tr(
"Show Values" ) : tr(
"Show Help" ) );
319 QString help = loadFunctionHelp( item );
320 txtHelpText->setText( help );
322 bool isUserExpression = item->parent() && item->parent()->text() == mUserExpressionsGroupName;
324 btnRemoveExpression->setEnabled( isUserExpression );
325 btnEditExpression->setEnabled( isUserExpression );
328 void QgsExpressionBuilderWidget::btnRun_pressed()
330 if ( !cmbFileNames->currentItem() )
333 QString file = cmbFileNames->currentItem()->text();
335 runPythonCode( txtPython->text() );
338 void QgsExpressionBuilderWidget::runPythonCode(
const QString &code )
342 QString pythontext = code;
345 mExpressionTreeView->refresh();
350 QDir myDir( mFunctionsPath );
351 if ( !myDir.exists() )
353 myDir.mkpath( mFunctionsPath );
356 if ( !fileName.endsWith( QLatin1String(
".py" ) ) )
358 fileName.append(
".py" );
361 fileName = mFunctionsPath + QDir::separator() + fileName;
362 QFile myFile( fileName );
363 if ( myFile.open( QIODevice::WriteOnly | QFile::Truncate ) )
365 QTextStream myFileStream( &myFile );
366 myFileStream << txtPython->text() << endl;
373 mFunctionsPath = path;
375 dir.setNameFilters( QStringList() << QStringLiteral(
"*.py" ) );
376 QStringList files = dir.entryList( QDir::Files );
377 cmbFileNames->clear();
378 const auto constFiles = files;
379 for (
const QString &name : constFiles )
381 QFileInfo info( mFunctionsPath + QDir::separator() + name );
382 if ( info.baseName() == QLatin1String(
"__init__" ) )
continue;
383 QListWidgetItem *item =
new QListWidgetItem(
QgsApplication::getThemeIcon( QStringLiteral(
"console/iconTabEditorConsole.svg" ) ), info.baseName() );
384 cmbFileNames->addItem( item );
386 if ( !cmbFileNames->currentItem() )
388 cmbFileNames->setCurrentRow( 0 );
391 if ( cmbFileNames->count() == 0 )
395 txtPython->setText( QStringLiteral(
"'''\n#Sample custom function file\n "
396 "(uncomment to use and customize or Add button to create a new file) \n%1 \n '''" ).arg( txtPython->text() ) );
403 QList<QListWidgetItem *> items = cmbFileNames->findItems( fileName, Qt::MatchExactly );
404 if ( !items.isEmpty() )
407 QListWidgetItem *item =
new QListWidgetItem(
QgsApplication::getThemeIcon( QStringLiteral(
"console/iconTabEditorConsole.svg" ) ), fileName );
408 cmbFileNames->insertItem( 0, item );
409 cmbFileNames->setCurrentRow( 0 );
413 txtPython->setText( templatetxt );
417 void QgsExpressionBuilderWidget::btnNewFile_pressed()
420 QString text = QInputDialog::getText(
this, tr(
"New File" ),
421 tr(
"New file name:" ), QLineEdit::Normal,
423 if ( ok && !text.isEmpty() )
429 void QgsExpressionBuilderWidget::btnRemoveFile_pressed()
431 if ( QMessageBox::question(
this, tr(
"Remove File" ),
432 tr(
"Are you sure you want to remove current functions file?" ),
433 QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) == QMessageBox::No )
436 int currentRow = cmbFileNames->currentRow();
437 QString fileName = cmbFileNames->currentItem()->text();
438 if ( QFile::remove( mFunctionsPath + QDir::separator() + fileName.append(
".py" ) ) )
441 QListWidgetItem *itemToRemove =
whileBlocking( cmbFileNames )->takeItem( currentRow );
445 if ( cmbFileNames->count() > 0 )
447 cmbFileNames->setCurrentRow( currentRow > 0 ? currentRow - 1 : 0 );
448 loadCodeFromFile( mFunctionsPath + QDir::separator() + cmbFileNames->currentItem()->text() );
452 btnRemoveFile->setEnabled(
false );
458 QMessageBox::warning(
this, tr(
"Remove file" ), tr(
"Failed to remove function file '%1'." ).arg( fileName ) );
462 void QgsExpressionBuilderWidget::cmbFileNames_currentItemChanged( QListWidgetItem *item, QListWidgetItem *lastitem )
466 QString filename = lastitem->text();
469 QString path = mFunctionsPath + QDir::separator() + item->text();
475 if ( !path.endsWith( QLatin1String(
".py" ) ) )
476 path.append(
".py" );
478 txtPython->loadScript( path );
483 txtPython->setText( code );
486 void QgsExpressionBuilderWidget::insertExpressionText(
const QString &text )
489 txtExpressionString->insertText( text );
490 txtExpressionString->setFocus();
495 Q_UNUSED( fieldValues )
499 void QgsExpressionBuilderWidget::fillFieldValues(
const QString &fieldName,
int countLimit,
bool forceUsedValues )
511 if ( fieldIndex < 0 )
518 if ( cbxValuesInUse->isVisible() && !cbxValuesInUse->isChecked() && !forceUsedValues )
522 values =
formatter->availableValues( setup.
config(), countLimit, fieldFormatterContext );
526 values = qgis::setToList( mLayer->
uniqueValues( fieldIndex, countLimit ) );
528 std::sort( values.begin(), values.end() );
530 mValuesModel->clear();
531 for (
const QVariant &value : qgis::as_const( values ) )
534 if ( value.isNull() )
535 strValue = QStringLiteral(
"NULL" );
536 else if ( value.type() == QVariant::Int || value.type() == QVariant::Double || value.type() == QVariant::LongLong )
537 strValue = value.toString();
539 strValue =
'\'' + value.toString().replace(
'\'', QLatin1String(
"''" ) ) +
'\'';
541 QString representedValue =
formatter->representValue( mLayer, fieldIndex, setup.
config(), QVariant(), value );
542 if ( representedValue != value.toString() )
543 representedValue = representedValue + QStringLiteral(
" [" ) + strValue +
']';
545 QStandardItem *item =
new QStandardItem( representedValue );
546 item->setData( strValue );
547 mValuesModel->appendRow( item );
558 return QStringLiteral(
"<head><style>" ) + helpStylesheet() + QStringLiteral(
"</style></head><body>" ) + helpContents + QStringLiteral(
"</body>" );
566 return mExpressionValid;
571 mExpressionTreeView->saveToRecent(
expressionText(), collection );
576 mExpressionTreeView->loadRecent( collection );
581 return mExpressionTreeView;
587 mExpressionTreeView->loadUserExpressions();
592 mExpressionTreeView->saveToUserExpressions( label, expression, helpText );
597 mExpressionTreeView->removeFromUserExpressions( label );
603 mExpressionPreviewWidget->setGeomCalculator( da );
608 return txtExpressionString->text();
613 txtExpressionString->setText( expression );
618 return lblExpected->text();
623 lblExpected->setText( expected );
624 mExpectedOutputFrame->setVisible( !expected.isNull() );
629 mExpressionContext = context;
630 txtExpressionString->setExpressionContext( mExpressionContext );
631 mExpressionTreeView->setExpressionContext( context );
632 mExpressionPreviewWidget->setExpressionContext( context );
635 void QgsExpressionBuilderWidget::txtExpressionString_textChanged()
639 btnClearEditor->setEnabled( ! txtExpressionString->text().isEmpty() );
640 btnSaveExpression->setEnabled(
false );
642 mExpressionPreviewWidget->setExpressionText( text );
647 return mExpressionPreviewWidget->parserError();
652 return mExpressionPreviewWidget->evalError();
658 return mExpressionTreeView->model();
670 mExpressionTreeView->setProject(
project );
675 QWidget::showEvent( e );
676 txtExpressionString->setFocus();
679 void QgsExpressionBuilderWidget::createErrorMarkers( QList<QgsExpression::ParserError> errors )
684 int errorFirstLine = error.firstLine - 1 ;
685 int errorFirstColumn = error.firstColumn - 1;
686 int errorLastColumn = error.lastColumn - 1;
687 int errorLastLine = error.lastLine - 1;
693 errorFirstLine = errorLastLine;
694 errorFirstColumn = errorLastColumn - 1;
696 txtExpressionString->fillIndicatorRange( errorFirstLine,
699 errorLastColumn, error.errorType );
703 void QgsExpressionBuilderWidget::createMarkers(
const QgsExpressionNode *inNode )
707 case QgsExpressionNode::NodeType::ntFunction:
710 txtExpressionString->SendScintilla( QsciScintilla::SCI_SETINDICATORCURRENT, FUNCTION_MARKER_ID );
711 txtExpressionString->SendScintilla( QsciScintilla::SCI_SETINDICATORVALUE, node->
fnIndex() );
714 int start_pos = txtExpressionString->positionFromLineIndex( inNode->
parserFirstLine - 1, start );
715 txtExpressionString->SendScintilla( QsciScintilla::SCI_INDICATORFILLRANGE, start_pos, end - start );
718 const QList< QgsExpressionNode * > nodeList = node->
args()->
list();
726 case QgsExpressionNode::NodeType::ntLiteral:
730 case QgsExpressionNode::NodeType::ntUnaryOperator:
733 createMarkers( node->
operand() );
736 case QgsExpressionNode::NodeType::ntBinaryOperator:
739 createMarkers( node->
opLeft() );
740 createMarkers( node->
opRight() );
743 case QgsExpressionNode::NodeType::ntColumnRef:
747 case QgsExpressionNode::NodeType::ntInOperator:
752 const QList< QgsExpressionNode * > nodeList = node->
list()->
list();
760 case QgsExpressionNode::NodeType::ntCondition:
765 createMarkers( cond->whenExp() );
766 createMarkers( cond->thenExp() );
770 createMarkers( node->
elseExp() );
774 case QgsExpressionNode::NodeType::ntIndexOperator:
781 void QgsExpressionBuilderWidget::clearFunctionMarkers()
783 int lastLine = txtExpressionString->lines() - 1;
784 txtExpressionString->clearIndicatorRange( 0, 0, lastLine, txtExpressionString->text( lastLine ).length() - 1, FUNCTION_MARKER_ID );
787 void QgsExpressionBuilderWidget::clearErrors()
789 int lastLine = txtExpressionString->lines() - 1;
798 void QgsExpressionBuilderWidget::txtSearchEditValues_textChanged()
800 mProxyValues->setFilterCaseSensitivity( Qt::CaseInsensitive );
801 mProxyValues->setFilterWildcard( txtSearchEditValues->text() );
804 void QgsExpressionBuilderWidget::mValuesListView_doubleClicked(
const QModelIndex &index )
807 txtExpressionString->insertText(
' ' + index.data( Qt::UserRole + 1 ).toString() +
' ' );
808 txtExpressionString->setFocus();
811 void QgsExpressionBuilderWidget::operatorButtonClicked()
813 QPushButton *button = qobject_cast<QPushButton *>( sender() );
816 txtExpressionString->insertText(
' ' + button->text() +
' ' );
817 txtExpressionString->setFocus();
825 if ( !mLayer || !item )
828 mValueGroupBox->show();
837 if ( !mLayer || !item )
840 mValueGroupBox->show();
849 if ( !mLayer || !item )
852 mValueGroupBox->show();
861 if ( !mLayer || !item )
864 mValueGroupBox->show();
868 void QgsExpressionBuilderWidget::txtPython_textChanged()
870 lblAutoSave->setText( tr(
"Saving…" ) );
880 if ( tabWidget->currentIndex() != 1 )
883 QListWidgetItem *item = cmbFileNames->currentItem();
887 QString file = item->text();
889 lblAutoSave->setText( QStringLiteral(
"Saved" ) );
890 QGraphicsOpacityEffect *effect =
new QGraphicsOpacityEffect();
891 lblAutoSave->setGraphicsEffect( effect );
892 QPropertyAnimation *anim =
new QPropertyAnimation( effect,
"opacity" );
893 anim->setDuration( 2000 );
894 anim->setStartValue( 1.0 );
895 anim->setEndValue( 0.0 );
896 anim->setEasingCurve( QEasingCurve::OutQuad );
897 anim->start( QAbstractAnimation::DeleteWhenStopped );
904 if ( dlg.exec() == QDialog::DialogCode::Accepted )
906 mExpressionTreeView->saveToUserExpressions( dlg.label(), dlg.expression(), dlg.helpText() );
920 ( item->parent() && item->parent()->text() != mUserExpressionsGroupName ) )
924 QString helpText = settings.
value( QStringLiteral(
"user/%1/helpText" ).arg( item->text() ),
"", QgsSettings::Section::Expressions ).toString();
927 if ( dlg.exec() == QDialog::DialogCode::Accepted )
930 if ( dlg.label() != item->text() )
932 mExpressionTreeView->removeFromUserExpressions( item->text() );
935 mExpressionTreeView->saveToUserExpressions( dlg.label(), dlg.expression(), dlg.helpText() );
950 ( item->parent() && item->parent()->text() != mUserExpressionsGroupName ) )
953 if ( QMessageBox::Yes == QMessageBox::question(
this, tr(
"Remove Stored Expression" ),
954 tr(
"Do you really want to remove stored expressions '%1'?" ).arg( item->text() ),
955 QMessageBox::Yes | QMessageBox::No ) )
957 mExpressionTreeView->removeFromUserExpressions( item->text() );
962 void QgsExpressionBuilderWidget::exportUserExpressions_pressed()
965 QString lastSaveDir = settings.
value( QStringLiteral(
"lastExportExpressionsDir" ), QDir::homePath(),
QgsSettings::App ).toString();
966 QString saveFileName = QFileDialog::getSaveFileName(
968 tr(
"Export User Expressions" ),
970 tr(
"User expressions" ) +
" (*.json)" );
972 if ( saveFileName.isEmpty() )
975 QFileInfo saveFileInfo( saveFileName );
977 if ( saveFileInfo.suffix().isEmpty() )
979 QString saveFileNameWithSuffix = saveFileName.append(
".json" );
980 saveFileInfo = QFileInfo( saveFileNameWithSuffix );
985 QJsonDocument exportJson = mExpressionTreeView->exportUserExpressions();
986 QFile jsonFile( saveFileName );
988 if ( !jsonFile.open( QFile::WriteOnly | QIODevice::Truncate ) )
989 QMessageBox::warning(
this, tr(
"Export user expressions" ), tr(
"Error while creating the expressions file." ) );
991 if ( ! jsonFile.write( exportJson.toJson() ) )
992 QMessageBox::warning(
this, tr(
"Export user expressions" ), tr(
"Error while creating the expressions file." ) );
997 void QgsExpressionBuilderWidget::importUserExpressions_pressed()
1000 QString lastImportDir = settings.
value( QStringLiteral(
"lastImportExpressionsDir" ), QDir::homePath(),
QgsSettings::App ).toString();
1001 QString loadFileName = QFileDialog::getOpenFileName(
1003 tr(
"Import User Expressions" ),
1005 tr(
"User expressions" ) +
" (*.json)" );
1007 if ( loadFileName.isEmpty() )
1010 QFileInfo loadFileInfo( loadFileName );
1014 QFile jsonFile( loadFileName );
1016 if ( !jsonFile.open( QFile::ReadOnly ) )
1017 QMessageBox::warning(
this, tr(
"Import User Expressions" ), tr(
"Error while reading the expressions file." ) );
1019 QTextStream jsonStream( &jsonFile );
1020 QString jsonString = jsonFile.readAll();
1023 QJsonDocument importJson = QJsonDocument::fromJson( jsonString.toUtf8() );
1025 if ( importJson.isNull() )
1027 QMessageBox::warning(
this, tr(
"Import User Expressions" ), tr(
"Error while reading the expressions file." ) );
1031 mExpressionTreeView->loadExpressionsFromJson( importJson );
1037 return mExpressionTreeView->findExpressions( label );
1040 void QgsExpressionBuilderWidget::indicatorClicked(
int line,
int index, Qt::KeyboardModifiers state )
1042 if ( state & Qt::ControlModifier )
1044 int position = txtExpressionString->positionFromLineIndex( line, index );
1045 long fncIndex = txtExpressionString->SendScintilla( QsciScintilla::SCI_INDICATORVALUEAT, FUNCTION_MARKER_ID,
static_cast<long int>( position ) );
1047 QString help = getFunctionHelp( func );
1048 txtHelpText->setText( help );
1052 void QgsExpressionBuilderWidget::onExpressionParsed(
bool state )
1056 mExpressionValid = state;
1059 createMarkers( mExpressionPreviewWidget->rootNode() );
1063 createErrorMarkers( mExpressionPreviewWidget->parserErrors() );
1067 QString QgsExpressionBuilderWidget::helpStylesheet()
const
1073 style +=
" .functionname {color: #0a6099; font-weight: bold;} "
1074 " .argument {font-family: monospace; color: #bf0c0c; font-style: italic; } "
1075 " td.argument { padding-right: 10px; }";
1080 QString QgsExpressionBuilderWidget::loadFunctionHelp(
QgsExpressionItem *expressionItem )
1082 if ( !expressionItem )
1085 QString helpContents = expressionItem->
getHelpText();
1088 if ( helpContents.isEmpty() )
1090 QString name = expressionItem->data( Qt::UserRole ).toString();
1098 return "<head><style>" + helpStylesheet() +
"</style></head><body>" + helpContents +
"</body>";
1105 QMenu *QgsExpressionBuilderWidget::ExpressionTreeMenuProvider::createContextMenu(
QgsExpressionItem *item )
1107 QMenu *menu =
nullptr;
1111 menu =
new QMenu( mExpressionBuilderWidget );
1117 menu->addAction( tr(
"Load First 10 Unique Used Values" ), mExpressionBuilderWidget, SLOT( loadSampleUsedValues() ) );