mirror of
https://github.com/zaphar/sheetsui.git
synced 2025-07-23 05:19:48 -04:00
wip: Convert over to UserModel
Step 1: update ironcalc version and plug it in
This commit is contained in:
parent
0a6807493c
commit
7a5bd63fde
117
Cargo.lock
generated
117
Cargo.lock
generated
@ -28,15 +28,6 @@ dependencies = [
|
|||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aho-corasick"
|
|
||||||
version = "0.6.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
@ -182,12 +173,6 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "1.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
@ -293,9 +278,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono-tz"
|
name = "chrono-tz"
|
||||||
version = "0.9.0"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb"
|
checksum = "9c6ac4f2c0bf0f44e9161aec9675e1050aa4a530663c4a9e37e108fa948bca9f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"chrono-tz-build",
|
"chrono-tz-build",
|
||||||
@ -304,12 +289,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono-tz-build"
|
name = "chrono-tz-build"
|
||||||
version = "0.3.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1"
|
checksum = "e94fea34d77a245229e7746bd2beb786cd2a896f306ff491fb8cecb3074b10a7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parse-zoneinfo",
|
"parse-zoneinfo",
|
||||||
"phf",
|
|
||||||
"phf_codegen",
|
"phf_codegen",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -431,7 +415,7 @@ version = "0.28.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
|
checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags",
|
||||||
"crossterm_winapi",
|
"crossterm_winapi",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"mio",
|
"mio",
|
||||||
@ -483,19 +467,6 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "csv-sniffer"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7b8e952164bb270a505d6cb6136624174c34cfb9abd16e0011f5e53058317f39"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"csv",
|
|
||||||
"csv-core",
|
|
||||||
"memchr",
|
|
||||||
"regex 0.2.11",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "csvx"
|
name = "csvx"
|
||||||
version = "0.1.17"
|
version = "0.1.17"
|
||||||
@ -869,8 +840,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ironcalc"
|
name = "ironcalc"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/ironcalc/IronCalc#98dc557a017b2ad640fb46eece17afda14177e59"
|
source = "git+https://github.com/ironcalc/IronCalc?rev=264fcac63cc93b08a4b4a6764815e0c0adf6a53c#99125f1fea1c8c72c61f8cba94d847ed3471a4af"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitcode",
|
"bitcode",
|
||||||
"chrono",
|
"chrono",
|
||||||
@ -885,18 +856,17 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ironcalc_base"
|
name = "ironcalc_base"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/ironcalc/IronCalc#98dc557a017b2ad640fb46eece17afda14177e59"
|
source = "git+https://github.com/ironcalc/IronCalc?rev=264fcac63cc93b08a4b4a6764815e0c0adf6a53c#99125f1fea1c8c72c61f8cba94d847ed3471a4af"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitcode",
|
"bitcode",
|
||||||
"chrono",
|
"chrono",
|
||||||
"chrono-tz",
|
"chrono-tz",
|
||||||
"csv",
|
"csv",
|
||||||
"csv-sniffer",
|
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rand",
|
"rand",
|
||||||
"regex 1.11.1",
|
"regex",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@ -949,12 +919,6 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lazy_static"
|
|
||||||
version = "1.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.161"
|
version = "0.2.161"
|
||||||
@ -1085,7 +1049,7 @@ version = "0.3.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24"
|
checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"regex 1.11.1",
|
"regex",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1251,7 +1215,7 @@ version = "0.29.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b"
|
checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags",
|
||||||
"cassowary",
|
"cassowary",
|
||||||
"compact_str",
|
"compact_str",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
@ -1281,20 +1245,7 @@ version = "0.5.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
|
checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex"
|
|
||||||
version = "0.2.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick 0.6.10",
|
|
||||||
"memchr",
|
|
||||||
"regex-syntax 0.5.6",
|
|
||||||
"thread_local",
|
|
||||||
"utf8-ranges",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1303,10 +1254,10 @@ version = "1.11.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick 1.1.3",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-automata",
|
"regex-automata",
|
||||||
"regex-syntax 0.8.5",
|
"regex-syntax",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1315,18 +1266,9 @@ version = "0.4.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick 1.1.3",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-syntax 0.8.5",
|
"regex-syntax",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-syntax"
|
|
||||||
version = "0.5.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
|
|
||||||
dependencies = [
|
|
||||||
"ucd-util",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1370,7 +1312,7 @@ dependencies = [
|
|||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"regex 1.11.1",
|
"regex",
|
||||||
"relative-path",
|
"relative-path",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"syn",
|
"syn",
|
||||||
@ -1398,7 +1340,7 @@ version = "0.38.37"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
|
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
@ -1636,15 +1578,6 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thread_local"
|
|
||||||
version = "0.3.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.36"
|
version = "0.3.36"
|
||||||
@ -1722,12 +1655,6 @@ version = "1.17.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ucd-util"
|
|
||||||
version = "0.1.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "abd2fc5d32b590614af8b0a20d837f32eca055edd0bbead59a9cfe80858be003"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.13"
|
version = "1.0.13"
|
||||||
@ -1763,12 +1690,6 @@ version = "0.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "utf8-ranges"
|
|
||||||
version = "1.0.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
@ -10,7 +10,8 @@ anyhow = { version = "1.0.91", features = ["backtrace"] }
|
|||||||
clap = { version = "4.5.20", features = ["derive"] }
|
clap = { version = "4.5.20", features = ["derive"] }
|
||||||
crossterm = { version = "0.28.1", features = ["event-stream", "serde"] }
|
crossterm = { version = "0.28.1", features = ["event-stream", "serde"] }
|
||||||
csvx = "0.1.17"
|
csvx = "0.1.17"
|
||||||
ironcalc = { git = "https://github.com/ironcalc/IronCalc" }
|
# this revision introduces a way to get the Model back out of the UserModel
|
||||||
|
ironcalc = { git = "https://github.com/ironcalc/IronCalc?rev=264fcac63cc93b08a4b4a6764815e0c0adf6a53c" }
|
||||||
futures = "0.3.31"
|
futures = "0.3.31"
|
||||||
ratatui = "0.29.0"
|
ratatui = "0.29.0"
|
||||||
thiserror = "1.0.65"
|
thiserror = "1.0.65"
|
||||||
|
208
src/book/mod.rs
208
src/book/mod.rs
@ -3,9 +3,10 @@ use std::cmp::max;
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use ironcalc::{
|
use ironcalc::{
|
||||||
base::{
|
base::{
|
||||||
|
expressions::types::Area,
|
||||||
types::{Border, Col, Fill, Font, Row, SheetData, Style, Worksheet},
|
types::{Border, Col, Fill, Font, Row, SheetData, Style, Worksheet},
|
||||||
worksheet::WorksheetDimension,
|
worksheet::WorksheetDimension,
|
||||||
Model,
|
Model, UserModel,
|
||||||
},
|
},
|
||||||
export::save_xlsx_to_writer,
|
export::save_xlsx_to_writer,
|
||||||
import::load_from_xlsx,
|
import::load_from_xlsx,
|
||||||
@ -78,14 +79,14 @@ impl<'book> AddressRange<'book> {
|
|||||||
|
|
||||||
/// A spreadsheet book with some internal state tracking.
|
/// A spreadsheet book with some internal state tracking.
|
||||||
pub struct Book {
|
pub struct Book {
|
||||||
pub(crate) model: Model,
|
pub(crate) model: UserModel,
|
||||||
pub current_sheet: u32,
|
pub current_sheet: u32,
|
||||||
pub location: crate::ui::Address,
|
pub location: crate::ui::Address,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Book {
|
impl Book {
|
||||||
/// Construct a new book from a Model
|
/// Construct a new book from a Model
|
||||||
pub fn new(model: Model) -> Self {
|
pub fn new(model: UserModel) -> Self {
|
||||||
Self {
|
Self {
|
||||||
model,
|
model,
|
||||||
current_sheet: 0,
|
current_sheet: 0,
|
||||||
@ -93,9 +94,17 @@ impl Book {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_model(model: Model) -> Self {
|
||||||
|
Self::new(UserModel::from_model(model))
|
||||||
|
}
|
||||||
|
|
||||||
/// Construct a new book from an xlsx file.
|
/// Construct a new book from an xlsx file.
|
||||||
pub fn new_from_xlsx(path: &str) -> Result<Self> {
|
pub fn new_from_xlsx(path: &str) -> Result<Self> {
|
||||||
Ok(Self::new(load_from_xlsx(path, "en", "America/New_York")?))
|
Ok(Self::from_model(load_from_xlsx(
|
||||||
|
path,
|
||||||
|
"en",
|
||||||
|
"America/New_York",
|
||||||
|
)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate the spreadsheet calculating formulas and style changes.
|
/// Evaluate the spreadsheet calculating formulas and style changes.
|
||||||
@ -107,7 +116,7 @@ impl Book {
|
|||||||
// TODO(zaphar): Should I support ICalc?
|
// TODO(zaphar): Should I support ICalc?
|
||||||
/// Construct a new book from a path.
|
/// Construct a new book from a path.
|
||||||
pub fn new_from_xlsx_with_locale(path: &str, locale: &str, tz: &str) -> Result<Self> {
|
pub fn new_from_xlsx_with_locale(path: &str, locale: &str, tz: &str) -> Result<Self> {
|
||||||
Ok(Self::new(load_from_xlsx(path, locale, tz)?))
|
Ok(Self::from_model(load_from_xlsx(path, locale, tz)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Save book to an xlsx file.
|
/// Save book to an xlsx file.
|
||||||
@ -116,7 +125,7 @@ impl Book {
|
|||||||
let file_path = std::path::Path::new(path);
|
let file_path = std::path::Path::new(path);
|
||||||
let file = std::fs::File::create(file_path)?;
|
let file = std::fs::File::create(file_path)?;
|
||||||
let writer = std::io::BufWriter::new(file);
|
let writer = std::io::BufWriter::new(file);
|
||||||
save_xlsx_to_writer(&self.model, writer)?;
|
save_xlsx_to_writer(self.model.get_model(), writer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,10 +133,9 @@ impl Book {
|
|||||||
/// is the sheet name and the u32 is the sheet index.
|
/// is the sheet name and the u32 is the sheet index.
|
||||||
pub fn get_all_sheets_identifiers(&self) -> Vec<(String, u32)> {
|
pub fn get_all_sheets_identifiers(&self) -> Vec<(String, u32)> {
|
||||||
self.model
|
self.model
|
||||||
.workbook
|
.get_worksheets_properties()
|
||||||
.worksheets
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|sheet| (sheet.get_name(), sheet.get_sheet_id()))
|
.map(|sheet| (sheet.name.to_owned(), sheet.sheet_id))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,11 +150,12 @@ impl Book {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_sheet(&mut self, sheet_name: Option<&str>) -> Result<()> {
|
pub fn new_sheet(&mut self, sheet_name: Option<&str>) -> Result<()> {
|
||||||
let (_, idx) = self.model.new_sheet();
|
todo!("We need to figure out how to find the new sheet index so we can rename it");
|
||||||
if let Some(name) = sheet_name {
|
//let (_, idx) = self.model.new_sheet();
|
||||||
self.set_sheet_name(idx as usize, name)?;
|
//if let Some(name) = sheet_name {
|
||||||
}
|
// self.set_sheet_name(idx as usize, name)?;
|
||||||
Ok(())
|
//}
|
||||||
|
//Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the sheet data for the current worksheet.
|
/// Get the sheet data for the current worksheet.
|
||||||
@ -172,8 +181,10 @@ impl Book {
|
|||||||
.iter()
|
.iter()
|
||||||
.skip(1)
|
.skip(1)
|
||||||
{
|
{
|
||||||
|
// TODO(jeremy): Is there a better way to do this using UserModel?
|
||||||
let contents = self
|
let contents = self
|
||||||
.model
|
.model
|
||||||
|
.get_model()
|
||||||
.extend_to(
|
.extend_to(
|
||||||
self.current_sheet,
|
self.current_sheet,
|
||||||
from.row as i32,
|
from.row as i32,
|
||||||
@ -187,7 +198,7 @@ impl Book {
|
|||||||
self.current_sheet,
|
self.current_sheet,
|
||||||
cell.row as i32,
|
cell.row as i32,
|
||||||
cell.col as i32,
|
cell.col as i32,
|
||||||
contents,
|
&contents,
|
||||||
)
|
)
|
||||||
.map_err(|e| anyhow!(e))?;
|
.map_err(|e| anyhow!(e))?;
|
||||||
}
|
}
|
||||||
@ -206,32 +217,53 @@ impl Book {
|
|||||||
pub fn clear_cell_contents(&mut self, sheet: u32, Address { row, col }: Address) -> Result<()> {
|
pub fn clear_cell_contents(&mut self, sheet: u32, Address { row, col }: Address) -> Result<()> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.model
|
.model
|
||||||
.cell_clear_contents(sheet, row as i32, col as i32)
|
.range_clear_contents(&Area {
|
||||||
|
sheet,
|
||||||
|
row: row as i32,
|
||||||
|
column: col as i32,
|
||||||
|
width: 1,
|
||||||
|
height: 1,
|
||||||
|
})
|
||||||
.map_err(|s| anyhow!("Unable to clear cell contents {}", s))?)
|
.map_err(|s| anyhow!("Unable to clear cell contents {}", s))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_cell_range(&mut self, sheet: u32, start: Address, end: Address) -> Result<()> {
|
pub fn clear_cell_range(&mut self, sheet: u32, start: Address, end: Address) -> Result<()> {
|
||||||
for row in start.row..=end.row {
|
let area = Area {
|
||||||
for col in start.col..=end.col {
|
sheet,
|
||||||
self.clear_cell_contents(sheet, Address { row, col })?;
|
row: start.row as i32,
|
||||||
}
|
column: start.col as i32,
|
||||||
}
|
width: (end.row - start.row) as i32,
|
||||||
|
height: (end.col - end.row) as i32,
|
||||||
|
};
|
||||||
|
self.model
|
||||||
|
.range_clear_contents(&area)
|
||||||
|
.map_err(|s| anyhow!("Unable to clear cell contents {}", s))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_cell_all(&mut self, sheet: u32, Address { row, col }: Address) -> Result<()> {
|
pub fn clear_cell_all(&mut self, sheet: u32, Address { row, col }: Address) -> Result<()> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.model
|
.model
|
||||||
.cell_clear_all(sheet, row as i32, col as i32)
|
.range_clear_all(&Area {
|
||||||
|
sheet,
|
||||||
|
row: row as i32,
|
||||||
|
column: col as i32,
|
||||||
|
width: 1,
|
||||||
|
height: 1,
|
||||||
|
})
|
||||||
.map_err(|s| anyhow!("Unable to clear cell contents {}", s))?)
|
.map_err(|s| anyhow!("Unable to clear cell contents {}", s))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_cell_range_all(&mut self, sheet: u32, start: Address, end: Address) -> Result<()> {
|
pub fn clear_cell_range_all(&mut self, sheet: u32, start: Address, end: Address) -> Result<()> {
|
||||||
for row in start.row..=end.row {
|
let area = Area {
|
||||||
for col in start.col..=end.col {
|
sheet,
|
||||||
self.clear_cell_all(sheet, Address { row, col })?;
|
row: start.row as i32,
|
||||||
}
|
column: start.col as i32,
|
||||||
}
|
width: (end.row - start.row) as i32,
|
||||||
|
height: (end.col - end.row) as i32,
|
||||||
|
};
|
||||||
|
self.model.range_clear_all(&area)
|
||||||
|
.map_err(|s| anyhow!("Unable to clear cell contents {}", s))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +276,7 @@ impl Book {
|
|||||||
// TODO(jwall): This is modeled a little weird. We should probably record
|
// TODO(jwall): This is modeled a little weird. We should probably record
|
||||||
// the error *somewhere* but for the user there is nothing to be done except
|
// the error *somewhere* but for the user there is nothing to be done except
|
||||||
// not use a style.
|
// not use a style.
|
||||||
match self.model.get_style_for_cell(sheet, cell.row as i32, cell.col as i32)
|
match self.model.get_model().get_style_for_cell(sheet, cell.row as i32, cell.col as i32)
|
||||||
{
|
{
|
||||||
Err(_) => None,
|
Err(_) => None,
|
||||||
Ok(s) => Some(s),
|
Ok(s) => Some(s),
|
||||||
@ -252,12 +284,12 @@ impl Book {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_column(&self, sheet: u32, col: usize) -> Result<Option<&Col>> {
|
fn get_column(&self, sheet: u32, col: usize) -> Result<Option<&Col>> {
|
||||||
Ok(self.model.workbook.worksheet(sheet)
|
Ok(self.model.get_model().workbook.worksheet(sheet)
|
||||||
.map_err(|e| anyhow!("{}", e))?.cols.get(col))
|
.map_err(|e| anyhow!("{}", e))?.cols.get(col))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_row(&self, sheet: u32, col: usize) -> Result<Option<&Row>> {
|
fn get_row(&self, sheet: u32, col: usize) -> Result<Option<&Row>> {
|
||||||
Ok(self.model.workbook.worksheet(sheet)
|
Ok(self.model.get_model().workbook.worksheet(sheet)
|
||||||
.map_err(|e| anyhow!("{}", e))?.rows.get(col))
|
.map_err(|e| anyhow!("{}", e))?.rows.get(col))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,7 +299,7 @@ impl Book {
|
|||||||
// not use a style.
|
// not use a style.
|
||||||
if let Some(col) = self.get_column(sheet, col)? {
|
if let Some(col) = self.get_column(sheet, col)? {
|
||||||
if let Some(style_idx) = col.style.map(|idx| idx as usize) {
|
if let Some(style_idx) = col.style.map(|idx| idx as usize) {
|
||||||
let styles = &self.model.workbook.styles;
|
let styles = &self.model.get_model().workbook.styles;
|
||||||
if styles.cell_style_xfs.len() <= style_idx {
|
if styles.cell_style_xfs.len() <= style_idx {
|
||||||
return Ok(Some(Style {
|
return Ok(Some(Style {
|
||||||
alignment: None,
|
alignment: None,
|
||||||
@ -289,7 +321,7 @@ impl Book {
|
|||||||
// not use a style.
|
// not use a style.
|
||||||
if let Some(row) = self.get_row(sheet, row)? {
|
if let Some(row) = self.get_row(sheet, row)? {
|
||||||
let style_idx = row.s as usize;
|
let style_idx = row.s as usize;
|
||||||
let styles = &self.model.workbook.styles;
|
let styles = &self.model.get_model().workbook.styles;
|
||||||
if styles.cell_style_xfs.len() <= style_idx {
|
if styles.cell_style_xfs.len() <= style_idx {
|
||||||
return Ok(Some(Style {
|
return Ok(Some(Style {
|
||||||
alignment: None,
|
alignment: None,
|
||||||
@ -316,40 +348,34 @@ impl Book {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_cell_style(&mut self, style: &Style, sheet: u32, cell: &Address) -> Result<()> {
|
pub fn set_cell_style(&mut self, style: &Style, sheet: u32, cell: &Address) -> Result<()> {
|
||||||
self.model.set_cell_style(sheet, cell.row as i32, cell.col as i32, style)
|
todo!()
|
||||||
.map_err(|s| anyhow!("Unable to format cell {}", s))?;
|
//self.model.set_cell_style(sheet, cell.row as i32, cell.col as i32, style)
|
||||||
Ok(())
|
// .map_err(|s| anyhow!("Unable to format cell {}", s))?;
|
||||||
|
//Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_col_style(&mut self, style: &Style, sheet: u32, col: usize) -> Result<()> {
|
pub fn set_col_style(&mut self, style: &Style, sheet: u32, col: usize) -> Result<()> {
|
||||||
let idx = self.create_or_get_style_idx(style);
|
todo!()
|
||||||
let sheet = self.model.workbook.worksheet_mut(sheet)
|
//let idx = self.create_or_get_style_idx(style);
|
||||||
.map_err(|e| anyhow!("{}", e))?;
|
//let sheet = self.model.workbook.worksheet_mut(sheet)
|
||||||
let width = sheet.get_column_width(col as i32)
|
// .map_err(|e| anyhow!("{}", e))?;
|
||||||
.map_err(|e| anyhow!("{}", e))?;
|
//let width = sheet.get_column_width(col as i32)
|
||||||
sheet.set_column_style(col as i32, idx)
|
// .map_err(|e| anyhow!("{}", e))?;
|
||||||
.map_err(|e| anyhow!("{}", e))?;
|
//sheet.set_column_style(col as i32, idx)
|
||||||
sheet.set_column_width(col as i32, width)
|
// .map_err(|e| anyhow!("{}", e))?;
|
||||||
.map_err(|e| anyhow!("{}", e))?;
|
//sheet.set_column_width(col as i32, width)
|
||||||
Ok(())
|
// .map_err(|e| anyhow!("{}", e))?;
|
||||||
|
//Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_row_style(&mut self, style: &Style, sheet: u32, row: usize) -> Result<()> {
|
pub fn set_row_style(&mut self, style: &Style, sheet: u32, row: usize) -> Result<()> {
|
||||||
let idx = self.create_or_get_style_idx(style);
|
todo!()
|
||||||
self.model.workbook.worksheet_mut(sheet)
|
//let idx = self.create_or_get_style_idx(style);
|
||||||
.map_err(|e| anyhow!("{}", e))?
|
//self.model.workbook.worksheet_mut(sheet)
|
||||||
.set_row_style(row as i32, idx)
|
// .map_err(|e| anyhow!("{}", e))?
|
||||||
.map_err(|e| anyhow!("{}", e))?;
|
// .set_row_style(row as i32, idx)
|
||||||
Ok(())
|
// .map_err(|e| anyhow!("{}", e))?;
|
||||||
}
|
//Ok(())
|
||||||
|
|
||||||
fn create_or_get_style_idx(&mut self, style: &Style) -> i32 {
|
|
||||||
let idx = if let Some(style_idx) = self.model.workbook.styles.get_style_index(style) {
|
|
||||||
style_idx
|
|
||||||
} else {
|
|
||||||
self.model.workbook.styles.create_new_style(style)
|
|
||||||
};
|
|
||||||
idx
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a cells rendered content for display.
|
/// Get a cells rendered content for display.
|
||||||
@ -395,7 +421,8 @@ impl Book {
|
|||||||
self.current_sheet,
|
self.current_sheet,
|
||||||
location.row as i32,
|
location.row as i32,
|
||||||
location.col as i32,
|
location.col as i32,
|
||||||
value.into(),
|
// TODO(jwall): This could probably be made more efficient
|
||||||
|
&value.into(),
|
||||||
)
|
)
|
||||||
.map_err(|e| anyhow!("Invalid cell contents: {}", e))?;
|
.map_err(|e| anyhow!("Invalid cell contents: {}", e))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -403,9 +430,11 @@ impl Book {
|
|||||||
|
|
||||||
/// Insert `count` rows at a `row_idx`.
|
/// Insert `count` rows at a `row_idx`.
|
||||||
pub fn insert_rows(&mut self, row_idx: usize, count: usize) -> Result<()> {
|
pub fn insert_rows(&mut self, row_idx: usize, count: usize) -> Result<()> {
|
||||||
self.model
|
for i in 0..count {
|
||||||
.insert_rows(self.current_sheet, row_idx as i32, count as i32)
|
self.model
|
||||||
.map_err(|e| anyhow!("Unable to insert row(s): {}", e))?;
|
.insert_row(self.current_sheet, (row_idx + i) as i32)
|
||||||
|
.map_err(|e| anyhow!("Unable to insert row(s): {}", e))?;
|
||||||
|
}
|
||||||
if self.location.row >= row_idx {
|
if self.location.row >= row_idx {
|
||||||
self.move_to(&Address {
|
self.move_to(&Address {
|
||||||
row: self.location.row + count,
|
row: self.location.row + count,
|
||||||
@ -417,9 +446,11 @@ impl Book {
|
|||||||
|
|
||||||
/// Insert `count` columns at a `col_idx`.
|
/// Insert `count` columns at a `col_idx`.
|
||||||
pub fn insert_columns(&mut self, col_idx: usize, count: usize) -> Result<()> {
|
pub fn insert_columns(&mut self, col_idx: usize, count: usize) -> Result<()> {
|
||||||
self.model
|
for i in 0..count {
|
||||||
.insert_columns(self.current_sheet, col_idx as i32, count as i32)
|
self.model
|
||||||
.map_err(|e| anyhow!("Unable to insert column(s): {}", e))?;
|
.insert_column(self.current_sheet, (col_idx + i) as i32)
|
||||||
|
.map_err(|e| anyhow!("Unable to insert column(s): {}", e))?;
|
||||||
|
}
|
||||||
if self.location.col >= col_idx {
|
if self.location.col >= col_idx {
|
||||||
self.move_to(&Address {
|
self.move_to(&Address {
|
||||||
row: self.location.row,
|
row: self.location.row,
|
||||||
@ -467,7 +498,7 @@ impl Book {
|
|||||||
/// Select a sheet by name.
|
/// Select a sheet by name.
|
||||||
pub fn select_sheet_by_name(&mut self, name: &str) -> bool {
|
pub fn select_sheet_by_name(&mut self, name: &str) -> bool {
|
||||||
if let Some((idx, _sheet)) = self
|
if let Some((idx, _sheet)) = self
|
||||||
.model
|
.model.get_model()
|
||||||
.workbook
|
.workbook
|
||||||
.worksheets
|
.worksheets
|
||||||
.iter()
|
.iter()
|
||||||
@ -482,11 +513,12 @@ impl Book {
|
|||||||
|
|
||||||
/// Get all sheet names
|
/// Get all sheet names
|
||||||
pub fn get_sheet_names(&self) -> Vec<String> {
|
pub fn get_sheet_names(&self) -> Vec<String> {
|
||||||
self.model.workbook.get_worksheet_names()
|
self.model.get_model().workbook.get_worksheet_names()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select_next_sheet(&mut self) {
|
pub fn select_next_sheet(&mut self) {
|
||||||
let len = self.model.workbook.worksheets.len() as u32;
|
// TODO(jwall): Is there a cleaner way to do this with UserModel?
|
||||||
|
let len = self.model.get_model().workbook.worksheets.len() as u32;
|
||||||
let mut next = self.current_sheet + 1;
|
let mut next = self.current_sheet + 1;
|
||||||
if next == len {
|
if next == len {
|
||||||
next = 0;
|
next = 0;
|
||||||
@ -495,7 +527,8 @@ impl Book {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn select_prev_sheet(&mut self) {
|
pub fn select_prev_sheet(&mut self) {
|
||||||
let len = self.model.workbook.worksheets.len() as u32;
|
// TODO(jwall): Is there a cleaner way to do this with UserModel?
|
||||||
|
let len = self.model.get_model().workbook.worksheets.len() as u32;
|
||||||
let next = if self.current_sheet == 0 {
|
let next = if self.current_sheet == 0 {
|
||||||
len - 1
|
len - 1
|
||||||
} else {
|
} else {
|
||||||
@ -506,8 +539,9 @@ impl Book {
|
|||||||
|
|
||||||
/// Select a sheet by id.
|
/// Select a sheet by id.
|
||||||
pub fn select_sheet_by_id(&mut self, id: u32) -> bool {
|
pub fn select_sheet_by_id(&mut self, id: u32) -> bool {
|
||||||
|
// TODO(jwall): Is there a cleaner way to do this with UserModel?
|
||||||
if let Some((idx, _sheet)) = self
|
if let Some((idx, _sheet)) = self
|
||||||
.model
|
.model.get_model()
|
||||||
.workbook
|
.workbook
|
||||||
.worksheets
|
.worksheets
|
||||||
.iter()
|
.iter()
|
||||||
@ -522,42 +556,46 @@ impl Book {
|
|||||||
|
|
||||||
/// Get the current `Worksheet`.
|
/// Get the current `Worksheet`.
|
||||||
pub(crate) fn get_sheet(&self) -> Result<&Worksheet> {
|
pub(crate) fn get_sheet(&self) -> Result<&Worksheet> {
|
||||||
|
// TODO(jwall): Is there a cleaner way to do this with UserModel?
|
||||||
Ok(self
|
Ok(self
|
||||||
.model
|
.model.get_model()
|
||||||
.workbook
|
.workbook
|
||||||
.worksheet(self.current_sheet)
|
.worksheet(self.current_sheet)
|
||||||
.map_err(|s| anyhow!("Invalid Worksheet id: {}: error: {}", self.current_sheet, s))?)
|
.map_err(|s| anyhow!("Invalid Worksheet id: {}: error: {}", self.current_sheet, s))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_sheet_mut(&mut self) -> Result<&mut Worksheet> {
|
pub(crate) fn get_sheet_mut(&mut self) -> Result<&mut Worksheet> {
|
||||||
Ok(self
|
todo!("Is there a clean way to do this with UserModel?")
|
||||||
.model
|
//Ok(self
|
||||||
.workbook
|
// .model.get_model()
|
||||||
.worksheet_mut(self.current_sheet)
|
// .workbook
|
||||||
.map_err(|s| anyhow!("Invalid Worksheet: {}", s))?)
|
// .worksheet_mut(self.current_sheet)
|
||||||
|
// .map_err(|s| anyhow!("Invalid Worksheet: {}", s))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_sheet_name_by_idx(&self, idx: usize) -> Result<&str> {
|
pub(crate) fn get_sheet_name_by_idx(&self, idx: usize) -> Result<&str> {
|
||||||
|
// TODO(jwall): Is there a cleaner way to do this with UserModel?
|
||||||
Ok(&self
|
Ok(&self
|
||||||
.model
|
.model.get_model()
|
||||||
.workbook
|
.workbook
|
||||||
.worksheet(idx as u32)
|
.worksheet(idx as u32)
|
||||||
.map_err(|s| anyhow!("Invalid Worksheet: {}", s))?
|
.map_err(|s| anyhow!("Invalid Worksheet: {}", s))?
|
||||||
.name)
|
.name)
|
||||||
}
|
}
|
||||||
pub(crate) fn get_sheet_by_idx_mut(&mut self, idx: usize) -> Result<&mut Worksheet> {
|
pub(crate) fn get_sheet_by_idx_mut(&mut self, idx: usize) -> Result<&mut Worksheet> {
|
||||||
Ok(self
|
todo!("Is there a clean way to do this with UserModel?")
|
||||||
.model
|
//Ok(self
|
||||||
.workbook
|
// .model
|
||||||
.worksheet_mut(idx as u32)
|
// .workbook
|
||||||
.map_err(|s| anyhow!("Invalid Worksheet: {}", s))?)
|
// .worksheet_mut(idx as u32)
|
||||||
|
// .map_err(|s| anyhow!("Invalid Worksheet: {}", s))?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Book {
|
impl Default for Book {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let mut book =
|
let mut book =
|
||||||
Book::new(Model::new_empty("default_name", "en", "America/New_York").unwrap());
|
Book::new(UserModel::new_empty("default_name", "en", "America/New_York").unwrap());
|
||||||
book.update_cell(&Address { row: 1, col: 1 }, "").unwrap();
|
book.update_cell(&Address { row: 1, col: 1 }, "").unwrap();
|
||||||
book
|
book
|
||||||
}
|
}
|
||||||
|
@ -187,7 +187,7 @@ impl<'ws> Workspace<'ws> {
|
|||||||
|
|
||||||
pub fn new_empty(locale: &str, tz: &str) -> Result<Self> {
|
pub fn new_empty(locale: &str, tz: &str) -> Result<Self> {
|
||||||
Ok(Self::new(
|
Ok(Self::new(
|
||||||
Book::new(Model::new_empty("", locale, tz).map_err(|e| anyhow!("{}", e))?),
|
Book::from_model(Model::new_empty("", locale, tz).map_err(|e| anyhow!("{}", e))?),
|
||||||
PathBuf::default(),
|
PathBuf::default(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use super::{Address, Book, Viewport, ViewportState};
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_viewport_get_visible_columns() {
|
fn test_viewport_get_visible_columns() {
|
||||||
let mut state = ViewportState::default();
|
let mut state = ViewportState::default();
|
||||||
let book = Book::new(
|
let book = Book::from_model(
|
||||||
Model::new_empty("test", "en", "America/New_York").expect("Failed to make model"),
|
Model::new_empty("test", "en", "America/New_York").expect("Failed to make model"),
|
||||||
);
|
);
|
||||||
let default_size = book.get_col_size(1).expect("Failed to get column size");
|
let default_size = book.get_col_size(1).expect("Failed to get column size");
|
||||||
@ -26,7 +26,7 @@ fn test_viewport_get_visible_columns() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_viewport_get_visible_rows() {
|
fn test_viewport_get_visible_rows() {
|
||||||
let mut state = dbg!(ViewportState::default());
|
let mut state = dbg!(ViewportState::default());
|
||||||
let book = Book::new(
|
let book = Book::from_model(
|
||||||
Model::new_empty("test", "en", "America/New_York").expect("Failed to make model"),
|
Model::new_empty("test", "en", "America/New_York").expect("Failed to make model"),
|
||||||
);
|
);
|
||||||
let height = 6;
|
let height = 6;
|
||||||
@ -45,7 +45,7 @@ fn test_viewport_get_visible_rows() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_viewport_visible_columns_after_length_change() {
|
fn test_viewport_visible_columns_after_length_change() {
|
||||||
let mut state = ViewportState::default();
|
let mut state = ViewportState::default();
|
||||||
let mut book = Book::new(
|
let mut book = Book::from_model(
|
||||||
Model::new_empty("test", "en", "America/New_York").expect("Failed to make model"),
|
Model::new_empty("test", "en", "America/New_York").expect("Failed to make model"),
|
||||||
);
|
);
|
||||||
let default_size = book.get_col_size(1).expect("Failed to get column size");
|
let default_size = book.get_col_size(1).expect("Failed to get column size");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user