summaryrefslogtreecommitdiffstats
path: root/src/libcommuni/examples
diff options
context:
space:
mode:
authorMarkus Mittendrein <git@maxmitti.tk>2015-09-09 19:00:56 +0200
committerMarkus Mittendrein <git@maxmitti.tk>2015-09-09 19:02:23 +0200
commit8a6d4b06f2291c363f3dea17837ed20893852453 (patch)
treec091375499e35eaa1810586454e0834c06e6c9b2 /src/libcommuni/examples
parentf554a27046f203e56a07baaf214d90834942e3f5 (diff)
downloadmanager-8a6d4b06f2291c363f3dea17837ed20893852453.tar.gz
manager-8a6d4b06f2291c363f3dea17837ed20893852453.zip
Cleanup repo with some directories
Diffstat (limited to 'src/libcommuni/examples')
-rw-r--r--src/libcommuni/examples/bot/bot.pro17
-rw-r--r--src/libcommuni/examples/bot/ircbot.cpp84
-rw-r--r--src/libcommuni/examples/bot/ircbot.h37
-rw-r--r--src/libcommuni/examples/bot/main.cpp59
-rw-r--r--src/libcommuni/examples/client/client.pro16
-rw-r--r--src/libcommuni/examples/client/ircclient.cpp321
-rw-r--r--src/libcommuni/examples/client/ircclient.h78
-rw-r--r--src/libcommuni/examples/client/ircmessageformatter.cpp113
-rw-r--r--src/libcommuni/examples/client/ircmessageformatter.h31
-rw-r--r--src/libcommuni/examples/client/main.cpp20
-rw-r--r--src/libcommuni/examples/examples.pri24
-rw-r--r--src/libcommuni/examples/examples.pro13
-rw-r--r--src/libcommuni/examples/minimal/main.cpp38
-rw-r--r--src/libcommuni/examples/minimal/minimal.pro16
-rw-r--r--src/libcommuni/examples/qmlbot/main.cpp22
-rw-r--r--src/libcommuni/examples/qmlbot/qml/main.qml84
-rw-r--r--src/libcommuni/examples/qmlbot/qmlbot.pro22
-rw-r--r--src/libcommuni/examples/qmlbot/qmlbot.qrc5
-rw-r--r--src/libcommuni/examples/quick/main.cpp20
-rw-r--r--src/libcommuni/examples/quick/qml/BufferListView.qml92
-rw-r--r--src/libcommuni/examples/quick/qml/ChatPage.qml111
-rw-r--r--src/libcommuni/examples/quick/qml/ConnectPage.qml160
-rw-r--r--src/libcommuni/examples/quick/qml/MessageFormatter.qml215
-rw-r--r--src/libcommuni/examples/quick/qml/TextBrowser.qml47
-rw-r--r--src/libcommuni/examples/quick/qml/TextEntry.qml77
-rw-r--r--src/libcommuni/examples/quick/qml/TopicLabel.qml48
-rw-r--r--src/libcommuni/examples/quick/qml/UserListView.qml71
-rw-r--r--src/libcommuni/examples/quick/qml/main.qml80
-rw-r--r--src/libcommuni/examples/quick/quick.pro28
-rw-r--r--src/libcommuni/examples/quick/quick.qrc13
30 files changed, 1962 insertions, 0 deletions
diff --git a/src/libcommuni/examples/bot/bot.pro b/src/libcommuni/examples/bot/bot.pro
new file mode 100644
index 0000000..1f4f434
--- /dev/null
+++ b/src/libcommuni/examples/bot/bot.pro
@@ -0,0 +1,17 @@
+######################################################################
+# Communi
+######################################################################
+
+TEMPLATE = app
+TARGET = bot
+DEPENDPATH += .
+INCLUDEPATH += .
+CONFIG += console
+CONFIG -= app_bundle
+QT = core network
+
+# Input
+HEADERS += ircbot.h
+SOURCES += ircbot.cpp main.cpp
+
+include(../examples.pri)
diff --git a/src/libcommuni/examples/bot/ircbot.cpp b/src/libcommuni/examples/bot/ircbot.cpp
new file mode 100644
index 0000000..1891e62
--- /dev/null
+++ b/src/libcommuni/examples/bot/ircbot.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+#include "ircbot.h"
+#include <IrcMessage>
+#include <IrcCommand>
+#include <QCoreApplication>
+#include <QTimer>
+
+IrcBot::IrcBot(QObject* parent) : IrcConnection(parent)
+{
+//! [messages]
+ connect(this, SIGNAL(privateMessageReceived(IrcPrivateMessage*)), this, SLOT(processMessage(IrcPrivateMessage*)));
+//! [messages]
+
+//! [commands]
+ parser.addCommand(IrcCommand::CtcpAction, "ACT [target] <message...>");
+ parser.addCommand(IrcCommand::Custom, "HELP (<command...>)");
+ parser.addCommand(IrcCommand::Nick, "NICK <nick>");
+ parser.addCommand(IrcCommand::Join, "JOIN <#channel> (<key>)");
+ parser.addCommand(IrcCommand::Part, "PART (<#channel>) (<message...>)");
+ parser.addCommand(IrcCommand::Quit, "QUIT (<message...>)");
+ parser.addCommand(IrcCommand::Message, "SAY [target] <message...>");
+//! [commands]
+
+ bufferModel.setConnection(this);
+//! [channels]
+ connect(&bufferModel, SIGNAL(channelsChanged(QStringList)), &parser, SLOT(setChannels(QStringList)));
+//! [channels]
+}
+
+void IrcBot::join(QString channel)
+{
+ sendCommand(IrcCommand::createJoin(channel));
+}
+
+//![receive]
+void IrcBot::processMessage(IrcPrivateMessage* message)
+{
+ if (message->isPrivate()) {
+ // private message: reply to the message sender
+ // => triggers: "!<cmd> <params>" and "<cmd> <params>"
+ parser.setTarget(message->nick());
+ parser.setTriggers(QStringList() << "!" << "");
+ } else {
+ // channel message: reply to the target channel
+ // => triggers: "!<cmd> <params>" and "bot: <cmd> <params>"
+ parser.setTarget(message->target());
+ parser.setTriggers(QStringList() << "!" << nickName().append(":"));
+ }
+
+ IrcCommand* cmd = parser.parse(message->content());
+ if (cmd) {
+ if (cmd->type() == IrcCommand::Custom && cmd->parameters().value(0) == "HELP") {
+ help(cmd->parameters().mid(1));
+ } else {
+ sendCommand(cmd);
+
+ if (cmd->type() == IrcCommand::Quit) {
+ connect(this, SIGNAL(disconnected()), qApp, SLOT(quit()));
+ QTimer::singleShot(1000, qApp, SLOT(quit()));
+ }
+ }
+ }
+}
+//![receive]
+
+void IrcBot::help(QStringList commands)
+{
+ if (commands.isEmpty())
+ commands = parser.commands();
+
+ QString target = parser.target();
+ foreach (const QString& command, commands) {
+ QString syntax = parser.syntax(command);
+ sendCommand(IrcCommand::createMessage(target, syntax));
+ }
+}
diff --git a/src/libcommuni/examples/bot/ircbot.h b/src/libcommuni/examples/bot/ircbot.h
new file mode 100644
index 0000000..1a88a01
--- /dev/null
+++ b/src/libcommuni/examples/bot/ircbot.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+#ifndef IRCBOT_H
+#define IRCBOT_H
+
+#include <IrcConnection>
+#include <IrcBufferModel>
+#include <IrcCommandParser>
+
+class IrcBot : public IrcConnection
+{
+ Q_OBJECT
+
+public:
+ IrcBot(QObject* parent = 0);
+
+public slots:
+ void join(QString channel);
+
+private slots:
+ void processMessage(IrcPrivateMessage* message);
+
+private:
+ void help(QStringList commands);
+
+ IrcCommandParser parser;
+ IrcBufferModel bufferModel;
+};
+
+#endif // IRCBOT_H
diff --git a/src/libcommuni/examples/bot/main.cpp b/src/libcommuni/examples/bot/main.cpp
new file mode 100644
index 0000000..526f776
--- /dev/null
+++ b/src/libcommuni/examples/bot/main.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+#include <QtCore>
+#include "ircbot.h"
+
+int main(int argc, char* argv[])
+{
+ QCoreApplication app(argc, argv);
+
+ // enable debug output
+ qputenv("IRC_DEBUG", "1");
+ qsrand(QTime::currentTime().msec());
+
+ IrcBot bot;
+ bot.setHost("irc.freenode.net");
+ bot.setUserName("communi");
+ bot.setNickName("Bot" + QString::number(qrand() % 9999));
+ bot.setRealName("Communi " + Irc::version() + " example bot");
+
+ bool joined = false;
+ QStringList args = app.arguments();
+ for (int i = 0; i < args.count(); ++i) {
+ QString arg = args.at(i);
+ if (arg == "-help") {
+ qDebug() << "Usage:" << argv[0] << "(-host <host>) (-port <port>) (-ssl) (-nick <nick>) (-user <user>) (-password <password>) (-channel <channel>)";
+ return 0;
+ } else if (arg == "-port") {
+ bool ok = false;
+ int port = args.value(++i).toInt(&ok);
+ if (ok)
+ bot.setPort(port);
+ } else if (arg == "-ssl") {
+ bot.setSecure(true);
+ } else if (arg == "-host") {
+ bot.setHost(args.value(++i));
+ } else if (arg == "-user") {
+ bot.setUserName(args.value(++i));
+ } else if (arg == "-password") {
+ bot.setPassword(args.value(++i));
+ } else if (arg == "-nick") {
+ bot.setNickName(args.value(++i));
+ } else if (arg == "-channel") {
+ bot.join(args.value(++i));
+ joined = true;
+ }
+ }
+ if (!joined)
+ bot.join("#communi");
+
+ bot.open();
+ return app.exec();
+}
diff --git a/src/libcommuni/examples/client/client.pro b/src/libcommuni/examples/client/client.pro
new file mode 100644
index 0000000..5e91b12
--- /dev/null
+++ b/src/libcommuni/examples/client/client.pro
@@ -0,0 +1,16 @@
+######################################################################
+# Communi
+######################################################################
+
+TEMPLATE = app
+TARGET = client
+DEPENDPATH += .
+INCLUDEPATH += .
+QT = core network gui
+greaterThan(QT_MAJOR_VERSION, 4):QT += widgets
+
+# Input
+HEADERS += ircclient.h ircmessageformatter.h
+SOURCES += ircclient.cpp ircmessageformatter.cpp main.cpp
+
+include(../examples.pri)
diff --git a/src/libcommuni/examples/client/ircclient.cpp b/src/libcommuni/examples/client/ircclient.cpp
new file mode 100644
index 0000000..c33043b
--- /dev/null
+++ b/src/libcommuni/examples/client/ircclient.cpp
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+#include "ircclient.h"
+#include "ircmessageformatter.h"
+
+#include <QTextDocument>
+#include <QTextCursor>
+#include <QVBoxLayout>
+#include <QScrollBar>
+#include <QLineEdit>
+#include <QShortcut>
+#include <QListView>
+#include <QTextEdit>
+#include <QTime>
+
+#include <Irc>
+#include <IrcUser>
+#include <IrcBuffer>
+#include <IrcCommand>
+#include <IrcMessage>
+#include <IrcUserModel>
+#include <IrcCompleter>
+#include <IrcConnection>
+#include <IrcBufferModel>
+#include <IrcCommandParser>
+
+static const char* CHANNEL = "#communi";
+static const char* SERVER = "irc.freenode.net";
+
+IrcClient::IrcClient(QWidget* parent) : QSplitter(parent)
+{
+ createParser();
+ createConnection();
+ createCompleter();
+ createUserList();
+ createLayout();
+ createBufferList();
+
+ // queue a command to automatically join the channel when connected
+ connection->sendCommand(IrcCommand::createJoin(CHANNEL));
+ connection->open();
+
+ textEdit->append(IrcMessageFormatter::formatMessage(tr("! Welcome to the Communi %1 example client.").arg(IRC_VERSION_STR)));
+ textEdit->append(IrcMessageFormatter::formatMessage(tr("! This example connects %1 and joins %2.").arg(SERVER, CHANNEL)));
+ textEdit->append(IrcMessageFormatter::formatMessage(tr("! PS. Available commands: JOIN, ME, NICK, PART")));
+}
+
+IrcClient::~IrcClient()
+{
+ if (connection->isActive()) {
+ connection->quit(connection->realName());
+ connection->close();
+ }
+}
+
+void IrcClient::onConnected()
+{
+ textEdit->append(IrcMessageFormatter::formatMessage("! Connected to %1.").arg(SERVER));
+ textEdit->append(IrcMessageFormatter::formatMessage("! Joining %1...").arg(CHANNEL));
+}
+
+void IrcClient::onConnecting()
+{
+ textEdit->append(IrcMessageFormatter::formatMessage("! Connecting %1...").arg(SERVER));
+}
+
+void IrcClient::onDisconnected()
+{
+ textEdit->append(IrcMessageFormatter::formatMessage("! Disconnected from %1.").arg(SERVER));
+}
+
+void IrcClient::onTextEdited()
+{
+ // clear the possible error indication
+ lineEdit->setStyleSheet(QString());
+}
+
+void IrcClient::onTextEntered()
+{
+ QString input = lineEdit->text();
+ IrcCommand* command = parser->parse(input);
+ if (command) {
+ connection->sendCommand(command);
+
+ // echo own messages (servers do not send our own messages back)
+ if (command->type() == IrcCommand::Message || command->type() == IrcCommand::CtcpAction) {
+ IrcMessage* msg = command->toMessage(connection->nickName(), connection);
+ receiveMessage(msg);
+ delete msg;
+ }
+
+ lineEdit->clear();
+ } else if (input.length() > 1) {
+ QString error;
+ QString command = lineEdit->text().mid(1).split(" ", QString::SkipEmptyParts).value(0).toUpper();
+ if (parser->commands().contains(command))
+ error = tr("[ERROR] Syntax: %1").arg(parser->syntax(command).replace("<", "&lt;").replace(">", "&gt;"));
+ else
+ error = tr("[ERROR] Unknown command: %1").arg(command);
+ textEdit->append(IrcMessageFormatter::formatMessage(error));
+ lineEdit->setStyleSheet("background: salmon");
+ }
+}
+
+void IrcClient::onCompletion()
+{
+ completer->complete(lineEdit->text(), lineEdit->cursorPosition());
+}
+
+void IrcClient::onCompleted(const QString& text, int cursor)
+{
+ lineEdit->setText(text);
+ lineEdit->setCursorPosition(cursor);
+}
+
+void IrcClient::onBufferAdded(IrcBuffer* buffer)
+{
+ // joined a buffer - start listening to buffer specific messages
+ connect(buffer, SIGNAL(messageReceived(IrcMessage*)), this, SLOT(receiveMessage(IrcMessage*)));
+
+ // create a document for storing the buffer specific messages
+ QTextDocument* document = new QTextDocument(buffer);
+ documents.insert(buffer, document);
+
+ // create a sorted model for buffer users
+ IrcUserModel* userModel = new IrcUserModel(buffer);
+ userModel->setSortMethod(Irc::SortByTitle);
+ userModels.insert(buffer, userModel);
+
+ // activate the new buffer
+ int idx = bufferModel->buffers().indexOf(buffer);
+ if (idx != -1)
+ bufferList->setCurrentIndex(bufferModel->index(idx));
+}
+
+void IrcClient::onBufferRemoved(IrcBuffer* buffer)
+{
+ // the buffer specific models and documents are no longer needed
+ delete userModels.take(buffer);
+ delete documents.take(buffer);
+}
+
+void IrcClient::onBufferActivated(const QModelIndex& index)
+{
+ IrcBuffer* buffer = index.data(Irc::BufferRole).value<IrcBuffer*>();
+
+ // document, user list and nick completion for the current buffer
+ textEdit->setDocument(documents.value(buffer));
+ textEdit->verticalScrollBar()->triggerAction(QScrollBar::SliderToMaximum);
+ userList->setModel(userModels.value(buffer));
+ completer->setBuffer(buffer);
+
+ // keep the command parser aware of the context
+ if (buffer)
+ parser->setTarget(buffer->title());
+}
+
+void IrcClient::onUserActivated(const QModelIndex& index)
+{
+ IrcUser* user = index.data(Irc::UserRole).value<IrcUser*>();
+
+ if (user) {
+ IrcBuffer* buffer = bufferModel->add(user->name());
+
+ // activate the new query
+ int idx = bufferModel->buffers().indexOf(buffer);
+ if (idx != -1)
+ bufferList->setCurrentIndex(bufferModel->index(idx));
+ }
+}
+
+static void appendHtml(QTextDocument* document, const QString& html)
+{
+ QTextCursor cursor(document);
+ cursor.beginEditBlock();
+ cursor.movePosition(QTextCursor::End);
+ if (!document->isEmpty())
+ cursor.insertBlock();
+ cursor.insertHtml(html);
+ cursor.endEditBlock();
+}
+
+void IrcClient::receiveMessage(IrcMessage* message)
+{
+ IrcBuffer* buffer = qobject_cast<IrcBuffer*>(sender());
+ if (!buffer)
+ buffer = bufferList->currentIndex().data(Irc::BufferRole).value<IrcBuffer*>();
+
+ QTextDocument* document = documents.value(buffer);
+ if (document) {
+ QString html = IrcMessageFormatter::formatMessage(message);
+ if (!html.isEmpty()) {
+ if (document == textEdit->document())
+ textEdit->append(html);
+ else
+ appendHtml(document, html);
+ }
+ }
+}
+
+void IrcClient::createLayout()
+{
+ setWindowTitle(tr("Communi %1 example client").arg(IRC_VERSION_STR));
+
+ // a read-only text editor for showing the messages
+ textEdit = new QTextEdit(this);
+ textEdit->setReadOnly(true);
+
+ // a line editor for entering commands
+ lineEdit = new QLineEdit(this);
+ lineEdit->setAttribute(Qt::WA_MacShowFocusRect, false);
+ textEdit->setFocusProxy(lineEdit);
+ connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(onTextEntered()));
+ connect(lineEdit, SIGNAL(textEdited(QString)), this, SLOT(onTextEdited()));
+
+ // the rest is just setting up the UI layout...
+ QSplitter* splitter = new QSplitter(this);
+ splitter->setHandleWidth(1);
+ splitter->addWidget(textEdit);
+ splitter->addWidget(userList);
+ splitter->setStretchFactor(0, 5);
+ splitter->setStretchFactor(1, 1);
+
+ QWidget* container = new QWidget(this);
+ QVBoxLayout* layout = new QVBoxLayout(container);
+ layout->setSpacing(0);
+ layout->setMargin(0);
+ layout->addWidget(splitter);
+ layout->addWidget(lineEdit);
+
+ addWidget(container);
+
+ setHandleWidth(1);
+}
+
+void IrcClient::createCompleter()
+{
+ // nick name completion
+ completer = new IrcCompleter(this);
+ completer->setParser(parser);
+ connect(completer, SIGNAL(completed(QString,int)), this, SLOT(onCompleted(QString,int)));
+
+ QShortcut* shortcut = new QShortcut(Qt::Key_Tab, this);
+ connect(shortcut, SIGNAL(activated()), this, SLOT(onCompletion()));
+}
+
+void IrcClient::createParser()
+{
+ // create a command parser and teach it some commands. notice also
+ // that we must keep the command parser aware of the context in
+ // createUi() and onBufferActivated()
+
+ parser = new IrcCommandParser(this);
+ parser->setTolerant(true);
+ parser->setTriggers(QStringList("/"));
+ parser->addCommand(IrcCommand::Join, "JOIN <#channel> (<key>)");
+ parser->addCommand(IrcCommand::CtcpAction, "ME [target] <message...>");
+ parser->addCommand(IrcCommand::Mode, "MODE (<channel/user>) (<mode>) (<arg>)");
+ parser->addCommand(IrcCommand::Nick, "NICK <nick>");
+ parser->addCommand(IrcCommand::Part, "PART (<#channel>) (<message...>)");
+}
+
+void IrcClient::createUserList()
+{
+ // a list of channel users
+ userList = new QListView(this);
+ userList->setFocusPolicy(Qt::NoFocus);
+
+ // open a private query when double clicking a user
+ connect(userList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(onUserActivated(QModelIndex)));
+}
+
+void IrcClient::createBufferList()
+{
+ bufferModel = new IrcBufferModel(connection);
+ connect(bufferModel, SIGNAL(added(IrcBuffer*)), this, SLOT(onBufferAdded(IrcBuffer*)));
+ connect(bufferModel, SIGNAL(removed(IrcBuffer*)), this, SLOT(onBufferRemoved(IrcBuffer*)));
+
+ bufferList = new QListView(this);
+ bufferList->setFocusPolicy(Qt::NoFocus);
+ bufferList->setModel(bufferModel);
+
+ // keep the command parser aware of the context
+ connect(bufferModel, SIGNAL(channelsChanged(QStringList)), parser, SLOT(setChannels(QStringList)));
+
+ // keep track of the current buffer, see also onBufferActivated()
+ connect(bufferList->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(onBufferActivated(QModelIndex)));
+
+ // create a server buffer for non-targeted messages...
+ IrcBuffer* serverBuffer = bufferModel->add(connection->host());
+
+ // ...and connect it to IrcBufferModel::messageIgnored()
+ connect(bufferModel, SIGNAL(messageIgnored(IrcMessage*)), serverBuffer, SLOT(receiveMessage(IrcMessage*)));
+
+ insertWidget(0, bufferList);
+
+ setStretchFactor(0, 1);
+ setStretchFactor(1, 3);
+}
+
+void IrcClient::createConnection()
+{
+ connection = new IrcConnection(this);
+ connect(connection, SIGNAL(connected()), this, SLOT(onConnected()));
+ connect(connection, SIGNAL(connecting()), this, SLOT(onConnecting()));
+ connect(connection, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
+
+ qsrand(QTime::currentTime().msec());
+
+ connection->setHost(SERVER);
+ connection->setUserName("communi");
+ connection->setNickName(tr("Client%1").arg(qrand() % 9999));
+ connection->setRealName(tr("Communi %1 example client").arg(IRC_VERSION_STR));
+}
diff --git a/src/libcommuni/examples/client/ircclient.h b/src/libcommuni/examples/client/ircclient.h
new file mode 100644
index 0000000..9d6ee3c
--- /dev/null
+++ b/src/libcommuni/examples/client/ircclient.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+#ifndef IRCCLIENT_H
+#define IRCCLIENT_H
+
+#include <QSplitter>
+#include <QHash>
+
+class IrcBuffer;
+class IrcMessage;
+class IrcUserModel;
+class IrcCompleter;
+class IrcConnection;
+class IrcBufferModel;
+class IrcCommandParser;
+
+QT_FORWARD_DECLARE_CLASS(QLineEdit)
+QT_FORWARD_DECLARE_CLASS(QListView)
+QT_FORWARD_DECLARE_CLASS(QTextEdit)
+QT_FORWARD_DECLARE_CLASS(QModelIndex)
+QT_FORWARD_DECLARE_CLASS(QTextDocument)
+
+class IrcClient : public QSplitter
+{
+ Q_OBJECT
+
+public:
+ IrcClient(QWidget* parent = 0);
+ ~IrcClient();
+
+private slots:
+ void onConnected();
+ void onConnecting();
+ void onDisconnected();
+
+ void onTextEdited();
+ void onTextEntered();
+
+ void onCompletion();
+ void onCompleted(const QString& text, int cursor);
+
+ void onBufferAdded(IrcBuffer* buffer);
+ void onBufferRemoved(IrcBuffer* buffer);
+
+ void onBufferActivated(const QModelIndex& index);
+ void onUserActivated(const QModelIndex& index);
+
+ void receiveMessage(IrcMessage* message);
+
+private:
+ void createLayout();
+ void createCompleter();
+ void createParser();
+ void createUserList();
+ void createBufferList();
+ void createConnection();
+
+ QLineEdit* lineEdit;
+ QTextEdit* textEdit;
+ QListView* userList;
+ QListView* bufferList;
+
+ IrcCompleter* completer;
+ IrcCommandParser* parser;
+ IrcConnection* connection;
+ IrcBufferModel* bufferModel;
+ QHash<IrcBuffer*, IrcUserModel*> userModels;
+ QHash<IrcBuffer*, QTextDocument*> documents;
+};
+
+#endif // IRCCLIENT_H
diff --git a/src/libcommuni/examples/client/ircmessageformatter.cpp b/src/libcommuni/examples/client/ircmessageformatter.cpp
new file mode 100644
index 0000000..6537664
--- /dev/null
+++ b/src/libcommuni/examples/client/ircmessageformatter.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+#include "ircmessageformatter.h"
+
+#include <IrcTextFormat>
+#include <IrcConnection>
+#include <QTime>
+#include <Irc>
+
+QString IrcMessageFormatter::formatMessage(IrcMessage* message)
+{
+ QString formatted;
+ switch (message->type()) {
+ case IrcMessage::Join:
+ formatted = formatJoinMessage(static_cast<IrcJoinMessage*>(message));
+ break;
+ case IrcMessage::Mode:
+ formatted = formatModeMessage(static_cast<IrcModeMessage*>(message));
+ break;
+ case IrcMessage::Names:
+ formatted = formatNamesMessage(static_cast<IrcNamesMessage*>(message));
+ break;
+ case IrcMessage::Nick:
+ formatted = formatNickMessage(static_cast<IrcNickMessage*>(message));
+ break;
+ case IrcMessage::Part:
+ formatted = formatPartMessage(static_cast<IrcPartMessage*>(message));
+ break;
+ case IrcMessage::Private:
+ formatted = formatPrivateMessage(static_cast<IrcPrivateMessage*>(message));
+ break;
+ case IrcMessage::Quit:
+ formatted = formatQuitMessage(static_cast<IrcQuitMessage*>(message));
+ break;
+ default:
+ break;
+ }
+ return formatMessage(formatted);
+}
+
+QString IrcMessageFormatter::formatMessage(const QString& message)
+{
+ if (!message.isEmpty()) {
+ QString formatted = QObject::tr("[%1] %2").arg(QTime::currentTime().toString(), message);
+ if (message.startsWith("!"))
+ formatted = QObject::tr("<font color='gray'>%1</font>").arg(formatted);
+ else if (message.startsWith("*"))
+ formatted = QObject::tr("<font color='maroon'>%1</font>").arg(formatted);
+ else if (message.startsWith("["))
+ formatted = QObject::tr("<font color='indianred'>%1</font>").arg(formatted);
+ return formatted;
+ }
+ return QString();
+}
+
+QString IrcMessageFormatter::formatJoinMessage(IrcJoinMessage* message)
+{
+ if (message->flags() & IrcMessage::Own)
+ return QObject::tr("! You have joined %1 as %2").arg(message->channel(), message->nick());
+ else
+ return QObject::tr("! %1 has joined %2").arg(message->nick(), message->channel());
+}
+
+QString IrcMessageFormatter::formatModeMessage(IrcModeMessage* message)
+{
+ QString args = message->arguments().join(" ");
+ if (message->isReply())
+ return QObject::tr("! %1 mode is %2 %3").arg(message->target(), message->mode(), args);
+ else
+ return QObject::tr("! %1 sets mode %2 %3 %4").arg(message->nick(), message->target(), message->mode(), args);
+}
+
+QString IrcMessageFormatter::formatNamesMessage(IrcNamesMessage* message)
+{
+ return QObject::tr("! %1 has %2 users").arg(message->channel()).arg(message->names().count());
+}
+
+QString IrcMessageFormatter::formatNickMessage(IrcNickMessage* message)
+{
+ return QObject::tr("! %1 has changed nick to %2").arg(message->oldNick(), message->newNick());
+}
+
+QString IrcMessageFormatter::formatPartMessage(IrcPartMessage* message)
+{
+ if (message->reason().isEmpty())
+ return QObject::tr("! %1 has left %2").arg(message->nick(), message->channel());
+ else
+ return QObject::tr("! %1 has left %2 (%3)").arg(message->nick(), message->channel(), message->reason());
+}
+
+QString IrcMessageFormatter::formatPrivateMessage(IrcPrivateMessage* message)
+{
+ const QString content = IrcTextFormat().toHtml(message->content());
+ if (message->isAction())
+ return QObject::tr("* %1 %2").arg(message->nick(), content);
+ else
+ return QObject::tr("&lt;%1&gt; %2").arg(message->nick(),content);
+}
+
+QString IrcMessageFormatter::formatQuitMessage(IrcQuitMessage* message)
+{
+ if (message->reason().isEmpty())
+ return QObject::tr("! %1 has quit").arg(message->nick());
+ else
+ return QObject::tr("! %1 has quit (%2)").arg(message->nick(), message->reason());
+}
diff --git a/src/libcommuni/examples/client/ircmessageformatter.h b/src/libcommuni/examples/client/ircmessageformatter.h
new file mode 100644
index 0000000..f91be50
--- /dev/null
+++ b/src/libcommuni/examples/client/ircmessageformatter.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+#ifndef IRCMESSAGEFORMATTER_H
+#define IRCMESSAGEFORMATTER_H
+
+#include <IrcMessage>
+
+class IrcMessageFormatter
+{
+public:
+ static QString formatMessage(IrcMessage* message);
+ static QString formatMessage(const QString& message);
+
+private:
+ static QString formatJoinMessage(IrcJoinMessage* message);
+ static QString formatModeMessage(IrcModeMessage* message);
+ static QString formatNamesMessage(IrcNamesMessage* message);
+ static QString formatNickMessage(IrcNickMessage* message);
+ static QString formatPartMessage(IrcPartMessage* message);
+ static QString formatPrivateMessage(IrcPrivateMessage* message);
+ static QString formatQuitMessage(IrcQuitMessage* message);
+};
+
+#endif // IRCMESSAGEFORMATTER_H
diff --git a/src/libcommuni/examples/client/main.cpp b/src/libcommuni/examples/client/main.cpp
new file mode 100644
index 0000000..951ee91
--- /dev/null
+++ b/src/libcommuni/examples/client/main.cpp
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+#include <QApplication>
+#include "ircclient.h"
+
+int main(int argc, char* argv[])
+{
+ QApplication app(argc, argv);
+ IrcClient client;
+ client.resize(800, 480);
+ client.show();
+ return app.exec();
+}
diff --git a/src/libcommuni/examples/examples.pri b/src/libcommuni/examples/examples.pri
new file mode 100644
index 0000000..bc9b138
--- /dev/null
+++ b/src/libcommuni/examples/examples.pri
@@ -0,0 +1,24 @@
+######################################################################
+# Communi
+######################################################################
+
+!verbose:CONFIG += silent
+
+CONFIG(debug, debug|release) {
+ OBJECTS_DIR = debug
+ MOC_DIR = debug
+ RCC_DIR = debug
+ UI_DIR = debug
+} else {
+ OBJECTS_DIR = release
+ MOC_DIR = release
+ RCC_DIR = release
+ UI_DIR = release
+}
+
+developer {
+ include(../src/src.pri)
+} else {
+ IRC_MODULES = IrcCore IrcModel IrcUtil
+ include(../src/module_deps.pri)
+}
diff --git a/src/libcommuni/examples/examples.pro b/src/libcommuni/examples/examples.pro
new file mode 100644
index 0000000..48d9906
--- /dev/null
+++ b/src/libcommuni/examples/examples.pro
@@ -0,0 +1,13 @@
+######################################################################
+# Communi
+######################################################################
+
+TEMPLATE = subdirs
+SUBDIRS += bot client minimal
+
+!lessThan(QT_MAJOR_VERSION, 5):!lessThan(QT_MINOR_VERSION, 1) {
+ qtHaveModule(qml):SUBDIRS += qmlbot
+}
+!lessThan(QT_MAJOR_VERSION, 5):!lessThan(QT_MINOR_VERSION, 2) {
+ qtHaveModule(quick):SUBDIRS += quick
+}
diff --git a/src/libcommuni/examples/minimal/main.cpp b/src/libcommuni/examples/minimal/main.cpp
new file mode 100644
index 0000000..790280e
--- /dev/null
+++ b/src/libcommuni/examples/minimal/main.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+#include <QtCore>
+#include <IrcConnection>
+#include <IrcCommand>
+#include <Irc>
+
+#ifndef IRC_DOXYGEN
+int main(int argc, char* argv[])
+{
+ QCoreApplication app(argc, argv);
+
+ // enable debug output
+ //qputenv("IRC_DEBUG", "1");
+ qsrand(QTime::currentTime().msec());
+
+//! [minimal]
+ IrcConnection connection("irc.rbx.fr.euirc.net");
+ connection.setUserName("communi");
+ connection.setNickName(QString("Minimal%1").arg(qrand() % 9999));
+ connection.setRealName(QString("Communi %1 minimal example").arg(Irc::version()));
+ connection.sendCommand(IrcCommand::createJoin("#clonk-tod"));
+ connection.sendCommand(IrcCommand::createMessage("#clonk-tod", "Hi, kthxbye!"));
+ connection.sendCommand(IrcCommand::createQuit());
+ connection.open();
+//! [minimal]
+
+ QObject::connect(&connection, SIGNAL(disconnected()), &app, SLOT(quit()));
+ return app.exec();
+}
+#endif
diff --git a/src/libcommuni/examples/minimal/minimal.pro b/src/libcommuni/examples/minimal/minimal.pro
new file mode 100644
index 0000000..5dd8584
--- /dev/null
+++ b/src/libcommuni/examples/minimal/minimal.pro
@@ -0,0 +1,16 @@
+######################################################################
+# Communi
+######################################################################
+
+TEMPLATE = app
+TARGET = minimal
+DEPENDPATH += .
+INCLUDEPATH += .
+CONFIG += console
+CONFIG -= app_bundle
+QT = core network
+
+# Input
+SOURCES += main.cpp
+
+include(../examples.pri)
diff --git a/src/libcommuni/examples/qmlbot/main.cpp b/src/libcommuni/examples/qmlbot/main.cpp
new file mode 100644
index 0000000..d74e909
--- /dev/null
+++ b/src/libcommuni/examples/qmlbot/main.cpp
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+#include <QCoreApplication>
+#include <QQmlApplicationEngine>
+
+int main(int argc, char* argv[])
+{
+ QCoreApplication app(argc, argv);
+
+ // enable debug output
+ qputenv("IRC_DEBUG", "1");
+
+ QQmlApplicationEngine engine(QUrl("qrc:/main.qml"));
+ return app.exec();
+}
diff --git a/src/libcommuni/examples/qmlbot/qml/main.qml b/src/libcommuni/examples/qmlbot/qml/main.qml
new file mode 100644
index 0000000..2dad458
--- /dev/null
+++ b/src/libcommuni/examples/qmlbot/qml/main.qml
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+import QtQml 2.0
+import Communi 3.0
+
+QtObject {
+ id: bot
+
+ property string channel: "#communi"
+
+ property Irc irc: Irc { id: irc }
+ property IrcCommand command: IrcCommand { id: command }
+
+ property IrcBufferModel model: IrcBufferModel {
+ id: model
+
+//! [connection]
+ connection: IrcConnection {
+ id: connection
+
+ host: "irc.freenode.net"
+ userName: "communi"
+ nickName: "QmlBot" + Math.round(Math.random() * 9999)
+ realName: qsTr("Communi %1 QML bot example").arg(irc.version())
+
+ Component.onCompleted: {
+ // queue a command to automatically join a channel when connected
+ sendCommand(command.createJoin(channel))
+ open()
+ }
+//! [connection]
+
+//! [receive]
+ onMessageReceived: {
+ if (message.type === IrcMessage.Private) {
+ // - in private, reply to the message sender
+ // - on channel, reply to the target channel
+ parser.target = message.private ? message.nick : message.target
+
+ var command = parser.parse(message.content)
+ if (command) {
+ // send the command to the IRC server
+ sendCommand(command)
+ if (command.type === IrcCommand.Quit) {
+ // close the connection & quit the app when a !quit command was received
+ close()
+ Qt.quit()
+ }
+ }
+ }
+ }
+//! [receive]
+ }
+ }
+
+//! [parser]
+ property IrcCommandParser parser: IrcCommandParser {
+ id: parser
+
+ // keep the parser aware of the context
+ channels: model.channels
+
+ // - on channel, respond to: "!<command> <params>" and "bot: <command> <params>"
+ // - in query, respond to: "!<command> <params>" and "<command> <params>"
+ triggers: connection.network.isChannel(target) ? ["!", connection.nickName + ":"] : ["!", ""]
+
+ Component.onCompleted: {
+ // teach the bot some commands
+ parser.addCommand(IrcCommand.Nick, "NICK <nick>");
+ parser.addCommand(IrcCommand.Join, "JOIN <#channel> (<key>)");
+ parser.addCommand(IrcCommand.Part, "PART (<#channel>) (<message...>)");
+ parser.addCommand(IrcCommand.Quit, "QUIT (<message...>)");
+ parser.addCommand(IrcCommand.Message, "SAY [target] <message...>");
+ }
+ }
+//! [parser]
+}
diff --git a/src/libcommuni/examples/qmlbot/qmlbot.pro b/src/libcommuni/examples/qmlbot/qmlbot.pro
new file mode 100644
index 0000000..95c2961
--- /dev/null
+++ b/src/libcommuni/examples/qmlbot/qmlbot.pro
@@ -0,0 +1,22 @@
+######################################################################
+# Communi
+######################################################################
+
+TEMPLATE = app
+TARGET = qmlbot
+DEPENDPATH += .
+INCLUDEPATH += .
+CONFIG += console
+CONFIG -= app_bundle
+QT = core network qml
+
+lessThan(QT_MAJOR_VERSION, 5)|lessThan(QT_MINOR_VERSION, 1) {
+ error(The QML2 based example requires Qt 5.1 or newer but Qt $$[QT_VERSION] was detected.)
+}
+
+# Input
+SOURCES += main.cpp
+RESOURCES += qmlbot.qrc
+OTHER_FILES += qml/main.qml
+
+include(../examples.pri)
diff --git a/src/libcommuni/examples/qmlbot/qmlbot.qrc b/src/libcommuni/examples/qmlbot/qmlbot.qrc
new file mode 100644
index 0000000..5f94096
--- /dev/null
+++ b/src/libcommuni/examples/qmlbot/qmlbot.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file alias="main.qml">qml/main.qml</file>
+ </qresource>
+</RCC>
diff --git a/src/libcommuni/examples/quick/main.cpp b/src/libcommuni/examples/quick/main.cpp
new file mode 100644
index 0000000..c503b98
--- /dev/null
+++ b/src/libcommuni/examples/quick/main.cpp
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+
+int main(int argc, char* argv[])
+{
+ QGuiApplication app(argc, argv);
+ app.setOrganizationName("Commmuni");
+ app.setApplicationName("QtQuick Example");
+ QQmlApplicationEngine engine(QUrl("qrc:/main.qml"));
+ return app.exec();
+}
diff --git a/src/libcommuni/examples/quick/qml/BufferListView.qml b/src/libcommuni/examples/quick/qml/BufferListView.qml
new file mode 100644
index 0000000..3d277b6
--- /dev/null
+++ b/src/libcommuni/examples/quick/qml/BufferListView.qml
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import Communi 3.0
+
+Rectangle {
+ id: background
+
+ property alias bufferModel: listView.model
+ property IrcBuffer currentBuffer
+
+ signal closed(IrcBuffer buffer)
+
+ color: "#edf3fe"
+
+ Rectangle {
+ id: frame
+ anchors.fill: parent
+ anchors.topMargin: -1
+ color: "transparent"
+ border.color: "#aaa"
+ }
+
+ Menu {
+ id: menu
+ MenuItem {
+ text: qsTr("Close")
+ shortcut: qsTr("Ctrl+W")
+ enabled: !!currentBuffer
+ onTriggered: closed(currentBuffer)
+ }
+ }
+
+ ScrollView {
+ id: scrollView
+
+ anchors.fill: parent
+ anchors.topMargin: -1
+
+ ListView {
+ id: listView
+
+ delegate: Rectangle {
+ property bool first: index === 0
+ property bool current: model.buffer === currentBuffer
+ anchors.left: parent ? parent.left : undefined
+ anchors.right: parent ? parent.right : undefined
+ anchors.margins: 1
+ height: Math.max(21, label.implicitHeight + 5)
+ color: first ? "#ddd" : current ? "#b5d5ff" : "transparent"
+ Rectangle {
+ visible: first
+ width: parent.width
+ height: 1
+ anchors.bottom: parent.bottom
+ anchors.fill: parent
+ anchors.leftMargin: -1
+ anchors.rightMargin: -1
+ color: "transparent"
+ border.color: "#aaa"
+ }
+ Label {
+ id: label
+ text: model.title
+ font.bold: first
+ anchors.margins: 2
+ anchors.leftMargin: 6
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+ onPressed: {
+ currentBuffer = model.buffer
+ if (mouse.button === Qt.RightButton)
+ menu.popup()
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/libcommuni/examples/quick/qml/ChatPage.qml b/src/libcommuni/examples/quick/qml/ChatPage.qml
new file mode 100644
index 0000000..474b950
--- /dev/null
+++ b/src/libcommuni/examples/quick/qml/ChatPage.qml
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+import QtQuick 2.1
+import QtQuick.Layouts 1.0
+import QtQuick.Controls 1.0
+import QtQuick.Controls.Styles 1.0
+import Communi 3.0
+
+Item {
+ id: page
+
+ property IrcBuffer serverBuffer
+ property alias bufferModel: bufferListView.bufferModel
+ property alias currentBuffer: bufferListView.currentBuffer
+ property IrcChannel currentChannel: currentBuffer ? currentBuffer.toChannel() : null
+
+ Connections {
+ target: bufferModel
+ onAdded: currentBuffer = buffer
+ onAboutToBeRemoved: {
+ var idx = bufferModel.indexOf(buffer)
+ currentBuffer = bufferModel.get(idx + 1) || bufferModel.get(Math.max(0, idx - 1))
+ }
+ }
+
+ SplitView {
+ anchors.fill: parent
+
+ handleDelegate: Item { }
+
+ BufferListView {
+ id: bufferListView
+ width: page.width / 6
+ onClosed: {
+ if (buffer === serverBuffer) {
+ bufferModel.quit()
+ } else {
+ if (buffer.channel)
+ buffer.part(qsTr("Communi %1 QtQuick example").arg(irc.version()))
+ bufferModel.remove(buffer)
+ }
+ }
+ }
+
+ Column {
+ Layout.fillWidth: true
+
+ TopicLabel {
+ id: topicLabel
+ width: parent.width
+ visible: currentChannel
+ channel: currentChannel
+ }
+
+ SplitView {
+ width: parent.width
+ height: parent.height - (currentChannel ? topicLabel.height : 0) - textEntry.height
+
+ handleDelegate: Item { }
+
+ Item {
+ id: stack
+
+ width: 1; height: 1
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ Repeater {
+ anchors.fill: parent
+ model: bufferModel
+ delegate: TextBrowser {
+ anchors.fill: parent
+ buffer: model.buffer
+ visible: buffer == currentBuffer
+ }
+ }
+ }
+
+ UserListView {
+ width: page.width / 6
+ visible: currentChannel
+ channel: currentChannel
+ onQueried: currentBuffer = currentBuffer.model.add(user.name)
+ }
+ }
+
+ TextEntry {
+ id: textEntry
+ width: parent.width
+ buffer: currentBuffer
+ enabled: currentBuffer
+ onMessageSent: currentBuffer.receiveMessage(message)
+
+ Connections {
+ target: page
+ onCurrentBufferChanged: {
+ if (page.visible && currentBuffer)
+ textEntry.forceActiveFocus()
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/libcommuni/examples/quick/qml/ConnectPage.qml b/src/libcommuni/examples/quick/qml/ConnectPage.qml
new file mode 100644
index 0000000..8a7c296
--- /dev/null
+++ b/src/libcommuni/examples/quick/qml/ConnectPage.qml
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+import QtQuick 2.1
+import QtQuick.Layouts 1.0
+import QtQuick.Controls 1.0
+import Qt.labs.settings 1.0
+import Communi 3.0
+
+Item {
+ id: page
+
+ property string host: hostField.text || hostField.placeholderText
+ property int port: portField.value
+ property bool secure: secureField.checked
+ property bool sasl: saslField.checked
+ property string nickName: nickNameField.text || nickNameField.placeholderText
+ property string realName: realNameField.text || realNameField.placeholderText
+ property string userName: userNameField.text || userNameField.placeholderText
+ property string password: passwordField.text
+ property string channel: channelField.text || channelField.placeholderText
+
+ Settings {
+ id: settings
+ property alias host: hostField.text
+ property alias port: portField.value
+ property alias secure: secureField.checked
+ property alias sasl: saslField.checked
+ property alias nickName: nickNameField.text
+ property alias realName: realNameField.text
+ property alias userName: userNameField.text
+ property alias password: passwordField.text
+ property alias channel: channelField.text
+ }
+
+ signal accepted()
+ signal rejected()
+
+ implicitWidth: grid.implicitWidth + row.implicitWidth
+ implicitHeight: grid.implicitHeight + row.implicitHeight + 48
+
+ GridLayout {
+ id: grid
+
+ width: page.width * 2 / 3
+ anchors.centerIn: parent
+ anchors.verticalCenterOffset: -row.height + 12
+
+ columns: 2
+ rowSpacing: 12
+ columnSpacing: 12
+
+ Label { text: qsTr("Host:") }
+ TextField {
+ id: hostField
+ focus: true
+ Layout.fillWidth: true
+ placeholderText: "irc.freenode.net"
+ }
+
+ Label { text: qsTr("Port:") }
+ RowLayout {
+ SpinBox {
+ id: portField
+ value: 6667
+ minimumValue: 1024
+ maximumValue: 65535
+ Layout.fillWidth: true
+ }
+ CheckBox {
+ id: secureField
+ text: qsTr("SSL")
+ }
+ CheckBox {
+ id: saslField
+ text: qsTr("SASL")
+ }
+ }
+
+ Label { text: qsTr("Nick name:") }
+ TextField {
+ id: nickNameField
+ Layout.fillWidth: true
+ placeholderText: "Quick" + Math.round(Math.random() * 9999)
+ }
+
+ Label { text: qsTr("Real name:") }
+ TextField {
+ id: realNameField
+ Layout.fillWidth: true
+ placeholderText: qsTr("Communi %1 QtQuick example").arg(irc.version())
+ }
+
+ Label { text: qsTr("User name:") }
+ TextField {
+ id: userNameField
+ Layout.fillWidth: true
+ placeholderText: "communi"
+ }
+
+ Label { text: qsTr("Password:") }
+ TextField {
+ id: passwordField
+ echoMode: TextInput.Password
+ Layout.fillWidth: true
+ }
+
+ Label { text: qsTr("Channel:") }
+ TextField {
+ id: channelField
+ Layout.fillWidth: true
+ placeholderText: "#communi"
+ }
+ }
+
+ Keys.onReturnPressed: {
+ if (okButton.enabled)
+ page.accepted()
+ }
+
+ Keys.onEnterPressed: {
+ if (okButton.enabled)
+ page.accepted()
+ }
+
+ Keys.onEscapePressed: {
+ if (cancelButton.enabled)
+ page.rejected()
+ }
+
+ RowLayout {
+ id: row
+
+ anchors.margins: 12
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+
+ Item { Layout.fillWidth: true }
+
+ Button {
+ id: okButton
+ text: qsTr("Ok")
+ enabled: page.visible
+ onClicked: page.accepted()
+ }
+
+ Button {
+ id: cancelButton
+ text: qsTr("Cancel")
+ onClicked: page.rejected()
+ }
+ }
+}
diff --git a/src/libcommuni/examples/quick/qml/MessageFormatter.qml b/src/libcommuni/examples/quick/qml/MessageFormatter.qml
new file mode 100644
index 0000000..754ca1c
--- /dev/null
+++ b/src/libcommuni/examples/quick/qml/MessageFormatter.qml
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+import QtQuick 2.1
+import Communi 3.0
+
+QtObject {
+ id: root
+
+ property IrcTextFormat textFormat: IrcTextFormat {
+ id: textFormat
+
+ palette.gray: "#606060"
+ palette.lightGray: "#808080"
+
+ // http://ethanschoonover.com/solarized
+ palette.blue: "#268bd2"
+ palette.green: "#859900"
+ palette.red: "#dc322f"
+ palette.brown: "#cb4b16"
+ palette.purple: "#6c71c4"
+ palette.orange: "#cb4b16"
+ palette.yellow: "#b58900"
+ palette.lightGreen: "#859900"
+ palette.cyan: "#2aa198"
+ palette.lightCyan: "#2aa198"
+ palette.lightBlue: "#268bd2"
+ palette.pink: "#6c71c4"
+ }
+
+ function formatMessage(message) {
+ var formatted
+ switch (message.type) {
+ case IrcMessage.Invite: formatted = formatInviteMessage(message); break
+ case IrcMessage.Join: formatted = formatJoinMessage(message); break
+ case IrcMessage.Kick: formatted = formatKickMessage(message); break
+ case IrcMessage.Mode: formatted = formatModeMessage(message); break
+ case IrcMessage.Names: formatted = formatNamesMessage(message); break
+ case IrcMessage.Nick: formatted = formatNickMessage(message); break
+ case IrcMessage.Notice: formatted = formatNoticeMessage(message); break
+ case IrcMessage.Numeric: formatted = formatNumericMessage(message); break
+ case IrcMessage.Part: formatted = formatPartMessage(message); break
+ case IrcMessage.Private: formatted = formatPrivateMessage(message); break
+ case IrcMessage.Quit: formatted = formatQuitMessage(message); break
+ case IrcMessage.Topic: formatted = formatTopicMessage(message); break
+ }
+ return formatText(formatted, message.timeStamp)
+ }
+
+ function formatText(text, timeStamp) {
+ if (text) {
+ switch (text[0]) {
+ case '!': text = qsTr("<font color='gray'>%1</font>").arg(text); break;
+ case '[': text = qsTr("<font color='brown'>%1</font>").arg(text); break;
+ case '*': text = qsTr("<font color='darkmagenta'>%1</font>").arg(text); break;
+ case '?': text = qsTr("<font color='brown'>%1</font>").arg(text); break;
+ default: break;
+ }
+
+ return qsTr("<font color='gray'>[%1]</font> %2").arg(Qt.formatTime(timeStamp, "hh:mm:ss")).arg(text)
+ }
+ }
+
+ function formatInviteMessage(message) {
+ var sender = formatName(message.nick)
+ return qsTr("! %1 invited to %3").arg(sender).arg(message.channel)
+ }
+
+ function formatJoinMessage(message) {
+ var sender = formatName(message.nick)
+ return qsTr("! %1 joined %2").arg(sender).arg(message.channel)
+ }
+
+ function formatKickMessage(message) {
+ var sender = formatName(message.nick)
+ var user = formatName(message.user)
+ if (message.reason.length)
+ return qsTr("! %1 kicked %2 (%3)").arg(sender).arg(user).arg(message.reason)
+ return qsTr("! %1 kicked %2").arg(sender).arg(user)
+ }
+
+ function formatModeMessage(message) {
+ var sender = formatName(message.nick)
+ if (message.reply)
+ return qsTr("! %1 mode is %2 %3").arg(message.target).arg(message.mode).arg(message.argument)
+ return qsTr("! %1 sets mode %2 %3").arg(sender).arg(message.mode).arg(message.argument)
+ }
+
+ function formatNamesMessage(message) {
+ return qsTr("! %1 has %2 users").arg(message.channel).arg(message.names.length)
+ }
+
+ function formatNickMessage(message) {
+ var sender = formatName(message.nick)
+ var nick = formatName(message.newNick)
+ return qsTr("! %1 changed nick to %2").arg(sender).arg(nick)
+ }
+
+ function formatNoticeMessage(message) {
+ var sender = formatName(message.nick)
+ var content = formatHtml(message.content)
+ return qsTr("[%1] %2").arg(sender).arg(content)
+ }
+
+ function formatNumericMessage(message) {
+ switch (message.code) {
+ case Irc.RPL_TOPIC:
+ case Irc.RPL_TOPICWHOTIME:
+ case Irc.RPL_CHANNEL_URL:
+ case Irc.RPL_NAMREPLY:
+ case Irc.RPL_ENDOFNAMES:
+ return // ignore
+ default:
+ return qsTr("[%1] %2").arg(message.code).arg(message.parameters.slice(1).join(" "))
+ }
+ }
+
+ function formatPartMessage(message) {
+ var sender = formatName(message.nick)
+ if (message.reason.length)
+ return qsTr("! %1 parted %2 (%3)").arg(sender).arg(message.channel).arg(formatHtml(message.reason))
+ return qsTr("! %1 parted %2").arg(sender).arg(message.channel)
+ }
+
+ function formatPrivateMessage(message) {
+ var sender = formatName(message.nick)
+ var content = formatHtml(message.content)
+ if (message.action)
+ return qsTr("* %1 %2").arg(sender).arg(content)
+ if (message.request)
+ return qsTr("! %1 requested %2").arg(sender).arg(content.split(" ")[0].toLowerCase())
+ return qsTr("&lt;%1&gt; %2").arg(sender).arg(content)
+ }
+
+ function formatQuitMessage(message) {
+ var sender = formatName(message.nick)
+ if (message.reason.length)
+ return qsTr("! %1 has quit (%2)").arg(sender).arg(formatHtml(message.reason))
+ return qsTr("! %1 has quit").arg(sender)
+ }
+
+ function formatTopicMessage(message) {
+ var sender = formatName(message.nick)
+ var topic = formatHtml(message.topic)
+ var channel = message.channel
+ if (message.reply)
+ return qsTr("! %1 topic is \"%2\"").arg(channel).arg(topic)
+ return qsTr("! %1 sets topic \"%2\" on %3").arg(sender).arg(topic).arg(channel)
+ }
+
+ function formatHtml(message) {
+ return textFormat.toHtml(message)
+ }
+
+ function formatName(name) {
+ var color = hslToRgb((hashCode(name) % 359)/359, 0.5, 0.25)
+ var r = ("0" + Math.round(Math.abs(color[0])).toString(16)).substr(-2)
+ var g = ("0" + Math.round(Math.abs(color[1])).toString(16)).substr(-2)
+ var b = ("0" + Math.round(Math.abs(color[2])).toString(16)).substr(-2)
+ return qsTr("<b><font color='#%1'>%2</font></b>").arg(r+g+b).arg(name);
+ }
+
+ function hashCode(str) {
+ var hash = 0;
+ if (str.length == 0) return hash;
+ for (var i = 0; i < str.length; i++) {
+ var chr = str.charCodeAt(i);
+ hash = ((hash<<5)-hash)+chr;
+ hash = hash & hash; // Convert to 32bit integer
+ }
+ return hash;
+ }
+
+ /**
+ * Converts an HSL color value to RGB. Conversion formula
+ * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
+ * Assumes h, s, and l are contained in the set [0, 1] and
+ * returns r, g, and b in the set [0, 255].
+ *
+ * @param Number h The hue
+ * @param Number s The saturation
+ * @param Number l The lightness
+ * @return Array The RGB representation
+ */
+ function hslToRgb(h, s, l){
+ var r, g, b;
+
+ function hue2rgb(p, q, t){
+ if(t < 0) t += 1;
+ if(t > 1) t -= 1;
+ if(t < 1/6) return p + (q - p) * 6 * t;
+ if(t < 1/2) return q;
+ if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
+ return p;
+ }
+
+ if(s == 0){
+ r = g = b = l; // achromatic
+ }else{
+ var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+ var p = 2 * l - q;
+ r = hue2rgb(p, q, h + 1/3);
+ g = hue2rgb(p, q, h);
+ b = hue2rgb(p, q, h - 1/3);
+ }
+
+ return [r * 255, g * 255, b * 255];
+ }
+}
diff --git a/src/libcommuni/examples/quick/qml/TextBrowser.qml b/src/libcommuni/examples/quick/qml/TextBrowser.qml
new file mode 100644
index 0000000..fb013bc
--- /dev/null
+++ b/src/libcommuni/examples/quick/qml/TextBrowser.qml
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import Communi 3.0
+
+Item {
+ id: background
+
+ property IrcBuffer buffer
+
+ implicitWidth: textArea.implicitWidth
+ implicitHeight: textArea.implicitHeight
+
+ MessageFormatter {
+ id: formatter
+ }
+
+ Connections {
+ target: buffer
+ onMessageReceived: {
+ var line = formatter.formatMessage(message)
+ if (line)
+ textArea.append(line)
+ }
+ }
+
+ TextArea {
+ id: textArea
+
+ anchors.fill: parent
+ anchors.topMargin: -1
+ anchors.leftMargin: -1
+ anchors.bottomMargin: -1
+
+ readOnly: true
+ textFormat: Qt.RichText
+ frameVisible: false
+ }
+}
diff --git a/src/libcommuni/examples/quick/qml/TextEntry.qml b/src/libcommuni/examples/quick/qml/TextEntry.qml
new file mode 100644
index 0000000..4201e86
--- /dev/null
+++ b/src/libcommuni/examples/quick/qml/TextEntry.qml
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import QtQuick.Controls.Styles 1.0
+import Communi 3.1
+
+TextField {
+ id: textField
+
+ property alias buffer: completer.buffer
+
+ signal messageSent(IrcMessage message)
+
+ focus: true
+ placeholderText: qsTr("...")
+
+ Keys.onTabPressed: completer.complete(text, cursorPosition)
+
+ IrcCompleter {
+ id: completer
+
+ onCompleted: {
+ textField.text = text
+ textField.cursorPosition = cursor
+ }
+
+ parser: IrcCommandParser {
+ id: parser
+
+ tolerant: true
+ triggers: ["/"]
+ channels: buffer ? buffer.model.channels : []
+ target: buffer ? buffer.title : ""
+
+ Component.onCompleted: {
+ parser.addCommand(IrcCommand.Join, "JOIN <#channel> (<key>)")
+ parser.addCommand(IrcCommand.CtcpAction, "ME [target] <message...>")
+ parser.addCommand(IrcCommand.Nick, "NICK <nick>")
+ parser.addCommand(IrcCommand.Part, "PART (<#channel>) (<message...>)")
+ }
+ }
+ }
+
+ style: TextFieldStyle {
+ background: Rectangle {
+ color: palette.base
+ Rectangle {
+ color: "transparent"
+ anchors.fill: parent
+ anchors.leftMargin: -1
+ border.color: "#aaa"
+ }
+ }
+ }
+
+ onAccepted: {
+ var cmd = parser.parse(text)
+ if (cmd) {
+ buffer.connection.sendCommand(cmd)
+ if (cmd.type === IrcCommand.Message
+ || cmd.type === IrcCommand.CtcpAction
+ || cmd.type === IrcCommand.Notice) {
+ var msg = cmd.toMessage(buffer.connection.nickName, buffer.connection)
+ textField.messageSent(msg)
+ }
+ textField.text = ""
+ }
+ }
+}
diff --git a/src/libcommuni/examples/quick/qml/TopicLabel.qml b/src/libcommuni/examples/quick/qml/TopicLabel.qml
new file mode 100644
index 0000000..4009304
--- /dev/null
+++ b/src/libcommuni/examples/quick/qml/TopicLabel.qml
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import Communi 3.0
+
+Rectangle {
+ id: background
+
+ property IrcChannel channel
+
+ color: "#ddd"
+ height: Math.max(20, label.implicitHeight + 4)
+
+ IrcTextFormat {
+ id: textFormat
+ }
+
+ Label {
+ id: label
+
+ anchors.margins: 2
+ anchors.leftMargin: 4
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+
+ wrapMode: Text.Wrap
+ text: channel && channel.topic ? textFormat.toHtml(channel.topic) : "-"
+ }
+
+ Rectangle {
+ id: frame
+
+ color: "transparent"
+ anchors.fill: parent
+ anchors.topMargin: -1
+ anchors.leftMargin: -1
+ border.color: "#aaa"
+ }
+}
diff --git a/src/libcommuni/examples/quick/qml/UserListView.qml b/src/libcommuni/examples/quick/qml/UserListView.qml
new file mode 100644
index 0000000..6daf06b
--- /dev/null
+++ b/src/libcommuni/examples/quick/qml/UserListView.qml
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import Communi 3.0
+
+Rectangle {
+ id: background
+
+ property IrcChannel channel
+
+ signal queried(IrcUser user)
+
+ color: "#edf3fe"
+
+ Rectangle {
+ id: frame
+ anchors.fill: parent
+ color: "transparent"
+ border.color: "#aaa"
+ anchors.topMargin: -1
+ anchors.leftMargin: -1
+ anchors.bottomMargin: -1
+ }
+
+ ScrollView {
+ id: scrollView
+
+ anchors.fill: parent
+ anchors.topMargin: -1
+ anchors.bottomMargin: -1
+
+ ListView {
+ id: listView
+
+ model: IrcUserModel {
+ id: userModel
+ sortMethod: Irc.SortByTitle
+ channel: background.channel
+ onChannelChanged: listView.currentIndex = -1
+ }
+
+ delegate: Rectangle {
+ width: parent.width
+ height: Math.max(20, label.implicitHeight + 4)
+ color: ListView.isCurrentItem ? "#b5d5ff" : "transparent"
+ Label {
+ id: label
+ text: model.title
+ anchors.margins: 2
+ anchors.leftMargin: 6
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ MouseArea {
+ anchors.fill: parent
+ onPressed: listView.currentIndex = index
+ onDoubleClicked: queried(model.user)
+ }
+ }
+ }
+ }
+}
diff --git a/src/libcommuni/examples/quick/qml/main.qml b/src/libcommuni/examples/quick/qml/main.qml
new file mode 100644
index 0000000..8c431ad
--- /dev/null
+++ b/src/libcommuni/examples/quick/qml/main.qml
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2008-2014 The Communi Project
+ *
+ * This example is free, and not covered by the BSD license. There is no
+ * restriction applied to their modification, redistribution, using and so on.
+ * You can study them, modify them, use them in your own program - either
+ * completely or partially.
+ */
+
+import QtQuick 2.1
+import QtQuick.Controls 1.0
+import Communi 3.0
+
+ApplicationWindow {
+ id: window
+
+ visible: true
+ title: qsTr("Communi %1 QtQuick example").arg(irc.version())
+
+ width: 800
+ height: 480
+
+ minimumWidth: connectPage.implicitWidth
+ minimumHeight: connectPage.implicitHeight
+
+ color: Qt.darker(palette.base, 1.06)
+
+ SystemPalette { id: palette }
+
+ Irc { id: irc }
+ IrcCommand { id: cmd }
+
+ ConnectPage {
+ id: connectPage
+ anchors.fill: parent
+ visible: !connection.active
+ onAccepted: {
+ chatPage.currentBuffer = serverBuffer
+ connection.sendCommand(cmd.createJoin(channel))
+ connection.open()
+ }
+ onRejected: Qt.quit()
+ }
+
+ ChatPage {
+ id: chatPage
+ anchors.fill: parent
+ visible: connection.active
+ bufferModel: IrcBufferModel {
+ id: bufferModel
+ sortMethod: Irc.SortByTitle
+ connection: IrcConnection {
+ id: connection
+ host: connectPage.host
+ port: connectPage.port
+ secure: connectPage.secure
+ saslMechanism: connectPage.sasl ? supportedSaslMechanisms[0] : ""
+ nickName: connectPage.nickName
+ realName: connectPage.realName
+ userName: connectPage.userName
+ password: connectPage.password
+ }
+ onMessageIgnored: serverBuffer.receiveMessage(message)
+ function quit() {
+ bufferModel.clear()
+ connection.quit(qsTr("Communi %1 QtQuick example").arg(irc.version()))
+ connection.close()
+ }
+ }
+ serverBuffer: IrcBuffer {
+ id: serverBuffer
+ sticky: true
+ persistent: true
+ name: connection.displayName
+ Component.onCompleted: bufferModel.add(serverBuffer)
+ }
+ }
+
+ Component.onDestruction: bufferModel.quit()
+}
diff --git a/src/libcommuni/examples/quick/quick.pro b/src/libcommuni/examples/quick/quick.pro
new file mode 100644
index 0000000..10690af
--- /dev/null
+++ b/src/libcommuni/examples/quick/quick.pro
@@ -0,0 +1,28 @@
+######################################################################
+# Communi
+######################################################################
+
+TEMPLATE = app
+TARGET = quick
+DEPENDPATH += .
+INCLUDEPATH += .
+QT += network quick
+
+lessThan(QT_MAJOR_VERSION, 5)|lessThan(QT_MINOR_VERSION, 2) {
+ error(The Qt Quick 2 based example requires Qt 5.2 or newer but Qt $$[QT_VERSION] was detected.)
+}
+
+# Input
+SOURCES += main.cpp
+RESOURCES += quick.qrc
+OTHER_FILES += qml/main.qml
+OTHER_FILES += qml/BufferListView.qml
+OTHER_FILES += qml/ChatPage.qml
+OTHER_FILES += qml/ConnectPage.qml
+OTHER_FILES += qml/MessageFormatter.qml
+OTHER_FILES += qml/TextBrowser.qml
+OTHER_FILES += qml/TextEntry.qml
+OTHER_FILES += qml/TopicLabel.qml
+OTHER_FILES += qml/UserListView.qml
+
+include(../examples.pri)
diff --git a/src/libcommuni/examples/quick/quick.qrc b/src/libcommuni/examples/quick/quick.qrc
new file mode 100644
index 0000000..aba83b9
--- /dev/null
+++ b/src/libcommuni/examples/quick/quick.qrc
@@ -0,0 +1,13 @@
+<RCC>
+ <qresource prefix="/">
+ <file alias="main.qml">qml/main.qml</file>
+ <file alias="BufferListView.qml">qml/BufferListView.qml</file>
+ <file alias="ChatPage.qml">qml/ChatPage.qml</file>
+ <file alias="ConnectPage.qml">qml/ConnectPage.qml</file>
+ <file alias="MessageFormatter.qml">qml/MessageFormatter.qml</file>
+ <file alias="TextBrowser.qml">qml/TextBrowser.qml</file>
+ <file alias="TextEntry.qml">qml/TextEntry.qml</file>
+ <file alias="TopicLabel.qml">qml/TopicLabel.qml</file>
+ <file alias="UserListView.qml">qml/UserListView.qml</file>
+ </qresource>
+</RCC>