16 #define GETTEXT_DOMAIN "wesnoth-lib" 21 #include "addon/manager.hpp" 67 struct filter_transform
69 explicit filter_transform(
const std::vector<std::string>& filtertext) :
filtertext_(filtertext) {}
70 bool operator()(
const config& cfg)
const 77 std::string val = attribute.second.str();
78 if(std::search(val.begin(),
90 for(
const auto& attribute : child.attribute_range()) {
91 std::string val = attribute.second.str();
107 std::string make_display_dependencies(
108 const std::string& addon_id,
112 const addon_info& addon = addons_list.at(addon_id);
117 for(
const auto& dep_id : deps) {
121 addons_list::const_iterator ali = addons_list.find(dep_id);
122 addons_tracking_list::const_iterator tli = addon_states.find(dep_id);
124 if(ali == addons_list.end()) {
130 if(tli == addon_states.end()) {
133 depstate = tli->second;
146 std::string langcode_to_string(
const std::string& lcode)
150 if(ld.localename == lcode || ld.localename.substr(0, 2) == lcode) {
187 {
N_(
"addons_order^Name ($order)"),
"name", 0,
190 {
N_(
"addons_order^Author ($order)"),
"author", 1,
193 {
N_(
"addons_order^Size ($order)"),
"size", 2,
196 {
N_(
"addons_order^Downloads ($order)"),
"downloads", 3,
199 {
N_(
"addons_order^Type ($order)"),
"type", 4,
202 {
N_(
"addons_order^Last updated ($datelike_order)"),
"last_updated", -1,
205 {
N_(
"addons_order^First uploaded ($datelike_order)"),
"first_uploaded", -1,
222 const std::vector<addon_tag> tag_filter_types_{
223 {
"cooperative",
N_(
"addon_tag^Cooperative"),
225 N_(
"addon_tag^All human players are on the same team, versus the AI")},
226 {
"cosmetic",
N_(
"addon_tag^Cosmetic"),
228 N_(
"addon_tag^These make the game look different, without changing gameplay")},
229 {
"difficulty",
N_(
"addon_tag^Difficulty"),
231 N_(
"addon_tag^Can make campaigns easier or harder")},
232 {
"rng",
N_(
"addon_tag^RNG"),
234 N_(
"addon_tag^Modify the randomness in the combat mechanics, or remove it entirely")},
235 {
"survival",
N_(
"addon_tag^Survival"),
237 N_(
"addon_tag^Fight against waves of enemies")},
238 {
"terraforming",
N_(
"addon_tag^Terraforming"),
240 N_(
"addon_tag^Players can change the terrain")},
251 , need_wml_cache_refresh_(false)
261 switch(state.
state) {
264 ?
_(
"addon_state^Not installed")
265 :
_(
"addon_state^Published, not installed");
269 ?
_(
"addon_state^Installed")
270 :
_(
"addon_state^Published");
274 ?
_(
"addon_state^Installed, not tracking local version")
277 :
_(
"addon_state^Published, not tracking local version");
281 ?
_(
"addon_state^Installed ($local_version|), upgradable")
282 :
_(
"addon_state^Published ($local_version| installed), upgradable");
288 ?
_(
"addon_state^Installed ($local_version|), outdated on server")
289 :
_(
"addon_state^Published ($local_version| installed), outdated on server");
295 ?
_(
"addon_state^Installed, not ready to publish")
296 :
_(
"addon_state^Ready to publish");
300 ?
_(
"addon_state^Installed, broken")
301 :
_(
"addon_state^Published, broken");
304 s =
_(
"addon_state^Unknown");
326 auto addr_box =
dynamic_cast<styled_widget*
>(addr_visible->find(
"server_addr",
false));
334 text_box& filter = find_widget<text_box>(&
window,
"filter",
false);
338 this, std::placeholders::_1));
340 this, std::placeholders::_1));
342 this, std::placeholders::_1));
345 this, std::placeholders::_1));
347 this, std::placeholders::_1));
354 menu_button& status_filter = find_widget<menu_button>(&
window,
"install_status_filter",
false);
356 std::vector<config> status_filter_entries;
361 status_filter.
set_values(status_filter_entries);
367 auto& tag_filter = find_widget<multimenu_button>(&
window,
"tag_filter",
false);
369 std::vector<config> tag_filter_entries;
370 for(
const auto&
f : tag_filter_types_) {
372 if(!
f.tooltip.empty()) {
377 tag_filter.set_values(tag_filter_entries);
384 std::vector<config> type_filter_entries;
396 std::set<std::string> languages_available;
398 for (
const auto&
b :
a.second.locales) {
399 languages_available.insert(
b);
402 std::set<std::string> language_strings_available;
403 for (
const auto&
i: languages_available) {
407 if (std::string lang_code_string = langcode_to_string(
i); !lang_code_string.empty()) {
408 language_strings_available.insert(lang_code_string);
411 for (
auto&
i: language_strings_available) {
416 std::vector<config> language_filter_entries;
418 language_filter_entries.emplace_back(
"label",
f.second,
"checkbox",
false);
421 language_filter.
set_values(language_filter_entries);
427 menu_button& order_dropdown = find_widget<menu_button>(&
window,
"order_dropdown",
false);
429 std::vector<config> order_dropdown_entries;
433 symbols[
"order"] =
_(
"ascending");
435 symbols[
"datelike_order"] =
_(
"oldest to newest");
437 order_dropdown_entries.push_back(entry);
438 symbols[
"order"] =
_(
"descending");
440 symbols[
"datelike_order"] =
_(
"newest to oldest");
441 entry[
"label"] =
VGETTEXT(
f.label.c_str(), symbols);
442 order_dropdown_entries.push_back(entry);
445 order_dropdown.
set_values(order_dropdown_entries);
450 if(!saved_order_name.empty()) {
451 auto order_it = std::find_if(all_orders_.begin(), all_orders_.end(),
452 [&saved_order_name](
const addon_order& order) {
return order.as_preference == saved_order_name;});
453 if(order_it != all_orders_.end()) {
454 int index = 2 * (std::distance(all_orders_.begin(), order_it));
456 if(saved_order_direction == sort_order::type::ascending) {
457 func = order_it->sort_func_asc;
459 func = order_it->sort_func_desc;
462 find_widget<menu_button>(&
window,
"order_dropdown",
false).set_value(index,
false);
463 auto& addons = find_widget<addon_list>(&
window,
"addons",
false);
464 addons.set_addon_order(func);
465 addons.select_first_addon();
473 label& url_label = find_widget<label>(&
window,
"url",
false);
479 find_widget<button>(&window,
"install",
false),
483 find_widget<button>(&window,
"uninstall",
false),
487 find_widget<button>(&window,
"update",
false),
491 find_widget<button>(&window,
"publish",
false),
495 find_widget<button>(&window,
"delete",
false),
499 find_widget<button>(&window,
"update_all",
false),
503 find_widget<button>(&window,
"show_help",
false),
506 if(
stacked_widget* stk = find_widget<stacked_widget>(&window,
"main_stack",
false,
false)) {
507 button& btn = find_widget<button>(&
window,
"details_toggle",
false);
509 stk->select_layer(0);
513 if(
stacked_widget* stk = find_widget<stacked_widget>(&window,
"main_stack",
false,
false)) {
514 version_filter_parent = stk->get_layer_grid(1);
517 menu_button& version_filter = find_widget<menu_button>(version_filter_parent,
"version_filter",
false);
523 window.set_enter_disabled(
true);
525 window.keyboard_capture(&filter);
564 for(std::string
id : publishable_addons) {
573 pbl_cfg[
"name"] =
id;
574 pbl_cfg[
"local_only"] =
true;
587 show_transient_message(
_(
"No Add-ons Available"),
_(
"There are no add-ons available for download from this server."));
593 bool has_upgradable_addons =
false;
598 has_upgradable_addons =
true;
612 find_widget<addon_list>(
get_window(),
"addons",
false).select_addon(
id);
618 const text_box& name_filter = find_widget<const text_box>(
get_window(),
"filter",
false);
619 const std::string& text = name_filter.
get_value();
622 boost::dynamic_bitset<> res;
628 const config& addon_cfg = *std::find_if(addon_cfgs.begin(), addon_cfgs.end(),
631 return cfg[
"name"] ==
a.first;
634 res.push_back(filter(addon_cfg));
642 const menu_button& status_filter = find_widget<const menu_button>(
get_window(),
"install_status_filter",
false);
645 boost::dynamic_bitset<> res;
663 const auto& tag_filter = find_widget<const multimenu_button>(
get_window(),
"tag_filter",
false);
664 const auto toggle_states = tag_filter.get_toggle_states();
665 if(toggle_states.none()) {
667 boost::dynamic_bitset<> res_flipped(
addons_.size());
671 std::vector<std::string> selected_tags;
672 for(std::size_t
i = 0;
i < tag_filter_types_.size(); ++
i) {
673 if(toggle_states[
i]) {
674 selected_tags.push_back(tag_filter_types_[i].
id);
678 boost::dynamic_bitset<> res;
680 bool matched_tag =
false;
681 for(
const auto&
id : selected_tags) {
687 res.push_back(matched_tag);
698 if(toggle_states.none()) {
700 boost::dynamic_bitset<> res_flipped(
addons_.size());
703 boost::dynamic_bitset<> res;
708 [&
a](
const std::pair<ADDON_TYPE, std::string>& entry) {
709 return entry.first ==
a.second.type;
712 res.push_back(toggle_states[index]);
724 if(toggle_states.none()) {
725 boost::dynamic_bitset<> res_flipped(
addons_.size());
728 boost::dynamic_bitset<> res;
733 std::vector<std::string> lang_string_vector;
734 for (
long unsigned int i = 0;
i <
a.second.locales.size();
i++) {
735 lang_string_vector.push_back(langcode_to_string(
a.second.locales[
i]));
738 for (
long unsigned int i = 0;
i < toggle_states.size();
i++) {
739 if (toggle_states[
i] ==
true) {
744 if ((contains_lang_code || contains_lang_string) ==
true)
748 res.push_back(retval);
763 auto list = find_widget<addon_list>(
get_window(),
"addons",
false,
false);
768 boost::dynamic_bitset<> res =
774 list->set_addon_shown(res);
779 const menu_button& order_menu = find_widget<const menu_button>(
get_window(),
"order_dropdown",
false);
783 if(order == sort_order::type::ascending) {
784 func = order_struct.sort_func_asc;
786 func = order_struct.sort_func_desc;
789 find_widget<addon_list>(
get_window(),
"addons",
false).set_addon_order(func);
798 [sort_column](
const addon_order& order) {
return order.column_index ==
static_cast<int>(sort_column);});
800 if(order == sort_order::type::descending) {
808 template<
void(addon_manager::*fptr)(const addon_info& addon)>
813 stk->select_layer(0);
818 const addon_info* addon = addons.get_selected_addon();
820 if(addon ==
nullptr) {
825 (this->*fptr)(*addon);
836 parent = stk->get_layer_grid(1);
838 if(addon.
id == find_widget<addon_list>(
get_window(),
"addons",
false).get_selected_addon()->
id) {
839 versioned_addon.
current_version = find_widget<menu_button>(
parent,
"version_filter",
false).get_value_string();
856 _(
"The following add-on appears to have publishing or version control information stored locally, and will not be removed:") +
" " +
909 std::string server_msg;
911 const std::string addon_id = addon.
id;
915 const version_info& version_to_publish = cfg[
"version"].str();
917 if(version_to_publish <=
tracking_info_[addon_id].remote_version) {
919 _(
"The remote version of this add-on is greater or equal to the version being uploaded. Do you really wish to continue?"),
928 if(cfg[
"passphrase"].empty()) {
930 if(!gui2::dialogs::addon_auth::execute(cfg)) {
942 }
else if(gui2::dialogs::addon_license_prompt::execute(server_msg)) {
944 const std::string&
msg =
_(
"The add-on was rejected by the server:") +
947 if (!extra_data.empty()) {
969 const std::string addon_id = addon.
id;
971 "Deleting '$addon|' will permanently erase its download and upload counts on the add-ons server. Do you really wish to continue?",
981 std::string server_msg;
1003 VGETTEXT(
"Do you want to uninstall '$addon|'?", symbols),
1030 std::ostringstream ss;
1034 ?
_(
"%B %d %Y, %I:%M %p")
1036 :
_(
"%B %d %Y, %H:%M");
1051 parent = stk->get_layer_grid(1);
1052 parent_of_addons_list = stk->get_layer_grid(0);
1055 const addon_info*
info = find_widget<addon_list>(parent_of_addons_list,
"addons",
false).get_selected_addon();
1057 if(info ==
nullptr) {
1065 menu_button& version_filter = find_widget<menu_button>(
parent,
"version_filter",
false);
1071 status.set_use_markup(
true);
1080 :
_(
"addon_dependencies^None"));
1082 std::string languages;
1084 for(
const auto& lc : info->
locales) {
1085 const std::string& langlabel = langcode_to_string(lc);
1086 if(!langlabel.empty()) {
1087 if(!languages.empty()) {
1090 languages += langlabel;
1094 find_widget<styled_widget>(
parent,
"translations",
false).
set_label(!languages.empty() ? languages :
_(
"translations^None"));
1097 find_widget<label>(
parent,
"url",
false).
set_label(!feedback_url.empty() ? feedback_url :
_(
"url^None"));
1104 std::vector<config> version_filter_entries;
1109 stacked_widget& install_update_stack = find_widget<stacked_widget>(
parent,
"install_update_stack",
false);
1121 version_filter_entries.emplace_back(
"label",
f.str());
1134 version_filter.set_values(version_filter_entries);
1135 version_filter.set_active(version_filter_entries.size() > 1);
1143 parent = stk->get_layer_grid(1);
1144 parent_of_addons_list = stk->get_layer_grid(0);
1147 const addon_info*
info = find_widget<addon_list>(parent_of_addons_list,
"addons",
false).get_selected_addon();
1149 if(info ==
nullptr) {
1155 != find_widget<menu_button>(
parent,
"version_filter",
false).get_value_string();
1159 stacked_widget& install_update_stack = find_widget<stacked_widget>(
parent,
"install_update_stack",
false);
window(const builder_window::window_resolution &definition)
< Needs to be initialized in show.
void uninstall_selected_addon()
const std::string & get_last_server_error() const
Returns the last error message sent by the server, or an empty string.
void read_addons_list(const config &cfg, addons_list &dest)
Parse the specified add-ons list WML into an actual addons_list object.
void close()
Requests to close the window.
#define REGISTER_DIALOG(window_id)
Wrapper for REGISTER_DIALOG2.
void set_text_changed_callback(std::function< void(text_box_base *textbox, const std::string text)> cb)
Set the text_changed callback.
void show_message(const std::string &title, const std::string &msg, const std::string &button_caption, const bool auto_close, const bool message_use_markup, const bool title_use_markup)
Shows a message to the user.
std::string addon_manager_saved_order_name()
Modification of the game.
void show_help(const std::string &show_topic, int xloc, int yloc)
Open the help browser, show topic with id show_topic.
config cfg_
Config which contains the list with the campaigns.
std::string interpolate_variables_into_string(const std::string &str, const string_map *const symbols)
const std::string & addr() const
Returns the current hostname:port used for this connection.
std::map< std::string, t_string > string_map
boost::dynamic_bitset get_status_filter_visibility() const
bool exit_hook(window &window)
void execute_action_on_selected_addon()
std::function< bool(const addon_info &, const addon_info &)> addon_sort_func
an add-on that fits in no other category
static std::string format_addon_time(std::time_t time)
addons_tracking_list tracking_info_
bool using_tls() const
Returns whether the current connection uses TLS.
std::string display_title_translated_or_original() const
std::string campaign_server()
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal &signal)
Connects a signal handler for a left mouse button click.
void add_list_to_keyboard_chain()
Adds the internal listbox to the keyboard event chain.
Exception thrown when the WML parser fails to read a .pbl file.
Shows an ok and cancel button.
std::string get_value() const
child_itors child_range(config_key_type key)
std::vector< std::pair< int, std::string > > language_filter_types_
void reload_list_and_reselect_item(const std::string id)
void execute_default_action(const addon_info &addon)
Called when the player double-clicks an add-on.
config get_addon_pbl_info(const std::string &addon_name, bool do_validate)
Gets the publish information for an add-on.
bool chars_equal_insensitive(char a, char b)
void set_escape_disabled(const bool escape_disabled)
Disable the escape key.
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
static const std::vector< std::pair< ADDON_STATUS_FILTER, std::string > > status_filter_types_
sort_order::type addon_manager_saved_order_direction()
A label displays a text, the text can be wrapped but no scrollbars are provided.
bool have_addon_in_vcs_tree(const std::string &addon_name)
Returns whether the specified add-on appears to be managed by a VCS or not.
static std::string _(const char *str)
Definitions for the interface to Wesnoth Markup Language (WML).
status
The status of the window.
version_info installed_version
std::deque< std::unique_ptr< editor_action > > action_stack
Action stack typedef.
No tracking information available.
const_attr_itors attribute_range() const
void update_addon(const addon_info &addon)
Class for a single line text area.
std::vector< std::string > available_addons()
Returns a list of local add-ons that can be published.
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
const std::vector< std::string > filtertext_
bool exists(const image::locator &i_locator)
Returns true if the given image actually exists, without loading it.
std::string strftime(const std::string &format, const std::tm *time)
Desktop environment interaction functions.
boost::dynamic_bitset get_name_filter_visibility() const
void set_delete_function(addon_op_func_t function)
Sets the function to install an addon from the addons server.
Version in the server is older than local installation.
bool is_installed_addon_status(ADDON_STATUS s)
std::string label
What to show in the filter's drop-down list.
This file contains the settings handling of the widget library.
ADDON_STATUS_FILTER
Add-on installation status filters for the user interface.
boost::dynamic_bitset get_tag_filter_visibility() const
void show_transient_message(const std::string &title, const std::string &message, const std::string &image, const bool message_use_markup, const bool title_use_markup)
Shows a transient message to the user.
std::string display_icon() const
Get an icon path fixed for display (e.g.
const std::string & get_last_server_error_data() const
Returns the last error message extra data sent by the server, or an empty string. ...
Version in the server is newer than local installation.
language_list get_languages(bool all)
Return a list of available translations.
void set_password(const std::string &server, const std::string &login, const std::string &key)
void toggle_details(button &btn, stacked_widget &stk)
std::string display_type() const
Get an add-on type identifier for display in the user's language.
Shows a yes and no button.
void refresh_addon_version_info_cache()
Refreshes the per-session cache of add-on's version information structs.
void set_addons(const addons_list &addons)
Sets the add-ons to show.
bool remove_local_addon(const std::string &addon)
Removes the specified add-on, deleting its full directory structure.
Dependencies not satisfied.
Add-ons (campaignd) client class.
void on_selected_version_change()
window * get_window()
Returns a pointer to the dialog's window.
User aborted the operation because of an issue with dependencies or chose not to overwrite the add-on...
Miscellaneous content/media (unit packs, terrain packs, music packs, etc.).
boost::iterator_range< const_child_iterator > const_child_itors
static std::string describe_status_verbose(const addon_tracking_info &state)
bool ci_search(const std::string &s1, const std::string &s2)
std::vector< std::string > locales
std::string id
Text to match against addon_info.tags()
void delete_addon(const addon_info &addon)
Performs all backend and UI actions for taking down the specified add-on.
bool have_addon_pbl_info(const std::string &addon_name)
Returns whether a .pbl file is present for the specified add-on or not.
static map_location::DIRECTION s
std::string size_display_string(double size)
Get a human-readable representation of the specified byte count.
addon_manager(addons_client &client)
std::string password(const std::string &server, const std::string &login)
void set_publish_function(addon_op_func_t function)
Sets the function to upload an addon to the addons server.
void execute_default_action_on_selected_addon()
void delete_selected_addon()
void set_update_function(addon_op_func_t function)
Sets the function to call when the player clicks the update button.
void set_callback_order_change(std::function< void(unsigned, sort_order::type)> callback)
Sets up a callback that will be called when the player changes the sorting order. ...
void on_order_changed(unsigned int sort_column, sort_order::type order)
std::string display_title_full() const
Multiplayer plain (no WML) map pack.
boost::dynamic_bitset get_lang_filter_visibility() const
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
No version in the server.
install_outcome outcome
Overall outcome of the operation.
std::set< version_info, std::greater< version_info > > versions
boost::dynamic_bitset get_type_filter_visibility() const
static std::string colorize_addon_state_string(const std::string &str, ADDON_STATUS state, bool verbose=false)
Changes the color of an add-on state string (installed, outdated, etc.) according to the state itself...
Represents version numbers.
void publish_addon(const addon_info &addon)
Performs all backend and UI actions for publishing the specified add-on.
virtual void set_active(const bool active) override
See styled_widget::set_active.
config & add_child(config_key_type key)
bool need_wml_cache_refresh_
std::string make_addon_title(const std::string &id)
Replaces underscores to dress up file or dirnames as add-on titles.
void install_addon(const addon_info &addon)
void uninstall_addon(const addon_info &addon)
void set_uninstall_function(addon_op_func_t function)
Sets the function to call when the player clicks the uninstall button.
static const std::vector< std::pair< ADDON_TYPE, std::string > > type_filter_types_
std::vector< std::string > depends
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...
std::vector< std::string > split(const config_attribute_value &val)
bool wml_changed
Specifies if WML on disk was altered and needs to be reloaded.
std::map< std::string, addon_tracking_info > addons_tracking_list
const std::string unicode_em_dash
std::set< std::string > resolve_dependencies(const addons_list &addons) const
Resolve an add-on's dependency tree in a recursive fashion.
Abstract base class for all modal dialogs.
std::string str() const
Serializes the version number into string form.
bool upload_addon(const std::string &id, std::string &response_message, config &cfg, bool local_only)
Uploads an add-on to the server.
void show_error_message(const std::string &msg, bool message_use_markup)
Shows an error message to the user.
void set_install_function(addon_op_func_t function)
Sets the function to call when the player clicks the install button.
retval
Default window/dialog return values.
Stores additional status information about add-ons.
Dialog was closed with the OK button.
A config object defines a single node in a WML file, with access to child nodes.
bool delete_remote_addon(const std::string &id, std::string &response_message)
Requests the specified add-on to be removed from the server.
bool request_distribution_terms(std::string &terms)
Request the add-ons server distribution terms message.
Contains the outcome of an add-on install operation.
version_info current_version
void publish_selected_addon()
void set_addon_manager_saved_order_direction(sort_order::type value)
std::map< std::string, addon_info > addons_list
base class of top level items, the only item which needs to store the final canvases to draw on...
install_result install_addon_with_checks(const addons_list &addons, const addon_info &addon)
Performs an add-on download and install cycle.
void set_addon_manager_saved_order_name(const std::string &value)
bool use_twelve_hour_clock_format()
static const int DEFAULT_ACTION_RETVAL
Special retval for the toggle panels in the addons list.
virtual void pre_show(window &window) override
Actions to be taken before showing the window.
bool request_addons_list(config &cfg)
Request the add-ons list from the server.
void set_modified_signal_handler(const std::function< void()> &callback)
Sets up a callback that will be called when the player selects an add-on.
void install_selected_addon()
void set_link_aware(bool l)
static const std::vector< addon_order > all_orders_
void update_selected_addon()
std::string tooltip
Shown when hovering over an entry in the filter's drop-down list.
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification &signal)
Connects a signal handler for getting a notification upon modification.
Version in the server matches local installation.
std::string description_translated() const