~ubuntu-branches/ubuntu/trusty/tomahawk/trusty-proposed

« back to all changes in this revision

Viewing changes to src/accounts/xmpp/sip/XmlConsole.cpp

  • Committer: Package Import Robot
  • Author(s): Harald Sitter
  • Date: 2013-03-07 21:50:13 UTC
  • Revision ID: package-import@ubuntu.com-20130307215013-6gdjkdds7i9uenvs
Tags: upstream-0.6.0+dfsg
ImportĀ upstreamĀ versionĀ 0.6.0+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
 
2
 *
 
3
 *   Copyright 2011, Ruslan Nigmatullin <euroelessar@ya.ru>
 
4
 *   Copyright 2011, Dominik Schmidt <dev@dominik-schmidt.de>
 
5
 *   Copyright 2011, Jeff Mitchell <jeff@tomahawk-player.org>
 
6
 *
 
7
 *   Tomahawk is free software: you can redistribute it and/or modify
 
8
 *   it under the terms of the GNU General Public License as published by
 
9
 *   the Free Software Foundation, either version 3 of the License, or
 
10
 *   (at your option) any later version.
 
11
 *
 
12
 *   Tomahawk is distributed in the hope that it will be useful,
 
13
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
15
 *   GNU General Public License for more details.
 
16
 *
 
17
 *   You should have received a copy of the GNU General Public License
 
18
 *   along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
 
19
 */
 
20
 
 
21
#include "XmlConsole.h"
 
22
#include "ui_XmlConsole.h"
 
23
 
 
24
#include "utils/Logger.h"
 
25
 
 
26
#include <QMenu>
 
27
#include <QActionGroup>
 
28
#include <QStringBuilder>
 
29
#include <QTextLayout>
 
30
#include <QPlainTextDocumentLayout>
 
31
#include <QFileDialog>
 
32
#include <QTextDocumentWriter>
 
33
 
 
34
using namespace Jreen;
 
35
 
 
36
 
 
37
XmlConsole::XmlConsole(Client* client, QWidget *parent) :
 
38
        QWidget(parent),
 
39
        m_ui(new Ui::XmlConsole),
 
40
        m_client(client),       m_filter(0x1f)
 
