|
1 | 1 | use std::collections::{BTreeSet, HashMap}; |
| 2 | +use std::io::Write; |
2 | 3 |
|
3 | 4 | use abstutil::prettyprint_usize; |
4 | 5 | use geom::{Duration, Polygon, Time}; |
5 | 6 | use map_gui::tools::{checkbox_per_mode, color_for_mode}; |
6 | 7 | use sim::TripID; |
7 | 8 | use synthpop::{TripEndpoint, TripMode}; |
8 | 9 | use widgetry::table::{Col, Filter, Table}; |
| 10 | +use widgetry::tools::PopupMsg; |
9 | 11 | use widgetry::{ |
10 | 12 | Color, EventCtx, Filler, GeomBatch, GfxCtx, Line, Outcome, Panel, Stash, State, TabController, |
11 | 13 | Text, Toggle, Widget, |
@@ -62,6 +64,11 @@ impl TripTable { |
62 | 64 | let finished_trips_table = make_table_finished_trips(app); |
63 | 65 | let finished_trips_content = Widget::col(vec![ |
64 | 66 | finished_trips_table.render(ctx, app), |
| 67 | + ctx.style() |
| 68 | + .btn_plain |
| 69 | + .text("Export to CSV") |
| 70 | + .build_def(ctx) |
| 71 | + .align_bottom(), |
65 | 72 | Filler::square_width(ctx, 0.15) |
66 | 73 | .named("preview") |
67 | 74 | .centered_horiz(), |
@@ -123,6 +130,18 @@ impl State<App> for TripTable { |
123 | 130 | fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition { |
124 | 131 | match self.panel.event(ctx) { |
125 | 132 | Outcome::Clicked(x) => { |
| 133 | + if x == "Export to CSV" { |
| 134 | + return Transition::Push(match export_trip_table(app) { |
| 135 | + Ok(path) => PopupMsg::new_state( |
| 136 | + ctx, |
| 137 | + "Data exported", |
| 138 | + vec![format!("Data exported to {}", path)], |
| 139 | + ), |
| 140 | + Err(err) => { |
| 141 | + PopupMsg::new_state(ctx, "Export failed", vec![err.to_string()]) |
| 142 | + } |
| 143 | + }); |
| 144 | + } |
126 | 145 | if self.table_tabs.active_tab_idx() == 0 && self.finished_trips_table.clicked(&x) { |
127 | 146 | self.finished_trips_table |
128 | 147 | .replace_render(ctx, app, &mut self.panel); |
@@ -698,3 +717,35 @@ fn make_table_unfinished_trips(app: &App) -> Table<App, UnfinishedTrip, Filters> |
698 | 717 |
|
699 | 718 | table |
700 | 719 | } |
| 720 | + |
| 721 | +fn export_trip_table(app: &App) -> anyhow::Result<String> { |
| 722 | + let (finished, _) = produce_raw_data(app); |
| 723 | + let path = format!( |
| 724 | + "trip_table_{}_{}.csv", |
| 725 | + app.primary.map.get_name().as_filename(), |
| 726 | + app.primary.sim.time().as_filename() |
| 727 | + ); |
| 728 | + |
| 729 | + let mut out = std::io::Cursor::new(Vec::new()); |
| 730 | + writeln!( |
| 731 | + out, |
| 732 | + "id,mode,modified,departure,duration,waiting_time,percent_waiting,duration_before" |
| 733 | + )?; |
| 734 | + |
| 735 | + for trip in finished { |
| 736 | + writeln!( |
| 737 | + out, |
| 738 | + "{},{:?},{},{},{},{},{},{}", |
| 739 | + trip.id.0, |
| 740 | + trip.mode, |
| 741 | + trip.modified, |
| 742 | + trip.departure, |
| 743 | + trip.duration_after.inner_seconds(), |
| 744 | + trip.waiting.inner_seconds(), |
| 745 | + trip.percent_waiting, |
| 746 | + trip.duration_before.inner_seconds() |
| 747 | + )?; |
| 748 | + } |
| 749 | + |
| 750 | + abstio::write_file(path, String::from_utf8(out.into_inner())?).map_err(anyhow::Error::from) |
| 751 | +} |
0 commit comments