The Battle for Wesnoth  1.19.2+dev
wml_error.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2024
3  by Iris Morelle <shadowm2006@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #define GETTEXT_DOMAIN "wesnoth-lib"
17 
19 
20 #include "addon/info.hpp"
21 // Needs the full path to avoid confusion with gui/dialogs/addon/manager.hpp.
22 #include "../../addon/manager.hpp"
23 #include "desktop/clipboard.hpp"
24 #include "filesystem.hpp"
26 #include "gui/widgets/button.hpp"
28 #include "gui/widgets/window.hpp"
30 
31 #include "gettext.hpp"
32 
33 #include <functional>
34 
35 namespace
36 {
37 
38 void strip_trailing_dir_separators(std::string& str)
39 {
40  while(filesystem::is_path_sep(str.back())) {
41  str.erase(str.size() - 1);
42  }
43 }
44 
45 std::string format_file_list(const std::vector<std::string>& files_original)
46 {
47  if(files_original.empty()) {
48  return "";
49  }
50 
51  const std::string& addons_path = filesystem::get_addons_dir();
52  std::vector<std::string> files(files_original);
53 
54  for(std::string & file : files)
55  {
56  std::string base;
57  std::string filename = filesystem::base_name(file);
58  std::string parent_path;
59 
60  const bool is_main_cfg = filename == "_main.cfg";
61 
62  if(is_main_cfg) {
63  parent_path = filesystem::directory_name(file) + "/..";
64  } else {
65  parent_path = filesystem::directory_name(file);
66  }
67 
68  // Only proceed to pretty-format the filename if it's from the add-ons
69  // directory.
70  if(filesystem::normalize_path(parent_path) != filesystem::normalize_path(addons_path)) {
71  continue;
72  }
73 
74  if(is_main_cfg) {
75  base = filesystem::directory_name(file);
76  // HACK: fool filesystem::base_name() into giving us the parent directory name
77  // alone by making base seem not like a directory path,
78  // otherwise it returns an empty string.
79  strip_trailing_dir_separators(base);
80  base = filesystem::base_name(base);
81  } else {
82  base = filename;
83  }
84 
85  if(base.empty()) {
86  // We did something wrong. In the interest of not messing up the
87  // report, leave the original filename intact.
88  continue;
89  }
90 
91  //
92  // Display the name as an add-on name instead of a filename.
93  //
94 
95  if(!is_main_cfg) {
96 
97  if(base.size() > filesystem::wml_extension.size()) {
98  const std::size_t suffix_pos = base.size() - filesystem::wml_extension.size();
99  if(base.substr(suffix_pos) == filesystem::wml_extension) {
100  base.erase(suffix_pos);
101  }
102  }
103  }
104 
105  if(have_addon_install_info(base)) {
106  // _info.cfg may have the add-on's title starting with 1.11.7,
107  // if the add-on was downloaded using the revised _info.cfg writer.
108  config info_cfg;
109  get_addon_install_info(base, info_cfg);
110 
111  if(!info_cfg.empty() && !info_cfg["title"].empty()) {
112  file = info_cfg["title"].str();
113  continue;
114  }
115  }
116 
117  // Fallback to using a synthetic title with underscores replaced with
118  // whitespace.
119  file = make_addon_title(base);
120  }
121 
122  if(files.size() == 1) {
123  return utils::indent(files.front());
124  }
125 
126  return utils::bullet_list(files);
127 }
128 }
129 
130 namespace gui2::dialogs
131 {
132 
133 REGISTER_DIALOG(wml_error)
134 
135 wml_error::wml_error(const std::string& summary,
136  const std::string& post_summary,
137  const std::vector<std::string>& files,
138  const std::string& details)
139  : modal_dialog(window_id())
140  , have_files_(!files.empty())
141  , have_post_summary_(!post_summary.empty())
142  , report_()
143 {
144  const std::string& file_list_text = format_file_list(files);
145 
146  report_ = summary;
147 
148  if(!file_list_text.empty()) {
149  report_ += "\n" + file_list_text;
150  }
151 
152  if(!post_summary.empty()) {
153  report_ += "\n\n" + post_summary;
154  }
155 
156  report_ += "\n\n";
157  report_ += _("Details:");
158  report_ += "\n\n" + utils::indent(details);
159  // Since this is likely to be pasted into a text file, add a final line
160  // break for convenience, since otherwise the report ends mid-line.
161  report_ += "\n";
162 
163  register_label("summary", true, summary);
164  register_label("post_summary", true, post_summary);
165  register_label("files", true, file_list_text);
166  register_label("details", true, details);
167 }
168 
170 {
171  if(!have_files_) {
172  styled_widget& filelist = find_widget<styled_widget>(&window, "files", false);
174  }
175 
176  if(!have_post_summary_) {
177  styled_widget& post_summary
178  = find_widget<styled_widget>(&window, "post_summary", false);
180  }
181 
182  button& copy_button = find_widget<button>(&window, "copy", false);
183 
185  copy_button, std::bind(&wml_error::copy_report_callback, this));
186 
188  copy_button.set_active(false);
189  copy_button.set_tooltip(_("Clipboard support not found, contact your packager"));
190  }
191 }
192 
194 {
196 }
197 
198 } // end namespace dialogs
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:106
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:101
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
bool empty() const
Definition: config.cpp:852
Simple push button.
Definition: button.hpp:36
virtual void set_active(const bool active) override
See styled_widget::set_active.
Definition: button.cpp:64
Abstract base class for all modal dialogs.
virtual void pre_show(window &window) override
Actions to be taken before showing the window.
Definition: wml_error.cpp:169
void set_tooltip(const t_string &tooltip)
void set_visible(const visibility visible)
Definition: widget.cpp:469
@ invisible
The user set the widget invisible, that means:
base class of top level items, the only item which needs to store the final canvases to draw on.
Definition: window.hpp:61
Declarations for File-IO.
static std::string _(const char *str)
Definition: gettext.hpp:93
This file contains the window object, this object is a top level container which has the event manage...
std::string make_addon_title(const std::string &id)
Replaces underscores to dress up file or dirnames as add-on titles.
Definition: info.cpp:319
void copy_to_clipboard(const std::string &text, const bool)
Copies text to the clipboard.
Definition: clipboard.cpp:32
bool available()
Whether wesnoth was compiled with support for a clipboard.
Definition: clipboard.cpp:53
const std::string wml_extension
Definition: filesystem.hpp:80
std::string base_name(const std::string &file, const bool remove_extension)
Returns the base filename of a file, with directory name stripped.
std::string directory_name(const std::string &file)
Returns the directory name of a file, with filename stripped.
std::string get_addons_dir()
bool is_path_sep(char c)
Returns whether c is a path separator.
std::string normalize_path(const std::string &fpath, bool normalize_separators, bool resolve_dot_entries)
Returns the absolute path of a file.
REGISTER_DIALOG(editor_edit_unit)
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal &signal)
Connects a signal handler for a left mouse button click.
Definition: dispatcher.cpp:177
std::string indent(const std::string &string, std::size_t indent_size)
Indent a block of text.
std::string bullet_list(const T &v, std::size_t indent=4, const std::string &bullet=font::unicode_bullet)
Generates a new string containing a bullet list.