41
{
 
42
        m_ui->setupUi(this);
 
43
 
 
44
    m_client->addXmlStreamHandler(this);
 
45
 
 
46
        QPalette pal = palette();
 
47
        pal.setColor(QPalette::Base, Qt::black);
 
48
        pal.setColor(QPalette::Text, Qt::white);
 
49
        m_ui->xmlBrowser->viewport()->setPalette(pal);
 
50
        QTextDocument *doc = m_ui->xmlBrowser->document();
 
51
        doc->setDocumentLayout(new QPlainTextDocumentLayout(doc));
 
52
        doc->clear();
 
53
 
 
54
        QTextFrameFormat format = doc->rootFrame()->frameFormat();
 
55
        format.setBackground(QColor(Qt::black));
 
56
        format.setMargin(0);
 
57
        doc->rootFrame()->setFrameFormat(format);
 
58
        QMenu *menu = new QMenu(m_ui->filterButton);
 
59
        menu->setSeparatorsCollapsible(false);
 
60
        menu->addSeparator()->setText(tr("Filter"));
 
61
        QActionGroup *group = new QActionGroup(menu);
 
62
        QAction *disabled = group->addAction(menu->addAction(tr("Disabled")));
 
63
        disabled->setCheckable(true);
 
64
        disabled->setData(Disabled);
 
65
        QAction *jid = group->addAction(menu->addAction(tr("By JID")));
 
66
        jid->setCheckable(true);
 
67
        jid->setData(ByJid);
 
68
        QAction *xmlns = group->addAction(menu->addAction(tr("By namespace uri")));
 
69
        xmlns->setCheckable(true);
 
70
        xmlns->setData(ByXmlns);
 
71
        QAction *attrb = group->addAction(menu->addAction(tr("By all attributes")));
 
72
        attrb->setCheckable(true);
 
73
        attrb->setData(ByAllAttributes);
 
74
        disabled->setChecked(true);
 
75
        connect(group, SIGNAL(triggered(QAction*)), this, SLOT(onActionGroupTriggered(QAction*)));
 
76
        menu->addSeparator()->setText(tr("Visible stanzas"));
 
77
        group = new QActionGroup(menu);
 
78
        group->setExclusive(false);
 
79
        QAction *iq = group->addAction(menu->addAction(tr("Information query")));
 
80
        iq->setCheckable(true);
 
81
        iq->setData(XmlNode::Iq);
 
82
        iq->setChecked(true);
 
83
        QAction *message = group->addAction(menu->addAction(tr("Message")));
 
84
        message->setCheckable(true);
 
85
        message->setData(XmlNode::Message);
 
86
        message->setChecked(true);
 
87
        QAction *presence = group->addAction(menu->addAction(tr("Presence")));
 
88
        presence->setCheckable(true);
 
89
        presence->setData(XmlNode::Presence);
 
90
        presence->setChecked(true);
 
91
        QAction *custom = group->addAction(menu->addAction(tr("Custom")));
 
92
        custom->setCheckable(true);
 
93
        custom->setData(XmlNode::Custom);
 
94
        custom->setChecked(true);
 
95
        connect(group, SIGNAL(triggered(QAction*)), this, SLOT(onActionGroupTriggered(QAction*)));
 
96
        m_ui->filterButton->setMenu(menu);
 
97
        m_stackBracketsColor = QColor(0x666666);
 
98
        m_stackIncoming.bodyColor = QColor(0xbb66bb);
 
99
        m_stackIncoming.tagColor = QColor(0x006666);
 
100
        m_stackIncoming.attributeColor = QColor(0x009933);
 
101
        m_stackIncoming.paramColor = QColor(0xcc0000);
 
102
        m_stackOutgoing.bodyColor = QColor(0x999999);
 
103
        m_stackOutgoing.tagColor = QColor(0x22aa22);
 
104
        m_stackOutgoing.attributeColor = QColor(0xffff33);
 
105
        m_stackOutgoing.paramColor = QColor(0xdd8811);
 
106
 
 
107
        QAction *action = new QAction(tr("Close"),this);
 
108
        action->setSoftKeyRole(QAction::NegativeSoftKey);
 
109
        connect(action, SIGNAL(triggered()), SLOT(close()));
 
110
        addAction(action);
 
111
}
 
112
 
 
113
XmlConsole::~XmlConsole()
 
114
{
 
115
        delete m_ui;
 
116
}
 
117
 
 
118
void XmlConsole::handleStreamBegin()
 
119
{
 
120
        m_stackIncoming.reader.clear();
 
121
        m_stackOutgoing.reader.clear();
 
122
        m_stackIncoming.depth = 0;
 
123
        m_stackOutgoing.depth = 0;
 
124
        qDeleteAll(m_stackIncoming.tokens);
 
125
        qDeleteAll(m_stackOutgoing.tokens);
 
126
        m_stackIncoming.tokens.clear();
 
127
        m_stackOutgoing.tokens.clear();
 
128
}
 
129
 
 
130
void XmlConsole::handleStreamEnd()
 
131
{
 
132
        m_stackIncoming.reader.clear();
 
133
        m_stackOutgoing.reader.clear();
 
134
        m_stackIncoming.depth = 0;
 
135
        m_stackOutgoing.depth = 0;
 
136
        qDeleteAll(m_stackIncoming.tokens);
 
137
        qDeleteAll(m_stackOutgoing.tokens);
 
138
        m_stackIncoming.tokens.clear();
 
139
        m_stackOutgoing.tokens.clear();
 
140
}
 
141
 
 
142
void XmlConsole::handleIncomingData(const char *data, qint64 size)
 
