gui/dialogs/chat_log.cpp

Go to the documentation of this file.
00001 /* $Id: chat_log.cpp 52937 2012-02-06 20:27:23Z mordante $ */
00002 /*
00003    Copyright (C) 2011 - 2012 by Yurii Chernyi <terraninfo@terraninfo.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 #define GETTEXT_DOMAIN "wesnoth-lib"
00017 
00018 #include "gui/dialogs/chat_log.hpp"
00019 
00020 #include "gui/dialogs/helper.hpp"
00021 #include "gui/widgets/button.hpp"
00022 #ifdef GUI2_EXPERIMENTAL_LISTBOX
00023 #include "gui/widgets/list.hpp"
00024 #else
00025 #include "gui/widgets/listbox.hpp"
00026 #endif
00027 #include "gui/widgets/settings.hpp"
00028 #include "gui/widgets/window.hpp"
00029 #include "gui/widgets/slider.hpp"
00030 
00031 #include "../../foreach.hpp"
00032 #include "../../gamestatus.hpp"
00033 #include "../../log.hpp"
00034 #include "../../resources.hpp"
00035 #include "../../team.hpp"
00036 #include "../../replay.hpp"
00037 
00038 #include <vector>
00039 #include <boost/bind.hpp>
00040 #include <boost/shared_ptr.hpp>
00041 
00042 static lg::log_domain log_chat_log("chat_log");
00043 #define DBG_CHAT_LOG LOG_STREAM(debug, log_chat_log)
00044 #define LOG_CHAT_LOG LOG_STREAM(info, log_chat_log)
00045 #define WRN_CHAT_LOG LOG_STREAM(warn, log_chat_log)
00046 #define ERR_CHAT_LOG LOG_STREAM(err, log_chat_log)
00047 
00048 namespace gui2 {
00049 
00050 /*WIKI
00051  * @page = GUIWindowDefinitionWML
00052  * @order = 3_chat_log
00053  *
00054  * == Settings manager ==
00055  *
00056  * This shows the settings manager
00057  *
00058  */
00059 
00060 
00061 REGISTER_DIALOG(chat_log)
00062 
00063 //The model is an interface defining the data to be displayed or otherwise acted upon in the user interface.
00064 class tchat_log::model {
00065 public:
00066     model(const vconfig &c, replay *r)
00067         : cfg(c)
00068         , msg_label(NULL)
00069         , chat_log_history(r->build_chat_log())
00070         , page(0)
00071         , page_number()
00072         , previous_page()
00073         , next_page()
00074     {
00075         LOG_CHAT_LOG << "entering tchat_log::model...\n";
00076         LOG_CHAT_LOG << "finished tchat_log::model...\n";
00077     }
00078 
00079     vconfig cfg;
00080     tcontrol *msg_label;
00081     const std::vector<chat_msg> &chat_log_history;
00082     int page;
00083     static const int COUNT_PER_PAGE = 1000;
00084     tslider *page_number;
00085     tbutton *previous_page;
00086     tbutton *next_page;
00087 
00088     void clear_chat_msg_list()
00089     {
00090         msg_label->set_label("");
00091     }
00092 
00093     std::string replace(std::string str, const std::string &src, const std::string &dst)
00094     {
00095         std::string::size_type pos = 0;
00096         while ( (pos = str.find(src, pos)) != std::string::npos ) {
00097             str.replace( pos, src.size(), dst );
00098             pos++;
00099         }
00100         return str;
00101     }
00102     std::string escape(const std::string &str)
00103     {
00104         // need pango escape here
00105         std::string result = replace(str,"&","&amp;");
00106         result = replace(result,"<","&lt;");
00107         result = replace(result,">","&gt;");
00108         return result;
00109     }
00110 
00111     int count_of_pages()
00112     {
00113         int size = chat_log_history.size();
00114         return (size%COUNT_PER_PAGE==0) ? (size/COUNT_PER_PAGE) : (size/COUNT_PER_PAGE)+1 ;
00115     }
00116 
00117     void populate_chat_message_list(int first, int last)
00118     {
00119         std::stringstream str;
00120         LOG_CHAT_LOG << "entering tchat_log::model::add_row_to_chat_message_list\n";
00121         if (first<last) {
00122             foreach (const chat_msg &t, make_pair(chat_log_history.begin()+first,chat_log_history.begin()+last))
00123             {
00124                 std::string prefix("/me");
00125                 bool me = false;
00126                 if (!t.text().compare(0, prefix.size(), prefix))
00127                 {
00128                     me = true;
00129                 }
00130                 const std::string & color = t.color();
00131                 std::string nick_prefix = "<span color=\""+color+"\">";
00132                 std::string nick_suffix ="</span> ";
00133                 std::map<std::string, string_map> data;
00134                 if (me) {
00135                     str << nick_prefix << "&lt;" << escape(t.nick()) << escape(t.text().substr(3))<<"&gt;" <<nick_suffix << std::endl;
00136                 } else {
00137                     str << nick_prefix << "&lt;" << escape(t.nick()) << "&gt;"<< nick_suffix << escape(t.text()) << std::endl;
00138                 }
00139             }
00140         }
00141         msg_label->set_label(str.str());
00142         LOG_CHAT_LOG << "exited tchat_log::model::add_row_to_chat_message_list\n";
00143     }
00144 
00145 };
00146 
00147 //The controller acts upon the model. It retrieves data from repositories, persists it, manipulates it, and determines how it will be displayed in the view.
00148 class tchat_log::controller {
00149 public:
00150     controller(model &m)
00151         : model_(m)
00152     {
00153         LOG_CHAT_LOG << "Entering tchat_log::controller" << std::endl;
00154         LOG_CHAT_LOG << "Exiting tchat_log::controller" << std::endl;
00155     }
00156 
00157     void next_page()
00158     {
00159         LOG_CHAT_LOG << "Entering tchat_log::controller::next_page" << std::endl;
00160         if (model_.page >= model_.count_of_pages()-1) {
00161             return;
00162         }
00163         model_.page++;
00164         LOG_CHAT_LOG << "Set page to " << model_.page+1 << std::endl;
00165         update_view_from_model();
00166         LOG_CHAT_LOG << "Exiting tchat_log::controller::next_page" << std::endl;
00167     }
00168 
00169     void previous_page()
00170     {
00171         LOG_CHAT_LOG << "Entering tchat_log::controller::previous_page" << std::endl;
00172         if (model_.page == 0) {
00173             return;
00174         }
00175         model_.page--;
00176         LOG_CHAT_LOG << "Set page to " << model_.page+1 << std::endl;
00177         update_view_from_model();
00178         LOG_CHAT_LOG << "Exiting tchat_log::controller::previous_page" << std::endl;
00179     }
00180 
00181     void handle_page_number_changed()
00182     {
00183         LOG_CHAT_LOG << "Entering tchat_log::controller::handle_page_number_changed" << std::endl;
00184         model_.page = model_.page_number->get_value()-1;
00185         LOG_CHAT_LOG << "Set page to " << model_.page+1 << std::endl;
00186         update_view_from_model();
00187         LOG_CHAT_LOG << "Exiting tchat_log::controller::handle_page_number_changed" << std::endl;
00188     }
00189 
00190     void update_view_from_model()
00191     {
00192         LOG_CHAT_LOG << "Entering tchat_log::controller::update_view_from_model" << std::endl;
00193         model_.msg_label->set_use_markup(true);
00194         int size = model_.chat_log_history.size();
00195         LOG_CHAT_LOG << "Number of chat messages: " << size << std::endl;
00196         // get page
00197         int page = model_.page;
00198         // determine count of pages
00199         int count_of_pages = model_.count_of_pages();
00200         if (count_of_pages==0) {
00201             count_of_pages = 1;
00202         }
00203         LOG_CHAT_LOG << "Page: " << page+1 << " of " << count_of_pages << std::endl;
00204         // determine first
00205         int first = model_.page*model_.COUNT_PER_PAGE;
00206         // determine last
00207         int last = (page<count_of_pages-1) ? first+model_.COUNT_PER_PAGE : size;
00208         LOG_CHAT_LOG << "First " << first << ", last " << last << std::endl;
00209         // determine has previous, determine has next
00210         bool has_next = page+1 < count_of_pages;
00211         bool has_previous = page > 0;
00212         model_.previous_page->set_active(has_previous);
00213         model_.next_page->set_active(has_next);
00214         model_.populate_chat_message_list(first,last);
00215         model_.page_number->set_minimum_value(1);
00216         model_.page_number->set_maximum_value(count_of_pages);
00217         model_.page_number->set_active(count_of_pages > 1);
00218         LOG_CHAT_LOG << "Maximum value of page number slider: " << count_of_pages << std::endl;
00219         model_.page_number->set_value(page+1);
00220         LOG_CHAT_LOG << "Exiting tchat_log::controller::update_view_from_model" << std::endl;
00221     }
00222 
00223 
00224 private:
00225     model &model_;
00226 };
00227 
00228 
00229 //The view is an interface that displays data (the model) and routes user commands to the controller to act upon that data.
00230 class tchat_log::view {
00231 public:
00232     view(const vconfig &cfg, replay *r)
00233         : model_(cfg, r),controller_(model_)
00234     {
00235     }
00236 
00237     void pre_show(CVideo& /*video*/, twindow& window)
00238     {
00239         LOG_CHAT_LOG << "Entering tchat_log::view::pre_show" << std::endl;
00240         controller_.update_view_from_model();
00241         window.invalidate_layout();//workaround for assertion failure
00242         LOG_CHAT_LOG << "Exiting tchat_log::view::pre_show" << std::endl;
00243     }
00244 
00245     void handle_page_number_changed(twindow &window)
00246     {
00247         controller_.handle_page_number_changed();
00248         window.invalidate_layout();//workaround for assertion failure
00249     }
00250 
00251     void next_page(twindow &window)
00252     {
00253         controller_.next_page();
00254         window.invalidate_layout();//workaround for assertion failure
00255     }
00256 
00257     void previous_page(twindow &window)
00258     {
00259         controller_.previous_page();
00260         window.invalidate_layout();//workaround for assertion failure
00261     }
00262 
00263     void bind(twindow &window)
00264     {
00265         LOG_CHAT_LOG << "Entering tchat_log::view::bind" << std::endl;
00266         model_.msg_label = &find_widget<tcontrol>(&window, "msg", false);
00267         model_.page_number = &find_widget<tslider>(&window, "page_number", false);
00268         connect_signal_notify_modified(*model_.page_number, boost::bind(&view::handle_page_number_changed, this, boost::ref(window)));
00269 
00270         model_.previous_page = &find_widget<tbutton>(&window, "previous_page", false);
00271         model_.previous_page->connect_click_handler(boost::bind(&view::previous_page, this, boost::ref(window)));
00272 
00273         model_.next_page = &find_widget<tbutton>(&window, "next_page", false);
00274         model_.next_page->connect_click_handler(boost::bind(&view::next_page, this, boost::ref(window)));
00275 
00276         LOG_CHAT_LOG << "Exiting tchat_log::view::bind" << std::endl;
00277     }
00278 
00279 private:
00280     model model_;
00281     controller controller_;
00282 };
00283 
00284 
00285 tchat_log::tchat_log(const vconfig &cfg, replay *r)
00286     : view_()
00287 {
00288     LOG_CHAT_LOG << "Entering tchat_log::tchat_log" << std::endl;
00289     view_ = boost::shared_ptr<view>(new view(cfg, r));
00290     LOG_CHAT_LOG << "Exiting tchat_log::tchat_log" << std::endl;
00291 }
00292 
00293 boost::shared_ptr<tchat_log::view> tchat_log::get_view()
00294 {
00295     return view_;
00296 }
00297 
00298 twindow* tchat_log::build_window(CVideo& video)
00299 {
00300     return build(video, window_id());
00301 }
00302 
00303 void tchat_log::pre_show(CVideo& video, twindow& window)
00304 {
00305     LOG_CHAT_LOG << "Entering tchat_log::pre_show" << std::endl;
00306     view_->bind(window);
00307     view_->pre_show(video,window);
00308     LOG_CHAT_LOG << "Exiting tchat_log::pre_show" << std::endl;
00309 }
00310 
00311 } //end of namespace gui2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Wed May 23 2012 01:02:43 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs