Skip to content

Commit

Permalink
Refactor the way to show publishable add-ons in the add-on manager
Browse files Browse the repository at this point in the history
This fixes two bugs:
* publishable add-ons were shown in the "Install Dependencies" dialog
* the game crashed when the player attempted to filter the list if
  publishable add-ons were present
  • Loading branch information
jyrkive committed Feb 14, 2017
1 parent e1045f9 commit 3e68d47
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 125 deletions.
3 changes: 3 additions & 0 deletions src/addon/state.cpp
Expand Up @@ -50,6 +50,9 @@ addon_tracking_info get_addon_tracking_info(const addon_info& addon)
t.state = ADDON_INSTALLED;
} else if(t.remote_version > t.installed_version) {
t.state = ADDON_INSTALLED_UPGRADABLE;
} else if(t.remote_version == version_info()) {
// Remote version not set.
t.state = ADDON_INSTALLED_LOCAL_ONLY;
} else /* if(remote_version < t.installed_version) */ {
t.state = ADDON_INSTALLED_OUTDATED;
}
Expand Down
2 changes: 2 additions & 0 deletions src/addon/state.hpp
Expand Up @@ -28,6 +28,8 @@ enum ADDON_STATUS {
ADDON_INSTALLED_UPGRADABLE,
/** Version in the server is older than local installation. */
ADDON_INSTALLED_OUTDATED,
/** No version in the server. */
ADDON_INSTALLED_LOCAL_ONLY,
/** Dependencies not satisfied.
* @todo This option isn't currently implemented! */
ADDON_INSTALLED_BROKEN,
Expand Down
14 changes: 13 additions & 1 deletion src/gui/dialogs/addon/manager.cpp
Expand Up @@ -425,8 +425,20 @@ void addon_manager::load_addon_list(window& window)

read_addons_list(cfg_, addons_);

addons_including_publishable_ = addons_;
std::vector<std::string> publishable_addons = available_addons();

for(std::string id : publishable_addons) {
if(addons_including_publishable_.find(id) == addons_including_publishable_.end()) {
// Add the add-on to the list.
addon_info addon;
addon.id = id;
addons_including_publishable_[id] = addon;
}
}

addon_list& list = find_widget<addon_list>(&window, "addons", false);
list.set_addons(addons_);
list.set_addons(addons_including_publishable_);

bool has_upgradable_addons = false;
for(const auto& a : addons_) {
Expand Down
1 change: 1 addition & 0 deletions src/gui/dialogs/addon/manager.hpp
Expand Up @@ -59,6 +59,7 @@ class addon_manager : public modal_dialog
addons_client& client_;

addons_list addons_;
addons_list addons_including_publishable_;

addons_tracking_list tracking_info_;

Expand Down
197 changes: 87 additions & 110 deletions src/gui/widgets/addon_list.cpp
Expand Up @@ -116,149 +116,132 @@ void addon_list::set_addons(const addons_list& addons)

addon_vector_.push_back(&addon);

// Note addons that can be deleted
if(tracking_info.can_publish) {
can_delete_ids_.push_back(addon.id);
}

std::map<std::string, string_map> data;
string_map item;

item["use_markup"] = "true";

item["label"] = addon.display_icon();
data.emplace("icon", item);
if(!tracking_info.can_publish) {
item["label"] = addon.display_icon();
data.emplace("icon", item);

item["label"] = addon.display_title();
data.emplace("name", item);
item["label"] = addon.display_title();
data.emplace("name", item);

item["label"] = describe_status(tracking_info);
data.emplace("installation_status", item);
item["label"] = describe_status(tracking_info);
data.emplace("installation_status", item);

item["label"] = addon.version.str();
data.emplace("version", item);
item["label"] = addon.version.str();
data.emplace("version", item);

item["label"] = addon.author;
data.emplace("author", item);
item["label"] = addon.author;
data.emplace("author", item);

item["label"] = size_display_string(addon.size);
data.emplace("size", item);
item["label"] = size_display_string(addon.size);
data.emplace("size", item);

item["label"] = std::to_string(addon.downloads);
data.emplace("downloads", item);
item["label"] = std::to_string(addon.downloads);
data.emplace("downloads", item);

item["label"] = addon.display_type();
data.emplace("type", item);
item["label"] = addon.display_type();
data.emplace("type", item);
} else {
item["label"] = "icons/icon-game.png~BLIT(icons/icon-addon-publish.png)";
data.emplace("icon", item);

const std::string publish_name = formatter()
<< "<span color='#00ff00'>" // GOOD_COLOR
<< vgettext("Publish: $addon_title", { { "addon_title", addon.display_title() } })
<< "</span>";

item["label"] = publish_name;
data.emplace("name", item);
}

grid* row_grid = &list.add_row(data);

stacked_widget& install_update_stack = find_widget<stacked_widget>(row_grid, "install_update_stack", false);

const bool is_updatable = tracking_info.state == ADDON_INSTALLED_UPGRADABLE;
const bool is_installed = tracking_info.state == ADDON_INSTALLED;
if(!tracking_info.can_publish) {
const bool is_updatable = tracking_info.state == ADDON_INSTALLED_UPGRADABLE;
const bool is_installed = tracking_info.state == ADDON_INSTALLED;

install_update_stack.select_layer(static_cast<int>(is_updatable));

if(!is_updatable) {
find_widget<button>(row_grid, "single_install", false).set_active(!is_installed);
if(install_function_ != nullptr) {
gui2::event::connect_signal_mouse_left_click(
find_widget<button>(row_grid, "single_install", false),
[this, addon](gui2::event::dispatcher&, const gui2::event::ui_event, bool& handled, bool& halt)
{
install_function_(addon);
handled = true;
halt = true;
});
}
}

if(is_installed) {
if(uninstall_function_ != nullptr) {
gui2::event::connect_signal_mouse_left_click(
find_widget<button>(row_grid, "single_uninstall", false),
[this, addon](gui2::event::dispatcher&, const gui2::event::ui_event, bool& handled, bool& halt)
{
uninstall_function_(addon);
handled = true;
halt = true;
});
}
}

install_update_stack.select_layer(static_cast<int>(is_updatable));
find_widget<button>(row_grid, "single_uninstall", false).set_active(is_installed);

if(!is_updatable) {
find_widget<button>(row_grid, "single_install", false).set_active(!is_installed);
if(install_function_ != nullptr) {
find_widget<grid>(row_grid, "single_install_buttons", false).set_visible(install_buttons_visibility_);
find_widget<label>(row_grid, "installation_status", false).set_visible(install_status_visibility_);
} else {
const bool is_updatable = tracking_info.state == ADDON_INSTALLED_OUTDATED;

find_widget<button>(row_grid, "single_install", false).set_active(true);
find_widget<button>(row_grid, "single_update", false).set_active(true);
find_widget<button>(row_grid, "single_uninstall", false).set_active(tracking_info.state == ADDON_INSTALLED);

install_update_stack.select_layer(static_cast<int>(is_updatable));

if(true) {
gui2::event::connect_signal_mouse_left_click(
find_widget<button>(row_grid, "single_install", false),
[this, addon](gui2::event::dispatcher&, const gui2::event::ui_event, bool& handled, bool& halt)
{
install_function_(addon);
publish_function_(addon.id);
handled = true;
halt = true;
});
}
}

if(is_installed) {
if(uninstall_function_ != nullptr) {
if(is_updatable) {
gui2::event::connect_signal_mouse_left_click(
find_widget<button>(row_grid, "single_uninstall", false),
find_widget<button>(row_grid, "single_update", false),
[this, addon](gui2::event::dispatcher&, const gui2::event::ui_event, bool& handled, bool& halt)
{
uninstall_function_(addon);
publish_function_(addon.id);
handled = true;
halt = true;
});
}
}

find_widget<button>(row_grid, "single_uninstall", false).set_active(is_installed);

find_widget<grid>(row_grid, "single_install_buttons", false).set_visible(install_buttons_visibility_);
find_widget<label>(row_grid, "installation_status", false).set_visible(install_status_visibility_);
}

const auto add_addon_author_rows = [&](const std::vector<std::string>& vec, const bool publish)
{
for(const std::string& id : vec) {
std::map<std::string, string_map> data;
string_map item;

item["use_markup"] = "true";

item["label"] = publish
? "icons/icon-game.png~BLIT(icons/icon-addon-publish.png)"
: "icons/icon-game.png~BLIT(icons/icon-addon-delete.png)";
data.emplace("icon", item);

const std::string publish_name = publish
? (formatter()
<< "<span color='#00ff00'>" // GOOD_COLOR
<< vgettext("Publish: $addon_title", {{"addon_title", make_addon_title(id)}})
<< "</span>").
str()
: (formatter()
<< "<span color='#ff0000'>" // BAD_COLOR
<< vgettext("Delete: $addon_title", {{"addon_title", make_addon_title(id)}})
<< "</span>").
str();

item["label"] = publish_name;
data.emplace("name", item);

grid* row_grid = &list.add_row(data);

find_widget<button>(row_grid, "single_install", false).set_active(publish);
find_widget<button>(row_grid, "single_update", false).set_active(publish);
find_widget<button>(row_grid, "single_uninstall", false).set_active(!publish);

find_widget<stacked_widget>(row_grid, "install_update_stack", false).select_layer(1);

if(publish) {
gui2::event::connect_signal_mouse_left_click(
find_widget<button>(row_grid, "single_update", false),
[this, id](gui2::event::dispatcher&, const gui2::event::ui_event, bool& handled, bool& halt)
{
publish_function_(id);
handled = true;
halt = true;
});
} else {
if(tracking_info.state == ADDON_INSTALLED) {
gui2::event::connect_signal_mouse_left_click(
find_widget<button>(row_grid, "single_uninstall", false),
[this, id](gui2::event::dispatcher&, const gui2::event::ui_event, bool& handled, bool& halt)
[this, addon](gui2::event::dispatcher&, const gui2::event::ui_event, bool& handled, bool& halt)
{
delete_function_(id);
delete_function_(addon.id);
handled = true;
halt = true;
});
}
}
};

//
// Addons that can be published
//
add_addon_author_rows(can_publish_ids_, true);

//
// Addons that can be deleted
//
add_addon_author_rows(can_delete_ids_, false);
}
}

const addon_info* addon_list::get_selected_addon() const
Expand All @@ -275,18 +258,12 @@ const addon_info* addon_list::get_selected_addon() const

std::string addon_list::get_remote_addon_id()
{
const listbox& list = find_widget<const listbox>(&get_grid(), "addons", false);

const int index = list.get_selected_row();
if(index >= int(addon_vector_.size() + can_publish_ids_.size())) {
// Remote deletion.
return can_delete_ids_[index - int(addon_vector_.size() + can_publish_ids_.size())];
} else if(index >= int(addon_vector_.size())) {
// Remote publishing.
return can_publish_ids_[index - int(addon_vector_.size())];
const addon_info* addon = get_selected_addon();
if(addon == nullptr || !get_addon_tracking_info(*addon).can_publish) {
return "";
} else {
return addon->id;
}

return "";
}

void addon_list::select_addon(const std::string& id)
Expand Down
14 changes: 0 additions & 14 deletions src/gui/widgets/addon_list.hpp
Expand Up @@ -48,8 +48,6 @@ class addon_list : public container_base
, uninstall_function_()
, publish_function_()
, delete_function_()
, can_publish_ids_(available_addons())
, can_delete_ids_()
{}

/** Sets the add-ons to show. */
Expand Down Expand Up @@ -148,18 +146,6 @@ class addon_list : public container_base
std::function<void(const std::string&)> publish_function_;
std::function<void(const std::string&)> delete_function_;

/**
* Add-ons available for publishing in the remote
* (i.e. we have .pbl files for them).
*/
const std::vector<std::string> can_publish_ids_;

/**
* 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_;

static std::string describe_status(const addon_tracking_info& info);

/** Returns the underlying list box. */
Expand Down

0 comments on commit 3e68d47

Please sign in to comment.