143
{
 
144
        stackProcess(QByteArray::fromRawData(data, size), true);
 
145
}
 
146
 
 
147
void XmlConsole::handleOutgoingData(const char *data, qint64 size)
 
148
{
 
149
        stackProcess(QByteArray::fromRawData(data, size), false);
 
150
}
 
151
 
 
152
QString generate_stacked_space(int depth)
 
153
{
 
154
        return QString(depth * 2, QLatin1Char(' '));
 
155
}
 
156
 
 
157
void XmlConsole::stackProcess(const QByteArray &data, bool incoming)
 
158
{
 
159
        StackEnvironment *d = &(incoming ? m_stackIncoming : m_stackOutgoing);
 
160
        d->reader.addData(data);
 
161
        StackToken *token;
 
162
//      debug() << incoming << data;
 
163
//      debug() << "==================================================================";
 
164
        while (d->reader.readNext() > QXmlStreamReader::Invalid) {
 
165
//              qDebug() << incoming << d->reader.tokenString();
 
166
                switch(d->reader.tokenType()) {
 
167
                case QXmlStreamReader::StartElement:
 
168
//                      dbg << d->reader.name().toString() << d->depth
 
169
//                                      << d->reader.attributes().value(QLatin1String("from")).toString();
 
170
                        d->depth++;
 
171
                        if (d->depth > 1) {
 
172
                                if (!d->tokens.isEmpty() && d->tokens.last()->type == QXmlStreamReader::Characters)
 
173
                                        delete d->tokens.takeLast();
 
174
                                d->tokens << new StackToken(d->reader);
 
175
                        }
 
176
                        break;
 
177
                case QXmlStreamReader::EndElement:
 
178
//                      dbg << d->reader.name().toString() << d->depth;
 
179
                        if (d->tokens.isEmpty())
 
180
                                break;
 
181
                        token = d->tokens.last();
 
182
                        if (token->type == QXmlStreamReader::StartElement && !token->startTag.empty)
 
183
                                token->startTag.empty = true;
 
184
                        else if (d->depth > 1)
 
185
                                d->tokens << new StackToken(d->reader);
 
186
                        if (d->depth == 2) {
 
187
                                QTextCursor cursor(m_ui->xmlBrowser->document());
 
188
                                cursor.movePosition(QTextCursor::End);
 
189
                                cursor.beginEditBlock();
 
190
                                QTextCharFormat zeroFormat = cursor.charFormat();
 
191
                                zeroFormat.setForeground(QColor(Qt::white));
 
192
                                QTextCharFormat bodyFormat = zeroFormat;
 
193
                                bodyFormat.setForeground(d->bodyColor);
 
194
                                QTextCharFormat tagFormat = zeroFormat;
 
195
                                tagFormat.setForeground(d->tagColor);
 
196
                                QTextCharFormat attributeFormat = zeroFormat;
 
197
                                attributeFormat.setForeground(d->attributeColor);
 
198
                                QTextCharFormat paramsFormat = zeroFormat;
 
199
                                paramsFormat.setForeground(d->paramColor);
 
200
                                QTextCharFormat bracketFormat = zeroFormat;
 
201
                                bracketFormat.setForeground(m_stackBracketsColor);
 
202
                                QString singleSpace = QLatin1String(" ");
 
203
                                cursor.insertBlock();
 
204
                                int depth = 0;
 
205
                                QString currentXmlns;
 
206
                                QXmlStreamReader::TokenType lastType = QXmlStreamReader::StartElement;
 
207
                                for (int i = 0; i < d->tokens.size(); i++) {
 
208
                                        token = d->tokens.at(i);
 
209
                                        if (token->type == QXmlStreamReader::StartElement) {
 
210
                                                QString space = generate_stacked_space(depth);
 
211
                                                cursor.insertText(QLatin1String("\n"));
 
212
                                                cursor.insertText(space);
 
213
                                                cursor.insertText(QLatin1String("<"), bracketFormat);
 
214
                                                cursor.insertText(token->startTag.name->toString(), tagFormat);
 
215
                                                const QStringRef &xmlns = *token->startTag.xmlns;
 
216
                                                if (i == 0 || xmlns != currentXmlns) {
 
217
                                                        currentXmlns = xmlns.toString();
 
218
                                                        cursor.insertText(singleSpace);
 
219
                                                        cursor.insertText(QLatin1String("xmlns"), attributeFormat);
 
220
                                                        cursor.insertText(QLatin1String("="), zeroFormat);
 
221
                                                        cursor.insertText(QLatin1String("'"), paramsFormat);
 
222
                                                        cursor.insertText(currentXmlns, paramsFormat);
 
223
                                                        cursor.insertText(QLatin1String("'"), paramsFormat);
 
224
                                                }
 
225
                                                QXmlStreamAttributes *attributes = token->startTag.attributes;
 
226
                                                for (int j = 0; j < attributes->count(); j++) {
 
227
                                                        const QXmlStreamAttribute &attr = attributes->at(j);
 
228
                                                        cursor.insertText(singleSpace);
 
229
                                                        cursor.insertText(attr.name().toString(), attributeFormat);
 
230
                                                        cursor.insertText(QLatin1String("="), zeroFormat);
 
231
                                                        cursor.insertText(QLatin1String("'"), paramsFormat);
 
232
                                                        cursor.insertText(attr.value().toString(), paramsFormat);
 
233
                                                        cursor.insertText(QLatin1String("'"), paramsFormat);
 
234
                                                }
 
235
                                                if (token->startTag.empty) {
 
236
                                                        cursor.insertText(QLatin1String("/>"), bracketFormat);
 
237
                                                } else {
 
238
                                                        cursor.insertText(QLatin1String(">"), bracketFormat);
 
239
                                                        depth++;
 
240
                                                }
 
241
                                        } else if (token->type == QXmlStreamReader::EndElement) {
 
242
                                                if (lastType == QXmlStreamReader::EndElement) {
 
243
                                                        QString space = generate_stacked_space(depth - 1);
 
244
                                                        cursor.insertText(QLatin1String("\n"));
 
245
                                                        cursor.insertText(space);
 
246
                                                }
 
247
                                                cursor.insertText(QLatin1String("</"), bracketFormat);
 
248
                                                cursor.insertText(token->endTag.name->toString(), tagFormat);
 
249
                                                cursor.insertText(QLatin1String(">"), bracketFormat);
 
250
                                                depth--;
 
251
                                        } else if (token->type == QXmlStreamReader::Characters) {
 
252
                                                cursor.setCharFormat(bodyFormat);
 
253
                                                QString text = token->charachters.text->toString();
 
254
                                                if (text.contains(QLatin1Char('\n'))) {
 
255
                                                        QString space = generate_stacked_space(depth);
 
256
                                                        space.prepend(QLatin1Char('\n'));
 
257
                                                        QStringList lines = text.split(QLatin1Char('\n'));
 
258
                                                        for (int j = 0; j < lines.size(); j++) {
 
259
                                                                cursor.insertText(space);
 
260
                                                                cursor.insertText(lines.at(j));
 
261
                                                        }
 
262
                                                        space.chop(1);
 
263
                                                        cursor.insertText(space);
 
264
                                                } else {
 
265
                                                        cursor.insertText(text);
 
266
                                                }
 
267
                                        }
 
268
                                        lastType = token->type;
 
269
                                        if (lastType == QXmlStreamReader::StartElement && token->startTag.empty)
 
270
                                                lastType = QXmlStreamReader::EndElement;
 
271
                                        delete token;
 
272
                                }
 
273
                                cursor.endEditBlock();
 
274
                                d->tokens.clear();
 
275
                        }
 
276
                        d->depth--;
 
277
                        break;
 
278
                case QXmlStreamReader::Characters:
 
279
                        token = d->tokens.isEmpty() ? 0 : d->tokens.last();
 
280
                        if (token && token->type == QXmlStreamReader::StartElement && !token->startTag.empty) {
 
281
                                if (*token->startTag.name == QLatin1String("auth")
 
282
                                                && *token->startTag.xmlns == QLatin1String("urn:ietf:params:xml:ns:xmpp-sasl")) {
 
283
                                        d->tokens << new StackToken(QLatin1String("<<Private data>>"));
 
284
                                } else {
 
285
                                        d->tokens << new StackToken(d->reader);
 
286
                                }
 
287
                        }
 
288
                        break;
 
289
                default:
 
290
                        break;
 
291
                }
 
292
        }
 
293
//      qDebug() << d->reader.tokenString();
 
294
//      if (d->reader.tokenType() == QXmlStreamReader::Invalid)
 
295
//              dbg << d->reader.error() << d->reader.errorString();
 
296
        if (!incoming && d->depth > 1) {
 
297
                qFatal("outgoing depth %d on\n\"%s\"", d->depth,
 
298
                           qPrintable(QString::fromUtf8(data, data.size())));
 
299
        }
 
300
}
 
