/home/koen/project/wt/cvs/wt/examples/simplechat/SimpleChatWidget.C

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2007 Koen Deforche
00003  *
00004  * See the LICENSE file for terms of use.
00005  */
00006 
00007 #include "SimpleChatWidget.h"
00008 #include "SimpleChatServer.h"
00009 
00010 #include <WApplication>
00011 #include <WContainerWidget>
00012 #include <WLineEdit>
00013 #include <WTable>
00014 #include <WTableCell>
00015 #include <WText>
00016 #include <WTextArea>
00017 #include <WPushButton>
00018 
00019 #include <iostream>
00020 
00021 using namespace Wt;
00022 
00023 SimpleChatWidget::SimpleChatWidget(SimpleChatServer& server,
00024                                    Wt::WContainerWidget *parent)
00025   : WCompositeWidget(parent),
00026     server_(server),
00027     app_(WApplication::instance())
00028 {
00029   setImplementation(layout_ = new WContainerWidget());
00030 
00031   setPositionScheme(Relative);
00032 
00033   user_ = server_.suggestGuest();
00034   letLogin();
00035 
00036   app_->enableUpdates();
00037 }
00038 
00039 SimpleChatWidget::~SimpleChatWidget()
00040 {
00041   logout();
00042 }
00043 
00044 void SimpleChatWidget::letLogin()
00045 {
00046   layout_->clear();
00047 
00048   new WText("User name: ", layout_);
00049   userNameEdit_ = new WLineEdit(user_, layout_);
00050   userNameEdit_->setFocus();
00051 
00052   WPushButton *b = new WPushButton("Login", layout_);
00053   b->setMargin(5, WWidget::Left);
00054 
00055   b->clicked.connect(SLOT(this, SimpleChatWidget::login));
00056   userNameEdit_->enterPressed.connect(SLOT(this, SimpleChatWidget::login));
00057 
00058   statusMsg_ = new WText(layout_);
00059   statusMsg_->setFormatting(WText::PlainFormatting);
00060   statusMsg_->setInline(false);
00061 }
00062 
00063 void SimpleChatWidget::login()
00064 {
00065   WString name = WWebWidget::escapeText(userNameEdit_->text());
00066 
00067   if (!startChat(name))
00068     statusMsg_->setText("Sorry, name '" + name + "' is already taken.");
00069 }
00070 
00071 void SimpleChatWidget::logout()
00072 {
00073   if (eventConnection_.connected()) {
00074     server_.logout(user_);
00075     eventConnection_.disconnect();
00076 
00077     messageEditArea_->clear();
00078 
00079     WPushButton *b = new WPushButton("Login again", messageEditArea_);
00080     b->clicked.connect(SLOT(this, SimpleChatWidget::letLogin));
00081   }
00082 }
00083 
00084 bool SimpleChatWidget::startChat(const WString& user)
00085 {
00086   if (server_.login(user)) {
00087     eventConnection_
00088       = server_.chatEvent.connect(SLOT(this,
00089                                        SimpleChatWidget::processChatEvent));
00090     user_ = user;    
00091 
00092     static const int MESSAGE_EDIT_AREA_HEIGHT = 80;
00093     static const int USERS_WIDTH_PERCENTAGE = 15;
00094 
00095     layout_->clear();
00096 
00097     messages_ = new WContainerWidget(layout_);
00098     messages_->setStyleClass("chat-msgs");
00099     messages_->setPositionScheme(Absolute);
00100     messages_->setOffsets(0, Left | Top);
00101     messages_
00102       ->resize(WLength(100 - USERS_WIDTH_PERCENTAGE - 1, WLength::Percentage),
00103                height().value() - MESSAGE_EDIT_AREA_HEIGHT - 3);
00104     messages_->setOverflow(WContainerWidget::OverflowAuto, Vertical);
00105 
00106     messageEditArea_ = new WContainerWidget(layout_);
00107     messageEditArea_->setPositionScheme(Absolute);
00108     messageEditArea_->setOffsets(0, Left | Bottom);
00109     messageEditArea_->resize(WLength(100, WLength::Percentage),
00110                              MESSAGE_EDIT_AREA_HEIGHT);
00111 
00112     WContainerWidget *a = new WContainerWidget(messageEditArea_);
00113     a->setContentAlignment(AlignCenter);
00114 
00115     messageEdit_ = new WTextArea(a);
00116     messageEdit_->setStyleClass("chat-noedit");
00117     messageEdit_->setRows(2);
00118     messageEdit_->resize(WLength(99, WLength::Percentage), WLength());
00119     messageEdit_->setFocus();
00120 
00121     sendButton_ = new WPushButton("Send", messageEditArea_);
00122 
00123     sendButton_->clicked.connect(SLOT(sendButton_, WPushButton::disable));
00124     sendButton_->clicked.connect(SLOT(messageEdit_, WTextArea::disable));
00125     sendButton_->clicked.connect(SLOT(this, SimpleChatWidget::send));
00126 
00127     messageEdit_->enterPressed.connect(SLOT(sendButton_, WPushButton::disable));
00128     messageEdit_->enterPressed.connect(SLOT(messageEdit_, WTextArea::disable));
00129     messageEdit_->enterPressed.connect(SLOT(this, SimpleChatWidget::send));
00130 
00131     WPushButton *b = new WPushButton("Logout", messageEditArea_);
00132     b->clicked.connect(SLOT(this, SimpleChatWidget::logout));
00133 
00134     userList_ = new WContainerWidget(layout_);
00135     userList_->setStyleClass("chat-users");
00136     userList_->setPositionScheme(Absolute);
00137     userList_->setOffsets(0, Top | Right);
00138     userList_->resize(WLength(USERS_WIDTH_PERCENTAGE, WLength::Percentage),
00139                       height().value() - MESSAGE_EDIT_AREA_HEIGHT - 3);
00140 
00141     WText *w
00142       = new WText(false,
00143                   "<span class='chat-info'>You are joining the conversation as "
00144                   + user_ + "</span>", messages_);
00145     w->setStyleClass("chat-msg");
00146 
00147     updateUsers();
00148     
00149     return true;
00150   } else
00151     return false;
00152 }
00153 
00154 void SimpleChatWidget::send()
00155 {
00156   if (!messageEdit_->text().empty()) {
00157     server_.sendMessage(user_, messageEdit_->text());
00158     messageEdit_->setText("");
00159   }
00160 
00161   messageEdit_->enable();
00162   messageEdit_->setFocus();
00163   sendButton_->enable();
00164 }
00165 
00166 void SimpleChatWidget::updateUsers()
00167 {
00168   userList_->clear();
00169 
00170   SimpleChatServer::UserSet users = server_.users();
00171 
00172   WString usersStr;
00173 
00174   for (SimpleChatServer::UserSet::iterator i = users.begin();
00175        i != users.end(); ++i) {
00176     if (*i == user_)
00177       usersStr += "<span class='chat-self'>" + *i + "</span><br />";
00178     else
00179       usersStr += *i + "<br />";
00180   }
00181 
00182   userList_->addWidget(new WText(false, usersStr));
00183 }
00184 
00185 void SimpleChatWidget::processChatEvent(const ChatEvent& event)
00186 {
00187   /*
00188    * This is where the "server-push" happens. This method is called
00189    * when a new event or message needs to be notified to the user. In
00190    * general, it is called from another session.
00191    *
00192    * First, we take the lock to safely manipulate the UI outside of the
00193    * normal event loop.
00194    */
00195   WApplication::UpdateLock lock = app_->getUpdateLock();
00196 
00197   WText *w = new WText(false, event.formattedHTML(user_), messages_);
00198   w->setStyleClass("chat-msg");
00199 
00200   /* no more than 100 messages back-log */
00201   if (messages_->count() > 100)
00202     delete messages_->children()[0];
00203 
00204   if (event.type() != ChatEvent::Message)
00205     updateUsers();
00206 
00207   /*
00208    * little javascript trick to make sure we scroll along with new content
00209    */
00210   app_->doJavaScript(messages_->jsRef() + ".scrollTop += "
00211                      + messages_->jsRef() + ".scrollHeight;");
00212 
00213   /*
00214    * Update the user-interface with these changes
00215    */
00216   app_->triggerUpdate();
00217 }

Generated on Mon Apr 14 15:15:04 2008 for Wt by doxygen 1.5.3