sculpt: don't use component names as widget IDs

Component names can be larger than widget IDs, which are capped at 20
characters. To uniquely correlate the component depicted in the graph
with clicks, this patch uses a dedicated graph ID for each runtime
component instead.

Fixes #5034
This commit is contained in:
Norman Feske 2023-10-19 12:24:43 +02:00 committed by Christian Helmuth
parent 94d04b724a
commit 0a001443e9
2 changed files with 69 additions and 15 deletions

View File

@ -43,7 +43,7 @@ struct Dialog::Selectable_node
{
bool selected;
bool important;
Start_name primary_dep;
Dialog::Id primary_dep;
Start_name pretty_name;
};
@ -57,7 +57,7 @@ struct Dialog::Selectable_node
s.attribute("style", "unimportant");
if (attr.primary_dep.valid()) {
s.attribute("dep", attr.primary_dep);
s.attribute("dep", attr.primary_dep.value);
if (!attr.important)
s.attribute("dep_visible", false);
}
@ -217,12 +217,17 @@ void Graph::view(Scope<Depgraph> &s) const
bool const unimportant = any_selected && !info.tcb;
Start_name primary_dep = component.primary_dependency;
/* basic categories, like GUI */
Dialog::Id primary_dep = Id { component.primary_dependency };
if (primary_dep == "default_fs_rw")
primary_dep = _sculpt_partition.fs();
if (primary_dep.value == "default_fs_rw")
primary_dep = Dialog::Id { _sculpt_partition.fs() };
Selectable_node::view(s, Id { name },
/* primary dependency is another component */
_runtime_config.with_graph_id(primary_dep,
[&] (Dialog::Id const &id) { primary_dep = id; });
Selectable_node::view(s, component.graph_id,
{
.selected = info.selected,
.important = !unimportant,
@ -247,17 +252,22 @@ void Graph::view(Scope<Depgraph> &s) const
bool const show_details = info.tcb;
if (show_details) {
component.for_each_secondary_dep([&] (Start_name dep) {
component.for_each_secondary_dep([&] (Start_name dep_name) {
if (Runtime_state::blacklisted_from_graph(dep))
if (Runtime_state::blacklisted_from_graph(dep_name))
return;
if (dep == "default_fs_rw")
dep = _sculpt_partition.fs();
if (dep_name == "default_fs_rw")
dep_name = _sculpt_partition.fs();
Dialog::Id dep_id { dep_name };
_runtime_config.with_graph_id(dep_name, [&] (Dialog::Id const &id) {
dep_id = id; });
s.node("dep", [&] () {
s.attribute("node", name);
s.attribute("on", dep);
s.attribute("node", component.graph_id.value);
s.attribute("on", dep_id.value);
});
});
}
@ -276,7 +286,8 @@ void Graph::click(Clicked_at const &at, Action &action)
if (_usb_selected) _usb_devices_dialog .reset();
if (_storage_selected) _block_devices_dialog.reset();
_runtime_state.toggle_selection(id.value, _runtime_config);
_runtime_config.with_start_name(id, [&] (Start_name const &name) {
_runtime_state.toggle_selection(name, _runtime_config); });
}
_plus.propagate(at, [&] {

View File

@ -17,7 +17,9 @@
/* Genode includes */
#include <util/xml_node.h>
#include <util/list_model.h>
#include <util/dictionary.h>
#include <base/registry.h>
#include <dialog/types.h>
/* local includes */
#include <types.h>
@ -178,12 +180,33 @@ class Sculpt::Runtime_config
}
};
/*
* Data structure to associate dialog widget IDs with component names.
*/
struct Graph_id;
using Graph_ids = Dictionary<Graph_id, Start_name>;
struct Graph_id : Graph_ids::Element, Dialog::Id
{
Graph_id(Graph_ids &dict, Start_name const &name, Dialog::Id const &id)
:
Graph_ids::Element(dict, name), Dialog::Id(id)
{ }
};
Graph_ids _graph_ids { };
unsigned _graph_id_count = 0;
public:
struct Component : List_model<Component>::Element
{
Start_name const name;
Graph_id const graph_id;
Start_name primary_dependency { };
struct Dep : List_model<Dep>::Element
@ -216,7 +239,10 @@ class Sculpt::Runtime_config
List_model<Child_service> _child_services { };
Component(Start_name const &name) : name(name) { }
Component(Start_name const &name, Graph_ids &graph_ids, Dialog::Id const &id)
:
name(name), graph_id(graph_ids, name, id)
{ }
template <typename FN>
void for_each_service(FN const &fn) const
@ -343,7 +369,10 @@ class Sculpt::Runtime_config
/* create */
[&] (Xml_node const &node) -> Component & {
return *new (_alloc)
Component(node.attribute_value("name", Start_name())); },
Component(node.attribute_value("name", Start_name()),
_graph_ids,
Dialog::Id { _graph_id_count++ });
},
/* destroy */
[&] (Component &e) {
@ -360,6 +389,20 @@ class Sculpt::Runtime_config
);
}
void with_start_name(Dialog::Id const &id, auto const &fn) const
{
_components.for_each([&] (Component const &component) {
if (component.graph_id == id)
fn(component.name); });
}
void with_graph_id(Start_name const &name, auto const &fn) const
{
_graph_ids.with_element(name,
[&] (Graph_id const &id) { fn(id); },
[&] { });
}
template <typename FN>
void for_each_component(FN const &fn) const { _components.for_each(fn); }