/* * \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 /* 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(); }