QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgscodeeditorhtml.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgscodeeditorhtml.cpp - A HTML editor based on QScintilla
3 --------------------------------------
4 Date : 20-Jul-2014
5 Copyright : (C) 2014 by Nathan Woodrow
6 Email : woodrow.nathan (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 "qgscodeeditorhtml.h"
17#include "qgspythonrunner.h"
18#include "qgsprocessingutils.h"
19
20#include <QWidget>
21#include <QString>
22#include <QFont>
23#include <Qsci/qscilexerhtml.h>
24
25
27 : QgsCodeEditor( parent,
28 QString(),
29 false,
30 false,
31 QgsCodeEditor::Flag::CodeFolding )
32{
33 if ( !parent )
34 {
35 setTitle( tr( "HTML Editor" ) );
36 }
38
41 {
42 // we could potentially check for beautifulsoup4 import here and reflect the capability accordingly.
43 // (current approach is to to always indicate this capability and raise a user-friendly warning
44 // when attempting to reformat if the libraries can't be imported)
46 }
47}
48
50{
52}
53
55{
56 return mCapabilities;
57}
58
60{
61 QFont font = lexerFont();
63
64 QsciLexerHTML *lexer = new QsciLexerHTML( this );
65 lexer->setDefaultFont( font );
66 lexer->setDefaultColor( defaultColor );
68 lexer->setFont( font, -1 );
69
70 font.setItalic( true );
71 lexer->setFont( font, QsciLexerHTML::HTMLComment );
72 lexer->setFont( font, QsciLexerHTML::JavaScriptComment );
73 lexer->setFont( font, QsciLexerHTML::JavaScriptCommentLine );
74
75 lexer->setColor( defaultColor, QsciLexerHTML::Default );
76 lexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Tag ), QsciLexerHTML::Tag );
77 lexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::UnknownTag ), QsciLexerHTML::UnknownTag );
78 lexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Method ), QsciLexerHTML::Attribute );
79 lexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Method ), QsciLexerHTML::UnknownAttribute );
80 lexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Class ), QsciLexerHTML::Entity );
81 lexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Number ), QsciLexerHTML::HTMLNumber );
82 lexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Comment ), QsciLexerHTML::HTMLComment );
83 lexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Comment ), QsciLexerHTML::JavaScriptComment );
84 lexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::CommentLine ), QsciLexerHTML::JavaScriptCommentLine );
85 lexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Number ), QsciLexerHTML::JavaScriptNumber );
86 lexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Keyword ), QsciLexerHTML::JavaScriptKeyword );
87 lexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::DoubleQuote ), QsciLexerHTML::JavaScriptDoubleQuotedString );
88 lexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::SingleQuote ), QsciLexerHTML::JavaScriptSingleQuotedString );
89 lexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::SingleQuote ), QsciLexerHTML::HTMLSingleQuotedString );
90 lexer->setColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::DoubleQuote ), QsciLexerHTML::HTMLDoubleQuotedString );
91
92 setLexer( lexer );
94}
95
96QString QgsCodeEditorHTML::reformatCodeString( const QString &string )
97{
99 {
100 return string;
101 }
102 QString newText = string;
103
104 const QString definePrettify = QStringLiteral(
105 "def __qgis_prettify(text):\n"
106 " try:\n"
107 " from bs4 import BeautifulSoup\n"
108 " return BeautifulSoup(text, 'html.parser').prettify()\n"
109 " except ImportError:\n"
110 " try:\n"
111 " import re\n"
112 " from lxml import etree, html\n"
113 " text = re.sub('>\\\\s+<', '><', text)\n"
114 " text = re.sub('\\n\\\\s*', '', text)\n"
115 " document_root = html.fromstring(text)\n"
116 " return etree.tostring(document_root, encoding='utf-8', pretty_print=True).decode('utf-8')\n"
117 " except ImportError:\n"
118 " return '_ImportError'\n" );
119
120
121 if ( !QgsPythonRunner::run( definePrettify ) )
122 {
123 QgsDebugError( QStringLiteral( "Error running script: %1" ).arg( definePrettify ) );
124 return string;
125 }
126
127 const QString script = QStringLiteral( "__qgis_prettify(%1)" ).arg( QgsProcessingUtils::stringToPythonLiteral( newText ) );
128 QString result;
129 if ( QgsPythonRunner::eval( script, result ) )
130 {
131 if ( result == QLatin1String( "_ImportError" ) )
132 {
133 showMessage( tr( "Reformat Code" ), tr( "HTML reformatting requires bs4 or lxml python modules to be installed" ), Qgis::MessageLevel::Warning );
134 }
135 else
136 {
137 newText = result;
138 }
139 }
140 else
141 {
142 QgsDebugError( QStringLiteral( "Error running script: %1" ).arg( script ) );
143 return newText;
144 }
145
146 return newText;
147}
148
150{
151 if ( isReadOnly() )
152 {
153 return;
154 }
155
156 const QString commentStart( "<!--" );
157 const QString commentEnd( "-->" );
158
159 int startLine, startPos, endLine, endPos;
160 if ( hasSelectedText() )
161 {
162 getSelection( &startLine, &startPos, &endLine, &endPos );
163 }
164 else
165 {
166 getCursorPosition( &startLine, &startPos );
167 endLine = startLine;
168 endPos = startPos;
169 }
170
171
172 // Compute first and last non-blank lines
173 while ( text( startLine ).trimmed().isEmpty() )
174 {
175 startLine++;
176 if ( startLine > endLine )
177 {
178 // Only blank lines selected
179 return;
180 }
181 }
182 while ( text( endLine ).trimmed().isEmpty() )
183 {
184 endLine--;
185 }
186
187 // Remove leading spaces from the start line
188 QString startLineTrimmed = text( startLine );
189 startLineTrimmed.remove( QRegularExpression( "^\\s+" ) );
190 // Remove trailing spaces from the end line
191 QString endLineTrimmed = text( endLine );
192 endLineTrimmed.remove( QRegularExpression( "\\s+$" ) );
193
194 const bool commented = startLineTrimmed.startsWith( commentStart ) && endLineTrimmed.endsWith( commentEnd );
195
196 // Special case, selected text is <!--> or <!--->
197 if ( commented && startLine == endLine && text( endLine ).trimmed().size() < commentStart.size() + commentEnd.size() )
198 {
199 return;
200 }
201
202 beginUndoAction();
203
204 // Selection is commented: uncomment it
205 if ( commented )
206 {
207 int c1, c2;
208
209 // Remove trailing comment tag ( --> )
210 c2 = endLineTrimmed.size();
211 if ( endLineTrimmed.endsWith( QStringLiteral( " " ) + commentEnd ) )
212 {
213 c1 = c2 - commentEnd.size() - 1;
214 }
215 else
216 {
217 c1 = c2 - commentEnd.size();
218 }
219
220 setSelection( endLine, c1, endLine, c2 );
221 removeSelectedText();
222
223 // Remove leading comment tag ( <!-- )
224 c1 = indentation( startLine );
225 if ( startLineTrimmed.startsWith( commentStart + QStringLiteral( " " ) ) )
226 {
227 c2 = c1 + commentStart.size() + 1;
228 }
229 else
230 {
231 c2 = c1 + commentStart.size();
232 }
233
234 setSelection( startLine, c1, startLine, c2 );
235 removeSelectedText();
236 }
237 // Selection is not commented: comment it
238 else
239 {
240 insertAt( QStringLiteral( " " ) + commentEnd, endLine, endLineTrimmed.size() );
241 insertAt( commentStart + QStringLiteral( " " ), startLine, indentation( startLine ) );
242 }
243
244 endUndoAction();
245
246 // Restore selection
247 setSelection( startLine, startPos, endLine, endPos );
248}
@ Reformat
Language supports automatic code reformatting.
@ ToggleComment
Language supports comment toggling.
ScriptLanguage
Scripting languages.
Definition: qgis.h:3718
QFlags< ScriptLanguageCapability > ScriptLanguageCapabilities
Script language capabilities.
Definition: qgis.h:3753
@ DoubleQuote
Double quote color.
@ CommentLine
Line comment color.
@ SingleQuote
Single quote color.
Qgis::ScriptLanguage language() const override
Returns the associated scripting language.
Qgis::ScriptLanguageCapabilities languageCapabilities() const override
Returns the associated scripting language capabilities.
void initializeLexer() override
Called when the dialect specific code lexer needs to be initialized (or reinitialized).
QString reformatCodeString(const QString &string) override
Applies code reformatting to a string and returns the result.
QgsCodeEditorHTML(QWidget *parent=nullptr)
Constructor for QgsCodeEditorHTML.
void toggleComment() override
Toggle comment for the selected text.
A text editor based on QScintilla2.
Definition: qgscodeeditor.h:93
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).
void setTitle(const QString &title)
Set the widget title.
Flag
Flags controlling behavior of code 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.
static QString stringToPythonLiteral(const QString &string)
Converts a string to a Python string literal.
static bool run(const QString &command, const QString &messageOnError=QString())
Execute a Python statement.
static bool eval(const QString &command, QString &result)
Eval a Python statement.
static bool isValid()
Returns true if the runner has an instance (and thus is able to run commands)
#define QgsDebugError(str)
Definition: qgslogger.h:38