Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007 #include "SimpleChatWidget.h"
00008 #include "SimpleChatServer.h"
00009
00010 #include <Wt/WApplication>
00011 #include <Wt/WContainerWidget>
00012 #include <Wt/WEnvironment>
00013 #include <Wt/WHBoxLayout>
00014 #include <Wt/WVBoxLayout>
00015 #include <Wt/WLabel>
00016 #include <Wt/WLineEdit>
00017 #include <Wt/WText>
00018 #include <Wt/WTextArea>
00019 #include <Wt/WPushButton>
00020 #include <Wt/WCheckBox>
00021
00022 #include <iostream>
00023
00024 using namespace Wt;
00025
00026 SimpleChatWidget::SimpleChatWidget(SimpleChatServer& server,
00027 Wt::WContainerWidget *parent)
00028 : WContainerWidget(parent),
00029 server_(server),
00030 userList_(0),
00031 messageReceived_(0)
00032 {
00033 user_ = server_.suggestGuest();
00034 letLogin();
00035 }
00036
00037 SimpleChatWidget::~SimpleChatWidget()
00038 {
00039 delete messageReceived_;
00040 logout();
00041 disconnect();
00042 }
00043
00044 void SimpleChatWidget::connect()
00045 {
00046 if (server_.connect(this,
00047 boost::bind(&SimpleChatWidget::processChatEvent,
00048 this, _1)))
00049 Wt::WApplication::instance()->enableUpdates(true);
00050 }
00051
00052 void SimpleChatWidget::disconnect()
00053 {
00054 if (server_.disconnect(this))
00055 Wt::WApplication::instance()->enableUpdates(false);
00056 }
00057
00058 void SimpleChatWidget::letLogin()
00059 {
00060 disconnect();
00061
00062 clear();
00063
00064 WVBoxLayout *vLayout = new WVBoxLayout();
00065 setLayout(vLayout, AlignLeft | AlignTop);
00066
00067 WHBoxLayout *hLayout = new WHBoxLayout();
00068 vLayout->addLayout(hLayout);
00069
00070 hLayout->addWidget(new WLabel("User name:"), 0, AlignMiddle);
00071 hLayout->addWidget(userNameEdit_ = new WLineEdit(user_), 0, AlignMiddle);
00072 userNameEdit_->setFocus();
00073
00074 WPushButton *b = new WPushButton("Login");
00075 hLayout->addWidget(b, 0, AlignMiddle);
00076
00077 b->clicked().connect(this, &SimpleChatWidget::login);
00078 userNameEdit_->enterPressed().connect(this, &SimpleChatWidget::login);
00079
00080 vLayout->addWidget(statusMsg_ = new WText());
00081 statusMsg_->setTextFormat(PlainText);
00082 }
00083
00084 void SimpleChatWidget::login()
00085 {
00086 if (!loggedIn()) {
00087 WString name = WWebWidget::escapeText(userNameEdit_->text());
00088
00089 if (!messageReceived_)
00090 messageReceived_ = new WSound("sounds/message_received.mp3");
00091
00092 if (!startChat(name))
00093 statusMsg_->setText("Sorry, name '" + name + "' is already taken.");
00094 }
00095 }
00096
00097 void SimpleChatWidget::logout()
00098 {
00099 if (loggedIn()) {
00100 server_.logout(user_);
00101
00102 letLogin();
00103 }
00104 }
00105
00106 void SimpleChatWidget::createLayout(WWidget *messages, WWidget *userList,
00107 WWidget *messageEdit,
00108 WWidget *sendButton, WWidget *logoutButton)
00109 {
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128 WVBoxLayout *vLayout = new WVBoxLayout();
00129
00130
00131 WHBoxLayout *hLayout = new WHBoxLayout();
00132
00133
00134 hLayout->addWidget(messages, 1);
00135 messages->setStyleClass("chat-msgs");
00136
00137
00138 hLayout->addWidget(userList);
00139 userList->setStyleClass("chat-users");
00140
00141 hLayout->setResizable(0, true);
00142
00143
00144 vLayout->addLayout(hLayout, 1);
00145
00146
00147 vLayout->addWidget(messageEdit);
00148 messageEdit->setStyleClass("chat-noedit");
00149
00150
00151 hLayout = new WHBoxLayout();
00152
00153
00154 hLayout->addWidget(sendButton);
00155
00156
00157 hLayout->addWidget(logoutButton);
00158
00159
00160 vLayout->addLayout(hLayout, 0, AlignLeft | AlignTop);
00161
00162 setLayout(vLayout);
00163 }
00164
00165 bool SimpleChatWidget::loggedIn() const
00166 {
00167 return !userNameEdit_;
00168 }
00169
00170 void SimpleChatWidget::render(WFlags<RenderFlag> flags)
00171 {
00172 if (flags & RenderFull) {
00173 if (loggedIn()) {
00174
00175 messageEdit_->setText(WString::Empty);
00176 doJavaScript("setTimeout(function() { "
00177 + messages_->jsRef() + ".scrollTop += "
00178 + messages_->jsRef() + ".scrollHeight;}, 0);");
00179 }
00180 }
00181
00182 WContainerWidget::render(flags);
00183 }
00184
00185 bool SimpleChatWidget::startChat(const WString& user)
00186 {
00187
00188
00189
00190
00191 if (server_.login(user)) {
00192 connect();
00193
00194 user_ = user;
00195
00196 clear();
00197 userNameEdit_ = 0;
00198
00199 messages_ = new WContainerWidget();
00200 userList_ = new WContainerWidget();
00201 messageEdit_ = new WTextArea();
00202 messageEdit_->setRows(2);
00203 messageEdit_->setFocus();
00204
00205
00206 messages_->setOverflow(WContainerWidget::OverflowAuto);
00207 userList_->setOverflow(WContainerWidget::OverflowAuto);
00208
00209 sendButton_ = new WPushButton("Send");
00210 WPushButton *logoutButton = new WPushButton("Logout");
00211
00212 createLayout(messages_, userList_, messageEdit_, sendButton_, logoutButton);
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226 clearInput_.setJavaScript
00227 ("function(o, e) { setTimeout(function() {"
00228 "" + messageEdit_->jsRef() + ".value='';"
00229 "}, 0); }");
00230
00231
00232 sendButton_->clicked().connect(this, &SimpleChatWidget::send);
00233 messageEdit_->enterPressed().connect(this, &SimpleChatWidget::send);
00234 sendButton_->clicked().connect(clearInput_);
00235 messageEdit_->enterPressed().connect(clearInput_);
00236 sendButton_->clicked().connect(messageEdit_, &WLineEdit::setFocus);
00237 messageEdit_->enterPressed().connect(messageEdit_, &WLineEdit::setFocus);
00238
00239
00240
00241 messageEdit_->enterPressed().preventDefaultAction();
00242
00243 logoutButton->clicked().connect(this, &SimpleChatWidget::logout);
00244
00245 WText *msg = new WText
00246 ("<div><span class='chat-info'>You are joining as "
00247 + user_ + ".</span></div>", messages_);
00248 msg->setStyleClass("chat-msg");
00249
00250 if (!userList_->parent()) {
00251 delete userList_;
00252 userList_ = 0;
00253 }
00254
00255 if (!sendButton_->parent()) {
00256 delete sendButton_;
00257 sendButton_ = 0;
00258 }
00259
00260 if (!logoutButton->parent())
00261 delete logoutButton;
00262
00263 updateUsers();
00264
00265 return true;
00266 } else
00267 return false;
00268 }
00269
00270 void SimpleChatWidget::send()
00271 {
00272 if (!messageEdit_->text().empty())
00273 server_.sendMessage(user_, messageEdit_->text());
00274 }
00275
00276 void SimpleChatWidget::updateUsers()
00277 {
00278 if (userList_) {
00279 userList_->clear();
00280
00281 SimpleChatServer::UserSet users = server_.users();
00282
00283 UserMap oldUsers = users_;
00284 users_.clear();
00285
00286 for (SimpleChatServer::UserSet::iterator i = users.begin();
00287 i != users.end(); ++i) {
00288 WCheckBox *w = new WCheckBox(*i, userList_);
00289 w->setInline(false);
00290
00291 UserMap::const_iterator j = oldUsers.find(*i);
00292 if (j != oldUsers.end())
00293 w->setChecked(j->second);
00294 else
00295 w->setChecked(true);
00296
00297 users_[*i] = w->isChecked();
00298 w->changed().connect(this, &SimpleChatWidget::updateUser);
00299
00300 if (*i == user_)
00301 w->setStyleClass("chat-self");
00302 }
00303 }
00304 }
00305
00306 void SimpleChatWidget::newMessage()
00307 { }
00308
00309 void SimpleChatWidget::updateUser()
00310 {
00311 WCheckBox *b = dynamic_cast<WCheckBox *>(sender());
00312 users_[b->text()] = b->isChecked();
00313 }
00314
00315 void SimpleChatWidget::processChatEvent(const ChatEvent& event)
00316 {
00317 WApplication *app = WApplication::instance();
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 if (event.type() != ChatEvent::Message) {
00337 if (event.type() == ChatEvent::Rename && event.user() == user_)
00338 user_ = event.data();
00339
00340 updateUsers();
00341 }
00342
00343 newMessage();
00344
00345
00346
00347
00348 if (!loggedIn()) {
00349 app->triggerUpdate();
00350 return;
00351 }
00352
00353 bool display = event.type() != ChatEvent::Message
00354 || !userList_
00355 || (users_.find(event.user()) != users_.end() && users_[event.user()]);
00356
00357 if (display) {
00358 WText *w = new WText(event.formattedHTML(user_), messages_);
00359 w->setInline(false);
00360 w->setStyleClass("chat-msg");
00361
00362
00363
00364
00365 if (messages_->count() > 100)
00366 delete messages_->children()[0];
00367
00368
00369
00370
00371 app->doJavaScript(messages_->jsRef() + ".scrollTop += "
00372 + messages_->jsRef() + ".scrollHeight;");
00373
00374
00375 if (event.user() != user_ && messageReceived_)
00376 messageReceived_->play();
00377 }
00378
00379
00380
00381
00382
00383 app->triggerUpdate();
00384 }