Skip to content

Commit 3337247

Browse files
authored
XMPP console highighting (#903)
* xmlconsole.ui: add XML highlighting * XMPP Console: make Send XML window bigger * XMPP Console: Don't allow sending broken XML
1 parent 76721df commit 3337247

File tree

8 files changed

+202
-9
lines changed

8 files changed

+202
-9
lines changed

Readme-dev-cmake-en.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ This file contains the CMake files description
101101

102102
./src/avcall/CMakeLists.txt - builds avcall static library
103103

104+
./src/BasicXMLSyntaxHighlighter/BasicXMLSyntaxHighlighter.cmake - class used for XML highlighting in the XMPP Console.
105+
104106
./src/Certificates/CMakeLists.txt - builds Certificates static library
105107

106108
./src/contactmanager/CMakeLists.txt - builds contactmanager static library

Readme-dev-cmake-ru.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@
105105

106106
./src/avcall/CMakeLists.txt - собирает статическую библиотеку avcall
107107

108+
./src/BasicXMLSyntaxHighlighter/BasicXMLSyntaxHighlighter.cmake - класс для подсветки XML в консоли XMPP.
109+
108110
./src/Certificates/CMakeLists.txt - собирает статическую библиотеку Certificates
109111

110112
./src/contactmanager/CMakeLists.txt - собирает статическую библиотеку contactmanager
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
list(APPEND HEADERS
2+
BasicXMLSyntaxHighlighter/BasicXMLSyntaxHighlighter.h
3+
)
4+
5+
list(APPEND SOURCES
6+
BasicXMLSyntaxHighlighter/BasicXMLSyntaxHighlighter.cpp
7+
)
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* The MIT License (MIT)
3+
4+
* Copyright (c) 2015 Dmitry Ivanov
5+
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
#include "BasicXMLSyntaxHighlighter.h"
26+
27+
BasicXMLSyntaxHighlighter::BasicXMLSyntaxHighlighter(QObject * parent) :
28+
QSyntaxHighlighter(parent)
29+
{
30+
setRegexes();
31+
setFormats();
32+
}
33+
34+
BasicXMLSyntaxHighlighter::BasicXMLSyntaxHighlighter(QTextDocument * parent) :
35+
QSyntaxHighlighter(parent)
36+
{
37+
setRegexes();
38+
setFormats();
39+
}
40+
41+
BasicXMLSyntaxHighlighter::BasicXMLSyntaxHighlighter(QTextEdit * parent) :
42+
QSyntaxHighlighter(parent)
43+
{
44+
setRegexes();
45+
setFormats();
46+
}
47+
48+
void BasicXMLSyntaxHighlighter::highlightBlock(const QString & text)
49+
{
50+
// Special treatment for xml element regex as we use captured text to emulate lookbehind
51+
int xmlElementIndex = m_xmlElementRegex.indexIn(text);
52+
while(xmlElementIndex >= 0)
53+
{
54+
int matchedPos = m_xmlElementRegex.pos(1);
55+
int matchedLength = m_xmlElementRegex.cap(1).length();
56+
setFormat(matchedPos, matchedLength, m_xmlElementFormat);
57+
58+
xmlElementIndex = m_xmlElementRegex.indexIn(text, matchedPos + matchedLength);
59+
}
60+
61+
// Highlight xml keywords *after* xml elements to fix any occasional / captured into the enclosing element
62+
typedef QList<QRegExp>::const_iterator Iter;
63+
Iter xmlKeywordRegexesEnd = m_xmlKeywordRegexes.end();
64+
for(Iter it = m_xmlKeywordRegexes.begin(); it != xmlKeywordRegexesEnd; ++it) {
65+
const QRegExp & regex = *it;
66+
highlightByRegex(m_xmlKeywordFormat, regex, text);
67+
}
68+
69+
highlightByRegex(m_xmlAttributeFormat, m_xmlAttributeRegex, text);
70+
highlightByRegex(m_xmlCommentFormat, m_xmlCommentRegex, text);
71+
highlightByRegex(m_xmlValueFormat, m_xmlValueRegex, text);
72+
}
73+
74+
void BasicXMLSyntaxHighlighter::highlightByRegex(const QTextCharFormat & format,
75+
const QRegExp & regex, const QString & text)
76+
{
77+
int index = regex.indexIn(text);
78+
79+
while(index >= 0)
80+
{
81+
int matchedLength = regex.matchedLength();
82+
setFormat(index, matchedLength, format);
83+
84+
index = regex.indexIn(text, index + matchedLength);
85+
}
86+
}
87+
88+
void BasicXMLSyntaxHighlighter::setRegexes()
89+
{
90+
m_xmlElementRegex.setPattern("<[?\\s]*[/]?[\\s]*([^\\n][^>]*)(?=[\\s/>])");
91+
m_xmlAttributeRegex.setPattern("\\w+(?=\\=)");
92+
m_xmlValueRegex.setPattern("\"[^\\n\"]+\"(?=[?\\s/>])");
93+
m_xmlCommentRegex.setPattern("<!--[^\\n]*-->");
94+
95+
m_xmlKeywordRegexes = QList<QRegExp>() << QRegExp("<\\?") << QRegExp("/>")
96+
<< QRegExp(">") << QRegExp("<") << QRegExp("</")
97+
<< QRegExp("\\?>");
98+
}
99+
100+
void BasicXMLSyntaxHighlighter::setFormats()
101+
{
102+
m_xmlKeywordFormat.setForeground(Qt::blue);
103+
m_xmlKeywordFormat.setFontWeight(QFont::Bold);
104+
105+
m_xmlElementFormat.setForeground(Qt::darkMagenta);
106+
m_xmlElementFormat.setFontWeight(QFont::Bold);
107+
108+
m_xmlAttributeFormat.setForeground(Qt::darkGreen);
109+
m_xmlAttributeFormat.setFontWeight(QFont::Bold);
110+
m_xmlAttributeFormat.setFontItalic(true);
111+
112+
m_xmlValueFormat.setForeground(Qt::darkRed);
113+
114+
m_xmlCommentFormat.setForeground(Qt::gray);
115+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* The MIT License (MIT)
3+
4+
* Copyright (c) 2015 Dmitry Ivanov
5+
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
#ifndef BASIC_XML_SYNTAX_HIGHLIGHTER_H
25+
#define BASIC_XML_SYNTAX_HIGHLIGHTER_H
26+
27+
#include <QSyntaxHighlighter>
28+
#include <QTextEdit>
29+
30+
class BasicXMLSyntaxHighlighter : public QSyntaxHighlighter
31+
{
32+
Q_OBJECT
33+
public:
34+
BasicXMLSyntaxHighlighter(QObject * parent);
35+
BasicXMLSyntaxHighlighter(QTextDocument * parent);
36+
BasicXMLSyntaxHighlighter(QTextEdit * parent);
37+
38+
protected:
39+
virtual void highlightBlock(const QString & text);
40+
41+
private:
42+
void highlightByRegex(const QTextCharFormat & format,
43+
const QRegExp & regex, const QString & text);
44+
45+
void setRegexes();
46+
void setFormats();
47+
48+
private:
49+
QTextCharFormat m_xmlKeywordFormat;
50+
QTextCharFormat m_xmlElementFormat;
51+
QTextCharFormat m_xmlAttributeFormat;
52+
QTextCharFormat m_xmlValueFormat;
53+
QTextCharFormat m_xmlCommentFormat;
54+
55+
QList<QRegExp> m_xmlKeywordRegexes;
56+
QRegExp m_xmlElementRegex;
57+
QRegExp m_xmlAttributeRegex;
58+
QRegExp m_xmlValueRegex;
59+
QRegExp m_xmlCommentRegex;
60+
};
61+
62+
#endif // BASIC_XML_SYNTAX_HIGHLIGHTER_H
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# basic-xml-syntax-highlighter
2+
3+
Basix XML syntax highlighter in C++/Qt (subclass of QSyntaxHighlighter)
4+
https://github.com/d1vanov/basic-xml-syntax-highlighter

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ if(EXISTS "${CONFIG_OUTPUT_FILE}")
245245
endif()
246246

247247
# Only headers or very small sources
248+
include(BasicXMLSyntaxHighlighter/BasicXMLSyntaxHighlighter.cmake)
248249
include(irisprotocol/irisprotocol.cmake)
249250
include(protocol/protocol.cmake)
250251
include(${PROJECT_SOURCE_DIR}/plugins/plugins.cmake)

src/xmlconsole.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "xmlconsole.h"
2121

22+
#include "BasicXMLSyntaxHighlighter/BasicXMLSyntaxHighlighter.h"
2223
#include "iconset.h"
2324
#include "iris/xmpp_client.h"
2425
#include "psiaccount.h"
@@ -56,6 +57,8 @@ XmlConsole::XmlConsole(PsiAccount *_pa) : QWidget()
5657
ui_.te->setUndoRedoEnabled(false);
5758
ui_.te->setReadOnly(true);
5859
ui_.te->setAcceptRichText(false);
60+
BasicXMLSyntaxHighlighter *highlighter = new BasicXMLSyntaxHighlighter(ui_.te);
61+
Q_UNUSED(highlighter);
5962

6063
connect(ui_.pb_clear, SIGNAL(clicked()), SLOT(clear()));
6164
connect(ui_.pb_input, SIGNAL(clicked()), SLOT(insertXml()));
@@ -140,7 +143,6 @@ static const QTextFrameFormat frameFormatOutcoming = [] {
140143
return f;
141144
}();
142145

143-
144146
void XmlConsole::addRecord(bool incoming, const QString &str)
145147
{
146148
if (filtered(str))
@@ -152,7 +154,7 @@ void XmlConsole::addRecord(bool incoming, const QString &str)
152154
auto prevCur = textEdit->textCursor();
153155

154156
textEdit->moveCursor(QTextCursor::End);
155-
textEdit->textCursor().insertFrame(incoming ? frameFormatIncoming : frameFormatOutcoming);
157+
textEdit->textCursor().insertFrame(incoming ? frameFormatIncoming : frameFormatOutcoming);
156158
textEdit->insertPlainText(str);
157159

158160
if (!wasAtBottom) {
@@ -194,6 +196,8 @@ XmlPrompt::XmlPrompt(QWidget *parent) : QDialog(parent)
194196
te = new QTextEdit(this);
195197
te->setAcceptRichText(false);
196198
vb1->addWidget(te);
199+
BasicXMLSyntaxHighlighter *highlighter = new BasicXMLSyntaxHighlighter(te);
200+
Q_UNUSED(highlighter);
197201

198202
QHBoxLayout *hb1 = new QHBoxLayout;
199203
vb1->addLayout(hb1);
@@ -209,23 +213,19 @@ XmlPrompt::XmlPrompt(QWidget *parent) : QDialog(parent)
209213
connect(pb, SIGNAL(clicked()), SLOT(close()));
210214
hb1->addWidget(pb);
211215

212-
resize(320, 240);
216+
resize(800, 600);
213217
}
214218

215219
XmlPrompt::~XmlPrompt() { }
216220

217221
void XmlPrompt::doTransmit()
218222
{
219223
QString str = te->toPlainText();
220-
221224
// Validate input
222225
QDomDocument doc;
223226
if (!doc.setContent(str)) {
224-
int i = QMessageBox::warning(this, tr("Malformed XML"),
225-
tr("You have entered malformed XML input. Are you sure you want to send this ?"),
226-
QMessageBox::Yes | QMessageBox::No);
227-
if (i != 0)
228-
return;
227+
QMessageBox::warning(this, tr("Malformed XML"), tr("You have entered malformed XML input."));
228+
return;
229229
}
230230

231231
emit textReady(str);

0 commit comments

Comments
 (0)