/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 <Wt/WApplication>
00011 #include <Wt/WContainerWidget>
00012 #include <Wt/WHBoxLayout>
00013 #include <Wt/WVBoxLayout>
00014 #include <Wt/WLabel>
00015 #include <Wt/WLineEdit>
00016 #include <Wt/WTable>
00017 #include <Wt/WTableCell>
00018 #include <Wt/WText>
00019 #include <Wt/WTextArea>
00020 #include <Wt/WPushButton>
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     app_(WApplication::instance())
00031 {
00032   user_ = server_.suggestGuest();
00033   letLogin();
00034 
00035   app_->enableUpdates();
00036 }
00037 
00038 SimpleChatWidget::~SimpleChatWidget()
00039 {
00040   logout();
00041 }
00042 
00043 void SimpleChatWidget::letLogin()
00044 {
00045   clear();
00046 
00047   WVBoxLayout *vLayout = new WVBoxLayout();
00048   setLayout(vLayout, AlignLeft | AlignTop);
00049 
00050   WHBoxLayout *hLayout = new WHBoxLayout();
00051   vLayout->addLayout(hLayout);
00052 
00053   hLayout->addWidget(new WLabel("User name:"), 0, AlignMiddle);
00054   hLayout->addWidget(userNameEdit_ = new WLineEdit(user_), 0, AlignMiddle);
00055   userNameEdit_->setFocus();
00056 
00057   WPushButton *b = new WPushButton("Login");
00058   hLayout->addWidget(b, 0, AlignMiddle);
00059   hLayout->addStretch(1);
00060 
00061   b->clicked.connect(SLOT(this, SimpleChatWidget::login));
00062   userNameEdit_->enterPressed.connect(SLOT(this, SimpleChatWidget::login));
00063 
00064   vLayout->addWidget(statusMsg_ = new WText());
00065   statusMsg_->setFormatting(WText::PlainFormatting);
00066 }
00067 
00068 void SimpleChatWidget::login()
00069 {
00070   WString name = WWebWidget::escapeText(userNameEdit_->text());
00071 
00072   if (!startChat(name))
00073     statusMsg_->setText("Sorry, name '" + name + "' is already taken.");
00074 }
00075 
00076 void SimpleChatWidget::logout()
00077 {
00078   if (eventConnection_.connected()) {
00079     eventConnection_.disconnect(); // do not listen for more events
00080     server_.logout(user_);
00081 
00082     letLogin();
00083   }
00084 }
00085 
00086 bool SimpleChatWidget::startChat(const WString& user)
00087 {
00088   if (server_.login(user)) {
00089     eventConnection_
00090       = server_.chatEvent.connect(SLOT(this,
00091                                        SimpleChatWidget::processChatEvent));
00092     user_ = user;    
00093 
00094     clear();
00095 
00096     /*
00097      * Create a vertical layout, which will hold 3 rows,
00098      * organized like this:
00099      *
00100      * WVBoxLayout
00101      * --------------------------------------------
00102      * | nested WHBoxLayout (vertical stretch=1)  |
00103      * |                              |           |
00104      * |  messages                    | userslist |
00105      * |   (horizontal stretch=1)     |           |
00106      * |                              |           |
00107      * --------------------------------------------
00108      * | message edit area                        |
00109      * --------------------------------------------
00110      * | WHBoxLayout                              |
00111      * | send | logout |       stretch = 1        |
00112      * --------------------------------------------
00113      */
00114     WVBoxLayout *vLayout = new WVBoxLayout();
00115 
00116     // Create a horizontal layout for the messages | userslist.
00117     WHBoxLayout *hLayout = new WHBoxLayout();
00118 
00119     // Add widget to horizontal layout with stretch = 1
00120     hLayout->addWidget(messages_ = new WContainerWidget(), 1);
00121     messages_->setStyleClass("chat-msgs");
00122     // Display scroll bars if contents overflows
00123     messages_->setOverflow(WContainerWidget::OverflowAuto);
00124 
00125     // Add another widget to hirozontal layout with stretch = 0
00126     hLayout->addWidget(userList_ = new WContainerWidget());
00127     userList_->setStyleClass("chat-users");
00128     userList_->setOverflow(WContainerWidget::OverflowAuto);
00129 
00130     // Add nested layout to vertical layout with stretch = 1
00131     vLayout->addLayout(hLayout, 1);
00132 
00133     // Add widget to vertical layout with stretch = 0
00134     vLayout->addWidget(messageEdit_ = new WTextArea());
00135     messageEdit_->setStyleClass("chat-noedit");
00136     messageEdit_->setRows(2);
00137     messageEdit_->setFocus();
00138 
00139     // Create a horizontal layout for the buttons.
00140     hLayout = new WHBoxLayout();
00141 
00142     // Add button to horizontal layout with stretch = 0
00143     hLayout->addWidget(sendButton_ = new WPushButton("Send"));
00144     WPushButton *b;
00145 
00146     // Add button to horizontal layout with stretch = 0
00147     hLayout->addWidget(b = new WPushButton("Logout", this));
00148 
00149     // Add stretching spacer to horizontal layout
00150     hLayout->addStretch(1);
00151 
00152     // Add nested layout to vertical layout with stretch = 0
00153     vLayout->addLayout(hLayout);
00154 
00155     setLayout(vLayout);
00156 
00157     /*
00158      * Connect event handlers
00159      */
00160     sendButton_->clicked.connect(SLOT(sendButton_, WPushButton::disable));
00161     sendButton_->clicked.connect(SLOT(messageEdit_, WTextArea::disable));
00162     sendButton_->clicked.connect(SLOT(this, SimpleChatWidget::send));
00163 
00164     messageEdit_->enterPressed.connect(SLOT(sendButton_, WPushButton::disable));
00165     messageEdit_->enterPressed.connect(SLOT(messageEdit_, WTextArea::disable));
00166     messageEdit_->enterPressed.connect(SLOT(this, SimpleChatWidget::send));
00167 
00168     b->clicked.connect(SLOT(this, SimpleChatWidget::logout));
00169 
00170     WText *msg
00171       = new WText(false,
00172                   "<span class='chat-info'>You are joining the conversation as "
00173                   + user_ + "</span>", messages_);
00174     msg->setStyleClass("chat-msg");
00175 
00176     updateUsers();
00177     
00178     return true;
00179   } else
00180     return false;
00181 }
00182 
00183 void SimpleChatWidget::send()
00184 {
00185   if (!messageEdit_->text().empty()) {
00186     server_.sendMessage(user_, messageEdit_->text());
00187     messageEdit_->setText("");
00188   }
00189 
00190   messageEdit_->enable();
00191   messageEdit_->setFocus();
00192   sendButton_->enable();
00193 }
00194 
00195 void SimpleChatWidget::updateUsers()
00196 {
00197   userList_->clear();
00198 
00199   SimpleChatServer::UserSet users = server_.users();
00200 
00201   WString usersStr;
00202 
00203   for (SimpleChatServer::UserSet::iterator i = users.begin();
00204        i != users.end(); ++i) {
00205     if (*i == user_)
00206       usersStr += "<span class='chat-self'>" + *i + "</span><br />";
00207     else
00208       usersStr += *i + "<br />";
00209   }
00210 
00211   userList_->addWidget(new WText(false, usersStr));
00212 }
00213 
00214 void SimpleChatWidget::processChatEvent(const ChatEvent& event)
00215 {
00216   /*
00217    * This is where the "server-push" happens. This method is called
00218    * when a new event or message needs to be notified to the user. In
00219    * general, it is called from another session.
00220    *
00221    * First, we take the lock to safely manipulate the UI outside of the
00222    * normal event loop.
00223    */
00224 
00225   WApplication::UpdateLock lock = app_->getUpdateLock();
00226 
00227   WText *w = new WText(false, event.formattedHTML(user_), messages_);
00228   w->setStyleClass("chat-msg");
00229 
00230   /* no more than 100 messages back-log */
00231   if (messages_->count() > 100)
00232     delete messages_->children()[0];
00233 
00234   if (event.type() != ChatEvent::Message)
00235     updateUsers();
00236 
00237   /*
00238    * little javascript trick to make sure we scroll along with new content
00239    */
00240   app_->doJavaScript(messages_->jsRef() + ".scrollTop += "
00241                      + messages_->jsRef() + ".scrollHeight;");
00242 
00243   app_->triggerUpdate();
00244 }

Generated on Fri Jul 25 17:05:59 2008 for Wt by doxygen 1.5.3