diff options
| author | Markus Mittendrein <git@maxmitti.tk> | 2015-09-09 19:00:56 +0200 |
|---|---|---|
| committer | Markus Mittendrein <git@maxmitti.tk> | 2015-09-09 19:02:23 +0200 |
| commit | 8a6d4b06f2291c363f3dea17837ed20893852453 (patch) | |
| tree | c091375499e35eaa1810586454e0834c06e6c9b2 /src/libcommuni/examples/client | |
| parent | f554a27046f203e56a07baaf214d90834942e3f5 (diff) | |
| download | manager-8a6d4b06f2291c363f3dea17837ed20893852453.tar.gz manager-8a6d4b06f2291c363f3dea17837ed20893852453.zip | |
Cleanup repo with some directories
Diffstat (limited to 'src/libcommuni/examples/client')
| -rw-r--r-- | src/libcommuni/examples/client/client.pro | 16 | ||||
| -rw-r--r-- | src/libcommuni/examples/client/ircclient.cpp | 321 | ||||
| -rw-r--r-- | src/libcommuni/examples/client/ircclient.h | 78 | ||||
| -rw-r--r-- | src/libcommuni/examples/client/ircmessageformatter.cpp | 113 | ||||
| -rw-r--r-- | src/libcommuni/examples/client/ircmessageformatter.h | 31 | ||||
| -rw-r--r-- | src/libcommuni/examples/client/main.cpp | 20 |
6 files changed, 579 insertions, 0 deletions
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("<", "<").replace(">", ">")); + 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("<%1> %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(); +} |
