fix(TUI): Selected column and selected row of table are now preserved when set_items() is called (#3161)

This commit is contained in:
Joseph Goulden 2019-12-10 19:21:03 +00:00 committed by Antioch Peverell
parent 39af7fa202
commit 5c7bc3d8cd
3 changed files with 109 additions and 9 deletions

View file

@ -193,6 +193,24 @@ pub struct PeerStats {
pub received_bytes_per_sec: u64,
}
impl PartialEq for PeerStats {
fn eq(&self, other: &PeerStats) -> bool {
*self.addr == other.addr
}
}
impl PartialEq for WorkerStats {
fn eq(&self, other: &WorkerStats) -> bool {
*self.id == other.id
}
}
impl PartialEq for DiffBlock {
fn eq(&self, other: &DiffBlock) -> bool {
self.block_height == other.block_height
}
}
impl StratumStats {
/// Calculate network hashrate
pub fn network_hashrate(&self, height: u64) -> f64 {

View file

@ -33,7 +33,7 @@ use crate::tui::table::{TableView, TableViewItem};
use crate::tui::types::TUIStatusListener;
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
enum PeerColumn {
pub enum PeerColumn {
Address,
State,
UsedBandwidth,

View file

@ -145,7 +145,7 @@ where
/// .default_column(BasicColumn::Name);
/// # }
/// ```
pub struct TableView<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> {
pub struct TableView<T: TableViewItem<H> + PartialEq, H: Eq + Hash + Copy + Clone + 'static> {
enabled: bool,
scrollbase: ScrollBase,
last_size: Vec2,
@ -165,7 +165,7 @@ pub struct TableView<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static>
on_select: Option<Rc<dyn Fn(&mut Cursive, usize, usize)>>,
}
impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H> {
impl<T: TableViewItem<H> + PartialEq, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H> {
/// Creates a new empty `TableView` without any columns.
///
/// A TableView should be accompanied by a enum of type `H` representing
@ -233,8 +233,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
pub fn sort_by(&mut self, column: H, order: Ordering) {
if self.column_indices.contains_key(&column) {
for c in &mut self.columns {
c.selected = c.column == column;
if c.selected {
if c.column == column {
c.order = order;
} else {
c.order = Ordering::Equal;
@ -437,8 +436,19 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
/// Sets the contained items of the table.
///
/// The currently active sort order is preserved and will be applied to all
/// items.
/// items. The selected item will also be preserved.
pub fn set_items(&mut self, items: Vec<T>) {
let mut new_location = 0;
if let Some(old_item_location) = self.item() {
let old_item = self.items.get(old_item_location).unwrap();
for (i, new_item) in items.iter().enumerate() {
if old_item == new_item {
new_location = i;
break;
}
}
}
self.items = items;
self.rows_to_items = Vec::with_capacity(self.items.len());
@ -453,7 +463,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
self.scrollbase
.set_heights(self.last_size.y.saturating_sub(2), self.rows_to_items.len());
self.set_selected_row(0);
self.set_selected_item(new_location);
}
/// Sets the contained items of the table.
@ -580,7 +590,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
}
}
impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H> {
impl<T: TableViewItem<H> + PartialEq, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H> {
fn draw_columns<C: Fn(&Printer<'_, '_>, &TableColumn<H>)>(
&self,
printer: &Printer<'_, '_>,
@ -689,7 +699,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
}
}
impl<T: TableViewItem<H> + 'static, H: Eq + Hash + Copy + Clone + 'static> View
impl<T: TableViewItem<H> + PartialEq + 'static, H: Eq + Hash + Copy + Clone + 'static> View
for TableView<T, H>
{
fn draw(&self, printer: &Printer<'_, '_>) {
@ -981,3 +991,75 @@ impl<H: Copy + Clone + 'static> TableColumn<H> {
printer.print((0, 0), value.as_str());
}
}
#[cfg(test)]
mod test {
use crate::tui::peers::PeerColumn;
use crate::tui::table::TableView;
use chrono::Utc;
use grin_core::ser::ProtocolVersion;
use grin_servers::PeerStats;
use std::cmp::Ordering;
#[test]
pub fn test_set_items_preserves_selected_item() {
let mut table = TableView::<PeerStats, PeerColumn>::new();
let ps1 = PeerStats {
addr: "123.0.0.1".to_string(),
..TestPeerStats::default()
};
let ps2 = PeerStats {
addr: "123.0.0.2".to_string(),
..TestPeerStats::default()
};
let mut items = vec![ps1, ps2];
table.set_items(items.clone());
assert_eq!(table.item().unwrap(), 0);
items.reverse();
table.set_items(items);
assert_eq!(table.item().unwrap(), 1);
}
#[test]
pub fn test_set_items_preserves_order() {
let mut table = TableView::<PeerStats, PeerColumn>::new();
let ps1 = PeerStats {
addr: "123.0.0.1".to_string(),
received_bytes_per_sec: 10,
..TestPeerStats::default()
};
let ps2 = PeerStats {
addr: "123.0.0.2".to_string(),
received_bytes_per_sec: 80,
..TestPeerStats::default()
};
let items = vec![ps1, ps2];
table.set_items(items);
assert_eq!(table.rows_to_items[0], 0);
table.sort_by(PeerColumn::UsedBandwidth, Ordering::Greater);
assert_eq!(table.rows_to_items[0], 1);
}
struct TestPeerStats(PeerStats);
impl TestPeerStats {
fn default() -> PeerStats {
PeerStats {
state: "Connected".to_string(),
addr: "127.0.0.1".to_string(),
version: ProtocolVersion::local(),
user_agent: "".to_string(),
total_difficulty: 0,
height: 0,
direction: "Outbound".to_string(),
last_seen: Utc::now(),
sent_bytes_per_sec: 0,
received_bytes_per_sec: 0,
}
}
}
}