Wt examples
3.2.2
|
A self-contained chat widget. More...
#include <SimpleChatWidget.h>
Public Member Functions | |
SimpleChatWidget (SimpleChatServer &server, Wt::WContainerWidget *parent=0) | |
Create a chat widget that will connect to the given server. | |
~SimpleChatWidget () | |
Delete a chat widget. | |
void | connect () |
void | disconnect () |
void | letLogin () |
Show a simple login screen. | |
bool | startChat (const Wt::WString &user) |
Start a chat for the given user. | |
void | logout () |
SimpleChatServer & | server () |
int | userCount () |
const Wt::WString & | userName () const |
Protected Member Functions | |
virtual void | createLayout (Wt::WWidget *messages, Wt::WWidget *userList, Wt::WWidget *messageEdit, Wt::WWidget *sendButton, Wt::WWidget *logoutButton) |
virtual void | updateUsers () |
virtual void | newMessage () |
virtual void | render (Wt::WFlags< Wt::RenderFlag > flags) |
bool | loggedIn () const |
Private Types | |
typedef std::map< Wt::WString, bool > | UserMap |
Private Member Functions | |
void | login () |
void | send () |
void | updateUser () |
void | processChatEvent (const ChatEvent &event) |
Private Attributes | |
UserMap | users_ |
SimpleChatServer & | server_ |
bool | loggedIn_ |
Wt::JSlot | clearInput_ |
Wt::WString | user_ |
Wt::WLineEdit * | userNameEdit_ |
Wt::WText * | statusMsg_ |
Wt::WContainerWidget * | messages_ |
Wt::WContainerWidget * | messageEditArea_ |
Wt::WTextArea * | messageEdit_ |
Wt::WPushButton * | sendButton_ |
Wt::WContainerWidget * | userList_ |
Wt::WSound * | messageReceived_ |
A self-contained chat widget.
Definition at line 34 of file SimpleChatWidget.h.
typedef std::map<Wt::WString, bool> SimpleChatWidget::UserMap [private] |
Definition at line 82 of file SimpleChatWidget.h.
SimpleChatWidget::SimpleChatWidget | ( | SimpleChatServer & | server, |
Wt::WContainerWidget * | parent = 0 |
||
) |
Create a chat widget that will connect to the given server.
Definition at line 26 of file SimpleChatWidget.C.
: WContainerWidget(parent), server_(server), loggedIn_(false), userList_(0), messageReceived_(0) { user_ = server_.suggestGuest(); letLogin(); }
SimpleChatWidget::~SimpleChatWidget | ( | ) |
Delete a chat widget.
Definition at line 38 of file SimpleChatWidget.C.
{ delete messageReceived_; logout(); disconnect(); }
void SimpleChatWidget::connect | ( | ) |
Definition at line 45 of file SimpleChatWidget.C.
{ if (server_.connect (this, boost::bind(&SimpleChatWidget::processChatEvent, this, _1))) Wt::WApplication::instance()->enableUpdates(true); }
void SimpleChatWidget::createLayout | ( | Wt::WWidget * | messages, |
Wt::WWidget * | userList, | ||
Wt::WWidget * | messageEdit, | ||
Wt::WWidget * | sendButton, | ||
Wt::WWidget * | logoutButton | ||
) | [protected, virtual] |
Reimplemented in PopupChatWidget.
Definition at line 108 of file SimpleChatWidget.C.
{ /* * Create a vertical layout, which will hold 3 rows, * organized like this: * * WVBoxLayout * -------------------------------------------- * | nested WHBoxLayout (vertical stretch=1) | * | | | * | messages | userList | * | (horizontal stretch=1) | | * | | | * -------------------------------------------- * | message edit area | * -------------------------------------------- * | WHBoxLayout | * | send | logout | * -------------------------------------------- */ WVBoxLayout *vLayout = new WVBoxLayout(); // Create a horizontal layout for the messages | userslist. WHBoxLayout *hLayout = new WHBoxLayout(); // Add widget to horizontal layout with stretch = 1 hLayout->addWidget(messages, 1); messages->setStyleClass("chat-msgs"); // Add another widget to horizontal layout with stretch = 0 hLayout->addWidget(userList); userList->setStyleClass("chat-users"); hLayout->setResizable(0, true); // Add nested layout to vertical layout with stretch = 1 vLayout->addLayout(hLayout, 1); // Add widget to vertical layout with stretch = 0 vLayout->addWidget(messageEdit); messageEdit->setStyleClass("chat-noedit"); // Create a horizontal layout for the buttons. hLayout = new WHBoxLayout(); // Add button to horizontal layout with stretch = 0 hLayout->addWidget(sendButton); // Add button to horizontal layout with stretch = 0 hLayout->addWidget(logoutButton); // Add nested layout to vertical layout with stretch = 0 vLayout->addLayout(hLayout, 0, AlignLeft); setLayout(vLayout); }
void SimpleChatWidget::disconnect | ( | ) |
Definition at line 52 of file SimpleChatWidget.C.
{ if (server_.disconnect(this)) Wt::WApplication::instance()->enableUpdates(false); }
void SimpleChatWidget::letLogin | ( | ) |
Show a simple login screen.
Definition at line 58 of file SimpleChatWidget.C.
{ disconnect(); clear(); WVBoxLayout *vLayout = new WVBoxLayout(); setLayout(vLayout); WHBoxLayout *hLayout = new WHBoxLayout(); vLayout->addLayout(hLayout, 0, AlignTop | AlignLeft); hLayout->addWidget(new WLabel("User name:"), 0, AlignMiddle); hLayout->addWidget(userNameEdit_ = new WLineEdit(user_), 0, AlignMiddle); userNameEdit_->setFocus(); WPushButton *b = new WPushButton("Login"); hLayout->addWidget(b, 0, AlignMiddle); b->clicked().connect(this, &SimpleChatWidget::login); userNameEdit_->enterPressed().connect(this, &SimpleChatWidget::login); vLayout->addWidget(statusMsg_ = new WText()); statusMsg_->setTextFormat(PlainText); }
bool SimpleChatWidget::loggedIn | ( | ) | const [protected] |
Definition at line 167 of file SimpleChatWidget.C.
{ return loggedIn_; }
void SimpleChatWidget::login | ( | ) | [private] |
Definition at line 84 of file SimpleChatWidget.C.
{ if (!loggedIn()) { WString name = userNameEdit_->text(); if (!messageReceived_) messageReceived_ = new WSound("sounds/message_received.mp3"); if (!startChat(name)) statusMsg_->setText("Sorry, name '" + escapeText(name) + "' is already taken."); } }
void SimpleChatWidget::logout | ( | ) |
void SimpleChatWidget::newMessage | ( | ) | [protected, virtual] |
void SimpleChatWidget::processChatEvent | ( | const ChatEvent & | event | ) | [private] |
Definition at line 319 of file SimpleChatWidget.C.
{ WApplication *app = WApplication::instance(); /* * This is where the "server-push" happens. The chat server posts to this * event from other sessions, see SimpleChatServer::postChatEvent() */ /* * Format and append the line to the conversation. * * This is also the step where the automatic XSS filtering will kick in: * - if another user tried to pass on some JavaScript, it is filtered away. * - if another user did not provide valid XHTML, the text is automatically * interpreted as PlainText */ /* * If it is not a plain message, also update the user list. */ if (event.type() != ChatEvent::Message) { if (event.type() == ChatEvent::Rename && event.user() == user_) user_ = event.data(); updateUsers(); } newMessage(); /* * Anything else doesn't matter if we are not logged in. */ if (!loggedIn()) { app->triggerUpdate(); return; } bool display = event.type() != ChatEvent::Message || !userList_ || (users_.find(event.user()) != users_.end() && users_[event.user()]); if (display) { WText *w = new WText(messages_); /* * If it fails, it is because the content wasn't valid XHTML */ if (!w->setText(event.formattedHTML(user_, XHTMLText))) { w->setText(event.formattedHTML(user_, PlainText)); w->setTextFormat(XHTMLText); } w->setInline(false); w->setStyleClass("chat-msg"); /* * Leave no more than 100 messages in the back-log */ if (messages_->count() > 100) delete messages_->children()[0]; /* * Little javascript trick to make sure we scroll along with new content */ app->doJavaScript(messages_->jsRef() + ".scrollTop += " + messages_->jsRef() + ".scrollHeight;"); /* If this message belongs to another user, play a received sound */ if (event.user() != user_ && messageReceived_) messageReceived_->play(); } /* * This is the server push action: we propagate the updated UI to the client, * (when the event was triggered by another user) */ app->triggerUpdate(); }
void SimpleChatWidget::render | ( | Wt::WFlags< Wt::RenderFlag > | flags | ) | [protected, virtual] |
Definition at line 172 of file SimpleChatWidget.C.
{ if (flags & RenderFull) { if (loggedIn()) { /* Handle a page refresh correctly */ messageEdit_->setText(WString::Empty); doJavaScript("setTimeout(function() { " + messages_->jsRef() + ".scrollTop += " + messages_->jsRef() + ".scrollHeight;}, 0);"); } } WContainerWidget::render(flags); }
void SimpleChatWidget::send | ( | ) | [private] |
Definition at line 274 of file SimpleChatWidget.C.
{ if (!messageEdit_->text().empty()) server_.sendMessage(user_, messageEdit_->text()); }
SimpleChatServer& SimpleChatWidget::server | ( | ) | [inline] |
Definition at line 62 of file SimpleChatWidget.h.
{ return server_; }
bool SimpleChatWidget::startChat | ( | const Wt::WString & | user | ) |
Start a chat for the given user.
Returns false if the user could not login.
Definition at line 187 of file SimpleChatWidget.C.
{ /* * When logging in, we pass our processChatEvent method as the function that * is used to indicate a new chat event for this user. */ if (server_.login(user)) { loggedIn_ = true; connect(); user_ = user; clear(); userNameEdit_ = 0; messages_ = new WContainerWidget(); userList_ = new WContainerWidget(); messageEdit_ = new WTextArea(); messageEdit_->setRows(2); messageEdit_->setFocus(); // Display scroll bars if contents overflows messages_->setOverflow(WContainerWidget::OverflowAuto); userList_->setOverflow(WContainerWidget::OverflowAuto); sendButton_ = new WPushButton("Send"); WPushButton *logoutButton = new WPushButton("Logout"); createLayout(messages_, userList_, messageEdit_, sendButton_, logoutButton); /* * Connect event handlers: * - click on button * - enter in text area * * We will clear the input field using a small custom client-side * JavaScript invocation. */ // Create a JavaScript 'slot' (JSlot). The JavaScript slot always takes // 2 arguments: the originator of the event (in our case the // button or text area), and the JavaScript event object. clearInput_.setJavaScript ("function(o, e) { setTimeout(function() {" "" + messageEdit_->jsRef() + ".value='';" "}, 0); }"); // Bind the C++ and JavaScript event handlers. sendButton_->clicked().connect(this, &SimpleChatWidget::send); messageEdit_->enterPressed().connect(this, &SimpleChatWidget::send); sendButton_->clicked().connect(clearInput_); messageEdit_->enterPressed().connect(clearInput_); sendButton_->clicked().connect(messageEdit_, &WLineEdit::setFocus); messageEdit_->enterPressed().connect(messageEdit_, &WLineEdit::setFocus); // Prevent the enter from generating a new line, which is its default // action messageEdit_->enterPressed().preventDefaultAction(); logoutButton->clicked().connect(this, &SimpleChatWidget::logout); WText *msg = new WText ("<div><span class='chat-info'>You are joining as " + escapeText(user_) + ".</span></div>", messages_); msg->setStyleClass("chat-msg"); if (!userList_->parent()) { delete userList_; userList_ = 0; } if (!sendButton_->parent()) { delete sendButton_; sendButton_ = 0; } if (!logoutButton->parent()) delete logoutButton; updateUsers(); return true; } else return false; }
void SimpleChatWidget::updateUser | ( | ) | [private] |
void SimpleChatWidget::updateUsers | ( | ) | [protected, virtual] |
Reimplemented in PopupChatWidget.
Definition at line 280 of file SimpleChatWidget.C.
{ if (userList_) { userList_->clear(); SimpleChatServer::UserSet users = server_.users(); UserMap oldUsers = users_; users_.clear(); for (SimpleChatServer::UserSet::iterator i = users.begin(); i != users.end(); ++i) { WCheckBox *w = new WCheckBox(escapeText(*i), userList_); w->setInline(false); UserMap::const_iterator j = oldUsers.find(*i); if (j != oldUsers.end()) w->setChecked(j->second); else w->setChecked(true); users_[*i] = w->isChecked(); w->changed().connect(this, &SimpleChatWidget::updateUser); if (*i == user_) w->setStyleClass("chat-self"); } } }
int SimpleChatWidget::userCount | ( | ) | [inline] |
Definition at line 64 of file SimpleChatWidget.h.
{ return users_.size(); }
const Wt::WString& SimpleChatWidget::userName | ( | ) | const [inline] |
Definition at line 66 of file SimpleChatWidget.h.
{ return user_; }
Wt::JSlot SimpleChatWidget::clearInput_ [private] |
Definition at line 88 of file SimpleChatWidget.h.
bool SimpleChatWidget::loggedIn_ [private] |
Definition at line 86 of file SimpleChatWidget.h.
Wt::WTextArea* SimpleChatWidget::messageEdit_ [private] |
Definition at line 97 of file SimpleChatWidget.h.
Definition at line 96 of file SimpleChatWidget.h.
Wt::WSound* SimpleChatWidget::messageReceived_ [private] |
Definition at line 101 of file SimpleChatWidget.h.
Wt::WContainerWidget* SimpleChatWidget::messages_ [private] |
Definition at line 95 of file SimpleChatWidget.h.
Wt::WPushButton* SimpleChatWidget::sendButton_ [private] |
Definition at line 98 of file SimpleChatWidget.h.
SimpleChatServer& SimpleChatWidget::server_ [private] |
Definition at line 85 of file SimpleChatWidget.h.
Wt::WText* SimpleChatWidget::statusMsg_ [private] |
Definition at line 93 of file SimpleChatWidget.h.
Wt::WString SimpleChatWidget::user_ [private] |
Definition at line 90 of file SimpleChatWidget.h.
Wt::WContainerWidget* SimpleChatWidget::userList_ [private] |
Definition at line 99 of file SimpleChatWidget.h.
Wt::WLineEdit* SimpleChatWidget::userNameEdit_ [private] |
Definition at line 92 of file SimpleChatWidget.h.
UserMap SimpleChatWidget::users_ [private] |
Definition at line 83 of file SimpleChatWidget.h.