The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
wml_error.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2014 - 2025
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"
29
30#include "gettext.hpp"
31
32#include <functional>
33
34namespace
35{
36
37void strip_trailing_dir_separators(std::string& str)
38{
39 while(filesystem::is_path_sep(str.back())) {
40 str.erase(str.size() - 1);
41 }
42}
43
44std::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
96 if(base.size() > filesystem::wml_extension.size()) {
97 const std::size_t suffix_pos = base.size() - filesystem::wml_extension.size();
98 if(base.substr(suffix_pos) == filesystem::wml_extension) {
99 base.erase(suffix_pos);
100 }
101 }
102 }
103
104 if(have_addon_install_info(base)) {
105 // _info.cfg may have the add-on's title starting with 1.11.7,
106 // if the add-on was downloaded using the revised _info.cfg writer.
107 config info_cfg;
108 get_addon_install_info(base, info_cfg);
109
110 if(!info_cfg.empty() && !info_cfg["title"].empty()) {
111 file = info_cfg["title"].str();
112 continue;
113 }
114 }
115
116 // Fallback to using a synthetic title with underscores replaced with
117 // whitespace.
118 file = make_addon_title(base);
119 }
120
121 if(files.size() == 1) {
122 return utils::indent(files.front());
123 }
124
125 return utils::bullet_list(files);
126}
127}
128
129namespace gui2::dialogs
130{
131
132REGISTER_DIALOG(wml_error)
133
134wml_error::wml_error(const std::string& summary,
135 const std::string& post_summary,
136 const std::vector<std::string>& files,
137 const std::string& details)
138 : modal_dialog(window_id())
139 , have_files_(!files.empty())
140 , have_post_summary_(!post_summary.empty())
141 , report_()
142{
143 const std::string& file_list_text = format_file_list(files);
144
145 report_ = summary;
146
147 if(!file_list_text.empty()) {
148 report_ += "\n" + file_list_text;
149 }
150
151 if(!post_summary.empty()) {
152 report_ += "\n\n" + post_summary;
153 }
154
155 report_ += "\n\n";
156 report_ += _("Details:");
157 report_ += "\n\n" + utils::indent(details);
158 // Since this is likely to be pasted into a text file, add a final line
159 // break for convenience, since otherwise the report ends mid-line.
160 report_ += "\n";
161
162 register_label("summary", true, summary);
163 register_label("post_summary", true, post_summary);
164 register_label("files", true, file_list_text);
165 register_label("details", true, details);
166}
167
169{
170 if(!have_files_) {
171 styled_widget& filelist = find_widget<styled_widget>("files");
173 }
174
175 if(!have_post_summary_) {
176 styled_widget& post_summary
177 = find_widget<styled_widget>("post_summary");
179 }
180
181 button& copy_button = find_widget<button>("copy");
182
183 connect_signal_mouse_left_click(
184 copy_button, std::bind(&wml_error::copy_report_callback, this));
185}
186
191
192} // 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:102
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:97
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
bool empty() const
Definition config.cpp:823
Simple push button.
Definition button.hpp:36
Abstract base class for all modal dialogs.
virtual void pre_show() override
Actions to be taken before showing the window.
void set_visible(const visibility visible)
Definition widget.cpp:479
@ invisible
The user set the widget invisible, that means:
Declarations for File-IO.
static std::string _(const char *str)
Definition gettext.hpp:100
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:299
#define REGISTER_DIALOG(window_id)
Wrapper for REGISTER_DIALOG2.
void copy_to_clipboard(const std::string &text)
Copies text to the clipboard.
Definition clipboard.cpp:24
const std::string wml_extension
std::string base_name(const std::string &file, const bool remove_extension=false)
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 &path, bool normalize_separators=false, bool resolve_dot_entries=false)
Returns the absolute path of a file.
STL namespace.
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.
std::string filename
Filename.