00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
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
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 REGISTER_DIALOG(chat_log)
00062
00063
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
00105 std::string result = replace(str,"&","&");
00106 result = replace(result,"<","<");
00107 result = replace(result,">",">");
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 << "<" << escape(t.nick()) << escape(t.text().substr(3))<<">" <<nick_suffix << std::endl;
00136 } else {
00137 str << nick_prefix << "<" << escape(t.nick()) << ">"<< 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
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
00197 int page = model_.page;
00198
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
00205 int first = model_.page*model_.COUNT_PER_PAGE;
00206
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
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
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& , 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();
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();
00249 }
00250
00251 void next_page(twindow &window)
00252 {
00253 controller_.next_page();
00254 window.invalidate_layout();
00255 }
00256
00257 void previous_page(twindow &window)
00258 {
00259 controller_.previous_page();
00260 window.invalidate_layout();
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 }