Removed GUI1 addons manager

This commit is contained in:
Charles Dang 2017-02-19 00:52:49 +11:00
parent 1c4102abad
commit 8a5274c39b

View file

@ -15,34 +15,22 @@
#include "addon/manager_ui.hpp"
#include "addon/client.hpp"
#include "addon/info.hpp"
#include "addon/manager.hpp"
#include "addon/state.hpp"
#include "filesystem.hpp"
#include "formula/string_utils.hpp"
#include "game_preferences.hpp"
#include "gettext.hpp"
#include "gui/dialogs/addon/manager.hpp"
#include "gui/dialogs/addon/description.hpp"
#include "gui/dialogs/addon/filter_options.hpp"
#include "gui/dialogs/addon/uninstall_list.hpp"
#include "gui/dialogs/addon/connect.hpp"
#include "gui/dialogs/message.hpp"
#include "gui/dialogs/transient_message.hpp"
#include "gui/widgets/window.hpp"
#include "gui/widgets/settings.hpp"
#include "help/help_button.hpp"
#include "image.hpp"
#include "log.hpp"
#include "font/marked-up_text.hpp"
#include "font/standard_colors.hpp"
#include "wml_separators.hpp"
#include "wml_exception.hpp"
#include "addon/client.hpp"
#include <boost/dynamic_bitset.hpp>
static lg::log_domain log_config("config");
static lg::log_domain log_network("network");
static lg::log_domain log_filesystem("filesystem");
@ -54,20 +42,11 @@ static lg::log_domain log_addons_client("addons-client");
#define ERR_FS LOG_STREAM(err, log_filesystem)
#define ERR_AC LOG_STREAM(err , log_addons_client)
#define WRN_AC LOG_STREAM(warn, log_addons_client)
#define LOG_AC LOG_STREAM(info, log_addons_client)
#define DBG_AC LOG_STREAM(debug, log_addons_client)
namespace {
inline const addon_info& addon_at(const std::string& id, const addons_list& addons)
{
addons_list::const_iterator it = addons.find(id);
assert(it != addons.end());
return it->second;
}
bool get_addons_list(addons_client& client, addons_list& list)
{
list.clear();
@ -84,724 +63,20 @@ bool get_addons_list(addons_client& client, addons_list& list)
return true;
}
const std::string color_upgradable = font::color2markup(font::YELLOW_COLOR);
const std::string color_outdated = "<255,127,0>";
std::string describe_addon_status(const addon_tracking_info& info)
{
switch(info.state) {
case ADDON_NONE:
return info.can_publish ? _("addon_state^Published, not installed") : _("addon_state^Not installed");
case ADDON_INSTALLED:
case ADDON_NOT_TRACKED:
// Consider add-ons without version information as installed
// for the main display. Their Description info should elaborate
// on their status.
return font::GOOD_TEXT + (
info.can_publish ? _("addon_state^Published") : _("addon_state^Installed"));
case ADDON_INSTALLED_UPGRADABLE:
return color_upgradable + (
info.can_publish ? _("addon_state^Published, upgradable") : _("addon_state^Installed, upgradable"));
case ADDON_INSTALLED_OUTDATED:
return color_outdated + (
info.can_publish ? _("addon_state^Published, outdated on server") : _("addon_state^Installed, outdated on server"));
case ADDON_INSTALLED_BROKEN:
return font::BAD_TEXT + (
info.can_publish ? _("addon_state^Published, broken") : _("addon_state^Installed, broken"));
default:
return font::color2markup(font::GRAY_COLOR) + _("addon_state^Unknown");
}
}
/** Performs all backend and UI actions for taking down the specified add-on. */
void do_remote_addon_delete(CVideo& video, addons_client& client, const std::string& addon_id)
{
utils::string_map symbols;
symbols["addon"] = make_addon_title(addon_id); // FIXME: need the real title!
const std::string& text = vgettext("Deleting '$addon|' will permanently erase its download and upload counts on the add-ons server. Do you really wish to continue?", symbols);
const int res = gui2::show_message(
video, _("Confirm"), text, gui2::dialogs::message::yes_no_buttons);
if(res != gui2::window::OK) {
return;
}
std::string server_msg;
if(!client.delete_remote_addon(addon_id, server_msg)) {
gui2::show_error_message(video,
_("The server responded with an error:") + "\n" +
client.get_last_server_error());
} else {
// FIXME: translation needed!
gui2::show_transient_message(video, _("Response"), server_msg);
}
}
/** Performs all backend and UI actions for publishing the specified add-on. */
void do_remote_addon_publish(CVideo& video, addons_client& client, const std::string& addon_id, const version_info& remote_version)
{
std::string server_msg;
config cfg = get_addon_pbl_info(addon_id);
const version_info& version_to_publish = cfg["version"].str();
if(version_to_publish <= remote_version) {
const int res = gui2::show_message(video, _("Warning"),
_("The remote version of this add-on is greater or equal to the version being uploaded. Do you really wish to continue?"),
gui2::dialogs::message::yes_no_buttons);
if(res != gui2::window::OK) {
return;
}
}
if(!image::exists(cfg["icon"].str())) {
gui2::show_error_message(video, _("Invalid icon path. Make sure the path points to a valid image."));
} else if(!client.request_distribution_terms(server_msg)) {
gui2::show_error_message(video,
_("The server responded with an error:") + "\n" +
client.get_last_server_error());
} else if(gui2::show_message(video, _("Terms"), server_msg, gui2::dialogs::message::ok_cancel_buttons) == gui2::window::OK) {
if(!client.upload_addon(addon_id, server_msg, cfg)) {
gui2::show_error_message(video,
_("The server responded with an error:") + "\n" +
client.get_last_server_error());
} else {
gui2::show_transient_message(video, _("Response"), server_msg);
}
}
}
/** GUI1 support class handling the button used to display add-on descriptions. */
class description_display_action : public gui::dialog_button_action
{
CVideo& v_;
std::vector<std::string> display_ids_;
addons_list addons_;
addons_tracking_list tracking_;
gui::filter_textbox* filter_;
public:
description_display_action(CVideo& v, const std::vector<std::string>& display_ids, const addons_list& addons, const addons_tracking_list& tracking, gui::filter_textbox* filter)
: v_(v) , display_ids_(display_ids), addons_(addons), tracking_(tracking), filter_(filter)
{}
virtual gui::dialog_button_action::RESULT button_pressed(int filter_choice)
{
assert(filter_ != nullptr);
const int menu_selection = filter_->get_index(filter_choice);
if(menu_selection < 0) { return gui::CONTINUE_DIALOG; }
const size_t choice = static_cast<size_t>(menu_selection);
if(choice < display_ids_.size()) {
const std::string& id = display_ids_[choice];
assert(tracking_.find(id) != tracking_.end());
gui2::dialogs::addon_description::display(id, addons_, tracking_, v_);
}
return gui::CONTINUE_DIALOG;
}
};
/** Struct type for storing filter options. */
struct addons_filter_state
{
std::string keywords;
boost::dynamic_bitset<> types;
ADDON_STATUS_FILTER status;
// Yes, the sorting criterion and direction are part of the
// filter options since changing them requires rebuilding the
// dialog list contents.
ADDON_SORT sort;
ADDON_SORT_DIRECTION direction;
bool changed;
addons_filter_state()
: keywords()
, types(ADDON_TYPES_COUNT)
, status(FILTER_ALL)
, sort(SORT_NAMES)
, direction(DIRECTION_ASCENDING)
, changed(false)
{
types.flip();
}
};
/** GUI1 support class handling the filter options button. */
class filter_options_action : public gui::dialog_button_action
{
CVideo& video_;
addons_filter_state& f_;
public:
filter_options_action(CVideo& video, addons_filter_state& filter)
: video_(video)
, f_(filter)
{}
virtual gui::dialog_button_action::RESULT button_pressed(int)
{
gui2::dialogs::addon_filter_options dlg;
dlg.set_displayed_status(f_.status);
dlg.set_displayed_types(f_.types);
dlg.set_sort(f_.sort);
dlg.set_direction(f_.direction);
dlg.show(video_);
const boost::dynamic_bitset<> new_types = dlg.displayed_types();
const ADDON_STATUS_FILTER new_status = dlg.displayed_status();
const ADDON_SORT new_sort = dlg.sort();
const ADDON_SORT_DIRECTION new_direction = dlg.direction();
assert(f_.types.size() == new_types.size());
if(f_.types == new_types && f_.status == new_status &&
f_.sort == new_sort && f_.direction == new_direction) {
// Close the manager dialog only if the filter options changed.
return gui::CONTINUE_DIALOG;
}
f_.types = new_types;
f_.status = new_status;
f_.sort = new_sort;
f_.direction = new_direction;
f_.changed = true;
return gui::CLOSE_DIALOG;
}
};
/**
* Comparator type used for sorting the add-ons list according to the user's preferences.
*/
struct addon_pointer_list_sorter
{
addon_pointer_list_sorter(ADDON_SORT sort, ADDON_SORT_DIRECTION direction)
: sort_(sort), dir_(direction)
{}
inline bool operator()(const addons_list::value_type* a, const addons_list::value_type* b) {
assert(a != nullptr && b != nullptr);
if(dir_ == DIRECTION_DESCENDING) {
const addons_list::value_type* c = a;
a = b;
b = c;
}
switch(sort_) {
case SORT_NAMES:
// Alphanumerical by name, case insensitive.
return utf8::lowercase(a->second.title) < utf8::lowercase(b->second.title);
case SORT_UPDATED:
// Numerical by last upload TS.
return a->second.updated < b->second.updated;
case SORT_CREATED:
default:
// Numerical by first upload TS (or the equivalent campaignd WML order).
return a->second.order < b->second.order;
}
}
private:
ADDON_SORT sort_;
ADDON_SORT_DIRECTION dir_;
};
/** Shorthand type for the sorted add-ons list. */
typedef std::vector<const addons_list::value_type*> sorted_addon_pointer_list;
/**
* Sorts the user-visible add-ons list according to the user's preferences.
*
* The internal add-ons list is actually implemented employing an associative
* container to map individual list entries to add-on ids for faster look-ups.
* The visible form of the list may actually include more elements than just
* the contents of the add-ons server; more specifically, it may include
* Publish and Delete entries for local add-ons with .pbl files.
*
* The GUI1 list/menu class does not support horizontal scrolling, which
* results in a very limited set of information columns that can be displayed
* safely without running out of space and causing content to be omitted, and
* clicking on any column header to change the sort also affects the
* Publish/Delete entries by necessity. These two factors combined make it
* inconvenient at this time to just use the GUI1 widget's interface to make
* it default to a specific sorting criterion.
*
* Thus, we need a "neutral" or "fallback" sorting step before feeding the
* add-ons list's data to the widget and appending Publish/Delete options to
* it. Since this is definitely not the most evident UI concept in use in this
* dialog, it is hidden behind the Options dialog and has sensible defaults
* intended to optimize the add-ons experience; alphanumerical sorting feels
* natural and breaks any illusion of quality rating or any such that could
* result from a list default-sorted by first-upload order as done in all
* versions prior to 1.11.0.
*
* This function takes care of sorting the list with minimal memory footprint
* by passing around a set of pointers to items of the source list in
* @a addons for use in the dialog building code.
*
* @param addons The source add-ons list.
* @param sort Sorting criterion.
* @param direction Sorting order (ascending/descending).
*
* @return A vector containing pointers to items from @a addons sorted
* accordingly. Iterators to items from @a addons <b>must</b> remain
* valid for the whole lifespan of this vector.
*/
sorted_addon_pointer_list sort_addons_list(addons_list& addons, ADDON_SORT sort, ADDON_SORT_DIRECTION direction)
{
sorted_addon_pointer_list res;
addon_pointer_list_sorter sorter(sort, direction);
for(const addons_list::value_type& entry : addons) {
res.push_back(&entry);
}
std::stable_sort(res.begin(), res.end(), sorter);
return res;
}
void show_addons_manager_dialog(CVideo& v, addons_client& client, addons_list& addons, std::string& last_addon_id, bool& stay_in_ui, bool& wml_changed, addons_filter_state& filter)
{
std::unique_ptr<cursor::setter> cursor_setter(new cursor::setter(cursor::WAIT));
stay_in_ui = false;
filter.changed = false;
const ADDON_STATUS_FILTER prev_view = filter.status;
assert(prev_view < FILTER_COUNT);
const bool updates_only =
filter.status == FILTER_UPGRADABLE;
const bool show_publish_delete = !updates_only;
// Currently installed add-ons, which we'll need to check when updating.
// const std::vector<std::string>& installed_addons_list = installed_addons();
// Add-ons available for publishing in the remote
// (i.e. we have .pbl files for them).
const std::vector<std::string>& can_publish_ids = available_addons();
// Add-ons available for deleting in the remote
// (i.e. already published, and we have .pbl files for them).
std::vector<std::string> can_delete_ids;
// Status tracking information about add-ons.
addons_tracking_list tracking;
// UI markup.
const std::string sep(1, COLUMN_SEPARATOR);
// List and list filter control contents.
std::vector<std::string> options, filter_options;
std::string header;
// The add-on ids actually available for the user to pick from in the UI.
std::vector<std::string> option_ids;
// UI sorting detail.
std::vector<int> sort_sizes;
header = HEADING_PREFIX + sep + _("Name") + sep;
if(updates_only) {
header += _("Old Version") + sep + _("New Version") + sep;
} else {
header += _("Version") + sep;
}
header += _("Author") + sep + _("Size");
// The Type and Downloads columns aren't displayed when updating because of
// display space constraints. Presumably, the user doesn't care about that
// information since the add-on is already installed.
//
// Type is also always displayed last so it can get automatically truncated
// if its translated contents don't fit, instead of truncating other, more
// important columns such as Size.
if(!updates_only) {
header += sep + _("Downloads") + sep + _("Type");
}
// end of list header
options.push_back(header);
filter_options.push_back(header);
//
// Prepare the add-ons list for display and get status
// information.
//
const sorted_addon_pointer_list& sorted_addons = sort_addons_list(addons, filter.sort, filter.direction);
bool have_upgradable_addons = false;
for(const sorted_addon_pointer_list::value_type& sorted_entry : sorted_addons) {
const addons_list::value_type& entry = *sorted_entry;
const addon_info& addon = entry.second;
tracking[addon.id] = get_addon_tracking_info(addon);
const ADDON_STATUS state = tracking[addon.id].state;
if((filter.status == FILTER_UPGRADABLE && state != ADDON_INSTALLED_UPGRADABLE) ||
(filter.status == FILTER_NOT_INSTALLED && state != ADDON_NONE) ||
(filter.status == FILTER_INSTALLED && !is_installed_addon_status(state)) ||
(!filter.types[addon.type])
)
continue;
if(state == ADDON_INSTALLED_UPGRADABLE) {
have_upgradable_addons = true;
}
option_ids.push_back(addon.id);
if(tracking[addon.id].can_publish) {
can_delete_ids.push_back(addon.id);
}
const std::string& display_sep = sep;
const std::string& display_size = size_display_string(addon.size);
const std::string& display_type = addon.display_type();
const std::string& display_down = std::to_string(addon.downloads);
const std::string& display_icon = addon.display_icon();
const std::string& display_status = describe_addon_status(tracking[addon.id]);
std::string display_version = addon.version.str();
std::string display_old_version = tracking[addon.id].installed_version;
std::string display_title = addon.display_title();
std::string display_author = addon.author;
// Add negative sizes to reverse the sort order.
sort_sizes.push_back(-addon.size);
std::string row;
// First we enter information that's used only for filtering.
// This includes the description, which we cannot display
// as a normal list row due to space constraints.
row = display_title + sep;
if(updates_only) {
row += display_old_version + sep;
}
row += display_version + sep + display_author + sep +
display_size + sep + display_down + sep +
display_type + sep + addon.description;
filter_options.push_back(row);
// Now we enter information for list row display.
// Three fields are truncated to accommodate for GUI1's limitations.
utils::ellipsis_truncate(display_author, 14);
// Word-wrap the title field to a limit of two lines.
display_title = font::word_wrap_text(display_title, font::SIZE_NORMAL, 150, -1, 2);
// Versions are too important in upgrades mode, so don't
// truncate them then.
if(!updates_only) {
utf8::truncate_as_ucs4(display_version, 12);
if(state == ADDON_INSTALLED_UPGRADABLE || state == ADDON_INSTALLED_OUTDATED) {
utf8::truncate_as_ucs4(display_old_version, 12);
if(state == ADDON_INSTALLED_UPGRADABLE) {
display_version =
color_upgradable + display_old_version +
"\n" + color_upgradable + display_version;
} else {
display_version =
color_outdated + display_old_version +
"\n" + color_outdated + display_version;
}
}
}
// NOTE: NULL_MARKUP used to escape abuse of formatting chars in add-on titles
row = IMAGE_PREFIX + display_icon + display_sep + font::NULL_MARKUP + display_title + "\n" + font::color2markup(font::TITLE_COLOR) + font::SMALL_TEXT + display_status + display_sep;
if(updates_only) {
row += display_old_version + display_sep;
}
row += display_version + display_sep + display_author + display_sep + display_size;
if(!updates_only) {
row += display_sep + display_down + display_sep + display_type;
}
options.push_back(row);
}
if(show_publish_delete) {
utils::string_map i18n_syms;
// Enter publish and remote deletion options
for(const std::string& pub_id : can_publish_ids) {
i18n_syms["addon_title"] = make_addon_title(pub_id);
static const std::string publish_icon = "icons/icon-game.png~BLIT(icons/icon-addon-publish.png)";
const std::string& text = vgettext("Publish: $addon_title", i18n_syms);
options.push_back(IMAGE_PREFIX + publish_icon + COLUMN_SEPARATOR + font::GOOD_TEXT + text);
filter_options.push_back(text);
}
for(const std::string& del_id : can_delete_ids) {
i18n_syms["addon_title"] = make_addon_title(del_id);
static const std::string delete_icon = "icons/icon-game.png~BLIT(icons/icon-addon-delete.png)";
const std::string& text = vgettext("Delete: $addon_title", i18n_syms);
options.push_back(IMAGE_PREFIX + delete_icon + COLUMN_SEPARATOR + font::BAD_TEXT + text);
filter_options.push_back(text);
}
}
// If the options vector is empty it means we don't have publish/delete
// entries to display, either because there are no add-ons on the server
// at all, or none match the selected criteria. In such cases, insert a
// message row informing the player of the situation.
const bool dummy_addons_list = options.size() == 1; // The header is always there.
int result;
// Magic constant assigned to the Update All button as its return value.
static const int update_all_value = -255;
/* do */ {
//
// Set-up the actual GUI1 dialog and its children.
//
std::string dlg_message;
if(dummy_addons_list) {
dlg_message = addons.empty()
? _("There are no add-ons available for download from this server.")
: _("There are no add-ons matching the specified criteria on this server.");
}
gui::dialog dlg(v, _("Add-ons Manager"), dlg_message, gui::OK_CANCEL);
gui::menu::basic_sorter sorter;
sorter.set_alpha_sort(1).set_alpha_sort(2).set_alpha_sort(3);
if(!updates_only) {
sorter.set_position_sort(4, sort_sizes).set_numeric_sort(5).set_alpha_sort(6);
} else {
sorter.set_alpha_sort(4).set_position_sort(5, sort_sizes);
}
gui::menu::imgsel_style addon_style(gui::menu::bluebg_style);
addon_style.scale_images(font::relative_size(72), font::relative_size(72));
gui::menu* addons_list_menu = new gui::menu(v, options, false, -1,
gui::dialog::max_menu_width, &sorter, &addon_style, false);
dlg.set_menu(addons_list_menu);
std::string filter_label;
if(!dummy_addons_list) {
filter_label = _("Filter: ");
}
gui::filter_textbox* filter_box = new gui::filter_textbox(v,
filter_label, options, filter_options, 1, dlg, 300);
filter_box->set_text(filter.keywords);
dlg.set_textbox(filter_box);
description_display_action description_helper(v, option_ids, addons, tracking, filter_box);
gui::dialog_button* description_button = new gui::dialog_button(v,
_("Description"), gui::button::TYPE_PRESS, gui::CONTINUE_DIALOG, &description_helper);
dlg.add_button(description_button, gui::dialog::BUTTON_EXTRA);
gui::dialog_button* update_all_button = new gui::dialog_button(v, _("Update All"),
gui::button::TYPE_PRESS, update_all_value);
update_all_button->enable(have_upgradable_addons);
dlg.add_button(update_all_button, gui::dialog::BUTTON_EXTRA);
filter_options_action filter_opts_helper(v, filter);
gui::dialog_button* filter_opts_button = new gui::dialog_button(v,
_("filter^Options"), gui::button::TYPE_PRESS, gui::CONTINUE_DIALOG, &filter_opts_helper);
dlg.add_button(filter_opts_button, gui::dialog::BUTTON_TOP);
help::help_button* help_button = new help::help_button(v, "installing_addons");
dlg.add_button(help_button, gui::dialog::BUTTON_HELP);
// Disable some buttons when there's nothing to display.
if(dummy_addons_list) {
filter_box->hide(true);
description_button->enable(false);
update_all_button->enable(false);
addons_list_menu->hide(true);
}
// Focus the menu on the previous selection.
std::vector<std::string>::iterator it = !last_addon_id.empty() ?
std::find(option_ids.begin(), option_ids.end(), last_addon_id) :
option_ids.end();
if(it != option_ids.end()) {
addons_list_menu->move_selection(std::distance(option_ids.begin(), it));
}
cursor_setter.reset();
//
// Execute the dialog.
//
result = filter_box->get_index(dlg.show());
filter.keywords = filter_box->text();
}
const bool update_everything = result == update_all_value;
if(result < 0 && !(update_everything || filter.changed)) {
// User canceled the dialog.
return;
}
stay_in_ui = true;
if(filter.changed) {
// The caller will run this function again.
return;
}
if(show_publish_delete) {
if(result >= int(option_ids.size() + can_publish_ids.size())) {
// Handle remote deletion.
const std::string& id = can_delete_ids[result - int(option_ids.size() + can_publish_ids.size())];
do_remote_addon_delete(v, client, id);
return;
} else if(result >= int(option_ids.size())) {
// Handle remote publishing.
const std::string& id = can_publish_ids[result - int(option_ids.size())];
do_remote_addon_publish(v, client, id, tracking[id].remote_version);
return;
}
}
std::vector<std::string> ids_to_install;
std::vector<std::string> failed_titles;
if(update_everything) {
for(const std::string& id : option_ids) {
if(tracking[id].state == ADDON_INSTALLED_UPGRADABLE) {
ids_to_install.push_back(id);
}
}
} else {
assert(result >= 0 && size_t(result) < option_ids.size());
last_addon_id = option_ids[result];
ids_to_install.push_back(option_ids[result]);
}
for(const std::string& id : ids_to_install) {
const addon_info& addon = addon_at(id, addons);
addons_client::install_result res = client.install_addon_with_checks(addons, addon);
wml_changed |= res.wml_changed; // take note if any wml_changes occurred
if (res.outcome == addons_client::install_outcome::abort) {
return; // the user aborted because of some issue encountered
} else if (res.outcome == addons_client::install_outcome::failure) {
failed_titles.push_back(addon.title); // we resolved dependencies, but fetching this particular addon failed.
} else { // res.outcome == success
wml_changed = true;
}
}
std::string msg_title;
std::string msg_text;
// Use the Update terminology when using Update All or working with the
// Upgradable add-ons view.
const bool updating = update_everything || updates_only;
if(ids_to_install.size() == 1 && failed_titles.empty()) {
utils::string_map syms;
syms["addon_title"] = addons[ids_to_install[0]].title;
msg_title = !updating ? _("Add-on Installed") : _("Add-on Updated");
msg_text = !updating ? _("The add-on '$addon_title|' has been successfully installed.") : _("The add-on '$addon_title|' has been successfully updated.");
// Extra flags are so restore_background can be set. Remove when no longer necessary
gui2::show_transient_message(v,
msg_title, utils::interpolate_variables_into_string(msg_text, &syms), "", false, false, true);
} else if(failed_titles.empty()) {
msg_title = !updating ? _("Add-ons Installed") : _("Add-ons Updated");
msg_text = !updating ? _("All add-ons installed successfully.") : _("All add-ons updated successfully.");
gui2::show_transient_message(v, msg_title, msg_text, "", false, false, true);
} else {
msg_title = !updating ? _("Installation Failed") : _("Update Failed");
msg_text = _n(
"The following add-on could not be downloaded or installed successfully:",
"The following add-ons could not be downloaded or installed successfully:",
failed_titles.size());
gui2::show_message(v, msg_title, msg_text + std::string("\n\n") + utils::bullet_list(failed_titles), gui2::dialogs::message::ok_button);
}
}
bool addons_manager_ui(CVideo& v, const std::string& remote_address)
{
bool stay_in_manager_ui = false;
bool need_wml_cache_refresh = false;
std::string last_addon_id;
addons_filter_state filter;
preferences::set_campaign_server(remote_address);
try {
do {
if(need_wml_cache_refresh) {
// The version info cache has gone stale because we installed/upgraded
// an add-on in the previous iteration. Normally this cache is refreshed
// along with all other caches, but we don't want to do all that here.
// Thus, we refresh this specific cache when required, so that add-ons
// are properly reported as installed/upgraded before leaving the
// manager UI.
refresh_addon_version_info_cache();
}
addons_client client(v, remote_address);
client.connect();
// TODO: don't create a new client instance each time we return to the UI,
// but for that we need to make sure any pending network operations are canceled
// whenever addons_client throws user_exit even before it gets destroyed
addons_client client(v, remote_address);
client.connect();
gui2::dialogs::addon_manager dlg(client);
dlg.show(v);
addons_list addons;
// BIG FAT TODO: get rid of the GUI1 addons manager. Just need to decide how best to decouple this.
//if(gui2::new_widgets) {
gui2::dialogs::addon_manager dlg(client);
dlg.show(v);
return dlg.get_need_wml_cache_refresh_();
//}
if(!get_addons_list(client, addons)) {
gui2::show_error_message(v, _("An error occurred while downloading the add-ons list from the server."));
return need_wml_cache_refresh;
}
try {
// Don't reconnect when switching between view modes.
do {
show_addons_manager_dialog(v, client, addons, last_addon_id, stay_in_manager_ui, need_wml_cache_refresh, filter);
} while(filter.changed);
} catch(const addons_client::user_exit&) {
// Don't do anything; just go back to the addons manager UI
// if the user cancels a download or other network operation
// after fetching the add-ons list above.
LOG_AC << "operation canceled by user; returning to add-ons manager\n";
}
} while(stay_in_manager_ui);
need_wml_cache_refresh = dlg.get_need_wml_cache_refresh_();
} catch(const config::error& e) {
ERR_CFG << "config::error thrown during transaction with add-on server; \""<< e.message << "\"" << std::endl;
gui2::show_error_message(v, _("Network communication error."));