genode/repos/gems/src/app/sculpt_manager/view/storage_dialog.cc

538 lines
16 KiB
C++

/*
* \brief Storage management dialog
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/log.h>
/* local includes */
#include "storage_dialog.h"
void Sculpt::Storage_dialog::_gen_partition_operations(Xml_generator &xml,
Storage_device const &device,
Partition const &partition) const
{
Storage_target const target { device.label, partition.number };
String<16> const version(device.label, ".", partition.number);
bool const whole_device = !partition.number.valid();
bool const device_in_use = (_used_target.device == device.label);
bool const target_in_use = (_used_target == target)
|| (whole_device && device_in_use)
|| partition.file_system_inspected;
bool const relabel_in_progress = device.relabel_in_progress();
bool const expand_in_progress = device.expand_in_progress();
bool const format_selected = _operation_item.selected("format");
bool const expand_selected = _operation_item.selected("expand");
if (partition.file_system.accessible() && !format_selected
&& !expand_selected && !expand_in_progress) {
if (!partition.check_in_progress && !partition.format_in_progress
&& partition.file_system.accessible() && !relabel_in_progress) {
xml.node("button", [&] () {
_inspect_item.gen_button_attr(xml, "browse");
xml.attribute("version", version);
if (partition.file_system_inspected)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Inspect"); });
});
}
if ((!_used_target.valid() || _used_target == target)
&& !partition.check_in_progress && !partition.format_in_progress
&& !relabel_in_progress) {
xml.node("button", [&] () {
xml.attribute("version", version);
_use_item.gen_button_attr(xml, "use");
if (_used_target == target)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Use"); });
});
}
if ((device.all_partitions_idle() || partition.relabel_in_progress())
&& partition.genode() && !device_in_use) {
xml.node("button", [&] () {
/* support hovering only if no relabeling is in progress */
if (partition.relabel_in_progress())
xml.attribute("name", "relabel");
else
_relabel_item.gen_button_attr(xml, "relabel");
xml.attribute("version", version);
if (partition.genode_default() || partition.relabel_in_progress())
xml.attribute("selected", "yes");
xml.node("label", [&] () {
xml.attribute("text", "Default"); });
});
if (partition.relabel_in_progress())
xml.node("label", [&] () { xml.attribute("text", "In progress..."); });
}
if (!target_in_use && !partition.format_in_progress && partition.checkable()
&& !relabel_in_progress) {
xml.node("button", [&] () {
_operation_item.gen_button_attr(xml, "check");
xml.attribute("version", version);
if (partition.check_in_progress)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Check"); });
});
if (partition.check_in_progress)
xml.node("label", [&] () { xml.attribute("text", "In progress..."); });
}
}
bool const whole_device_with_partition_in_use =
whole_device && !device.all_partitions_idle();
bool const format_button_visible = !target_in_use
&& !whole_device_with_partition_in_use
&& !partition.check_in_progress
&& !expand_in_progress
&& !relabel_in_progress
&& !_operation_item.selected("expand");
bool const expand_button_visible = !target_in_use
&& !whole_device
&& !partition.check_in_progress
&& !partition.format_in_progress
&& !relabel_in_progress
&& partition.expandable()
&& !_operation_item.selected("format");
bool const progress_msg_visible =
(_operation_item.selected("format") && partition.format_in_progress)
|| (_operation_item.selected("expand") && partition.expand_in_progress());
bool const confirm_visible =
(_operation_item.selected("format") && !partition.format_in_progress)
|| (_operation_item.selected("expand") && !partition.expand_in_progress());
if (format_button_visible) {
xml.node("button", [&] () {
_operation_item.gen_button_attr(xml, "format");
xml.attribute("version", version);
if (partition.format_in_progress)
xml.attribute("selected", "yes");
if (whole_device) {
xml.node("label", [&] () { xml.attribute("text", "Format device ..."); });
} else {
xml.node("label", [&] () { xml.attribute("text", "Format partition ..."); });
}
});
}
if (expand_button_visible) {
xml.node("button", [&] () {
_operation_item.gen_button_attr(xml, "expand");
xml.attribute("version", version);
if (partition.expand_in_progress())
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Expand ..."); });
});
}
if (progress_msg_visible)
xml.node("label", [&] () { xml.attribute("text", "In progress..."); });
if (confirm_visible) {
xml.node("button", [&] () {
_confirm_item.gen_button_attr(xml, "confirm");
xml.attribute("version", version);
xml.node("label", [&] () { xml.attribute("text", "Confirm"); });
});
}
}
void Sculpt::Storage_dialog::_gen_partition(Xml_generator &xml,
Storage_device const &device,
Partition const &partition) const
{
bool const selected = _partition_item.selected(partition.number);
gen_named_node(xml, "hbox", partition.number, [&] () {
gen_named_node(xml, "float", "left", [&] () {
xml.attribute("west", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "button", "button", [&] () {
if (_partition_item.hovered(partition.number))
xml.attribute("hovered", "yes");
if (selected)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", partition.number); });
});
if (partition.label.length() > 1)
gen_named_node(xml, "label", "label", [&] () {
xml.attribute("text", String<80>(" (", partition.label, ") ")); });
Storage_target const target { device.label, partition.number };
if (_used_target == target)
gen_named_node(xml, "label", "used", [&] () { xml.attribute("text", "* "); });
});
});
gen_named_node(xml, "float", "right", [&] () {
xml.attribute("east", "yes");
xml.node("label", [&] () {
xml.attribute("text", String<64>(partition.capacity, " ")); });
});
});
if (selected)
_gen_partition_operations(xml, device, partition);
}
void Sculpt::Storage_dialog::_gen_block_device(Xml_generator &xml,
Block_device const &dev) const
{
bool const selected = _device_item.selected(dev.label);
xml.node("button", [&] () {
xml.attribute("name", dev.label);
if (_device_item.hovered(dev.label))
xml.attribute("hovered", "yes");
if (selected)
xml.attribute("selected", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "float", "info", [&] () {
xml.attribute("west", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "label", "device", [&] () {
xml.attribute("text", dev.label); });
gen_named_node(xml, "label", "model", [&] () {
xml.attribute("text", String<80>(" (", dev.model, ") ")); });
if (_used_target.device == dev.label)
gen_named_node(xml, "label", "used", [&] () {
xml.attribute("text", "* "); });
});
});
gen_named_node(xml, "float", "capacity", [&] () {
xml.attribute("east", "yes");
xml.node("label", [&] () {
xml.attribute("text", String<64>(dev.capacity)); }); });
});
});
if (selected) {
xml.node("frame", [&] () {
xml.attribute("name", dev.label);
xml.node("vbox", [&] () {
dev.partitions.for_each([&] (Partition const &partition) {
_gen_partition(xml, dev, partition); });
if (!_partition_item.any_selected())
_gen_partition_operations(xml, dev, *dev.whole_device_partition);
});
});
}
}
void Sculpt::Storage_dialog::_gen_usb_storage_device(Xml_generator &xml,
Usb_storage_device const &dev) const
{
bool const selected = _device_item.selected(dev.label);
xml.node("button", [&] () {
xml.attribute("name", dev.label);
if (_device_item.hovered(dev.label))
xml.attribute("hovered", "yes");
if (selected)
xml.attribute("selected", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "float", "info", [&] () {
xml.attribute("west", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "label", "device", [&] () {
xml.attribute("text", dev.label); });
if (dev.driver_info.constructed()) {
gen_named_node(xml, "label", "vendor", [&] () {
String<16> const vendor { dev.driver_info->vendor };
xml.attribute("text", String<64>(" (", vendor, ") ")); });
}
if (_used_target.device == dev.label)
gen_named_node(xml, "label", "used", [&] () {
xml.attribute("text", " *"); });
});
});
gen_named_node(xml, "float", "capacity", [&] () {
xml.attribute("east", "yes");
xml.node("label", [&] () {
xml.attribute("text", String<64>(dev.capacity)); }); });
});
});
if (selected)
xml.node("frame", [&] () {
xml.attribute("name", dev.label);
xml.node("vbox", [&] () {
dev.partitions.for_each([&] (Partition const &partition) {
_gen_partition(xml, dev, partition); });
if (!_partition_item.any_selected())
_gen_partition_operations(xml, dev, *dev.whole_device_partition);
});
});
}
void Sculpt::Storage_dialog::_gen_ram_fs(Xml_generator &xml) const
{
bool const selected = _device_item.selected("ram_fs");
gen_named_node(xml, "button", "ram_fs", [&] () {
if (_device_item.hovered("ram_fs"))
xml.attribute("hovered", "yes");
if (selected)
xml.attribute("selected", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "float", "info", [&] () {
xml.attribute("west", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "label", "device", [&] () {
xml.attribute("text", "ram (in-memory file system) "); });
if (_used_target.device == "ram_fs")
gen_named_node(xml, "label", "used", [&] () {
xml.attribute("text", "* "); });
});
});
gen_named_node(xml, "float", "capacity", [&] () {
xml.attribute("east", "yes");
xml.node("label", [&] () {
Capacity const capacity { _ram_fs_state.ram_quota().value };
xml.attribute("text", String<64>(capacity)); }); });
});
});
if (selected) {
xml.node("frame", [&] () {
xml.attribute("name", "ram_fs_operations");
xml.node("vbox", [&] () {
xml.node("button", [&] () {
_inspect_item.gen_button_attr(xml, "browse");
if (_ram_fs_state.inspected)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Inspect"); });
});
if (!_used_target.valid() || _used_target.ram_fs()) {
xml.node("button", [&] () {
_use_item.gen_button_attr(xml, "use");
if (_used_target.ram_fs())
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Use"); });
});
}
if (!_used_target.ram_fs() && !_ram_fs_state.inspected) {
xml.node("button", [&] () {
_operation_item.gen_button_attr(xml, "reset");
xml.node("label", [&] () { xml.attribute("text", "Reset ..."); });
});
if (_operation_item.selected("reset")) {
xml.node("button", [&] () {
_confirm_item.gen_button_attr(xml, "confirm");
xml.node("label", [&] () { xml.attribute("text", "Confirm"); });
});
}
}
});
});
}
}
void Sculpt::Storage_dialog::generate(Xml_generator &xml, bool expanded) const
{
gen_named_node(xml, "frame", "storage", [&] () {
xml.node("vbox", [&] () {
gen_named_node(xml, "label", "title", [&] () {
xml.attribute("text", "Storage");
xml.attribute("font", "title/regular");
});
if (!expanded)
return;
_storage_devices.block_devices.for_each([&] (Block_device const &dev) {
_gen_block_device(xml, dev); });
_storage_devices.usb_storage_devices.for_each([&] (Usb_storage_device const &dev) {
_gen_usb_storage_device(xml, dev); });
_gen_ram_fs(xml);
});
});
}
void Sculpt::Storage_dialog::hover(Xml_node hover)
{
bool const changed =
_device_item .match(hover, "vbox", "button", "name") |
_partition_item.match(hover, "vbox", "frame", "vbox", "hbox", "name") |
_use_item .match(hover, "vbox", "frame", "vbox", "button", "name") |
_relabel_item .match(hover, "vbox", "frame", "vbox", "button", "name") |
_inspect_item .match(hover, "vbox", "frame", "vbox", "button", "name") |
_operation_item.match(hover, "vbox", "frame", "vbox", "button", "name") |
_confirm_item .match(hover, "vbox", "frame", "vbox", "button", "name");
if (changed)
_dialog_generator.generate_dialog();
}
void Sculpt::Storage_dialog::click(Action &action)
{
Selectable_item::Id const old_selected_device = _device_item._selected;
Selectable_item::Id const old_selected_partition = _partition_item._selected;
_device_item.toggle_selection_on_click();
_partition_item.toggle_selection_on_click();
if (!_device_item.selected(old_selected_device))
_partition_item.reset();
if (!_device_item.selected(old_selected_device)
|| !_partition_item.selected(old_selected_partition))
reset_operation();
Storage_target const target = _selected_storage_target();
if (_operation_item.hovered("format")) {
if (_operation_item.selected("format"))
action.cancel_format(_selected_storage_target());
else
_operation_item.toggle_selection_on_click();
}
if (_operation_item.hovered("expand")) {
if (_operation_item.selected("expand"))
action.cancel_expand(_selected_storage_target());
else
_operation_item.toggle_selection_on_click();
}
/* toggle confirmation button when clicking on ram_fs reset */
if (_operation_item.hovered("reset"))
_operation_item.toggle_selection_on_click();
if (_operation_item.hovered("check"))
action.check(target);
/* toggle file browser */
if (_inspect_item.hovered("browse"))
action.toggle_file_browser(target);
if (_use_item.hovered("use")) {
/* release currently used device */
if (target.valid() && target == _used_target)
action.use(Storage_target{});
/* select new used device if none is defined */
else if (!_used_target.valid())
action.use(target);
}
if (_relabel_item.hovered("relabel"))
action.toggle_default_storage_target(target);
if (_confirm_item.hovered("confirm")) {
_confirm_item.propose_activation_on_click();
}
_dialog_generator.generate_dialog();
}
void Sculpt::Storage_dialog::clack(Action &action)
{
if (_confirm_item.hovered("confirm")) {
_confirm_item.confirm_activation_on_clack();
if (_confirm_item.activated("confirm")) {
Storage_target const target = _selected_storage_target();
if (_operation_item.selected("format"))
action.format(target);
if (_operation_item.selected("expand"))
action.expand(target);
if (target.ram_fs() && _operation_item.selected("reset"))
action.reset_ram_fs();
}
} else {
_confirm_item.reset();
}
_dialog_generator.generate_dialog();
}