QGIS API Documentation 3.32.0-Lima (311a8cb8a6)
•All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
qgscodeeditor.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgscodeeditor.cpp - A base code editor for QGIS and plugins. Provides
3 a base editor using QScintilla for editors
4 --------------------------------------
5 Date : 06-Oct-2013
6 Copyright : (C) 2013 by Salvatore Larosa
7 Email : lrssvtml (at) gmail (dot) com
8 ***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16
17#include "qgsapplication.h"
18#include "qgscodeeditor.h"
19#include "qgssettings.h"
20#include "qgssymbollayerutils.h"
21#include "qgsgui.h"
24#include "qgsstringutils.h"
25
26#include <QLabel>
27#include <QWidget>
28#include <QFont>
29#include <QFontDatabase>
30#include <QDebug>
31#include <QFocusEvent>
32#include <Qsci/qscistyle.h>
33#include <QMenu>
34#include <QClipboard>
35#include <QScrollBar>
36#include <QMessageBox>
37
38QMap< QgsCodeEditorColorScheme::ColorRole, QString > QgsCodeEditor::sColorRoleToSettingsKey
39{
40 {QgsCodeEditorColorScheme::ColorRole::Default, QStringLiteral( "defaultFontColor" ) },
41 {QgsCodeEditorColorScheme::ColorRole::Keyword, QStringLiteral( "keywordFontColor" ) },
42 {QgsCodeEditorColorScheme::ColorRole::Class, QStringLiteral( "classFontColor" ) },
43 {QgsCodeEditorColorScheme::ColorRole::Method, QStringLiteral( "methodFontColor" ) },
44 {QgsCodeEditorColorScheme::ColorRole::Decoration, QStringLiteral( "decoratorFontColor" ) },
45 {QgsCodeEditorColorScheme::ColorRole::Number, QStringLiteral( "numberFontColor" ) },
46 {QgsCodeEditorColorScheme::ColorRole::Comment, QStringLiteral( "commentFontColor" ) },
47 {QgsCodeEditorColorScheme::ColorRole::CommentLine, QStringLiteral( "commentLineFontColor" ) },
48 {QgsCodeEditorColorScheme::ColorRole::CommentBlock, QStringLiteral( "commentBlockFontColor" ) },
49 {QgsCodeEditorColorScheme::ColorRole::Background, QStringLiteral( "paperBackgroundColor" ) },
50 {QgsCodeEditorColorScheme::ColorRole::Cursor, QStringLiteral( "cursorColor" ) },
51 {QgsCodeEditorColorScheme::ColorRole::CaretLine, QStringLiteral( "caretLineColor" ) },
52 {QgsCodeEditorColorScheme::ColorRole::Operator, QStringLiteral( "operatorFontColor" ) },
53 {QgsCodeEditorColorScheme::ColorRole::QuotedOperator, QStringLiteral( "quotedOperatorFontColor" ) },
54 {QgsCodeEditorColorScheme::ColorRole::Identifier, QStringLiteral( "identifierFontColor" ) },
55 {QgsCodeEditorColorScheme::ColorRole::QuotedIdentifier, QStringLiteral( "quotedIdentifierFontColor" ) },
56 {QgsCodeEditorColorScheme::ColorRole::Tag, QStringLiteral( "tagFontColor" ) },
57 {QgsCodeEditorColorScheme::ColorRole::UnknownTag, QStringLiteral( "unknownTagFontColor" ) },
58 {QgsCodeEditorColorScheme::ColorRole::SingleQuote, QStringLiteral( "singleQuoteFontColor" ) },
59 {QgsCodeEditorColorScheme::ColorRole::DoubleQuote, QStringLiteral( "doubleQuoteFontColor" ) },
60 {QgsCodeEditorColorScheme::ColorRole::TripleSingleQuote, QStringLiteral( "tripleSingleQuoteFontColor" ) },
61 {QgsCodeEditorColorScheme::ColorRole::TripleDoubleQuote, QStringLiteral( "tripleDoubleQuoteFontColor" ) },
62 {QgsCodeEditorColorScheme::ColorRole::MarginBackground, QStringLiteral( "marginBackgroundColor" ) },
63 {QgsCodeEditorColorScheme::ColorRole::MarginForeground, QStringLiteral( "marginForegroundColor" ) },
64 {QgsCodeEditorColorScheme::ColorRole::SelectionBackground, QStringLiteral( "selectionBackgroundColor" ) },
65 {QgsCodeEditorColorScheme::ColorRole::SelectionForeground, QStringLiteral( "selectionForegroundColor" ) },
66 {QgsCodeEditorColorScheme::ColorRole::MatchedBraceBackground, QStringLiteral( "matchedBraceBackground" ) },
67 {QgsCodeEditorColorScheme::ColorRole::MatchedBraceForeground, QStringLiteral( "matchedBraceColor" ) },
68 {QgsCodeEditorColorScheme::ColorRole::Edge, QStringLiteral( "edgeColor" ) },
69 {QgsCodeEditorColorScheme::ColorRole::Fold, QStringLiteral( "foldColor" ) },
70 {QgsCodeEditorColorScheme::ColorRole::Error, QStringLiteral( "stderrFontColor" ) },
71 {QgsCodeEditorColorScheme::ColorRole::ErrorBackground, QStringLiteral( "stderrBackgroundColor" ) },
72 {QgsCodeEditorColorScheme::ColorRole::FoldIconForeground, QStringLiteral( "foldIconForeground" ) },
73 {QgsCodeEditorColorScheme::ColorRole::FoldIconHalo, QStringLiteral( "foldIconHalo" ) },
74 {QgsCodeEditorColorScheme::ColorRole::IndentationGuide, QStringLiteral( "indentationGuide" ) },
75};
76
77
78QgsCodeEditor::QgsCodeEditor( QWidget *parent, const QString &title, bool folding, bool margin, QgsCodeEditor::Flags flags, QgsCodeEditor::Mode mode )
79 : QsciScintilla( parent )
80 , mWidgetTitle( title )
81 , mMargin( margin )
82 , mFlags( flags )
83 , mMode( mode )
84{
85 if ( !parent && mWidgetTitle.isEmpty() )
86 {
87 setWindowTitle( QStringLiteral( "Text Editor" ) );
88 }
89 else
90 {
91 setWindowTitle( mWidgetTitle );
92 }
93
94 if ( folding )
96
97 mSoftHistory.append( QString() );
98
99 setSciWidget();
100 setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded );
101
102 SendScintilla( SCI_SETADDITIONALSELECTIONTYPING, 1 );
103 SendScintilla( SCI_SETMULTIPASTE, 1 );
104 SendScintilla( SCI_SETVIRTUALSPACEOPTIONS, SCVS_RECTANGULARSELECTION );
105
106 SendScintilla( SCI_SETMARGINTYPEN, static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), SC_MARGIN_SYMBOL );
107 SendScintilla( SCI_SETMARGINMASKN, static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), 1 << MARKER_NUMBER );
108 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), 0 );
109 setAnnotationDisplay( QsciScintilla::AnnotationBoxed );
110
111 connect( QgsGui::instance(), &QgsGui::optionsChanged, this, [ = ]
112 {
113 setSciWidget();
115 } );
116
117 switch ( mMode )
118 {
120 break;
121
123 {
124 // Don't want to see the horizontal scrollbar at all
125 SendScintilla( QsciScintilla::SCI_SETHSCROLLBAR, 0 );
126
127 setWrapMode( QsciScintilla::WrapCharacter );
128 break;
129 }
130
132 {
133 // Don't want to see the horizontal scrollbar at all
134 SendScintilla( QsciScintilla::SCI_SETHSCROLLBAR, 0 );
135
136 setWrapMode( QsciScintilla::WrapCharacter );
137 SendScintilla( QsciScintilla::SCI_EMPTYUNDOBUFFER );
138 break;
139 }
140 }
141
142#if QSCINTILLA_VERSION < 0x020d03
143 installEventFilter( this );
144#endif
145}
146
147// Workaround a bug in QScintilla 2.8.X
148void QgsCodeEditor::focusOutEvent( QFocusEvent *event )
149{
150#if QSCINTILLA_VERSION >= 0x020800 && QSCINTILLA_VERSION < 0x020900
151 if ( event->reason() != Qt::ActiveWindowFocusReason )
152 {
153 /* There's a bug in all QScintilla 2.8.X, where
154 a focus out event that is not due to ActiveWindowFocusReason doesn't
155 lead to the bliking caret being disabled. The hack consists in making
156 QsciScintilla::focusOutEvent believe that the event is a ActiveWindowFocusReason
157 The bug was fixed in 2.9 per:
158 2015-04-14 Phil Thompson <phil@riverbankcomputing.com>
159
160 * qt/qsciscintillabase.cpp:
161 Fixed a problem notifying when focus is lost to another application
162 widget.
163 [41734678234e]
164 */
165 QFocusEvent newFocusEvent( QEvent::FocusOut, Qt::ActiveWindowFocusReason );
166 QsciScintilla::focusOutEvent( &newFocusEvent );
167 }
168 else
169#endif
170 {
171 QsciScintilla::focusOutEvent( event );
172 }
173}
174
175// This workaround a likely bug in QScintilla. The ESC key should not be consumned
176// by the main entry, so that the default behavior (Dialog closing) can trigger,
177// but only is the auto-completion suggestion list isn't displayed
178void QgsCodeEditor::keyPressEvent( QKeyEvent *event )
179{
180 if ( isListActive() )
181 {
182 QsciScintilla::keyPressEvent( event );
183 return;
184 }
185
186 if ( event->key() == Qt::Key_Escape )
187 {
188 // Shortcut QScintilla and redirect the event to the QWidget handler
189 QWidget::keyPressEvent( event ); // NOLINT(bugprone-parent-virtual-call) clazy:exclude=skipped-base-method
190 return;
191 }
192
194 {
195 switch ( event->key() )
196 {
197 case Qt::Key_Return:
198 case Qt::Key_Enter:
199 runCommand( text() );
200 updatePrompt();
201 return;
202
203 case Qt::Key_Down:
205 updatePrompt();
206 return;
207
208 case Qt::Key_Up:
210 updatePrompt();
211 return;
212
213 default:
214 break;
215 }
216 }
217
218 const bool ctrlModifier = event->modifiers() & Qt::ControlModifier;
219 const bool altModifier = event->modifiers() & Qt::AltModifier;
220
221 // Ctrl+Alt+F: reformat code
223 if ( !isReadOnly() && canReformat && ctrlModifier && altModifier && event->key() == Qt::Key_F )
224 {
225 event->accept();
226 reformatCode();
227 return;
228 }
229
230 // Toggle comment when user presses Ctrl+:
232 if ( !isReadOnly() && canToggle && ctrlModifier && event->key() == Qt::Key_Colon )
233 {
234 event->accept();
236 return;
237 }
238
239 QsciScintilla::keyPressEvent( event );
240
241}
242
243void QgsCodeEditor::contextMenuEvent( QContextMenuEvent *event )
244{
245 switch ( mMode )
246 {
248 {
249 QMenu *menu = createStandardContextMenu();
250 menu->setAttribute( Qt::WA_DeleteOnClose );
251
254 {
255 menu->addSeparator();
256 }
257
259 {
260 QAction *reformatAction = new QAction( tr( "Reformat Code" ), menu );
261 reformatAction->setShortcut( QStringLiteral( "Ctrl+Alt+F" ) );
262 reformatAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "console/iconFormatCode.svg" ) ) );
263 reformatAction->setEnabled( !isReadOnly() );
264 connect( reformatAction, &QAction::triggered, this, &QgsCodeEditor::reformatCode );
265 menu->addAction( reformatAction );
266 }
267
269 {
270 QAction *syntaxCheckAction = new QAction( tr( "Check Syntax" ), menu );
271 syntaxCheckAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "console/iconSyntaxErrorConsole.svg" ) ) );
272 connect( syntaxCheckAction, &QAction::triggered, this, &QgsCodeEditor::checkSyntax );
273 menu->addAction( syntaxCheckAction );
274 }
275
277 {
278 QAction *toggleCommentAction = new QAction( tr( "Toggle Comment" ), menu );
279 toggleCommentAction->setShortcut( QStringLiteral( "Ctrl+:" ) );
280 toggleCommentAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "console/iconCommentEditorConsole.svg" ) ) );
281 toggleCommentAction->setEnabled( !isReadOnly() );
282 connect( toggleCommentAction, &QAction::triggered, this, &QgsCodeEditor::toggleComment );
283 menu->addAction( toggleCommentAction );
284 }
285
286 populateContextMenu( menu );
287
288 menu->exec( mapToGlobal( event->pos() ) );
289 break;
290 }
291
293 {
294 QMenu *menu = new QMenu( this );
295 QMenu *historySubMenu = new QMenu( tr( "Command History" ), menu );
296
297 historySubMenu->addAction( tr( "Show" ), this, &QgsCodeEditor::showHistory, QStringLiteral( "Ctrl+Shift+SPACE" ) );
298 historySubMenu->addAction( tr( "Clear File" ), this, &QgsCodeEditor::clearPersistentHistory );
299 historySubMenu->addAction( tr( "Clear Session" ), this, &QgsCodeEditor::clearSessionHistory );
300
301 menu->addMenu( historySubMenu );
302 menu->addSeparator();
303
304 QAction *copyAction = menu->addAction( QgsApplication::getThemeIcon( "mActionEditCopy.svg" ), tr( "Copy" ), this, &QgsCodeEditor::copy, QKeySequence::Copy );
305 QAction *pasteAction = menu->addAction( QgsApplication::getThemeIcon( "mActionEditPaste.svg" ), tr( "Paste" ), this, &QgsCodeEditor::paste, QKeySequence::Paste );
306 copyAction->setEnabled( hasSelectedText() );
307 pasteAction->setEnabled( !QApplication::clipboard()->text().isEmpty() );
308
309 populateContextMenu( menu );
310
311 menu->exec( mapToGlobal( event->pos() ) );
312 break;
313 }
314
316 QsciScintilla::contextMenuEvent( event );
317 break;
318 }
319}
320
321bool QgsCodeEditor::eventFilter( QObject *watched, QEvent *event )
322{
323#if QSCINTILLA_VERSION < 0x020d03
324 if ( watched == this && event->type() == QEvent::InputMethod )
325 {
326 // swallow input method events, which cause loss of selected text.
327 // See https://sourceforge.net/p/scintilla/bugs/1913/ , which was ported to QScintilla
328 // in version 2.13.3
329 return true;
330 }
331#endif
332
333 return QsciScintilla::eventFilter( watched, event );
334}
335
337{
338
339}
340
342{
343 if ( mUseDefaultSettings )
344 return color( role );
345
346 if ( !mOverrideColors )
347 {
348 return defaultColor( role, mColorScheme );
349 }
350 else
351 {
352 const QColor color = mCustomColors.value( role );
353 return !color.isValid() ? defaultColor( role ) : color;
354 }
355}
356
358{
359 if ( mUseDefaultSettings )
360 return getMonospaceFont();
361
362 QFont font = QFontDatabase::systemFont( QFontDatabase::FixedFont );
363
364 const QgsSettings settings;
365 if ( !mFontFamily.isEmpty() )
366 font.setFamily( mFontFamily );
367
368#ifdef Q_OS_MAC
369 if ( mFontSize > 0 )
370 font.setPointSize( mFontSize );
371 else
372 {
373 // The font size gotten from getMonospaceFont() is too small on Mac
374 font.setPointSize( QLabel().font().pointSize() );
375 }
376#else
377 if ( mFontSize > 0 )
378 font.setPointSize( mFontSize );
379 else
380 {
381 const int fontSize = settings.value( QStringLiteral( "qgis/stylesheet/fontPointSize" ), 10 ).toInt();
382 font.setPointSize( fontSize );
383 }
384#endif
385 font.setBold( false );
386
387 return font;
388}
389
391{
392 updateFolding();
393
396
397 SendScintilla( SCI_MARKERSETFORE, SC_MARKNUM_FOLDEROPEN, lexerColor( QgsCodeEditorColorScheme::ColorRole::FoldIconHalo ) );
398 SendScintilla( SCI_MARKERSETBACK, SC_MARKNUM_FOLDEROPEN, lexerColor( QgsCodeEditorColorScheme::ColorRole::FoldIconForeground ) );
399 SendScintilla( SCI_MARKERSETFORE, SC_MARKNUM_FOLDER, lexerColor( QgsCodeEditorColorScheme::ColorRole::FoldIconHalo ) );
400 SendScintilla( SCI_MARKERSETBACK, SC_MARKNUM_FOLDER, lexerColor( QgsCodeEditorColorScheme::ColorRole::FoldIconForeground ) );
401 SendScintilla( SCI_STYLESETFORE, STYLE_INDENTGUIDE, lexerColor( QgsCodeEditorColorScheme::ColorRole::IndentationGuide ) );
402 SendScintilla( SCI_STYLESETBACK, STYLE_INDENTGUIDE, lexerColor( QgsCodeEditorColorScheme::ColorRole::IndentationGuide ) );
403
405 {
406 setCaretLineVisible( false );
407 setLineNumbersVisible( false ); // NO linenumbers for the input line
408 // Margin 1 is used for the '>' prompt (console input)
409 setMarginLineNumbers( 1, true );
410 setMarginWidth( 1, "00000" );
411 setMarginType( 1, QsciScintilla::MarginType::TextMarginRightJustified );
412 setMarginsBackgroundColor( color( QgsCodeEditorColorScheme::ColorRole::Background ) );
413 setEdgeMode( QsciScintilla::EdgeNone );
414 }
415}
416
417void QgsCodeEditor::setSciWidget()
418{
419 const QFont font = lexerFont();
420 setFont( font );
421
422 setUtf8( true );
423 setCaretLineVisible( true );
424 setCaretLineBackgroundColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::CaretLine ) );
425 setCaretForegroundColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Cursor ) );
428
429 setBraceMatching( QsciScintilla::SloppyBraceMatch );
432
433 setLineNumbersVisible( false );
434
435 // temporarily disable folding, will be enabled later if required by updateFolding()
436 setFolding( QsciScintilla::NoFoldStyle );
437 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::FoldingControls ), 0 );
438
439 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), 0 );
440
443 setIndentationGuidesForegroundColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::MarginForeground ) );
444 setIndentationGuidesBackgroundColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::MarginBackground ) );
445 // whether margin will be shown
446 updateFolding();
447 const QColor foldColor = lexerColor( QgsCodeEditorColorScheme::ColorRole::Fold );
448 setFoldMarginColors( foldColor, foldColor );
449 // indentation
450 setAutoIndent( true );
451 setIndentationWidth( 4 );
452 setTabIndents( true );
453 setBackspaceUnindents( true );
454 setTabWidth( 4 );
455 // autocomplete
456 setAutoCompletionThreshold( 2 );
457 setAutoCompletionSource( QsciScintilla::AcsAPIs );
458
459 markerDefine( QgsApplication::getThemePixmap( "console/iconSyntaxErrorConsoleParams.svg", lexerColor( QgsCodeEditorColorScheme::ColorRole::Error ),
461}
462
463void QgsCodeEditor::setTitle( const QString &title )
464{
465 setWindowTitle( title );
466}
467
469{
471}
472
473Qgis::ScriptLanguageCapabilities QgsCodeEditor::languageCapabilities() const
474{
475 return Qgis::ScriptLanguageCapabilities();
476}
477
479{
480 switch ( language )
481 {
483 return tr( "CSS" );
485 return tr( "Expression" );
487 return tr( "HTML" );
489 return tr( "JavaScript" );
491 return tr( "JSON" );
493 return tr( "Python" );
495 return tr( "R" );
497 return tr( "SQL" );
499 return tr( "Batch" );
501 return tr( "Bash" );
503 return QString();
504 }
506}
507
509{
510 mMargin = margin;
511 if ( margin )
512 {
513 QFont marginFont = lexerFont();
514 marginFont.setPointSize( 10 );
515 setMarginLineNumbers( 0, true );
516 setMarginsFont( marginFont );
517 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ), QStringLiteral( "00000" ) );
520 }
521 else
522 {
523 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ), 0 );
524 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), 0 );
525 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::FoldingControls ), 0 );
526 }
527}
528
530{
531 if ( visible )
532 {
533 QFont marginFont = lexerFont();
534 marginFont.setPointSize( 10 );
535 setMarginLineNumbers( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ), true );
536 setMarginsFont( marginFont );
537 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ), QStringLiteral( "00000" ) );
540 }
541 else
542 {
543 setMarginLineNumbers( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ), false );
544 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ), 0 );
545 }
546}
547
549{
550 return marginLineNumbers( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ) );
551}
552
554{
555 if ( folding )
556 {
558 }
559 else
560 {
561 mFlags &= ~( static_cast< int >( QgsCodeEditor::Flag::CodeFolding ) );
562 }
563 updateFolding();
564}
565
567{
568 return mFlags & QgsCodeEditor::Flag::CodeFolding;
569}
570
571void QgsCodeEditor::updateFolding()
572{
574 {
575 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::FoldingControls ), "0" );
578 setFolding( QsciScintilla::PlainFoldStyle );
579 }
580 else
581 {
582 setFolding( QsciScintilla::NoFoldStyle );
583 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::FoldingControls ), 0 );
584 }
585}
586
587bool QgsCodeEditor::readHistoryFile()
588{
589 if ( mHistoryFilePath.isEmpty() || !QFile::exists( mHistoryFilePath ) )
590 return false;
591
592 QFile file( mHistoryFilePath );
593 if ( file.open( QIODevice::ReadOnly ) )
594 {
595 QTextStream stream( &file );
596#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
597 // Always use UTF-8
598 stream.setCodec( "UTF-8" );
599#endif
600 QString line;
601 while ( !stream.atEnd() )
602 {
603 line = stream.readLine(); // line of text excluding '\n'
604 mHistory.append( line );
605 }
606 syncSoftHistory();
607 return true;
608 }
609
610 return false;
611}
612
613void QgsCodeEditor::syncSoftHistory()
614{
615 mSoftHistory = mHistory;
616 mSoftHistory.append( QString() );
617 mSoftHistoryIndex = mSoftHistory.length() - 1;
618}
619
621{
622 mSoftHistory[mSoftHistoryIndex] = text();
623}
624
625void QgsCodeEditor::updateHistory( const QStringList &commands, bool skipSoftHistory )
626{
627 if ( commands.size() > 1 )
628 {
629 mHistory.append( commands );
630 }
631 else if ( !commands.value( 0 ).isEmpty() )
632 {
633 const QString command = commands.value( 0 );
634 if ( mHistory.empty() || command != mHistory.constLast() )
635 mHistory.append( command );
636 }
637
638 if ( !skipSoftHistory )
639 syncSoftHistory();
640}
641
643{
644
645}
646
647QString QgsCodeEditor::reformatCodeString( const QString &string )
648{
649 return string;
650}
651
652void QgsCodeEditor::showMessage( const QString &title, const QString &message, Qgis::MessageLevel level )
653{
654 switch ( level )
655 {
656 case Qgis::Info:
657 case Qgis::Success:
658 case Qgis::NoLevel:
659 QMessageBox::information( this, title, message );
660 break;
661
662 case Qgis::Warning:
663 QMessageBox::warning( this, title, message );
664 break;
665
666 case Qgis::Critical:
667 QMessageBox::critical( this, title, message );
668 break;
669 }
670}
671
673{
674 if ( mInterpreter )
675 {
676 const QString prompt = mInterpreter->promptForState( mInterpreter->currentState() );
677 SendScintilla( QsciScintilla::SCI_MARGINSETTEXT, static_cast< uintptr_t >( 0 ), prompt.toUtf8().constData() );
678 }
679}
680
682{
683 return mInterpreter;
684}
685
687{
688 mInterpreter = newInterpreter;
689 updatePrompt();
690}
691
692// Find the source substring index that most closely matches the target string
693int findMinimalDistanceIndex( const QString &source, const QString &target )
694{
695 const int index = std::min( source.length(), target.length() );
696
697 const int d0 = QgsStringUtils::levenshteinDistance( source.left( index ), target );
698 if ( d0 == 0 )
699 return index;
700
701 int refDistanceMore = d0;
702 int refIndexMore = index;
703 if ( index < source.length() - 1 )
704 {
705 while ( true )
706 {
707 const int newDistance = QgsStringUtils::levenshteinDistance( source.left( refIndexMore + 1 ), target );
708 if ( newDistance <= refDistanceMore )
709 {
710 refDistanceMore = newDistance;
711 refIndexMore++;
712 if ( refIndexMore == source.length() - 1 )
713 break;
714 }
715 else
716 {
717 break;
718 }
719 }
720 }
721
722 int refDistanceLess = d0;
723 int refIndexLess = index;
724 if ( index > 0 )
725 {
726 while ( true )
727 {
728 const int newDistance = QgsStringUtils::levenshteinDistance( source.left( refIndexLess - 1 ), target );
729 if ( newDistance <= refDistanceLess )
730 {
731 refDistanceLess = newDistance;
732 refIndexLess--;
733 if ( refIndexLess == 0 )
734 break;
735 }
736 else
737 {
738 break;
739 }
740 }
741 }
742
743 if ( refDistanceMore < refDistanceLess )
744 return refIndexMore;
745 else
746 return refIndexLess;
747}
748
750{
752 return;
753
754 int line = 0;
755 int index = 0;
756 getCursorPosition( &line, &index );
757 const QString textBeforeCursor = text( 0, positionFromLineIndex( line, index ) );
758
759 const QString originalText = text();
760
761 const QString newText = reformatCodeString( originalText );
762
763 if ( originalText == newText )
764 return;
765
766 // try to preserve the cursor position and scroll position
767 const int oldScrollValue = verticalScrollBar()->value();
768 const int linearPosition = findMinimalDistanceIndex( newText, textBeforeCursor );
769
770 beginUndoAction();
771 selectAll();
772 removeSelectedText();
773 insert( newText );
774 lineIndexFromPosition( linearPosition, &line, &index );
775 setCursorPosition( line, index );
776 verticalScrollBar()->setValue( oldScrollValue );
777 endUndoAction();
778}
779
781{
782 return true;
783}
784
786{
787
788}
789
790QStringList QgsCodeEditor::history() const
791{
792 return mHistory;
793}
794
795void QgsCodeEditor::runCommand( const QString &command, bool skipHistory )
796{
797 if ( !skipHistory )
798 {
799 updateHistory( { command } );
802 }
803
804 if ( mInterpreter )
805 mInterpreter->exec( command );
806
807 clear();
809}
810
812{
813 mHistory.clear();
814 readHistoryFile();
815 syncSoftHistory();
816
818}
819
821{
822 mHistory.clear();
823
824 if ( !mHistoryFilePath.isEmpty() && QFile::exists( mHistoryFilePath ) )
825 {
826 QFile file( mHistoryFilePath );
827 file.open( QFile::WriteOnly | QFile::Truncate );
828 }
829
831}
832
834{
835 if ( mHistoryFilePath.isEmpty() )
836 return false;
837
838 QFile f( mHistoryFilePath );
839 if ( !f.open( QFile::WriteOnly | QIODevice::Truncate ) )
840 {
841 return false;
842 }
843
844 QTextStream ts( &f );
845#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
846 ts.setCodec( "UTF-8" );
847#endif
848 for ( const QString &command : std::as_const( mHistory ) )
849 {
850 ts << command + '\n';
851 }
852 return true;
853}
854
856{
857 if ( mSoftHistoryIndex < mSoftHistory.length() - 1 && !mSoftHistory.isEmpty() )
858 {
859 mSoftHistoryIndex += 1;
860 setText( mSoftHistory[mSoftHistoryIndex] );
862 }
863}
864
866{
867 if ( mSoftHistoryIndex > 0 && !mSoftHistory.empty() )
868 {
869 mSoftHistoryIndex -= 1;
870 setText( mSoftHistory[mSoftHistoryIndex] );
872 }
873}
874
876{
877 QgsCodeEditorHistoryDialog *dialog = new QgsCodeEditorHistoryDialog( this, this );
878 dialog->setAttribute( Qt::WA_DeleteOnClose );
879
880 dialog->show();
881 dialog->activateWindow();
882}
883
885{
886 // remove item from the command history (just for the current session)
887 mHistory.removeAt( index );
888 mSoftHistory.removeAt( index );
889 if ( index < mSoftHistoryIndex )
890 {
891 mSoftHistoryIndex -= 1;
892 if ( mSoftHistoryIndex < 0 )
893 mSoftHistoryIndex = mSoftHistory.length() - 1;
894 }
895}
896
897void QgsCodeEditor::insertText( const QString &text )
898{
899 // Insert the text or replace selected text
900 if ( hasSelectedText() )
901 {
902 replaceSelectedText( text );
903 }
904 else
905 {
906 int line, index;
907 getCursorPosition( &line, &index );
908 insertAt( text, line, index );
909 setCursorPosition( line, index + text.length() );
910 }
911}
912
914{
915 if ( theme.isEmpty() && QgsApplication::themeName() == QLatin1String( "default" ) )
916 {
917 // if using default theme, take certain colors from the palette
918 const QPalette pal = qApp->palette();
919
920 switch ( role )
921 {
923 return pal.color( QPalette::Highlight );
925 return pal.color( QPalette::HighlightedText );
926 default:
927 break;
928 }
929 }
930 else if ( theme.isEmpty() )
931 {
932 // non default theme (e.g. Blend of Gray). Take colors from theme ini file...
933 const QSettings ini( QgsApplication::uiThemes().value( QgsApplication::themeName() ) + "/qscintilla.ini", QSettings::IniFormat );
934
935 static const QMap< QgsCodeEditorColorScheme::ColorRole, QString > sColorRoleToIniKey
936 {
937 {QgsCodeEditorColorScheme::ColorRole::Default, QStringLiteral( "python/defaultFontColor" ) },
938 {QgsCodeEditorColorScheme::ColorRole::Keyword, QStringLiteral( "python/keywordFontColor" ) },
939 {QgsCodeEditorColorScheme::ColorRole::Class, QStringLiteral( "python/classFontColor" ) },
940 {QgsCodeEditorColorScheme::ColorRole::Method, QStringLiteral( "python/methodFontColor" ) },
941 {QgsCodeEditorColorScheme::ColorRole::Decoration, QStringLiteral( "python/decoratorFontColor" ) },
942 {QgsCodeEditorColorScheme::ColorRole::Number, QStringLiteral( "python/numberFontColor" ) },
943 {QgsCodeEditorColorScheme::ColorRole::Comment, QStringLiteral( "python/commentFontColor" ) },
944 {QgsCodeEditorColorScheme::ColorRole::CommentLine, QStringLiteral( "sql/commentLineFontColor" ) },
945 {QgsCodeEditorColorScheme::ColorRole::CommentBlock, QStringLiteral( "python/commentBlockFontColor" ) },
946 {QgsCodeEditorColorScheme::ColorRole::Background, QStringLiteral( "python/paperBackgroundColor" ) },
947 {QgsCodeEditorColorScheme::ColorRole::Cursor, QStringLiteral( "cursorColor" ) },
948 {QgsCodeEditorColorScheme::ColorRole::CaretLine, QStringLiteral( "caretLineColor" ) },
949 {QgsCodeEditorColorScheme::ColorRole::Operator, QStringLiteral( "sql/operatorFontColor" ) },
950 {QgsCodeEditorColorScheme::ColorRole::QuotedOperator, QStringLiteral( "sql/QuotedOperatorFontColor" ) },
951 {QgsCodeEditorColorScheme::ColorRole::Identifier, QStringLiteral( "sql/identifierFontColor" ) },
952 {QgsCodeEditorColorScheme::ColorRole::QuotedIdentifier, QStringLiteral( "sql/QuotedIdentifierFontColor" ) },
953 {QgsCodeEditorColorScheme::ColorRole::Tag, QStringLiteral( "html/tagFontColor" ) },
954 {QgsCodeEditorColorScheme::ColorRole::UnknownTag, QStringLiteral( "html/unknownTagFontColor" ) },
955 {QgsCodeEditorColorScheme::ColorRole::SingleQuote, QStringLiteral( "sql/singleQuoteFontColor" ) },
956 {QgsCodeEditorColorScheme::ColorRole::DoubleQuote, QStringLiteral( "sql/doubleQuoteFontColor" ) },
957 {QgsCodeEditorColorScheme::ColorRole::TripleSingleQuote, QStringLiteral( "python/tripleSingleQuoteFontColor" ) },
958 {QgsCodeEditorColorScheme::ColorRole::TripleDoubleQuote, QStringLiteral( "python/tripleDoubleQuoteFontColor" ) },
959 {QgsCodeEditorColorScheme::ColorRole::MarginBackground, QStringLiteral( "marginBackgroundColor" ) },
960 {QgsCodeEditorColorScheme::ColorRole::MarginForeground, QStringLiteral( "marginForegroundColor" ) },
961 {QgsCodeEditorColorScheme::ColorRole::SelectionBackground, QStringLiteral( "selectionBackgroundColor" ) },
962 {QgsCodeEditorColorScheme::ColorRole::SelectionForeground, QStringLiteral( "selectionForegroundColor" ) },
963 {QgsCodeEditorColorScheme::ColorRole::MatchedBraceBackground, QStringLiteral( "matchedBraceBackground" ) },
964 {QgsCodeEditorColorScheme::ColorRole::MatchedBraceForeground, QStringLiteral( "matchedBraceColor" ) },
965 {QgsCodeEditorColorScheme::ColorRole::Edge, QStringLiteral( "edgeColor" ) },
966 {QgsCodeEditorColorScheme::ColorRole::Fold, QStringLiteral( "foldColor" ) },
967 {QgsCodeEditorColorScheme::ColorRole::Error, QStringLiteral( "stderrFontColor" ) },
968 {QgsCodeEditorColorScheme::ColorRole::ErrorBackground, QStringLiteral( "stderrBackground" ) },
969 {QgsCodeEditorColorScheme::ColorRole::FoldIconForeground, QStringLiteral( "foldIconForeground" ) },
970 {QgsCodeEditorColorScheme::ColorRole::FoldIconHalo, QStringLiteral( "foldIconHalo" ) },
971 {QgsCodeEditorColorScheme::ColorRole::IndentationGuide, QStringLiteral( "indentationGuide" ) },
972 };
973
974 const QgsCodeEditorColorScheme defaultScheme = QgsGui::codeEditorColorSchemeRegistry()->scheme( QStringLiteral( "default" ) );
975 return QgsSymbolLayerUtils::decodeColor( ini.value( sColorRoleToIniKey.value( role ), defaultScheme.color( role ).name() ).toString() );
976 }
977
978 const QgsCodeEditorColorScheme scheme = QgsGui::codeEditorColorSchemeRegistry()->scheme( theme.isEmpty() ? QStringLiteral( "default" ) : theme );
979 return scheme.color( role );
980}
981
983{
984 const QgsSettings settings;
985 if ( !settings.value( QStringLiteral( "codeEditor/overrideColors" ), false, QgsSettings::Gui ).toBool() )
986 {
987 const QString theme = settings.value( QStringLiteral( "codeEditor/colorScheme" ), QString(), QgsSettings::Gui ).toString();
988 return defaultColor( role, theme );
989 }
990 else
991 {
992 const QString color = settings.value( QStringLiteral( "codeEditor/%1" ).arg( sColorRoleToSettingsKey.value( role ) ), QString(), QgsSettings::Gui ).toString();
993 return color.isEmpty() ? defaultColor( role ) : QgsSymbolLayerUtils::decodeColor( color );
994 }
995}
996
998{
999 QgsSettings settings;
1000 if ( color.isValid() )
1001 {
1002 settings.setValue( QStringLiteral( "codeEditor/%1" ).arg( sColorRoleToSettingsKey.value( role ) ), color.name(), QgsSettings::Gui );
1003 }
1004 else
1005 {
1006 settings.remove( QStringLiteral( "codeEditor/%1" ).arg( sColorRoleToSettingsKey.value( role ) ), QgsSettings::Gui );
1007 }
1008}
1009
1010// Settings for font and fontsize
1011bool QgsCodeEditor::isFixedPitch( const QFont &font )
1012{
1013 return font.fixedPitch();
1014}
1015
1017{
1018 QFont font = QFontDatabase::systemFont( QFontDatabase::FixedFont );
1019
1020 const QgsSettings settings;
1021 if ( !settings.value( QStringLiteral( "codeEditor/fontfamily" ), QString(), QgsSettings::Gui ).toString().isEmpty() )
1022 font.setFamily( settings.value( QStringLiteral( "codeEditor/fontfamily" ), QString(), QgsSettings::Gui ).toString() );
1023
1024 const int fontSize = settings.value( QStringLiteral( "codeEditor/fontsize" ), 0, QgsSettings::Gui ).toInt();
1025
1026#ifdef Q_OS_MAC
1027 if ( fontSize > 0 )
1028 font.setPointSize( fontSize );
1029 else
1030 {
1031 // The font size gotten from getMonospaceFont() is too small on Mac
1032 font.setPointSize( QLabel().font().pointSize() );
1033 }
1034#else
1035 if ( fontSize > 0 )
1036 font.setPointSize( fontSize );
1037 else
1038 {
1039 const int fontSize = settings.value( QStringLiteral( "qgis/stylesheet/fontPointSize" ), 10 ).toInt();
1040 font.setPointSize( fontSize );
1041 }
1042#endif
1043 font.setBold( false );
1044
1045 return font;
1046}
1047
1048void QgsCodeEditor::setCustomAppearance( const QString &scheme, const QMap<QgsCodeEditorColorScheme::ColorRole, QColor> &customColors, const QString &fontFamily, int fontSize )
1049{
1050 mUseDefaultSettings = false;
1051 mOverrideColors = !customColors.isEmpty();
1052 mColorScheme = scheme;
1053 mCustomColors = customColors;
1054 mFontFamily = fontFamily;
1055 mFontSize = fontSize;
1056
1057 setSciWidget();
1059}
1060
1061void QgsCodeEditor::addWarning( const int lineNumber, const QString &warning )
1062{
1063 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), "000" );
1064 markerAdd( lineNumber, MARKER_NUMBER );
1065 QFont font = lexerFont();
1066 font.setItalic( true );
1067 const QsciStyle styleAnn = QsciStyle( -1, QStringLiteral( "Annotation" ),
1070 font,
1071 true );
1072 annotate( lineNumber, warning, styleAnn );
1073 mWarningLines.push_back( lineNumber );
1074}
1075
1077{
1078 for ( const int line : mWarningLines )
1079 {
1080 markerDelete( line );
1081 clearAnnotations( line );
1082 }
1083 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), 0 );
1084 mWarningLines.clear();
1085}
1086
1088{
1089 int line = 0;
1090 int index = 0;
1091 getCursorPosition( &line, &index );
1092 return line == lines() - 1;
1093}
1094
1095void QgsCodeEditor::setHistoryFilePath( const QString &path )
1096{
1097 mHistoryFilePath = path;
1098 readHistoryFile();
1099}
1100
1102{
1103 setCursorPosition( 0, 0 );
1104 ensureCursorVisible();
1105 ensureLineVisible( 0 );
1106
1107 if ( mMode == QgsCodeEditor::Mode::CommandInput )
1108 updatePrompt();
1109}
1110
1112{
1113 const int endLine = lines() - 1;
1114 const int endLineLength = lineLength( endLine );
1115 setCursorPosition( endLine, endLineLength );
1116 ensureCursorVisible();
1117 ensureLineVisible( endLine );
1118
1119 if ( mMode == QgsCodeEditor::Mode::CommandInput )
1120 updatePrompt();
1121}
1122
1124
1125int QgsCodeInterpreter::exec( const QString &command )
1126{
1127 mState = execCommandImpl( command );
1128 return mState;
1129}
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition: qgis.h:99
@ NoLevel
No level.
Definition: qgis.h:104
@ Warning
Warning message.
Definition: qgis.h:101
@ Critical
Critical/error message.
Definition: qgis.h:102
@ Info
Information message.
Definition: qgis.h:100
@ Success
Used for reporting a successful operation.
Definition: qgis.h:103
@ CheckSyntax
Language supports syntax checking.
@ Reformat
Language supports automatic code reformatting.
@ ToggleComment
Language supports comment toggling.
ScriptLanguage
Scripting languages.
Definition: qgis.h:2920
@ QgisExpression
QGIS expressions.
@ Batch
Windows batch files.
@ JavaScript
JavaScript.
@ Bash
Bash scripts.
@ Unknown
Unknown/other language.
static QPixmap getThemePixmap(const QString &name, const QColor &foreColor=QColor(), const QColor &backColor=QColor(), int size=16)
Helper to get a theme icon as a pixmap.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QHash< QString, QString > uiThemes()
All themes found in ~/.qgis3/themes folder.
static QString themeName()
Set the active theme to the specified theme.
QgsCodeEditorColorScheme scheme(const QString &id) const
Returns the color scheme with matching id.
Defines a color scheme for use in QgsCodeEditor widgets.
@ TripleSingleQuote
Triple single quote color.
@ CommentBlock
Comment block color.
@ QuotedOperator
Quoted operator color.
@ DoubleQuote
Double quote color.
@ QuotedIdentifier
Quoted identifier color.
@ SelectionForeground
Selection foreground color.
@ CommentLine
Line comment color.
@ FoldIconForeground
Fold icon foreground color.
@ MarginForeground
Margin foreground color.
@ ErrorBackground
Error background color.
@ MatchedBraceBackground
Matched brace background color.
@ IndentationGuide
Indentation guide line.
@ SingleQuote
Single quote color.
@ MarginBackground
Margin background color.
@ SelectionBackground
Selection background color.
@ MatchedBraceForeground
Matched brace foreground color.
@ TripleDoubleQuote
Triple double quote color.
@ FoldIconHalo
Fold icon halo color.
QColor color(ColorRole role) const
Returns the color to use in the editor for the specified role.
A dialog for displaying and managing command history for a QgsCodeEditor widget.
bool eventFilter(QObject *watched, QEvent *event) override
void sessionHistoryCleared()
Emitted when the history of commands run in the current session is cleared.
void showHistory()
Shows the command history dialog.
void setCustomAppearance(const QString &scheme=QString(), const QMap< QgsCodeEditorColorScheme::ColorRole, QColor > &customColors=QMap< QgsCodeEditorColorScheme::ColorRole, QColor >(), const QString &fontFamily=QString(), int fontSize=0)
Sets a custom appearance for the widget, disconnecting it from using the standard appearance taken fr...
Mode
Code editor modes.
@ OutputDisplay
Read only mode for display of command outputs.
@ ScriptEditor
Standard mode, allows for display and edit of entire scripts.
@ CommandInput
Command input mode.
void reformatCode()
Applies code reformatting to the editor.
virtual void toggleComment()
Toggle comment for the selected text.
void contextMenuEvent(QContextMenuEvent *event) override
void clearPersistentHistory()
Clears the entire persistent history of commands run in the editor.
void removeHistoryCommand(int index)
Removes the command at the specified index from the history of the code editor.
static void setColor(QgsCodeEditorColorScheme::ColorRole role, const QColor &color)
Sets the color to use in the editor for the specified role.
void setHistoryFilePath(const QString &path)
Sets the file path to use for recording and retrieving previously executed commands.
QStringList history() const
Returns the list of commands previously executed in the editor.
void keyPressEvent(QKeyEvent *event) override
virtual void moveCursorToStart()
Moves the cursor to the start of the document and scrolls to ensure it is visible.
virtual void populateContextMenu(QMenu *menu)
Called when the context menu for the widget is about to be shown, after it has been fully populated w...
void persistentHistoryCleared()
Emitted when the persistent history of commands run in the editor is cleared.
void runCommand(const QString &command, bool skipHistory=false)
Runs a command in the editor.
void setFoldingVisible(bool folding)
Set whether the folding controls are visible in the editor.
virtual Qgis::ScriptLanguageCapabilities languageCapabilities() const
Returns the associated scripting language capabilities.
void setInterpreter(QgsCodeInterpreter *newInterpreter)
Sets an attached code interpreter for executing commands when the editor is in the QgsCodeEditor::Mod...
@ FoldingControls
Folding controls.
@ ErrorIndicators
Error indicators.
@ LineNumbers
Line numbers.
void runPostLexerConfigurationTasks()
Performs tasks which must be run after a lexer has been set for the widget.
virtual void showMessage(const QString &title, const QString &message, Qgis::MessageLevel level)
Shows a user facing message (eg a warning message).
virtual void initializeLexer()
Called when the dialect specific code lexer needs to be initialized (or reinitialized).
void setTitle(const QString &title)
Set the widget title.
QgsCodeEditor(QWidget *parent=nullptr, const QString &title=QString(), bool folding=false, bool margin=false, QgsCodeEditor::Flags flags=QgsCodeEditor::Flags(), QgsCodeEditor::Mode mode=QgsCodeEditor::Mode::ScriptEditor)
Flags controlling behavior of code editor.
void clearWarnings()
Clears all warning messages from the editor.
static QFont getMonospaceFont()
Returns the monospaced font to use for code editors.
void showNextCommand()
Shows the next command from the session in the editor.
void focusOutEvent(QFocusEvent *event) override
@ CodeFolding
Indicates that code folding should be enabled for the editor.
@ ImmediatelyUpdateHistory
Indicates that the history file should be immediately updated whenever a command is executed,...
bool isCursorOnLastLine() const
Returns true if the cursor is on the last line of the document.
static bool isFixedPitch(const QFont &font)
Returns true if a font is a fixed pitch font.
void updateSoftHistory()
Updates the soft history by storing the current editor text in the history.
void clearSessionHistory()
Clears the history of commands run in the current session.
void insertText(const QString &text)
Insert text at cursor position, or replace any selected text if user has made a selection.
bool writeHistoryFile()
Stores the commands executed in the editor to the persistent history file.
virtual void moveCursorToEnd()
Moves the cursor to the end of the document and scrolls to ensure it is visible.
static QString languageToString(Qgis::ScriptLanguage language)
Returns a user-friendly, translated name of the specified script language.
void setLineNumbersVisible(bool visible)
Sets whether line numbers should be visible in the editor.
virtual Qgis::ScriptLanguage language() const
Returns the associated scripting language.
QFont lexerFont() const
Returns the font to use in the lexer.
virtual QString reformatCodeString(const QString &string)
Applies code reformatting to a string and returns the result.
QgsCodeInterpreter * interpreter() const
Returns the attached code interpreter, or nullptr if not set.
bool lineNumbersVisible() const
Returns whether line numbers are visible in the editor.
QColor lexerColor(QgsCodeEditorColorScheme::ColorRole role) const
Returns the color to use in the lexer for the specified role.
bool foldingVisible()
Returns true if the folding controls are visible in the editor.
void showPreviousCommand()
Shows the previous command from the session in the editor.
Q_DECL_DEPRECATED void setMarginVisible(bool margin)
Set margin visible state.
void updatePrompt()
Triggers an update of the interactive prompt part of the editor.
static QColor defaultColor(QgsCodeEditorColorScheme::ColorRole role, const QString &theme=QString())
Returns the default color for the specified role.
void addWarning(int lineNumber, const QString &warning)
Adds a warning message and indicator to the specified a lineNumber.
virtual bool checkSyntax()
Applies syntax checking to the editor.
static QColor color(QgsCodeEditorColorScheme::ColorRole role)
Returns the color to use in the editor for the specified role.
An interface for code interpreters.
Definition: qgscodeeditor.h:41
virtual int execCommandImpl(const QString &command)=0
Pure virtual method for executing commands in the interpreter.
virtual int currentState() const
Returns the current interpreter state.
Definition: qgscodeeditor.h:59
virtual QString promptForState(int state) const =0
Returns the interactive prompt string to use for the interpreter, given a state.
int exec(const QString &command)
Executes a command in the interpreter.
virtual ~QgsCodeInterpreter()
void optionsChanged()
This signal is emitted whenever the application options have been changed.
static QgsGui * instance()
Returns a pointer to the singleton instance.
Definition: qgsgui.cpp:72
static QgsCodeEditorColorSchemeRegistry * codeEditorColorSchemeRegistry()
Returns the global code editor color scheme registry, used for registering the color schemes for QgsC...
Definition: qgsgui.cpp:153
This class is a composition of two QSettings instances:
Definition: qgssettings.h:63
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void remove(const QString &key, QgsSettings::Section section=QgsSettings::NoSection)
Removes the setting key and any sub-settings of key in a section.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static int levenshteinDistance(const QString &string1, const QString &string2, bool caseSensitive=false)
Returns the Levenshtein edit distance between two strings.
static QColor decodeColor(const QString &str)
#define BUILTIN_UNREACHABLE
Definition: qgis.h:4659
int findMinimalDistanceIndex(const QString &source, const QString &target)