aboutsummaryrefslogtreecommitdiff
path: root/src/handlers/file.rs
blob: f816e62f0fdd1522882fa196d9e220638c576bff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Map, wardley map editor for linux
// Copyright (C) 2026 Rubén Beltrán del Río

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
use std::path::PathBuf;

use gtk::prelude::*;
use relm4::{ComponentSender, gtk};

use crate::AppModel;
use crate::actions::Action;
use crate::constants;
use crate::dialogs;
use crate::file_registry;
use crate::tr;

/// Loads a file into the current document, updating the file registry.
pub fn load_file(model: &mut AppModel, path: PathBuf) {
    match std::fs::read_to_string(&path) {
        Ok(content) => {
            unregister_current_file(model);
            model.set_source_text(&content);
            file_registry::register_file(&path, &model.window);
            model.current_file = Some(path);
            model.modified = false;
        }
        Err(error) => {
            dialogs::show_error(
                &model.window,
                &tr!("Could not open file. Please make sure the file is readable."),
                &error.to_string(),
            );
        }
    }
}

/// Saves the document to the specified path, optionally closing after.
pub fn save_to_file(model: &mut AppModel, path: PathBuf, close_after: bool) {
    let content = model.source_text();
    let path = ensure_wmap_extension(path);

    match std::fs::write(&path, content.as_str()) {
        Ok(()) => {
            if close_after {
                file_registry::unregister_file(&path);
                model.modified = false;
                model.window.close();
            } else {
                update_file_registration(model, &path);
                model.current_file = Some(path);
                model.modified = false;
            }
        }
        Err(error) => {
            dialogs::show_error(
                &model.window,
                &tr!("Could not save file. Please make sure the destination is writable."),
                &error.to_string(),
            );
        }
    }
}

/// Handles window close, prompting for unsaved changes if needed.
pub fn close_window(model: &mut AppModel, sender: &ComponentSender<AppModel>) {
    if model.modified {
        dialogs::show_unsaved_changes_dialog(
            &model.window,
            model.current_file.clone(),
            sender.clone(),
        );
    } else {
        unregister_current_file(model);
        model.window.destroy();
    }
}

/// Dispatches save action based on whether file already has a path.
pub fn save(model: &AppModel, close_after: bool, sender: &ComponentSender<AppModel>) {
    if let Some(path) = model.current_file.clone() {
        sender.input(Action::SaveToFile { path, close_after });
    } else {
        sender.input(Action::SaveAs { close_after });
    }
}

// === Helper Functions ===

/// Unregisters the current file from the registry if one is open.
fn unregister_current_file(model: &AppModel) {
    if let Some(ref path) = model.current_file {
        file_registry::unregister_file(path);
    }
}

/// Updates file registration when saving to a new path.
fn update_file_registration(model: &mut AppModel, new_path: &PathBuf) {
    if model.current_file.as_ref() != Some(new_path) {
        unregister_current_file(model);
        file_registry::register_file(new_path, &model.window);
    }
}

/// Ensures the path has the .wmap extension.
fn ensure_wmap_extension(path: PathBuf) -> PathBuf {
    if path.extension().is_none()
        || path.extension().unwrap_or_default() != constants::FILE_EXTENSION
    {
        path.with_extension(constants::FILE_EXTENSION)
    } else {
        path
    }
}