gui/dialogs/gamestate_inspector.cpp

Go to the documentation of this file.
00001 /* $Id: gamestate_inspector.cpp 54158 2012-05-12 16:28:46Z jamit $ */
00002 /*
00003    Copyright (C) 2009 - 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/gamestate_inspector.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 
00030 #include "../../foreach.hpp"
00031 #include "../../gamestatus.hpp"
00032 #include "../../resources.hpp"
00033 #include "../../team.hpp"
00034 #include "../../ai/manager.hpp"
00035 
00036 #include <vector>
00037 #include <boost/bind.hpp>
00038 #include <boost/shared_ptr.hpp>
00039 
00040 namespace gui2 {
00041 
00042 /*WIKI
00043  * @page = GUIWindowDefinitionWML
00044  * @order = 2_gamestate_inspector
00045  *
00046  * == Gamestate inspector ==
00047  *
00048  * This shows the gamestate inspector
00049  *
00050  * @begin{table}{dialog_widgets}
00051  *
00052  * inspector_name & & control & m &
00053  *         Name of the inspector. $
00054  *
00055  * stuff_list & & control & m &
00056  *         List of various stuff that can be viewed. $
00057  *
00058  * inspect & & control & m &
00059  *         The state of the variable or event. $
00060  *
00061  * @end{table}
00062  */
00063 
00064 
00065 /*
00066 static void inspect_ai(twindow& window, int side)
00067 {
00068     const config &ai_cfg = ai::manager::to_config(side);
00069     NEW_find_widget<tcontrol>(&window, "inspect", false).set_label(ai_cfg.debug());
00070 }
00071 */
00072 
00073 /**
00074  * Template for dialog callbacks for dialogs using model-view-controller architecture pattern.
00075  * It allows delegating of the callback to a private view class, which should be accessible via
00076  * dialog->get_view() (and return a pointer to the view class). Example usage:
00077  * widget->set_callback(dialog_callback<my_dialog_class, my_dialog_class::inner_view_class
00078  * &my_dialog_class::inner_view_class::member_function>);
00079  */
00080 template <class D, class V, void (V::*fptr)(twindow&)>
00081 void dialog_view_callback(twidget* caller)
00082 {
00083         D* dialog = dynamic_cast<D*>(caller->dialog());
00084         assert(dialog);
00085         twindow* window = dynamic_cast<twindow*>(caller->get_window());
00086         assert(window);
00087         (*(dialog->get_view()).*fptr)(*window);
00088 }
00089 
00090 
00091 //The model is an interface defining the data to be displayed or otherwise acted upon in the user interface.
00092 class tgamestate_inspector::model {
00093 public:
00094     model(const vconfig &c)
00095         : cfg(c), name(), stuff_list(),stuff_types_list(),inspect(),inspector_name()
00096     {
00097         name = cfg["name"].str();
00098     }
00099 
00100     vconfig cfg;
00101     std::string name;
00102 
00103     tlistbox *stuff_list;
00104     tlistbox *stuff_types_list;
00105     tcontrol *inspect;
00106     tcontrol *inspector_name;
00107 
00108 
00109     void clear_stuff_list()
00110     {
00111         stuff_list->clear();
00112     }
00113 
00114 
00115     void clear_stuff_types_list()
00116     {
00117         stuff_types_list->clear();
00118     }
00119 
00120     void add_row_to_stuff_list(const std::string &id, const std::string &label)
00121     {
00122         std::map<std::string, string_map> data;
00123         string_map item;
00124         item["id"] = id;
00125         item["label"] = label;
00126         data.insert(std::make_pair("name", item));
00127         stuff_list->add_row(data);
00128     }
00129 
00130 
00131     void add_row_to_stuff_types_list(const std::string &id, const std::string &label)
00132     {
00133         std::map<std::string, string_map> data;
00134         string_map item;
00135         item["id"] = id;
00136         item["label"] = label;
00137         data.insert(std::make_pair("typename", item));
00138         stuff_types_list->add_row(data);
00139     }
00140 
00141 
00142     void set_inspect_window_text(const std::string &s)
00143     {
00144         std::string s_ = s;
00145         if (s_.length()>20000) {//workaround for known bug
00146             s_.resize(20000);
00147         }
00148         inspect->set_label(s_);
00149     }
00150 
00151 };
00152 
00153 class single_mode_controller {
00154 public:
00155     single_mode_controller(const std::string& name, tgamestate_inspector::model &m)
00156         :model_(m), name_(name)
00157     {
00158     }
00159     virtual ~single_mode_controller()
00160     {
00161     }
00162 
00163     std::string name() const
00164     {
00165         return name_;
00166     }
00167 
00168     virtual void show_stuff_list() = 0;
00169     virtual void handle_stuff_list_selection() = 0;
00170     virtual void update_view_from_model() = 0;
00171 
00172 protected:
00173     tgamestate_inspector::model &model_;
00174     std::string name_;
00175 };
00176 
00177 class variable_mode_controller : public single_mode_controller{
00178 public:
00179     variable_mode_controller(const std::string& name, tgamestate_inspector::model &m)
00180         :single_mode_controller(name,m)
00181     {
00182     }
00183 
00184     void show_stuff_list()
00185     {
00186         model_.clear_stuff_list();
00187 
00188         const config &vars = resources::state_of_game
00189                 ? resources::state_of_game->get_variables()
00190                 : config();
00191 
00192         foreach( const config::attribute &a, vars.attribute_range()) {
00193             model_.add_row_to_stuff_list(a.first,a.first);
00194         }
00195 
00196         foreach( const config::any_child &c, vars.all_children_range()) {
00197             model_.add_row_to_stuff_list("["+c.key+"]","["+c.key+"]");
00198         }
00199 
00200         model_.set_inspect_window_text("");
00201 
00202     }
00203 
00204     void handle_stuff_list_selection()
00205     {
00206         int selected = model_.stuff_list->get_selected_row();
00207         if (selected==-1) {
00208             model_.set_inspect_window_text("");
00209             return;
00210         }
00211 
00212         int i = 0;///@todo replace with precached data
00213         const config &vars = resources::state_of_game
00214                 ? resources::state_of_game->get_variables()
00215                 : config();
00216 
00217         foreach( const config::attribute &a, vars.attribute_range()) {
00218             if (selected==i) {
00219                 model_.set_inspect_window_text(a.second);
00220                 return;
00221             }
00222             i++;
00223         }
00224 
00225         foreach( const config::any_child &c, vars.all_children_range()) {
00226             if (selected==i) {
00227                 model_.set_inspect_window_text(c.cfg.debug());
00228                 return;
00229             }
00230             i++;
00231         }
00232     }
00233 
00234     virtual void update_view_from_model()
00235     {
00236         show_stuff_list();
00237         //handle_stuff_list_selection();
00238     }
00239 };
00240 
00241 
00242 
00243 class unit_mode_controller : public single_mode_controller{
00244 public:
00245     unit_mode_controller(const std::string& name, tgamestate_inspector::model &m)
00246         :single_mode_controller(name,m)
00247     {
00248     }
00249 
00250     void show_stuff_list()
00251     {
00252         model_.clear_stuff_list();
00253 
00254         if(resources::units) {
00255             for(unit_map::iterator i = resources::units->begin()
00256                     ; i != resources::units->end()
00257                     ; ++i) {
00258 
00259                 std::stringstream s;
00260                 s << '(' << i->get_location();
00261                 s << ") side=" << i->side() << ' ';
00262                 if (i->can_recruit()) {
00263                     s << "LEADER ";
00264                 }
00265 
00266                 s << "id=[" << i->id() << "] " << i->type_id()
00267                     << "; L" << i->level()<< "; " << i->experience()
00268                     << '/' << i->max_experience() << " xp; "
00269                     << i->hitpoints() << '/' << i->max_hitpoints()
00270                     << " hp; ";
00271                 foreach (const std::string &str, i->get_traits_list()) {
00272                     s << str <<" ";
00273                 }
00274 
00275                 std::string key = s.str();
00276                 model_.add_row_to_stuff_list(key,key);
00277             }
00278         }
00279 
00280         model_.set_inspect_window_text("");
00281 
00282     }
00283 
00284     void handle_stuff_list_selection()
00285     {
00286         int selected = model_.stuff_list->get_selected_row();
00287         if (selected==-1) {
00288             model_.set_inspect_window_text("");
00289             return;
00290         }
00291 
00292         if(resources::units) {
00293             int i = 0;///@todo replace with precached data
00294             for(unit_map::iterator u = resources::units->begin()
00295                     ; u != resources::units->end()
00296                     ; ++u) {
00297                 if (selected==i) {
00298                     config c_unit;
00299                     u->write(c_unit);
00300                     model_.set_inspect_window_text(c_unit.debug());
00301                     return;
00302                 }
00303                 i++;
00304             }
00305         }
00306         model_.set_inspect_window_text("");
00307 
00308     }
00309 
00310     virtual void update_view_from_model()
00311     {
00312         show_stuff_list();
00313         //handle_stuff_list_selection();
00314     }
00315 };
00316 
00317 
00318 class team_mode_controller : public single_mode_controller{
00319 public:
00320     team_mode_controller(const std::string& name, tgamestate_inspector::model &m, int side)
00321         :single_mode_controller(name,m), side_(side)
00322     {
00323     }
00324 
00325     void show_stuff_list()
00326     {
00327         model_.clear_stuff_list();
00328         //note: needs sync with handle_stuff_list_selection()
00329         model_.add_row_to_stuff_list("overview","overview");
00330         model_.add_row_to_stuff_list("ai overview","ai overview");
00331         model_.add_row_to_stuff_list("ai config full","ai config full");
00332         model_.add_row_to_stuff_list("recall list overview","recall list overview");
00333         model_.add_row_to_stuff_list("recall list full","recall list full");
00334         model_.add_row_to_stuff_list("ai component structure","ai component structure");
00335         model_.add_row_to_stuff_list("unit list overview","unit list overview");
00336         model_.set_inspect_window_text("");
00337 
00338     }
00339 
00340     void handle_stuff_list_selection()
00341     {
00342         int selected = model_.stuff_list->get_selected_row();
00343         if (selected==-1) {
00344             model_.set_inspect_window_text("");
00345             return;
00346         }
00347 
00348         if (selected==0) {
00349             config c = resources::teams
00350                     ? resources::teams->at(side_-1).to_config()
00351                     : config();
00352             c.clear_children("ai");
00353             c.clear_children("village");
00354             model_.set_inspect_window_text(c.debug());
00355             return;
00356         }
00357 
00358         if (selected==1) {
00359             model_.set_inspect_window_text(ai::manager::get_active_ai_overview_for_side(side_));
00360             return;
00361         }
00362 
00363         if (selected==2) {
00364             model_.set_inspect_window_text(ai::manager::to_config(side_).debug());
00365             return;
00366         }
00367 
00368         if (selected==3) {
00369             const std::vector<unit> recall_list = resources::teams
00370                     ? resources::teams->at(side_-1).recall_list()
00371                     : std::vector<unit>();
00372 
00373             std::stringstream s;
00374             foreach (const unit &u, recall_list) {
00375                 s << "id=["<<u.id() << "] "<<u.type_id() << "; L"<<u.level()<<"; " << u.experience() <<"/" << u.max_experience()<< " xp "<< std::endl;
00376                 foreach (const std::string &str, u.get_traits_list() ) {
00377                     s << "\t" << str<< std::endl;
00378                 }
00379                 s << std::endl << std::endl;
00380             }
00381             model_.set_inspect_window_text(s.str());
00382             return;
00383         }
00384 
00385         if (selected==4) {
00386             const std::vector<unit> recall_list = resources::teams
00387                     ? resources::teams->at(side_-1).recall_list()
00388                     : std::vector<unit>();
00389 
00390             config c;
00391             foreach (const unit &u, recall_list) {
00392                 config c_unit;
00393                 u.write(c_unit);
00394                 c.add_child("unit",c_unit);
00395             }
00396             model_.set_inspect_window_text(c.debug());
00397             return;
00398         }
00399 
00400         if (selected==5) {
00401             model_.set_inspect_window_text(ai::manager::get_active_ai_structure_for_side(side_));
00402             return;
00403         }
00404 
00405 
00406         if (selected==6) {
00407             std::stringstream s;
00408             if(resources::units) {
00409                 for(unit_map::iterator i = resources::units->begin()
00410                         ; i != resources::units->end()
00411                         ; ++i) {
00412                     if (i->side()!=side_) {
00413                         continue;
00414                     }
00415                     s << i->get_location();
00416                     if (i->can_recruit()) {
00417                         s << " LEADER ";
00418                     }
00419 
00420                     s << "id=[" << i->id() << "] " << i->type_id()
00421                         << "; L" << i->level()<< "; "
00422                         << i->experience() << '/'
00423                         << i->max_experience() << " xp; "
00424                         << i->hitpoints() << '/'
00425                         << i->max_hitpoints()<<" hp.\n";
00426                     foreach (const std::string &str, i->get_traits_list() ) {
00427                         s << "\t" << str<< std::endl;
00428                     }
00429                     s << std::endl << std::endl;
00430                 }
00431             }
00432             model_.set_inspect_window_text(s.str());
00433             return;
00434         }
00435 
00436     }
00437 
00438     virtual void update_view_from_model()
00439     {
00440         show_stuff_list();
00441         //handle_stuff_list_selection();
00442     }
00443 private:
00444     int side_;
00445 };
00446 
00447 
00448 //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.
00449 class tgamestate_inspector::controller {
00450 public:
00451     typedef std::vector< boost::shared_ptr<single_mode_controller> > sm_controller_ptr_vector;
00452     controller(model &m)
00453         : model_(m)
00454         , sm_controllers_()
00455     {
00456         sm_controllers_.push_back(
00457                 boost::shared_ptr<single_mode_controller>(new variable_mode_controller("variables",model_)));
00458         sm_controllers_.push_back(
00459                 boost::shared_ptr<single_mode_controller>(new unit_mode_controller("units",model_)));
00460         //foreach team
00461         int sides = resources::teams
00462                 ? static_cast<int>((*resources::teams).size())
00463                 : 0;
00464         for( int side = 1; side<=sides; ++side) {
00465             std::string side_str = str_cast(side);
00466             sm_controllers_.push_back(boost::shared_ptr<single_mode_controller>(
00467                     new team_mode_controller(std::string("team ")+side_str,model_,side)));
00468         }
00469     }
00470 
00471     boost::shared_ptr<single_mode_controller> get_sm_controller()
00472     {
00473         int selected = model_.stuff_types_list->get_selected_row();
00474         if (selected==-1) {
00475             //TODO: select row (maybe remember last selected row?...)
00476             selected=0;
00477         }
00478         return sm_controllers_.at(selected);
00479     }
00480 
00481     void show_stuff_types_list()
00482     {
00483         model_.clear_stuff_types_list();
00484         foreach (boost::shared_ptr<single_mode_controller> sm_controller, sm_controllers_ ) {
00485             model_.add_row_to_stuff_types_list(sm_controller->name(),sm_controller->name());
00486         }
00487     }
00488 
00489 
00490     void show_title()
00491     {
00492         model_.inspector_name->set_label(model_.name);
00493     }
00494 
00495 
00496     void update_view_from_model()
00497     {
00498         boost::shared_ptr<single_mode_controller> c = get_sm_controller();
00499 
00500         show_title();
00501         c->update_view_from_model();
00502     }
00503 
00504 
00505     void handle_stuff_list_item_clicked()
00506     {
00507         model_.set_inspect_window_text("");
00508         boost::shared_ptr<single_mode_controller> c = get_sm_controller();
00509         c->handle_stuff_list_selection();
00510     }
00511 
00512 
00513     void handle_stuff_types_list_item_clicked()
00514     {
00515         model_.clear_stuff_list();
00516         model_.set_inspect_window_text("");
00517         boost::shared_ptr<single_mode_controller> c = get_sm_controller();
00518         c->update_view_from_model();//TODO: 'activate'
00519     }
00520 
00521 
00522 private:
00523     model &model_;
00524     sm_controller_ptr_vector sm_controllers_;
00525 };
00526 
00527 
00528 //The view is an interface that displays data (the model) and routes user commands to the controller to act upon that data.
00529 class tgamestate_inspector::view {
00530 public:
00531     view(const vconfig &cfg)
00532         : model_(cfg),controller_(model_)
00533     {
00534     }
00535 
00536     void pre_show(CVideo& /*video*/, twindow& window)
00537     {
00538         controller_.show_stuff_types_list();
00539         controller_.update_view_from_model();
00540         window.invalidate_layout();//workaround for assertion failure
00541     }
00542 
00543 
00544     void handle_stuff_list_item_clicked(twindow &window)
00545     {
00546         controller_.handle_stuff_list_item_clicked();
00547         window.invalidate_layout();//workaround for assertion failure
00548     }
00549 
00550     void handle_stuff_types_list_item_clicked(twindow &window)
00551     {
00552         controller_.handle_stuff_types_list_item_clicked();
00553         window.invalidate_layout();//workaround for assertion failure
00554     }
00555 
00556 
00557     void bind(twindow &window)
00558     {
00559         model_.stuff_list = &find_widget<tlistbox>(&window, "stuff_list", false);
00560         model_.stuff_types_list = &find_widget<tlistbox>(&window, "stuff_types_list", false);
00561         model_.inspect = find_widget<tcontrol>(&window, "inspect", false,true);
00562         model_.inspector_name = &find_widget<tcontrol>(&window, "inspector_name", false);
00563 
00564 #ifdef GUI2_EXPERIMENTAL_LISTBOX
00565         connect_signal_notify_modified(*model_.stuff_list, boost::bind(
00566                   &tgamestate_inspector::view::handle_stuff_list_item_clicked
00567                 , this
00568                 , boost::ref(window)));
00569 
00570         connect_signal_notify_modified(*model_.stuff_types_list, boost::bind(
00571                   &tgamestate_inspector::view::handle_stuff_list_item_clicked
00572                 , this
00573                 , boost::ref(window)));
00574 
00575 #else
00576         model_.stuff_list->set_callback_value_change(
00577             dialog_view_callback<tgamestate_inspector, tgamestate_inspector::view, &tgamestate_inspector::view::handle_stuff_list_item_clicked>);
00578 
00579         model_.stuff_types_list->set_callback_value_change(
00580             dialog_view_callback<tgamestate_inspector, tgamestate_inspector::view, &tgamestate_inspector::view::handle_stuff_types_list_item_clicked>);
00581 #endif
00582 
00583     }
00584 
00585 private:
00586     model model_;
00587     controller controller_;
00588 };
00589 
00590 
00591 REGISTER_DIALOG(gamestate_inspector)
00592 
00593 tgamestate_inspector::tgamestate_inspector(const vconfig &cfg)
00594     : view_()
00595 {
00596 
00597     view_ = boost::shared_ptr<view>(new view(cfg));
00598 }
00599 
00600 boost::shared_ptr<tgamestate_inspector::view> tgamestate_inspector::get_view()
00601 {
00602     return view_;
00603 }
00604 
00605 void tgamestate_inspector::pre_show(CVideo& video, twindow& window)
00606 {
00607     view_->bind(window);
00608     view_->pre_show(video,window);
00609 }
00610 
00611 } //end of namespace gui2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:02:58 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs