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