301
 
 
302
void XmlConsole::changeEvent(QEvent *e)
 
303
{
 
304
        QWidget::changeEvent(e);
 
305
        switch (e->type()) {
 
306
        case QEvent::LanguageChange:
 
307
                m_ui->retranslateUi(this);
 
308
                break;
 
309
        default:
 
310
                break;
 
311
        }
 
312
}
 
313
 
 
314
void XmlConsole::onActionGroupTriggered(QAction *action)
 
315
{
 
316
        int type = action->data().toInt();
 
317
        if (type >= 0x10) {
 
318
                m_filter = (m_filter & 0xf) | type;
 
319
                m_ui->lineEdit->setEnabled(type != 0x10);
 
320
        } else {
 
321
                m_filter = m_filter ^ type;
 
322
        }
 
323
        on_lineEdit_textChanged(m_ui->lineEdit->text());
 
324
}
 
325
 
 
326
void XmlConsole::on_lineEdit_textChanged(const QString &text)
 
327
{
 
328
        int filterType = m_filter & 0xf0;
 
329
        JID filterJid = (filterType == ByJid) ? text : QString();
 
330
    for (int i = 0; i < m_nodes.size(); i++) {
 
331
                XmlNode &node = m_nodes[i];
 
332
                bool ok = true;
 
333
                switch (filterType) {
 
334
                case ByXmlns:
 
335
                        ok = node.xmlns.contains(text);
 
336
                        break;
 
337
                case ByJid:
 
338
                        ok = node.jid.full() == filterJid.full() || node.jid.bare() == filterJid.full();
 
339
                        break;
 
340
                case ByAllAttributes:
 
341
                        ok = node.attributes.contains(text);
 
342
                        break;
 
343
                default:
 
344
                        break;
 
345
                }
 
346
                ok &= bool(node.type & m_filter);
 
347
                node.block.setVisible(ok);
 
348
                node.block.setLineCount(ok ? node.lineCount : 0);
 
349
                //              qDebug() << node.block.lineCount();
 
350
        }
 
351
        QAbstractTextDocumentLayout *layout = m_ui->xmlBrowser->document()->documentLayout();
 
352
        Q_ASSERT(qobject_cast<QPlainTextDocumentLayout*>(layout));
 
353
        qobject_cast<QPlainTextDocumentLayout*>(layout)->requestUpdate();
 
354
}
 
355
 
 
356
void XmlConsole::on_saveButton_clicked()
 
357
{
 
358
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save XMPP log to file"),
 
359
                                                        QString(), tr("OpenDocument Format (*.odf);;HTML file (*.html);;Plain text (*.txt)"));
 
360
        if (!fileName.isEmpty()) {
 
361
                QTextDocumentWriter writer(fileName);
 
362
                writer.write(m_ui->xmlBrowser->document());
 
363
        }
 
364
}