gui/widgets/debug.cpp

Go to the documentation of this file.
00001 /* $Id: debug.cpp 54183 2012-05-17 16:21:47Z mordante $ */
00002 /*
00003    Copyright (C) 2008 - 2012 by Mark de Wever <koraq@xs4all.nl>
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 
00019 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
00020 
00021 #include "gui/widgets/debug.hpp"
00022 
00023 #include "foreach.hpp"
00024 #include "formatter.hpp"
00025 #include "gui/widgets/generator.hpp"
00026 #ifdef GUI2_EXPERIMENTAL_LISTBOX
00027 #include "gui/widgets/list.hpp"
00028 #else
00029 #include "gui/widgets/listbox.hpp"
00030 #endif
00031 #include "gui/widgets/scrollbar_container.hpp"
00032 #include "gui/widgets/window.hpp"
00033 #include "serialization/string_utils.hpp"
00034 
00035 #include <fstream>
00036 #include <iostream>
00037 
00038 namespace gui2 {
00039 
00040 namespace {
00041 
00042 /**
00043  * Gets the id of a grid child cell.
00044  *
00045  * @param parent_id               The id of the parent grid.
00046  * @param row                     Row number in the grid.
00047  * @param col                     Column number in the grid.
00048  *
00049  * @returns                       The id of the child cell.
00050  */
00051 std::string get_child_id(
00052         const std::string& parent_id, const unsigned row, const unsigned col)
00053 {
00054     // Originally used this formatter function but it managed to return empty
00055     // trings. No idea why so switched to using the good old lexical_cast
00056     // instead.
00057 //  return (formatter() << parent_id << "_C_" << row << '_' << col).c_str();
00058     std::string result = parent_id + "_C_"
00059             + lexical_cast<std::string>(row) + '_'
00060             + lexical_cast<std::string>(col);
00061 
00062     return result;
00063 }
00064 
00065 /**
00066  * Gets the id of a widget in a grid child cell.
00067  *
00068  * @param parent_id               The id of the parent grid.
00069  * @param row                     Row number in the grid.
00070  * @param col                     Column number in the grid.
00071  *
00072  * @returns                       The id of the widget.
00073  */
00074 std::string get_child_widget_id(
00075         const std::string& parent_id, const unsigned row, const unsigned col)
00076 {
00077     return get_child_id(parent_id, row, col) + "_W";
00078 }
00079 
00080 /** Gets the prefix of the filename. */
00081 std::string get_base_filename()
00082 {
00083     char buf[17] = {0};
00084     time_t t = time(NULL);
00085     tm* lt = localtime(&t);
00086     if(lt) {
00087         strftime(buf, sizeof(buf), "%Y%m%d_%H%M%S", lt);
00088     }
00089     static unsigned counter = 0;
00090     ++counter;
00091 
00092     return (formatter() << buf << '_' << counter << '_').str();
00093 }
00094     /***** ***** ***** ***** FLAGS ***** ***** ***** *****/
00095 
00096     const unsigned ALL = UINT_MAX;       /**< All levels/domains */
00097 
00098     const unsigned SIZE_INFO  = 1 << 0; /**<
00099                                          * Shows the size info of
00100                                          * children/widgets.
00101                                          */
00102     const unsigned STATE_INFO = 1 << 1; /**<
00103                                          * Shows the state info of widgets.
00104                                          */
00105     unsigned level_ = 0;
00106     unsigned domain_ = 0;
00107 } //namespace
00108 
00109 tdebug_layout_graph::tdebug_layout_graph(const twindow* window)
00110     : window_(window)
00111     , sequence_number_(0)
00112     , filename_base_(get_base_filename())
00113 {
00114 }
00115 
00116 void tdebug_layout_graph::set_level(const std::string& level)
00117 {
00118     if(level.empty()) {
00119         level_ = ALL; /** @todo Should default to 0. */
00120         return;
00121     }
00122 
00123     std::vector<std::string> params = utils::split(level);
00124 
00125     foreach(const std::string& param, params) {
00126         if(param == "all") {
00127             level_ = ALL;
00128             // No need to look further eventhought invalid items are now
00129             // ignored.
00130             return;
00131         } else if(param == "size") {
00132             level_ |= SIZE_INFO;
00133         } else if(param == "state") {
00134             level_ |= STATE_INFO;
00135         } else {
00136             // loging might not be up yet.
00137             std::cerr << "Unknown level '" << param << "' is ignored.\n";
00138         }
00139     }
00140 }
00141 
00142 void tdebug_layout_graph::set_domain(const std::string& domain)
00143 {
00144     if(domain.empty()) {
00145         // return error and die
00146         domain_ = ALL; /** @todo Should default to 0. */
00147         return;
00148     }
00149 
00150     std::vector<std::string> params = utils::split(domain);
00151 
00152     foreach(const std::string& param, params) {
00153         if(param == "all") {
00154             domain_ = ALL;
00155             // No need to look further eventhought invalid items are now
00156             // ignored.
00157             return;
00158         } else if(param == "show") {
00159             domain_ |= SHOW;
00160         } else if(param == "layout") {
00161             domain_ |= LAYOUT;
00162         } else {
00163             // loging might not be up yet.
00164             std::cerr << "Unknown domain '" << param << "' is ignored.\n";
00165         }
00166     }
00167 }
00168 
00169 void tdebug_layout_graph::generate_dot_file(
00170         const std::string& generator, const unsigned domain)
00171 {
00172     // domain == 0 must also evaluate to true.
00173     if((domain_ & domain) != domain) {
00174         return;
00175     }
00176 
00177     std::string id = window_->id();
00178     if(!id.empty()) {
00179         id += '_';
00180     }
00181     const std::string filename = filename_base_ + id
00182             + lexical_cast<std::string>(++sequence_number_)
00183             + "-" + generator + ".dot";
00184 
00185     std::ofstream file(filename.c_str());
00186 
00187     file << "//Basic layout graph for window id '" << window_->id()
00188         << "' using definition '" <<  window_->definition_ << "'.\n"
00189         << "digraph window {\n"
00190         << "\tnode [shape=record, style=filled, fillcolor=\"bisque\"];\n"
00191         << "\trankdir=LR;\n"
00192         ;
00193 
00194     widget_generate_info(file, window_, "root");
00195 
00196     file << "}\n";
00197 }
00198 
00199 void tdebug_layout_graph::widget_generate_info(std::ostream& out,
00200         const twidget* widget, const std::string& id, const bool embedded) const
00201 {
00202     assert(!id.empty());
00203 
00204     out << "\t" << id
00205         << " [label=<<table border=\"0\" cellborder=\"1\" cellspacing=\"0\">";
00206 
00207     widget_generate_basic_info(out, widget);
00208     if(level_ & STATE_INFO) widget_generate_state_info(out, widget);
00209     if(level_ & SIZE_INFO) widget_generate_size_info(out, widget);
00210 
00211     out << "</table>>";
00212     if(embedded) {
00213         out << ", fillcolor=\"palegoldenrod\"";
00214     }
00215     out << "];\n";
00216 
00217     const tgrid* grid = dynamic_cast<const tgrid*>(widget);
00218     if(!grid) {
00219         const tcontainer_* container = dynamic_cast<const tcontainer_*>(widget);
00220 
00221         if(container) {
00222 
00223             widget_generate_info(out, &container->grid(), id + "_G", true);
00224             out << "\t" << id << " -> "
00225                 << id << "_G"
00226                 << " [label=\"(grid)\"];\n";
00227         }
00228 
00229         const tscrollbar_container* scrollbar_container =
00230             dynamic_cast<const tscrollbar_container*>(widget);
00231 
00232         if(scrollbar_container) {
00233             widget_generate_info(out, scrollbar_container->content_grid_, id + "_C", true);
00234             out << "\t" << id << " -> "
00235                 << id << "_C"
00236                 << " [label=\"(content)\"];\n";
00237         }
00238 
00239         const tlistbox* listbox = dynamic_cast<const tlistbox*>(widget);
00240         if(listbox) {
00241             assert(listbox->generator_);
00242         }
00243 
00244         const tgenerator_* generator =
00245                 dynamic_cast<const tgenerator_*>(widget);
00246 
00247         if(generator) {
00248             for(size_t i = 0;
00249                     i < generator->get_item_count(); ++i) {
00250 
00251                 const std::string child_id =
00252                     id + "_I_" + lexical_cast<std::string>(i);
00253 
00254                 widget_generate_info(out,
00255                     &generator->item(i),
00256                     child_id, true);
00257 
00258                 out << "\t" << id << " -> "
00259                         << child_id
00260                         << " [label=\"(item)\"];\n";
00261             }
00262         }
00263     }
00264     if(grid) {
00265         grid_generate_info(out, grid, id);
00266     }
00267 }
00268 
00269 static std::string format_label(std::string label)
00270 {
00271     if(label.size() > 50) {
00272         label = label.substr(0, 50) + "...";
00273     }
00274 
00275     // Replace characters that break the dot file/
00276     std::replace(label.begin(), label.end(), '>', '_');
00277 
00278     return label;
00279 }
00280 
00281 void tdebug_layout_graph::widget_generate_basic_info(
00282         std::ostream& out, const twidget* widget) const
00283 {
00284     std::string header_background = level_ & (SIZE_INFO|STATE_INFO)
00285        ? " bgcolor=\"gray\"" : "";
00286     const tcontrol* control = dynamic_cast<const tcontrol*>(widget);
00287 
00288     out << "<tr><td" << header_background << ">" << '\n'
00289         << "type=" << get_type(widget) << '\n'
00290         << "</td></tr>" << '\n'
00291         << "<tr><td" << header_background << ">" << '\n'
00292         << "id=" << widget->id() << '\n'
00293         << "</td></tr>" << '\n'
00294         << "<tr><td" << header_background << ">" << '\n'
00295         << "address=" << widget << '\n'
00296         << "</td></tr>" << '\n'
00297         << "<tr><td" << header_background << ">" << '\n'
00298         << "parent=" << widget->parent_ << '\n'
00299         << "</td></tr>" << '\n';
00300         if(control) {
00301             out << "<tr><td" << header_background << ">" << '\n'
00302                 << "label=" << format_label(control->label()) << '\n'
00303                 << "<tr><td" << header_background << ">" << '\n'
00304                 << "definition=" << control->definition_ << '\n'
00305                 << "</td></tr>" << '\n'
00306                 << "</td></tr>\n";
00307         }
00308 }
00309 
00310 void tdebug_layout_graph::widget_generate_state_info(
00311         std::ostream& out, const twidget* widget) const
00312 {
00313     const tcontrol* control = dynamic_cast<const tcontrol*>(widget);
00314     if(!control) {
00315         return;
00316     }
00317 
00318     out << "<tr><td>\n"
00319         << "tooltip=" << control->tooltip() << '\n'
00320         << "</td></tr>\n"
00321         << "<tr><td>\n"
00322         << "help message" << control->help_message() << '\n'
00323         // FIXME add value and other specific items
00324         << "</td></tr>\n"
00325         << "<tr><td>\n"
00326         << "active=" << control->get_active() << '\n'
00327         << "</td></tr>\n"
00328         << "<tr><td>\n"
00329         << "visible=" << control->get_visible() << '\n'
00330         << "</td></tr>\n"
00331         << "<tr><td>\n"
00332         << "drawing action=" << control->get_drawing_action() << '\n'
00333         << "</td></tr>\n"
00334         << "<tr><td>\n"
00335         << "clip rect=" << control->clip_rect_ << '\n'
00336         << "</td></tr>\n"
00337         << "<tr><td>\n"
00338         << "use tooltip on label overflow="
00339             << control->get_use_tooltip_on_label_overflow() << '\n'
00340         << "</td></tr>\n"
00341         << "<tr><td>\n"
00342         << "does block click dismiss="
00343             << control->disable_click_dismiss() << '\n'
00344         << "</td></tr>\n";
00345 
00346     const tscrollbar_container* scrollbar_container =
00347         dynamic_cast<const tscrollbar_container*>(widget);
00348 
00349     if(scrollbar_container) {
00350         out << "<tr><td>\n"
00351             << "vertical_scrollbar_mode_="
00352                 << scrollbar_container->vertical_scrollbar_mode_ << '\n'
00353             << "</td></tr>\n"
00354             << "<tr><td>\n"
00355             << "horizontal_scrollbar_mode_="
00356                 << scrollbar_container->horizontal_scrollbar_mode_ << '\n'
00357             << "</td></tr>\n";
00358     }
00359 }
00360 
00361 void tdebug_layout_graph::widget_generate_size_info(
00362         std::ostream& out, const twidget* widget) const
00363 {
00364     out << "<tr><td>\n"
00365         << "can wrap=" << widget->can_wrap() << '\n'
00366         << "</td></tr>\n"
00367         << "<tr><td>\n"
00368         << "size=" << widget->get_size() << '\n'
00369         << "</td></tr>\n"
00370         << "<tr><td>\n"
00371         << "position=" << widget->get_origin() << '\n'
00372         << "</td></tr>\n"
00373         << "<tr><td>\n"
00374         << "last_best_size_=" << widget->last_best_size_ << '\n'
00375         << "</td></tr>\n"
00376         << "<tr><td>\n"
00377         << "layout_size_=" << widget->layout_size_ << '\n'
00378         << "</td></tr>\n";
00379 
00380 
00381     const tcontrol* control = dynamic_cast<const tcontrol*>(widget);
00382 
00383     if(control) {
00384         out << "<tr><td>\n"
00385             << "minimum config size=" << control->get_config_minimum_size() << '\n'
00386             << "</td></tr>\n"
00387             << "<tr><td>\n"
00388             << "default config size=" << control->get_config_default_size() << '\n'
00389             << "</td></tr>\n"
00390             << "<tr><td>\n"
00391             << "maximum config size=" << control->get_config_maximum_size() << '\n'
00392             << "</td></tr>\n"
00393             << "<tr><td>\n"
00394             << "shrunken_=" << control->shrunken_ << '\n'
00395             << "</td></tr>\n";
00396     }
00397 
00398     const tcontainer_* container = dynamic_cast<const tcontainer_*>(widget);
00399 
00400     if(container) {
00401         out << "<tr><td>\n"
00402             << "border_space=" << container->border_space() << '\n'
00403             << "</td></tr>\n";
00404     }
00405 }
00406 
00407 void tdebug_layout_graph::grid_generate_info(std::ostream& out,
00408         const tgrid* grid, const std::string& parent_id) const
00409 {
00410     assert(!parent_id.empty());
00411 
00412     // maybe change the order to links, child, widgets so the output of the
00413     // dot file might look better.
00414 
00415     out << "\n\n\t// The children of " << parent_id << ".\n";
00416 
00417     for(unsigned row = 0; row < grid->get_rows(); ++row) {
00418         for(unsigned col = 0; col < grid->get_cols(); ++col) {
00419 
00420             const twidget* widget = grid->child(row, col).widget();
00421             assert(widget);
00422 
00423             widget_generate_info(
00424                     out, widget, get_child_widget_id(parent_id, row, col));
00425         }
00426     }
00427 
00428     out << "\n\t// The grid child data of " << parent_id << ".\n";
00429 
00430     for(unsigned row = 0; row < grid->get_rows(); ++row) {
00431         for(unsigned col = 0; col < grid->get_cols(); ++col) {
00432 
00433             child_generate_info(out, grid->child(row, col),
00434                 get_child_id(parent_id, row, col));
00435         }
00436     }
00437 
00438 
00439     out << "\n\t// The links of " << parent_id << ".\n";
00440 
00441     for(unsigned row = 0; row < grid->get_rows(); ++row) {
00442         for(unsigned col = 0; col < grid->get_cols(); ++col) {
00443 
00444             // grid -> child
00445             out << "\t" << parent_id << " -> "
00446                 << get_child_id(parent_id, row, col)
00447                 << " [label=\"(" << row << ',' << col
00448                 << ")\"];\n";
00449 
00450             // child -> widget
00451             out << "\t" << get_child_id(parent_id, row, col) << " -> "
00452                 << get_child_widget_id(parent_id, row, col) << ";\n";
00453         }
00454     }
00455 }
00456 
00457 void tdebug_layout_graph::child_generate_info(std::ostream& out,
00458         const tgrid::tchild& child, const std::string& id) const
00459 {
00460     assert(!id.empty());
00461 
00462     unsigned flags = child.get_flags();
00463 
00464     out << "\t" << id
00465         << " [style=\"\", label=<<table border=\"0\" "
00466             "cellborder=\"1\" cellspacing=\"0\">\n";
00467     out << "<tr><td>\n"
00468         << "vertical flag=";
00469 
00470     switch(flags & tgrid::VERTICAL_MASK) {
00471         case tgrid::VERTICAL_GROW_SEND_TO_CLIENT : out << "send to client"; break;
00472         case tgrid::VERTICAL_ALIGN_TOP           : out << "align to top"; break;
00473         case tgrid::VERTICAL_ALIGN_CENTER        : out << "center"; break;
00474         case tgrid::VERTICAL_ALIGN_BOTTOM        : out << "align to bottom"; break;
00475         default                                  :
00476             out << "unknown value("
00477                 << ((flags & tgrid::VERTICAL_MASK) >> tgrid::VERTICAL_SHIFT)
00478                 << ")";
00479     }
00480 
00481     out << "\n</td></tr>\n"
00482         << "<tr><td>\n"
00483         << "horizontal flag=";
00484 
00485     switch(flags & tgrid::HORIZONTAL_MASK) {
00486         case tgrid::HORIZONTAL_GROW_SEND_TO_CLIENT : out << "send to client"; break;
00487         case tgrid::HORIZONTAL_ALIGN_LEFT          : out << "align to left"; break;
00488         case tgrid::HORIZONTAL_ALIGN_CENTER        : out << "center"; break;
00489         case tgrid::HORIZONTAL_ALIGN_RIGHT         : out << "align to right"; break;
00490         default                                    :
00491             out << "unknown value("
00492                 << ((flags & tgrid::HORIZONTAL_MASK) >> tgrid::HORIZONTAL_SHIFT)
00493                 << ")";
00494     }
00495 
00496     out << "\n</td></tr>\n"
00497         << "<tr><td>\n"
00498         << "border location=";
00499 
00500     if((flags & tgrid::BORDER_ALL) == 0) {
00501         out << "none";
00502     } else if((flags & tgrid::BORDER_ALL) == tgrid::BORDER_ALL) {
00503         out << "all";
00504     } else {
00505         std::string result;
00506         if(flags & tgrid::BORDER_TOP)    result += "top, ";
00507         if(flags & tgrid::BORDER_BOTTOM) result += "bottom, ";
00508         if(flags & tgrid::BORDER_LEFT)   result += "left, ";
00509         if(flags & tgrid::BORDER_RIGHT)  result += "right, ";
00510 
00511         if(!result.empty()) {
00512             result.resize(result.size() - 2);
00513         }
00514 
00515         out << result;
00516     }
00517 
00518     out << "\n</td></tr>\n"
00519         << "<tr><td>\n"
00520         << "border_size="<< child.get_border_size()
00521         << "\n</td></tr>\n";
00522 
00523     out << "</table>>];\n";
00524 }
00525 
00526 std::string tdebug_layout_graph::get_type(const twidget* widget) const
00527 {
00528     const tcontrol* control = dynamic_cast<const tcontrol*>(widget);
00529     if(control) {
00530         return control->get_control_type();
00531     } else {
00532         const tgrid* grid = dynamic_cast<const tgrid*>(widget);
00533         const tgenerator_* generator =
00534                 dynamic_cast<const tgenerator_*>(widget);
00535 
00536         if(grid) {
00537             return "grid";
00538         } else if(generator) {
00539             return "generator";
00540         } else {
00541             return "unknown";
00542         }
00543     }
00544 }
00545 
00546 } // namespace gui2
00547 #endif
00548 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

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