The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
wml_error.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2016 by Ignacio R. Morelle <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
18 
19 #include "addon/info.hpp"
20 #include "addon/manager.hpp"
21 #include "desktop/clipboard.hpp"
22 #include "filesystem.hpp"
24 #include "gui/widgets/button.hpp"
25 #include "gui/widgets/control.hpp"
26 #include "gui/widgets/settings.hpp"
27 #include "gui/widgets/window.hpp"
29 
30 #include "gettext.hpp"
31 
32 #include "utils/functional.hpp"
33 
34 namespace
35 {
36 
37 void strip_trailing_dir_separators(std::string& str)
38 {
39  while(filesystem::is_path_sep(str[str.size() - 1])) {
40  str.erase(str.size() - 1);
41  }
42 }
43 
44 std::string format_file_list(const std::vector<std::string>& files_original)
45 {
46  if(files_original.empty()) {
47  return "";
48  }
49 
50  const std::string& addons_path = filesystem::get_addons_dir();
51  std::vector<std::string> files(files_original);
52 
53  for(std::string & file : files)
54  {
55  std::string base;
56  std::string filename = filesystem::base_name(file);
57  std::string parent_path;
58 
59  const bool is_main_cfg = filename == "_main.cfg";
60 
61  if(is_main_cfg) {
62  parent_path = filesystem::directory_name(file) + "/..";
63  } else {
64  parent_path = filesystem::directory_name(file);
65  }
66 
67  // Only proceed to pretty-format the filename if it's from the add-ons
68  // directory.
69  if(filesystem::normalize_path(parent_path) != filesystem::normalize_path(addons_path)) {
70  continue;
71  }
72 
73  if(is_main_cfg) {
74  base = filesystem::directory_name(file);
75  // HACK: fool filesystem::base_name() into giving us the parent directory name
76  // alone by making base seem not like a directory path,
77  // otherwise it returns an empty string.
78  strip_trailing_dir_separators(base);
79  base = filesystem::base_name(base);
80  } else {
81  base = filename;
82  }
83 
84  if(base.empty()) {
85  // We did something wrong. In the interest of not messing up the
86  // report, leave the original filename intact.
87  continue;
88  }
89 
90  //
91  // Display the name as an add-on name instead of a filename.
92  //
93 
94  if(!is_main_cfg) {
95  // Remove the file extension first.
96  static const std::string wml_suffix = ".cfg";
97 
98  if(base.size() > wml_suffix.size()) {
99  const size_t suffix_pos = base.size() - wml_suffix.size();
100  if(base.substr(suffix_pos) == wml_suffix) {
101  base.erase(suffix_pos);
102  }
103  }
104  }
105 
106  if(have_addon_install_info(base)) {
107  // _info.cfg may have the add-on's title starting with 1.11.7,
108  // if the add-on was downloaded using the revised _info.cfg writer.
109  config cfg;
110  get_addon_install_info(base, cfg);
111 
112  const config& info_cfg = cfg.child("info");
113 
114  if(info_cfg && !info_cfg["title"].empty()) {
115  file = info_cfg["title"].str();
116  continue;
117  }
118  }
119 
120  // Fallback to using a synthetic title with underscores replaced with
121  // whitespace.
122  file = make_addon_title(base);
123  }
124 
125  if(files.size() == 1) {
126  return utils::indent(files.front());
127  }
128 
129  return utils::bullet_list(files);
130 }
131 }
132 
133 namespace gui2
134 {
135 
136 /*WIKI
137  * @page = GUIWindowDefinitionWML
138  * @order = 2_wml_error
139  *
140  * == WML error ==
141  *
142  * Dialog used to report WML parser or preprocessor errors.
143  *
144  * @begin{table}{dialog_widgets}
145  *
146  * summary & & control & m &
147  * Label used for displaying a brief summary of the error(s). $
148  *
149  * files & & control & m &
150  * Label used to display the list of affected add-ons or files, if
151  * applicable. It is hidden otherwise. It is recommended to place it
152  * after the summary label. $
153  *
154  * post_summary & & control & m &
155  * Label used for displaying instructions for reporting the error.
156  * It is recommended to place it after the file list label. It may be
157  * hidden if empty. $
158  *
159  * details & & control & m &
160  * Full report of the parser or preprocessor error(s) found. $
161  *
162  * copy & & button & m &
163  * Button that the user can click on to copy the error report to the
164  * system clipboard. $
165  *
166  * @end{table}
167  */
168 
170 
171 twml_error::twml_error(const std::string& summary,
172  const std::string& post_summary,
173  const std::vector<std::string>& files,
174  const std::string& details)
175  : have_files_(!files.empty())
176  , have_post_summary_(!post_summary.empty())
177  , report_()
178 {
179  set_restore(true);
180 
181  const std::string& file_list_text = format_file_list(files);
182 
183  report_ = summary;
184 
185  if(!file_list_text.empty()) {
186  report_ += "\n" + file_list_text;
187  }
188 
189  if(!post_summary.empty()) {
190  report_ += "\n\n" + post_summary;
191  }
192 
193  report_ += "\n\n";
194  report_ += _("Details:");
195  report_ += "\n\n" + utils::indent(details);
196  // Since this is likely to be pasted into a text file, add a final line
197  // break for convenience, since otherwise the report ends mid-line.
198  report_ += "\n";
199 
200  register_label("summary", true, summary);
201  register_label("post_summary", true, post_summary);
202  register_label("files", true, file_list_text);
203  register_label("details", true, details);
204 }
205 
207 {
208  if(!have_files_) {
209  tcontrol& filelist = find_widget<tcontrol>(&window, "files", false);
211  }
212 
213  if(!have_post_summary_) {
214  tcontrol& post_summary
215  = find_widget<tcontrol>(&window, "post_summary", false);
217  }
218 
219  tbutton& copy_button = find_widget<tbutton>(&window, "copy", false);
220 
222  copy_button, std::bind(&twml_error::copy_report_callback, this));
223 
225  copy_button.set_active(false);
226  copy_button.set_tooltip(_("Clipboard support not found, contact your packager"));
227  }
228 }
229 
231 {
233 }
234 
235 } // end namespace gui2
virtual void set_active(const bool active) override
See tcontrol::set_active.
Definition: button.cpp:58
std::string bullet_list(const T &v, size_t indent=4, const std::string &bullet=unicode_bullet)
Generates a new string containing a bullet list.
void pre_show(twindow &window)
Inherited from tdialog.
Definition: wml_error.cpp:206
bool available()
Whether wesnoth was compiled with support for a clipboard.
Definition: clipboard.cpp:61
bool have_post_summary_
Definition: wml_error.hpp:61
This file contains the window object, this object is a top level container which has the event manage...
REGISTER_DIALOG(label_settings)
void get_addon_install_info(const std::string &addon_name, config &cfg)
Gets the installation info (_info.cfg) for an add-on.
Definition: manager.cpp:107
void connect_signal_mouse_left_click(tdispatcher &dispatcher, const tsignal_function &signal)
Connects a signal handler for a left mouse button click.
Definition: dispatcher.hpp:710
STL namespace.
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:62
A class inherited from ttext_box that displays its input as stars.
Definition: field-fwd.hpp:23
Simple push button.
Definition: button.hpp:32
bool have_addon_install_info(const std::string &addon_name)
Returns true if there is a local installation info (_info.cfg) file for the add-on.
Definition: manager.cpp:102
The user set the widget invisible, that means:
Definition: widget.hpp:103
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
This file contains the settings handling of the widget library.
WML preprocessor/parser error report dialog.
Definition: wml_error.hpp:24
std::string normalize_path(const std::string &path)
Returns the absolute path of a file.
std::string base_name(const std::string &file)
Returns the base filename of a file, with directory name stripped.
void copy_report_callback()
Definition: wml_error.cpp:230
void set_tooltip(const t_string &tooltip)
Definition: control.hpp:265
std::string indent(const std::string &string, size_t indent_size)
Indent a block of text.
bool is_path_sep(char c)
Returns whether c is a path separator.
std::stringstream & wml_error()
Use this logger to send errors due to deprecated WML.
Definition: log.cpp:262
Declarations for File-IO.
Base class for all visible items.
Definition: control.hpp:34
void copy_to_clipboard(const std::string &text, const bool)
Copies text to the clipboard.
Definition: clipboard.cpp:40
std::string make_addon_title(const std::string &id)
Replaces underscores to dress up file or dirnames as add-on titles.
Definition: info.cpp:228
std::string get_addons_dir()
config & child(const std::string &key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:658
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
void set_visible(const tvisible::scoped_enum visible)
Definition: widget.cpp:445
GLsizei const GLcharARB ** string
Definition: glew.h:4503
std::string directory_name(const std::string &file)
Returns the directory name of a file, with filename stripped.
std::string report_
Definition: wml_error.hpp:62