mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-11-15 07:07:07 +00:00
Compare commits
164
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d878fb0e1 | ||
|
|
972510bfbc | ||
|
|
46563ef283 | ||
|
|
c778766293 | ||
|
|
fbd8775528 | ||
|
|
b3fe640575 | ||
|
|
c3ace59527 | ||
|
|
50348e7c5c | ||
|
|
c3ce577e6d | ||
|
|
957f0c35ec | ||
|
|
fbfdc1933c | ||
|
|
6956c19410 | ||
|
|
f5a2db0565 | ||
|
|
39454f0b83 | ||
|
|
68eacc76d1 | ||
|
|
603b73b99d | ||
|
|
3f8e2a0c56 | ||
|
|
45f877ec78 | ||
|
|
0f957fb1f2 | ||
|
|
764d0b233a | ||
|
|
b6c0f5190a | ||
|
|
c842da8dc1 | ||
|
|
5bc35f30d9 | ||
|
|
873e2e1654 | ||
|
|
6c2d2879f4 | ||
|
|
f5670cdd8e | ||
|
|
741d35db1e | ||
|
|
6556c29492 | ||
|
|
7fa850e4c8 | ||
|
|
f9e8d4c644 | ||
|
|
a07da16163 | ||
|
|
4583874e7e | ||
|
|
48325e6016 | ||
|
|
9033401094 | ||
|
|
b64c192c4f | ||
|
|
9dd4af98a5 | ||
|
|
05510ece92 | ||
|
|
8bbcbdc097 | ||
|
|
3012f6bf73 | ||
|
|
5373d0f0d4 | ||
|
|
8fd47d8b18 | ||
|
|
a5c1f6ad33 | ||
|
|
3ef2bf135a | ||
|
|
adbf89e318 | ||
|
|
11709316d2 | ||
|
|
d52b61f707 | ||
|
|
358253b7a9 | ||
|
|
8d6885d58b | ||
|
|
128338aa05 | ||
|
|
c84e1c9a06 | ||
|
|
9f49119eec | ||
|
|
67a47cf065 | ||
|
|
e57949dc01 | ||
|
|
da92fd15d2 | ||
|
|
01443943b3 | ||
|
|
970cf7d1e1 | ||
|
|
593b43e433 | ||
|
|
8fa88680b3 | ||
|
|
b2495d1466 | ||
|
|
ed90ba6a1f | ||
|
|
b0a3c3a9ba | ||
|
|
005cc7b305 | ||
|
|
1bfd319758 | ||
|
|
187296a277 | ||
|
|
55a8b020e0 | ||
|
|
1ba5436af3 | ||
|
|
2e1ca00afa | ||
|
|
97d597e139 | ||
|
|
41b9116c6a | ||
|
|
ce8398f749 | ||
|
|
3c2055b50e | ||
|
|
1d13972014 | ||
|
|
890bcd765a | ||
|
|
4795513344 | ||
|
|
d84ca47745 | ||
|
|
9adb8e7221 | ||
|
|
a2b4d89150 | ||
|
|
77929cfa04 | ||
|
|
dc36de2a48 | ||
|
|
da9abbae5e | ||
|
|
3bb553d6b5 | ||
|
|
83b76bb838 | ||
|
|
42a55e6759 | ||
|
|
b085a1d476 | ||
|
|
840e943626 | ||
|
|
16e2e0f679 | ||
|
|
0f9557ea82 | ||
|
|
67a4c090bd | ||
|
|
606a0e974a | ||
|
|
e8c4eb92f9 | ||
|
|
f0851086c0 | ||
|
|
bec1ce4c9b | ||
|
|
b29c4cdb08 | ||
|
|
63ba8596a7 | ||
|
|
82d2f79da0 | ||
|
|
f642d60f42 | ||
|
|
24b877c4ee | ||
|
|
e07ec97e12 | ||
|
|
290f4d8c44 | ||
|
|
a48608840f | ||
|
|
df07892e76 | ||
|
|
594dd8979a | ||
|
|
29850c1c8f | ||
|
|
adbe4a2693 | ||
|
|
b843a18441 | ||
|
|
da8a9e3d84 | ||
|
|
c6bd5b06e8 | ||
|
|
c04367dd86 | ||
|
|
5e2f506120 | ||
|
|
c536e6247b | ||
|
|
594d714b7f | ||
|
|
543fecadb8 | ||
|
|
017d8521d6 | ||
|
|
78e9d45072 | ||
|
|
7651d859c4 | ||
|
|
ec448b72e2 | ||
|
|
bf946f179a | ||
|
|
9ff9b5475a | ||
|
|
55f1d275b7 | ||
|
|
1d534881f8 | ||
|
|
03cbacfbb4 | ||
|
|
9d0905959b | ||
|
|
b7ca462f58 | ||
|
|
9015da4876 | ||
|
|
f458a1104f | ||
|
|
caba9388af | ||
|
|
763a7406ce | ||
|
|
68c8933c35 | ||
|
|
84b1558b2e | ||
|
|
cd870f0186 | ||
|
|
9ac2a2b69c | ||
|
|
86aba8f4b1 | ||
|
|
74b674e8e8 | ||
|
|
f1904bc12f | ||
|
|
9afba53e5d | ||
|
|
fd76e0fa46 | ||
|
|
438a87f06f | ||
|
|
a994e16f51 | ||
|
|
639e7491eb | ||
|
|
891a08a3cc | ||
|
|
0c07164dec | ||
|
|
f133d55889 | ||
|
|
fbb636cb06 | ||
|
|
bddceb28aa | ||
|
|
bff84fa24c | ||
|
|
64914f9aa0 | ||
|
|
2abf46c747 | ||
|
|
888f41e979 | ||
|
|
17533586ef | ||
|
|
c6ad088947 | ||
|
|
87d6d5f30e | ||
|
|
dbe894b3a3 | ||
|
|
a921d4b9cd | ||
|
|
b7db73cf77 | ||
|
|
5868595a6c | ||
|
|
eb8e09b835 | ||
|
|
41dc853f65 | ||
|
|
27c0a57cc1 | ||
|
|
497ac120ec | ||
|
|
a486016d96 | ||
|
|
cc5f5653ef | ||
|
|
20222c450d | ||
|
|
69049e1345 | ||
|
|
ed6264444f |
No files matched your search
@@ -63,5 +63,5 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
command: pages deploy website/build --project-name=${{ vars.CLOUDFLARE_PROJECT_NAME || 'gpxstudio' }} --branch=${{ github.ref_name }} --commit-dirty=true
|
command: pages deploy website/build --project-name=${{ vars.CLOUDFLARE_PROJECT_NAME || 'gpxstudio' }} --branch=${{ github.ref_name }}
|
||||||
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
|
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
name: Desktop beta
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: 'dev'
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: desktop-beta-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- platform: macos-latest
|
|
||||||
rust_targets: aarch64-apple-darwin,x86_64-apple-darwin,wasm32-unknown-unknown
|
|
||||||
args: --target universal-apple-darwin
|
|
||||||
bundles: target/universal-apple-darwin/release/bundle/dmg/*.dmg
|
|
||||||
# the oldest supported Ubuntu, so that the AppImage runs on older systems too
|
|
||||||
- platform: ubuntu-22.04
|
|
||||||
rust_targets: wasm32-unknown-unknown
|
|
||||||
args: ''
|
|
||||||
bundles: |
|
|
||||||
target/release/bundle/deb/*.deb
|
|
||||||
target/release/bundle/rpm/*.rpm
|
|
||||||
target/release/bundle/appimage/*.AppImage
|
|
||||||
- platform: windows-latest
|
|
||||||
rust_targets: wasm32-unknown-unknown
|
|
||||||
args: ''
|
|
||||||
bundles: |
|
|
||||||
target/release/bundle/msi/*.msi
|
|
||||||
target/release/bundle/nsis/*.exe
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.platform }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Install Linux dependencies
|
|
||||||
if: runner.os == 'Linux'
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
|
|
||||||
|
|
||||||
- name: Install Node.js
|
|
||||||
uses: actions/setup-node@v6
|
|
||||||
with:
|
|
||||||
node-version: 24
|
|
||||||
cache: npm
|
|
||||||
cache-dependency-path: website/package-lock.json
|
|
||||||
|
|
||||||
- name: Install Rust
|
|
||||||
uses: dtolnay/rust-toolchain@stable
|
|
||||||
with:
|
|
||||||
targets: ${{ matrix.rust_targets }}
|
|
||||||
|
|
||||||
- name: Cache Rust build
|
|
||||||
uses: Swatinem/rust-cache@v2
|
|
||||||
|
|
||||||
- name: Install wasm-pack
|
|
||||||
uses: taiki-e/install-action@v2
|
|
||||||
with:
|
|
||||||
tool: wasm-pack
|
|
||||||
|
|
||||||
# the desktop app does not use it, but the website depends on its package
|
|
||||||
- name: Build wasm
|
|
||||||
run: wasm-pack build --target bundler
|
|
||||||
working-directory: wasm
|
|
||||||
|
|
||||||
- name: Install dependencies for website
|
|
||||||
run: npm install --prefix website
|
|
||||||
|
|
||||||
# the key would be readable in the app: it is left empty, so only the MapTiler layer fails
|
|
||||||
- name: Create env file
|
|
||||||
run: echo "PUBLIC_MAPTILER_KEY=" >> website/.env
|
|
||||||
|
|
||||||
- name: Build app
|
|
||||||
run: npx --yes @tauri-apps/cli@2 build ${{ matrix.args }}
|
|
||||||
working-directory: tauri
|
|
||||||
|
|
||||||
# after the build, which gives the app the website it embeds
|
|
||||||
- name: Test engine and app
|
|
||||||
run: cargo test -p gpx-engine -p gpx-studio-desktop
|
|
||||||
|
|
||||||
- name: Upload bundles
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: bundles-${{ matrix.platform }}
|
|
||||||
path: ${{ matrix.bundles }}
|
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
# replaces the beta release only once every platform is built
|
|
||||||
release:
|
|
||||||
needs: build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
GH_REPO: ${{ github.repository }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Download bundles
|
|
||||||
uses: actions/download-artifact@v5
|
|
||||||
with:
|
|
||||||
pattern: bundles-*
|
|
||||||
path: bundles
|
|
||||||
merge-multiple: true
|
|
||||||
|
|
||||||
- name: Publish beta release
|
|
||||||
# the bundles of a platform are in a folder per format (deb, msi…)
|
|
||||||
run: |
|
|
||||||
mapfile -t files < <(find bundles -type f)
|
|
||||||
gh release delete desktop-beta --cleanup-tag --yes || true
|
|
||||||
gh release create desktop-beta "${files[@]}" \
|
|
||||||
--prerelease \
|
|
||||||
--target ${{ github.sha }} \
|
|
||||||
--title "Desktop beta" \
|
|
||||||
--notes "Beta of the desktop app, built from ${{ github.sha }} on the dev branch. The builds are not signed yet: macOS and Windows will warn before opening them."
|
|
||||||
@@ -7,15 +7,6 @@ edition = "2024"
|
|||||||
[lib]
|
[lib]
|
||||||
name = "gpx_studio_desktop_lib"
|
name = "gpx_studio_desktop_lib"
|
||||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||||
# the tests are in `tests/app`: on Windows, a test binary of the library or of the app could not
|
|
||||||
# start without the manifest, which `build.rs` only gives to the binaries of `tests`
|
|
||||||
test = false
|
|
||||||
doctest = false
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "gpx-studio-desktop"
|
|
||||||
path = "src/main.rs"
|
|
||||||
test = false
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tauri = { version = "2", features = ["test"] }
|
tauri = { version = "2", features = ["test"] }
|
||||||
|
|||||||
@@ -1,20 +1,3 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
// On Windows, the dialogs need Common Controls v6, which a binary only gets with a manifest that
|
|
||||||
// asks for it: tauri-build gives one to the app, but not to the test binaries, which would stop
|
|
||||||
// with STATUS_ENTRYPOINT_NOT_FOUND before running any test. This gives them the same manifest
|
|
||||||
// (`-tests` only reaches the binaries of `tests`, hence the tests are there).
|
|
||||||
if std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("windows")
|
|
||||||
&& std::env::var("CARGO_CFG_TARGET_ENV").as_deref() == Ok("msvc")
|
|
||||||
{
|
|
||||||
let manifest = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
|
|
||||||
.join("tests")
|
|
||||||
.join("windows-test.manifest");
|
|
||||||
println!("cargo:rerun-if-changed={}", manifest.display());
|
|
||||||
println!("cargo:rustc-link-arg-tests=/MANIFEST:EMBED");
|
|
||||||
println!(
|
|
||||||
"cargo:rustc-link-arg-tests=/MANIFESTINPUT:{}",
|
|
||||||
manifest.display()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
tauri_build::build()
|
tauri_build::build()
|
||||||
}
|
}
|
||||||
+9
-6
@@ -3,20 +3,20 @@
|
|||||||
|
|
||||||
mod bytes;
|
mod bytes;
|
||||||
mod commands;
|
mod commands;
|
||||||
pub mod state;
|
mod state;
|
||||||
pub mod store;
|
mod store;
|
||||||
pub mod workspace;
|
mod workspace;
|
||||||
|
|
||||||
use commands::*;
|
use commands::*;
|
||||||
use tauri::{Emitter, Manager};
|
use tauri::{Emitter, Manager};
|
||||||
|
|
||||||
/// The engine of the app: each file has its own history, so that undoing only concerns the
|
/// The engine of the app: each file has its own history, so that undoing only concerns the
|
||||||
/// selected files, and opening or closing a file is not something to undo.
|
/// selected files, and opening or closing a file is not something to undo.
|
||||||
pub type Engine = gpx_engine::Engine<gpx_engine::PerFileHistory>;
|
pub(crate) type Engine = gpx_engine::Engine<gpx_engine::PerFileHistory>;
|
||||||
|
|
||||||
/// The GPX files among what the system gave to the app (the arguments of the command line, when a
|
/// The GPX files among what the system gave to the app (the arguments of the command line, when a
|
||||||
/// file is opened with it).
|
/// file is opened with it).
|
||||||
pub fn gpx_paths(arguments: impl IntoIterator<Item = String>) -> Vec<std::path::PathBuf> {
|
fn gpx_paths(arguments: impl IntoIterator<Item = String>) -> Vec<std::path::PathBuf> {
|
||||||
arguments
|
arguments
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(std::path::PathBuf::from)
|
.map(std::path::PathBuf::from)
|
||||||
@@ -108,7 +108,7 @@ fn menu<R: tauri::Runtime>(app: &tauri::AppHandle<R>) -> tauri::Result<tauri::me
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gives the builder the commands that reach the engine (which it has to be given as `AppState`).
|
/// Gives the builder the commands that reach the engine (which it has to be given as `AppState`).
|
||||||
pub fn register_commands<R: tauri::Runtime>(builder: tauri::Builder<R>) -> tauri::Builder<R> {
|
fn register_commands<R: tauri::Runtime>(builder: tauri::Builder<R>) -> tauri::Builder<R> {
|
||||||
builder.invoke_handler(tauri::generate_handler![
|
builder.invoke_handler(tauri::generate_handler![
|
||||||
// selection
|
// selection
|
||||||
selection::select,
|
selection::select,
|
||||||
@@ -234,3 +234,6 @@ pub fn register_commands<R: tauri::Runtime>(builder: tauri::Builder<R>) -> tauri
|
|||||||
system::reveal_path,
|
system::reveal_path,
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
@@ -280,6 +280,13 @@ impl AppState {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An engine that keeps its data in a directory of its own, and has nobody to tell.
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn temporary() -> Self {
|
||||||
|
let directory = std::env::temp_dir().join(format!("gpx-studio-{}", uuid::Uuid::new_v4()));
|
||||||
|
Self::open(directory, Arc::new(|_, _| {})).expect("the storage can be opened")
|
||||||
|
}
|
||||||
|
|
||||||
/// Opens files that the system gave to the app, see `Core::open_external`.
|
/// Opens files that the system gave to the app, see `Core::open_external`.
|
||||||
pub fn open_external(&self, paths: Vec<PathBuf>) {
|
pub fn open_external(&self, paths: Vec<PathBuf>) {
|
||||||
self.core(move |core| core.open_external(&paths));
|
self.core(move |core| core.open_external(&paths));
|
||||||
|
|||||||
@@ -217,3 +217,69 @@ impl Storage for FileStorage {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::Engine;
|
||||||
|
use gpx_engine::{Action, Command, Load, LoadFiles, Persister};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn directory() -> PathBuf {
|
||||||
|
std::env::temp_dir().join(format!("gpx-studio-store-{}", Uuid::new_v4()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn engine_with_a_file() -> Engine {
|
||||||
|
let mut engine = Engine::default();
|
||||||
|
let data = std::fs::read("../gpx-rs/data/simple.gpx").unwrap();
|
||||||
|
engine
|
||||||
|
.execute(Action::Edit(Command::LoadFiles(LoadFiles {
|
||||||
|
files: vec![Load {
|
||||||
|
data: &data,
|
||||||
|
name: "simple",
|
||||||
|
}],
|
||||||
|
})))
|
||||||
|
.unwrap();
|
||||||
|
engine
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn keeps_the_files_and_the_settings_between_sessions() {
|
||||||
|
let root = directory();
|
||||||
|
let engine = engine_with_a_file();
|
||||||
|
let order = engine.order().to_vec();
|
||||||
|
|
||||||
|
let storage = FileStorage::open(&root).unwrap();
|
||||||
|
pollster::block_on(Persister::default().save(&storage, engine.snapshot())).unwrap();
|
||||||
|
pollster::block_on(storage.put_setting("units", "\"metric\"")).unwrap();
|
||||||
|
|
||||||
|
// another session
|
||||||
|
let storage = FileStorage::open(&root).unwrap();
|
||||||
|
let restored = pollster::block_on(Persister::default().restore(&storage)).unwrap();
|
||||||
|
let mut other = Engine::default();
|
||||||
|
other.restore(restored);
|
||||||
|
assert_eq!(other.order(), order);
|
||||||
|
assert_eq!(
|
||||||
|
other.file_statistics(&order[0]).unwrap().total_distance,
|
||||||
|
engine.file_statistics(&order[0]).unwrap().total_distance
|
||||||
|
);
|
||||||
|
assert_eq!(storage.settings()["units"], "\"metric\"");
|
||||||
|
fs::remove_dir_all(root).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn refuses_a_commit_that_is_not_based_on_the_head() {
|
||||||
|
let root = directory();
|
||||||
|
let storage = FileStorage::open(&root).unwrap();
|
||||||
|
let batch = Batch {
|
||||||
|
order: Some(vec![]),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
assert_eq!(pollster::block_on(storage.commit(&batch)), Ok(Revision(1)));
|
||||||
|
assert_eq!(
|
||||||
|
pollster::block_on(storage.commit(&batch)),
|
||||||
|
Err(CommitError::Stale { head: Revision(1) })
|
||||||
|
);
|
||||||
|
fs::remove_dir_all(root).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,23 +6,14 @@ use tauri::test::{INVOKE_KEY, get_ipc_response, mock_builder, mock_context, noop
|
|||||||
use tauri::webview::InvokeRequest;
|
use tauri::webview::InvokeRequest;
|
||||||
use tauri::{WebviewWindow, ipc::CallbackFn, ipc::InvokeBody, ipc::InvokeResponseBody};
|
use tauri::{WebviewWindow, ipc::CallbackFn, ipc::InvokeBody, ipc::InvokeResponseBody};
|
||||||
|
|
||||||
/// The origin of the pages of the app, the one Tauri allows the commands from: Windows has no
|
|
||||||
/// custom protocols, the pages come from `http://tauri.localhost` there.
|
|
||||||
const ORIGIN: &str = if cfg!(windows) {
|
|
||||||
"http://tauri.localhost"
|
|
||||||
} else {
|
|
||||||
"tauri://localhost"
|
|
||||||
};
|
|
||||||
|
|
||||||
struct App(WebviewWindow<tauri::test::MockRuntime>);
|
struct App(WebviewWindow<tauri::test::MockRuntime>);
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let app = gpx_studio_desktop_lib::register_commands(
|
let app =
|
||||||
mock_builder().manage(crate::temporary_state()),
|
crate::register_commands(mock_builder().manage(crate::state::AppState::temporary()))
|
||||||
)
|
.build(mock_context(noop_assets()))
|
||||||
.build(mock_context(noop_assets()))
|
.unwrap();
|
||||||
.unwrap();
|
|
||||||
let window = tauri::WebviewWindowBuilder::new(&app, "main", Default::default())
|
let window = tauri::WebviewWindowBuilder::new(&app, "main", Default::default())
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -43,7 +34,7 @@ impl App {
|
|||||||
cmd: cmd.into(),
|
cmd: cmd.into(),
|
||||||
callback: CallbackFn(0),
|
callback: CallbackFn(0),
|
||||||
error: CallbackFn(1),
|
error: CallbackFn(1),
|
||||||
url: ORIGIN.parse().unwrap(),
|
url: "tauri://localhost".parse().unwrap(),
|
||||||
body,
|
body,
|
||||||
headers,
|
headers,
|
||||||
invoke_key: INVOKE_KEY.to_string(),
|
invoke_key: INVOKE_KEY.to_string(),
|
||||||
@@ -65,7 +56,7 @@ impl App {
|
|||||||
cmd: cmd.into(),
|
cmd: cmd.into(),
|
||||||
callback: CallbackFn(0),
|
callback: CallbackFn(0),
|
||||||
error: CallbackFn(1),
|
error: CallbackFn(1),
|
||||||
url: ORIGIN.parse().unwrap(),
|
url: "tauri://localhost".parse().unwrap(),
|
||||||
body: InvokeBody::Json(args),
|
body: InvokeBody::Json(args),
|
||||||
headers: Default::default(),
|
headers: Default::default(),
|
||||||
invoke_key: INVOKE_KEY.to_string(),
|
invoke_key: INVOKE_KEY.to_string(),
|
||||||
@@ -320,8 +311,8 @@ fn keeps_settings_for_the_session() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn the_files_are_still_there_in_the_next_session() {
|
fn the_files_are_still_there_in_the_next_session() {
|
||||||
|
use crate::state::AppState;
|
||||||
use gpx_engine::api;
|
use gpx_engine::api;
|
||||||
use gpx_studio_desktop_lib::state::AppState;
|
|
||||||
|
|
||||||
let directory =
|
let directory =
|
||||||
std::env::temp_dir().join(format!("gpx-studio-session-{}", uuid::Uuid::new_v4()));
|
std::env::temp_dir().join(format!("gpx-studio-session-{}", uuid::Uuid::new_v4()));
|
||||||
@@ -356,14 +347,14 @@ fn only_gpx_files_that_exist_are_taken_from_what_the_system_gives() {
|
|||||||
text.to_string_lossy().into_owned(),
|
text.to_string_lossy().into_owned(),
|
||||||
directory.join("missing.gpx").to_string_lossy().into_owned(),
|
directory.join("missing.gpx").to_string_lossy().into_owned(),
|
||||||
];
|
];
|
||||||
assert_eq!(gpx_studio_desktop_lib::gpx_paths(arguments), [track]);
|
assert_eq!(crate::gpx_paths(arguments), [track]);
|
||||||
std::fs::remove_dir_all(directory).unwrap();
|
std::fs::remove_dir_all(directory).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn a_file_opened_with_the_app_is_opened_selected_and_announced() {
|
fn a_file_opened_with_the_app_is_opened_selected_and_announced() {
|
||||||
|
use crate::state::AppState;
|
||||||
use gpx_engine::api;
|
use gpx_engine::api;
|
||||||
use gpx_studio_desktop_lib::state::AppState;
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
let directory = std::env::temp_dir().join(format!("gpx-studio-open-{}", uuid::Uuid::new_v4()));
|
let directory = std::env::temp_dir().join(format!("gpx-studio-open-{}", uuid::Uuid::new_v4()));
|
||||||
@@ -450,7 +441,7 @@ fn a_file_outside_the_open_folder_is_read_again_when_the_disk_changes() {
|
|||||||
|
|
||||||
let (events, received) = mpsc::channel();
|
let (events, received) = mpsc::channel();
|
||||||
let directory = std::env::temp_dir().join(format!("gpx-store-{}", uuid::Uuid::new_v4()));
|
let directory = std::env::temp_dir().join(format!("gpx-store-{}", uuid::Uuid::new_v4()));
|
||||||
let state = gpx_studio_desktop_lib::state::AppState::open(
|
let state = crate::state::AppState::open(
|
||||||
directory.clone(),
|
directory.clone(),
|
||||||
std::sync::Arc::new(move |name, _| {
|
std::sync::Arc::new(move |name, _| {
|
||||||
let _ = events.send(name.to_string());
|
let _ = events.send(name.to_string());
|
||||||
@@ -470,8 +461,8 @@ fn a_file_outside_the_open_folder_is_read_again_when_the_disk_changes() {
|
|||||||
});
|
});
|
||||||
let id = uuid::Uuid::parse_str(&id).unwrap();
|
let id = uuid::Uuid::parse_str(&id).unwrap();
|
||||||
// the name comes from the path, which does not change: the content does
|
// the name comes from the path, which does not change: the content does
|
||||||
let signature = |state: &gpx_studio_desktop_lib::state::AppState| {
|
let signature = |state: &crate::state::AppState| {
|
||||||
state.core(move |core| gpx_studio_desktop_lib::workspace::signature(&core.engine, id))
|
state.core(move |core| crate::workspace::signature(&core.engine, id))
|
||||||
};
|
};
|
||||||
let before = signature(&state);
|
let before = signature(&state);
|
||||||
|
|
||||||
@@ -492,7 +483,7 @@ fn a_file_outside_the_open_folder_is_read_again_when_the_disk_changes() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn files_made_from_a_file_of_the_open_folder_are_written_next_to_it_at_once() {
|
fn files_made_from_a_file_of_the_open_folder_are_written_next_to_it_at_once() {
|
||||||
let state = crate::temporary_state();
|
let state = crate::state::AppState::temporary();
|
||||||
let folder = std::env::temp_dir().join(format!("gpx-tests-{}", uuid::Uuid::new_v4()));
|
let folder = std::env::temp_dir().join(format!("gpx-tests-{}", uuid::Uuid::new_v4()));
|
||||||
std::fs::create_dir_all(folder.join("sub")).unwrap();
|
std::fs::create_dir_all(folder.join("sub")).unwrap();
|
||||||
std::fs::copy("../gpx-rs/data/simple.gpx", folder.join("sub/track.gpx")).unwrap();
|
std::fs::copy("../gpx-rs/data/simple.gpx", folder.join("sub/track.gpx")).unwrap();
|
||||||
@@ -525,23 +516,19 @@ fn files_made_from_a_file_of_the_open_folder_are_written_next_to_it_at_once() {
|
|||||||
.collect();
|
.collect();
|
||||||
// the copy is in the subfolder, named after its name (the one in the file, not of the file)
|
// the copy is in the subfolder, named after its name (the one in the file, not of the file)
|
||||||
assert!(
|
assert!(
|
||||||
paths
|
paths.iter().any(|path| path.ends_with("sub/simple.gpx")),
|
||||||
.iter()
|
|
||||||
.any(|path| std::path::Path::new(path).ends_with("sub/simple.gpx")),
|
|
||||||
"{paths:?}"
|
"{paths:?}"
|
||||||
);
|
);
|
||||||
// the new file went where the selected file is
|
// the new file went where the selected file is
|
||||||
assert!(
|
assert!(
|
||||||
paths
|
paths.iter().any(|path| path.ends_with("sub/fresh.gpx")),
|
||||||
.iter()
|
|
||||||
.any(|path| std::path::Path::new(path).ends_with("sub/fresh.gpx")),
|
|
||||||
"{paths:?}"
|
"{paths:?}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn the_parts_of_a_split_are_numbered_from_one() {
|
fn the_parts_of_a_split_are_numbered_from_one() {
|
||||||
let state = crate::temporary_state();
|
let state = crate::state::AppState::temporary();
|
||||||
let folder = std::env::temp_dir().join(format!("gpx-tests-{}", uuid::Uuid::new_v4()));
|
let folder = std::env::temp_dir().join(format!("gpx-tests-{}", uuid::Uuid::new_v4()));
|
||||||
std::fs::create_dir_all(&folder).unwrap();
|
std::fs::create_dir_all(&folder).unwrap();
|
||||||
std::fs::copy("../gpx-rs/data/simple.gpx", folder.join("track.gpx")).unwrap();
|
std::fs::copy("../gpx-rs/data/simple.gpx", folder.join("track.gpx")).unwrap();
|
||||||
@@ -662,7 +649,7 @@ fn a_file_keeps_its_name_and_its_file_is_renamed_apart() {
|
|||||||
|
|
||||||
// the name of another file is not taken
|
// the name of another file is not taken
|
||||||
let error = app.error("rename_file", json!({ "fileId": id, "name": "taken" }));
|
let error = app.error("rename_file", json!({ "fileId": id, "name": "taken" }));
|
||||||
assert_eq!(error, gpx_studio_desktop_lib::workspace::NAME_TAKEN);
|
assert_eq!(error, crate::workspace::NAME_TAKEN);
|
||||||
assert!(folder.join("moved.gpx").exists());
|
assert!(folder.join("moved.gpx").exists());
|
||||||
|
|
||||||
// a name is one that a file can have
|
// a name is one that a file can have
|
||||||
+812
-2
@@ -148,7 +148,7 @@ pub struct Entry {
|
|||||||
pub is_dir: bool,
|
pub is_dir: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_gpx(path: &Path) -> bool {
|
fn is_gpx(path: &Path) -> bool {
|
||||||
path.extension()
|
path.extension()
|
||||||
.and_then(|extension| extension.to_str())
|
.and_then(|extension| extension.to_str())
|
||||||
.is_some_and(|extension| extension.eq_ignore_ascii_case("gpx"))
|
.is_some_and(|extension| extension.eq_ignore_ascii_case("gpx"))
|
||||||
@@ -156,7 +156,7 @@ pub fn is_gpx(path: &Path) -> bool {
|
|||||||
|
|
||||||
/// Compares names the way people read them: the numbers in them by their value ("track 2" before
|
/// Compares names the way people read them: the numbers in them by their value ("track 2" before
|
||||||
/// "track 10"), the rest regardless of case.
|
/// "track 10"), the rest regardless of case.
|
||||||
pub fn natural_cmp(a: &str, b: &str) -> Ordering {
|
fn natural_cmp(a: &str, b: &str) -> Ordering {
|
||||||
let (mut a, mut b) = (a.chars().peekable(), b.chars().peekable());
|
let (mut a, mut b) = (a.chars().peekable(), b.chars().peekable());
|
||||||
loop {
|
loop {
|
||||||
let order = match (a.peek().copied(), b.peek().copied()) {
|
let order = match (a.peek().copied(), b.peek().copied()) {
|
||||||
@@ -1040,3 +1040,813 @@ impl Workspace {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use gpx_engine::SelectMode;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn gpx(name: &str) -> String {
|
||||||
|
format!(
|
||||||
|
r#"<?xml version="1.0"?><gpx version="1.1" creator="test" xmlns="http://www.topografix.com/GPX/1/1"><metadata><name>{name}</name></metadata><trk><name>{name}</name><trkseg><trkpt lat="50.0" lon="4.0"><ele>10</ele></trkpt><trkpt lat="50.1" lon="4.1"><ele>20</ele></trkpt></trkseg></trk></gpx>"#
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The GPX files of a folder and of the folders in it.
|
||||||
|
pub(super) fn gpx_files(folder: &Path) -> Vec<PathBuf> {
|
||||||
|
let mut found = vec![];
|
||||||
|
for entry in fs::read_dir(folder).unwrap().flatten() {
|
||||||
|
let path = entry.path();
|
||||||
|
if path.is_dir() {
|
||||||
|
found.extend(gpx_files(&path));
|
||||||
|
} else if is_gpx(&path) {
|
||||||
|
found.push(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
found.sort();
|
||||||
|
found
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Fixture {
|
||||||
|
folder: PathBuf,
|
||||||
|
engine: Engine,
|
||||||
|
workspace: Workspace,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Fixture {
|
||||||
|
fn new() -> Self {
|
||||||
|
let folder =
|
||||||
|
canonical(&std::env::temp_dir()).join(format!("gpx-ws-{}", Uuid::new_v4()));
|
||||||
|
fs::create_dir_all(&folder).unwrap();
|
||||||
|
Self {
|
||||||
|
folder,
|
||||||
|
engine: Engine::default(),
|
||||||
|
workspace: Workspace::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&self, name: &str, title: &str) -> PathBuf {
|
||||||
|
let path = self.folder.join(name);
|
||||||
|
fs::write(&path, gpx(title)).unwrap();
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Opens the folder, and all the files that are in it.
|
||||||
|
fn open_folder(&mut self) {
|
||||||
|
let folder = self.folder.clone();
|
||||||
|
self.workspace.open_folder(&mut self.engine, &folder, false);
|
||||||
|
let files = gpx_files(&folder);
|
||||||
|
self.workspace.open_files(&mut self.engine, &files, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reconcile(&mut self, changed: Option<&[PathBuf]>) -> Option<api::Outcome> {
|
||||||
|
self.workspace.reconcile(&mut self.engine, changed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save(&mut self, ids: &[Uuid]) {
|
||||||
|
self.workspace
|
||||||
|
.save(&mut self.engine, ids, &BTreeMap::new(), None)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ids(&self) -> Vec<Uuid> {
|
||||||
|
self.engine.order().iter().map(|id| id.0).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn id_named(&self, name: &str) -> Uuid {
|
||||||
|
self.ids()
|
||||||
|
.into_iter()
|
||||||
|
.find(|id| self.name(*id) == name)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self, id: Uuid) -> String {
|
||||||
|
self.engine
|
||||||
|
.file_structure(&FileId(id))
|
||||||
|
.unwrap()
|
||||||
|
.name
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// What the file holds: the name of its track (its own name is the one of the file).
|
||||||
|
fn content(&self, id: Uuid) -> String {
|
||||||
|
self.engine.file_structure(&FileId(id)).unwrap().tracks[0]
|
||||||
|
.info
|
||||||
|
.name
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rename(&mut self, id: Uuid, name: &str) {
|
||||||
|
api::select(&mut self.engine, &[id], SelectMode::Replace);
|
||||||
|
assert!(!api::metadata(&mut self.engine, name, "").has_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn status(&self, id: Uuid) -> FileStatus {
|
||||||
|
self.workspace
|
||||||
|
.state(&self.engine)
|
||||||
|
.files
|
||||||
|
.remove(&id.to_string())
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Fixture {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = fs::remove_dir_all(&self.folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn an_opened_file_is_clean_until_it_is_edited_and_clean_again_once_saved() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
let path = fx.write("a.gpx", "a");
|
||||||
|
fx.workspace
|
||||||
|
.open_files(&mut fx.engine, std::slice::from_ref(&path), true);
|
||||||
|
let id = fx.ids()[0];
|
||||||
|
assert!(!fx.workspace.is_dirty(&fx.engine, id));
|
||||||
|
assert_eq!(fx.status(id).path.as_deref(), path.to_str());
|
||||||
|
|
||||||
|
fx.rename(id, "renamed");
|
||||||
|
assert!(fx.workspace.is_dirty(&fx.engine, id));
|
||||||
|
// nothing is written before it is saved
|
||||||
|
assert!(fs::read_to_string(&path).unwrap().contains(">a<"));
|
||||||
|
|
||||||
|
fx.save(&[id]);
|
||||||
|
assert!(!fx.workspace.is_dirty(&fx.engine, id));
|
||||||
|
assert!(fs::read_to_string(&path).unwrap().contains(">renamed<"));
|
||||||
|
|
||||||
|
// going back before the save is an edit again
|
||||||
|
api::select(&mut fx.engine, &[id], SelectMode::Replace);
|
||||||
|
api::undo(&mut fx.engine);
|
||||||
|
assert!(fx.workspace.is_dirty(&fx.engine, id));
|
||||||
|
api::redo(&mut fx.engine);
|
||||||
|
assert!(!fx.workspace.is_dirty(&fx.engine, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_file_that_is_not_on_the_disk_is_unsaved_until_it_is_given_a_place() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
api::new_file(&mut fx.engine, "fresh", None, None, None, false);
|
||||||
|
let id = fx.ids()[0];
|
||||||
|
assert!(fx.workspace.is_dirty(&fx.engine, id));
|
||||||
|
assert_eq!(
|
||||||
|
fx.workspace.unlinked(&fx.engine, &[id]),
|
||||||
|
[(id, "fresh".to_string())]
|
||||||
|
);
|
||||||
|
// nowhere to put it without being told
|
||||||
|
fx.save(&[id]);
|
||||||
|
assert!(fx.workspace.is_dirty(&fx.engine, id));
|
||||||
|
|
||||||
|
let path = fx.folder.join("fresh.gpx");
|
||||||
|
let paths = BTreeMap::from([(id, path.clone())]);
|
||||||
|
fx.workspace
|
||||||
|
.save(&mut fx.engine, &[id], &paths, None)
|
||||||
|
.unwrap();
|
||||||
|
assert!(path.exists());
|
||||||
|
assert!(!fx.workspace.is_dirty(&fx.engine, id));
|
||||||
|
assert!(fx.workspace.unlinked(&fx.engine, &[id]).is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn several_files_without_a_place_go_in_a_folder_with_names_that_are_free() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
fx.write("fresh.gpx", "already there");
|
||||||
|
api::new_file(&mut fx.engine, "fresh", None, None, None, false);
|
||||||
|
api::new_file(&mut fx.engine, "a/b: c", None, None, None, false);
|
||||||
|
api::new_file(&mut fx.engine, "fresh", None, None, None, false);
|
||||||
|
let ids = fx.ids();
|
||||||
|
let folder = fx.folder.clone();
|
||||||
|
fx.workspace
|
||||||
|
.save(&mut fx.engine, &ids, &BTreeMap::new(), Some(&folder))
|
||||||
|
.unwrap();
|
||||||
|
for name in ["fresh (2).gpx", "fresh (3).gpx", "a_b_ c.gpx"] {
|
||||||
|
assert!(fx.folder.join(name).exists(), "{name}");
|
||||||
|
}
|
||||||
|
assert!(ids.iter().all(|id| !fx.workspace.is_dirty(&fx.engine, *id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn what_this_app_writes_is_not_a_change_of_the_disk() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
let path = fx.write("a.gpx", "a");
|
||||||
|
fx.open_folder();
|
||||||
|
let id = fx.ids()[0];
|
||||||
|
api::select(&mut fx.engine, &[id], SelectMode::Replace);
|
||||||
|
assert!(!api::style(&mut fx.engine, Some("#ff0000"), None, None).has_error());
|
||||||
|
fx.save(&[id]);
|
||||||
|
assert!(fx.reconcile(Some(&[path])).is_none());
|
||||||
|
assert!(!fx.status(id).replaced && !fx.status(id).dirty);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn the_folders_of_the_files_outside_the_open_folder_are_watched_too() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
let inside = fx.write("in.gpx", "in");
|
||||||
|
let elsewhere = canonical(&std::env::temp_dir()).join(format!("gpx-ws-{}", Uuid::new_v4()));
|
||||||
|
fs::create_dir_all(&elsewhere).unwrap();
|
||||||
|
let (one, two) = (elsewhere.join("one.gpx"), elsewhere.join("two.gpx"));
|
||||||
|
fs::write(&one, gpx("one")).unwrap();
|
||||||
|
fs::write(&two, gpx("two")).unwrap();
|
||||||
|
let folder = fx.folder.clone();
|
||||||
|
|
||||||
|
// no folder: only the folder of the files
|
||||||
|
fx.workspace.open_files(&mut fx.engine, &[one, two], false);
|
||||||
|
assert_eq!(fx.workspace.watched(), [(elsewhere.clone(), false)]);
|
||||||
|
|
||||||
|
// the open folder as a whole, and the file in it needs nothing more
|
||||||
|
fx.workspace.open_folder(&mut fx.engine, &folder, false);
|
||||||
|
fx.workspace.open_files(&mut fx.engine, &[inside], false);
|
||||||
|
assert_eq!(
|
||||||
|
fx.workspace.watched(),
|
||||||
|
[(folder, true), (elsewhere.clone(), false)]
|
||||||
|
);
|
||||||
|
|
||||||
|
// closing the files stops it
|
||||||
|
let ids = fx.ids();
|
||||||
|
fx.workspace.close_files(&mut fx.engine, &ids, true);
|
||||||
|
assert_eq!(fx.workspace.watched(), [(fx.folder.clone(), true)]);
|
||||||
|
fs::remove_dir_all(elsewhere).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn opening_a_folder_does_not_open_its_files() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
fx.write("a.gpx", "a");
|
||||||
|
let folder = fx.folder.clone();
|
||||||
|
let outcome = fx.workspace.open_folder(&mut fx.engine, &folder, false);
|
||||||
|
assert!(!outcome.changed);
|
||||||
|
assert!(fx.ids().is_empty());
|
||||||
|
assert_eq!(fx.workspace.folder.as_deref(), Some(folder.as_path()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn folders_are_made_renamed_and_moved_and_the_open_files_follow() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
let a = fx.write("a.gpx", "a");
|
||||||
|
fx.open_folder();
|
||||||
|
let id = fx.ids()[0];
|
||||||
|
let root = fx.folder.clone();
|
||||||
|
let path_of = |fx: &Fixture| PathBuf::from(fx.status(id).path.unwrap());
|
||||||
|
|
||||||
|
let first = fx.workspace.create_folder(&root, "New folder").unwrap();
|
||||||
|
let second = fx.workspace.create_folder(&root, "New folder").unwrap();
|
||||||
|
assert_eq!(first, root.join("New folder"));
|
||||||
|
assert_eq!(second, root.join("New folder 2"));
|
||||||
|
|
||||||
|
fx.workspace.move_paths(&[a], &first).unwrap();
|
||||||
|
assert_eq!(path_of(&fx), first.join("a.gpx"));
|
||||||
|
assert!(first.join("a.gpx").exists() && !fx.status(id).dirty);
|
||||||
|
|
||||||
|
let trips = fx.workspace.rename_path(&first, "Trips").unwrap();
|
||||||
|
assert_eq!(path_of(&fx), root.join("Trips/a.gpx"));
|
||||||
|
// a folder does not go into itself, nor onto something else
|
||||||
|
assert!(
|
||||||
|
fx.workspace
|
||||||
|
.move_paths(std::slice::from_ref(&trips), &trips)
|
||||||
|
.is_err()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
fx.workspace.rename_path(&trips, "New folder 2"),
|
||||||
|
Err(NAME_TAKEN.to_owned())
|
||||||
|
);
|
||||||
|
fx.workspace.move_paths(&[trips], &second).unwrap();
|
||||||
|
assert_eq!(path_of(&fx), second.join("Trips/a.gpx"));
|
||||||
|
|
||||||
|
// a file keeps its extension
|
||||||
|
let closed = fx.write("c.gpx", "c");
|
||||||
|
assert_eq!(
|
||||||
|
fx.workspace.rename_path(&closed, "d").unwrap(),
|
||||||
|
root.join("d.gpx")
|
||||||
|
);
|
||||||
|
// the open folder and what is not in it are left alone
|
||||||
|
assert!(fx.workspace.rename_path(&root, "x").is_err());
|
||||||
|
let elsewhere = canonical(&std::env::temp_dir());
|
||||||
|
assert!(fx.workspace.rename_path(&elsewhere, "x").is_err());
|
||||||
|
assert!(fx.workspace.create_folder(&elsewhere, "x").is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deleted_files_are_closed_unless_they_have_edits() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
let a = fx.write("a.gpx", "a");
|
||||||
|
let b = fx.write("b.gpx", "b");
|
||||||
|
fx.open_folder();
|
||||||
|
let (id_a, id_b) = (fx.id_named("a"), fx.id_named("b"));
|
||||||
|
api::select(&mut fx.engine, &[id_b], SelectMode::Replace);
|
||||||
|
assert!(!api::style(&mut fx.engine, Some("#ff0000"), None, None).has_error());
|
||||||
|
|
||||||
|
let outcome = fx
|
||||||
|
.workspace
|
||||||
|
.delete_paths(&mut fx.engine, &[a.clone(), b.clone()], |paths| {
|
||||||
|
paths.iter().for_each(|path| fs::remove_file(path).unwrap());
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
assert!(outcome.changed);
|
||||||
|
assert_eq!(fx.ids(), [id_b]);
|
||||||
|
assert!(!fx.ids().contains(&id_a));
|
||||||
|
let status = fx.status(id_b);
|
||||||
|
assert!(status.dirty && status.missing);
|
||||||
|
assert!(!a.exists() && !b.exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn the_tree_of_the_folder_shows_folders_first_and_only_gpx_files() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
fx.write("b.gpx", "b");
|
||||||
|
fx.write("A.GPX", "a");
|
||||||
|
fx.write("b 10.gpx", "b 10");
|
||||||
|
fx.write("b 2.gpx", "b 2");
|
||||||
|
fx.write("notes.txt", "not a track");
|
||||||
|
fx.write(".hidden.gpx", "hidden");
|
||||||
|
fs::create_dir(fx.folder.join("zoo")).unwrap();
|
||||||
|
fs::create_dir(fx.folder.join("Alps")).unwrap();
|
||||||
|
fs::create_dir(fx.folder.join(".git")).unwrap();
|
||||||
|
fx.write("zoo/c.gpx", "c");
|
||||||
|
let folder = fx.folder.clone();
|
||||||
|
fx.workspace.open_folder(&mut fx.engine, &folder, false);
|
||||||
|
|
||||||
|
let names = |entries: Vec<Entry>| -> Vec<(String, bool)> {
|
||||||
|
entries.into_iter().map(|e| (e.name, e.is_dir)).collect()
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
names(fx.workspace.list_folder(&folder).unwrap()),
|
||||||
|
[
|
||||||
|
("Alps".to_string(), true),
|
||||||
|
("zoo".to_string(), true),
|
||||||
|
("A.GPX".to_string(), false),
|
||||||
|
("b.gpx".to_string(), false),
|
||||||
|
("b 2.gpx".to_string(), false),
|
||||||
|
("b 10.gpx".to_string(), false),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
names(fx.workspace.list_folder(&folder.join("zoo")).unwrap()),
|
||||||
|
[("c.gpx".to_string(), false)]
|
||||||
|
);
|
||||||
|
// only what is in the open folder can be listed
|
||||||
|
let elsewhere = canonical(&std::env::temp_dir());
|
||||||
|
assert!(fx.workspace.list_folder(&elsewhere).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn names_are_sorted_by_the_numbers_they_hold() {
|
||||||
|
let mut names = vec![
|
||||||
|
"track 10",
|
||||||
|
"track 2",
|
||||||
|
"Track 1",
|
||||||
|
"track",
|
||||||
|
"track 02b",
|
||||||
|
"track 2a",
|
||||||
|
"b",
|
||||||
|
"A",
|
||||||
|
];
|
||||||
|
names.sort_by(|a, b| natural_cmp(a, b).then_with(|| a.cmp(b)));
|
||||||
|
assert_eq!(
|
||||||
|
names,
|
||||||
|
[
|
||||||
|
"A",
|
||||||
|
"b",
|
||||||
|
"track",
|
||||||
|
"Track 1",
|
||||||
|
"track 2",
|
||||||
|
"track 2a",
|
||||||
|
"track 02b",
|
||||||
|
"track 10",
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_file_without_edits_is_read_again_when_the_disk_changes() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
let a = fx.write("a.gpx", "a");
|
||||||
|
fx.open_folder();
|
||||||
|
let id = fx.ids()[0];
|
||||||
|
|
||||||
|
fx.write("a.gpx", "theirs");
|
||||||
|
let outcome = fx.reconcile(Some(std::slice::from_ref(&a))).unwrap();
|
||||||
|
assert!(outcome.changed);
|
||||||
|
// the same file, now the one on the disk
|
||||||
|
assert_eq!(fx.ids(), [id]);
|
||||||
|
assert_eq!(fx.content(id), "theirs");
|
||||||
|
let status = fx.status(id);
|
||||||
|
assert!(!status.dirty && !status.replaced);
|
||||||
|
// looking again changes nothing
|
||||||
|
assert!(fx.reconcile(Some(std::slice::from_ref(&a))).is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_file_with_edits_is_flagged_when_the_disk_changes_and_not_read_again() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
let a = fx.write("a.gpx", "a");
|
||||||
|
fx.open_folder();
|
||||||
|
let id = fx.ids()[0];
|
||||||
|
fx.rename(id, "mine");
|
||||||
|
|
||||||
|
fx.write("a.gpx", "theirs");
|
||||||
|
let outcome = fx.reconcile(Some(std::slice::from_ref(&a))).unwrap();
|
||||||
|
assert!(!outcome.changed);
|
||||||
|
assert_eq!(fx.name(id), "mine");
|
||||||
|
let status = fx.status(id);
|
||||||
|
assert!(status.dirty && status.replaced && !status.missing);
|
||||||
|
// looking again changes nothing
|
||||||
|
assert!(fx.reconcile(Some(std::slice::from_ref(&a))).is_none());
|
||||||
|
|
||||||
|
// the disk goes back to what was read: only the edits are left
|
||||||
|
fx.write("a.gpx", "a");
|
||||||
|
assert!(fx.reconcile(Some(std::slice::from_ref(&a))).is_some());
|
||||||
|
let status = fx.status(id);
|
||||||
|
assert!(status.dirty && !status.replaced);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn the_user_can_take_the_disk_instead_of_the_edits() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
fx.write("a.gpx", "a");
|
||||||
|
fx.open_folder();
|
||||||
|
let id = fx.ids()[0];
|
||||||
|
fx.rename(id, "mine");
|
||||||
|
fx.write("a.gpx", "theirs");
|
||||||
|
fx.reconcile(None);
|
||||||
|
assert!(fx.status(id).replaced);
|
||||||
|
|
||||||
|
fx.workspace.reload(&mut fx.engine, &[id]).unwrap();
|
||||||
|
assert_eq!(fx.content(id), "theirs");
|
||||||
|
let status = fx.status(id);
|
||||||
|
assert!(!status.dirty && !status.replaced);
|
||||||
|
// and it is one undo step
|
||||||
|
api::select(&mut fx.engine, &[id], SelectMode::Replace);
|
||||||
|
api::undo(&mut fx.engine);
|
||||||
|
assert_eq!(fx.content(id), "mine");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn saving_overwrites_what_replaced_the_file() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
let a = fx.write("a.gpx", "a");
|
||||||
|
fx.open_folder();
|
||||||
|
let id = fx.ids()[0];
|
||||||
|
fx.rename(id, "mine");
|
||||||
|
fx.write("a.gpx", "theirs");
|
||||||
|
fx.reconcile(None);
|
||||||
|
assert!(fx.status(id).replaced);
|
||||||
|
|
||||||
|
fx.save(&[id]);
|
||||||
|
assert!(fs::read_to_string(a).unwrap().contains(">mine<"));
|
||||||
|
assert!(!fx.status(id).replaced && !fx.status(id).dirty);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_file_that_is_gone_from_the_disk_stays_open_and_dirty_until_it_is_saved_again() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
let a = fx.write("a.gpx", "a");
|
||||||
|
fx.open_folder();
|
||||||
|
let id = fx.ids()[0];
|
||||||
|
|
||||||
|
fs::remove_file(&a).unwrap();
|
||||||
|
assert!(fx.reconcile(Some(std::slice::from_ref(&a))).is_some());
|
||||||
|
assert_eq!(fx.ids(), [id]);
|
||||||
|
let status = fx.status(id);
|
||||||
|
assert!(status.dirty && status.missing && status.path.is_some());
|
||||||
|
|
||||||
|
// saving puts it back
|
||||||
|
fx.save(&[id]);
|
||||||
|
assert!(a.exists());
|
||||||
|
let status = fx.status(id);
|
||||||
|
assert!(!status.dirty && !status.missing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_file_that_comes_back_different_is_read_again() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
let a = fx.write("a.gpx", "a");
|
||||||
|
fx.open_folder();
|
||||||
|
let id = fx.ids()[0];
|
||||||
|
fs::remove_file(&a).unwrap();
|
||||||
|
fx.reconcile(None);
|
||||||
|
assert!(fx.status(id).missing);
|
||||||
|
|
||||||
|
fx.write("a.gpx", "back");
|
||||||
|
fx.reconcile(None);
|
||||||
|
assert_eq!(fx.content(id), "back");
|
||||||
|
let status = fx.status(id);
|
||||||
|
assert!(!status.dirty && !status.missing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn what_changed_while_the_app_was_closed_is_found_when_it_starts() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
let a = fx.write("a.gpx", "a");
|
||||||
|
fx.open_folder();
|
||||||
|
let id = fx.ids()[0];
|
||||||
|
fx.write("a.gpx", "changed");
|
||||||
|
assert!(fx.reconcile(None).is_some());
|
||||||
|
assert_eq!(fx.content(id), "changed");
|
||||||
|
fs::remove_file(a).unwrap();
|
||||||
|
assert!(fx.reconcile(None).is_some());
|
||||||
|
assert!(fx.status(id).missing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn new_files_made_from_a_file_of_the_folder_are_saved_next_to_it() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
fs::create_dir(fx.folder.join("sub")).unwrap();
|
||||||
|
fx.write("sub/b.gpx", "b");
|
||||||
|
fx.write("a.gpx", "a");
|
||||||
|
fx.open_folder();
|
||||||
|
let b = fx.id_named("b");
|
||||||
|
let sub = fx.folder.join("sub");
|
||||||
|
assert_eq!(fx.workspace.source_dir(&[b]), Some(canonical(&sub)));
|
||||||
|
|
||||||
|
let before = fx.ids();
|
||||||
|
api::select(&mut fx.engine, &[b], SelectMode::Replace);
|
||||||
|
let outcome = api::duplicate(&mut fx.engine);
|
||||||
|
let copy = fx
|
||||||
|
.ids()
|
||||||
|
.into_iter()
|
||||||
|
.find(|id| !before.contains(id))
|
||||||
|
.unwrap();
|
||||||
|
fx.workspace.inherit(outcome.added(), &canonical(&sub));
|
||||||
|
assert_eq!(fx.status(copy).folder.as_deref(), canonical(&sub).to_str());
|
||||||
|
assert!(fx.status(copy).path.is_none() && fx.status(copy).dirty);
|
||||||
|
// nobody needs to be asked where it goes
|
||||||
|
assert!(fx.workspace.unlinked(&fx.engine, &[copy]).is_empty());
|
||||||
|
|
||||||
|
fx.save(&[copy]);
|
||||||
|
assert!(sub.join("b (2).gpx").exists());
|
||||||
|
let status = fx.status(copy);
|
||||||
|
assert!(!status.dirty && status.folder.is_none());
|
||||||
|
assert_eq!(
|
||||||
|
status.path.as_deref(),
|
||||||
|
canonical(&sub.join("b (2).gpx")).to_str()
|
||||||
|
);
|
||||||
|
// the copy of the copy is next to it as well
|
||||||
|
assert_eq!(fx.workspace.source_dir(&[copy]), Some(canonical(&sub)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_file_outside_the_open_folder_hands_nothing_down() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
let elsewhere = canonical(&std::env::temp_dir()).join(format!("gpx-ws-{}", Uuid::new_v4()));
|
||||||
|
fs::create_dir_all(&elsewhere).unwrap();
|
||||||
|
let outside = elsewhere.join("o.gpx");
|
||||||
|
fs::write(&outside, gpx("o")).unwrap();
|
||||||
|
let folder = fx.folder.clone();
|
||||||
|
fx.workspace.open_folder(&mut fx.engine, &folder, false);
|
||||||
|
fx.workspace
|
||||||
|
.open_files(&mut fx.engine, std::slice::from_ref(&outside), true);
|
||||||
|
let id = fx.ids()[0];
|
||||||
|
assert_eq!(fx.workspace.source_dir(&[id]), None);
|
||||||
|
// a new file with no source is not linked to a folder by `source_dir`: the caller falls back
|
||||||
|
fs::remove_dir_all(elsewhere).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn closing_files_asks_what_to_do_with_the_unsaved_ones() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
fx.write("a.gpx", "a");
|
||||||
|
fx.write("b.gpx", "b");
|
||||||
|
fx.open_folder();
|
||||||
|
let (a, b) = (fx.id_named("a"), fx.id_named("b"));
|
||||||
|
fx.rename(a, "edited");
|
||||||
|
assert_eq!(fx.workspace.unsaved(&fx.engine, &[a, b]), [a]);
|
||||||
|
|
||||||
|
// without a choice what has edits stays
|
||||||
|
let outcome = fx.workspace.close_files(&mut fx.engine, &[a, b], false);
|
||||||
|
assert!(outcome.changed);
|
||||||
|
assert_eq!(fx.ids(), [a]);
|
||||||
|
|
||||||
|
// saved first
|
||||||
|
fx.save(&[a]);
|
||||||
|
fx.workspace.close_files(&mut fx.engine, &[a], false);
|
||||||
|
assert!(fx.ids().is_empty());
|
||||||
|
assert!(
|
||||||
|
fs::read_to_string(fx.folder.join("a.gpx"))
|
||||||
|
.unwrap()
|
||||||
|
.contains("edited")
|
||||||
|
);
|
||||||
|
assert!(fx.workspace.links.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn closing_files_can_discard_their_edits() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
fx.write("a.gpx", "a");
|
||||||
|
fx.open_folder();
|
||||||
|
let a = fx.ids()[0];
|
||||||
|
fx.rename(a, "edited");
|
||||||
|
api::new_file(&mut fx.engine, "fresh", None, None, None, false);
|
||||||
|
let fresh = fx.id_named("fresh");
|
||||||
|
fx.workspace.close_files(&mut fx.engine, &[a, fresh], true);
|
||||||
|
assert!(fx.ids().is_empty());
|
||||||
|
assert!(
|
||||||
|
fs::read_to_string(fx.folder.join("a.gpx"))
|
||||||
|
.unwrap()
|
||||||
|
.contains(">a<")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn closing_the_folder_closes_every_file() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
fx.write("a.gpx", "a");
|
||||||
|
fx.open_folder();
|
||||||
|
api::new_file(&mut fx.engine, "fresh", None, None, None, false);
|
||||||
|
assert_eq!(fx.ids().len(), 2);
|
||||||
|
|
||||||
|
// the new file has nowhere to go: it has to be discarded
|
||||||
|
let outcome = fx.workspace.close_folder(&mut fx.engine, false);
|
||||||
|
assert!(outcome.changed);
|
||||||
|
assert_eq!(fx.ids().len(), 1);
|
||||||
|
assert!(fx.workspace.folder.is_none());
|
||||||
|
|
||||||
|
let outcome = fx.workspace.close_folder(&mut fx.engine, true);
|
||||||
|
assert!(outcome.changed);
|
||||||
|
assert!(fx.ids().is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn opening_another_folder_closes_the_first_with_all_its_files() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
fx.write("a.gpx", "a");
|
||||||
|
fx.open_folder();
|
||||||
|
let a = fx.ids()[0];
|
||||||
|
fx.rename(a, "edited");
|
||||||
|
let other = canonical(&std::env::temp_dir()).join(format!("gpx-ws-{}", Uuid::new_v4()));
|
||||||
|
fs::create_dir_all(&other).unwrap();
|
||||||
|
|
||||||
|
// the edits stay, nothing is lost without a choice
|
||||||
|
fx.workspace.open_folder(&mut fx.engine, &other, false);
|
||||||
|
assert_eq!(fx.ids(), [a]);
|
||||||
|
assert_eq!(fx.workspace.folder.as_deref(), Some(other.as_path()));
|
||||||
|
|
||||||
|
let first = fx.folder.clone();
|
||||||
|
fx.workspace.open_folder(&mut fx.engine, &first, true);
|
||||||
|
assert!(fx.ids().is_empty());
|
||||||
|
assert!(
|
||||||
|
fs::read_to_string(fx.folder.join("a.gpx"))
|
||||||
|
.unwrap()
|
||||||
|
.contains(">a<")
|
||||||
|
);
|
||||||
|
fs::remove_dir_all(other).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn opening_the_same_folder_again_changes_nothing() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
fx.write("a.gpx", "a");
|
||||||
|
fx.open_folder();
|
||||||
|
let folder = fx.folder.clone();
|
||||||
|
let outcome = fx.workspace.open_folder(&mut fx.engine, &folder, true);
|
||||||
|
assert!(!outcome.changed);
|
||||||
|
assert_eq!(fx.ids().len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_failed_save_stops_at_the_file_and_leaves_it_dirty() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
fx.write("a.gpx", "a");
|
||||||
|
fx.open_folder();
|
||||||
|
let id = fx.ids()[0];
|
||||||
|
fx.rename(id, "edited");
|
||||||
|
// the place of the file is taken by a folder
|
||||||
|
fs::remove_file(fx.folder.join("a.gpx")).unwrap();
|
||||||
|
fs::create_dir(fx.folder.join("a.gpx")).unwrap();
|
||||||
|
let result = fx
|
||||||
|
.workspace
|
||||||
|
.save(&mut fx.engine, &[id], &BTreeMap::new(), None);
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert!(fx.workspace.is_dirty(&fx.engine, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn saving_as_gives_the_file_another_place() {
|
||||||
|
let mut fx = Fixture::new();
|
||||||
|
let a = fx.write("a.gpx", "a");
|
||||||
|
fx.write("b.gpx", "b");
|
||||||
|
fx.open_folder();
|
||||||
|
let id = fx.id_named("a");
|
||||||
|
let other = fx.id_named("b");
|
||||||
|
fx.rename(id, "edited");
|
||||||
|
|
||||||
|
let target = fx.folder.join("copy.gpx");
|
||||||
|
fx.workspace.save_as(&mut fx.engine, id, &target).unwrap();
|
||||||
|
assert!(fs::read_to_string(&target).unwrap().contains("edited"));
|
||||||
|
assert!(fs::read_to_string(a).unwrap().contains(">a<"));
|
||||||
|
let status = fx.status(id);
|
||||||
|
assert!(!status.dirty);
|
||||||
|
assert_eq!(status.path.as_deref(), canonical(&target).to_str());
|
||||||
|
|
||||||
|
// the place of another open file is not available
|
||||||
|
let taken = fx.folder.join("b.gpx");
|
||||||
|
assert!(fx.workspace.save_as(&mut fx.engine, id, &taken).is_err());
|
||||||
|
assert!(!fx.workspace.is_dirty(&fx.engine, other));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod restart_tests {
|
||||||
|
use gpx_engine::Persister;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::store::FileStorage;
|
||||||
|
|
||||||
|
/// What the app does when it starts again: the engine and the links are read from what was
|
||||||
|
/// kept.
|
||||||
|
fn restart(engine: &Engine, workspace: &Workspace, root: &Path) -> (Engine, Workspace) {
|
||||||
|
let storage = FileStorage::open(root).unwrap();
|
||||||
|
pollster::block_on(Persister::default().save(&storage, engine.snapshot())).unwrap();
|
||||||
|
let mut restarted = Engine::default();
|
||||||
|
let restored = pollster::block_on(Persister::default().restore(&storage)).unwrap();
|
||||||
|
restarted.restore(restored);
|
||||||
|
let links = serde_json::to_string(workspace).unwrap();
|
||||||
|
(restarted, serde_json::from_str(&links).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup() -> (PathBuf, Engine, Workspace, Vec<Uuid>) {
|
||||||
|
let root = std::env::temp_dir().join(format!("gpx-restart-{}", Uuid::new_v4()));
|
||||||
|
let folder = root.join("tracks");
|
||||||
|
fs::create_dir_all(&folder).unwrap();
|
||||||
|
for name in ["with_tracks", "with_time", "with_waypoint"] {
|
||||||
|
let _ = fs::copy(
|
||||||
|
format!("../gpx-rs/data/{name}.gpx"),
|
||||||
|
folder.join(format!("{name}.gpx")),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let mut engine = Engine::default();
|
||||||
|
let mut workspace = Workspace::default();
|
||||||
|
workspace.open_folder(&mut engine, &folder, false);
|
||||||
|
workspace.open_files(&mut engine, &tests::gpx_files(&folder), false);
|
||||||
|
let ids = engine.order().iter().map(|id| id.0).collect();
|
||||||
|
(root, engine, workspace, ids)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn files_that_were_not_edited_are_not_unsaved_after_a_restart() {
|
||||||
|
let (root, engine, workspace, ids) = setup();
|
||||||
|
assert!(ids.len() >= 2);
|
||||||
|
let (restarted, mut workspace) = restart(&engine, &workspace, &root.join("store"));
|
||||||
|
// the files are the same, but the engine knows their contents by new identities
|
||||||
|
assert!(ids.iter().any(|id| workspace.is_dirty(&restarted, *id)));
|
||||||
|
workspace.verify(&restarted);
|
||||||
|
assert!(ids.iter().all(|id| !workspace.is_dirty(&restarted, *id)));
|
||||||
|
fs::remove_dir_all(root).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn files_that_were_edited_are_still_unsaved_after_a_restart() {
|
||||||
|
let (root, mut engine, workspace, ids) = setup();
|
||||||
|
api::select(&mut engine, &[ids[0]], gpx_engine::SelectMode::Replace);
|
||||||
|
api::metadata(&mut engine, "edited", "");
|
||||||
|
assert!(workspace.is_dirty(&engine, ids[0]));
|
||||||
|
let (restarted, mut workspace) = restart(&engine, &workspace, &root.join("store"));
|
||||||
|
workspace.verify(&restarted);
|
||||||
|
assert!(workspace.is_dirty(&restarted, ids[0]));
|
||||||
|
assert!(
|
||||||
|
ids[1..]
|
||||||
|
.iter()
|
||||||
|
.all(|id| !workspace.is_dirty(&restarted, *id))
|
||||||
|
);
|
||||||
|
fs::remove_dir_all(root).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn links_made_before_the_content_was_kept_are_checked_against_the_disk() {
|
||||||
|
let (root, mut engine, mut workspace, ids) = setup();
|
||||||
|
api::select(&mut engine, &[ids[0]], gpx_engine::SelectMode::Replace);
|
||||||
|
api::metadata(&mut engine, "edited", "");
|
||||||
|
for link in workspace.links.values_mut() {
|
||||||
|
link.export_hash = 0;
|
||||||
|
}
|
||||||
|
let (restarted, mut workspace) = restart(&engine, &workspace, &root.join("store"));
|
||||||
|
workspace.verify(&restarted);
|
||||||
|
assert!(workspace.is_dirty(&restarted, ids[0]));
|
||||||
|
assert!(
|
||||||
|
ids[1..]
|
||||||
|
.iter()
|
||||||
|
.all(|id| !workspace.is_dirty(&restarted, *id))
|
||||||
|
);
|
||||||
|
fs::remove_dir_all(root).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn the_folders_of_new_files_and_the_old_flag_name_survive_a_restart() {
|
||||||
|
let (root, engine, mut workspace, ids) = setup();
|
||||||
|
let folder = workspace.folder.clone().unwrap();
|
||||||
|
let fresh = Uuid::new_v4();
|
||||||
|
workspace.inherit(&[fresh.to_string()], &folder);
|
||||||
|
workspace.links.get_mut(&ids[0]).unwrap().replaced = true;
|
||||||
|
let json = serde_json::to_string(&workspace).unwrap();
|
||||||
|
// links written by the previous version had `conflict`, which is the same thing
|
||||||
|
let json = json.replace("\"replaced\"", "\"conflict\"");
|
||||||
|
assert!(json.contains("\"conflict\":true"));
|
||||||
|
let read: Workspace = serde_json::from_str(&json).unwrap();
|
||||||
|
assert!(read.links[&ids[0]].replaced);
|
||||||
|
assert_eq!(read.dirs.get(&fresh), Some(&folder));
|
||||||
|
let _ = engine;
|
||||||
|
fs::remove_dir_all(root).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
//! The tests of the desktop app. They are integration tests, in a single binary, rather than unit
|
|
||||||
//! tests: on Windows, only test binaries can be given the manifest that the app needs to start
|
|
||||||
//! (see `build.rs`).
|
|
||||||
|
|
||||||
mod commands;
|
|
||||||
mod store;
|
|
||||||
mod workspace;
|
|
||||||
|
|
||||||
use gpx_studio_desktop_lib::state::AppState;
|
|
||||||
|
|
||||||
/// An engine that keeps its data in a directory of its own, and has nobody to tell.
|
|
||||||
fn temporary_state() -> AppState {
|
|
||||||
let directory = std::env::temp_dir().join(format!("gpx-studio-{}", uuid::Uuid::new_v4()));
|
|
||||||
AppState::open(directory, std::sync::Arc::new(|_, _| {})).expect("the storage can be opened")
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
//! The storage of the engine on the file system (`store`).
|
|
||||||
|
|
||||||
use std::fs;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use gpx_engine::{
|
|
||||||
Action, Batch, Command, CommitError, Load, LoadFiles, Persister, Revision, Storage,
|
|
||||||
};
|
|
||||||
use gpx_studio_desktop_lib::Engine;
|
|
||||||
use gpx_studio_desktop_lib::store::FileStorage;
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
fn directory() -> PathBuf {
|
|
||||||
std::env::temp_dir().join(format!("gpx-studio-store-{}", Uuid::new_v4()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn engine_with_a_file() -> Engine {
|
|
||||||
let mut engine = Engine::default();
|
|
||||||
let data = std::fs::read("../gpx-rs/data/simple.gpx").unwrap();
|
|
||||||
engine
|
|
||||||
.execute(Action::Edit(Command::LoadFiles(LoadFiles {
|
|
||||||
files: vec![Load {
|
|
||||||
data: &data,
|
|
||||||
name: "simple",
|
|
||||||
}],
|
|
||||||
})))
|
|
||||||
.unwrap();
|
|
||||||
engine
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn keeps_the_files_and_the_settings_between_sessions() {
|
|
||||||
let root = directory();
|
|
||||||
let engine = engine_with_a_file();
|
|
||||||
let order = engine.order().to_vec();
|
|
||||||
|
|
||||||
let storage = FileStorage::open(&root).unwrap();
|
|
||||||
pollster::block_on(Persister::default().save(&storage, engine.snapshot())).unwrap();
|
|
||||||
pollster::block_on(storage.put_setting("units", "\"metric\"")).unwrap();
|
|
||||||
|
|
||||||
// another session
|
|
||||||
let storage = FileStorage::open(&root).unwrap();
|
|
||||||
let restored = pollster::block_on(Persister::default().restore(&storage)).unwrap();
|
|
||||||
let mut other = Engine::default();
|
|
||||||
other.restore(restored);
|
|
||||||
assert_eq!(other.order(), order);
|
|
||||||
assert_eq!(
|
|
||||||
other.file_statistics(&order[0]).unwrap().total_distance,
|
|
||||||
engine.file_statistics(&order[0]).unwrap().total_distance
|
|
||||||
);
|
|
||||||
assert_eq!(storage.settings()["units"], "\"metric\"");
|
|
||||||
fs::remove_dir_all(root).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn refuses_a_commit_that_is_not_based_on_the_head() {
|
|
||||||
let root = directory();
|
|
||||||
let storage = FileStorage::open(&root).unwrap();
|
|
||||||
let batch = Batch {
|
|
||||||
order: Some(vec![]),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
assert_eq!(pollster::block_on(storage.commit(&batch)), Ok(Revision(1)));
|
|
||||||
assert_eq!(
|
|
||||||
pollster::block_on(storage.commit(&batch)),
|
|
||||||
Err(CommitError::Stale { head: Revision(1) })
|
|
||||||
);
|
|
||||||
fs::remove_dir_all(root).unwrap();
|
|
||||||
}
|
|
||||||
@@ -1,811 +0,0 @@
|
|||||||
//! The places of the files of the engine on the disk (`workspace`).
|
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::fs;
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
|
|
||||||
use gpx_engine::{FileId, SelectMode, api};
|
|
||||||
use gpx_studio_desktop_lib::Engine;
|
|
||||||
use gpx_studio_desktop_lib::workspace::*;
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
fn gpx(name: &str) -> String {
|
|
||||||
format!(
|
|
||||||
r#"<?xml version="1.0"?><gpx version="1.1" creator="test" xmlns="http://www.topografix.com/GPX/1/1"><metadata><name>{name}</name></metadata><trk><name>{name}</name><trkseg><trkpt lat="50.0" lon="4.0"><ele>10</ele></trkpt><trkpt lat="50.1" lon="4.1"><ele>20</ele></trkpt></trkseg></trk></gpx>"#
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The GPX files of a folder and of the folders in it.
|
|
||||||
pub fn gpx_files(folder: &Path) -> Vec<PathBuf> {
|
|
||||||
let mut found = vec![];
|
|
||||||
for entry in fs::read_dir(folder).unwrap().flatten() {
|
|
||||||
let path = entry.path();
|
|
||||||
if path.is_dir() {
|
|
||||||
found.extend(gpx_files(&path));
|
|
||||||
} else if is_gpx(&path) {
|
|
||||||
found.push(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
found.sort();
|
|
||||||
found
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Fixture {
|
|
||||||
folder: PathBuf,
|
|
||||||
engine: Engine,
|
|
||||||
workspace: Workspace,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Fixture {
|
|
||||||
fn new() -> Self {
|
|
||||||
let folder = canonical(&std::env::temp_dir()).join(format!("gpx-ws-{}", Uuid::new_v4()));
|
|
||||||
fs::create_dir_all(&folder).unwrap();
|
|
||||||
Self {
|
|
||||||
folder,
|
|
||||||
engine: Engine::default(),
|
|
||||||
workspace: Workspace::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&self, name: &str, title: &str) -> PathBuf {
|
|
||||||
let path = self.folder.join(name);
|
|
||||||
fs::write(&path, gpx(title)).unwrap();
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Opens the folder, and all the files that are in it.
|
|
||||||
fn open_folder(&mut self) {
|
|
||||||
let folder = self.folder.clone();
|
|
||||||
self.workspace.open_folder(&mut self.engine, &folder, false);
|
|
||||||
let files = gpx_files(&folder);
|
|
||||||
self.workspace.open_files(&mut self.engine, &files, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reconcile(&mut self, changed: Option<&[PathBuf]>) -> Option<api::Outcome> {
|
|
||||||
self.workspace.reconcile(&mut self.engine, changed)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn save(&mut self, ids: &[Uuid]) {
|
|
||||||
self.workspace
|
|
||||||
.save(&mut self.engine, ids, &BTreeMap::new(), None)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ids(&self) -> Vec<Uuid> {
|
|
||||||
self.engine.order().iter().map(|id| id.0).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn id_named(&self, name: &str) -> Uuid {
|
|
||||||
self.ids()
|
|
||||||
.into_iter()
|
|
||||||
.find(|id| self.name(*id) == name)
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name(&self, id: Uuid) -> String {
|
|
||||||
self.engine
|
|
||||||
.file_structure(&FileId(id))
|
|
||||||
.unwrap()
|
|
||||||
.name
|
|
||||||
.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// What the file holds: the name of its track (its own name is the one of the file).
|
|
||||||
fn content(&self, id: Uuid) -> String {
|
|
||||||
self.engine.file_structure(&FileId(id)).unwrap().tracks[0]
|
|
||||||
.info
|
|
||||||
.name
|
|
||||||
.clone()
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rename(&mut self, id: Uuid, name: &str) {
|
|
||||||
api::select(&mut self.engine, &[id], SelectMode::Replace);
|
|
||||||
assert!(!api::metadata(&mut self.engine, name, "").has_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn status(&self, id: Uuid) -> FileStatus {
|
|
||||||
self.workspace
|
|
||||||
.state(&self.engine)
|
|
||||||
.files
|
|
||||||
.remove(&id.to_string())
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Fixture {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let _ = fs::remove_dir_all(&self.folder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn an_opened_file_is_clean_until_it_is_edited_and_clean_again_once_saved() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
let path = fx.write("a.gpx", "a");
|
|
||||||
fx.workspace
|
|
||||||
.open_files(&mut fx.engine, std::slice::from_ref(&path), true);
|
|
||||||
let id = fx.ids()[0];
|
|
||||||
assert!(!fx.workspace.is_dirty(&fx.engine, id));
|
|
||||||
assert_eq!(fx.status(id).path.as_deref(), path.to_str());
|
|
||||||
|
|
||||||
fx.rename(id, "renamed");
|
|
||||||
assert!(fx.workspace.is_dirty(&fx.engine, id));
|
|
||||||
// nothing is written before it is saved
|
|
||||||
assert!(fs::read_to_string(&path).unwrap().contains(">a<"));
|
|
||||||
|
|
||||||
fx.save(&[id]);
|
|
||||||
assert!(!fx.workspace.is_dirty(&fx.engine, id));
|
|
||||||
assert!(fs::read_to_string(&path).unwrap().contains(">renamed<"));
|
|
||||||
|
|
||||||
// going back before the save is an edit again
|
|
||||||
api::select(&mut fx.engine, &[id], SelectMode::Replace);
|
|
||||||
api::undo(&mut fx.engine);
|
|
||||||
assert!(fx.workspace.is_dirty(&fx.engine, id));
|
|
||||||
api::redo(&mut fx.engine);
|
|
||||||
assert!(!fx.workspace.is_dirty(&fx.engine, id));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn a_file_that_is_not_on_the_disk_is_unsaved_until_it_is_given_a_place() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
api::new_file(&mut fx.engine, "fresh", None, None, None, false);
|
|
||||||
let id = fx.ids()[0];
|
|
||||||
assert!(fx.workspace.is_dirty(&fx.engine, id));
|
|
||||||
assert_eq!(
|
|
||||||
fx.workspace.unlinked(&fx.engine, &[id]),
|
|
||||||
[(id, "fresh".to_string())]
|
|
||||||
);
|
|
||||||
// nowhere to put it without being told
|
|
||||||
fx.save(&[id]);
|
|
||||||
assert!(fx.workspace.is_dirty(&fx.engine, id));
|
|
||||||
|
|
||||||
let path = fx.folder.join("fresh.gpx");
|
|
||||||
let paths = BTreeMap::from([(id, path.clone())]);
|
|
||||||
fx.workspace
|
|
||||||
.save(&mut fx.engine, &[id], &paths, None)
|
|
||||||
.unwrap();
|
|
||||||
assert!(path.exists());
|
|
||||||
assert!(!fx.workspace.is_dirty(&fx.engine, id));
|
|
||||||
assert!(fx.workspace.unlinked(&fx.engine, &[id]).is_empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn several_files_without_a_place_go_in_a_folder_with_names_that_are_free() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
fx.write("fresh.gpx", "already there");
|
|
||||||
api::new_file(&mut fx.engine, "fresh", None, None, None, false);
|
|
||||||
api::new_file(&mut fx.engine, "a/b: c", None, None, None, false);
|
|
||||||
api::new_file(&mut fx.engine, "fresh", None, None, None, false);
|
|
||||||
let ids = fx.ids();
|
|
||||||
let folder = fx.folder.clone();
|
|
||||||
fx.workspace
|
|
||||||
.save(&mut fx.engine, &ids, &BTreeMap::new(), Some(&folder))
|
|
||||||
.unwrap();
|
|
||||||
for name in ["fresh (2).gpx", "fresh (3).gpx", "a_b_ c.gpx"] {
|
|
||||||
assert!(fx.folder.join(name).exists(), "{name}");
|
|
||||||
}
|
|
||||||
assert!(ids.iter().all(|id| !fx.workspace.is_dirty(&fx.engine, *id)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn what_this_app_writes_is_not_a_change_of_the_disk() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
let path = fx.write("a.gpx", "a");
|
|
||||||
fx.open_folder();
|
|
||||||
let id = fx.ids()[0];
|
|
||||||
api::select(&mut fx.engine, &[id], SelectMode::Replace);
|
|
||||||
assert!(!api::style(&mut fx.engine, Some("#ff0000"), None, None).has_error());
|
|
||||||
fx.save(&[id]);
|
|
||||||
assert!(fx.reconcile(Some(&[path])).is_none());
|
|
||||||
assert!(!fx.status(id).replaced && !fx.status(id).dirty);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn the_folders_of_the_files_outside_the_open_folder_are_watched_too() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
let inside = fx.write("in.gpx", "in");
|
|
||||||
let elsewhere = canonical(&std::env::temp_dir()).join(format!("gpx-ws-{}", Uuid::new_v4()));
|
|
||||||
fs::create_dir_all(&elsewhere).unwrap();
|
|
||||||
let (one, two) = (elsewhere.join("one.gpx"), elsewhere.join("two.gpx"));
|
|
||||||
fs::write(&one, gpx("one")).unwrap();
|
|
||||||
fs::write(&two, gpx("two")).unwrap();
|
|
||||||
let folder = fx.folder.clone();
|
|
||||||
|
|
||||||
// no folder: only the folder of the files
|
|
||||||
fx.workspace.open_files(&mut fx.engine, &[one, two], false);
|
|
||||||
assert_eq!(fx.workspace.watched(), [(elsewhere.clone(), false)]);
|
|
||||||
|
|
||||||
// the open folder as a whole, and the file in it needs nothing more
|
|
||||||
fx.workspace.open_folder(&mut fx.engine, &folder, false);
|
|
||||||
fx.workspace.open_files(&mut fx.engine, &[inside], false);
|
|
||||||
assert_eq!(
|
|
||||||
fx.workspace.watched(),
|
|
||||||
[(folder, true), (elsewhere.clone(), false)]
|
|
||||||
);
|
|
||||||
|
|
||||||
// closing the files stops it
|
|
||||||
let ids = fx.ids();
|
|
||||||
fx.workspace.close_files(&mut fx.engine, &ids, true);
|
|
||||||
assert_eq!(fx.workspace.watched(), [(fx.folder.clone(), true)]);
|
|
||||||
fs::remove_dir_all(elsewhere).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn opening_a_folder_does_not_open_its_files() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
fx.write("a.gpx", "a");
|
|
||||||
let folder = fx.folder.clone();
|
|
||||||
let outcome = fx.workspace.open_folder(&mut fx.engine, &folder, false);
|
|
||||||
assert!(!outcome.changed);
|
|
||||||
assert!(fx.ids().is_empty());
|
|
||||||
assert_eq!(fx.workspace.folder.as_deref(), Some(folder.as_path()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn folders_are_made_renamed_and_moved_and_the_open_files_follow() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
let a = fx.write("a.gpx", "a");
|
|
||||||
fx.open_folder();
|
|
||||||
let id = fx.ids()[0];
|
|
||||||
let root = fx.folder.clone();
|
|
||||||
let path_of = |fx: &Fixture| PathBuf::from(fx.status(id).path.unwrap());
|
|
||||||
|
|
||||||
let first = fx.workspace.create_folder(&root, "New folder").unwrap();
|
|
||||||
let second = fx.workspace.create_folder(&root, "New folder").unwrap();
|
|
||||||
assert_eq!(first, root.join("New folder"));
|
|
||||||
assert_eq!(second, root.join("New folder 2"));
|
|
||||||
|
|
||||||
fx.workspace.move_paths(&[a], &first).unwrap();
|
|
||||||
assert_eq!(path_of(&fx), first.join("a.gpx"));
|
|
||||||
assert!(first.join("a.gpx").exists() && !fx.status(id).dirty);
|
|
||||||
|
|
||||||
let trips = fx.workspace.rename_path(&first, "Trips").unwrap();
|
|
||||||
assert_eq!(path_of(&fx), root.join("Trips/a.gpx"));
|
|
||||||
// a folder does not go into itself, nor onto something else
|
|
||||||
assert!(
|
|
||||||
fx.workspace
|
|
||||||
.move_paths(std::slice::from_ref(&trips), &trips)
|
|
||||||
.is_err()
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
fx.workspace.rename_path(&trips, "New folder 2"),
|
|
||||||
Err(NAME_TAKEN.to_owned())
|
|
||||||
);
|
|
||||||
fx.workspace.move_paths(&[trips], &second).unwrap();
|
|
||||||
assert_eq!(path_of(&fx), second.join("Trips/a.gpx"));
|
|
||||||
|
|
||||||
// a file keeps its extension
|
|
||||||
let closed = fx.write("c.gpx", "c");
|
|
||||||
assert_eq!(
|
|
||||||
fx.workspace.rename_path(&closed, "d").unwrap(),
|
|
||||||
root.join("d.gpx")
|
|
||||||
);
|
|
||||||
// the open folder and what is not in it are left alone
|
|
||||||
assert!(fx.workspace.rename_path(&root, "x").is_err());
|
|
||||||
let elsewhere = canonical(&std::env::temp_dir());
|
|
||||||
assert!(fx.workspace.rename_path(&elsewhere, "x").is_err());
|
|
||||||
assert!(fx.workspace.create_folder(&elsewhere, "x").is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deleted_files_are_closed_unless_they_have_edits() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
let a = fx.write("a.gpx", "a");
|
|
||||||
let b = fx.write("b.gpx", "b");
|
|
||||||
fx.open_folder();
|
|
||||||
let (id_a, id_b) = (fx.id_named("a"), fx.id_named("b"));
|
|
||||||
api::select(&mut fx.engine, &[id_b], SelectMode::Replace);
|
|
||||||
assert!(!api::style(&mut fx.engine, Some("#ff0000"), None, None).has_error());
|
|
||||||
|
|
||||||
let outcome = fx
|
|
||||||
.workspace
|
|
||||||
.delete_paths(&mut fx.engine, &[a.clone(), b.clone()], |paths| {
|
|
||||||
paths.iter().for_each(|path| fs::remove_file(path).unwrap());
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
assert!(outcome.changed);
|
|
||||||
assert_eq!(fx.ids(), [id_b]);
|
|
||||||
assert!(!fx.ids().contains(&id_a));
|
|
||||||
let status = fx.status(id_b);
|
|
||||||
assert!(status.dirty && status.missing);
|
|
||||||
assert!(!a.exists() && !b.exists());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn the_tree_of_the_folder_shows_folders_first_and_only_gpx_files() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
fx.write("b.gpx", "b");
|
|
||||||
fx.write("A.GPX", "a");
|
|
||||||
fx.write("b 10.gpx", "b 10");
|
|
||||||
fx.write("b 2.gpx", "b 2");
|
|
||||||
fx.write("notes.txt", "not a track");
|
|
||||||
fx.write(".hidden.gpx", "hidden");
|
|
||||||
fs::create_dir(fx.folder.join("zoo")).unwrap();
|
|
||||||
fs::create_dir(fx.folder.join("Alps")).unwrap();
|
|
||||||
fs::create_dir(fx.folder.join(".git")).unwrap();
|
|
||||||
fx.write("zoo/c.gpx", "c");
|
|
||||||
let folder = fx.folder.clone();
|
|
||||||
fx.workspace.open_folder(&mut fx.engine, &folder, false);
|
|
||||||
|
|
||||||
let names = |entries: Vec<Entry>| -> Vec<(String, bool)> {
|
|
||||||
entries.into_iter().map(|e| (e.name, e.is_dir)).collect()
|
|
||||||
};
|
|
||||||
assert_eq!(
|
|
||||||
names(fx.workspace.list_folder(&folder).unwrap()),
|
|
||||||
[
|
|
||||||
("Alps".to_string(), true),
|
|
||||||
("zoo".to_string(), true),
|
|
||||||
("A.GPX".to_string(), false),
|
|
||||||
("b.gpx".to_string(), false),
|
|
||||||
("b 2.gpx".to_string(), false),
|
|
||||||
("b 10.gpx".to_string(), false),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
names(fx.workspace.list_folder(&folder.join("zoo")).unwrap()),
|
|
||||||
[("c.gpx".to_string(), false)]
|
|
||||||
);
|
|
||||||
// only what is in the open folder can be listed
|
|
||||||
let elsewhere = canonical(&std::env::temp_dir());
|
|
||||||
assert!(fx.workspace.list_folder(&elsewhere).is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn names_are_sorted_by_the_numbers_they_hold() {
|
|
||||||
let mut names = vec![
|
|
||||||
"track 10",
|
|
||||||
"track 2",
|
|
||||||
"Track 1",
|
|
||||||
"track",
|
|
||||||
"track 02b",
|
|
||||||
"track 2a",
|
|
||||||
"b",
|
|
||||||
"A",
|
|
||||||
];
|
|
||||||
names.sort_by(|a, b| natural_cmp(a, b).then_with(|| a.cmp(b)));
|
|
||||||
assert_eq!(
|
|
||||||
names,
|
|
||||||
[
|
|
||||||
"A",
|
|
||||||
"b",
|
|
||||||
"track",
|
|
||||||
"Track 1",
|
|
||||||
"track 2",
|
|
||||||
"track 2a",
|
|
||||||
"track 02b",
|
|
||||||
"track 10",
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn a_file_without_edits_is_read_again_when_the_disk_changes() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
let a = fx.write("a.gpx", "a");
|
|
||||||
fx.open_folder();
|
|
||||||
let id = fx.ids()[0];
|
|
||||||
|
|
||||||
fx.write("a.gpx", "theirs");
|
|
||||||
let outcome = fx.reconcile(Some(std::slice::from_ref(&a))).unwrap();
|
|
||||||
assert!(outcome.changed);
|
|
||||||
// the same file, now the one on the disk
|
|
||||||
assert_eq!(fx.ids(), [id]);
|
|
||||||
assert_eq!(fx.content(id), "theirs");
|
|
||||||
let status = fx.status(id);
|
|
||||||
assert!(!status.dirty && !status.replaced);
|
|
||||||
// looking again changes nothing
|
|
||||||
assert!(fx.reconcile(Some(std::slice::from_ref(&a))).is_none());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn a_file_with_edits_is_flagged_when_the_disk_changes_and_not_read_again() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
let a = fx.write("a.gpx", "a");
|
|
||||||
fx.open_folder();
|
|
||||||
let id = fx.ids()[0];
|
|
||||||
fx.rename(id, "mine");
|
|
||||||
|
|
||||||
fx.write("a.gpx", "theirs");
|
|
||||||
let outcome = fx.reconcile(Some(std::slice::from_ref(&a))).unwrap();
|
|
||||||
assert!(!outcome.changed);
|
|
||||||
assert_eq!(fx.name(id), "mine");
|
|
||||||
let status = fx.status(id);
|
|
||||||
assert!(status.dirty && status.replaced && !status.missing);
|
|
||||||
// looking again changes nothing
|
|
||||||
assert!(fx.reconcile(Some(std::slice::from_ref(&a))).is_none());
|
|
||||||
|
|
||||||
// the disk goes back to what was read: only the edits are left
|
|
||||||
fx.write("a.gpx", "a");
|
|
||||||
assert!(fx.reconcile(Some(std::slice::from_ref(&a))).is_some());
|
|
||||||
let status = fx.status(id);
|
|
||||||
assert!(status.dirty && !status.replaced);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn the_user_can_take_the_disk_instead_of_the_edits() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
fx.write("a.gpx", "a");
|
|
||||||
fx.open_folder();
|
|
||||||
let id = fx.ids()[0];
|
|
||||||
fx.rename(id, "mine");
|
|
||||||
fx.write("a.gpx", "theirs");
|
|
||||||
fx.reconcile(None);
|
|
||||||
assert!(fx.status(id).replaced);
|
|
||||||
|
|
||||||
fx.workspace.reload(&mut fx.engine, &[id]).unwrap();
|
|
||||||
assert_eq!(fx.content(id), "theirs");
|
|
||||||
let status = fx.status(id);
|
|
||||||
assert!(!status.dirty && !status.replaced);
|
|
||||||
// and it is one undo step
|
|
||||||
api::select(&mut fx.engine, &[id], SelectMode::Replace);
|
|
||||||
api::undo(&mut fx.engine);
|
|
||||||
assert_eq!(fx.content(id), "mine");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn saving_overwrites_what_replaced_the_file() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
let a = fx.write("a.gpx", "a");
|
|
||||||
fx.open_folder();
|
|
||||||
let id = fx.ids()[0];
|
|
||||||
fx.rename(id, "mine");
|
|
||||||
fx.write("a.gpx", "theirs");
|
|
||||||
fx.reconcile(None);
|
|
||||||
assert!(fx.status(id).replaced);
|
|
||||||
|
|
||||||
fx.save(&[id]);
|
|
||||||
assert!(fs::read_to_string(a).unwrap().contains(">mine<"));
|
|
||||||
assert!(!fx.status(id).replaced && !fx.status(id).dirty);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn a_file_that_is_gone_from_the_disk_stays_open_and_dirty_until_it_is_saved_again() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
let a = fx.write("a.gpx", "a");
|
|
||||||
fx.open_folder();
|
|
||||||
let id = fx.ids()[0];
|
|
||||||
|
|
||||||
fs::remove_file(&a).unwrap();
|
|
||||||
assert!(fx.reconcile(Some(std::slice::from_ref(&a))).is_some());
|
|
||||||
assert_eq!(fx.ids(), [id]);
|
|
||||||
let status = fx.status(id);
|
|
||||||
assert!(status.dirty && status.missing && status.path.is_some());
|
|
||||||
|
|
||||||
// saving puts it back
|
|
||||||
fx.save(&[id]);
|
|
||||||
assert!(a.exists());
|
|
||||||
let status = fx.status(id);
|
|
||||||
assert!(!status.dirty && !status.missing);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn a_file_that_comes_back_different_is_read_again() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
let a = fx.write("a.gpx", "a");
|
|
||||||
fx.open_folder();
|
|
||||||
let id = fx.ids()[0];
|
|
||||||
fs::remove_file(&a).unwrap();
|
|
||||||
fx.reconcile(None);
|
|
||||||
assert!(fx.status(id).missing);
|
|
||||||
|
|
||||||
fx.write("a.gpx", "back");
|
|
||||||
fx.reconcile(None);
|
|
||||||
assert_eq!(fx.content(id), "back");
|
|
||||||
let status = fx.status(id);
|
|
||||||
assert!(!status.dirty && !status.missing);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn what_changed_while_the_app_was_closed_is_found_when_it_starts() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
let a = fx.write("a.gpx", "a");
|
|
||||||
fx.open_folder();
|
|
||||||
let id = fx.ids()[0];
|
|
||||||
fx.write("a.gpx", "changed");
|
|
||||||
assert!(fx.reconcile(None).is_some());
|
|
||||||
assert_eq!(fx.content(id), "changed");
|
|
||||||
fs::remove_file(a).unwrap();
|
|
||||||
assert!(fx.reconcile(None).is_some());
|
|
||||||
assert!(fx.status(id).missing);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn new_files_made_from_a_file_of_the_folder_are_saved_next_to_it() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
fs::create_dir(fx.folder.join("sub")).unwrap();
|
|
||||||
fx.write("sub/b.gpx", "b");
|
|
||||||
fx.write("a.gpx", "a");
|
|
||||||
fx.open_folder();
|
|
||||||
let b = fx.id_named("b");
|
|
||||||
let sub = fx.folder.join("sub");
|
|
||||||
assert_eq!(fx.workspace.source_dir(&[b]), Some(canonical(&sub)));
|
|
||||||
|
|
||||||
let before = fx.ids();
|
|
||||||
api::select(&mut fx.engine, &[b], SelectMode::Replace);
|
|
||||||
let outcome = api::duplicate(&mut fx.engine);
|
|
||||||
let copy = fx
|
|
||||||
.ids()
|
|
||||||
.into_iter()
|
|
||||||
.find(|id| !before.contains(id))
|
|
||||||
.unwrap();
|
|
||||||
fx.workspace.inherit(outcome.added(), &canonical(&sub));
|
|
||||||
assert_eq!(fx.status(copy).folder.as_deref(), canonical(&sub).to_str());
|
|
||||||
assert!(fx.status(copy).path.is_none() && fx.status(copy).dirty);
|
|
||||||
// nobody needs to be asked where it goes
|
|
||||||
assert!(fx.workspace.unlinked(&fx.engine, &[copy]).is_empty());
|
|
||||||
|
|
||||||
fx.save(&[copy]);
|
|
||||||
assert!(sub.join("b (2).gpx").exists());
|
|
||||||
let status = fx.status(copy);
|
|
||||||
assert!(!status.dirty && status.folder.is_none());
|
|
||||||
assert_eq!(
|
|
||||||
status.path.as_deref(),
|
|
||||||
canonical(&sub.join("b (2).gpx")).to_str()
|
|
||||||
);
|
|
||||||
// the copy of the copy is next to it as well
|
|
||||||
assert_eq!(fx.workspace.source_dir(&[copy]), Some(canonical(&sub)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn a_file_outside_the_open_folder_hands_nothing_down() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
let elsewhere = canonical(&std::env::temp_dir()).join(format!("gpx-ws-{}", Uuid::new_v4()));
|
|
||||||
fs::create_dir_all(&elsewhere).unwrap();
|
|
||||||
let outside = elsewhere.join("o.gpx");
|
|
||||||
fs::write(&outside, gpx("o")).unwrap();
|
|
||||||
let folder = fx.folder.clone();
|
|
||||||
fx.workspace.open_folder(&mut fx.engine, &folder, false);
|
|
||||||
fx.workspace
|
|
||||||
.open_files(&mut fx.engine, std::slice::from_ref(&outside), true);
|
|
||||||
let id = fx.ids()[0];
|
|
||||||
assert_eq!(fx.workspace.source_dir(&[id]), None);
|
|
||||||
// a new file with no source is not linked to a folder by `source_dir`: the caller falls back
|
|
||||||
fs::remove_dir_all(elsewhere).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn closing_files_asks_what_to_do_with_the_unsaved_ones() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
fx.write("a.gpx", "a");
|
|
||||||
fx.write("b.gpx", "b");
|
|
||||||
fx.open_folder();
|
|
||||||
let (a, b) = (fx.id_named("a"), fx.id_named("b"));
|
|
||||||
fx.rename(a, "edited");
|
|
||||||
assert_eq!(fx.workspace.unsaved(&fx.engine, &[a, b]), [a]);
|
|
||||||
|
|
||||||
// without a choice what has edits stays
|
|
||||||
let outcome = fx.workspace.close_files(&mut fx.engine, &[a, b], false);
|
|
||||||
assert!(outcome.changed);
|
|
||||||
assert_eq!(fx.ids(), [a]);
|
|
||||||
|
|
||||||
// saved first
|
|
||||||
fx.save(&[a]);
|
|
||||||
fx.workspace.close_files(&mut fx.engine, &[a], false);
|
|
||||||
assert!(fx.ids().is_empty());
|
|
||||||
assert!(
|
|
||||||
fs::read_to_string(fx.folder.join("a.gpx"))
|
|
||||||
.unwrap()
|
|
||||||
.contains("edited")
|
|
||||||
);
|
|
||||||
assert!(fx.workspace.links.is_empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn closing_files_can_discard_their_edits() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
fx.write("a.gpx", "a");
|
|
||||||
fx.open_folder();
|
|
||||||
let a = fx.ids()[0];
|
|
||||||
fx.rename(a, "edited");
|
|
||||||
api::new_file(&mut fx.engine, "fresh", None, None, None, false);
|
|
||||||
let fresh = fx.id_named("fresh");
|
|
||||||
fx.workspace.close_files(&mut fx.engine, &[a, fresh], true);
|
|
||||||
assert!(fx.ids().is_empty());
|
|
||||||
assert!(
|
|
||||||
fs::read_to_string(fx.folder.join("a.gpx"))
|
|
||||||
.unwrap()
|
|
||||||
.contains(">a<")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn closing_the_folder_closes_every_file() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
fx.write("a.gpx", "a");
|
|
||||||
fx.open_folder();
|
|
||||||
api::new_file(&mut fx.engine, "fresh", None, None, None, false);
|
|
||||||
assert_eq!(fx.ids().len(), 2);
|
|
||||||
|
|
||||||
// the new file has nowhere to go: it has to be discarded
|
|
||||||
let outcome = fx.workspace.close_folder(&mut fx.engine, false);
|
|
||||||
assert!(outcome.changed);
|
|
||||||
assert_eq!(fx.ids().len(), 1);
|
|
||||||
assert!(fx.workspace.folder.is_none());
|
|
||||||
|
|
||||||
let outcome = fx.workspace.close_folder(&mut fx.engine, true);
|
|
||||||
assert!(outcome.changed);
|
|
||||||
assert!(fx.ids().is_empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn opening_another_folder_closes_the_first_with_all_its_files() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
fx.write("a.gpx", "a");
|
|
||||||
fx.open_folder();
|
|
||||||
let a = fx.ids()[0];
|
|
||||||
fx.rename(a, "edited");
|
|
||||||
let other = canonical(&std::env::temp_dir()).join(format!("gpx-ws-{}", Uuid::new_v4()));
|
|
||||||
fs::create_dir_all(&other).unwrap();
|
|
||||||
|
|
||||||
// the edits stay, nothing is lost without a choice
|
|
||||||
fx.workspace.open_folder(&mut fx.engine, &other, false);
|
|
||||||
assert_eq!(fx.ids(), [a]);
|
|
||||||
assert_eq!(fx.workspace.folder.as_deref(), Some(other.as_path()));
|
|
||||||
|
|
||||||
let first = fx.folder.clone();
|
|
||||||
fx.workspace.open_folder(&mut fx.engine, &first, true);
|
|
||||||
assert!(fx.ids().is_empty());
|
|
||||||
assert!(
|
|
||||||
fs::read_to_string(fx.folder.join("a.gpx"))
|
|
||||||
.unwrap()
|
|
||||||
.contains(">a<")
|
|
||||||
);
|
|
||||||
fs::remove_dir_all(other).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn opening_the_same_folder_again_changes_nothing() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
fx.write("a.gpx", "a");
|
|
||||||
fx.open_folder();
|
|
||||||
let folder = fx.folder.clone();
|
|
||||||
let outcome = fx.workspace.open_folder(&mut fx.engine, &folder, true);
|
|
||||||
assert!(!outcome.changed);
|
|
||||||
assert_eq!(fx.ids().len(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn a_failed_save_stops_at_the_file_and_leaves_it_dirty() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
fx.write("a.gpx", "a");
|
|
||||||
fx.open_folder();
|
|
||||||
let id = fx.ids()[0];
|
|
||||||
fx.rename(id, "edited");
|
|
||||||
// the place of the file is taken by a folder
|
|
||||||
fs::remove_file(fx.folder.join("a.gpx")).unwrap();
|
|
||||||
fs::create_dir(fx.folder.join("a.gpx")).unwrap();
|
|
||||||
let result = fx
|
|
||||||
.workspace
|
|
||||||
.save(&mut fx.engine, &[id], &BTreeMap::new(), None);
|
|
||||||
assert!(result.is_err());
|
|
||||||
assert!(fx.workspace.is_dirty(&fx.engine, id));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn saving_as_gives_the_file_another_place() {
|
|
||||||
let mut fx = Fixture::new();
|
|
||||||
let a = fx.write("a.gpx", "a");
|
|
||||||
fx.write("b.gpx", "b");
|
|
||||||
fx.open_folder();
|
|
||||||
let id = fx.id_named("a");
|
|
||||||
let other = fx.id_named("b");
|
|
||||||
fx.rename(id, "edited");
|
|
||||||
|
|
||||||
let target = fx.folder.join("copy.gpx");
|
|
||||||
fx.workspace.save_as(&mut fx.engine, id, &target).unwrap();
|
|
||||||
assert!(fs::read_to_string(&target).unwrap().contains("edited"));
|
|
||||||
assert!(fs::read_to_string(a).unwrap().contains(">a<"));
|
|
||||||
let status = fx.status(id);
|
|
||||||
assert!(!status.dirty);
|
|
||||||
assert_eq!(status.path.as_deref(), canonical(&target).to_str());
|
|
||||||
|
|
||||||
// the place of another open file is not available
|
|
||||||
let taken = fx.folder.join("b.gpx");
|
|
||||||
assert!(fx.workspace.save_as(&mut fx.engine, id, &taken).is_err());
|
|
||||||
assert!(!fx.workspace.is_dirty(&fx.engine, other));
|
|
||||||
}
|
|
||||||
|
|
||||||
mod restart {
|
|
||||||
use gpx_engine::Persister;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use gpx_studio_desktop_lib::store::FileStorage;
|
|
||||||
|
|
||||||
/// What the app does when it starts again: the engine and the links are read from what was
|
|
||||||
/// kept.
|
|
||||||
fn restart(engine: &Engine, workspace: &Workspace, root: &Path) -> (Engine, Workspace) {
|
|
||||||
let storage = FileStorage::open(root).unwrap();
|
|
||||||
pollster::block_on(Persister::default().save(&storage, engine.snapshot())).unwrap();
|
|
||||||
let mut restarted = Engine::default();
|
|
||||||
let restored = pollster::block_on(Persister::default().restore(&storage)).unwrap();
|
|
||||||
restarted.restore(restored);
|
|
||||||
let links = serde_json::to_string(workspace).unwrap();
|
|
||||||
(restarted, serde_json::from_str(&links).unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup() -> (PathBuf, Engine, Workspace, Vec<Uuid>) {
|
|
||||||
let root = std::env::temp_dir().join(format!("gpx-restart-{}", Uuid::new_v4()));
|
|
||||||
let folder = root.join("tracks");
|
|
||||||
fs::create_dir_all(&folder).unwrap();
|
|
||||||
for name in ["with_tracks", "with_time", "with_waypoint"] {
|
|
||||||
let _ = fs::copy(
|
|
||||||
format!("../gpx-rs/data/{name}.gpx"),
|
|
||||||
folder.join(format!("{name}.gpx")),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let mut engine = Engine::default();
|
|
||||||
let mut workspace = Workspace::default();
|
|
||||||
workspace.open_folder(&mut engine, &folder, false);
|
|
||||||
workspace.open_files(&mut engine, &gpx_files(&folder), false);
|
|
||||||
let ids = engine.order().iter().map(|id| id.0).collect();
|
|
||||||
(root, engine, workspace, ids)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn files_that_were_not_edited_are_not_unsaved_after_a_restart() {
|
|
||||||
let (root, engine, workspace, ids) = setup();
|
|
||||||
assert!(ids.len() >= 2);
|
|
||||||
let (restarted, mut workspace) = restart(&engine, &workspace, &root.join("store"));
|
|
||||||
// the files are the same, but the engine knows their contents by new identities
|
|
||||||
assert!(ids.iter().any(|id| workspace.is_dirty(&restarted, *id)));
|
|
||||||
workspace.verify(&restarted);
|
|
||||||
assert!(ids.iter().all(|id| !workspace.is_dirty(&restarted, *id)));
|
|
||||||
fs::remove_dir_all(root).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn files_that_were_edited_are_still_unsaved_after_a_restart() {
|
|
||||||
let (root, mut engine, workspace, ids) = setup();
|
|
||||||
api::select(&mut engine, &[ids[0]], gpx_engine::SelectMode::Replace);
|
|
||||||
api::metadata(&mut engine, "edited", "");
|
|
||||||
assert!(workspace.is_dirty(&engine, ids[0]));
|
|
||||||
let (restarted, mut workspace) = restart(&engine, &workspace, &root.join("store"));
|
|
||||||
workspace.verify(&restarted);
|
|
||||||
assert!(workspace.is_dirty(&restarted, ids[0]));
|
|
||||||
assert!(
|
|
||||||
ids[1..]
|
|
||||||
.iter()
|
|
||||||
.all(|id| !workspace.is_dirty(&restarted, *id))
|
|
||||||
);
|
|
||||||
fs::remove_dir_all(root).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn links_made_before_the_content_was_kept_are_checked_against_the_disk() {
|
|
||||||
let (root, mut engine, mut workspace, ids) = setup();
|
|
||||||
api::select(&mut engine, &[ids[0]], gpx_engine::SelectMode::Replace);
|
|
||||||
api::metadata(&mut engine, "edited", "");
|
|
||||||
for link in workspace.links.values_mut() {
|
|
||||||
link.export_hash = 0;
|
|
||||||
}
|
|
||||||
let (restarted, mut workspace) = restart(&engine, &workspace, &root.join("store"));
|
|
||||||
workspace.verify(&restarted);
|
|
||||||
assert!(workspace.is_dirty(&restarted, ids[0]));
|
|
||||||
assert!(
|
|
||||||
ids[1..]
|
|
||||||
.iter()
|
|
||||||
.all(|id| !workspace.is_dirty(&restarted, *id))
|
|
||||||
);
|
|
||||||
fs::remove_dir_all(root).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn the_folders_of_new_files_and_the_old_flag_name_survive_a_restart() {
|
|
||||||
let (root, engine, mut workspace, ids) = setup();
|
|
||||||
let folder = workspace.folder.clone().unwrap();
|
|
||||||
let fresh = Uuid::new_v4();
|
|
||||||
workspace.inherit(&[fresh.to_string()], &folder);
|
|
||||||
workspace.links.get_mut(&ids[0]).unwrap().replaced = true;
|
|
||||||
let json = serde_json::to_string(&workspace).unwrap();
|
|
||||||
// links written by the previous version had `conflict`, which is the same thing
|
|
||||||
let json = json.replace("\"replaced\"", "\"conflict\"");
|
|
||||||
assert!(json.contains("\"conflict\":true"));
|
|
||||||
let read: Workspace = serde_json::from_str(&json).unwrap();
|
|
||||||
assert!(read.links[&ids[0]].replaced);
|
|
||||||
assert_eq!(read.dirs.get(&fresh), Some(&folder));
|
|
||||||
let _ = engine;
|
|
||||||
fs::remove_dir_all(root).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
|
||||||
<dependency>
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity
|
|
||||||
type="win32"
|
|
||||||
name="Microsoft.Windows.Common-Controls"
|
|
||||||
version="6.0.0.0"
|
|
||||||
processorArchitecture="*"
|
|
||||||
publicKeyToken="6595b64144ccf1df"
|
|
||||||
language="*"
|
|
||||||
/>
|
|
||||||
</dependentAssembly>
|
|
||||||
</dependency>
|
|
||||||
</assembly>
|
|
||||||
Generated
-26
@@ -44,7 +44,6 @@
|
|||||||
"@typescript-eslint/parser": "^8.33.1",
|
"@typescript-eslint/parser": "^8.33.1",
|
||||||
"bits-ui": "^2.17.2",
|
"bits-ui": "^2.17.2",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cross-env": "^10.1.0",
|
|
||||||
"eslint": "^9.28.0",
|
"eslint": "^9.28.0",
|
||||||
"eslint-config-prettier": "^10.1.5",
|
"eslint-config-prettier": "^10.1.5",
|
||||||
"eslint-plugin-svelte": "^3.9.1",
|
"eslint-plugin-svelte": "^3.9.1",
|
||||||
@@ -355,13 +354,6 @@
|
|||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@epic-web/invariant": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.27.7",
|
"version": "0.27.7",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz",
|
||||||
@@ -3283,24 +3275,6 @@
|
|||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/cross-env": {
|
|
||||||
"version": "10.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz",
|
|
||||||
"integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@epic-web/invariant": "^1.0.0",
|
|
||||||
"cross-spawn": "^7.0.6"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"cross-env": "dist/bin/cross-env.js",
|
|
||||||
"cross-env-shell": "dist/bin/cross-env-shell.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.6",
|
"version": "7.0.6",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
|||||||
@@ -5,12 +5,11 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"build:desktop": "cross-env BUILD_TARGET=desktop BASE_PATH= vite build",
|
"build:desktop": "BUILD_TARGET=desktop BASE_PATH='' vite build",
|
||||||
"prebuild": "npx tsx src/lib/scripts/pwa-manifest.ts",
|
"prebuild": "npx tsx src/lib/scripts/pwa-manifest.ts",
|
||||||
"postbuild": "npx tsx src/lib/scripts/sitemap.ts",
|
"postbuild": "npx tsx src/lib/scripts/sitemap.ts",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
"pretest": "svelte-kit sync",
|
|
||||||
"test": "node --import tsx --import ./src/test/register.mjs --experimental-wasm-modules --disable-warning=ExperimentalWarning --test \"src/**/*.test.ts\"",
|
"test": "node --import tsx --import ./src/test/register.mjs --experimental-wasm-modules --disable-warning=ExperimentalWarning --test \"src/**/*.test.ts\"",
|
||||||
"generate:example": "node --import tsx src/lib/scripts/example-statistics.ts",
|
"generate:example": "node --import tsx src/lib/scripts/example-statistics.ts",
|
||||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||||
@@ -39,7 +38,6 @@
|
|||||||
"@typescript-eslint/parser": "^8.33.1",
|
"@typescript-eslint/parser": "^8.33.1",
|
||||||
"bits-ui": "^2.17.2",
|
"bits-ui": "^2.17.2",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cross-env": "^10.1.0",
|
|
||||||
"eslint": "^9.28.0",
|
"eslint": "^9.28.0",
|
||||||
"eslint-config-prettier": "^10.1.5",
|
"eslint-config-prettier": "^10.1.5",
|
||||||
"eslint-plugin-svelte": "^3.9.1",
|
"eslint-plugin-svelte": "^3.9.1",
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ By right-clicking on a file tab, you can access the same actions as in the [edit
|
|||||||
|
|
||||||
As mentioned in the [view options section](./menu/view), you can switch to a tree layout for the files list.
|
As mentioned in the [view options section](./menu/view), you can switch to a tree layout for the files list.
|
||||||
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map.
|
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map.
|
||||||
In addition, the file tree view enables you to inspect the [tracks, segments, routes, and points of interest](./gpx) contained inside the files through collapsible sections.
|
In addition, the file tree view enables you to inspect the [tracks, segments, and points of interest](./gpx) contained inside the files through collapsible sections.
|
||||||
|
|
||||||
You can also apply [edit actions](./menu/edit) and [tools](./toolbar) to internal file items.
|
You can also apply [edit actions](./menu/edit) and [tools](./toolbar) to internal file items.
|
||||||
Furthermore, you can drag and drop the inner items to reorder them, or move them in the hierarchy or even to another file.
|
Furthermore, you can drag and drop the inner items to reorder them, or move them in the hierarchy or even to another file.
|
||||||
|
|||||||
@@ -3,15 +3,13 @@ title: Фармат файла GPX
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import { Waypoints, MapPin } from '@lucide/svelte';
|
||||||
import { Waypoints, Route, MapPin } from '@lucide/svelte';
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
<a href="https://www.topografix.com/gpx.asp" target="_blank">Фармат файла GPX</a> - гэта адкрыты стандарт для абмену дадзенымі GPS паміж праграмамі і прыладамі GPS.
|
<a href="https://www.topografix.com/gpx.asp" target="_blank">Фармат файла GPX</a> - гэта адкрыты стандарт для абмену дадзенымі GPS паміж праграмамі і прыладамі GPS.
|
||||||
Па сутнасці, ён складаецца з серыі кропак GPS, якія кадзіруюць адну або некалькі слядоў GPS, і, па жаданні, некаторыя кропкі цікавасці.
|
Па сутнасці, ён складаецца з серыі кропак GPS, якія кадзіруюць адну або некалькі слядоў GPS, і, па жаданні, некаторыя кропкі цікавасці.
|
||||||
These traces can be stored either as tracks or as routes.
|
|
||||||
|
|
||||||
Файлы GPX могуць таксама ўтрымліваць метададзеныя, з якіх палі **імя** і **апісанне** найбольш карысныя для карыстальнікаў.
|
Файлы GPX могуць таксама ўтрымліваць метададзеныя, з якіх палі **імя** і **апісанне** найбольш карысныя для карыстальнікаў.
|
||||||
|
|
||||||
@@ -29,20 +27,6 @@ These traces can be stored either as tracks or as routes.
|
|||||||
У большасці выпадкаў файлы GPX утрымліваюць адзін трэк з адным сегментам.
|
У большасці выпадкаў файлы GPX утрымліваюць адзін трэк з адным сегментам.
|
||||||
Аднак іерархія, апісаная вышэй, дазваляе выкарыстоўваць больш складаныя выпадкі, напрыклад, планаваць шматдзённыя паездкі з некалькімі варыянтамі на кожны дзень.
|
Аднак іерархія, апісаная вышэй, дазваляе выкарыстоўваць больш складаныя выпадкі, напрыклад, планаваць шматдзённыя паездкі з некалькімі варыянтамі на кожны дзень.
|
||||||
|
|
||||||
### <Route size="16" class="inline-block" style="margin-bottom: 2px" /> Routes
|
|
||||||
|
|
||||||
A **route** is a single continuous path made of a sequence of **route points**.
|
|
||||||
These are mandatory checkpoints, which correspond to the anchor points of the [routing tool](./toolbar/routing).
|
|
||||||
The points in between are only a suggested path connecting the route points.
|
|
||||||
Like a track, a route can have a **name**, a **description**, and **appearance properties**.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
Nowadays, most apps and GPS devices work perfectly well with tracks, even for navigation.
|
|
||||||
However, some of them only work with routes: in that case, you can [convert](./menu/edit) your tracks to routes, or [create](./menu/file) a route file from the start.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Кропкі цікавасці
|
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Кропкі цікавасці
|
||||||
|
|
||||||
**Кропкі цікавасці** (тэхнічна званыя _маршрутнымі кропкамі_) уяўляюць цікавыя месцы, якія можна паказаць альбо на прыладзе GPS, альбо на лічбавай карце.
|
**Кропкі цікавасці** (тэхнічна званыя _маршрутнымі кропкамі_) уяўляюць цікавыя месцы, якія можна паказаць альбо на прыладзе GPS, альбо на лічбавай карце.
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ title: Edit actions
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Undo2, Redo2, Info, PaintBucket, ArrowRightLeft, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Plus } from '@lucide/svelte';
|
import { Undo2, Redo2, Info, PaintBucket, EyeOff, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Maximize, Plus } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
Unlike the file actions, the edit actions can potentially modify the content of the currently selected files.
|
Unlike the file actions, the edit actions can potentially modify the content of the currently selected files.
|
||||||
Moreover, when the tree layout of the files list is enabled (see [Files and statistics](../files-and-stats)), they can also be applied to [tracks, segments, routes, and points of interest](../gpx).
|
Moreover, when the tree layout of the files list is enabled (see [Files and statistics](../files-and-stats)), they can also be applied to [tracks, segments, and points of interest](../gpx).
|
||||||
Therefore, we will refer to the elements that can be modified by these actions as _file items_.
|
Therefore, we will refer to the elements that can be modified by these actions as _file items_.
|
||||||
Note that except for the undo and redo actions, the edit actions are also accessible through the context menu (right-click) of the file items.
|
Note that except for the undo and redo actions, the edit actions are also accessible through the context menu (right-click) of the file items.
|
||||||
|
|
||||||
@@ -27,6 +27,10 @@ Open the information dialog of the currently selected file item, where you can s
|
|||||||
|
|
||||||
Open the appearance dialog, where you can change the color, opacity, and width of the selected file items on the map.
|
Open the appearance dialog, where you can change the color, opacity, and width of the selected file items on the map.
|
||||||
|
|
||||||
|
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Hide/unhide
|
||||||
|
|
||||||
|
Toggle the visibility of the selected file items on the map.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New track
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New track
|
||||||
|
|
||||||
Create a new track in the selected file.
|
Create a new track in the selected file.
|
||||||
@@ -38,17 +42,6 @@ Additionally, the selection must be a single file.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New route
|
|
||||||
|
|
||||||
Create a new route in the selected file.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
This action is only available when the tree layout of the files list is enabled.
|
|
||||||
Additionally, the selection must be a single file.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New segment
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New segment
|
||||||
|
|
||||||
Create a new segment in the selected track.
|
Create a new segment in the selected track.
|
||||||
@@ -60,17 +53,14 @@ Additionally, the selection must be a single track.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <ArrowRightLeft size="16" class="inline-block" style="margin-bottom: 2px" /> Convert to route/track
|
|
||||||
|
|
||||||
Convert the selected routes to tracks, or the selected tracks or segments to routes.
|
|
||||||
Since a route has a single segment, a track with multiple segments is converted into one route per segment.
|
|
||||||
|
|
||||||
When the selected files contain only routes, or only tracks, you can also convert all of them at once.
|
|
||||||
|
|
||||||
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Select all
|
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Select all
|
||||||
|
|
||||||
Add all file items in the current hierarchy level to the selection.
|
Add all file items in the current hierarchy level to the selection.
|
||||||
|
|
||||||
|
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Center
|
||||||
|
|
||||||
|
Center the map on the selected file items.
|
||||||
|
|
||||||
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Copy
|
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Copy
|
||||||
|
|
||||||
Copy the selected file items to the clipboard.
|
Copy the selected file items to the clipboard.
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ The file actions menu contains a set of pretty self-explanatory file operations.
|
|||||||
|
|
||||||
Create a new empty file.
|
Create a new empty file.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New route file
|
|
||||||
|
|
||||||
Create a new file containing an empty [route](../gpx).
|
|
||||||
|
|
||||||
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Open...
|
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Open...
|
||||||
|
|
||||||
Open files from your computer.
|
Open files from your computer.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: View options
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, EyeOff, Maximize, Box, Maximize2 } from '@lucide/svelte';
|
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, Box, Maximize2 } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ Hide the elevation profile to make room for the map, or show it to inspect the c
|
|||||||
|
|
||||||
Toggle the tree layout for the [file list](../files-and-stats).
|
Toggle the tree layout for the [file list](../files-and-stats).
|
||||||
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map.
|
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map.
|
||||||
In addition, the file tree view enables you to inspect the [tracks, segments, routes, and points of interest](../gpx) contained inside the files through collapsible sections.
|
In addition, the file tree view enables you to inspect the [tracks, segments, and points of interest](../gpx) contained inside the files through collapsible sections.
|
||||||
|
|
||||||
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Switch to previous basemap
|
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Switch to previous basemap
|
||||||
|
|
||||||
@@ -38,14 +38,6 @@ They are displayed for the current selection, like the [elevation profile](../fi
|
|||||||
|
|
||||||
Toggle the visibility of direction arrows on the map.
|
Toggle the visibility of direction arrows on the map.
|
||||||
|
|
||||||
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Hide/unhide
|
|
||||||
|
|
||||||
Toggle the visibility of the selected file items on the map.
|
|
||||||
|
|
||||||
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Center
|
|
||||||
|
|
||||||
Center the map on the selected file items.
|
|
||||||
|
|
||||||
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Toggle 3D
|
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Toggle 3D
|
||||||
|
|
||||||
Enter or exit the 3D map view.
|
Enter or exit the 3D map view.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ This tool allows you to extract [tracks (or segments)](../gpx) from files (or tr
|
|||||||
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Applying the tool to a file containing multiple [tracks or routes](../gpx) will create a new file for each of the tracks and routes it contains.
|
Applying the tool to a file containing multiple tracks will create a new file for each of the tracks it contains.
|
||||||
Similarly, applying the tool to a track containing multiple segments will create (in the same file) a new track for each of the segments it contains.
|
Similarly, applying the tool to a track containing multiple segments will create (in the same file) a new track for each of the segments it contains.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ title: Merge
|
|||||||
|
|
||||||
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
||||||
|
|
||||||
To use this tool, you need to [select](../files-and-stats) multiple files, [tracks, segments or routes](../gpx).
|
To use this tool, you need to [select](../files-and-stats) multiple files, [tracks, or segments](../gpx).
|
||||||
|
|
||||||
- If your goal is to create a single continuous trace from your selection, use the **Connect the traces** option and validate.
|
- If your goal is to create a single continuous trace from your selection, use the **Connect the traces** option and validate.
|
||||||
- The second option can be used to create or manage files with multiple [tracks, segments or routes](../gpx).
|
- The second option can be used to create or manage files with multiple [tracks or segments](../gpx).
|
||||||
Merging files (or tracks) will result in a single file (or track) containing all tracks and routes (or segments) from the selection.
|
Merging files (or tracks) will result in a single file (or track) containing all tracks (or segments) from the selection.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,6 @@ To split the selected trace into two parts, click on one of the split markers di
|
|||||||
To split at a specific point of your choice, hover over the trace on the map.
|
To split at a specific point of your choice, hover over the trace on the map.
|
||||||
Scissors will appear at the cursor position, showing that you can split the trace at that point.
|
Scissors will appear at the cursor position, showing that you can split the trace at that point.
|
||||||
|
|
||||||
You can choose to split the trace into two GPX files, or to keep the split parts in the same file as [tracks, segments or routes](../gpx).
|
You can choose to split the trace into two GPX files, or to keep the split parts in the same file as [tracks or segments](../gpx).
|
||||||
|
|
||||||
<DocsImage src="tools/split" alt="Hovering over the selected trace turns your cursor into scissors." />
|
<DocsImage src="tools/split" alt="Hovering over the selected trace turns your cursor into scissors." />
|
||||||
@@ -51,7 +51,7 @@ Clicant el botó dret en la pestanya d'un arxiu, pots accedir a les mateixes acc
|
|||||||
|
|
||||||
Tal i com es menciona en la [secció d'opcions de vista](./menu/view), pots canviar a un esquema d'arbre per a la llista d'arxius.
|
Tal i com es menciona en la [secció d'opcions de vista](./menu/view), pots canviar a un esquema d'arbre per a la llista d'arxius.
|
||||||
Aquesta disposició és ideal per tal d'administrar un gran nombre d'arxius oberts, ja que els organitza en una llista vertical en la part dreta del mapa.
|
Aquesta disposició és ideal per tal d'administrar un gran nombre d'arxius oberts, ja que els organitza en una llista vertical en la part dreta del mapa.
|
||||||
In addition, the file tree view enables you to inspect the [tracks, segments, routes, and points of interest](./gpx) contained inside the files through collapsible sections.
|
A més, la vista d'arbre d'arxius permet inspeccionar [tracs, segments i punts d'interès](./gpx) continguts dins dels arxius a través de seccions plegables.
|
||||||
|
|
||||||
També pots aplicar [accions d'edició](./menu/edit) i [eines](./toolbar) a elements interns de l'arxiu.
|
També pots aplicar [accions d'edició](./menu/edit) i [eines](./toolbar) a elements interns de l'arxiu.
|
||||||
A més, pots arrossegar i deixar anar els elements interns per reordenar-los, o moure'ls en la jerarquia o fins i tot a un altre arxiu.
|
A més, pots arrossegar i deixar anar els elements interns per reordenar-los, o moure'ls en la jerarquia o fins i tot a un altre arxiu.
|
||||||
|
|||||||
@@ -3,15 +3,13 @@ title: Format d'arxiu GPX
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import { Waypoints, MapPin } from '@lucide/svelte';
|
||||||
import { Waypoints, Route, MapPin } from '@lucide/svelte';
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
El <a href="https://www.topografix.com/gpx.asp" target="_blank">format d'arxiu GPX</a> és un estàndard obert per intercanviar dades GPS entre aplicacions i aparells GPS.
|
El <a href="https://www.topografix.com/gpx.asp" target="_blank">format d'arxiu GPX</a> és un estàndard obert per intercanviar dades GPS entre aplicacions i aparells GPS.
|
||||||
Bàsicament consisteix en una sèrie de punts GPS que codifiquen una o diverses traces GPS i, opcionalment, alguns punts d'interès.
|
Bàsicament consisteix en una sèrie de punts GPS que codifiquen una o diverses traces GPS i, opcionalment, alguns punts d'interès.
|
||||||
These traces can be stored either as tracks or as routes.
|
|
||||||
|
|
||||||
Els arxius GPX poden contenir també metadades, de les quals els camps **nom** i **descripció** són els més útils pels usuaris.
|
Els arxius GPX poden contenir també metadades, de les quals els camps **nom** i **descripció** són els més útils pels usuaris.
|
||||||
|
|
||||||
@@ -29,20 +27,6 @@ Aquests estan organitzats en una estructura jeràrquica, amb els tracs en el niv
|
|||||||
En la majoria dels casos, els arxius GPX contenen un sol trac amb un sol segment.
|
En la majoria dels casos, els arxius GPX contenen un sol trac amb un sol segment.
|
||||||
Tanmateix, la jerarquia descrita a dalt permet casos d'ús més avançat, com la planificació de viatges de diversos dies amb variants per cada dia.
|
Tanmateix, la jerarquia descrita a dalt permet casos d'ús més avançat, com la planificació de viatges de diversos dies amb variants per cada dia.
|
||||||
|
|
||||||
### <Route size="16" class="inline-block" style="margin-bottom: 2px" /> Routes
|
|
||||||
|
|
||||||
A **route** is a single continuous path made of a sequence of **route points**.
|
|
||||||
These are mandatory checkpoints, which correspond to the anchor points of the [routing tool](./toolbar/routing).
|
|
||||||
The points in between are only a suggested path connecting the route points.
|
|
||||||
Like a track, a route can have a **name**, a **description**, and **appearance properties**.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
Nowadays, most apps and GPS devices work perfectly well with tracks, even for navigation.
|
|
||||||
However, some of them only work with routes: in that case, you can [convert](./menu/edit) your tracks to routes, or [create](./menu/file) a route file from the start.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Punts d'interès
|
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Punts d'interès
|
||||||
|
|
||||||
**Punts d'interès** (tècnicament anomenats _waypoints_) representen ubicacions d'interès per mostrar en un dispositiu GPS o en mapa digital.
|
**Punts d'interès** (tècnicament anomenats _waypoints_) representen ubicacions d'interès per mostrar en un dispositiu GPS o en mapa digital.
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ title: Accions d'edició
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Undo2, Redo2, Info, PaintBucket, ArrowRightLeft, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Plus } from '@lucide/svelte';
|
import { Undo2, Redo2, Info, PaintBucket, EyeOff, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Maximize, Plus } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
A diferència de les accions de l'arxiu, les accions d'edició poden potencialment modificar el contingut dels arxius seleccionats actualment.
|
A diferència de les accions de l'arxiu, les accions d'edició poden potencialment modificar el contingut dels arxius seleccionats actualment.
|
||||||
Moreover, when the tree layout of the files list is enabled (see [Files and statistics](../files-and-stats)), they can also be applied to [tracks, segments, routes, and points of interest](../gpx).
|
A més a més, quan està habilitada la disposició de l'arbre de la llista d'arxius (veure [Arxius i estadístiques](../files-and-stats)), també es poden aplicar a [tracs, segments i punts d'interès](../gpx).
|
||||||
Per tant, ens referirem als elements que poden ser modificats per aquestes accions com a _elements d'arxiu_.
|
Per tant, ens referirem als elements que poden ser modificats per aquestes accions com a _elements d'arxiu_.
|
||||||
Tingui en compte que excepte per a les accions de desfer i refer, les accions d'edició també són accessibles a través del menú contextual (clic dret) dels elements de l'arxiu.
|
Tingui en compte que excepte per a les accions de desfer i refer, les accions d'edició també són accessibles a través del menú contextual (clic dret) dels elements de l'arxiu.
|
||||||
|
|
||||||
@@ -27,6 +27,10 @@ Obre el quadre de diàleg d'informació de l'element de l'arxiu seleccionat, on
|
|||||||
|
|
||||||
Obre el diàleg d'aparença, on pots canviar el color, l'opacitat i l'amplada del mapa dels elements de l'arxiu seleccionat.
|
Obre el diàleg d'aparença, on pots canviar el color, l'opacitat i l'amplada del mapa dels elements de l'arxiu seleccionat.
|
||||||
|
|
||||||
|
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Amaga/mostra
|
||||||
|
|
||||||
|
Alterna la visibilitat dels elements de l'arxiu seleccionat en el mapa.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Nou trac
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Nou trac
|
||||||
|
|
||||||
Crear nova ruta en l'arxiu seleccionat.
|
Crear nova ruta en l'arxiu seleccionat.
|
||||||
@@ -38,17 +42,6 @@ A més, la selecció ha de ser un únic arxiu.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New route
|
|
||||||
|
|
||||||
Create a new route in the selected file.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
Aquesta acció només està disponible quan està habilitada la disposició de l'arbre de la llista d'arxius.
|
|
||||||
A més, la selecció ha de ser un únic arxiu.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Nou segment
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Nou segment
|
||||||
|
|
||||||
Crear un nou segment en el trac seleccionat.
|
Crear un nou segment en el trac seleccionat.
|
||||||
@@ -60,17 +53,14 @@ A més, la selecció ha de ser un trac únic.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <ArrowRightLeft size="16" class="inline-block" style="margin-bottom: 2px" /> Convert to route/track
|
|
||||||
|
|
||||||
Convert the selected routes to tracks, or the selected tracks or segments to routes.
|
|
||||||
Since a route has a single segment, a track with multiple segments is converted into one route per segment.
|
|
||||||
|
|
||||||
When the selected files contain only routes, or only tracks, you can also convert all of them at once.
|
|
||||||
|
|
||||||
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Selecciona tot
|
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Selecciona tot
|
||||||
|
|
||||||
Afegeix a la selecció tots els elements de l'arxiu en el nivell de jerarquia actual.
|
Afegeix a la selecció tots els elements de l'arxiu en el nivell de jerarquia actual.
|
||||||
|
|
||||||
|
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Centrar
|
||||||
|
|
||||||
|
Centrar el mapa en els elements de l'arxiu seleccionat.
|
||||||
|
|
||||||
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Copia
|
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Copia
|
||||||
|
|
||||||
Copia els elements de l'arxiu seleccionat en el porta-retalls.
|
Copia els elements de l'arxiu seleccionat en el porta-retalls.
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ El menú d'accions d'arxiu conté un conjunt d'operacions força autoexplicative
|
|||||||
|
|
||||||
Crea un arxiu nou buit.
|
Crea un arxiu nou buit.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New route file
|
|
||||||
|
|
||||||
Create a new file containing an empty [route](../gpx).
|
|
||||||
|
|
||||||
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Obrir...
|
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Obrir...
|
||||||
|
|
||||||
Obrir arxius del teu equip.
|
Obrir arxius del teu equip.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: Opcions de vista
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, EyeOff, Maximize, Box, Maximize2 } from '@lucide/svelte';
|
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, Box, Maximize2 } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ Amagar el perfil d'elevació per fer espai al mapa o mostra-lo per inspeccionar
|
|||||||
|
|
||||||
Alterna el disseny de l'arbre per la [llista d'arxius](../files-and-stats).
|
Alterna el disseny de l'arbre per la [llista d'arxius](../files-and-stats).
|
||||||
Aquesta disposició és ideal per tal d'administrar un gran nombre d'arxius oberts, ja que els organitza en una llista vertical en la part dreta del mapa.
|
Aquesta disposició és ideal per tal d'administrar un gran nombre d'arxius oberts, ja que els organitza en una llista vertical en la part dreta del mapa.
|
||||||
In addition, the file tree view enables you to inspect the [tracks, segments, routes, and points of interest](../gpx) contained inside the files through collapsible sections.
|
A més, la vista de l'arbre d'arxius permet inspeccionar [tracs, segments i punts d'interès](../gpx) continguts en els arxius a través de les seccions plegables.
|
||||||
|
|
||||||
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Canvia la mapa base anterior
|
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Canvia la mapa base anterior
|
||||||
|
|
||||||
@@ -38,14 +38,6 @@ Es mostren per a la selecció actual, com el [perfil d'elevació](../files-and-s
|
|||||||
|
|
||||||
Alterna la visibilitat de les fletxes de direcció en el mapa.
|
Alterna la visibilitat de les fletxes de direcció en el mapa.
|
||||||
|
|
||||||
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Hide/unhide
|
|
||||||
|
|
||||||
Toggle the visibility of the selected file items on the map.
|
|
||||||
|
|
||||||
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Center
|
|
||||||
|
|
||||||
Center the map on the selected file items.
|
|
||||||
|
|
||||||
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Alternar 3D
|
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Alternar 3D
|
||||||
|
|
||||||
Entra o surt de la vista de mapa en 3D.
|
Entra o surt de la vista de mapa en 3D.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ Aquesta eina permet extreure [tracs (o segments)](../gpx) des d'arxius (o tracs)
|
|||||||
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Applying the tool to a file containing multiple [tracks or routes](../gpx) will create a new file for each of the tracks and routes it contains.
|
Aplicant l'eina a un arxiu que contingui múltiples tracs, crearà un arxiu nou per cada trac que contingui.
|
||||||
Igualment, aplicant l'eina a un trac que contingui múltiples segments, crearà (en el mateix arxiu) un nou trac per cada un dels segments que contingui.
|
Igualment, aplicant l'eina a un trac que contingui múltiples segments, crearà (en el mateix arxiu) un nou trac per cada un dels segments que contingui.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ title: Fusionar
|
|||||||
|
|
||||||
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
||||||
|
|
||||||
To use this tool, you need to [select](../files-and-stats) multiple files, [tracks, segments or routes](../gpx).
|
Per utilitzar aquesta eina, s'ha de [seleccionar](../files-and-stats) múltiples arxius, [tracs o segments](../gpx).
|
||||||
|
|
||||||
- Si el teu objectiu és crear una traça contínua a partir de la selecció, utilitza l'opció **Connectar les traces** i valida-ho.
|
- Si el teu objectiu és crear una traça contínua a partir de la selecció, utilitza l'opció **Connectar les traces** i valida-ho.
|
||||||
- The second option can be used to create or manage files with multiple [tracks, segments or routes](../gpx).
|
- La segona opció es pot utilitzar per a crear o gestionar arxius amb múltiples [tracs o segments](../gpx).
|
||||||
Merging files (or tracks) will result in a single file (or track) containing all tracks and routes (or segments) from the selection.
|
Fusionar arxius (o tracs) crearà un sol arxiu (o trac) que contindrà tots els tracs (o segments) seleccionats.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,6 @@ Per dividir la traça seleccionada en dues parts, clica sobre un dels marcadors
|
|||||||
Per dividir en un punt triat específicament, situat sobre la traça del mapa.
|
Per dividir en un punt triat específicament, situat sobre la traça del mapa.
|
||||||
Les tisores apareixeran en la posició del cursor, mostrant que pots dividir el traçat en aquest punt.
|
Les tisores apareixeran en la posició del cursor, mostrant que pots dividir el traçat en aquest punt.
|
||||||
|
|
||||||
You can choose to split the trace into two GPX files, or to keep the split parts in the same file as [tracks, segments or routes](../gpx).
|
Pots triar dividir el traçat en dos arxius GPX o mantenir les parts dividides en el mateix arxiu com a [tracs o segments](../gpx).
|
||||||
|
|
||||||
<DocsImage src="tools/split" alt="Situar el cursor sobre el traçat seleccionat el converteix en tisores." />
|
<DocsImage src="tools/split" alt="Situar el cursor sobre el traçat seleccionat el converteix en tisores." />
|
||||||
@@ -51,7 +51,7 @@ Kliknutím pravým tlačítkem myši na kartu souboru můžete provést stejné
|
|||||||
|
|
||||||
Jak je uvedeno v části [možnosti zobrazení](./menu/view), můžete přepnout na stromové rozvržení seznamu souborů.
|
Jak je uvedeno v části [možnosti zobrazení](./menu/view), můžete přepnout na stromové rozvržení seznamu souborů.
|
||||||
Toto zobrazení je ideální pro správu velkého počtu otevřených souborů, protože je uspořádá do svislého seznamu na pravé straně mapy.
|
Toto zobrazení je ideální pro správu velkého počtu otevřených souborů, protože je uspořádá do svislého seznamu na pravé straně mapy.
|
||||||
In addition, the file tree view enables you to inspect the [tracks, segments, routes, and points of interest](./gpx) contained inside the files through collapsible sections.
|
Stromové rozvržení souborů navíc umožňuje zkontrolovat [trasy, úseky a body zájmu](./gpx) obsažené v souborech prostřednictvím sbalitelných sekcí.
|
||||||
|
|
||||||
Rovněž můžete využít [akce úprav](./menu/edit) a [nástroje](./toolbar) na prvky uvnitř souborů.
|
Rovněž můžete využít [akce úprav](./menu/edit) a [nástroje](./toolbar) na prvky uvnitř souborů.
|
||||||
Navíc přetažením prvků uvnitř souborů můžete změnit jejich pořadí nebo je přesunout v hierarchii či dokonce do jiného souboru.
|
Navíc přetažením prvků uvnitř souborů můžete změnit jejich pořadí nebo je přesunout v hierarchii či dokonce do jiného souboru.
|
||||||
|
|||||||
@@ -3,15 +3,13 @@ title: Formát souboru GPX
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import { Waypoints, MapPin } from '@lucide/svelte';
|
||||||
import { Waypoints, Route, MapPin } from '@lucide/svelte';
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
<a href="https://www.topografix.com/gpx.asp" target="_blank">GPX formát</a> je otevřeným standardem pro výměnu GPS dat mezi aplikacemi a GPS zařízeními.
|
<a href="https://www.topografix.com/gpx.asp" target="_blank">GPX formát</a> je otevřeným standardem pro výměnu GPS dat mezi aplikacemi a GPS zařízeními.
|
||||||
V podstatě se skládá z řady GPS bodů kódujících jednu nebo více GPS stop a volitelně i nějaké body zájmu.
|
V podstatě se skládá z řady GPS bodů kódujících jednu nebo více GPS stop a volitelně i nějaké body zájmu.
|
||||||
These traces can be stored either as tracks or as routes.
|
|
||||||
|
|
||||||
GPX soubory mohou obsahovat také metadata, z nichž pole **název** a **popis** jsou pro uživatele nejužitečnější.
|
GPX soubory mohou obsahovat také metadata, z nichž pole **název** a **popis** jsou pro uživatele nejužitečnější.
|
||||||
|
|
||||||
@@ -29,20 +27,6 @@ Ty jsou uspořádány v hierarchické struktuře, přičemž trasy jsou na nejvy
|
|||||||
Ve většině případů obsahují GPX soubory pouze jednu trasu s jedním úsekem.
|
Ve většině případů obsahují GPX soubory pouze jednu trasu s jedním úsekem.
|
||||||
Nicméně výše popsaná hierarchie umožňuje pokročilejší případy použití, například plánování vícedenních výletů s několika variantami pro každý den.
|
Nicméně výše popsaná hierarchie umožňuje pokročilejší případy použití, například plánování vícedenních výletů s několika variantami pro každý den.
|
||||||
|
|
||||||
### <Route size="16" class="inline-block" style="margin-bottom: 2px" /> Routes
|
|
||||||
|
|
||||||
A **route** is a single continuous path made of a sequence of **route points**.
|
|
||||||
These are mandatory checkpoints, which correspond to the anchor points of the [routing tool](./toolbar/routing).
|
|
||||||
The points in between are only a suggested path connecting the route points.
|
|
||||||
Like a track, a route can have a **name**, a **description**, and **appearance properties**.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
Nowadays, most apps and GPS devices work perfectly well with tracks, even for navigation.
|
|
||||||
However, some of them only work with routes: in that case, you can [convert](./menu/edit) your tracks to routes, or [create](./menu/file) a route file from the start.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Body zájmu
|
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Body zájmu
|
||||||
|
|
||||||
**Body zájmu** (odborně nazývané _waypoints_) představují zajímavá místa, která se zobrazí buď na zařízení GPS, nebo na digitální mapě.
|
**Body zájmu** (odborně nazývané _waypoints_) představují zajímavá místa, která se zobrazí buď na zařízení GPS, nebo na digitální mapě.
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ title: Akce úprav
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Undo2, Redo2, Info, PaintBucket, ArrowRightLeft, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Plus } from '@lucide/svelte';
|
import { Undo2, Redo2, Info, PaintBucket, EyeOff, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Maximize, Plus } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
Na rozdíl od akcí v menu Soubor, mohou akce úprav potenciálně změnit obsah aktuálně vybraných souborů.
|
Na rozdíl od akcí v menu Soubor, mohou akce úprav potenciálně změnit obsah aktuálně vybraných souborů.
|
||||||
Moreover, when the tree layout of the files list is enabled (see [Files and statistics](../files-and-stats)), they can also be applied to [tracks, segments, routes, and points of interest](../gpx).
|
Navíc pokud je povoleno rozvržení stromu seznamu souborů (viz [Soubory a statistiky](../files-and-stats)), mohou být také použity na [trasy, segmenty a body zájmu](../gpx).
|
||||||
Proto budeme všechny prvky, které mohou být těmito akcemi upraveny, označovat jako _prvky souborů_.
|
Proto budeme všechny prvky, které mohou být těmito akcemi upraveny, označovat jako _prvky souborů_.
|
||||||
Všechny akce kromě zpět a opakovat jsou také dostupné z kontextového menu (klik pravým tlačítkem) prvků souborů.
|
Všechny akce kromě zpět a opakovat jsou také dostupné z kontextového menu (klik pravým tlačítkem) prvků souborů.
|
||||||
|
|
||||||
@@ -27,6 +27,10 @@ Otevře informační dialog zvoleného prvku souborů, kde lze zobrazit a změni
|
|||||||
|
|
||||||
Otevře dialog vzhledu, kde můžete změnit barvu, neprůhlednost a tloušťku zvolených prvků souborů v mapě.
|
Otevře dialog vzhledu, kde můžete změnit barvu, neprůhlednost a tloušťku zvolených prvků souborů v mapě.
|
||||||
|
|
||||||
|
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Skrýt/zobrazit
|
||||||
|
|
||||||
|
Přepnout viditelnost zvolených prvků souborů v mapě.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Nová trasa
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Nová trasa
|
||||||
|
|
||||||
Vytvořit novou trasu ve zvoleném souboru.
|
Vytvořit novou trasu ve zvoleném souboru.
|
||||||
@@ -38,17 +42,6 @@ Kromě toho musí být vybrán právě jeden soubor.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New route
|
|
||||||
|
|
||||||
Create a new route in the selected file.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
Tato akce je dostupná pouze v případě, že je povoleno rozvržení stromu seznamu souborů.
|
|
||||||
Kromě toho musí být vybrán právě jeden soubor.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Nový úsek
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Nový úsek
|
||||||
|
|
||||||
Vytvořit nový úsek na zvolené trase.
|
Vytvořit nový úsek na zvolené trase.
|
||||||
@@ -60,17 +53,14 @@ Kromě toho musí být zvolena právě jedna trasa.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <ArrowRightLeft size="16" class="inline-block" style="margin-bottom: 2px" /> Convert to route/track
|
|
||||||
|
|
||||||
Convert the selected routes to tracks, or the selected tracks or segments to routes.
|
|
||||||
Since a route has a single segment, a track with multiple segments is converted into one route per segment.
|
|
||||||
|
|
||||||
When the selected files contain only routes, or only tracks, you can also convert all of them at once.
|
|
||||||
|
|
||||||
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Vybrat vše
|
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Vybrat vše
|
||||||
|
|
||||||
Přidejte k výběru všechny prvky souborů v dané úrovni hierarchie.
|
Přidejte k výběru všechny prvky souborů v dané úrovni hierarchie.
|
||||||
|
|
||||||
|
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Vycentrovat
|
||||||
|
|
||||||
|
Vystředí mapu na označené prvky souborů.
|
||||||
|
|
||||||
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Kopírovat
|
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Kopírovat
|
||||||
|
|
||||||
Zkopíruje zvolené prvky souborů do schránky.
|
Zkopíruje zvolené prvky souborů do schránky.
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ Menu akce souboru obsahuje sadu poměrně samovysvětlujících operací.
|
|||||||
|
|
||||||
Vytvořit nový prázdný soubor.
|
Vytvořit nový prázdný soubor.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New route file
|
|
||||||
|
|
||||||
Create a new file containing an empty [route](../gpx).
|
|
||||||
|
|
||||||
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Otevřít...
|
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Otevřít...
|
||||||
|
|
||||||
Otevřít soubor z vašeho počítače.
|
Otevřít soubor z vašeho počítače.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: Možnosti zobrazení
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, EyeOff, Maximize, Box, Maximize2 } from '@lucide/svelte';
|
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, Box, Maximize2 } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ Skrýt výškový profil, aby se vytvořilo místo pro mapu, nebo ho zobrazit a
|
|||||||
|
|
||||||
Přepnout rozvržení stromu pro [seznam souborů](../files-and-stats).
|
Přepnout rozvržení stromu pro [seznam souborů](../files-and-stats).
|
||||||
Toto zobrazení je ideální pro správu velkého počtu otevřených souborů, protože je uspořádá do svislého seznamu na pravé straně mapy.
|
Toto zobrazení je ideální pro správu velkého počtu otevřených souborů, protože je uspořádá do svislého seznamu na pravé straně mapy.
|
||||||
In addition, the file tree view enables you to inspect the [tracks, segments, routes, and points of interest](../gpx) contained inside the files through collapsible sections.
|
Kromě jiného umožňuje zobrazení stromu souborů zkontrolovat [trasy, segmenty, a body zájmu](../gpx) obsažené uvnitř souborů skrze sbalitelné sekce.
|
||||||
|
|
||||||
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Přepnout na předchozí základní mapu
|
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Přepnout na předchozí základní mapu
|
||||||
|
|
||||||
@@ -38,14 +38,6 @@ Zobrazují se pro aktuální výběr, jako je [výškový profil](../files-and-s
|
|||||||
|
|
||||||
Přepnout viditelnost směrových šipek na mapě.
|
Přepnout viditelnost směrových šipek na mapě.
|
||||||
|
|
||||||
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Hide/unhide
|
|
||||||
|
|
||||||
Toggle the visibility of the selected file items on the map.
|
|
||||||
|
|
||||||
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Center
|
|
||||||
|
|
||||||
Center the map on the selected file items.
|
|
||||||
|
|
||||||
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Přepnout 3D
|
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Přepnout 3D
|
||||||
|
|
||||||
Zapnout nebo vypnout 3D zobrazení mapy.
|
Zapnout nebo vypnout 3D zobrazení mapy.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ Tento nástroj umožňuje extrahovat [trasy (nebo úseky)](../gpx) ze souborů (
|
|||||||
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Applying the tool to a file containing multiple [tracks or routes](../gpx) will create a new file for each of the tracks and routes it contains.
|
Použití nástroje na soubor obsahující více tras vytvoří nový soubor pro každou z tras, kterou obsahuje.
|
||||||
Obdobně použití nástroje na trasu obsahující více úseků vytvoří (ve stejném souboru) novou trasu pro každý úsek, který obsahuje.
|
Obdobně použití nástroje na trasu obsahující více úseků vytvoří (ve stejném souboru) novou trasu pro každý úsek, který obsahuje.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ title: Sloučit
|
|||||||
|
|
||||||
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
||||||
|
|
||||||
To use this tool, you need to [select](../files-and-stats) multiple files, [tracks, segments or routes](../gpx).
|
Chcete-li použít tento nástroj, musíte [vybrat](../files-and-stats) více souborů, [tras nebo segmentů](../gpx).
|
||||||
|
|
||||||
- Pokud je vaším cílem vytvořit z vašeho výběru jednu spojitou stopu, použijte možnost **Připojit stopy** a potvrďte.
|
- Pokud je vaším cílem vytvořit z vašeho výběru jednu spojitou stopu, použijte možnost **Připojit stopy** a potvrďte.
|
||||||
- The second option can be used to create or manage files with multiple [tracks, segments or routes](../gpx).
|
- Druhá možnost může být použita k vytvoření nebo správě souborů s více [trasami nebo segmenty](../gpx).
|
||||||
Merging files (or tracks) will result in a single file (or track) containing all tracks and routes (or segments) from the selection.
|
Sloučením souborů (nebo tras) vznikne jeden soubor (nebo trasa) obsahující všechny trasy (nebo úseky) z výběru.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,6 @@ Chcete-li rozdělit vybranou stopu na dvě části, klikněte na jednu z rozděl
|
|||||||
Chcete-li rozdělit stopu v určitém bodě dle vašeho výběru, najeďte nad stopu na mapě.
|
Chcete-li rozdělit stopu v určitém bodě dle vašeho výběru, najeďte nad stopu na mapě.
|
||||||
Na pozici kurzoru se objeví nůžky, což znázorňuje, že v tomto bodě můžete stopu rozdělit.
|
Na pozici kurzoru se objeví nůžky, což znázorňuje, že v tomto bodě můžete stopu rozdělit.
|
||||||
|
|
||||||
You can choose to split the trace into two GPX files, or to keep the split parts in the same file as [tracks, segments or routes](../gpx).
|
Můžete zvolit rozdělení stopy na dva GPX soubory, nebo uchovat rozdělené části ve stejném souboru jako [trasy nebo segmenty](../gpx).
|
||||||
|
|
||||||
<DocsImage src="tools/split" alt="Najetí kurzorem nad vybranou stopu změní kurzor v nůžky." />
|
<DocsImage src="tools/split" alt="Najetí kurzorem nad vybranou stopu změní kurzor v nůžky." />
|
||||||
@@ -51,7 +51,7 @@ By right-clicking on a file tab, you can access the same actions as in the [edit
|
|||||||
|
|
||||||
As mentioned in the [view options section](./menu/view), you can switch to a tree layout for the files list.
|
As mentioned in the [view options section](./menu/view), you can switch to a tree layout for the files list.
|
||||||
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map.
|
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map.
|
||||||
In addition, the file tree view enables you to inspect the [tracks, segments, routes, and points of interest](./gpx) contained inside the files through collapsible sections.
|
In addition, the file tree view enables you to inspect the [tracks, segments, and points of interest](./gpx) contained inside the files through collapsible sections.
|
||||||
|
|
||||||
You can also apply [edit actions](./menu/edit) and [tools](./toolbar) to internal file items.
|
You can also apply [edit actions](./menu/edit) and [tools](./toolbar) to internal file items.
|
||||||
Furthermore, you can drag and drop the inner items to reorder them, or move them in the hierarchy or even to another file.
|
Furthermore, you can drag and drop the inner items to reorder them, or move them in the hierarchy or even to another file.
|
||||||
|
|||||||
@@ -3,15 +3,13 @@ title: GPX file format
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import { Waypoints, MapPin } from '@lucide/svelte';
|
||||||
import { Waypoints, Route, MapPin } from '@lucide/svelte';
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
The <a href="https://www.topografix.com/gpx.asp" target="_blank">GPX file format</a> is an open standard for exchanging GPS data between applications and GPS devices.
|
The <a href="https://www.topografix.com/gpx.asp" target="_blank">GPX file format</a> is an open standard for exchanging GPS data between applications and GPS devices.
|
||||||
It essentially consists of a series of GPS points encoding one or multiple GPS traces, and, optionally, some points of interest.
|
It essentially consists of a series of GPS points encoding one or multiple GPS traces, and, optionally, some points of interest.
|
||||||
These traces can be stored either as tracks or as routes.
|
|
||||||
|
|
||||||
GPX files may also contain metadata, of which the **name** and **description** fields are the most useful for users.
|
GPX files may also contain metadata, of which the **name** and **description** fields are the most useful for users.
|
||||||
|
|
||||||
@@ -29,20 +27,6 @@ These are organized in a hierarchical structure, with tracks at the top level.
|
|||||||
In most cases, GPX files contain a single track with a single segment.
|
In most cases, GPX files contain a single track with a single segment.
|
||||||
However, the hierarchy described above allows for more advanced use cases, such as planning multi-day trips with several variants for each day.
|
However, the hierarchy described above allows for more advanced use cases, such as planning multi-day trips with several variants for each day.
|
||||||
|
|
||||||
### <Route size="16" class="inline-block" style="margin-bottom: 2px" /> Routes
|
|
||||||
|
|
||||||
A **route** is a single continuous path made of a sequence of **route points**.
|
|
||||||
These are mandatory checkpoints, which correspond to the anchor points of the [routing tool](./toolbar/routing).
|
|
||||||
The points in between are only a suggested path connecting the route points.
|
|
||||||
Like a track, a route can have a **name**, a **description**, and **appearance properties**.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
Nowadays, most apps and GPS devices work perfectly well with tracks, even for navigation.
|
|
||||||
However, some of them only work with routes: in that case, you can [convert](./menu/edit) your tracks to routes, or [create](./menu/file) a route file from the start.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Points of interest
|
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Points of interest
|
||||||
|
|
||||||
**Points of interest** (technically called _waypoints_) represent locations of interest to show either on a GPS device or on a digital map.
|
**Points of interest** (technically called _waypoints_) represent locations of interest to show either on a GPS device or on a digital map.
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ title: Edit actions
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Undo2, Redo2, Info, PaintBucket, ArrowRightLeft, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Plus } from '@lucide/svelte';
|
import { Undo2, Redo2, Info, PaintBucket, EyeOff, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Maximize, Plus } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
Unlike the file actions, the edit actions can potentially modify the content of the currently selected files.
|
Unlike the file actions, the edit actions can potentially modify the content of the currently selected files.
|
||||||
Moreover, when the tree layout of the files list is enabled (see [Files and statistics](../files-and-stats)), they can also be applied to [tracks, segments, routes, and points of interest](../gpx).
|
Moreover, when the tree layout of the files list is enabled (see [Files and statistics](../files-and-stats)), they can also be applied to [tracks, segments, and points of interest](../gpx).
|
||||||
Therefore, we will refer to the elements that can be modified by these actions as _file items_.
|
Therefore, we will refer to the elements that can be modified by these actions as _file items_.
|
||||||
Note that except for the undo and redo actions, the edit actions are also accessible through the context menu (right-click) of the file items.
|
Note that except for the undo and redo actions, the edit actions are also accessible through the context menu (right-click) of the file items.
|
||||||
|
|
||||||
@@ -27,6 +27,10 @@ Open the information dialog of the currently selected file item, where you can s
|
|||||||
|
|
||||||
Open the appearance dialog, where you can change the color, opacity, and width of the selected file items on the map.
|
Open the appearance dialog, where you can change the color, opacity, and width of the selected file items on the map.
|
||||||
|
|
||||||
|
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Hide/unhide
|
||||||
|
|
||||||
|
Toggle the visibility of the selected file items on the map.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New track
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New track
|
||||||
|
|
||||||
Create a new track in the selected file.
|
Create a new track in the selected file.
|
||||||
@@ -38,17 +42,6 @@ Additionally, the selection must be a single file.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New route
|
|
||||||
|
|
||||||
Create a new route in the selected file.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
This action is only available when the tree layout of the files list is enabled.
|
|
||||||
Additionally, the selection must be a single file.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New segment
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New segment
|
||||||
|
|
||||||
Create a new segment in the selected track.
|
Create a new segment in the selected track.
|
||||||
@@ -60,17 +53,14 @@ Additionally, the selection must be a single track.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <ArrowRightLeft size="16" class="inline-block" style="margin-bottom: 2px" /> Convert to route/track
|
|
||||||
|
|
||||||
Convert the selected routes to tracks, or the selected tracks or segments to routes.
|
|
||||||
Since a route has a single segment, a track with multiple segments is converted into one route per segment.
|
|
||||||
|
|
||||||
When the selected files contain only routes, or only tracks, you can also convert all of them at once.
|
|
||||||
|
|
||||||
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Select all
|
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Select all
|
||||||
|
|
||||||
Add all file items in the current hierarchy level to the selection.
|
Add all file items in the current hierarchy level to the selection.
|
||||||
|
|
||||||
|
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Center
|
||||||
|
|
||||||
|
Center the map on the selected file items.
|
||||||
|
|
||||||
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Kopier
|
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Kopier
|
||||||
|
|
||||||
Copy the selected file items to the clipboard.
|
Copy the selected file items to the clipboard.
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ The file actions menu contains a set of pretty self-explanatory file operations.
|
|||||||
|
|
||||||
Create a new empty file.
|
Create a new empty file.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New route file
|
|
||||||
|
|
||||||
Create a new file containing an empty [route](../gpx).
|
|
||||||
|
|
||||||
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Open...
|
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Open...
|
||||||
|
|
||||||
Open files from your computer.
|
Open files from your computer.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: View options
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, EyeOff, Maximize, Box, Maximize2 } from '@lucide/svelte';
|
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, Box, Maximize2 } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ Hide the elevation profile to make room for the map, or show it to inspect the c
|
|||||||
|
|
||||||
Toggle the tree layout for the [file list](../files-and-stats).
|
Toggle the tree layout for the [file list](../files-and-stats).
|
||||||
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map.
|
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map.
|
||||||
In addition, the file tree view enables you to inspect the [tracks, segments, routes, and points of interest](../gpx) contained inside the files through collapsible sections.
|
In addition, the file tree view enables you to inspect the [tracks, segments, and points of interest](../gpx) contained inside the files through collapsible sections.
|
||||||
|
|
||||||
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Switch to previous basemap
|
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Switch to previous basemap
|
||||||
|
|
||||||
@@ -38,14 +38,6 @@ They are displayed for the current selection, like the [elevation profile](../fi
|
|||||||
|
|
||||||
Toggle the visibility of direction arrows on the map.
|
Toggle the visibility of direction arrows on the map.
|
||||||
|
|
||||||
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Hide/unhide
|
|
||||||
|
|
||||||
Toggle the visibility of the selected file items on the map.
|
|
||||||
|
|
||||||
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Center
|
|
||||||
|
|
||||||
Center the map on the selected file items.
|
|
||||||
|
|
||||||
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Toggle 3D
|
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Toggle 3D
|
||||||
|
|
||||||
Enter or exit the 3D map view.
|
Enter or exit the 3D map view.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ This tool allows you to extract [tracks (or segments)](../gpx) from files (or tr
|
|||||||
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Applying the tool to a file containing multiple [tracks or routes](../gpx) will create a new file for each of the tracks and routes it contains.
|
Applying the tool to a file containing multiple tracks will create a new file for each of the tracks it contains.
|
||||||
Similarly, applying the tool to a track containing multiple segments will create (in the same file) a new track for each of the segments it contains.
|
Similarly, applying the tool to a track containing multiple segments will create (in the same file) a new track for each of the segments it contains.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ title: Merge
|
|||||||
|
|
||||||
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
||||||
|
|
||||||
To use this tool, you need to [select](../files-and-stats) multiple files, [tracks, segments or routes](../gpx).
|
To use this tool, you need to [select](../files-and-stats) multiple files, [tracks, or segments](../gpx).
|
||||||
|
|
||||||
- If your goal is to create a single continuous trace from your selection, use the **Connect the traces** option and validate.
|
- If your goal is to create a single continuous trace from your selection, use the **Connect the traces** option and validate.
|
||||||
- The second option can be used to create or manage files with multiple [tracks, segments or routes](../gpx).
|
- The second option can be used to create or manage files with multiple [tracks or segments](../gpx).
|
||||||
Merging files (or tracks) will result in a single file (or track) containing all tracks and routes (or segments) from the selection.
|
Merging files (or tracks) will result in a single file (or track) containing all tracks (or segments) from the selection.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,6 @@ To split the selected trace into two parts, click on one of the split markers di
|
|||||||
To split at a specific point of your choice, hover over the trace on the map.
|
To split at a specific point of your choice, hover over the trace on the map.
|
||||||
Scissors will appear at the cursor position, showing that you can split the trace at that point.
|
Scissors will appear at the cursor position, showing that you can split the trace at that point.
|
||||||
|
|
||||||
You can choose to split the trace into two GPX files, or to keep the split parts in the same file as [tracks, segments or routes](../gpx).
|
You can choose to split the trace into two GPX files, or to keep the split parts in the same file as [tracks or segments](../gpx).
|
||||||
|
|
||||||
<DocsImage src="tools/split" alt="Hovering over the selected trace turns your cursor into scissors." />
|
<DocsImage src="tools/split" alt="Hovering over the selected trace turns your cursor into scissors." />
|
||||||
@@ -51,7 +51,7 @@ Wenn du mit der rechten Maustaste auf einen Datei-Tab klickst, kannst du auf die
|
|||||||
|
|
||||||
Wie schon in den Anzeigeoptionen (/Menü/Ansicht) erwähnt, kann man das Layout des Dateibaums für die Dateienliste anpassen.
|
Wie schon in den Anzeigeoptionen (/Menü/Ansicht) erwähnt, kann man das Layout des Dateibaums für die Dateienliste anpassen.
|
||||||
Dieses Layout eignet sich am besten um für eine große Anzahl von Dateien, da es diese in einer vertikalen Liste auf der rechten Seite der Karte anordnet.
|
Dieses Layout eignet sich am besten um für eine große Anzahl von Dateien, da es diese in einer vertikalen Liste auf der rechten Seite der Karte anordnet.
|
||||||
In addition, the file tree view enables you to inspect the [tracks, segments, routes, and points of interest](./gpx) contained inside the files through collapsible sections.
|
Darüber hinaus ermöglicht die Dateibaumansicht die Prüfung der [Tracks, Segmente, und Punkte von Interesse](./gpx), die in den Dateien durch zusammenklappbare Abschnitte enthalten sind.
|
||||||
|
|
||||||
Du kannst auch [Bearbeiten von Aktionen](./menu/edit) und [tools](./toolbar) auf interne Dateielemente anwenden.
|
Du kannst auch [Bearbeiten von Aktionen](./menu/edit) und [tools](./toolbar) auf interne Dateielemente anwenden.
|
||||||
Außerdem können Sie die inneren Elemente per Drag & Drop verschieben, um sie neu zu ordnen oder in die Hierarchie oder sogar in eine andere Datei zu verschieben.
|
Außerdem können Sie die inneren Elemente per Drag & Drop verschieben, um sie neu zu ordnen oder in die Hierarchie oder sogar in eine andere Datei zu verschieben.
|
||||||
|
|||||||
@@ -3,15 +3,13 @@ title: GPX Dateiformat
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import { Waypoints, MapPin } from '@lucide/svelte';
|
||||||
import { Waypoints, Route, MapPin } from '@lucide/svelte';
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
Das <a href="https://www.topografix.com/gpx.asp" target="_blank">GPX-Dateiformat</a> ist ein offener Standard für den Austausch von GPS-Daten zwischen Anwendungen und GPS-Geräten.
|
Das <a href="https://www.topografix.com/gpx.asp" target="_blank">GPX-Dateiformat</a> ist ein offener Standard für den Austausch von GPS-Daten zwischen Anwendungen und GPS-Geräten.
|
||||||
Es besteht im Wesentlichen aus einer Serie von GPS-Punkten, die einen oder mehrere GPS-Spuren kodieren, und optional aus einigen interessanten Punkten.
|
Es besteht im Wesentlichen aus einer Serie von GPS-Punkten, die einen oder mehrere GPS-Spuren kodieren, und optional aus einigen interessanten Punkten.
|
||||||
These traces can be stored either as tracks or as routes.
|
|
||||||
|
|
||||||
GPX-Dateien können auch Metadaten enthalten, von denen die Felder **Name** und **Beschreibung** für Benutzer am nützlichsten sind.
|
GPX-Dateien können auch Metadaten enthalten, von denen die Felder **Name** und **Beschreibung** für Benutzer am nützlichsten sind.
|
||||||
|
|
||||||
@@ -29,20 +27,6 @@ Diese sind in einer hierarchischen Struktur mit Spuren auf der obersten Ebene or
|
|||||||
In den meisten Fällen enthalten GPX-Dateien einen einzigen Track mit einem Segment.
|
In den meisten Fällen enthalten GPX-Dateien einen einzigen Track mit einem Segment.
|
||||||
Die oben beschriebene Hierarchie erlaubt jedoch weitergehende Anwendungsfälle, wie zum Beispiel die Planung von Mehrtagestouren mit mehreren Varianten pro Tag.
|
Die oben beschriebene Hierarchie erlaubt jedoch weitergehende Anwendungsfälle, wie zum Beispiel die Planung von Mehrtagestouren mit mehreren Varianten pro Tag.
|
||||||
|
|
||||||
### <Route size="16" class="inline-block" style="margin-bottom: 2px" /> Routes
|
|
||||||
|
|
||||||
A **route** is a single continuous path made of a sequence of **route points**.
|
|
||||||
These are mandatory checkpoints, which correspond to the anchor points of the [routing tool](./toolbar/routing).
|
|
||||||
The points in between are only a suggested path connecting the route points.
|
|
||||||
Like a track, a route can have a **name**, a **description**, and **appearance properties**.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
Nowadays, most apps and GPS devices work perfectly well with tracks, even for navigation.
|
|
||||||
However, some of them only work with routes: in that case, you can [convert](./menu/edit) your tracks to routes, or [create](./menu/file) a route file from the start.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Punkte von Interesse
|
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Punkte von Interesse
|
||||||
|
|
||||||
**Points of Interessive** (technisch genannt _Wegpunkte_) stellen Orte dar, die auf einem GPS-Gerät oder auf einer digitalen Karte angezeigt werden.
|
**Points of Interessive** (technisch genannt _Wegpunkte_) stellen Orte dar, die auf einem GPS-Gerät oder auf einer digitalen Karte angezeigt werden.
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ title: Bearbeite Aktionen
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Undo2, Redo2, Info, PaintBucket, ArrowRightLeft, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Plus } from '@lucide/svelte';
|
import { Undo2, Redo2, Info, PaintBucket, EyeOff, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Maximize, Plus } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
Im Gegensatz zu den Datei-Aktionen können die Bearbeitungs-Aktionen möglicherweise den Inhalt der aktuell ausgewählten Dateien verändern.
|
Im Gegensatz zu den Datei-Aktionen können die Bearbeitungs-Aktionen möglicherweise den Inhalt der aktuell ausgewählten Dateien verändern.
|
||||||
Moreover, when the tree layout of the files list is enabled (see [Files and statistics](../files-and-stats)), they can also be applied to [tracks, segments, routes, and points of interest](../gpx).
|
Wenn das vertikale Layout der Dateiliste aktiviert ist (siehe [Dateien und Statistik](.. /files-and-stats)), können dieses auch auf [Tracks, Segmente und Points-of-Interest](../gpx) angewendet werden.
|
||||||
Daher bezeichnen wir die Elemente, die durch diese Aktionen geändert werden können, als _file items_.
|
Daher bezeichnen wir die Elemente, die durch diese Aktionen geändert werden können, als _file items_.
|
||||||
Beachte, dass die Bearbeitungsaktionen auch über das Kontextmenü (Rechtsklick) der Dateielemente zugänglich sind, ausgenommen von "rückgängig" und "wiederholen".
|
Beachte, dass die Bearbeitungsaktionen auch über das Kontextmenü (Rechtsklick) der Dateielemente zugänglich sind, ausgenommen von "rückgängig" und "wiederholen".
|
||||||
|
|
||||||
@@ -27,6 +27,10 @@ Dies gilt für alle Aktionen der Bedienoberfläche, aber nicht für Optionen, An
|
|||||||
|
|
||||||
Öffnen Sie das Dialogfeld Darstellung, in der Sie die Farbe, Deckkraft und Breite der ausgewählten Dateielemente auf der Karte ändern können.
|
Öffnen Sie das Dialogfeld Darstellung, in der Sie die Farbe, Deckkraft und Breite der ausgewählten Dateielemente auf der Karte ändern können.
|
||||||
|
|
||||||
|
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Einblenden/Ausblenden
|
||||||
|
|
||||||
|
Konfigurieren Sie die Sichtbarkeit der ausgewählten Dateielemente auf der Karte.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Neuer Track
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Neuer Track
|
||||||
|
|
||||||
Erstelle ein neues Segment im ausgewählten Track.
|
Erstelle ein neues Segment im ausgewählten Track.
|
||||||
@@ -38,17 +42,6 @@ Außerdem muss die Auswahl aus einem einzelnen Track bestehen.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New route
|
|
||||||
|
|
||||||
Create a new route in the selected file.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
Diese Aktion ist nur verfügbar, wenn das vertikale Layout der Dateiliste aktiviert ist.
|
|
||||||
Außerdem muss die Auswahl aus einem einzelnen Track bestehen.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Neues Segment
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Neues Segment
|
||||||
|
|
||||||
Erstelle ein neues Segment im ausgewählten Track.
|
Erstelle ein neues Segment im ausgewählten Track.
|
||||||
@@ -60,17 +53,14 @@ Außerdem muss die Auswahl aus einem einzelnen Track bestehen.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <ArrowRightLeft size="16" class="inline-block" style="margin-bottom: 2px" /> Convert to route/track
|
|
||||||
|
|
||||||
Convert the selected routes to tracks, or the selected tracks or segments to routes.
|
|
||||||
Since a route has a single segment, a track with multiple segments is converted into one route per segment.
|
|
||||||
|
|
||||||
When the selected files contain only routes, or only tracks, you can also convert all of them at once.
|
|
||||||
|
|
||||||
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Alle auswählen
|
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Alle auswählen
|
||||||
|
|
||||||
Alle Dateielemente in der aktuellen Hierarchieebene zur Auswahl hinzufügen.
|
Alle Dateielemente in der aktuellen Hierarchieebene zur Auswahl hinzufügen.
|
||||||
|
|
||||||
|
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Zentrieren
|
||||||
|
|
||||||
|
Zentrieren der Karte auf den ausgewählten Dateielementen.
|
||||||
|
|
||||||
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Kopieren
|
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Kopieren
|
||||||
|
|
||||||
Kopieren Sie die ausgewählten Dateielemente in die Zwischenablage.
|
Kopieren Sie die ausgewählten Dateielemente in die Zwischenablage.
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ Das Aktionsmenü Datei enthält eine Reihe von selbsterklärenden Dateioperation
|
|||||||
|
|
||||||
Neue leere Datei erstellen.
|
Neue leere Datei erstellen.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New route file
|
|
||||||
|
|
||||||
Create a new file containing an empty [route](../gpx).
|
|
||||||
|
|
||||||
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Öffnen...
|
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Öffnen...
|
||||||
|
|
||||||
Öffne Dateien von Ihrem Computer.
|
Öffne Dateien von Ihrem Computer.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: Anzeigeoptionen
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, EyeOff, Maximize, Box, Maximize2 } from '@lucide/svelte';
|
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, Box, Maximize2 } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ Das Höhenprofil ausblenden, um Platz für die Karte zu schaffen, oder um die ak
|
|||||||
|
|
||||||
Umschalten des vertikalen Layouts für die [Dateiliste](../files-and-stats).
|
Umschalten des vertikalen Layouts für die [Dateiliste](../files-and-stats).
|
||||||
Dieses Layout eignet sich am besten um für eine große Anzahl von Dateien, da es diese in einer vertikalen Liste auf der rechten Seite der Karte anordnet.
|
Dieses Layout eignet sich am besten um für eine große Anzahl von Dateien, da es diese in einer vertikalen Liste auf der rechten Seite der Karte anordnet.
|
||||||
In addition, the file tree view enables you to inspect the [tracks, segments, routes, and points of interest](../gpx) contained inside the files through collapsible sections.
|
Darüber hinaus ermöglicht die Dateibaumansicht die Prüfung der [Tracks, Segmente, und Punkte von Interesse](../gpx), die in den Dateien durch zusammenklappbare Abschnitte enthalten sind.
|
||||||
|
|
||||||
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Wechseln zur vorherigen Basiskarte
|
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Wechseln zur vorherigen Basiskarte
|
||||||
|
|
||||||
@@ -38,14 +38,6 @@ Sie werden für die aktuelle Auswahl angezeigt, wie in [elevation profile](../fi
|
|||||||
|
|
||||||
Schaltet die Sichtbarkeit der Richtungspfeile auf der Karte um.
|
Schaltet die Sichtbarkeit der Richtungspfeile auf der Karte um.
|
||||||
|
|
||||||
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Hide/unhide
|
|
||||||
|
|
||||||
Toggle the visibility of the selected file items on the map.
|
|
||||||
|
|
||||||
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Center
|
|
||||||
|
|
||||||
Center the map on the selected file items.
|
|
||||||
|
|
||||||
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> 3D Ein/Aus
|
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> 3D Ein/Aus
|
||||||
|
|
||||||
Aufrufen oder Beenden der 3D-Kartenansicht.
|
Aufrufen oder Beenden der 3D-Kartenansicht.
|
||||||
|
|||||||
@@ -19,6 +19,6 @@ Mit diesem Tool kannst du Höhendaten zu Routen und [Points of Interest] (../gpx
|
|||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|
||||||
Elevation data is provided by <a href="https://mapterhorn.com" target="_blank">Mapterhorn</a>.
|
Elevation data is provided by <a href="https://mapterhorn.com" target="_blank">Mapterhorn</a>.
|
||||||
Mehr über die Herkunft und Genauigkeit erfährst du in der <a href="https://mapterhorn.com/attribution/" target="_blank">Dokumentation</a>.
|
You can learn more about its origin and accuracy in the <a href="https://mapterhorn.com/attribution/" target="_blank">documentation</a>.
|
||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
@@ -16,7 +16,7 @@ Dieses Werkzeug ermöglicht Ihnen [Tracks (oder Segmente)](../gpx) von Dateien (
|
|||||||
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Applying the tool to a file containing multiple [tracks or routes](../gpx) will create a new file for each of the tracks and routes it contains.
|
Wenn Sie das Werkzeug auf eine Datei mit mehreren enthaltenen Tracks anwenden, wird für jeden der darin enthaltenen Tracks eine neue Datei erstellt.
|
||||||
Gleichermaßen gilt: wenn du das Werkzeug auf einen Track anwendest, der mehrere Segmente enthält, wird (in derselben Datei) ein neuer Track für jedes der darin enthaltenen Segmente erstellt.
|
Gleichermaßen gilt: wenn du das Werkzeug auf einen Track anwendest, der mehrere Segmente enthält, wird (in derselben Datei) ein neuer Track für jedes der darin enthaltenen Segmente erstellt.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ title: Zusammenfügen
|
|||||||
|
|
||||||
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
||||||
|
|
||||||
To use this tool, you need to [select](../files-and-stats) multiple files, [tracks, segments or routes](../gpx).
|
Um dieses Tool nutzen zu können, musst du [select](../files-and-stats) mehrere Dateien, [Tracks oder Segmente](../gpx).
|
||||||
|
|
||||||
- Wenn Ihr Ziel darin besteht, eine einzige kontinuierliche Spur aus Ihrer Auswahl zu erstellen, verwenden Sie die Option **Verbinden Sie die Spuren** und validieren Sie sie.
|
- Wenn Ihr Ziel darin besteht, eine einzige kontinuierliche Spur aus Ihrer Auswahl zu erstellen, verwenden Sie die Option **Verbinden Sie die Spuren** und validieren Sie sie.
|
||||||
- The second option can be used to create or manage files with multiple [tracks, segments or routes](../gpx).
|
- Die zweite Option kann verwendet werden, um Dateien mit mehreren [Tracks oder Segments](../gpx) zu erstellen oder zu verwalten.
|
||||||
Merging files (or tracks) will result in a single file (or track) containing all tracks and routes (or segments) from the selection.
|
Das Zusammenführen von Dateien (oder Tracks) führt zu einer einzigen Datei (oder Track), die alle Tracks (oder Segmente) aus der Auswahl enthält.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,6 @@ Um die ausgewählte Spur in zwei Teile aufzuteilen, klicken Sie auf einen der ge
|
|||||||
Um sich an einem bestimmten Punkt Ihrer Wahl zu teilen, fahren Sie über die Spur auf der Karte.
|
Um sich an einem bestimmten Punkt Ihrer Wahl zu teilen, fahren Sie über die Spur auf der Karte.
|
||||||
Schere werden an der Cursorposition angezeigt, so dass Sie die Spur an diesem Punkt teilen können.
|
Schere werden an der Cursorposition angezeigt, so dass Sie die Spur an diesem Punkt teilen können.
|
||||||
|
|
||||||
You can choose to split the trace into two GPX files, or to keep the split parts in the same file as [tracks, segments or routes](../gpx).
|
Du kannst die Trace in zwei GPX-Dateien aufteilen oder die Teile in der gleichen Datei wie [Tracks oder Segmente](../gpx).
|
||||||
|
|
||||||
<DocsImage src="tools/split" alt="Über dem ausgewählten Pfad schweben verwandelt den Cursor in Scheren." />
|
<DocsImage src="tools/split" alt="Über dem ausgewählten Pfad schweben verwandelt den Cursor in Scheren." />
|
||||||
@@ -51,7 +51,7 @@ By right-clicking on a file tab, you can access the same actions as in the [edit
|
|||||||
|
|
||||||
As mentioned in the [view options section](./menu/view), you can switch to a tree layout for the files list.
|
As mentioned in the [view options section](./menu/view), you can switch to a tree layout for the files list.
|
||||||
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map.
|
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map.
|
||||||
In addition, the file tree view enables you to inspect the [tracks, segments, routes, and points of interest](./gpx) contained inside the files through collapsible sections.
|
In addition, the file tree view enables you to inspect the [tracks, segments, and points of interest](./gpx) contained inside the files through collapsible sections.
|
||||||
|
|
||||||
You can also apply [edit actions](./menu/edit) and [tools](./toolbar) to internal file items.
|
You can also apply [edit actions](./menu/edit) and [tools](./toolbar) to internal file items.
|
||||||
Furthermore, you can drag and drop the inner items to reorder them, or move them in the hierarchy or even to another file.
|
Furthermore, you can drag and drop the inner items to reorder them, or move them in the hierarchy or even to another file.
|
||||||
|
|||||||
@@ -3,15 +3,13 @@ title: GPX file format
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import { Waypoints, MapPin } from '@lucide/svelte';
|
||||||
import { Waypoints, Route, MapPin } from '@lucide/svelte';
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
The <a href="https://www.topografix.com/gpx.asp" target="_blank">GPX file format</a> is an open standard for exchanging GPS data between applications and GPS devices.
|
The <a href="https://www.topografix.com/gpx.asp" target="_blank">GPX file format</a> is an open standard for exchanging GPS data between applications and GPS devices.
|
||||||
It essentially consists of a series of GPS points encoding one or multiple GPS traces, and, optionally, some points of interest.
|
It essentially consists of a series of GPS points encoding one or multiple GPS traces, and, optionally, some points of interest.
|
||||||
These traces can be stored either as tracks or as routes.
|
|
||||||
|
|
||||||
GPX files may also contain metadata, of which the **name** and **description** fields are the most useful for users.
|
GPX files may also contain metadata, of which the **name** and **description** fields are the most useful for users.
|
||||||
|
|
||||||
@@ -29,20 +27,6 @@ These are organized in a hierarchical structure, with tracks at the top level.
|
|||||||
In most cases, GPX files contain a single track with a single segment.
|
In most cases, GPX files contain a single track with a single segment.
|
||||||
However, the hierarchy described above allows for more advanced use cases, such as planning multi-day trips with several variants for each day.
|
However, the hierarchy described above allows for more advanced use cases, such as planning multi-day trips with several variants for each day.
|
||||||
|
|
||||||
### <Route size="16" class="inline-block" style="margin-bottom: 2px" /> Routes
|
|
||||||
|
|
||||||
A **route** is a single continuous path made of a sequence of **route points**.
|
|
||||||
These are mandatory checkpoints, which correspond to the anchor points of the [routing tool](./toolbar/routing).
|
|
||||||
The points in between are only a suggested path connecting the route points.
|
|
||||||
Like a track, a route can have a **name**, a **description**, and **appearance properties**.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
Nowadays, most apps and GPS devices work perfectly well with tracks, even for navigation.
|
|
||||||
However, some of them only work with routes: in that case, you can [convert](./menu/edit) your tracks to routes, or [create](./menu/file) a route file from the start.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Points of interest
|
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Points of interest
|
||||||
|
|
||||||
**Points of interest** (technically called _waypoints_) represent locations of interest to show either on a GPS device or on a digital map.
|
**Points of interest** (technically called _waypoints_) represent locations of interest to show either on a GPS device or on a digital map.
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ title: Edit actions
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Undo2, Redo2, Info, PaintBucket, ArrowRightLeft, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Plus } from '@lucide/svelte';
|
import { Undo2, Redo2, Info, PaintBucket, EyeOff, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Maximize, Plus } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
Unlike the file actions, the edit actions can potentially modify the content of the currently selected files.
|
Unlike the file actions, the edit actions can potentially modify the content of the currently selected files.
|
||||||
Moreover, when the tree layout of the files list is enabled (see [Files and statistics](../files-and-stats)), they can also be applied to [tracks, segments, routes, and points of interest](../gpx).
|
Moreover, when the tree layout of the files list is enabled (see [Files and statistics](../files-and-stats)), they can also be applied to [tracks, segments, and points of interest](../gpx).
|
||||||
Therefore, we will refer to the elements that can be modified by these actions as _file items_.
|
Therefore, we will refer to the elements that can be modified by these actions as _file items_.
|
||||||
Note that except for the undo and redo actions, the edit actions are also accessible through the context menu (right-click) of the file items.
|
Note that except for the undo and redo actions, the edit actions are also accessible through the context menu (right-click) of the file items.
|
||||||
|
|
||||||
@@ -27,6 +27,10 @@ Open the information dialog of the currently selected file item, where you can s
|
|||||||
|
|
||||||
Open the appearance dialog, where you can change the color, opacity, and width of the selected file items on the map.
|
Open the appearance dialog, where you can change the color, opacity, and width of the selected file items on the map.
|
||||||
|
|
||||||
|
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Hide/unhide
|
||||||
|
|
||||||
|
Toggle the visibility of the selected file items on the map.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New track
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New track
|
||||||
|
|
||||||
Create a new track in the selected file.
|
Create a new track in the selected file.
|
||||||
@@ -38,17 +42,6 @@ Additionally, the selection must be a single file.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New route
|
|
||||||
|
|
||||||
Create a new route in the selected file.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
This action is only available when the tree layout of the files list is enabled.
|
|
||||||
Additionally, the selection must be a single file.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New segment
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New segment
|
||||||
|
|
||||||
Create a new segment in the selected track.
|
Create a new segment in the selected track.
|
||||||
@@ -60,17 +53,14 @@ Additionally, the selection must be a single track.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <ArrowRightLeft size="16" class="inline-block" style="margin-bottom: 2px" /> Convert to route/track
|
|
||||||
|
|
||||||
Convert the selected routes to tracks, or the selected tracks or segments to routes.
|
|
||||||
Since a route has a single segment, a track with multiple segments is converted into one route per segment.
|
|
||||||
|
|
||||||
When the selected files contain only routes, or only tracks, you can also convert all of them at once.
|
|
||||||
|
|
||||||
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Select all
|
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Select all
|
||||||
|
|
||||||
Add all file items in the current hierarchy level to the selection.
|
Add all file items in the current hierarchy level to the selection.
|
||||||
|
|
||||||
|
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Center
|
||||||
|
|
||||||
|
Center the map on the selected file items.
|
||||||
|
|
||||||
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Copy
|
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Copy
|
||||||
|
|
||||||
Copy the selected file items to the clipboard.
|
Copy the selected file items to the clipboard.
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ The file actions menu contains a set of pretty self-explanatory file operations.
|
|||||||
|
|
||||||
Create a new empty file.
|
Create a new empty file.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New route file
|
|
||||||
|
|
||||||
Create a new file containing an empty [route](../gpx).
|
|
||||||
|
|
||||||
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Open...
|
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Open...
|
||||||
|
|
||||||
Open files from your computer.
|
Open files from your computer.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: View options
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, EyeOff, Maximize, Box, Maximize2 } from '@lucide/svelte';
|
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, Box, Maximize2 } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ Hide the elevation profile to make room for the map, or show it to inspect the c
|
|||||||
|
|
||||||
Toggle the tree layout for the [file list](../files-and-stats).
|
Toggle the tree layout for the [file list](../files-and-stats).
|
||||||
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map.
|
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map.
|
||||||
In addition, the file tree view enables you to inspect the [tracks, segments, routes, and points of interest](../gpx) contained inside the files through collapsible sections.
|
In addition, the file tree view enables you to inspect the [tracks, segments, and points of interest](../gpx) contained inside the files through collapsible sections.
|
||||||
|
|
||||||
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Switch to previous basemap
|
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Switch to previous basemap
|
||||||
|
|
||||||
@@ -38,14 +38,6 @@ They are displayed for the current selection, like the [elevation profile](../fi
|
|||||||
|
|
||||||
Toggle the visibility of direction arrows on the map.
|
Toggle the visibility of direction arrows on the map.
|
||||||
|
|
||||||
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Hide/unhide
|
|
||||||
|
|
||||||
Toggle the visibility of the selected file items on the map.
|
|
||||||
|
|
||||||
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Center
|
|
||||||
|
|
||||||
Center the map on the selected file items.
|
|
||||||
|
|
||||||
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Toggle 3D
|
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Toggle 3D
|
||||||
|
|
||||||
Enter or exit the 3D map view.
|
Enter or exit the 3D map view.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ This tool allows you to extract [tracks (or segments)](../gpx) from files (or tr
|
|||||||
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Applying the tool to a file containing multiple [tracks or routes](../gpx) will create a new file for each of the tracks and routes it contains.
|
Applying the tool to a file containing multiple tracks will create a new file for each of the tracks it contains.
|
||||||
Similarly, applying the tool to a track containing multiple segments will create (in the same file) a new track for each of the segments it contains.
|
Similarly, applying the tool to a track containing multiple segments will create (in the same file) a new track for each of the segments it contains.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ title: Merge
|
|||||||
|
|
||||||
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
||||||
|
|
||||||
To use this tool, you need to [select](../files-and-stats) multiple files, [tracks, segments or routes](../gpx).
|
To use this tool, you need to [select](../files-and-stats) multiple files, [tracks, or segments](../gpx).
|
||||||
|
|
||||||
- If your goal is to create a single continuous trace from your selection, use the **Connect the traces** option and validate.
|
- If your goal is to create a single continuous trace from your selection, use the **Connect the traces** option and validate.
|
||||||
- The second option can be used to create or manage files with multiple [tracks, segments or routes](../gpx).
|
- The second option can be used to create or manage files with multiple [tracks or segments](../gpx).
|
||||||
Merging files (or tracks) will result in a single file (or track) containing all tracks and routes (or segments) from the selection.
|
Merging files (or tracks) will result in a single file (or track) containing all tracks (or segments) from the selection.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,6 @@ To split the selected trace into two parts, click on one of the split markers di
|
|||||||
To split at a specific point of your choice, hover over the trace on the map.
|
To split at a specific point of your choice, hover over the trace on the map.
|
||||||
Scissors will appear at the cursor position, showing that you can split the trace at that point.
|
Scissors will appear at the cursor position, showing that you can split the trace at that point.
|
||||||
|
|
||||||
You can choose to split the trace into two GPX files, or to keep the split parts in the same file as [tracks, segments or routes](../gpx).
|
You can choose to split the trace into two GPX files, or to keep the split parts in the same file as [tracks or segments](../gpx).
|
||||||
|
|
||||||
<DocsImage src="tools/split" alt="Hovering over the selected trace turns your cursor into scissors." />
|
<DocsImage src="tools/split" alt="Hovering over the selected trace turns your cursor into scissors." />
|
||||||
@@ -67,6 +67,12 @@ Since a route has a single segment, a track with multiple segments is converted
|
|||||||
|
|
||||||
When the selected files contain only routes, or only tracks, you can also convert all of them at once.
|
When the selected files contain only routes, or only tracks, you can also convert all of them at once.
|
||||||
|
|
||||||
|
<DocsNote>
|
||||||
|
|
||||||
|
Except for whole files, this action is only available when the tree layout of the files list is enabled.
|
||||||
|
|
||||||
|
</DocsNote>
|
||||||
|
|
||||||
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Select all
|
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Select all
|
||||||
|
|
||||||
Add all file items in the current hierarchy level to the selection.
|
Add all file items in the current hierarchy level to the selection.
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ Al hacer clic con el botón derecho en una pestaña de archivo, puede acceder a
|
|||||||
|
|
||||||
Como se mencionó en la [sección de opciones de vista](./menu/view), puede cambiar a un esquema de árbol para la lista de archivos.
|
Como se mencionó en la [sección de opciones de vista](./menu/view), puede cambiar a un esquema de árbol para la lista de archivos.
|
||||||
Esta disposición es ideal para administrar un gran número de archivos abiertos ya que los organiza en una lista vertical en la parte derecha del mapa.
|
Esta disposición es ideal para administrar un gran número de archivos abiertos ya que los organiza en una lista vertical en la parte derecha del mapa.
|
||||||
In addition, the file tree view enables you to inspect the [tracks, segments, routes, and points of interest](./gpx) contained inside the files through collapsible sections.
|
Además, la vista de árbol de archivos permite inspeccionar [pistas, segmentos y puntos de interés](./gpx) contenidos dentro de los archivos a través de secciones plegables.
|
||||||
|
|
||||||
También puede aplicar [acciones de edición](./menu/edit) y [herramientas](./toolbar) a los elementos internos del archivo.
|
También puede aplicar [acciones de edición](./menu/edit) y [herramientas](./toolbar) a los elementos internos del archivo.
|
||||||
Además, puede arrastrar y soltar los elementos internos para reordenarlos, o moverlos dentro de la jerarquía o incluso a otro archivo.
|
Además, puede arrastrar y soltar los elementos internos para reordenarlos, o moverlos dentro de la jerarquía o incluso a otro archivo.
|
||||||
|
|||||||
@@ -3,15 +3,13 @@ title: Formato de archivo GPX
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import { Waypoints, MapPin } from '@lucide/svelte';
|
||||||
import { Waypoints, Route, MapPin } from '@lucide/svelte';
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
El <a href="https://www.topografix.com/gpx.asp" target="_blank">formato de archivo GPX</a> es un estándar abierto para el intercambio de datos GPS entre aplicaciones y dispositivos GPS.
|
El <a href="https://www.topografix.com/gpx.asp" target="_blank">formato de archivo GPX</a> es un estándar abierto para el intercambio de datos GPS entre aplicaciones y dispositivos GPS.
|
||||||
Consiste esencialmente en una serie de puntos GPS que codifican uno o varios trazados GPS y, opcionalmente, algunos puntos de interés.
|
Consiste esencialmente en una serie de puntos GPS que codifican uno o varios trazados GPS y, opcionalmente, algunos puntos de interés.
|
||||||
These traces can be stored either as tracks or as routes.
|
|
||||||
|
|
||||||
Los archivos GPX también pueden contener metadatos, de los cuales los campos **nombre** y **descripción** son los más útiles para los usuarios.
|
Los archivos GPX también pueden contener metadatos, de los cuales los campos **nombre** y **descripción** son los más útiles para los usuarios.
|
||||||
|
|
||||||
@@ -29,20 +27,6 @@ Como se mencionó anteriormente, un archivo GPX puede contener múltiples trazad
|
|||||||
En la mayoría de los casos, los archivos GPX contienen una sola pista con un solo segmento.
|
En la mayoría de los casos, los archivos GPX contienen una sola pista con un solo segmento.
|
||||||
Sin embargo, la jerarquía descrita anteriormente permite casos de uso más avanzados, como la planificación de viajes de varios días con varias variantes para cada día.
|
Sin embargo, la jerarquía descrita anteriormente permite casos de uso más avanzados, como la planificación de viajes de varios días con varias variantes para cada día.
|
||||||
|
|
||||||
### <Route size="16" class="inline-block" style="margin-bottom: 2px" /> Routes
|
|
||||||
|
|
||||||
A **route** is a single continuous path made of a sequence of **route points**.
|
|
||||||
These are mandatory checkpoints, which correspond to the anchor points of the [routing tool](./toolbar/routing).
|
|
||||||
The points in between are only a suggested path connecting the route points.
|
|
||||||
Like a track, a route can have a **name**, a **description**, and **appearance properties**.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
Nowadays, most apps and GPS devices work perfectly well with tracks, even for navigation.
|
|
||||||
However, some of them only work with routes: in that case, you can [convert](./menu/edit) your tracks to routes, or [create](./menu/file) a route file from the start.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Puntos de interés
|
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Puntos de interés
|
||||||
|
|
||||||
**Puntos de interés** (técnicamente llamados _waypoints_) representan ubicaciones de interés para mostrar en un dispositivo GPS o en un mapa digital.
|
**Puntos de interés** (técnicamente llamados _waypoints_) representan ubicaciones de interés para mostrar en un dispositivo GPS o en un mapa digital.
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ title: Acciones de edición
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Undo2, Redo2, Info, PaintBucket, ArrowRightLeft, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Plus } from '@lucide/svelte';
|
import { Undo2, Redo2, Info, PaintBucket, EyeOff, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Maximize, Plus } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
A diferencia de las acciones de archivo, las acciones de edición pueden potencialmente modificar el contenido de los archivos seleccionados actualmente.
|
A diferencia de las acciones de archivo, las acciones de edición pueden potencialmente modificar el contenido de los archivos seleccionados actualmente.
|
||||||
Moreover, when the tree layout of the files list is enabled (see [Files and statistics](../files-and-stats)), they can also be applied to [tracks, segments, routes, and points of interest](../gpx).
|
Además, cuando está habilitada la disposición del árbol de la lista de archivos (ver [Archivos y estadísticas](../files-and-stats)), se pueden aplicar a [pistas, segmentos y puntos de interés](../gpx).
|
||||||
Por lo tanto, nos referiremos a los elementos que pueden ser modificados por estas acciones como _elementos de archivo_.
|
Por lo tanto, nos referiremos a los elementos que pueden ser modificados por estas acciones como _elementos de archivo_.
|
||||||
Tenga en cuenta que, excepto para las acciones de deshacer y rehacer, las acciones de edición también son accesibles a través del menú contextual (clic derecho) de los elementos del archivo.
|
Tenga en cuenta que, excepto para las acciones de deshacer y rehacer, las acciones de edición también son accesibles a través del menú contextual (clic derecho) de los elementos del archivo.
|
||||||
|
|
||||||
@@ -27,6 +27,10 @@ Abre el cuadro de diálogo de información del elemento del archivo seleccionado
|
|||||||
|
|
||||||
Abre el diálogo de apariencia, donde puede cambiar el color, la opacidad y el ancho en el mapa de los elementos de archivo seleccionados.
|
Abre el diálogo de apariencia, donde puede cambiar el color, la opacidad y el ancho en el mapa de los elementos de archivo seleccionados.
|
||||||
|
|
||||||
|
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Ocultar/mostrar
|
||||||
|
|
||||||
|
Alterna la visibilidad de los elementos del archivo seleccionado en el mapa.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Nueva pista
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Nueva pista
|
||||||
|
|
||||||
Crear una nueva pista en el archivo seleccionado.
|
Crear una nueva pista en el archivo seleccionado.
|
||||||
@@ -38,17 +42,6 @@ Además, la selección debe ser un solo archivo.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New route
|
|
||||||
|
|
||||||
Create a new route in the selected file.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
Esta acción sólo está disponible cuando está habilitada la disposición del árbol de la lista de archivos.
|
|
||||||
Además, la selección debe ser un solo archivo.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Nuevo segmento
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Nuevo segmento
|
||||||
|
|
||||||
Crear un nuevo segmento en la pista seleccionada.
|
Crear un nuevo segmento en la pista seleccionada.
|
||||||
@@ -60,17 +53,14 @@ Además, la selección debe ser una sola pista.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <ArrowRightLeft size="16" class="inline-block" style="margin-bottom: 2px" /> Convert to route/track
|
|
||||||
|
|
||||||
Convert the selected routes to tracks, or the selected tracks or segments to routes.
|
|
||||||
Since a route has a single segment, a track with multiple segments is converted into one route per segment.
|
|
||||||
|
|
||||||
When the selected files contain only routes, or only tracks, you can also convert all of them at once.
|
|
||||||
|
|
||||||
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Seleccionar todo
|
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Seleccionar todo
|
||||||
|
|
||||||
Añade todos los elementos del archivo en el nivel de jerarquía actual a la selección.
|
Añade todos los elementos del archivo en el nivel de jerarquía actual a la selección.
|
||||||
|
|
||||||
|
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Centrar
|
||||||
|
|
||||||
|
Centrar el mapa en los elementos de archivo seleccionados.
|
||||||
|
|
||||||
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Copiar
|
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Copiar
|
||||||
|
|
||||||
Copia los elementos del archivo seleccionado al portapapeles.
|
Copia los elementos del archivo seleccionado al portapapeles.
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ El menú de acciones de archivo contiene un conjunto de operaciones bastante aut
|
|||||||
|
|
||||||
Crea un nuevo archivo vacío.
|
Crea un nuevo archivo vacío.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New route file
|
|
||||||
|
|
||||||
Create a new file containing an empty [route](../gpx).
|
|
||||||
|
|
||||||
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Abrir...
|
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Abrir...
|
||||||
|
|
||||||
Abre archivos desde su equipo.
|
Abre archivos desde su equipo.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: Opciones de vista
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, EyeOff, Maximize, Box, Maximize2 } from '@lucide/svelte';
|
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, Box, Maximize2 } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ Oculta el perfil de elevación para dejar espacio para el mapa, o lo muestra par
|
|||||||
|
|
||||||
Alterna el diseño de árbol para la [lista de archivos](../files-and-stats).
|
Alterna el diseño de árbol para la [lista de archivos](../files-and-stats).
|
||||||
Esta disposición es ideal para administrar un gran número de archivos abiertos ya que los organiza en una lista vertical en la parte derecha del mapa.
|
Esta disposición es ideal para administrar un gran número de archivos abiertos ya que los organiza en una lista vertical en la parte derecha del mapa.
|
||||||
In addition, the file tree view enables you to inspect the [tracks, segments, routes, and points of interest](../gpx) contained inside the files through collapsible sections.
|
Además, la vista de árbol de archivos le permite inspeccionar [pistas, segmentos y puntos de interés](../gpx) contenidos dentro de los archivos a través de secciones plegables.
|
||||||
|
|
||||||
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Cambiar al mapa base anterior
|
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Cambiar al mapa base anterior
|
||||||
|
|
||||||
@@ -38,14 +38,6 @@ Se muestran para la selección actual, como el [perfil de elevación](../files-a
|
|||||||
|
|
||||||
Alterna la visibilidad de las flechas de dirección en el mapa.
|
Alterna la visibilidad de las flechas de dirección en el mapa.
|
||||||
|
|
||||||
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Hide/unhide
|
|
||||||
|
|
||||||
Toggle the visibility of the selected file items on the map.
|
|
||||||
|
|
||||||
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Center
|
|
||||||
|
|
||||||
Center the map on the selected file items.
|
|
||||||
|
|
||||||
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Alternar 3D
|
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Alternar 3D
|
||||||
|
|
||||||
Entra o sale de la vista 3D del mapa.
|
Entra o sale de la vista 3D del mapa.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ Esta herramienta le permite extraer [pistas (o segmentos)](../gpx) de archivos (
|
|||||||
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Applying the tool to a file containing multiple [tracks or routes](../gpx) will create a new file for each of the tracks and routes it contains.
|
Aplicar la herramienta a un archivo que contenga múltiples pistas creará un nuevo archivo para cada una de las pistas.
|
||||||
Del mismo modo, la aplicación de la herramienta a una pista que contenga varios segmentos creará (en el mismo archivo) una nueva pista para cada uno de los segmentos.
|
Del mismo modo, la aplicación de la herramienta a una pista que contenga varios segmentos creará (en el mismo archivo) una nueva pista para cada uno de los segmentos.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ title: Combinar
|
|||||||
|
|
||||||
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
||||||
|
|
||||||
To use this tool, you need to [select](../files-and-stats) multiple files, [tracks, segments or routes](../gpx).
|
Para usar esta herramienta, necesita [seleccionar](../files-and-stats) múltiples archivos, [pistas o segmentos](../gpx).
|
||||||
|
|
||||||
- Si su objetivo es crear un único trazado continuo a partir de su selección, use la opción **Conectar los trazados** y valide.
|
- Si su objetivo es crear un único trazado continuo a partir de su selección, use la opción **Conectar los trazados** y valide.
|
||||||
- The second option can be used to create or manage files with multiple [tracks, segments or routes](../gpx).
|
- La segunda opción se puede usar para crear o gestionar archivos con múltiples [pistas o segmentos](../gpx).
|
||||||
Merging files (or tracks) will result in a single file (or track) containing all tracks and routes (or segments) from the selection.
|
Combinar archivos (o pistas) dará como resultado un único archivo (o pista) que contendrá todas las pistas (o segmentos) de la selección.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,6 @@ Para dividir el trazado seleccionado en dos partes, haga clic en uno de los marc
|
|||||||
Para dividir en un punto específico de su elección, sitúe el cursor sobre el trazado en el mapa.
|
Para dividir en un punto específico de su elección, sitúe el cursor sobre el trazado en el mapa.
|
||||||
Las tijeras aparecerán en la posición del cursor, mostrando que puede dividir el trazado en ese punto.
|
Las tijeras aparecerán en la posición del cursor, mostrando que puede dividir el trazado en ese punto.
|
||||||
|
|
||||||
You can choose to split the trace into two GPX files, or to keep the split parts in the same file as [tracks, segments or routes](../gpx).
|
Puede elegir dividir el trazado en dos archivos GPX o mantener las partes divididas en el mismo archivo como [pistas o segmentos](../gpx).
|
||||||
|
|
||||||
<DocsImage src="tools/split" alt="Situar el cursor sobre el trazado seleccionado lo convierte en tijeras." />
|
<DocsImage src="tools/split" alt="Situar el cursor sobre el trazado seleccionado lo convierte en tijeras." />
|
||||||
@@ -50,7 +50,7 @@ Fitxategi fitxa batean eskuin-klik eginez, [editatu menuko](./menu/edit) ekintza
|
|||||||
|
|
||||||
Aipatu bezala, [ikusi atalean](./menu/view), fitxategien zerrendaren zuhaitz diseinura alda dezakezu.
|
Aipatu bezala, [ikusi atalean](./menu/view), fitxategien zerrendaren zuhaitz diseinura alda dezakezu.
|
||||||
Diseinu hau aproposa da irekitako fitxategi ugari kudeatzeko, maparen eskuinaldean zerrenda bertikal batean antolatzen baitu.
|
Diseinu hau aproposa da irekitako fitxategi ugari kudeatzeko, maparen eskuinaldean zerrenda bertikal batean antolatzen baitu.
|
||||||
In addition, the file tree view enables you to inspect the [tracks, segments, routes, and points of interest](./gpx) contained inside the files through collapsible sections.
|
Gainera, fitxategi-zuhaitzaren ikuspegiak aukera ematen du [arrastoak, segmentuak eta interesguneak](./gpx) ikuskatzeko ataletan antolatutako fitxategietan.
|
||||||
|
|
||||||
[Edizio ekintzak](./menu/edit) eta [tresnak](./toolbar) fitxategien barneko elementuetara ere aplikatu ditzakezu.
|
[Edizio ekintzak](./menu/edit) eta [tresnak](./toolbar) fitxategien barneko elementuetara ere aplikatu ditzakezu.
|
||||||
Gainera, barruko elementuak arrastatu eta jaregin ditzakezu berrantolatzeko edo hierarkian edo beste fitxategi batera eraman.
|
Gainera, barruko elementuak arrastatu eta jaregin ditzakezu berrantolatzeko edo hierarkian edo beste fitxategi batera eraman.
|
||||||
|
|||||||
@@ -3,15 +3,13 @@ title: GPX fitxategi formatua
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import { Waypoints, MapPin } from '@lucide/svelte';
|
||||||
import { Waypoints, Route, MapPin } from '@lucide/svelte';
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
<a href="https://www.topografix.com/gpx.asp" target="_blank">GPX fitxategi formatua</a> GPS datuak aplikazioen eta GPS gailuen artean trukatzeko formatu ireki estandarra da.
|
<a href="https://www.topografix.com/gpx.asp" target="_blank">GPX fitxategi formatua</a> GPS datuak aplikazioen eta GPS gailuen artean trukatzeko formatu ireki estandarra da.
|
||||||
GPS puntu serie bat GPS arrasto bat edo gehiagotan bildua, eta, aukeran, interesgune batzuk.
|
GPS puntu serie bat GPS arrasto bat edo gehiagotan bildua, eta, aukeran, interesgune batzuk.
|
||||||
These traces can be stored either as tracks or as routes.
|
|
||||||
|
|
||||||
GPX fitxategiek metadatuak ere izan ditzakete, horien artean **izena** eta **deskribapena** eremuak erabiltzaileentzat erabilgarrienak izaten dira.
|
GPX fitxategiek metadatuak ere izan ditzakete, horien artean **izena** eta **deskribapena** eremuak erabiltzaileentzat erabilgarrienak izaten dira.
|
||||||
|
|
||||||
@@ -29,20 +27,6 @@ Egitura hierarkiko batean antolatuta daude, goiko mailan:
|
|||||||
Gehienetan, GPX fitxategiek segmentu bakarraz osatutako arrasto edo ibilbide bakarra dute.
|
Gehienetan, GPX fitxategiek segmentu bakarraz osatutako arrasto edo ibilbide bakarra dute.
|
||||||
Hala ere, goian deskribatutako hierarkiak erabilera kasu aurreratuagoak egiteko aukera ematen du, hala nola egun anitzeko bidaiak antolatzea egun bakoitzeko hainbat aldaerekin.
|
Hala ere, goian deskribatutako hierarkiak erabilera kasu aurreratuagoak egiteko aukera ematen du, hala nola egun anitzeko bidaiak antolatzea egun bakoitzeko hainbat aldaerekin.
|
||||||
|
|
||||||
### <Route size="16" class="inline-block" style="margin-bottom: 2px" /> Routes
|
|
||||||
|
|
||||||
A **route** is a single continuous path made of a sequence of **route points**.
|
|
||||||
These are mandatory checkpoints, which correspond to the anchor points of the [routing tool](./toolbar/routing).
|
|
||||||
The points in between are only a suggested path connecting the route points.
|
|
||||||
Like a track, a route can have a **name**, a **description**, and **appearance properties**.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
Nowadays, most apps and GPS devices work perfectly well with tracks, even for navigation.
|
|
||||||
However, some of them only work with routes: in that case, you can [convert](./menu/edit) your tracks to routes, or [create](./menu/file) a route file from the start.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Interesguneak
|
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Interesguneak
|
||||||
|
|
||||||
**Interesguneak** (_bide-puntu_ gisa ere ezagunak) interesgarriak diren kokapenak GPS gailu batean edo mapa digital batean erakusteko erabiltzen dira.
|
**Interesguneak** (_bide-puntu_ gisa ere ezagunak) interesgarriak diren kokapenak GPS gailu batean edo mapa digital batean erakusteko erabiltzen dira.
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ title: Integrazioa
|
|||||||
|
|
||||||
Behar duzun guztia hau da:
|
Behar duzun guztia hau da:
|
||||||
|
|
||||||
1. Zure zerbitzarian edo Google Drive-n ostatatutako GPX fitxategiak, edo URL publiko baten bidez eskura daitezke;
|
1. GPX files hosted on your server or on Google Drive, or accessible via a public URL;
|
||||||
2. _Aukerakoa:_ <a href="https://cloud.maptiler.com/auth/widget?next=https://cloud.maptiler.com/maps/" target="_blank">MapTiler tekla</a> MapTiler mapak kargatzeko.
|
2. _Optional:_ a <a href="https://cloud.maptiler.com/auth/widget?next=https://cloud.maptiler.com/maps/" target="_blank">MapTiler key</a> to load MapTiler maps.
|
||||||
|
|
||||||
Ondoren, konfiguratzailearekin jolastu dezakezu zure mapa pertsonalizatzeko eta dagokion HTML kodea sortzeko.
|
Ondoren, konfiguratzailearekin jolastu dezakezu zure mapa pertsonalizatzeko eta dagokion HTML kodea sortzeko.
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ Maparen geruzen botoiak mapa-oinarri desberdinen artean aldatzeko aukera ematen
|
|||||||
<DocsLayers />
|
<DocsLayers />
|
||||||
<span class="text-sm text-center mt-2">
|
<span class="text-sm text-center mt-2">
|
||||||
|
|
||||||
Pasa ezazu maparen gainean <a href="https://hiking.waymarkedtrails.org" target="_blank">markatutako mendi-ibiliak</a> gainjartzeko oinarrizko mapa topografikoaren gainean.
|
Hover over the map to show the <a href="https://hiking.waymarkedtrails.org" target="_blank">Waymarked Trails hiking</a> overlay on top of the topographic basemap.
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -69,4 +69,4 @@ Global eta tokiko mapa oinarri bilduma handia dago **gpx.studio**-n eskuragarri,
|
|||||||
|
|
||||||
Ezarpen horietan, gainjartzeen opakutasuna ere kudeatu dezakezu.
|
Ezarpen horietan, gainjartzeen opakutasuna ere kudeatu dezakezu.
|
||||||
|
|
||||||
Erabiltzaile aurreratuentzat, oinarrizko mapa pertsonalizatuak eta gainjartzeak gehi daitezke <a href="https://en.wikipedia.org/wiki/Web_Map_Tile_Service" target="_blank">WMTS</a>, <a href="https://en.wikipedia.org/wiki/Web_Map_Service" target="_blank">WMS</a> edo <a href="https://maplibre.org/maplibre-style-spec/" target="_blank">MapLibre estiloko JSON</a> URLak.
|
For advanced users, it is possible to add custom basemaps and overlays by providing <a href="https://en.wikipedia.org/wiki/Web_Map_Tile_Service" target="_blank">WMTS</a>, <a href="https://en.wikipedia.org/wiki/Web_Map_Service" target="_blank">WMS</a>, or <a href="https://maplibre.org/maplibre-style-spec/" target="_blank">MapLibre style JSON</a> URLs.
|
||||||
@@ -3,14 +3,14 @@ title: Edizio ekintzak
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Undo2, Redo2, Info, PaintBucket, ArrowRightLeft, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Plus } from '@lucide/svelte';
|
import { Undo2, Redo2, Info, PaintBucket, EyeOff, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Maximize, Plus } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
Fitxategi-ekintzak ez bezala, edizio-ekintzek hautatutako fitxategien edukia alda dezakete.
|
Fitxategi-ekintzak ez bezala, edizio-ekintzek hautatutako fitxategien edukia alda dezakete.
|
||||||
Moreover, when the tree layout of the files list is enabled (see [Files and statistics](../files-and-stats)), they can also be applied to [tracks, segments, routes, and points of interest](../gpx).
|
Are gehiago, fitxategien zerrendaren zuhaitzaren diseinua gaituta dagoenean (Ikusi [Fitxategiak eta estatistikak](../files-and-stats)), ekintzek [arrasto, segmentu eta interesgunetan](../gpx) ere aplikatu daitezke.
|
||||||
Hori dela eta, ekintza hauek alda dezaketen elementuei _fitxategi-elementuak_ izendatzen ditugu.
|
Hori dela eta, ekintza hauek alda dezaketen elementuei _fitxategi-elementuak_ izendatzen ditugu.
|
||||||
Ohar zaitez, desegin eta berregin ekintzak ez, beste guztiak fitxategi-elementu hauen alboko menuaren bidez (eskuin-klik) ere erabili daitezke.
|
Ohar zaitez, desegin eta berregin ekintzak ez, beste guztiak fitxategi-elementu hauen alboko menuaren bidez (eskuin-klik) ere erabili daitezke.
|
||||||
|
|
||||||
@@ -27,6 +27,10 @@ Ireki hautatutako fitxategiaren elementuaren elkarrizketa-koadroa, non bere izen
|
|||||||
|
|
||||||
Ireki Itxuraren elkarrizketa-koadroa, eta bertan mapan hautatutako elementuaren kolorea, opakotasuna eta zabalera alda ditzakezu.
|
Ireki Itxuraren elkarrizketa-koadroa, eta bertan mapan hautatutako elementuaren kolorea, opakotasuna eta zabalera alda ditzakezu.
|
||||||
|
|
||||||
|
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Ezkutatu/erakutsi
|
||||||
|
|
||||||
|
Aldatu mapan hautatutako elementuen ikusgarritasuna.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Arrasto berria
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Arrasto berria
|
||||||
|
|
||||||
Sortu arrasto berri bat hautatutako fitxategian.
|
Sortu arrasto berri bat hautatutako fitxategian.
|
||||||
@@ -38,17 +42,6 @@ Gainera, fitxategi bakarra egon behar du hautatuta.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New route
|
|
||||||
|
|
||||||
Create a new route in the selected file.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
Ekintza hau soilik aktibatuko da fitxategien zerrendako zuhaitz-geruza gaituta dagoenean.
|
|
||||||
Gainera, fitxategi bakarra egon behar du hautatuta.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Segmentu berria
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Segmentu berria
|
||||||
|
|
||||||
Sortu segmentu berri bat hautatutako arrastoan.
|
Sortu segmentu berri bat hautatutako arrastoan.
|
||||||
@@ -60,17 +53,14 @@ Gainera, arrasto bakarra egon behar du hautatuta.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <ArrowRightLeft size="16" class="inline-block" style="margin-bottom: 2px" /> Convert to route/track
|
|
||||||
|
|
||||||
Convert the selected routes to tracks, or the selected tracks or segments to routes.
|
|
||||||
Since a route has a single segment, a track with multiple segments is converted into one route per segment.
|
|
||||||
|
|
||||||
When the selected files contain only routes, or only tracks, you can also convert all of them at once.
|
|
||||||
|
|
||||||
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Hautatu denak
|
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Hautatu denak
|
||||||
|
|
||||||
Gehitu hautapenera uneko hierarkia mailako fitxategi elementu guztiak.
|
Gehitu hautapenera uneko hierarkia mailako fitxategi elementu guztiak.
|
||||||
|
|
||||||
|
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Erdiratu
|
||||||
|
|
||||||
|
Erdiratu mapan hautatutako fitxategi-elementuak.
|
||||||
|
|
||||||
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Kopiatu
|
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Kopiatu
|
||||||
|
|
||||||
Kopiatu arbelean hautatutako fitxategi-elementuak.
|
Kopiatu arbelean hautatutako fitxategi-elementuak.
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ Fitxategi ekintzen menuan fitxategien eragiketa multzoa dago.
|
|||||||
|
|
||||||
Sortu fitxategi huts berri bat.
|
Sortu fitxategi huts berri bat.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New route file
|
|
||||||
|
|
||||||
Create a new file containing an empty [route](../gpx).
|
|
||||||
|
|
||||||
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Ireki...
|
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Ireki...
|
||||||
|
|
||||||
Ireki zure ordenagailuko fitxategiak.
|
Ireki zure ordenagailuko fitxategiak.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: Ikusteko aukerak
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, EyeOff, Maximize, Box, Maximize2 } from '@lucide/svelte';
|
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, Box, Maximize2 } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ Ezkutatu altueren profila mapari lekua egiteko, edo erakutsi uneko hautapena iku
|
|||||||
|
|
||||||
Aldatu [fitxategi zerrendaren](../files-and-stats) zuhaitza ikuspegira.
|
Aldatu [fitxategi zerrendaren](../files-and-stats) zuhaitza ikuspegira.
|
||||||
Diseinu hau aproposa da irekitako fitxategi ugari kudeatzeko, maparen eskuinaldean zerrenda bertikal batean antolatzen baitu.
|
Diseinu hau aproposa da irekitako fitxategi ugari kudeatzeko, maparen eskuinaldean zerrenda bertikal batean antolatzen baitu.
|
||||||
In addition, the file tree view enables you to inspect the [tracks, segments, routes, and points of interest](../gpx) contained inside the files through collapsible sections.
|
Fitxategien zuhaitza ikuspegiak fitxategien barneko [ibilbideak, segmentuak eta interesguneak](../gpx) atal gisa erakusten ditu.
|
||||||
|
|
||||||
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Aldatu erabilitako aurreko geruzara
|
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Aldatu erabilitako aurreko geruzara
|
||||||
|
|
||||||
@@ -38,14 +38,6 @@ Unean hautatutako ibilbidean ikusten dira, [koten profila bezala](../files-and-s
|
|||||||
|
|
||||||
Aldatu ibilbidearen noranzko gezien ikusgarritasuna.
|
Aldatu ibilbidearen noranzko gezien ikusgarritasuna.
|
||||||
|
|
||||||
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Hide/unhide
|
|
||||||
|
|
||||||
Toggle the visibility of the selected file items on the map.
|
|
||||||
|
|
||||||
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Center
|
|
||||||
|
|
||||||
Center the map on the selected file items.
|
|
||||||
|
|
||||||
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Aldatu 3D
|
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Aldatu 3D
|
||||||
|
|
||||||
Aktibatu edo desaktibatu maparen 3D ikuspegia.
|
Aktibatu edo desaktibatu maparen 3D ikuspegia.
|
||||||
@@ -56,6 +48,7 @@ Maparen orientazioa eta okertzea kontrolatzeko, mapa ere arrasta dezakezu <kbd>
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <Maximize2 size="16" class="inline-block" style="margin-bottom: 2px" /> Pantaila osoa
|
### <Maximize2 size="16" class="inline-block" style="margin-bottom: 2px" /> Full screen
|
||||||
|
|
||||||
Sartu edo irten pantaila osoko moduan.<kbd>F11</kbd> ere saka dezakezu txandakatzeko, edo <kbd>Ihes</kbd> irteteko.
|
Enter or exit full screen mode.
|
||||||
|
You can also press <kbd>F11</kbd> to toggle, or <kbd>Escape</kbd> to exit.
|
||||||
@@ -18,7 +18,7 @@ Tresna honen bidez elebazio datuak gehitzen ahal dira ibilbidetan eta [interesgu
|
|||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|
||||||
Altueraren datuak <a href="https://mapterhorn.com" target="_blank">Mapterhorn</a>k ematen ditu.
|
Elevation data is provided by <a href="https://mapterhorn.com" target="_blank">Mapterhorn</a>.
|
||||||
Haren jatorriari eta zehaztasunari buruz gehiago jakin dezakezu <a href="https://mapterhorn.com/attribution/" target="_blank">dokumentazioan</a>.
|
You can learn more about its origin and accuracy in the <a href="https://mapterhorn.com/attribution/" target="_blank">documentation</a>.
|
||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
@@ -16,7 +16,7 @@ Tresna honen bidez [ibilbideak (edo segmentuak)](../gpx) erauzi ditzakezu fitxat
|
|||||||
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Applying the tool to a file containing multiple [tracks or routes](../gpx) will create a new file for each of the tracks and routes it contains.
|
Hainbat ibilbide dituen fitxategi bati aplikatuz gero dituen ibilbide bakoitzarentzat fitxategi bana sortuko du.
|
||||||
Era berean, hainbat segmentu duen ibilbide bati aplikatuz gero (fitxategi berean) duen segmentu bakoitzeko ibilbide bana sortuko du.
|
Era berean, hainbat segmentu duen ibilbide bati aplikatuz gero (fitxategi berean) duen segmentu bakoitzeko ibilbide bana sortuko du.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|||||||
@@ -10,16 +10,16 @@ title: Batu
|
|||||||
|
|
||||||
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
||||||
|
|
||||||
To use this tool, you need to [select](../files-and-stats) multiple files, [tracks, segments or routes](../gpx).
|
Tresna hau erabiltzeko [hautatu](../files-and-stats) behar duzu hainbat fitxategi [ibilbidea, edo segmentuak](../gpx).
|
||||||
|
|
||||||
- Zure helburua hautaketatik abiatuta etengabeko arrasto bakarra sortzea bada, erabili **Konektatu trazak ** aukera eta balioztatu.
|
- Zure helburua hautaketatik abiatuta etengabeko arrasto bakarra sortzea bada, erabili **Konektatu trazak ** aukera eta balioztatu.
|
||||||
- The second option can be used to create or manage files with multiple [tracks, segments or routes](../gpx).
|
- Bigarren aukera bat izan daiteke hainbat [arrasto edo segmentu](../gpx) biltzen duen fitxategiak sortzea edo kudeatzea.
|
||||||
Merging files (or tracks) will result in a single file (or track) containing all tracks and routes (or segments) from the selection.
|
Fitxategiak (edo arrastoak) batzearen emaitza fitxategi (edo arrasto) bakarra sortzea da zeinak hautapenaren arrastoak (edo segmentuak) biltzen duena.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|
||||||
Hautatutako elementuak fitxategien zerrendan agertzen diren ordenan batzen dira.
|
Selected items are merged in the order they appear in the files list.
|
||||||
Berrantolatu elementuak arrastatu eta jareginez, behar izanez gero.
|
Reorder items by drag-and-drop if needed.
|
||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,6 @@ Hautatutako ibilbidea bi zatitan banatzeko, egin klik arrastoko zatiketa markatz
|
|||||||
Puntu zehatz batean banatzeko, pasa ezazu maparen arrastoaren gainean.
|
Puntu zehatz batean banatzeko, pasa ezazu maparen arrastoaren gainean.
|
||||||
Artaziak agertuko dira kurtsorearen posizioan, puntu horretan ebaki dezakezula erakutsiz.
|
Artaziak agertuko dira kurtsorearen posizioan, puntu horretan ebaki dezakezula erakutsiz.
|
||||||
|
|
||||||
You can choose to split the trace into two GPX files, or to keep the split parts in the same file as [tracks, segments or routes](../gpx).
|
Arrastoa bi GPX fitxategietan zatitzea edo fitxategi berean zatiak [arrastoak edo segmentuak](../gpx) gisa gordetzea aukeratu dezakezu.
|
||||||
|
|
||||||
<DocsImage src="tools/split" alt="Aukeratutako trazaren gainean kokatzean, zure kurtsorea guraize bihurtuko da." />
|
<DocsImage src="tools/split" alt="Aukeratutako trazaren gainean kokatzean, zure kurtsorea guraize bihurtuko da." />
|
||||||
@@ -51,7 +51,7 @@ By right-clicking on a file tab, you can access the same actions as in the [edit
|
|||||||
|
|
||||||
As mentioned in the [view options section](./menu/view), you can switch to a tree layout for the files list.
|
As mentioned in the [view options section](./menu/view), you can switch to a tree layout for the files list.
|
||||||
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map.
|
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map.
|
||||||
In addition, the file tree view enables you to inspect the [tracks, segments, routes, and points of interest](./gpx) contained inside the files through collapsible sections.
|
In addition, the file tree view enables you to inspect the [tracks, segments, and points of interest](./gpx) contained inside the files through collapsible sections.
|
||||||
|
|
||||||
You can also apply [edit actions](./menu/edit) and [tools](./toolbar) to internal file items.
|
You can also apply [edit actions](./menu/edit) and [tools](./toolbar) to internal file items.
|
||||||
Furthermore, you can drag and drop the inner items to reorder them, or move them in the hierarchy or even to another file.
|
Furthermore, you can drag and drop the inner items to reorder them, or move them in the hierarchy or even to another file.
|
||||||
|
|||||||
@@ -3,15 +3,13 @@ title: GPX file format
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import { Waypoints, MapPin } from '@lucide/svelte';
|
||||||
import { Waypoints, Route, MapPin } from '@lucide/svelte';
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
The <a href="https://www.topografix.com/gpx.asp" target="_blank">GPX file format</a> is an open standard for exchanging GPS data between applications and GPS devices.
|
The <a href="https://www.topografix.com/gpx.asp" target="_blank">GPX file format</a> is an open standard for exchanging GPS data between applications and GPS devices.
|
||||||
It essentially consists of a series of GPS points encoding one or multiple GPS traces, and, optionally, some points of interest.
|
It essentially consists of a series of GPS points encoding one or multiple GPS traces, and, optionally, some points of interest.
|
||||||
These traces can be stored either as tracks or as routes.
|
|
||||||
|
|
||||||
GPX files may also contain metadata, of which the **name** and **description** fields are the most useful for users.
|
GPX files may also contain metadata, of which the **name** and **description** fields are the most useful for users.
|
||||||
|
|
||||||
@@ -29,20 +27,6 @@ These are organized in a hierarchical structure, with tracks at the top level.
|
|||||||
In most cases, GPX files contain a single track with a single segment.
|
In most cases, GPX files contain a single track with a single segment.
|
||||||
However, the hierarchy described above allows for more advanced use cases, such as planning multi-day trips with several variants for each day.
|
However, the hierarchy described above allows for more advanced use cases, such as planning multi-day trips with several variants for each day.
|
||||||
|
|
||||||
### <Route size="16" class="inline-block" style="margin-bottom: 2px" /> Routes
|
|
||||||
|
|
||||||
A **route** is a single continuous path made of a sequence of **route points**.
|
|
||||||
These are mandatory checkpoints, which correspond to the anchor points of the [routing tool](./toolbar/routing).
|
|
||||||
The points in between are only a suggested path connecting the route points.
|
|
||||||
Like a track, a route can have a **name**, a **description**, and **appearance properties**.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
Nowadays, most apps and GPS devices work perfectly well with tracks, even for navigation.
|
|
||||||
However, some of them only work with routes: in that case, you can [convert](./menu/edit) your tracks to routes, or [create](./menu/file) a route file from the start.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Points of interest
|
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Points of interest
|
||||||
|
|
||||||
**Points of interest** (technically called _waypoints_) represent locations of interest to show either on a GPS device or on a digital map.
|
**Points of interest** (technically called _waypoints_) represent locations of interest to show either on a GPS device or on a digital map.
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ title: Edit actions
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Undo2, Redo2, Info, PaintBucket, ArrowRightLeft, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Plus } from '@lucide/svelte';
|
import { Undo2, Redo2, Info, PaintBucket, EyeOff, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Maximize, Plus } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
Unlike the file actions, the edit actions can potentially modify the content of the currently selected files.
|
Unlike the file actions, the edit actions can potentially modify the content of the currently selected files.
|
||||||
Moreover, when the tree layout of the files list is enabled (see [Files and statistics](../files-and-stats)), they can also be applied to [tracks, segments, routes, and points of interest](../gpx).
|
Moreover, when the tree layout of the files list is enabled (see [Files and statistics](../files-and-stats)), they can also be applied to [tracks, segments, and points of interest](../gpx).
|
||||||
Therefore, we will refer to the elements that can be modified by these actions as _file items_.
|
Therefore, we will refer to the elements that can be modified by these actions as _file items_.
|
||||||
Note that except for the undo and redo actions, the edit actions are also accessible through the context menu (right-click) of the file items.
|
Note that except for the undo and redo actions, the edit actions are also accessible through the context menu (right-click) of the file items.
|
||||||
|
|
||||||
@@ -27,6 +27,10 @@ Open the information dialog of the currently selected file item, where you can s
|
|||||||
|
|
||||||
Open the appearance dialog, where you can change the color, opacity, and width of the selected file items on the map.
|
Open the appearance dialog, where you can change the color, opacity, and width of the selected file items on the map.
|
||||||
|
|
||||||
|
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Hide/unhide
|
||||||
|
|
||||||
|
Toggle the visibility of the selected file items on the map.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New track
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New track
|
||||||
|
|
||||||
Create a new track in the selected file.
|
Create a new track in the selected file.
|
||||||
@@ -38,17 +42,6 @@ Additionally, the selection must be a single file.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New route
|
|
||||||
|
|
||||||
Create a new route in the selected file.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
This action is only available when the tree layout of the files list is enabled.
|
|
||||||
Additionally, the selection must be a single file.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New segment
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New segment
|
||||||
|
|
||||||
Create a new segment in the selected track.
|
Create a new segment in the selected track.
|
||||||
@@ -60,17 +53,14 @@ Additionally, the selection must be a single track.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <ArrowRightLeft size="16" class="inline-block" style="margin-bottom: 2px" /> Convert to route/track
|
|
||||||
|
|
||||||
Convert the selected routes to tracks, or the selected tracks or segments to routes.
|
|
||||||
Since a route has a single segment, a track with multiple segments is converted into one route per segment.
|
|
||||||
|
|
||||||
When the selected files contain only routes, or only tracks, you can also convert all of them at once.
|
|
||||||
|
|
||||||
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Select all
|
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Select all
|
||||||
|
|
||||||
Add all file items in the current hierarchy level to the selection.
|
Add all file items in the current hierarchy level to the selection.
|
||||||
|
|
||||||
|
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Center
|
||||||
|
|
||||||
|
Center the map on the selected file items.
|
||||||
|
|
||||||
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Copy
|
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Copy
|
||||||
|
|
||||||
Copy the selected file items to the clipboard.
|
Copy the selected file items to the clipboard.
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ The file actions menu contains a set of pretty self-explanatory file operations.
|
|||||||
|
|
||||||
Create a new empty file.
|
Create a new empty file.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> New route file
|
|
||||||
|
|
||||||
Create a new file containing an empty [route](../gpx).
|
|
||||||
|
|
||||||
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Open...
|
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Open...
|
||||||
|
|
||||||
Open files from your computer.
|
Open files from your computer.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: View options
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, EyeOff, Maximize, Box, Maximize2 } from '@lucide/svelte';
|
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, Box, Maximize2 } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ Hide the elevation profile to make room for the map, or show it to inspect the c
|
|||||||
|
|
||||||
Toggle the tree layout for the [file list](../files-and-stats).
|
Toggle the tree layout for the [file list](../files-and-stats).
|
||||||
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map.
|
This layout is ideal for managing a large number of open files, as it organizes them into a vertical list on the right side of the map.
|
||||||
In addition, the file tree view enables you to inspect the [tracks, segments, routes, and points of interest](../gpx) contained inside the files through collapsible sections.
|
In addition, the file tree view enables you to inspect the [tracks, segments, and points of interest](../gpx) contained inside the files through collapsible sections.
|
||||||
|
|
||||||
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Switch to previous basemap
|
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Switch to previous basemap
|
||||||
|
|
||||||
@@ -38,14 +38,6 @@ They are displayed for the current selection, like the [elevation profile](../fi
|
|||||||
|
|
||||||
Toggle the visibility of direction arrows on the map.
|
Toggle the visibility of direction arrows on the map.
|
||||||
|
|
||||||
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Hide/unhide
|
|
||||||
|
|
||||||
Toggle the visibility of the selected file items on the map.
|
|
||||||
|
|
||||||
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Center
|
|
||||||
|
|
||||||
Center the map on the selected file items.
|
|
||||||
|
|
||||||
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Toggle 3D
|
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Toggle 3D
|
||||||
|
|
||||||
Enter or exit the 3D map view.
|
Enter or exit the 3D map view.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ This tool allows you to extract [tracks (or segments)](../gpx) from files (or tr
|
|||||||
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Applying the tool to a file containing multiple [tracks or routes](../gpx) will create a new file for each of the tracks and routes it contains.
|
Applying the tool to a file containing multiple tracks will create a new file for each of the tracks it contains.
|
||||||
Similarly, applying the tool to a track containing multiple segments will create (in the same file) a new track for each of the segments it contains.
|
Similarly, applying the tool to a track containing multiple segments will create (in the same file) a new track for each of the segments it contains.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ title: Merge
|
|||||||
|
|
||||||
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
||||||
|
|
||||||
To use this tool, you need to [select](../files-and-stats) multiple files, [tracks, segments or routes](../gpx).
|
To use this tool, you need to [select](../files-and-stats) multiple files, [tracks, or segments](../gpx).
|
||||||
|
|
||||||
- If your goal is to create a single continuous trace from your selection, use the **Connect the traces** option and validate.
|
- If your goal is to create a single continuous trace from your selection, use the **Connect the traces** option and validate.
|
||||||
- The second option can be used to create or manage files with multiple [tracks, segments or routes](../gpx).
|
- The second option can be used to create or manage files with multiple [tracks or segments](../gpx).
|
||||||
Merging files (or tracks) will result in a single file (or track) containing all tracks and routes (or segments) from the selection.
|
Merging files (or tracks) will result in a single file (or track) containing all tracks (or segments) from the selection.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,6 @@ To split the selected trace into two parts, click on one of the split markers di
|
|||||||
To split at a specific point of your choice, hover over the trace on the map.
|
To split at a specific point of your choice, hover over the trace on the map.
|
||||||
Scissors will appear at the cursor position, showing that you can split the trace at that point.
|
Scissors will appear at the cursor position, showing that you can split the trace at that point.
|
||||||
|
|
||||||
You can choose to split the trace into two GPX files, or to keep the split parts in the same file as [tracks, segments or routes](../gpx).
|
You can choose to split the trace into two GPX files, or to keep the split parts in the same file as [tracks or segments](../gpx).
|
||||||
|
|
||||||
<DocsImage src="tools/split" alt="Hovering over the selected trace turns your cursor into scissors." />
|
<DocsImage src="tools/split" alt="Hovering over the selected trace turns your cursor into scissors." />
|
||||||
@@ -51,7 +51,7 @@ En faisant un clic droit sur un onglet de fichier, vous pouvez accéder aux mêm
|
|||||||
|
|
||||||
Comme mentionné dans la [section des options d'affichage](./menu/view), vous pouvez basculer vers une présentation en arborescence pour la liste des fichiers.
|
Comme mentionné dans la [section des options d'affichage](./menu/view), vous pouvez basculer vers une présentation en arborescence pour la liste des fichiers.
|
||||||
Cette disposition est idéale pour gérer un grand nombre de fichiers ouverts, car elle les organise en une liste verticale à droite de la carte.
|
Cette disposition est idéale pour gérer un grand nombre de fichiers ouverts, car elle les organise en une liste verticale à droite de la carte.
|
||||||
De plus, la vue en arborescence des fichiers vous permet d'inspecter les [traces, segments, routes, et points d'intérêt](./gpx) contenus dans les fichiers grâce à des sections pliables.
|
De plus, la vue en arborescence des fichiers vous permet d'inspecter les [traces, segments, et points d'intérêt](./gpx) contenus dans les fichiers grâce à des sections pliables.
|
||||||
|
|
||||||
Vous pouvez également appliquer les [actions d'édition](./menu/edit) et les [outils](./toolbar) aux éléments intérieurs aux fichiers.
|
Vous pouvez également appliquer les [actions d'édition](./menu/edit) et les [outils](./toolbar) aux éléments intérieurs aux fichiers.
|
||||||
De plus, vous pouvez glisser-déposer les éléments intérieurs pour les réorganiser, ou les déplacer dans la hiérarchie ou même dans un autre fichier.
|
De plus, vous pouvez glisser-déposer les éléments intérieurs pour les réorganiser, ou les déplacer dans la hiérarchie ou même dans un autre fichier.
|
||||||
|
|||||||
@@ -3,15 +3,13 @@ title: Format de fichier GPX
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import { Waypoints, MapPin } from '@lucide/svelte';
|
||||||
import { Waypoints, Route, MapPin } from '@lucide/svelte';
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
Le format de fichier <a href="https://www.topografix.com/gpx.asp" target="_blank">GPX</a> est un standard ouvert pour l'échange de données GPS entre applications et appareils GPS.
|
Le format de fichier <a href="https://www.topografix.com/gpx.asp" target="_blank">GPX</a> est un standard ouvert pour l'échange de données GPS entre applications et appareils GPS.
|
||||||
Il consiste principalement en une série de points GPS encodant une ou plusieurs traces GPS, et, éventuellement, certains points d'intérêt.
|
Il consiste principalement en une série de points GPS encodant une ou plusieurs traces GPS, et, éventuellement, certains points d'intérêt.
|
||||||
Ces traces peuvent être stockées sous forme de pistes ou de routes.
|
|
||||||
|
|
||||||
Les fichiers GPX peuvent aussi contenir des métadonnées, dont les champs **nom** et **description** sont les plus utiles pour les utilisateurs.
|
Les fichiers GPX peuvent aussi contenir des métadonnées, dont les champs **nom** et **description** sont les plus utiles pour les utilisateurs.
|
||||||
|
|
||||||
@@ -29,20 +27,6 @@ Celles-ci sont organisées en une structure hiérarchique, dont les pistes const
|
|||||||
Dans la plupart des cas, les fichiers GPX contiennent une seule piste avec un seul segment.
|
Dans la plupart des cas, les fichiers GPX contiennent une seule piste avec un seul segment.
|
||||||
Cependant, la hiérarchie décrite ci-dessus permet des cas d'utilisation plus avancés, comme la planification de voyages de plusieurs jours avec plusieurs variantes pour chaque jour.
|
Cependant, la hiérarchie décrite ci-dessus permet des cas d'utilisation plus avancés, comme la planification de voyages de plusieurs jours avec plusieurs variantes pour chaque jour.
|
||||||
|
|
||||||
### <Route size="16" class="inline-block" style="margin-bottom: 2px" /> Routes
|
|
||||||
|
|
||||||
Une **route** est un chemin continu constitué d'une séquence de **points de passage**.
|
|
||||||
Ces points de passage correspondent aux points d'ancrage de [l'outil de routage](./toolbar/routing).
|
|
||||||
Les points intermédiaires entre les points de passage ne sont qu'un chemin suggéré pour les relier.
|
|
||||||
Comme une piste, une route peut avoir un **nom**, une **description**, et des **propriétés d'apparence**.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
De nos jours, la plupart des applications et des appareils GPS fonctionnent parfaitement avec les pistes, même pour la navigation.
|
|
||||||
Cependant, certains d'entre eux ne fonctionnent qu'avec des routes : dans ce cas, vous pouvez [convertir](./menu/edit) vos pistes en routes, ou [créer](./menu/file) un fichier route dès le début.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Points d'intérêt
|
### <MapPin size="16" class="inline-block" style="margin-bottom: 2px" /> Points d'intérêt
|
||||||
|
|
||||||
Les **points d'intérêt** (techniquement appelés _waypoints_) représentent des lieux d'intérêt à afficher sur un appareil GPS ou sur une carte numérique.
|
Les **points d'intérêt** (techniquement appelés _waypoints_) représentent des lieux d'intérêt à afficher sur un appareil GPS ou sur une carte numérique.
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ title: Actions d'édition
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Undo2, Redo2, Info, PaintBucket, ArrowRightLeft, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Plus } from '@lucide/svelte';
|
import { Undo2, Redo2, Info, PaintBucket, EyeOff, FileStack, ClipboardCopy, Scissors, ClipboardPaste, Trash2, Maximize, Plus } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
# { title }
|
# { title }
|
||||||
|
|
||||||
Contrairement aux actions sur les fichiers, les actions d'édition peuvent potentiellement modifier le contenu des fichiers sélectionnés.
|
Contrairement aux actions sur les fichiers, les actions d'édition peuvent potentiellement modifier le contenu des fichiers sélectionnés.
|
||||||
De plus, lorsque la présentation en arborescence de la liste de fichiers est activée (voir [Fichiers et statistiques](../files-and-stats)), elles peuvent également être appliquées aux [pistes, segments, routes, et points d'intérêt](../gpx).
|
De plus, lorsque la présentation en arborescence de la liste de fichiers est activée (voir [Fichiers et statistiques](../files-and-stats)), elles peuvent également être appliquées aux [pistes, segments, et points d'intérêt](../gpx).
|
||||||
Par conséquent, nous appellerons les éléments qui peuvent être modifiés par ces actions des _éléments de fichier_.
|
Par conséquent, nous appellerons les éléments qui peuvent être modifiés par ces actions des _éléments de fichier_.
|
||||||
Notez que, à part les actions annuler et rétablir, les actions d'édition sont également accessibles via le menu contextuel (clic droit) des éléments de fichier.
|
Notez que, à part les actions annuler et rétablir, les actions d'édition sont également accessibles via le menu contextuel (clic droit) des éléments de fichier.
|
||||||
|
|
||||||
@@ -27,6 +27,10 @@ Ouvrir la boîte de dialogue d'information de l'élément de fichier actuellemen
|
|||||||
|
|
||||||
Ouvrir la boîte de dialogue d'apparence, où vous pouvez changer la couleur, l'opacité et l'épaisseur des éléments de fichier sélectionnés sur la carte.
|
Ouvrir la boîte de dialogue d'apparence, où vous pouvez changer la couleur, l'opacité et l'épaisseur des éléments de fichier sélectionnés sur la carte.
|
||||||
|
|
||||||
|
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Cacher/afficher
|
||||||
|
|
||||||
|
Activer/désactiver la visibilité des éléments de fichier sélectionnés sur la carte.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Nouvelle piste
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Nouvelle piste
|
||||||
|
|
||||||
Créer une nouvelle piste dans le fichier sélectionné.
|
Créer une nouvelle piste dans le fichier sélectionné.
|
||||||
@@ -38,17 +42,6 @@ De plus, la sélection doit contenir un seul fichier.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Nouvelle route
|
|
||||||
|
|
||||||
Créer une nouvelle route dans le fichier sélectionné.
|
|
||||||
|
|
||||||
<DocsNote>
|
|
||||||
|
|
||||||
Cette action n'est disponible que lorsque la présentation en arborescence de la liste de fichiers est activée.
|
|
||||||
De plus, la sélection doit contenir un seul fichier.
|
|
||||||
|
|
||||||
</DocsNote>
|
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Nouveau segment
|
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" /> Nouveau segment
|
||||||
|
|
||||||
Créer un nouveau segment dans la piste sélectionnée.
|
Créer un nouveau segment dans la piste sélectionnée.
|
||||||
@@ -60,17 +53,14 @@ De plus, la sélection doit contenir une seule piste.
|
|||||||
|
|
||||||
</DocsNote>
|
</DocsNote>
|
||||||
|
|
||||||
### <ArrowRightLeft size="16" class="inline-block" style="margin-bottom: 2px" /> Convertir en fichier route/piste
|
|
||||||
|
|
||||||
Convertir les routes sélectionnées en pistes, ou les pistes ou segments sélectionnés en routes.
|
|
||||||
Comme une route a un seul segment, une piste avec plusieurs segments est convertie en une route par segment.
|
|
||||||
|
|
||||||
Lorsque les fichiers sélectionnés ne contiennent que des routes, ou seulement des pistes, vous pouvez également les convertir tous en même temps.
|
|
||||||
|
|
||||||
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Sélectionner tout
|
### <FileStack size="16" class="inline-block" style="margin-bottom: 2px" /> Sélectionner tout
|
||||||
|
|
||||||
Ajouter tous les éléments de fichier du niveau de hiérarchie actuel à la sélection.
|
Ajouter tous les éléments de fichier du niveau de hiérarchie actuel à la sélection.
|
||||||
|
|
||||||
|
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Centrer
|
||||||
|
|
||||||
|
Centrer la carte sur les éléments de fichier sélectionnés.
|
||||||
|
|
||||||
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Copier
|
### <ClipboardCopy size="16" class="inline-block" style="margin-bottom: 2px" /> Copier
|
||||||
|
|
||||||
Copier les éléments de fichier sélectionnés dans le presse-papiers.
|
Copier les éléments de fichier sélectionnés dans le presse-papiers.
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ Le menu des actions sur les fichiers contient un ensemble d'opérations de fichi
|
|||||||
|
|
||||||
Créer un nouveau fichier vide.
|
Créer un nouveau fichier vide.
|
||||||
|
|
||||||
### <Plus size="16" class="inline-block" style="margin-bottom: 2px" />Nouveau fichier route
|
|
||||||
|
|
||||||
Créer un nouveau fichier contenant une [route](../gpx) vide.
|
|
||||||
|
|
||||||
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Ouvrir...
|
### <FolderOpen size="16" class="inline-block" style="margin-bottom: 2px" /> Ouvrir...
|
||||||
|
|
||||||
Ouvrir des fichiers depuis votre ordinateur.
|
Ouvrir des fichiers depuis votre ordinateur.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ title: Options d'affichage
|
|||||||
---
|
---
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, EyeOff, Maximize, Box, Maximize2 } from '@lucide/svelte';
|
import { ChartArea, ListTree, Map, Layers2, Coins, Milestone, Box, Maximize2 } from '@lucide/svelte';
|
||||||
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
import DocsNote from '$lib/components/docs/DocsNote.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ Masquer le profil altimétrique pour faire de la place pour la carte, ou l'affic
|
|||||||
|
|
||||||
Activer/désactiver la présentation en arborescence pour la [liste de fichiers](../files-and-stats).
|
Activer/désactiver la présentation en arborescence pour la [liste de fichiers](../files-and-stats).
|
||||||
Cette disposition est idéale pour gérer un grand nombre de fichiers ouverts, car elle les organise en une liste verticale à droite de la carte.
|
Cette disposition est idéale pour gérer un grand nombre de fichiers ouverts, car elle les organise en une liste verticale à droite de la carte.
|
||||||
De plus, la vue en arborescence des fichiers vous permet d'inspecter les [traces, segments, routes, et points d'intérêt](../gpx) contenus dans les fichiers grâce à des sections pliables.
|
De plus, la vue en arborescence des fichiers vous permet d'inspecter les [traces, segments, et points d'intérêt](../gpx) contenus dans les fichiers grâce à des sections pliables.
|
||||||
|
|
||||||
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Basculer au fond de carte précédent
|
### <Map size="16" class="inline-block" style="margin-bottom: 2px" /> Basculer au fond de carte précédent
|
||||||
|
|
||||||
@@ -38,14 +38,6 @@ Ceux-ci sont affichés pour la sélection courante, comme le [profil altimétriq
|
|||||||
|
|
||||||
Activer/désactiver la visibilité des flèches de direction sur la carte.
|
Activer/désactiver la visibilité des flèches de direction sur la carte.
|
||||||
|
|
||||||
### <EyeOff size="16" class="inline-block" style="margin-bottom: 2px" /> Cacher/afficher
|
|
||||||
|
|
||||||
Activer/désactiver la visibilité des éléments de fichier sélectionnés sur la carte.
|
|
||||||
|
|
||||||
### <Maximize size="16" class="inline-block" style="margin-bottom: 2px" /> Centrer
|
|
||||||
|
|
||||||
Centrer la carte sur les éléments de fichier sélectionnés.
|
|
||||||
|
|
||||||
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Activer/désactiver la 3D
|
### <Box size="16" class="inline-block" style="margin-bottom: 2px" /> Activer/désactiver la 3D
|
||||||
|
|
||||||
Entrer ou sortir de la vue 3D de la carte.
|
Entrer ou sortir de la vue 3D de la carte.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ Cet outil vous permet d'extraire [des pistes (ou des segments)](../gpx) de fichi
|
|||||||
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
<Extract class="text-foreground p-3 border rounded-md shadow-lg" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Appliquer l'outil à un fichier contenant plusieurs [pistes ou routes](../gpx) créera un nouveau fichier pour chacune des pistes et routes qu'il contient.
|
Appliquer l'outil à un fichier contenant plusieurs pistes créera un nouveau fichier pour chacune des pistes qu'il contient.
|
||||||
De même, appliquer l'outil à une piste contenant plusieurs segments créera (dans le même fichier) une nouvelle piste pour chacun des segments qu'elle contient.
|
De même, appliquer l'outil à une piste contenant plusieurs segments créera (dans le même fichier) une nouvelle piste pour chacun des segments qu'elle contient.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ title: Fusionner
|
|||||||
|
|
||||||
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
# <Group size="24" class="inline-block" style="margin-bottom: 5px" /> { title }
|
||||||
|
|
||||||
Pour utiliser cet outil, vous devez [sélectionner](../files-and-stats) plusieurs fichiers, [pistes, segments ou routes](../gpx).
|
Pour utiliser cet outil, vous devez [sélectionner](../files-and-stats) plusieurs fichiers, [pistes ou segments](../gpx).
|
||||||
|
|
||||||
- Si votre objectif est de créer une seule trace continue à partir de votre sélection, utilisez l'option **Connecter les traces** et validez.
|
- Si votre objectif est de créer une seule trace continue à partir de votre sélection, utilisez l'option **Connecter les traces** et validez.
|
||||||
- La deuxième option peut être utilisée pour créer ou gérer des fichiers avec plusieurs [pistes, segments ou routes](../gpx).
|
- La deuxième option peut être utilisée pour créer ou gérer des fichiers avec plusieurs [pistes ou segments](../gpx).
|
||||||
Fusionner des fichiers (ou des pistes) résultera en un seul fichier (ou piste) contenant toutes les pistes et routes (ou tous les segments) de la sélection.
|
Fusionner des fichiers (ou des pistes) résultera en un seul fichier (ou piste) contenant toutes les pistes (ou tous les segments) de la sélection.
|
||||||
|
|
||||||
<DocsNote>
|
<DocsNote>
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,6 @@ Pour diviser la trace sélectionnée en deux parties, cliquez sur l'un des marqu
|
|||||||
Pour diviser à un point précis de votre choix, survolez la trace sur la carte.
|
Pour diviser à un point précis de votre choix, survolez la trace sur la carte.
|
||||||
Des ciseaux apparaîtront à la position du curseur, montrant que vous pouvez diviser la trace à ce point.
|
Des ciseaux apparaîtront à la position du curseur, montrant que vous pouvez diviser la trace à ce point.
|
||||||
|
|
||||||
Vous pouvez choisir de diviser la trace en deux fichiers GPX, ou de créer [une piste, un segment ou une route](../gpx) pour chaque partie dans le même fichier.
|
Vous pouvez choisir de diviser la trace en deux fichiers GPX, ou de créer une [piste ou un segment](../gpx) pour chaque partie dans le même fichier.
|
||||||
|
|
||||||
<DocsImage src="tools/split" alt="Survoler la trace sélectionnée transforme votre curseur en ciseaux." />
|
<DocsImage src="tools/split" alt="Survoler la trace sélectionnée transforme votre curseur en ciseaux." />
|
||||||
Loaded 100 of 343 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user