mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-10-16 00:19:58 +00:00
renaming
This commit is contained in:
1 parent
3c2055b50e
commit
ce8398f749
16 files changed
+227
-235
No files matched your search
@@ -1,6 +1,6 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::{Apply, CommandError, FileId, Selection, StackEntry, State, Waypoint};
|
||||
use crate::{Apply, CommandError, FileId, Files, Selection, State, Waypoint};
|
||||
|
||||
/// Deletes the selected elements. With `whole_files`, the files holding the selected elements
|
||||
/// are deleted instead, even if only a track or a waypoint is selected.
|
||||
@@ -75,7 +75,7 @@ impl Apply for Delete {
|
||||
}
|
||||
|
||||
pub(crate) fn delete_waypoints(
|
||||
files: &mut StackEntry,
|
||||
files: &mut Files,
|
||||
file_id: FileId,
|
||||
filter: impl Fn(&Waypoint) -> bool,
|
||||
) -> Result<Selection, CommandError> {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::{collections::HashSet, rc::Rc};
|
||||
|
||||
use crate::{
|
||||
Apply, CommandError, FileId, Selection, StackEntry, State, Waypoint, copy_file, copy_segment,
|
||||
Apply, CommandError, FileId, Files, Selection, State, Waypoint, copy_file, copy_segment,
|
||||
copy_track, copy_waypoint,
|
||||
};
|
||||
|
||||
@@ -107,7 +107,7 @@ impl Apply for Duplicate {
|
||||
}
|
||||
|
||||
fn duplicate_waypoints(
|
||||
files: &mut StackEntry,
|
||||
files: &mut Files,
|
||||
file_id: FileId,
|
||||
filter: impl Fn(&Waypoint) -> bool,
|
||||
) -> Result<Selection, CommandError> {
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::{Clipboard, FileId, FileOrder, Selection, StackEntry, State, TrackpointCategories};
|
||||
use crate::{Clipboard, FileId, FileOrder, Files, Selection, State, TrackpointCategories};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Fixture {
|
||||
pub files: StackEntry,
|
||||
pub files: Files,
|
||||
pub selection: Selection,
|
||||
pub order: FileOrder,
|
||||
pub clipboard: Option<Clipboard>,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::{File, FileId, Selection, StackEntry, State, Track, TrackSegment, Waypoint};
|
||||
use crate::{File, FileId, Files, Selection, State, Track, TrackSegment, Waypoint};
|
||||
|
||||
/// What an [`Editor`] hook did to the element it was given.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -70,7 +70,7 @@ fn edit_where<T>(
|
||||
|
||||
/// Edits a copy of the file (cheap, track points are shared chunks) and stores it back as a
|
||||
/// new snapshot only if something changed.
|
||||
fn update_file(files: &mut StackEntry, id: FileId, f: impl FnOnce(&mut File) -> Edit) {
|
||||
fn update_file(files: &mut Files, id: FileId, f: impl FnOnce(&mut File) -> Edit) {
|
||||
let Some(current) = files.get(&id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use crate::{
|
||||
FileId, FileWaypointsRevisionId, StackEntry as Files, TrackSegmentId, TrackSegmentRevisionId,
|
||||
};
|
||||
use crate::{FileId, FileWaypointsRevisionId, Files, TrackSegmentId, TrackSegmentRevisionId};
|
||||
|
||||
/// Coordinates buffers, as flat `[lng, lat, lng, lat, ...]` arrays so that they can be handed
|
||||
/// to the UI without per-point calls: one per track segment (its trackpoints) and one per file
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{Diff, FileId, FileStructure, StackEntry as Files};
|
||||
use crate::{Diff, FileId, FileStructure, Files};
|
||||
|
||||
/// The structure of each file, only recomputed for the files that changed according to the
|
||||
/// [`Diff`] of the stack.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{FileId, Selection, StackEntry, TrackSegmentId, TrackSegmentRevisionId};
|
||||
use crate::{FileId, Files, Selection, TrackSegmentId, TrackSegmentRevisionId};
|
||||
|
||||
/// What the routing tool needs about the selected segments (see
|
||||
/// [`Selection::segment_locations`]): where their anchors are among their trackpoints.
|
||||
@@ -27,7 +27,7 @@ pub struct RoutingBuffer {
|
||||
}
|
||||
|
||||
impl RoutingBuffer {
|
||||
pub fn update(&mut self, files: Option<&StackEntry>, selection: &Selection, order: &[FileId]) {
|
||||
pub fn update(&mut self, files: Option<&Files>, selection: &Selection, order: &[FileId]) {
|
||||
self.anchor_indices.clear();
|
||||
self.anchor_zooms.clear();
|
||||
self.segment_starts.clear();
|
||||
@@ -70,11 +70,11 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
fn loaded() -> (StackEntry, FileId) {
|
||||
fn loaded() -> (Files, FileId) {
|
||||
let data = std::fs::read("data/with_tracks_and_segments.gpx").unwrap();
|
||||
let file = parse(&data, &mut Default::default()).unwrap();
|
||||
let id = file.id;
|
||||
let mut files = StackEntry::default();
|
||||
let mut files = Files::default();
|
||||
files.insert(id, Rc::new(file));
|
||||
(files, id)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::collections::{HashMap, HashSet, hash_map::Entry};
|
||||
|
||||
use crate::{
|
||||
File, FileId, GlobalStatistics, Selection, StackEntry, Statistics, Track, TrackSegment,
|
||||
File, FileId, Files, GlobalStatistics, Selection, Statistics, Track, TrackSegment,
|
||||
TrackSegmentRevisionId,
|
||||
};
|
||||
|
||||
@@ -14,7 +14,7 @@ pub struct StatisticsCache {
|
||||
}
|
||||
|
||||
impl StatisticsCache {
|
||||
pub fn update(&mut self, state: Option<&StackEntry>) {
|
||||
pub fn update(&mut self, state: Option<&Files>) {
|
||||
let mut stale: HashSet<TrackSegmentRevisionId> = self.map.keys().copied().collect();
|
||||
if let Some(state) = state {
|
||||
for file in state.values() {
|
||||
@@ -40,7 +40,7 @@ impl StatisticsCache {
|
||||
/// Statistics of the segments of the selection.
|
||||
pub fn get<'a>(
|
||||
&'a self,
|
||||
state: Option<&'a StackEntry>,
|
||||
state: Option<&'a Files>,
|
||||
selection: &Selection,
|
||||
) -> Vec<&'a Statistics> {
|
||||
self.selected(state, selection, &[])
|
||||
@@ -53,7 +53,7 @@ impl StatisticsCache {
|
||||
/// files follow `order` (the files missing from it come last).
|
||||
pub fn selected<'a>(
|
||||
&'a self,
|
||||
state: Option<&'a StackEntry>,
|
||||
state: Option<&'a Files>,
|
||||
selection: &Selection,
|
||||
order: &[FileId],
|
||||
) -> Vec<SelectedSegment<'a>> {
|
||||
@@ -159,10 +159,10 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
fn state(path: &str) -> (StackEntry, Rc<File>) {
|
||||
fn state(path: &str) -> (Files, Rc<File>) {
|
||||
let data = std::fs::read(path).unwrap();
|
||||
let file = Rc::new(parse(&data, &mut Default::default()).unwrap());
|
||||
let mut state = StackEntry::default();
|
||||
let mut state = Files::default();
|
||||
state.insert(file.id, file.clone());
|
||||
(state, file)
|
||||
}
|
||||
@@ -235,7 +235,7 @@ mod tests {
|
||||
let before: *const Statistics = cache.get(Some(&state), &file_selection(file.id))[0];
|
||||
|
||||
// a new snapshot of the file that shares its segments (same revision ids)
|
||||
let mut next = StackEntry::default();
|
||||
let mut next = Files::default();
|
||||
let renamed = {
|
||||
let mut f = (*file).clone();
|
||||
f.info.name = "other".to_string();
|
||||
@@ -258,7 +258,7 @@ mod tests {
|
||||
let mut f = (*file).clone();
|
||||
f.trk[0].trkseg[0].rev_id = Default::default();
|
||||
let new_rev = f.trk[0].trkseg[0].rev_id;
|
||||
let mut next = StackEntry::default();
|
||||
let mut next = Files::default();
|
||||
next.insert(f.id, Rc::new(f));
|
||||
cache.update(Some(&next));
|
||||
assert!(cache.map.contains_key(&new_rev));
|
||||
|
||||
@@ -17,7 +17,7 @@ use crate::{
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Engine {
|
||||
stack: Stack,
|
||||
history: History,
|
||||
selection: Selection,
|
||||
order: FileOrder,
|
||||
statistics_cache: StatisticsCache,
|
||||
@@ -56,7 +56,7 @@ impl Engine {
|
||||
|
||||
/// Global statistics (distance, time, elevation, bounds...) of a file.
|
||||
pub fn file_statistics(&self, id: &FileId) -> Option<GlobalStatistics> {
|
||||
let file = self.stack.current()?.get(id)?;
|
||||
let file = self.history.current()?.get(id)?;
|
||||
Some(self.statistics_cache.file_global(file))
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ impl Engine {
|
||||
|
||||
/// A waypoint of a file, with all its data. `None` if it does not exist.
|
||||
pub fn waypoint(&self, file_id: &FileId, id: &WaypointId) -> Option<&Waypoint> {
|
||||
self.stack
|
||||
self.history
|
||||
.current()?
|
||||
.get(file_id)?
|
||||
.wpt
|
||||
@@ -90,7 +90,7 @@ impl Engine {
|
||||
index: usize,
|
||||
) -> Option<&Trackpoint> {
|
||||
let segment = self
|
||||
.stack
|
||||
.history
|
||||
.current()?
|
||||
.get(file_id)?
|
||||
.trk
|
||||
@@ -103,7 +103,7 @@ impl Engine {
|
||||
/// For each trackpoint of the selection (numbered as in the statistics), the tolerance up to
|
||||
/// which `Reduce` keeps it, see [`reduction_distances`].
|
||||
pub fn reduction_distances(&self) -> Vec<f64> {
|
||||
let Some(files) = self.stack.current() else {
|
||||
let Some(files) = self.history.current() else {
|
||||
return vec![];
|
||||
};
|
||||
self.selection
|
||||
@@ -120,7 +120,7 @@ impl Engine {
|
||||
/// What there is to keep of the engine, see [`crate::Persister`].
|
||||
pub fn snapshot(&self) -> Snapshot {
|
||||
Snapshot {
|
||||
files: self.stack.current().cloned().unwrap_or_default(),
|
||||
files: self.history.current().cloned().unwrap_or_default(),
|
||||
order: self.order.0.clone(),
|
||||
categories: self.categories.clone(),
|
||||
}
|
||||
@@ -137,19 +137,19 @@ impl Engine {
|
||||
pub fn restore(&mut self, restored: Restored) -> Outcome {
|
||||
let selection_before = self.selection.clone();
|
||||
let order_before = self.order.0.clone();
|
||||
let before = self.stack.current().cloned();
|
||||
let files: StackEntry = restored
|
||||
let before = self.history.current().cloned();
|
||||
let files: Files = restored
|
||||
.files
|
||||
.into_iter()
|
||||
.map(|file| (file.id, file))
|
||||
.collect();
|
||||
let diff = Stack::diff_between(before.as_ref(), Some(&files));
|
||||
let diff = History::diff_between(before.as_ref(), Some(&files));
|
||||
let mut diff =
|
||||
(!(diff.added.is_empty() && diff.removed.is_empty() && diff.modified.is_empty()))
|
||||
.then_some(diff);
|
||||
self.categories = restored.categories;
|
||||
self.order = FileOrder(restored.order);
|
||||
self.stack = Stack::restored(files);
|
||||
self.history = History::restored(files);
|
||||
self.refresh(diff.as_ref());
|
||||
sort_diff(&mut diff, &self.order.0);
|
||||
Outcome {
|
||||
@@ -165,13 +165,13 @@ impl Engine {
|
||||
|
||||
/// A file as GPX (UTF-8), `None` if it does not exist.
|
||||
pub fn export(&self, id: &FileId, options: ExportOptions) -> Option<Vec<u8>> {
|
||||
let file = self.stack.current()?.get(id)?;
|
||||
let file = self.history.current()?.get(id)?;
|
||||
Some(write(file, &self.categories, options))
|
||||
}
|
||||
|
||||
/// The data that the given files have, which the options of `export` can leave out.
|
||||
pub fn exportable_data(&self, ids: &[FileId]) -> ExportOptions {
|
||||
let Some(files) = self.stack.current() else {
|
||||
let Some(files) = self.history.current() else {
|
||||
return ExportOptions::NONE;
|
||||
};
|
||||
ids.iter()
|
||||
@@ -183,12 +183,12 @@ impl Engine {
|
||||
|
||||
/// Whether there is something to undo.
|
||||
pub fn can_undo(&self) -> bool {
|
||||
self.stack.can_undo()
|
||||
self.history.can_undo()
|
||||
}
|
||||
|
||||
/// Whether there is something to redo.
|
||||
pub fn can_redo(&self) -> bool {
|
||||
self.stack.can_redo()
|
||||
self.history.can_redo()
|
||||
}
|
||||
|
||||
/// Currently selected elements.
|
||||
@@ -216,20 +216,21 @@ impl Engine {
|
||||
// the files change iff there is a diff, but selection and order actions have none
|
||||
let mut diff = match action {
|
||||
Action::Edit(command) => self.edit(command)?,
|
||||
Action::Undo => self.stack.undo(),
|
||||
Action::Redo => self.stack.redo(),
|
||||
Action::Undo => self.history.undo(),
|
||||
Action::Redo => self.history.redo(),
|
||||
Action::Select { selection, mode } => {
|
||||
self.selection.select(self.stack.current(), selection, mode);
|
||||
self.selection
|
||||
.select(self.history.current(), selection, mode);
|
||||
None
|
||||
}
|
||||
Action::SelectAll => {
|
||||
if let Some(files) = self.stack.current() {
|
||||
if let Some(files) = self.history.current() {
|
||||
self.selection.select_all(files, &self.order.0);
|
||||
}
|
||||
None
|
||||
}
|
||||
Action::ArrowSelect { down, add } => {
|
||||
if let Some(files) = self.stack.current() {
|
||||
if let Some(files) = self.history.current() {
|
||||
self.selection
|
||||
.select_neighbour(files, &self.order.0, down, add);
|
||||
}
|
||||
@@ -271,7 +272,7 @@ impl Engine {
|
||||
|
||||
/// Puts the selection in the clipboard, if there is one.
|
||||
fn copy(&mut self, cut: bool) {
|
||||
if let Some(files) = self.stack.current()
|
||||
if let Some(files) = self.history.current()
|
||||
&& let Some(clipboard) = Clipboard::new(&self.selection, files, &self.order.0, cut)
|
||||
{
|
||||
self.clipboard = Some(clipboard);
|
||||
@@ -279,7 +280,7 @@ impl Engine {
|
||||
}
|
||||
|
||||
fn edit(&mut self, command: Command) -> Result<Option<Diff>, CommandError> {
|
||||
self.stack.create_and_push_next(|files| {
|
||||
self.history.create_and_push_next(|files| {
|
||||
let mut state = State {
|
||||
categories: &mut self.categories,
|
||||
files,
|
||||
@@ -291,9 +292,9 @@ impl Engine {
|
||||
})
|
||||
}
|
||||
|
||||
/// Brings everything derived from the files back in line with the current stack entry.
|
||||
/// Brings everything derived from the files back in line with the current history entry.
|
||||
fn refresh(&mut self, diff: Option<&Diff>) {
|
||||
let current = self.stack.current();
|
||||
let current = self.history.current();
|
||||
match current {
|
||||
Some(files) => {
|
||||
// files coming back after an undo/redo are added at the end of the order
|
||||
@@ -319,7 +320,7 @@ impl Engine {
|
||||
}
|
||||
}
|
||||
|
||||
/// Puts the files of a diff in the order of the files (the stack does not know it), so that
|
||||
/// Puts the files of a diff in the order of the files (the history does not know it), so that
|
||||
/// whatever is done with them one after the other, like giving them colors, follows it.
|
||||
fn sort_diff(diff: &mut Option<Diff>, order: &[FileId]) {
|
||||
let position = |id: &FileId| order.iter().position(|other| other == id);
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::rc::Rc;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
File, FileId, Selection, StackEntry, Track, TrackId, TrackSegment, TrackSegmentId, Waypoint,
|
||||
File, FileId, Files, Selection, Track, TrackId, TrackSegment, TrackSegmentId, Waypoint,
|
||||
WaypointId,
|
||||
};
|
||||
|
||||
@@ -71,7 +71,7 @@ impl Clipboard {
|
||||
/// selected does not exist).
|
||||
pub fn new(
|
||||
selection: &Selection,
|
||||
files: &StackEntry,
|
||||
files: &Files,
|
||||
order: &[FileId],
|
||||
cut: bool,
|
||||
) -> Option<Clipboard> {
|
||||
@@ -238,14 +238,14 @@ mod tests {
|
||||
file
|
||||
}
|
||||
|
||||
fn files_of(files: Vec<File>) -> StackEntry {
|
||||
fn files_of(files: Vec<File>) -> Files {
|
||||
files
|
||||
.into_iter()
|
||||
.map(|file| (file.id, Rc::new(file)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn order_of(files: &StackEntry) -> Vec<FileId> {
|
||||
fn order_of(files: &Files) -> Vec<FileId> {
|
||||
files.keys().copied().collect()
|
||||
}
|
||||
|
||||
|
||||
+134
-134
@@ -6,17 +6,17 @@ use std::{
|
||||
use crate::{CommandError, File, FileId};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Stack {
|
||||
entries: Vec<StackEntry>,
|
||||
pub struct History {
|
||||
entries: Vec<Files>,
|
||||
index: Option<usize>,
|
||||
/// Whether the first entry is the state the stack starts from, which is not undone: files
|
||||
/// Whether the first entry is the state the history starts from, which is not undone: files
|
||||
/// restored from the storage.
|
||||
floor: bool,
|
||||
}
|
||||
|
||||
impl Stack {
|
||||
/// A stack whose first entry is `entry`, from which nothing can be undone.
|
||||
pub fn restored(entry: StackEntry) -> Self {
|
||||
impl History {
|
||||
/// A history whose first entry is `entry`, from which nothing can be undone.
|
||||
pub fn restored(entry: Files) -> Self {
|
||||
Self {
|
||||
entries: vec![entry],
|
||||
index: Some(0),
|
||||
@@ -24,7 +24,7 @@ impl Stack {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn current(&self) -> Option<&StackEntry> {
|
||||
pub fn current(&self) -> Option<&Files> {
|
||||
self.index.map_or_default(|i| self.get(i))
|
||||
}
|
||||
|
||||
@@ -35,18 +35,18 @@ impl Stack {
|
||||
/// history. Files are told apart by their identity, not their content.
|
||||
pub fn create_and_push_next<F>(&mut self, f: F) -> Result<Option<Diff>, CommandError>
|
||||
where
|
||||
F: FnOnce(&mut StackEntry) -> Result<(), CommandError>,
|
||||
F: FnOnce(&mut Files) -> Result<(), CommandError>,
|
||||
{
|
||||
let mut next = self.current().map_or_default(|c| c.clone());
|
||||
f(&mut next)?;
|
||||
if self.is_current(&next) {
|
||||
return Ok(None);
|
||||
}
|
||||
Ok(self.record_diff(|stack| stack.push(next)))
|
||||
Ok(self.record_diff(|history| history.push(next)))
|
||||
}
|
||||
|
||||
/// Whether `entry` holds exactly the files of the current entry.
|
||||
fn is_current(&self, entry: &StackEntry) -> bool {
|
||||
fn is_current(&self, entry: &Files) -> bool {
|
||||
let current = self.current();
|
||||
let len = current.map_or(0, |current| current.len());
|
||||
entry.len() == len
|
||||
@@ -58,29 +58,29 @@ impl Stack {
|
||||
}
|
||||
|
||||
pub fn undo(&mut self) -> Option<Diff> {
|
||||
self.record_diff(|stack| {
|
||||
if let Some(i) = stack.index {
|
||||
self.record_diff(|history| {
|
||||
if let Some(i) = history.index {
|
||||
if i == 0 {
|
||||
if !stack.floor {
|
||||
stack.index = None;
|
||||
if !history.floor {
|
||||
history.index = None;
|
||||
}
|
||||
} else {
|
||||
stack.index = Some(i - 1);
|
||||
history.index = Some(i - 1);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn redo(&mut self) -> Option<Diff> {
|
||||
self.record_diff(|stack| match stack.index {
|
||||
self.record_diff(|history| match history.index {
|
||||
Some(i) => {
|
||||
if i + 1 < stack.entries.len() {
|
||||
stack.index = Some(i + 1);
|
||||
if i + 1 < history.entries.len() {
|
||||
history.index = Some(i + 1);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if !stack.entries.is_empty() {
|
||||
stack.index = Some(0);
|
||||
if !history.entries.is_empty() {
|
||||
history.index = Some(0);
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -97,11 +97,11 @@ impl Stack {
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self, index: usize) -> Option<&StackEntry> {
|
||||
fn get(&self, index: usize) -> Option<&Files> {
|
||||
self.entries.get(index)
|
||||
}
|
||||
|
||||
fn push(&mut self, entry: StackEntry) {
|
||||
fn push(&mut self, entry: Files) {
|
||||
if let Some(i) = self.index {
|
||||
self.entries.truncate(i + 1);
|
||||
}
|
||||
@@ -127,7 +127,7 @@ impl Stack {
|
||||
}
|
||||
|
||||
/// Which files differ between two states.
|
||||
pub fn diff_between(prev: Option<&StackEntry>, cur: Option<&StackEntry>) -> Diff {
|
||||
pub fn diff_between(prev: Option<&Files>, cur: Option<&Files>) -> Diff {
|
||||
let prev_ids: HashSet<FileId> = prev.map_or_default(|e| e.keys().copied().collect());
|
||||
let cur_ids: HashSet<FileId> = cur.map_or_default(|e| e.keys().copied().collect());
|
||||
let mut modified = vec![];
|
||||
@@ -146,9 +146,9 @@ impl Stack {
|
||||
}
|
||||
}
|
||||
|
||||
pub type StackEntry = HashMap<FileId, Rc<File>>;
|
||||
pub type Files = HashMap<FileId, Rc<File>>;
|
||||
|
||||
/// Which files were added, removed or modified by a change of the current stack entry.
|
||||
/// Which files were added, removed or modified by a change of the current history entry.
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
pub struct Diff {
|
||||
pub added: Vec<FileId>,
|
||||
@@ -160,11 +160,11 @@ pub struct Diff {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
impl Stack {
|
||||
impl History {
|
||||
/// A step that is expected not to fail.
|
||||
fn push_ok(
|
||||
&mut self,
|
||||
f: impl FnOnce(&mut StackEntry) -> Result<(), CommandError>,
|
||||
f: impl FnOnce(&mut Files) -> Result<(), CommandError>,
|
||||
) -> Option<Diff> {
|
||||
self.create_and_push_next(f).unwrap()
|
||||
}
|
||||
@@ -172,21 +172,21 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_new_file() {
|
||||
let mut stack = Stack::default();
|
||||
let mut history = History::default();
|
||||
|
||||
assert!(!stack.can_undo());
|
||||
assert!(!stack.can_redo());
|
||||
assert!(stack.current().is_none());
|
||||
assert!(!history.can_undo());
|
||||
assert!(!history.can_redo());
|
||||
assert!(history.current().is_none());
|
||||
|
||||
let diff = stack.push_ok(|e| {
|
||||
let diff = history.push_ok(|e| {
|
||||
let file = Rc::new(File::default());
|
||||
e.insert(file.id, file);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
assert!(stack.can_undo());
|
||||
assert!(!stack.can_redo());
|
||||
assert!(stack.current().is_some());
|
||||
assert!(history.can_undo());
|
||||
assert!(!history.can_redo());
|
||||
assert!(history.current().is_some());
|
||||
|
||||
assert!(diff.is_some());
|
||||
|
||||
@@ -196,10 +196,10 @@ mod tests {
|
||||
assert!(diff.modified.is_empty());
|
||||
}
|
||||
|
||||
fn add_file(stack: &mut Stack) -> FileId {
|
||||
fn add_file(history: &mut History) -> FileId {
|
||||
let file = Rc::new(File::default());
|
||||
let id = file.id;
|
||||
stack
|
||||
history
|
||||
.push_ok(|e| {
|
||||
e.insert(id, file);
|
||||
Ok(())
|
||||
@@ -210,46 +210,46 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_failed_command_pushes_nothing() {
|
||||
let mut stack = Stack::default();
|
||||
let diff = stack.create_and_push_next(|e| {
|
||||
let mut history = History::default();
|
||||
let diff = history.create_and_push_next(|e| {
|
||||
e.insert(FileId::default(), Rc::new(File::default()));
|
||||
Err(CommandError::InvalidData("nope".to_string()))
|
||||
});
|
||||
assert_eq!(diff, Err(CommandError::InvalidData("nope".to_string())));
|
||||
assert!(!stack.can_undo());
|
||||
assert!(stack.current().is_none());
|
||||
assert!(!history.can_undo());
|
||||
assert!(history.current().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_undo_redo() {
|
||||
let mut stack = Stack::default();
|
||||
assert!(stack.undo().is_none());
|
||||
assert!(stack.redo().is_none());
|
||||
let mut history = History::default();
|
||||
assert!(history.undo().is_none());
|
||||
assert!(history.redo().is_none());
|
||||
|
||||
let id = add_file(&mut stack);
|
||||
let id = add_file(&mut history);
|
||||
|
||||
let diff = stack.undo().unwrap();
|
||||
let diff = history.undo().unwrap();
|
||||
assert_eq!(diff.removed, vec![id]);
|
||||
assert!(diff.added.is_empty());
|
||||
assert!(stack.current().is_none());
|
||||
assert!(!stack.can_undo());
|
||||
assert!(stack.can_redo());
|
||||
assert!(stack.undo().is_none());
|
||||
assert!(history.current().is_none());
|
||||
assert!(!history.can_undo());
|
||||
assert!(history.can_redo());
|
||||
assert!(history.undo().is_none());
|
||||
|
||||
let diff = stack.redo().unwrap();
|
||||
let diff = history.redo().unwrap();
|
||||
assert_eq!(diff.added, vec![id]);
|
||||
assert!(stack.current().unwrap().contains_key(&id));
|
||||
assert!(stack.can_undo());
|
||||
assert!(!stack.can_redo());
|
||||
assert!(stack.redo().is_none());
|
||||
assert!(history.current().unwrap().contains_key(&id));
|
||||
assert!(history.can_undo());
|
||||
assert!(!history.can_redo());
|
||||
assert!(history.redo().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_modified_and_removed() {
|
||||
let mut stack = Stack::default();
|
||||
let id = add_file(&mut stack);
|
||||
let mut history = History::default();
|
||||
let id = add_file(&mut history);
|
||||
|
||||
let diff = stack
|
||||
let diff = history
|
||||
.push_ok(|e| {
|
||||
let mut file = (**e.get(&id).unwrap()).clone();
|
||||
file.info.name = "renamed".to_string();
|
||||
@@ -261,9 +261,9 @@ mod tests {
|
||||
assert!(diff.added.is_empty() && diff.removed.is_empty());
|
||||
|
||||
// a step that changes nothing is not a step
|
||||
assert!(stack.push_ok(|_| Ok(())).is_none());
|
||||
assert!(history.push_ok(|_| Ok(())).is_none());
|
||||
assert!(
|
||||
stack
|
||||
history
|
||||
.push_ok(|e| {
|
||||
let file = e[&id].clone();
|
||||
e.insert(id, file);
|
||||
@@ -272,28 +272,28 @@ mod tests {
|
||||
.is_none()
|
||||
);
|
||||
|
||||
let diff = stack
|
||||
let diff = history
|
||||
.push_ok(|e| {
|
||||
e.remove(&id);
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(diff.removed, vec![id]);
|
||||
assert!(stack.current().unwrap().is_empty());
|
||||
assert!(history.current().unwrap().is_empty());
|
||||
|
||||
// going back restores the renamed file
|
||||
stack.undo();
|
||||
assert_eq!(stack.current().unwrap()[&id].info.name, "renamed");
|
||||
history.undo();
|
||||
assert_eq!(history.current().unwrap()[&id].info.name, "renamed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_a_file_is_modified_when_it_is_not_the_same_one_anymore() {
|
||||
let mut stack = Stack::default();
|
||||
let id = add_file(&mut stack);
|
||||
let mut history = History::default();
|
||||
let id = add_file(&mut history);
|
||||
|
||||
// a copy, even if it has the same content, is another file for the stack: files are
|
||||
// a copy, even if it has the same content, is another file for the history: files are
|
||||
// told apart by their identity, comparing them would read all of them
|
||||
let diff = stack
|
||||
let diff = history
|
||||
.push_ok(|e| {
|
||||
let copy = (**e.get(&id).unwrap()).clone();
|
||||
e.insert(id, Rc::new(copy));
|
||||
@@ -303,8 +303,8 @@ mod tests {
|
||||
assert_eq!(diff.modified, vec![id]);
|
||||
|
||||
// and the files that were not replaced are not
|
||||
let other = add_file(&mut stack);
|
||||
let diff = stack
|
||||
let other = add_file(&mut history);
|
||||
let diff = history
|
||||
.push_ok(|e| {
|
||||
let copy = (**e.get(&other).unwrap()).clone();
|
||||
e.insert(other, Rc::new(copy));
|
||||
@@ -316,120 +316,120 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_push_after_undo_drops_redo_branch() {
|
||||
let mut stack = Stack::default();
|
||||
let first = add_file(&mut stack);
|
||||
let second = add_file(&mut stack);
|
||||
let mut history = History::default();
|
||||
let first = add_file(&mut history);
|
||||
let second = add_file(&mut history);
|
||||
|
||||
stack.undo();
|
||||
assert!(stack.can_redo());
|
||||
assert!(!stack.current().unwrap().contains_key(&second));
|
||||
history.undo();
|
||||
assert!(history.can_redo());
|
||||
assert!(!history.current().unwrap().contains_key(&second));
|
||||
|
||||
let third = add_file(&mut stack);
|
||||
assert!(!stack.can_redo());
|
||||
assert!(stack.redo().is_none());
|
||||
let current = stack.current().unwrap();
|
||||
let third = add_file(&mut history);
|
||||
assert!(!history.can_redo());
|
||||
assert!(history.redo().is_none());
|
||||
let current = history.current().unwrap();
|
||||
assert!(current.contains_key(&first));
|
||||
assert!(current.contains_key(&third));
|
||||
assert!(!current.contains_key(&second));
|
||||
}
|
||||
|
||||
fn restored_entry() -> (StackEntry, FileId) {
|
||||
fn restored_entry() -> (Files, FileId) {
|
||||
let file = Rc::new(File::default());
|
||||
let id = file.id;
|
||||
(StackEntry::from([(id, file)]), id)
|
||||
(Files::from([(id, file)]), id)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_restored_stack_starts_from_its_entry() {
|
||||
fn test_restored_history_starts_from_its_entry() {
|
||||
let (entry, id) = restored_entry();
|
||||
let mut stack = Stack::restored(entry);
|
||||
let mut history = History::restored(entry);
|
||||
|
||||
assert!(stack.current().unwrap().contains_key(&id));
|
||||
assert!(history.current().unwrap().contains_key(&id));
|
||||
// there is nothing to go back to, nor forward to
|
||||
assert!(!stack.can_undo());
|
||||
assert!(!stack.can_redo());
|
||||
assert!(stack.undo().is_none());
|
||||
assert!(stack.redo().is_none());
|
||||
assert!(stack.current().unwrap().contains_key(&id));
|
||||
assert!(!history.can_undo());
|
||||
assert!(!history.can_redo());
|
||||
assert!(history.undo().is_none());
|
||||
assert!(history.redo().is_none());
|
||||
assert!(history.current().unwrap().contains_key(&id));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_restored_stack_cannot_undo_an_empty_entry_either() {
|
||||
let mut stack = Stack::restored(StackEntry::new());
|
||||
fn test_restored_history_cannot_undo_an_empty_entry_either() {
|
||||
let mut history = History::restored(Files::new());
|
||||
|
||||
assert!(stack.current().is_some_and(|files| files.is_empty()));
|
||||
assert!(!stack.can_undo());
|
||||
assert!(stack.undo().is_none());
|
||||
// the stack is not the one of an engine that has done nothing
|
||||
assert!(stack.current().is_some());
|
||||
assert!(history.current().is_some_and(|files| files.is_empty()));
|
||||
assert!(!history.can_undo());
|
||||
assert!(history.undo().is_none());
|
||||
// the history is not the one of an engine that has done nothing
|
||||
assert!(history.current().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_restored_stack_undoes_what_comes_after_it_and_no_further() {
|
||||
fn test_restored_history_undoes_what_comes_after_it_and_no_further() {
|
||||
let (entry, restored) = restored_entry();
|
||||
let mut stack = Stack::restored(entry);
|
||||
let mut history = History::restored(entry);
|
||||
|
||||
let added = add_file(&mut stack);
|
||||
assert!(stack.can_undo());
|
||||
assert!(!stack.can_redo());
|
||||
assert_eq!(stack.current().unwrap().len(), 2);
|
||||
let added = add_file(&mut history);
|
||||
assert!(history.can_undo());
|
||||
assert!(!history.can_redo());
|
||||
assert_eq!(history.current().unwrap().len(), 2);
|
||||
|
||||
// back to the restored files
|
||||
let diff = stack.undo().unwrap();
|
||||
let diff = history.undo().unwrap();
|
||||
assert_eq!(diff.removed, vec![added]);
|
||||
assert!(diff.added.is_empty() && diff.modified.is_empty());
|
||||
assert_eq!(stack.current().unwrap().len(), 1);
|
||||
assert!(stack.current().unwrap().contains_key(&restored));
|
||||
assert!(!stack.can_undo());
|
||||
assert!(stack.can_redo());
|
||||
assert!(stack.undo().is_none());
|
||||
assert!(stack.current().unwrap().contains_key(&restored));
|
||||
assert_eq!(history.current().unwrap().len(), 1);
|
||||
assert!(history.current().unwrap().contains_key(&restored));
|
||||
assert!(!history.can_undo());
|
||||
assert!(history.can_redo());
|
||||
assert!(history.undo().is_none());
|
||||
assert!(history.current().unwrap().contains_key(&restored));
|
||||
|
||||
let diff = stack.redo().unwrap();
|
||||
let diff = history.redo().unwrap();
|
||||
assert_eq!(diff.added, vec![added]);
|
||||
assert!(stack.can_undo());
|
||||
assert!(!stack.can_redo());
|
||||
assert!(history.can_undo());
|
||||
assert!(!history.can_redo());
|
||||
|
||||
// and again
|
||||
assert!(stack.undo().is_some());
|
||||
assert!(stack.undo().is_none());
|
||||
assert!(stack.current().unwrap().contains_key(&restored));
|
||||
assert!(history.undo().is_some());
|
||||
assert!(history.undo().is_none());
|
||||
assert!(history.current().unwrap().contains_key(&restored));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_restored_stack_removing_its_files_can_be_undone() {
|
||||
fn test_restored_history_removing_its_files_can_be_undone() {
|
||||
let (entry, restored) = restored_entry();
|
||||
let mut stack = Stack::restored(entry);
|
||||
let mut history = History::restored(entry);
|
||||
|
||||
let diff = stack
|
||||
let diff = history
|
||||
.push_ok(|e| {
|
||||
e.remove(&restored);
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(diff.removed, vec![restored]);
|
||||
assert!(stack.current().unwrap().is_empty());
|
||||
assert!(history.current().unwrap().is_empty());
|
||||
|
||||
let diff = stack.undo().unwrap();
|
||||
let diff = history.undo().unwrap();
|
||||
assert_eq!(diff.added, vec![restored]);
|
||||
assert!(stack.current().unwrap().contains_key(&restored));
|
||||
assert!(!stack.can_undo());
|
||||
assert!(history.current().unwrap().contains_key(&restored));
|
||||
assert!(!history.can_undo());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_restored_stack_push_after_undo_drops_redo_branch() {
|
||||
fn test_restored_history_push_after_undo_drops_redo_branch() {
|
||||
let (entry, restored) = restored_entry();
|
||||
let mut stack = Stack::restored(entry);
|
||||
add_file(&mut stack);
|
||||
stack.undo().unwrap();
|
||||
assert!(stack.can_redo());
|
||||
let mut history = History::restored(entry);
|
||||
add_file(&mut history);
|
||||
history.undo().unwrap();
|
||||
assert!(history.can_redo());
|
||||
|
||||
let other = add_file(&mut stack);
|
||||
assert!(!stack.can_redo());
|
||||
assert!(stack.can_undo());
|
||||
let diff = stack.undo().unwrap();
|
||||
let other = add_file(&mut history);
|
||||
assert!(!history.can_redo());
|
||||
assert!(history.can_undo());
|
||||
let diff = history.undo().unwrap();
|
||||
assert_eq!(diff.removed, vec![other]);
|
||||
assert!(stack.current().unwrap().contains_key(&restored));
|
||||
assert!(!stack.can_undo());
|
||||
assert!(history.current().unwrap().contains_key(&restored));
|
||||
assert!(!history.can_undo());
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
mod clipboard;
|
||||
mod history;
|
||||
mod order;
|
||||
mod selection;
|
||||
mod stack;
|
||||
|
||||
pub use clipboard::*;
|
||||
pub use history::*;
|
||||
pub use order::*;
|
||||
pub use selection::*;
|
||||
pub use stack::*;
|
||||
|
||||
pub struct State<'a> {
|
||||
pub categories: &'a mut crate::TrackpointCategories,
|
||||
pub files: &'a mut StackEntry,
|
||||
pub files: &'a mut Files,
|
||||
pub selection: &'a mut Selection,
|
||||
pub order: &'a mut FileOrder,
|
||||
pub clipboard: &'a mut Option<Clipboard>,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::{FileId, StackEntry as Files};
|
||||
use crate::{FileId, Files};
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
pub struct FileOrder(pub Vec<FileId>);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::{FileId, StackEntry, TrackId, TrackSegmentId, WaypointId};
|
||||
use crate::{FileId, Files, TrackId, TrackSegmentId, WaypointId};
|
||||
|
||||
/// How a new selection combines with the current one.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -52,12 +52,7 @@ impl Selection {
|
||||
/// Combines `selection` with this one according to `mode`, ignoring the elements of
|
||||
/// `selection` that do not exist in `files`. Nothing to add or toggle leaves the selection
|
||||
/// as it is, while replacing it with nothing deselects everything.
|
||||
pub fn select(
|
||||
&mut self,
|
||||
files: Option<&StackEntry>,
|
||||
mut selection: Selection,
|
||||
mode: SelectMode,
|
||||
) {
|
||||
pub fn select(&mut self, files: Option<&Files>, mut selection: Selection, mode: SelectMode) {
|
||||
match files {
|
||||
Some(files) => selection.retain_existing(files),
|
||||
None => selection = Selection::Empty,
|
||||
@@ -72,7 +67,7 @@ impl Selection {
|
||||
|
||||
/// Selects all the elements of the same kind as the selected ones, see
|
||||
/// [`Selection::all_at_level`]. Does nothing when there is nothing more to select.
|
||||
pub fn select_all(&mut self, files: &StackEntry, order: &[FileId]) {
|
||||
pub fn select_all(&mut self, files: &Files, order: &[FileId]) {
|
||||
if let Some(all) = self.all_at_level(files, order) {
|
||||
*self = all;
|
||||
}
|
||||
@@ -81,13 +76,7 @@ impl Selection {
|
||||
/// Moves the selection to the next (`down`) or previous element, see
|
||||
/// [`Selection::neighbour`]. With `add`, the element is added to the selection instead of
|
||||
/// replacing it.
|
||||
pub fn select_neighbour(
|
||||
&mut self,
|
||||
files: &StackEntry,
|
||||
order: &[FileId],
|
||||
down: bool,
|
||||
add: bool,
|
||||
) {
|
||||
pub fn select_neighbour(&mut self, files: &Files, order: &[FileId], down: bool, add: bool) {
|
||||
if let Some(next) = self.neighbour(files, order, down) {
|
||||
if add {
|
||||
self.extend(next);
|
||||
@@ -102,7 +91,7 @@ impl Selection {
|
||||
/// The track segments covered by the selection, in order: the segments of several selected
|
||||
/// files follow `order` (the files missing from it come last), then the tracks and segments
|
||||
/// follow the file. Waypoints are not segments: selecting only waypoints covers none.
|
||||
pub fn segment_locations(&self, files: &StackEntry, order: &[FileId]) -> Vec<SegmentLocation> {
|
||||
pub fn segment_locations(&self, files: &Files, order: &[FileId]) -> Vec<SegmentLocation> {
|
||||
let mut locations = vec![];
|
||||
let mut add = |file_id: FileId,
|
||||
trk_filter: &dyn Fn(&crate::Track) -> bool,
|
||||
@@ -145,7 +134,7 @@ impl Selection {
|
||||
|
||||
/// Drops what does not exist anymore (e.g. after an undo): files, and the tracks, segments
|
||||
/// and waypoints of the files that remain. A selection left with nothing becomes empty.
|
||||
pub fn retain_existing(&mut self, files: &StackEntry) {
|
||||
pub fn retain_existing(&mut self, files: &Files) {
|
||||
let empty = match self {
|
||||
Selection::Empty => false,
|
||||
Selection::File { file_ids } => {
|
||||
@@ -340,7 +329,7 @@ impl Selection {
|
||||
/// the files, all the tracks of the file, all the segments of the track, all the waypoints
|
||||
/// of the file. All the files when nothing is selected. `None` when there is nothing to
|
||||
/// select (the waypoints node, or a file that does not exist).
|
||||
pub fn all_at_level(&self, files: &StackEntry, order: &[FileId]) -> Option<Selection> {
|
||||
pub fn all_at_level(&self, files: &Files, order: &[FileId]) -> Option<Selection> {
|
||||
match self {
|
||||
Selection::Empty | Selection::File { .. } => Some(Selection::File {
|
||||
file_ids: order.iter().copied().collect(),
|
||||
@@ -375,7 +364,7 @@ impl Selection {
|
||||
/// (`down`) or the previous one among the elements of the same kind, in the same place.
|
||||
/// The tracks, segments and waypoints stop at their ends, the files wrap around and skip
|
||||
/// the ones that are already selected. `None` when there is no such element.
|
||||
pub fn neighbour(&self, files: &StackEntry, order: &[FileId], down: bool) -> Option<Selection> {
|
||||
pub fn neighbour(&self, files: &Files, order: &[FileId], down: bool) -> Option<Selection> {
|
||||
match self {
|
||||
Selection::Empty | Selection::Waypoints { .. } => None,
|
||||
Selection::File { file_ids } => {
|
||||
@@ -443,7 +432,7 @@ mod tests {
|
||||
fn test_retain_existing() {
|
||||
let file = File::default();
|
||||
let (kept, gone) = (file.id, FileId::default());
|
||||
let mut files = StackEntry::default();
|
||||
let mut files = Files::default();
|
||||
files.insert(kept, Rc::new(file));
|
||||
|
||||
let mut selection = Selection::File {
|
||||
@@ -481,7 +470,7 @@ mod tests {
|
||||
});
|
||||
let (file_id, trk_id) = (file.id, file.trk[0].id);
|
||||
let (seg_id, wpt_id) = (file.trk[0].trkseg[0].id, file.wpt[0].id);
|
||||
let mut files = StackEntry::default();
|
||||
let mut files = Files::default();
|
||||
files.insert(file_id, Rc::new(file));
|
||||
|
||||
let mut selection = Selection::Track {
|
||||
@@ -610,7 +599,7 @@ mod tests {
|
||||
|
||||
/// A file with 3 tracks of 2 segments each and 3 waypoints, with the ids of everything.
|
||||
struct Tree {
|
||||
files: StackEntry,
|
||||
files: Files,
|
||||
order: Vec<FileId>,
|
||||
file: FileId,
|
||||
tracks: Vec<TrackId>,
|
||||
@@ -644,7 +633,7 @@ mod tests {
|
||||
.collect(),
|
||||
waypoints: file.wpt.iter().map(|w| w.id).collect(),
|
||||
order: vec![file.id],
|
||||
files: StackEntry::from([(file.id, Rc::new(file))]),
|
||||
files: Files::from([(file.id, Rc::new(file))]),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -772,7 +761,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_neighbour_of_files_wraps_around_and_skips_the_selected() {
|
||||
let files = StackEntry::default();
|
||||
let files = Files::default();
|
||||
let [a, b, c] = [FileId::default(), FileId::default(), FileId::default()];
|
||||
let order = [a, b, c];
|
||||
let select = |ids: &[FileId]| Selection::File {
|
||||
|
||||
@@ -120,7 +120,7 @@ fn test_load_file() {
|
||||
fn test_new_file_has_no_statistics() {
|
||||
let mut engine = TestEngine::default();
|
||||
assert!(new(&mut engine, "empty"));
|
||||
assert_eq!(engine.stack.current().unwrap().len(), 1);
|
||||
assert_eq!(engine.history.current().unwrap().len(), 1);
|
||||
assert_eq!(engine.order.0.len(), 1);
|
||||
assert!(engine.statistics().total_distance.is_empty());
|
||||
}
|
||||
@@ -135,7 +135,7 @@ fn test_statistics_follow_selection() {
|
||||
// a newly created (empty) file becomes the selection
|
||||
assert!(new(&mut engine, "empty"));
|
||||
assert!(engine.statistics().total_distance.is_empty());
|
||||
assert_eq!(engine.stack.current().unwrap().len(), 2);
|
||||
assert_eq!(engine.history.current().unwrap().len(), 2);
|
||||
|
||||
// loading a file selects it again
|
||||
assert!(load(&mut engine, "data/simple.gpx"));
|
||||
@@ -152,8 +152,8 @@ fn test_invalid_load_is_rejected() {
|
||||
name: "file",
|
||||
})
|
||||
));
|
||||
assert!(engine.stack.current().is_none());
|
||||
assert!(!engine.stack.can_undo());
|
||||
assert!(engine.history.current().is_none());
|
||||
assert!(!engine.history.can_undo());
|
||||
assert!(engine.order.0.is_empty());
|
||||
}
|
||||
|
||||
@@ -162,8 +162,8 @@ fn test_command_with_nothing_to_do_is_rejected() {
|
||||
let mut engine = TestEngine::default();
|
||||
new(&mut engine, "file");
|
||||
assert!(!edit(&mut engine, Command::Reverse(crate::Reverse)));
|
||||
assert!(!engine.stack.can_redo());
|
||||
assert_eq!(engine.stack.current().unwrap().len(), 1);
|
||||
assert!(!engine.history.can_redo());
|
||||
assert_eq!(engine.history.current().unwrap().len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -177,7 +177,7 @@ fn test_metadata_renames_selected_file() {
|
||||
desc: "about",
|
||||
})
|
||||
));
|
||||
let file = engine.stack.current().unwrap().values().next().unwrap();
|
||||
let file = engine.history.current().unwrap().values().next().unwrap();
|
||||
assert_eq!(file.info.name, "after");
|
||||
assert_eq!(file.info.desc.as_deref(), Some("about"));
|
||||
}
|
||||
@@ -194,7 +194,7 @@ fn test_metadata_without_selection_does_not_modify_files() {
|
||||
desc: "",
|
||||
}),
|
||||
);
|
||||
let file = engine.stack.current().unwrap().values().next().unwrap();
|
||||
let file = engine.history.current().unwrap().values().next().unwrap();
|
||||
assert_eq!(file.info.name, "file");
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ fn test_edit_changes_statistics_when_segments_change() {
|
||||
load(&mut engine, "data/simple.gpx");
|
||||
let before = engine
|
||||
.statistics_cache
|
||||
.get(engine.stack.current(), &engine.selection)[0] as *const _;
|
||||
.get(engine.history.current(), &engine.selection)[0] as *const _;
|
||||
edit(&mut engine, Command::NewTrack(NewTrack));
|
||||
edit(
|
||||
&mut engine,
|
||||
@@ -217,7 +217,7 @@ fn test_edit_changes_statistics_when_segments_change() {
|
||||
// styling does not touch the segments: their statistics are reused
|
||||
let after = engine
|
||||
.statistics_cache
|
||||
.get(engine.stack.current(), &engine.selection)[0] as *const _;
|
||||
.get(engine.history.current(), &engine.selection)[0] as *const _;
|
||||
assert!(std::ptr::eq(before, after));
|
||||
}
|
||||
|
||||
@@ -241,7 +241,7 @@ fn test_undo_redo_keep_selection_and_order_consistent() {
|
||||
assert!(engine.run(Action::Undo));
|
||||
assert!(engine.order.0.is_empty());
|
||||
assert!(!engine.run(Action::Undo));
|
||||
assert!(engine.stack.current().is_none());
|
||||
assert!(engine.history.current().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -381,7 +381,7 @@ fn test_selection_does_not_create_undo_steps() {
|
||||
new(&mut engine, "a");
|
||||
select_all(&mut engine);
|
||||
engine.run(Action::Undo);
|
||||
assert!(engine.stack.current().is_none());
|
||||
assert!(engine.history.current().is_none());
|
||||
}
|
||||
|
||||
fn select_elements(engine: &mut TestEngine, selection: Selection, mode: SelectMode) -> bool {
|
||||
@@ -408,7 +408,7 @@ fn test_select_elements() {
|
||||
let mut engine = TestEngine::default();
|
||||
load(&mut engine, "data/with_tracks_and_segments.gpx");
|
||||
let file = engine
|
||||
.stack
|
||||
.history
|
||||
.current()
|
||||
.unwrap()
|
||||
.values()
|
||||
@@ -507,7 +507,7 @@ fn test_toggle_elements() {
|
||||
let mut engine = TestEngine::default();
|
||||
load(&mut engine, "data/with_tracks_and_segments.gpx");
|
||||
let file = engine
|
||||
.stack
|
||||
.history
|
||||
.current()
|
||||
.unwrap()
|
||||
.values()
|
||||
@@ -541,7 +541,7 @@ fn test_selected_elements_are_dropped_when_they_disappear() {
|
||||
let mut engine = TestEngine::default();
|
||||
load(&mut engine, "data/with_tracks_and_segments.gpx");
|
||||
let file = engine
|
||||
.stack
|
||||
.history
|
||||
.current()
|
||||
.unwrap()
|
||||
.values()
|
||||
@@ -597,7 +597,7 @@ fn test_select_all_follows_the_selected_level() {
|
||||
let load = |engine: &mut TestEngine| load(engine, "data/with_tracks_and_segments.gpx");
|
||||
load(&mut engine);
|
||||
let file = engine
|
||||
.stack
|
||||
.history
|
||||
.current()
|
||||
.unwrap()
|
||||
.values()
|
||||
@@ -648,7 +648,7 @@ fn test_arrow_select() {
|
||||
edit(&mut engine, Command::NewTrack(NewTrack));
|
||||
}
|
||||
let file = engine
|
||||
.stack
|
||||
.history
|
||||
.current()
|
||||
.unwrap()
|
||||
.values()
|
||||
@@ -1153,7 +1153,7 @@ fn test_export_writes_the_file_as_it_is() {
|
||||
let id = engine.order()[0];
|
||||
let bytes = engine.export(&id, ExportOptions::ALL).unwrap();
|
||||
let again = crate::parse(&bytes, &mut engine.categories().clone()).unwrap();
|
||||
let file = engine.stack.current().unwrap()[&id].clone();
|
||||
let file = engine.history.current().unwrap()[&id].clone();
|
||||
assert_eq!(again.trk.len(), file.trk.len());
|
||||
assert_eq!(again.trk[0].trkseg[0].len(), file.trk[0].trkseg[0].len());
|
||||
assert!(again.trk[0].trkseg[0][0].time.is_some());
|
||||
|
||||
@@ -9,7 +9,7 @@ use super::codec::{
|
||||
encode_order, encode_trackpoints, encode_waypoints,
|
||||
};
|
||||
use crate::{
|
||||
Batch, ChunkKey, CommitError, File, FileId, Revision, StackEntry, Storage, StorageError,
|
||||
Batch, ChunkKey, CommitError, File, FileId, Files, Revision, Storage, StorageError,
|
||||
TrackpointCategories, TrackpointChunk, WaypointChunk,
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ use crate::{
|
||||
/// categories their trackpoints refer to. See [`crate::Engine::snapshot`].
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct Snapshot {
|
||||
pub files: StackEntry,
|
||||
pub files: Files,
|
||||
pub order: Vec<FileId>,
|
||||
pub categories: TrackpointCategories,
|
||||
}
|
||||
@@ -533,7 +533,11 @@ mod tests {
|
||||
changed.order.clear();
|
||||
changed.files.clear();
|
||||
let result = block_on(persister.save(&storage, changed));
|
||||
assert_eq!(result, Err(CommitError::Failed(StorageError::Newer)), "{what}");
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(CommitError::Failed(StorageError::Newer)),
|
||||
"{what}"
|
||||
);
|
||||
assert!(storage.batches.borrow().is_empty(), "{what}");
|
||||
assert_eq!(storage.inner.counts(), before, "{what}");
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user