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