Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Code completion for expression builder [FEATURE]
- Loading branch information
Showing
8 changed files
with
279 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
/*************************************************************************** | ||
qgscodeeditorexpressoin.cpp - An expression editor based on QScintilla | ||
-------------------------------------- | ||
Date : 8.9.2018 | ||
Copyright : (C) 2018 by Matthias Kuhn | ||
Email : matthias@opengis.ch | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#include "qgsapplication.h" | ||
#include "qgscodeeditorexpression.h" | ||
|
||
#include <QWidget> | ||
#include <QString> | ||
#include <QFont> | ||
#include <QLabel> | ||
|
||
|
||
QgsCodeEditorExpression::QgsCodeEditorExpression( QWidget *parent ) | ||
: QgsCodeEditor( parent ) | ||
{ | ||
if ( !parent ) | ||
{ | ||
setTitle( tr( "Expression Editor" ) ); | ||
} | ||
setMarginVisible( false ); | ||
setFoldingVisible( true ); | ||
setAutoCompletionCaseSensitivity( false ); | ||
initializeLexer(); | ||
} | ||
|
||
void QgsCodeEditorExpression::setExpressionContext( const QgsExpressionContext &context ) | ||
{ | ||
mVariables.clear(); | ||
|
||
const QStringList variableNames = context.filteredVariableNames(); | ||
for ( const QString &var : variableNames ) | ||
{ | ||
mVariables << '@' + var; | ||
} | ||
|
||
mContextFunctions = context.functionNames(); | ||
|
||
mFunctions.clear(); | ||
|
||
const int count = QgsExpression::functionCount(); | ||
for ( int i = 0; i < count; i++ ) | ||
{ | ||
QgsExpressionFunction *func = QgsExpression::Functions()[i]; | ||
if ( func->isDeprecated() ) // don't show deprecated functions | ||
continue; | ||
if ( func->isContextual() ) | ||
{ | ||
//don't show contextual functions by default - it's up the the QgsExpressionContext | ||
//object to provide them if supported | ||
continue; | ||
} | ||
|
||
QString signature = func->name(); | ||
if ( !signature.startsWith( '$' ) ) | ||
{ | ||
signature += '('; | ||
|
||
QStringList paramNames; | ||
const auto ¶meters = func->parameters(); | ||
for ( const auto ¶m : parameters ) | ||
{ | ||
paramNames << param.name(); | ||
} | ||
|
||
// No named parameters but there should be parameteres? Show an ellipsis at least | ||
if ( parameters.isEmpty() && func->params() ) | ||
signature += QChar( 0x2026 ); | ||
|
||
signature += paramNames.join( ", " ); | ||
|
||
signature += ')'; | ||
} | ||
mFunctions << signature; | ||
} | ||
|
||
updateApis(); | ||
} | ||
|
||
void QgsCodeEditorExpression::setFields( const QgsFields &fields ) | ||
{ | ||
mFieldNames.clear(); | ||
|
||
for ( const QgsField &field : fields ) | ||
{ | ||
mFieldNames << field.name(); | ||
} | ||
|
||
updateApis(); | ||
} | ||
|
||
|
||
void QgsCodeEditorExpression::initializeLexer() | ||
{ | ||
QFont font = getMonospaceFont(); | ||
#ifdef Q_OS_MAC | ||
// The font size gotten from getMonospaceFont() is too small on Mac | ||
font.setPointSize( QLabel().font().pointSize() ); | ||
#endif | ||
mSqlLexer = new QgsCaseInsensitiveLexerExpression( this ); | ||
mSqlLexer->setDefaultFont( font ); | ||
mSqlLexer->setFont( font, -1 ); | ||
font.setBold( true ); | ||
mSqlLexer->setFont( font, QsciLexerSQL::Keyword ); | ||
mSqlLexer->setColor( Qt::darkYellow, QsciLexerSQL::DoubleQuotedString ); // fields | ||
|
||
setLexer( mSqlLexer ); | ||
} | ||
|
||
void QgsCodeEditorExpression::updateApis() | ||
{ | ||
mApis = new QsciAPIs( mSqlLexer ); | ||
|
||
for ( const QString &var : qgis::as_const( mVariables ) ) | ||
{ | ||
mApis->add( var ); | ||
} | ||
|
||
for ( const QString &function : qgis::as_const( mContextFunctions ) ) | ||
{ | ||
mApis->add( function ); | ||
} | ||
|
||
for ( const QString &function : qgis::as_const( mFunctions ) ) | ||
{ | ||
mApis->add( function ); | ||
} | ||
|
||
for ( const QString &fieldName : qgis::as_const( mFieldNames ) ) | ||
{ | ||
mApis->add( fieldName ); | ||
} | ||
|
||
mApis->prepare(); | ||
mSqlLexer->setAPIs( mApis ); | ||
} | ||
|
||
bool QgsCaseInsensitiveLexerExpression::caseSensitive() const | ||
{ | ||
return false; | ||
} | ||
#if 0 | ||
const char *QgsCaseInsensitiveLexerExpression::wordCharacters() const | ||
{ | ||
static QString wordChars; | ||
|
||
wordChars = QsciLexerSQL::wordCharacters(); | ||
wordChars += '@'; | ||
return wordChars.toUtf8().constData(); | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/*************************************************************************** | ||
qgscodeeditorsql.h - A SQL editor based on QScintilla | ||
-------------------------------------- | ||
Date : 06-Oct-2013 | ||
Copyright : (C) 2013 by Salvatore Larosa | ||
Email : lrssvtml (at) gmail (dot) com | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#ifndef QGSCODEEDITOREXPRESSION_H | ||
#define QGSCODEEDITOREXPRESSION_H | ||
|
||
#include "qgis_sip.h" | ||
#include "qgis_gui.h" | ||
#include "qgscodeeditor.h" | ||
#include "qgsexpressioncontext.h" | ||
|
||
#include <Qsci/qscilexersql.h> | ||
|
||
SIP_IF_MODULE( HAVE_QSCI_SIP ) | ||
|
||
/** | ||
* \ingroup gui | ||
* | ||
* A QGIS expression editor based on QScintilla2. Adds syntax highlighting and | ||
* code autocompletion. | ||
* | ||
* \since QGIS 3.4 | ||
*/ | ||
class GUI_EXPORT QgsCodeEditorExpression : public QgsCodeEditor | ||
{ | ||
Q_OBJECT | ||
|
||
public: | ||
//! Constructor for QgsCodeEditorExpression | ||
QgsCodeEditorExpression( QWidget *parent SIP_TRANSFERTHIS = nullptr ); | ||
|
||
/** | ||
* Variables and functions from this expression context will be added to | ||
* the API. | ||
* Will also reload all globally registered functions. | ||
*/ | ||
void setExpressionContext( const QgsExpressionContext &context ); | ||
|
||
/** | ||
* Field names will be added to the API. | ||
*/ | ||
void setFields( const QgsFields &fields ); | ||
|
||
private: | ||
void initializeLexer(); | ||
void updateApis(); | ||
QsciAPIs *mApis; | ||
QsciLexerSQL *mSqlLexer; | ||
|
||
QStringList mVariables; | ||
QStringList mContextFunctions; | ||
QStringList mFunctions; | ||
QStringList mFieldNames; | ||
}; | ||
|
||
#ifndef SIP_RUN | ||
///@cond PRIVATE | ||
|
||
/** | ||
* Internal use. | ||
setAutoCompletionCaseSensitivity( false ) is not sufficient when installing | ||
a lexer, since its caseSensitive() method is actually used, and defaults | ||
to true. | ||
\note not available in Python bindings | ||
\ingroup gui | ||
*/ | ||
class QgsCaseInsensitiveLexerExpression : public QsciLexerSQL | ||
{ | ||
Q_OBJECT | ||
|
||
public: | ||
//! constructor | ||
explicit QgsCaseInsensitiveLexerExpression( QObject *parent = nullptr ) : QsciLexerSQL( parent ) {} | ||
|
||
bool caseSensitive() const override; | ||
|
||
#if 0 | ||
const char *wordCharacters() const override; | ||
#endif | ||
}; | ||
///@endcond | ||
#endif | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters