QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgscodeeditorpython.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscodeeditorpython.cpp - A Python editor based on QScintilla
3  --------------------------------------
4  Date : 06-Oct-2013
5  Copyright : (C) 2013 by Salvatore Larosa
6  Email : lrssvtml (at) gmail (dot) com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsapplication.h"
17 #include "qgscodeeditorpython.h"
18 #include "qgslogger.h"
19 #include "qgssymbollayerutils.h"
20 #include "qgssettings.h"
21 #include "qgis.h"
22 
23 #include <QWidget>
24 #include <QString>
25 #include <QFont>
26 #include <QFileInfo>
27 #include <QMessageBox>
28 #include <QTextStream>
29 #include <Qsci/qscilexerpython.h>
30 #include <QDesktopServices>
31 
32 QgsCodeEditorPython::QgsCodeEditorPython( QWidget *parent, const QList<QString> &filenames )
33  : QgsCodeEditor( parent )
34  , mAPISFilesList( filenames )
35 {
36  if ( !parent )
37  {
38  setTitle( tr( "Python Editor" ) );
39  }
40 
41  setCaretWidth( 2 );
42 
44 }
45 
47 {
48  // current line
49  setEdgeMode( QsciScintilla::EdgeLine );
50  setEdgeColumn( 80 );
52 
53  setWhitespaceVisibility( QsciScintilla::WsVisibleAfterIndent );
54 
55  QFont font = lexerFont();
57 
58  QsciLexerPython *pyLexer = new QgsQsciLexerPython( this );
59 
60  pyLexer->setIndentationWarning( QsciLexerPython::Inconsistent );
61  pyLexer->setFoldComments( true );
62  pyLexer->setFoldQuotes( true );
63 
64  pyLexer->setDefaultFont( font );
65  pyLexer->setDefaultColor( defaultColor );
66  pyLexer->setDefaultPaper( lexerColor( QgsCodeEditorColorScheme::ColorRole::Background ) );
67  pyLexer->setFont( font, -1 );
68 
69  font.setItalic( true );
70  pyLexer->setFont( font, QsciLexerPython::Comment );
71  pyLexer->setFont( font, QsciLexerPython::CommentBlock );
72 
73  font.setItalic( false );
74  font.setBold( true );
75  pyLexer->setFont( font, QsciLexerPython::SingleQuotedString );
76  pyLexer->setFont( font, QsciLexerPython::DoubleQuotedString );
77 
78  pyLexer->setColor( defaultColor, QsciLexerPython::Default );
79  pyLexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Class ), QsciLexerPython::ClassName );
80  pyLexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Method ), QsciLexerPython::FunctionMethodName );
81  pyLexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Number ), QsciLexerPython::Number );
82  pyLexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Operator ), QsciLexerPython::Operator );
83  pyLexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Identifier ), QsciLexerPython::Identifier );
84  pyLexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Comment ), QsciLexerPython::Comment );
85  pyLexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::CommentBlock ), QsciLexerPython::CommentBlock );
86  pyLexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Keyword ), QsciLexerPython::Keyword );
87  pyLexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Decoration ), QsciLexerPython::Decorator );
88  pyLexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::SingleQuote ), QsciLexerPython::SingleQuotedString );
89  pyLexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::DoubleQuote ), QsciLexerPython::DoubleQuotedString );
90  pyLexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::TripleSingleQuote ), QsciLexerPython::TripleSingleQuotedString );
91  pyLexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::TripleDoubleQuote ), QsciLexerPython::TripleDoubleQuotedString );
92 
93  QsciAPIs *apis = new QsciAPIs( pyLexer );
94 
95  QgsSettings settings;
96 
97  if ( mAPISFilesList.isEmpty() )
98  {
99  if ( settings.value( QStringLiteral( "pythonConsole/preloadAPI" ), true ).toBool() )
100  {
101  mPapFile = QgsApplication::pkgDataPath() + QStringLiteral( "/python/qsci_apis/pyqgis.pap" );
102  apis->loadPrepared( mPapFile );
103  }
104  else if ( settings.value( QStringLiteral( "pythonConsole/usePreparedAPIFile" ), false ).toBool() )
105  {
106  apis->loadPrepared( settings.value( QStringLiteral( "pythonConsole/preparedAPIFile" ) ).toString() );
107  }
108  else
109  {
110  const QStringList apiPaths = settings.value( QStringLiteral( "pythonConsole/userAPI" ) ).toStringList();
111  for ( const QString &path : apiPaths )
112  {
113  if ( !QFileInfo::exists( path ) )
114  {
115  QgsDebugMsg( QStringLiteral( "The apis file %1 was not found" ).arg( path ) );
116  }
117  else
118  {
119  apis->load( path );
120  }
121  }
122  apis->prepare();
123  pyLexer->setAPIs( apis );
124  }
125  }
126  else if ( mAPISFilesList.length() == 1 && mAPISFilesList[0].right( 3 ) == QLatin1String( "pap" ) )
127  {
128  if ( !QFileInfo::exists( mAPISFilesList[0] ) )
129  {
130  QgsDebugMsg( QStringLiteral( "The apis file %1 not found" ).arg( mAPISFilesList.at( 0 ) ) );
131  return;
132  }
133  mPapFile = mAPISFilesList[0];
134  apis->loadPrepared( mPapFile );
135  }
136  else
137  {
138  for ( const QString &path : mAPISFilesList )
139  {
140  if ( !QFileInfo::exists( path ) )
141  {
142  QgsDebugMsg( QStringLiteral( "The apis file %1 was not found" ).arg( path ) );
143  }
144  else
145  {
146  apis->load( path );
147  }
148  }
149  apis->prepare();
150  pyLexer->setAPIs( apis );
151  }
152  setLexer( pyLexer );
153 
154  const int threshold = settings.value( QStringLiteral( "pythonConsole/autoCompThreshold" ), 2 ).toInt();
155  setAutoCompletionThreshold( threshold );
156  if ( !settings.value( "pythonConsole/autoCompleteEnabled", true ).toBool() )
157  {
158  setAutoCompletionSource( AcsNone );
159  }
160  else
161  {
162  QString autoCompleteSource = settings.value( QStringLiteral( "pythonConsole/autoCompleteSource" ), QStringLiteral( "fromAPI" ) ).toString();
163  if ( autoCompleteSource == QLatin1String( "fromDoc" ) )
164  setAutoCompletionSource( AcsDocument );
165  else if ( autoCompleteSource == QLatin1String( "fromDocAPI" ) )
166  setAutoCompletionSource( AcsAll );
167  else
168  setAutoCompletionSource( AcsAPIs );
169  }
170 
171  setLineNumbersVisible( true );
172  setFoldingVisible( true );
173  setIndentationsUseTabs( false );
174  setIndentationGuides( true );
175 
177 }
178 
180 {
181  switch ( autoCompletionSource() )
182  {
183  case AcsDocument:
184  autoCompleteFromDocument();
185  break;
186 
187  case AcsAPIs:
188  autoCompleteFromAPIs();
189  break;
190 
191  case AcsAll:
192  autoCompleteFromAll();
193  break;
194 
195  case AcsNone:
196  break;
197  }
198 }
199 
200 void QgsCodeEditorPython::loadAPIs( const QList<QString> &filenames )
201 {
202  mAPISFilesList = filenames;
203  //QgsDebugMsg( QStringLiteral( "The apis files: %1" ).arg( mAPISFilesList[0] ) );
204  initializeLexer();
205 }
206 
207 bool QgsCodeEditorPython::loadScript( const QString &script )
208 {
209  QgsDebugMsgLevel( QStringLiteral( "The script file: %1" ).arg( script ), 2 );
210  QFile file( script );
211  if ( !file.open( QIODevice::ReadOnly ) )
212  {
213  return false;
214  }
215 
216  QTextStream in( &file );
217 
218  setText( in.readAll().trimmed() );
219  file.close();
220 
221  initializeLexer();
222  return true;
223 }
224 
226 {
227  if ( !hasSelectedText() )
228  return;
229 
230  QString text = selectedText();
231  text = text.replace( QLatin1String( ">>> " ), QString() ).replace( QLatin1String( "... " ), QString() ).trimmed(); // removing prompts
232  const QString version = QString( Qgis::version() ).split( '.' ).mid( 0, 2 ).join( '.' );
233  QDesktopServices::openUrl( QUrl( QStringLiteral( "https://qgis.org/pyqgis/%1/search.html?q=%2" ).arg( version, text ) ) );
234 }
235 
236 //
237 // QgsQsciLexerPython
238 //
239 QgsQsciLexerPython::QgsQsciLexerPython( QObject *parent )
240  : QsciLexerPython( parent )
241 {
242 
243 }
244 
245 const char *QgsQsciLexerPython::keywords( int set ) const
246 {
247  if ( set == 1 )
248  {
249  return "True False and as assert break class continue def del elif else except exec "
250  "finally for from global if import in is lambda None not or pass "
251  "print raise return try while with yield";
252  }
253 
254  return QsciLexerPython::keywords( set );
255 }
QgsCodeEditorColorScheme::ColorRole::Edge
@ Edge
Edge color.
QgsCodeEditor::lexerColor
QColor lexerColor(QgsCodeEditorColorScheme::ColorRole role) const
Returns the color to use in the lexer for the specified role.
Definition: qgscodeeditor.cpp:154
Qgis::version
static QString version()
Version string.
Definition: qgis.cpp:276
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:174
QgsCodeEditorColorScheme::ColorRole::Default
@ Default
Default text color.
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsCodeEditorPython::autoComplete
void autoComplete()
Triggers the autocompletion popup.
Definition: qgscodeeditorpython.cpp:179
qgscodeeditorpython.h
QgsCodeEditorPython::QgsCodeEditorPython
QgsCodeEditorPython(QWidget *parent=nullptr, const QList< QString > &filenames=QList< QString >())
Construct a new Python editor.
Definition: qgscodeeditorpython.cpp:32
qgssymbollayerutils.h
QgsCodeEditor
A text editor based on QScintilla2.
Definition: qgscodeeditor.h:42
qgis.h
QgsCodeEditorColorScheme::ColorRole::Operator
@ Operator
Operator color.
QgsSettings
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsCodeEditorColorScheme::ColorRole::SingleQuote
@ SingleQuote
Single quote color.
QgsCodeEditor::setTitle
void setTitle(const QString &title)
Set the widget title.
Definition: qgscodeeditor.cpp:259
qgsapplication.h
QgsCodeEditorColorScheme::ColorRole::DoubleQuote
@ DoubleQuote
Double quote color.
QgsCodeEditorPython::loadAPIs
void loadAPIs(const QList< QString > &filenames)
Load APIs from one or more files.
Definition: qgscodeeditorpython.cpp:200
QgsCodeEditorColorScheme::ColorRole::Method
@ Method
Method color.
QgsCodeEditorColorScheme::ColorRole::Comment
@ Comment
Comment color.
QgsCodeEditor::lexerFont
QFont lexerFont() const
Returns the font to use in the lexer.
Definition: qgscodeeditor.cpp:170
QgsCodeEditorColorScheme::ColorRole::Decoration
@ Decoration
Decoration color.
QgsCodeEditorColorScheme::ColorRole::CommentBlock
@ CommentBlock
Comment block color.
QgsCodeEditor::runPostLexerConfigurationTasks
void runPostLexerConfigurationTasks()
Performs tasks which must be run after a lexer has been set for the widget.
Definition: qgscodeeditor.cpp:203
QgsCodeEditorPython::initializeLexer
void initializeLexer() override
Called when the dialect specific code lexer needs to be initialized (or reinitialized).
Definition: qgscodeeditorpython.cpp:46
QgsApplication::pkgDataPath
static QString pkgDataPath()
Returns the common root path of all application data directories.
Definition: qgsapplication.cpp:578
QgsCodeEditor::setLineNumbersVisible
void setLineNumbersVisible(bool visible)
Sets whether line numbers should be visible in the editor.
Definition: qgscodeeditor.cpp:285
QgsCodeEditorColorScheme::ColorRole::TripleSingleQuote
@ TripleSingleQuote
Triple single quote color.
QgsCodeEditorColorScheme::ColorRole::Number
@ Number
Number color.
QgsCodeEditorColorScheme::ColorRole::Identifier
@ Identifier
Identifier color.
QgsCodeEditorColorScheme::ColorRole::TripleDoubleQuote
@ TripleDoubleQuote
Triple double quote color.
QgsCodeEditorPython::loadScript
bool loadScript(const QString &script)
Load a script file.
Definition: qgscodeeditorpython.cpp:207
qgssettings.h
QgsCodeEditor::defaultColor
static QColor defaultColor(QgsCodeEditorColorScheme::ColorRole role, const QString &theme=QString())
Returns the default color for the specified role.
Definition: qgscodeeditor.cpp:342
QgsCodeEditorColorScheme::ColorRole::Class
@ Class
Class color.
QgsCodeEditor::setFoldingVisible
void setFoldingVisible(bool folding)
Set whether the folding controls are visible in the editor.
Definition: qgscodeeditor.cpp:309
qgslogger.h
QgsCodeEditorPython::searchSelectedTextInPyQGISDocs
void searchSelectedTextInPyQGISDocs()
Searches the selected text in the official PyQGIS online documentation.
Definition: qgscodeeditorpython.cpp:225
QgsCodeEditorColorScheme::ColorRole::Background
@ Background
Background color.
QgsCodeEditorColorScheme::ColorRole::Keyword
@ Keyword
Keyword color.