The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
description.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 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 "desktop/clipboard.hpp"
20 #include "desktop/open.hpp"
21 #include "formula/string_utils.hpp"
22 #include "gettext.hpp"
24 #include "gui/widgets/button.hpp"
25 #include "gui/widgets/settings.hpp"
26 #include "gui/widgets/text_box.hpp"
27 #include "gui/widgets/window.hpp"
28 #include "language.hpp"
29 #include "preferences.hpp"
30 #include "strftime.hpp"
31 
32 #include "utils/functional.hpp"
33 
34 #include <stdexcept>
35 
36 namespace
37 {
38 std::string format_addon_time(time_t time)
39 {
40  if(time) {
41  char buf[1024] = { 0 };
42  struct std::tm* const t = std::localtime(&time);
43 
45  ? "%Y-%m-%d %I:%M %p"
46  : "%Y-%m-%d %H:%M";
47 
48  if(util::strftime(buf, sizeof(buf), format, t)) {
49  return buf;
50  }
51  }
52 
54 }
55 
56 std::string langcode_to_string(const std::string& lcode)
57 {
58  for(const auto & ld : get_languages())
59  {
60  if(ld.localename == lcode || ld.localename.substr(0, 2) == lcode) {
61  return ld.language;
62  }
63  }
64 
65  return "";
66 }
67 
69  const addon_tracking_info& state)
70 {
71  std::string colorname = "";
72 
73  // NOTE: these Pango color names must match the colors used
74  // in describe_addon_status() for GUI1.
75 
76  switch(state.state) {
77  case ADDON_NONE:
78  return str;
79  case ADDON_INSTALLED:
80  case ADDON_NOT_TRACKED:
81  colorname = "#00ff00"; // GOOD_COLOR
82  break;
84  colorname = "#ffff00"; // YELLOW_COLOR/color_upgradable
85  break;
87  colorname = "#ff7f00"; // <255,127,0>/color_outdated
88  break;
90  colorname = "#ff0000"; // BAD_COLOR
91  break;
92  default:
93  colorname = "#777777"; // GRAY_COLOR
94  break;
95  }
96 
97  return "<span color='" + colorname + "'>" + str + "</span>";
98 }
99 
100 std::string describe_addon_state_info(const addon_tracking_info& state)
101 {
102  std::string s;
103 
104  utils::string_map i18n_symbols;
105  i18n_symbols["local_version"] = state.installed_version.str();
106 
107  switch(state.state) {
108  case ADDON_NONE:
109  if(!state.can_publish) {
110  s = _("addon_state^Not installed");
111  } else {
112  s = _("addon_state^Published, not installed");
113  }
114  break;
115  case ADDON_INSTALLED:
116  if(!state.can_publish) {
117  s = _("addon_state^Installed");
118  } else {
119  s = _("addon_state^Published");
120  }
121  break;
122  case ADDON_NOT_TRACKED:
123  if(!state.can_publish) {
124  s = _("addon_state^Installed, not tracking local version");
125  } else {
126  // Published add-ons often don't have local status information,
127  // hence untracked. This should be considered normal.
128  s = _("addon_state^Published, not tracking local version");
129  }
130  break;
132  const std::string vstr
133  = !state.can_publish
134  ? _("addon_state^Installed ($local_version|), "
135  "upgradable")
136  : _("addon_state^Published ($local_version| "
137  "installed), upgradable");
138  s = utils::interpolate_variables_into_string(vstr, &i18n_symbols);
139  } break;
141  const std::string vstr
142  = !state.can_publish
143  ? _("addon_state^Installed ($local_version|), "
144  "outdated on server")
145  : _("addon_state^Published ($local_version| "
146  "installed), outdated on server");
147  s = utils::interpolate_variables_into_string(vstr, &i18n_symbols);
148  } break;
150  if(!state.can_publish) {
151  s = _("addon_state^Installed, broken");
152  } else {
153  s = _("addon_state^Published, broken");
154  }
155  break;
156  default:
157  s = _("addon_state^Unknown");
158  }
159 
160  return colorify_addon_state_string(s, state);
161 }
162 
163 /**
164  * Retrieves an element from the given associative container or dies in some
165  * way.
166  *
167  * It fails an @a assert() check or throws an exception if the requested element
168  * does not exist.
169  *
170  * @return An element from the container that is guranteed to have existed
171  * before running this function.
172  */
173 template <typename MapT>
174 typename MapT::mapped_type const& const_at(typename MapT::key_type const& key,
175  MapT const& map)
176 {
177  typename MapT::const_iterator it = map.find(key);
178  if(it == map.end()) {
179  assert(it != map.end());
180  throw std::out_of_range(
181  "const_at()"); // Shouldn't get here without disabling assert()
182  }
183  return it->second;
184 }
185 
186 std::string make_display_dependencies(const std::string& addon_id,
187  const addons_list& addons_list,
188  const addons_tracking_list& addon_states)
189 {
190  const addon_info& addon = const_at(addon_id, addons_list);
191  std::string str;
192 
193  const std::set<std::string>& deps = addon.resolve_dependencies(addons_list);
194 
195  for(const auto & dep_id : deps)
196  {
197  addon_info dep;
198  addon_tracking_info depstate;
199 
200  addons_list::const_iterator ali = addons_list.find(dep_id);
201  addons_tracking_list::const_iterator tli = addon_states.find(dep_id);
202 
203  if(ali == addons_list.end()) {
204  dep.id = dep_id; // Build dummy addon_info.
205  } else {
206  dep = ali->second;
207  }
208 
209  if(tli == addon_states.end()) {
210  depstate = get_addon_tracking_info(dep);
211  } else {
212  depstate = tli->second;
213  }
214 
215  if(!str.empty()) {
216  str += ", ";
217  }
218 
219  str += colorify_addon_state_string(dep.display_title(), depstate);
220  }
221 
222  return str;
223 }
224 }
225 
226 namespace gui2
227 {
228 
229 /*WIKI
230  * @page = GUIWindowDefinitionWML
231  * @order = 2_addon_description
232  *
233  * == Add-on description ==
234  *
235  * Add-on description and details for the add-ons manager interface.
236  *
237  * @begin{table}{dialog_widgets}
238  *
239  * image & & control & m &
240  * Label for displaying the add-on icon, in a 72x72 area. $
241  *
242  * title & & control & m &
243  * Dialog title label, corresponding to the add-on name. $
244  *
245  * type & & control & m &
246  * Label for displaying the add-on's type. $
247  *
248  * version & & control & m &
249  * Label for displaying the add-on version number. $
250  *
251  * status & & control & m &
252  * Label for displaying the current installation/upgradability status. $
253  *
254  * author & & control & m &
255  * Label for displaying the add-on author/maintainer name. $
256  *
257  * size & & control & m &
258  * Label for displaying the add-on package size. $
259  *
260  * downloads & & control & m &
261  * Label for displaying the add-on's download count. $
262  *
263  * description & & control & m &
264  * Text label for displaying the add-on's description. The control can
265  * be given a text, this text is shown when the addon has no
266  * description. If the addon has a description this field shows the
267  * description of the addon. $
268  *
269  * translations & & control & m &
270  * Label for displaying a list of translations provided by the add-on.
271  * Like the ''description'' it can also show a default text if no
272  * translations are available. $
273  *
274  * dependencies & & control & m &
275  * Label for displaying a list of dependencies of the add-on. Like the
276  * ''description'' it can also show a default text if no dependencies
277  * are defined. $
278  *
279  * updated & & control & m &
280  * Label displaying the add-on's last upload date. $
281  *
282  * created & & control & m &
283  * Label displaying the add-on's first upload date. $
284  *
285  * url & & text_box & m &
286  * Textbox displaying the add-on's feedback page URL if provided by
287  * the server. $
288  *
289  * url_go & & button & m &
290  * Button for launching a web browser to visit the add-on's feedback
291  * page URL if provided by the server. $
292  *
293  * url_copy & & button & m &
294  * Button for copying the add-on's feedback page URL to clipboard if
295  * provided by the server. $
296  *
297  * url_none & & control & m &
298  * Label displayed instead of the other url_* widgets when no URL is
299  * provided by the server.
300  *
301  * @end{table}
302  */
303 
304 REGISTER_DIALOG(addon_description)
305 
306 taddon_description::taddon_description(const std::string& addon_id,
307  const addons_list& addons_list,
308  const addons_tracking_list& addon_states)
309  : feedback_url_()
310 {
311  const addon_info& addon = const_at(addon_id, addons_list);
312  const addon_tracking_info& state = const_at(addon_id, addon_states);
313 
314  const std::string& created_text = format_addon_time(addon.created);
315  const std::string& updated_text = format_addon_time(addon.updated);
316 
317  register_label("image", true, addon.display_icon());
318  register_label("title", true, addon.title);
319  register_label("version", true, addon.version);
320  register_label("status", true, describe_addon_state_info(state), true);
321  register_label("author", true, addon.author);
322  register_label("type", true, addon.display_type());
323  register_label("size", true, size_display_string(addon.size));
324  register_label("downloads", true, std::to_string(addon.downloads));
325  register_label("created", true, created_text);
326  register_label("updated", true, updated_text);
327  if(!addon.description.empty()) {
328  register_label("description", true, addon.description);
329  }
330  if(!addon.depends.empty()) {
331  register_label(
332  "dependencies",
333  true,
334  make_display_dependencies(addon_id, addons_list, addon_states),
335  true);
336  }
337 
338  feedback_url_ = addon.feedback_url;
339 
340  std::string languages;
341 
342  for(const auto & lc : addon.locales)
343  {
344  const std::string& langlabel = langcode_to_string(lc);
345  if(!langlabel.empty()) {
346  if(!languages.empty()) {
347  languages += ", ";
348  }
349  languages += langlabel;
350  }
351  }
352 
353  if(!languages.empty()) {
354  register_label("translations", true, languages);
355  }
356 }
357 
359 {
360  /* TODO: ask for confirmation */
361 
363 }
364 
366 {
368 }
369 
371 {
372  tcontrol& url_none = find_widget<tcontrol>(&window, "url_none", false);
373  tbutton& url_go_button = find_widget<tbutton>(&window, "url_go", false);
374  tbutton& url_copy_button = find_widget<tbutton>(&window, "url_copy", false);
375  ttext_box& url_textbox = find_widget<ttext_box>(&window, "url", false);
376 
377  url_textbox.set_value(feedback_url_);
378  url_textbox.set_active(false);
379 
380  if(!feedback_url_.empty()) {
382 
384  url_go_button,
385  std::bind(&taddon_description::browse_url_callback, this));
386 
388  url_copy_button,
389  std::bind(&taddon_description::copy_url_callback, this));
390 
392  url_copy_button.set_active(false);
393  url_copy_button.set_tooltip(_("Clipboard support not found, contact your packager"));
394  }
395  } else {
396  url_go_button.set_active(false);
397  url_copy_button.set_active(false);
398 
399  url_go_button.set_visible(tcontrol::tvisible::invisible);
400  url_copy_button.set_visible(tcontrol::tvisible::invisible);
401  url_textbox.set_visible(tcontrol::tvisible::invisible);
402  }
403 
405  // No point in displaying the button on platforms that can't do
406  // open_object().
407  url_go_button.set_visible(tcontrol::tvisible::invisible);
408  }
409 }
410 
411 } // namespace gui2
int size
Definition: info.hpp:41
size_t strftime(char *str, size_t count, const std::string &format, const std::tm *time)
Definition: strftime.cpp:132
ADDON_STATUS state
Definition: state.hpp:55
std::string interpolate_variables_into_string(const std::string &str, const string_map *const symbols)
Function which will interpolate variables, starting with '$' in the string 'str' with the equivalent ...
bool available()
Whether wesnoth was compiled with support for a clipboard.
Definition: clipboard.cpp:61
std::string size_display_string(double size)
Get a human-readable representation of the specified byte count.
Definition: info.cpp:219
This file contains the window object, this object is a top level container which has the event manage...
REGISTER_DIALOG(label_settings)
std::string description
Definition: info.hpp:33
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.
Class for a single line text area.
Definition: text_box.hpp:118
std::string feedback_url
Definition: info.hpp:54
GLdouble GLdouble t
Definition: glew.h:1366
time_t created
Definition: info.hpp:57
version_info installed_version
Definition: state.hpp:58
virtual void set_value(const std::string &text)
The set_value is virtual for the tpassword_box class.
Definition: text.cpp:95
No tracking information available.
Definition: state.hpp:35
Add-on is not installed.
Definition: state.hpp:24
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
The user set the widget invisible, that means:
Definition: widget.hpp:103
Desktop environment interaction functions.
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
Version in the server is older than local installation.
Definition: state.hpp:30
std::map< std::string, t_string > string_map
This file contains the settings handling of the widget library.
std::string display_title() const
Get a title or automatic title for display.
Definition: info.cpp:124
std::map< std::string, addon_info > addons_list
Definition: info.hpp:26
std::string id
Definition: info.hpp:31
Version in the server is newer than local installation.
Definition: state.hpp:28
GLenum GLuint GLsizei const char * buf
Definition: glew.h:2498
const std::string unicode_em_dash
Dependencies not satisfied.
Definition: state.hpp:33
std::string str() const
Serializes the version number into string form.
Definition: version.cpp:90
std::string display_icon() const
Get an icon path fixed for display (e.g.
Definition: info.cpp:133
bool open_object(const std::string &path_or_url)
Opens the specified object with the default application configured for its type.
Definition: open.cpp:53
std::vector< std::string > locales
Definition: info.hpp:47
void pre_show(twindow &window)
Inherited from tdialog.
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: glew.h:1222
static std::string colorify_addon_state_string(const std::string &str, const addon_tracking_info &state, bool verbose=false)
Definition: list.cpp:250
std::string display_type() const
Get an add-on type identifier for display in the user's language.
Definition: info.cpp:154
language_list get_languages()
Definition: language.cpp:118
Base class for all visible items.
Definition: control.hpp:34
bool open_object_is_supported()
Returns whether open_object() is supported/implemented for the current platform.
Definition: open.cpp:44
void copy_to_clipboard(const std::string &text, const bool)
Copies text to the clipboard.
Definition: clipboard.cpp:40
std::vector< std::string > depends
Definition: info.hpp:51
addon_tracking_info get_addon_tracking_info(const addon_info &addon)
Get information about an add-on comparing its local state with the add-ons server entry...
Definition: state.cpp:26
std::map< std::string, addon_tracking_info > addons_tracking_list
Definition: state.hpp:62
std::string title
Definition: info.hpp:32
static std::string format_addon_time(time_t time)
Definition: list.cpp:524
version_info version
Definition: info.hpp:37
Stores additional status information about add-ons.
Definition: state.hpp:44
int downloads
Definition: info.hpp:42
GLdouble s
Definition: glew.h:1358
void set_visible(const tvisible::scoped_enum visible)
Definition: widget.cpp:445
GLsizei const GLcharARB ** string
Definition: glew.h:4503
std::set< std::string > resolve_dependencies(const addons_list &addons) const
Resolve an add-on's dependency tree in a recursive fashion.
Definition: info.cpp:186
bool use_twelve_hour_clock_format()
std::string author
Definition: info.hpp:39
Version in the server matches local installation.
Definition: state.hpp:26
time_t updated
Definition: info.hpp:56