ironcalc 0.7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +6 -0
- data/Cargo.lock +1239 -0
- data/Cargo.toml +9 -0
- data/LICENSE-Apache-2.0.md +191 -0
- data/LICENSE-MIT.md +9 -0
- data/README.md +124 -0
- data/ext/ironcalc/Cargo.toml +18 -0
- data/ext/ironcalc/extconf.rb +4 -0
- data/ext/ironcalc/src/error.rs +17 -0
- data/ext/ironcalc/src/lib.rs +270 -0
- data/ext/ironcalc/src/model.rs +330 -0
- data/ext/ironcalc/src/user_model.rs +365 -0
- data/lib/ironcalc/model.rb +81 -0
- data/lib/ironcalc/native_methods.rb +501 -0
- data/lib/ironcalc/version.rb +3 -0
- data/lib/ironcalc.rb +11 -0
- metadata +74 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
use std::cell::RefCell;
|
|
2
|
+
|
|
3
|
+
use magnus::value::StaticSymbol;
|
|
4
|
+
use magnus::{RArray, RString, Ruby};
|
|
5
|
+
|
|
6
|
+
use xlsx::base::types::Style;
|
|
7
|
+
use xlsx::base::Model as CoreModel;
|
|
8
|
+
use xlsx::export::{save_to_icalc, save_to_xlsx};
|
|
9
|
+
|
|
10
|
+
use crate::error::workbook_error;
|
|
11
|
+
|
|
12
|
+
/// Maps an engine `CellType` to a snake_case name, matching the names of the
|
|
13
|
+
/// Python binding's `CellType` enum variants. Returned to Ruby as a Symbol.
|
|
14
|
+
pub(crate) fn cell_type_to_str(cell_type: xlsx::base::types::CellType) -> &'static str {
|
|
15
|
+
use xlsx::base::types::CellType::*;
|
|
16
|
+
match cell_type {
|
|
17
|
+
Number => "number",
|
|
18
|
+
Text => "text",
|
|
19
|
+
LogicalValue => "logical_value",
|
|
20
|
+
ErrorValue => "error_value",
|
|
21
|
+
Array => "array",
|
|
22
|
+
CompoundData => "compound_data",
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/// The raw IronCalc API. Wraps [`CoreModel`]; you must call `evaluate` yourself
|
|
27
|
+
/// after setting inputs.
|
|
28
|
+
#[magnus::wrap(class = "IronCalc::Model", free_immediately, size)]
|
|
29
|
+
pub struct Model {
|
|
30
|
+
pub model: RefCell<CoreModel<'static>>,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
impl Model {
|
|
34
|
+
pub fn new(model: CoreModel<'static>) -> Self {
|
|
35
|
+
Model {
|
|
36
|
+
model: RefCell::new(model),
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Persistence -----------------------------------------------------------
|
|
41
|
+
|
|
42
|
+
pub fn save_to_xlsx(&self, file: String) -> Result<(), magnus::Error> {
|
|
43
|
+
save_to_xlsx(&self.model.borrow(), &file).map_err(workbook_error)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
pub fn save_to_icalc(&self, file: String) -> Result<(), magnus::Error> {
|
|
47
|
+
save_to_icalc(&self.model.borrow(), &file).map_err(workbook_error)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
pub fn to_bytes(ruby: &Ruby, rb_self: &Self) -> RString {
|
|
51
|
+
ruby.str_from_slice(&rb_self.model.borrow().to_bytes())
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Evaluation ------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
pub fn evaluate(&self) {
|
|
57
|
+
self.model.borrow_mut().evaluate()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Set / clear values ----------------------------------------------------
|
|
61
|
+
|
|
62
|
+
pub fn set_user_input(
|
|
63
|
+
&self,
|
|
64
|
+
sheet: u32,
|
|
65
|
+
row: i32,
|
|
66
|
+
column: i32,
|
|
67
|
+
value: String,
|
|
68
|
+
) -> Result<(), magnus::Error> {
|
|
69
|
+
self.model
|
|
70
|
+
.borrow_mut()
|
|
71
|
+
.set_user_input(sheet, row, column, value)
|
|
72
|
+
.map_err(workbook_error)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
pub fn clear_cell_contents(
|
|
76
|
+
&self,
|
|
77
|
+
sheet: u32,
|
|
78
|
+
row: i32,
|
|
79
|
+
column: i32,
|
|
80
|
+
) -> Result<(), magnus::Error> {
|
|
81
|
+
self.model
|
|
82
|
+
.borrow_mut()
|
|
83
|
+
.cell_clear_contents(sheet, row, column)
|
|
84
|
+
.map_err(workbook_error)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Get values ------------------------------------------------------------
|
|
88
|
+
|
|
89
|
+
pub fn get_cell_content(
|
|
90
|
+
&self,
|
|
91
|
+
sheet: u32,
|
|
92
|
+
row: i32,
|
|
93
|
+
column: i32,
|
|
94
|
+
) -> Result<String, magnus::Error> {
|
|
95
|
+
self.model
|
|
96
|
+
.borrow()
|
|
97
|
+
.get_localized_cell_content(sheet, row, column)
|
|
98
|
+
.map_err(workbook_error)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
pub fn get_cell_type(
|
|
102
|
+
ruby: &Ruby,
|
|
103
|
+
rb_self: &Self,
|
|
104
|
+
sheet: u32,
|
|
105
|
+
row: i32,
|
|
106
|
+
column: i32,
|
|
107
|
+
) -> Result<StaticSymbol, magnus::Error> {
|
|
108
|
+
rb_self
|
|
109
|
+
.model
|
|
110
|
+
.borrow()
|
|
111
|
+
.get_cell_type(sheet, row, column)
|
|
112
|
+
.map(|t| ruby.sym_new(cell_type_to_str(t)))
|
|
113
|
+
.map_err(workbook_error)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
pub fn get_formatted_cell_value(
|
|
117
|
+
&self,
|
|
118
|
+
sheet: u32,
|
|
119
|
+
row: i32,
|
|
120
|
+
column: i32,
|
|
121
|
+
) -> Result<String, magnus::Error> {
|
|
122
|
+
self.model
|
|
123
|
+
.borrow()
|
|
124
|
+
.get_formatted_cell_value(sheet, row, column)
|
|
125
|
+
.map_err(workbook_error)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Styles (serialized as JSON; the Ruby layer exposes them as hashes) -----
|
|
129
|
+
|
|
130
|
+
pub fn set_cell_style_json(
|
|
131
|
+
&self,
|
|
132
|
+
sheet: u32,
|
|
133
|
+
row: i32,
|
|
134
|
+
column: i32,
|
|
135
|
+
style_json: String,
|
|
136
|
+
) -> Result<(), magnus::Error> {
|
|
137
|
+
let style: Style = serde_json::from_str(&style_json).map_err(workbook_error)?;
|
|
138
|
+
self.model
|
|
139
|
+
.borrow_mut()
|
|
140
|
+
.set_cell_style(sheet, row, column, &style)
|
|
141
|
+
.map_err(workbook_error)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
pub fn get_cell_style_json(
|
|
145
|
+
&self,
|
|
146
|
+
sheet: u32,
|
|
147
|
+
row: i32,
|
|
148
|
+
column: i32,
|
|
149
|
+
) -> Result<String, magnus::Error> {
|
|
150
|
+
let style = self
|
|
151
|
+
.model
|
|
152
|
+
.borrow()
|
|
153
|
+
.get_style_for_cell(sheet, row, column)
|
|
154
|
+
.map_err(workbook_error)?;
|
|
155
|
+
serde_json::to_string(&style).map_err(workbook_error)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Rows / columns --------------------------------------------------------
|
|
159
|
+
|
|
160
|
+
pub fn insert_rows(&self, sheet: u32, row: i32, row_count: i32) -> Result<(), magnus::Error> {
|
|
161
|
+
self.model
|
|
162
|
+
.borrow_mut()
|
|
163
|
+
.insert_rows(sheet, row, row_count)
|
|
164
|
+
.map_err(workbook_error)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
pub fn insert_columns(
|
|
168
|
+
&self,
|
|
169
|
+
sheet: u32,
|
|
170
|
+
column: i32,
|
|
171
|
+
column_count: i32,
|
|
172
|
+
) -> Result<(), magnus::Error> {
|
|
173
|
+
self.model
|
|
174
|
+
.borrow_mut()
|
|
175
|
+
.insert_columns(sheet, column, column_count)
|
|
176
|
+
.map_err(workbook_error)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
pub fn delete_rows(&self, sheet: u32, row: i32, row_count: i32) -> Result<(), magnus::Error> {
|
|
180
|
+
self.model
|
|
181
|
+
.borrow_mut()
|
|
182
|
+
.delete_rows(sheet, row, row_count)
|
|
183
|
+
.map_err(workbook_error)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
pub fn delete_columns(
|
|
187
|
+
&self,
|
|
188
|
+
sheet: u32,
|
|
189
|
+
column: i32,
|
|
190
|
+
column_count: i32,
|
|
191
|
+
) -> Result<(), magnus::Error> {
|
|
192
|
+
self.model
|
|
193
|
+
.borrow_mut()
|
|
194
|
+
.delete_columns(sheet, column, column_count)
|
|
195
|
+
.map_err(workbook_error)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
pub fn get_column_width(&self, sheet: u32, column: i32) -> Result<f64, magnus::Error> {
|
|
199
|
+
self.model
|
|
200
|
+
.borrow()
|
|
201
|
+
.get_column_width(sheet, column)
|
|
202
|
+
.map_err(workbook_error)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
pub fn get_row_height(&self, sheet: u32, row: i32) -> Result<f64, magnus::Error> {
|
|
206
|
+
self.model
|
|
207
|
+
.borrow()
|
|
208
|
+
.get_row_height(sheet, row)
|
|
209
|
+
.map_err(workbook_error)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
pub fn set_column_width(
|
|
213
|
+
&self,
|
|
214
|
+
sheet: u32,
|
|
215
|
+
column: i32,
|
|
216
|
+
width: f64,
|
|
217
|
+
) -> Result<(), magnus::Error> {
|
|
218
|
+
self.model
|
|
219
|
+
.borrow_mut()
|
|
220
|
+
.set_column_width(sheet, column, width)
|
|
221
|
+
.map_err(workbook_error)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
pub fn set_row_height(&self, sheet: u32, row: i32, height: f64) -> Result<(), magnus::Error> {
|
|
225
|
+
self.model
|
|
226
|
+
.borrow_mut()
|
|
227
|
+
.set_row_height(sheet, row, height)
|
|
228
|
+
.map_err(workbook_error)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Frozen rows / columns -------------------------------------------------
|
|
232
|
+
|
|
233
|
+
pub fn get_frozen_columns_count(&self, sheet: u32) -> Result<i32, magnus::Error> {
|
|
234
|
+
self.model
|
|
235
|
+
.borrow()
|
|
236
|
+
.get_frozen_columns_count(sheet)
|
|
237
|
+
.map_err(workbook_error)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
pub fn get_frozen_rows_count(&self, sheet: u32) -> Result<i32, magnus::Error> {
|
|
241
|
+
self.model
|
|
242
|
+
.borrow()
|
|
243
|
+
.get_frozen_rows_count(sheet)
|
|
244
|
+
.map_err(workbook_error)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
pub fn set_frozen_columns_count(
|
|
248
|
+
&self,
|
|
249
|
+
sheet: u32,
|
|
250
|
+
column_count: i32,
|
|
251
|
+
) -> Result<(), magnus::Error> {
|
|
252
|
+
self.model
|
|
253
|
+
.borrow_mut()
|
|
254
|
+
.set_frozen_columns(sheet, column_count)
|
|
255
|
+
.map_err(workbook_error)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
pub fn set_frozen_rows_count(&self, sheet: u32, row_count: i32) -> Result<(), magnus::Error> {
|
|
259
|
+
self.model
|
|
260
|
+
.borrow_mut()
|
|
261
|
+
.set_frozen_rows(sheet, row_count)
|
|
262
|
+
.map_err(workbook_error)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Sheets ----------------------------------------------------------------
|
|
266
|
+
|
|
267
|
+
pub fn get_worksheets_properties(ruby: &Ruby, rb_self: &Self) -> RArray {
|
|
268
|
+
let array = ruby.ary_new();
|
|
269
|
+
for sheet in rb_self.model.borrow().get_worksheets_properties() {
|
|
270
|
+
let hash = ruby.hash_new();
|
|
271
|
+
let _ = hash.aset(ruby.sym_new("name"), sheet.name);
|
|
272
|
+
let _ = hash.aset(ruby.sym_new("state"), sheet.state);
|
|
273
|
+
let _ = hash.aset(ruby.sym_new("sheet_id"), sheet.sheet_id);
|
|
274
|
+
let _ = hash.aset(ruby.sym_new("color"), sheet.color);
|
|
275
|
+
let _ = array.push(hash);
|
|
276
|
+
}
|
|
277
|
+
array
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
pub fn set_sheet_color(&self, sheet: u32, color: String) -> Result<(), magnus::Error> {
|
|
281
|
+
self.model
|
|
282
|
+
.borrow_mut()
|
|
283
|
+
.set_sheet_color(sheet, &color)
|
|
284
|
+
.map_err(workbook_error)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
pub fn add_sheet(&self, sheet_name: String) -> Result<(), magnus::Error> {
|
|
288
|
+
self.model
|
|
289
|
+
.borrow_mut()
|
|
290
|
+
.add_sheet(&sheet_name)
|
|
291
|
+
.map_err(workbook_error)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
pub fn new_sheet(&self) {
|
|
295
|
+
self.model.borrow_mut().new_sheet();
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
pub fn delete_sheet(&self, sheet: u32) -> Result<(), magnus::Error> {
|
|
299
|
+
self.model
|
|
300
|
+
.borrow_mut()
|
|
301
|
+
.delete_sheet(sheet)
|
|
302
|
+
.map_err(workbook_error)
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
pub fn rename_sheet(&self, sheet: u32, new_name: String) -> Result<(), magnus::Error> {
|
|
306
|
+
self.model
|
|
307
|
+
.borrow_mut()
|
|
308
|
+
.rename_sheet_by_index(sheet, &new_name)
|
|
309
|
+
.map_err(workbook_error)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/// Returns `[min_row, max_row, min_column, max_column]` for all non-empty
|
|
313
|
+
/// cells. An empty sheet returns `[1, 1, 1, 1]`.
|
|
314
|
+
pub fn get_sheet_dimensions(&self, sheet: u32) -> Result<(i32, i32, i32, i32), magnus::Error> {
|
|
315
|
+
let model = self.model.borrow();
|
|
316
|
+
let worksheet = model.workbook.worksheet(sheet).map_err(workbook_error)?;
|
|
317
|
+
let dimension = worksheet.dimension();
|
|
318
|
+
Ok((
|
|
319
|
+
dimension.min_row,
|
|
320
|
+
dimension.max_row,
|
|
321
|
+
dimension.min_column,
|
|
322
|
+
dimension.max_column,
|
|
323
|
+
))
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
#[allow(clippy::panic)]
|
|
327
|
+
pub fn test_panic(&self) {
|
|
328
|
+
panic!("This function panics for testing panic handling");
|
|
329
|
+
}
|
|
330
|
+
}
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
use std::cell::RefCell;
|
|
2
|
+
|
|
3
|
+
use magnus::value::StaticSymbol;
|
|
4
|
+
use magnus::{RArray, RString, Ruby};
|
|
5
|
+
|
|
6
|
+
use xlsx::base::expressions::types::Area;
|
|
7
|
+
use xlsx::base::UserModel as CoreUserModel;
|
|
8
|
+
use xlsx::export::{save_to_icalc, save_to_xlsx};
|
|
9
|
+
|
|
10
|
+
use crate::error::workbook_error;
|
|
11
|
+
use crate::model::cell_type_to_str;
|
|
12
|
+
|
|
13
|
+
/// The higher-level, recommended IronCalc API. Wraps [`CoreUserModel`], which
|
|
14
|
+
/// **auto-evaluates after every action** and records diffs for collaboration
|
|
15
|
+
/// (`flush_send_queue` / `apply_external_diffs`). Prefer this over the raw
|
|
16
|
+
/// `Model`, which requires manual `evaluate` and can be left inconsistent.
|
|
17
|
+
///
|
|
18
|
+
/// This mirrors the surface of IronCalc's WebAssembly binding (the engine's
|
|
19
|
+
/// canonical UserModel), so it is a superset of the Python binding's thinner
|
|
20
|
+
/// `UserModel`.
|
|
21
|
+
#[magnus::wrap(class = "IronCalc::UserModel", free_immediately, size)]
|
|
22
|
+
pub struct UserModel {
|
|
23
|
+
pub model: RefCell<CoreUserModel<'static>>,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
impl UserModel {
|
|
27
|
+
pub fn new(model: CoreUserModel<'static>) -> Self {
|
|
28
|
+
UserModel {
|
|
29
|
+
model: RefCell::new(model),
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/// A single-cell `Area`, for the range-based engine operations below.
|
|
34
|
+
fn cell_area(sheet: u32, row: i32, column: i32) -> Area {
|
|
35
|
+
Area {
|
|
36
|
+
sheet,
|
|
37
|
+
row,
|
|
38
|
+
column,
|
|
39
|
+
width: 1,
|
|
40
|
+
height: 1,
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Persistence -----------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
pub fn save_to_xlsx(&self, file: String) -> Result<(), magnus::Error> {
|
|
47
|
+
let model = self.model.borrow();
|
|
48
|
+
save_to_xlsx(model.get_model(), &file).map_err(workbook_error)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
pub fn save_to_icalc(&self, file: String) -> Result<(), magnus::Error> {
|
|
52
|
+
let model = self.model.borrow();
|
|
53
|
+
save_to_icalc(model.get_model(), &file).map_err(workbook_error)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
pub fn to_bytes(ruby: &Ruby, rb_self: &Self) -> RString {
|
|
57
|
+
ruby.str_from_slice(&rb_self.model.borrow().to_bytes())
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Collaboration (diff queue) --------------------------------------------
|
|
61
|
+
|
|
62
|
+
pub fn apply_external_diffs(&self, external_diffs: RString) -> Result<(), magnus::Error> {
|
|
63
|
+
let bytes = unsafe { external_diffs.as_slice() }.to_vec();
|
|
64
|
+
self.model
|
|
65
|
+
.borrow_mut()
|
|
66
|
+
.apply_external_diffs(&bytes)
|
|
67
|
+
.map_err(workbook_error)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
pub fn flush_send_queue(ruby: &Ruby, rb_self: &Self) -> RString {
|
|
71
|
+
let bytes = rb_self.model.borrow_mut().flush_send_queue();
|
|
72
|
+
ruby.str_from_slice(&bytes)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Evaluation / history --------------------------------------------------
|
|
76
|
+
|
|
77
|
+
/// Usually unnecessary (the user model auto-evaluates); exposed for parity.
|
|
78
|
+
pub fn evaluate(&self) {
|
|
79
|
+
self.model.borrow_mut().evaluate();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
pub fn undo(&self) -> Result<(), magnus::Error> {
|
|
83
|
+
self.model.borrow_mut().undo().map_err(workbook_error)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
pub fn redo(&self) -> Result<(), magnus::Error> {
|
|
87
|
+
self.model.borrow_mut().redo().map_err(workbook_error)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
pub fn can_undo(&self) -> bool {
|
|
91
|
+
self.model.borrow().can_undo()
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
pub fn can_redo(&self) -> bool {
|
|
95
|
+
self.model.borrow().can_redo()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Set / clear values ----------------------------------------------------
|
|
99
|
+
|
|
100
|
+
pub fn set_user_input(
|
|
101
|
+
&self,
|
|
102
|
+
sheet: u32,
|
|
103
|
+
row: i32,
|
|
104
|
+
column: i32,
|
|
105
|
+
value: String,
|
|
106
|
+
) -> Result<(), magnus::Error> {
|
|
107
|
+
self.model
|
|
108
|
+
.borrow_mut()
|
|
109
|
+
.set_user_input(sheet, row, column, &value)
|
|
110
|
+
.map_err(workbook_error)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
pub fn clear_cell_contents(
|
|
114
|
+
&self,
|
|
115
|
+
sheet: u32,
|
|
116
|
+
row: i32,
|
|
117
|
+
column: i32,
|
|
118
|
+
) -> Result<(), magnus::Error> {
|
|
119
|
+
self.model
|
|
120
|
+
.borrow_mut()
|
|
121
|
+
.range_clear_contents(&Self::cell_area(sheet, row, column))
|
|
122
|
+
.map_err(workbook_error)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Get values ------------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
pub fn get_cell_content(
|
|
128
|
+
&self,
|
|
129
|
+
sheet: u32,
|
|
130
|
+
row: i32,
|
|
131
|
+
column: i32,
|
|
132
|
+
) -> Result<String, magnus::Error> {
|
|
133
|
+
self.model
|
|
134
|
+
.borrow()
|
|
135
|
+
.get_cell_content(sheet, row, column)
|
|
136
|
+
.map_err(workbook_error)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
pub fn get_cell_type(
|
|
140
|
+
ruby: &Ruby,
|
|
141
|
+
rb_self: &Self,
|
|
142
|
+
sheet: u32,
|
|
143
|
+
row: i32,
|
|
144
|
+
column: i32,
|
|
145
|
+
) -> Result<StaticSymbol, magnus::Error> {
|
|
146
|
+
rb_self
|
|
147
|
+
.model
|
|
148
|
+
.borrow()
|
|
149
|
+
.get_cell_type(sheet, row, column)
|
|
150
|
+
.map(|t| ruby.sym_new(cell_type_to_str(t)))
|
|
151
|
+
.map_err(workbook_error)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
pub fn get_formatted_cell_value(
|
|
155
|
+
&self,
|
|
156
|
+
sheet: u32,
|
|
157
|
+
row: i32,
|
|
158
|
+
column: i32,
|
|
159
|
+
) -> Result<String, magnus::Error> {
|
|
160
|
+
self.model
|
|
161
|
+
.borrow()
|
|
162
|
+
.get_formatted_cell_value(sheet, row, column)
|
|
163
|
+
.map_err(workbook_error)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Styles ----------------------------------------------------------------
|
|
167
|
+
//
|
|
168
|
+
// Reads return the full style as JSON (the Ruby layer exposes it as a Hash).
|
|
169
|
+
// The user-model styling primitive is per-property (`update_range_style`,
|
|
170
|
+
// mirroring the WASM binding) rather than the whole-Style setter the raw
|
|
171
|
+
// `Model` exposes.
|
|
172
|
+
|
|
173
|
+
pub fn get_cell_style_json(
|
|
174
|
+
&self,
|
|
175
|
+
sheet: u32,
|
|
176
|
+
row: i32,
|
|
177
|
+
column: i32,
|
|
178
|
+
) -> Result<String, magnus::Error> {
|
|
179
|
+
let style = self
|
|
180
|
+
.model
|
|
181
|
+
.borrow()
|
|
182
|
+
.get_cell_style(sheet, row, column)
|
|
183
|
+
.map_err(workbook_error)?;
|
|
184
|
+
serde_json::to_string(&style).map_err(workbook_error)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
pub fn update_range_style(
|
|
188
|
+
&self,
|
|
189
|
+
sheet: u32,
|
|
190
|
+
row: i32,
|
|
191
|
+
column: i32,
|
|
192
|
+
style_path: String,
|
|
193
|
+
value: String,
|
|
194
|
+
) -> Result<(), magnus::Error> {
|
|
195
|
+
self.model
|
|
196
|
+
.borrow_mut()
|
|
197
|
+
.update_range_style(&Self::cell_area(sheet, row, column), &style_path, &value)
|
|
198
|
+
.map_err(workbook_error)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Rows / columns --------------------------------------------------------
|
|
202
|
+
|
|
203
|
+
pub fn insert_rows(&self, sheet: u32, row: i32, row_count: i32) -> Result<(), magnus::Error> {
|
|
204
|
+
self.model
|
|
205
|
+
.borrow_mut()
|
|
206
|
+
.insert_rows(sheet, row, row_count)
|
|
207
|
+
.map_err(workbook_error)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
pub fn insert_columns(
|
|
211
|
+
&self,
|
|
212
|
+
sheet: u32,
|
|
213
|
+
column: i32,
|
|
214
|
+
column_count: i32,
|
|
215
|
+
) -> Result<(), magnus::Error> {
|
|
216
|
+
self.model
|
|
217
|
+
.borrow_mut()
|
|
218
|
+
.insert_columns(sheet, column, column_count)
|
|
219
|
+
.map_err(workbook_error)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
pub fn delete_rows(&self, sheet: u32, row: i32, row_count: i32) -> Result<(), magnus::Error> {
|
|
223
|
+
self.model
|
|
224
|
+
.borrow_mut()
|
|
225
|
+
.delete_rows(sheet, row, row_count)
|
|
226
|
+
.map_err(workbook_error)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
pub fn delete_columns(
|
|
230
|
+
&self,
|
|
231
|
+
sheet: u32,
|
|
232
|
+
column: i32,
|
|
233
|
+
column_count: i32,
|
|
234
|
+
) -> Result<(), magnus::Error> {
|
|
235
|
+
self.model
|
|
236
|
+
.borrow_mut()
|
|
237
|
+
.delete_columns(sheet, column, column_count)
|
|
238
|
+
.map_err(workbook_error)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
pub fn get_column_width(&self, sheet: u32, column: i32) -> Result<f64, magnus::Error> {
|
|
242
|
+
self.model
|
|
243
|
+
.borrow()
|
|
244
|
+
.get_column_width(sheet, column)
|
|
245
|
+
.map_err(workbook_error)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
pub fn get_row_height(&self, sheet: u32, row: i32) -> Result<f64, magnus::Error> {
|
|
249
|
+
self.model
|
|
250
|
+
.borrow()
|
|
251
|
+
.get_row_height(sheet, row)
|
|
252
|
+
.map_err(workbook_error)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
pub fn set_column_width(
|
|
256
|
+
&self,
|
|
257
|
+
sheet: u32,
|
|
258
|
+
column: i32,
|
|
259
|
+
width: f64,
|
|
260
|
+
) -> Result<(), magnus::Error> {
|
|
261
|
+
self.model
|
|
262
|
+
.borrow_mut()
|
|
263
|
+
.set_columns_width(sheet, column, column, width)
|
|
264
|
+
.map_err(workbook_error)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
pub fn set_row_height(&self, sheet: u32, row: i32, height: f64) -> Result<(), magnus::Error> {
|
|
268
|
+
self.model
|
|
269
|
+
.borrow_mut()
|
|
270
|
+
.set_rows_height(sheet, row, row, height)
|
|
271
|
+
.map_err(workbook_error)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Frozen rows / columns -------------------------------------------------
|
|
275
|
+
|
|
276
|
+
pub fn get_frozen_columns_count(&self, sheet: u32) -> Result<i32, magnus::Error> {
|
|
277
|
+
self.model
|
|
278
|
+
.borrow()
|
|
279
|
+
.get_frozen_columns_count(sheet)
|
|
280
|
+
.map_err(workbook_error)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
pub fn get_frozen_rows_count(&self, sheet: u32) -> Result<i32, magnus::Error> {
|
|
284
|
+
self.model
|
|
285
|
+
.borrow()
|
|
286
|
+
.get_frozen_rows_count(sheet)
|
|
287
|
+
.map_err(workbook_error)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
pub fn set_frozen_columns_count(
|
|
291
|
+
&self,
|
|
292
|
+
sheet: u32,
|
|
293
|
+
column_count: i32,
|
|
294
|
+
) -> Result<(), magnus::Error> {
|
|
295
|
+
self.model
|
|
296
|
+
.borrow_mut()
|
|
297
|
+
.set_frozen_columns_count(sheet, column_count)
|
|
298
|
+
.map_err(workbook_error)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
pub fn set_frozen_rows_count(&self, sheet: u32, row_count: i32) -> Result<(), magnus::Error> {
|
|
302
|
+
self.model
|
|
303
|
+
.borrow_mut()
|
|
304
|
+
.set_frozen_rows_count(sheet, row_count)
|
|
305
|
+
.map_err(workbook_error)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Sheets ----------------------------------------------------------------
|
|
309
|
+
|
|
310
|
+
pub fn get_worksheets_properties(ruby: &Ruby, rb_self: &Self) -> RArray {
|
|
311
|
+
let array = ruby.ary_new();
|
|
312
|
+
for sheet in rb_self.model.borrow().get_worksheets_properties() {
|
|
313
|
+
let hash = ruby.hash_new();
|
|
314
|
+
let _ = hash.aset(ruby.sym_new("name"), sheet.name);
|
|
315
|
+
let _ = hash.aset(ruby.sym_new("state"), sheet.state);
|
|
316
|
+
let _ = hash.aset(ruby.sym_new("sheet_id"), sheet.sheet_id);
|
|
317
|
+
let _ = hash.aset(ruby.sym_new("color"), sheet.color);
|
|
318
|
+
let _ = array.push(hash);
|
|
319
|
+
}
|
|
320
|
+
array
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
pub fn set_sheet_color(&self, sheet: u32, color: String) -> Result<(), magnus::Error> {
|
|
324
|
+
self.model
|
|
325
|
+
.borrow_mut()
|
|
326
|
+
.set_sheet_color(sheet, &color)
|
|
327
|
+
.map_err(workbook_error)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
pub fn new_sheet(&self) -> Result<(), magnus::Error> {
|
|
331
|
+
self.model.borrow_mut().new_sheet().map_err(workbook_error)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
pub fn delete_sheet(&self, sheet: u32) -> Result<(), magnus::Error> {
|
|
335
|
+
self.model
|
|
336
|
+
.borrow_mut()
|
|
337
|
+
.delete_sheet(sheet)
|
|
338
|
+
.map_err(workbook_error)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
pub fn rename_sheet(&self, sheet: u32, new_name: String) -> Result<(), magnus::Error> {
|
|
342
|
+
self.model
|
|
343
|
+
.borrow_mut()
|
|
344
|
+
.rename_sheet(sheet, &new_name)
|
|
345
|
+
.map_err(workbook_error)
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/// Returns `[min_row, max_row, min_column, max_column]` for all non-empty
|
|
349
|
+
/// cells. An empty sheet returns `[1, 1, 1, 1]`.
|
|
350
|
+
pub fn get_sheet_dimensions(&self, sheet: u32) -> Result<(i32, i32, i32, i32), magnus::Error> {
|
|
351
|
+
let model = self.model.borrow();
|
|
352
|
+
let worksheet = model
|
|
353
|
+
.get_model()
|
|
354
|
+
.workbook
|
|
355
|
+
.worksheet(sheet)
|
|
356
|
+
.map_err(workbook_error)?;
|
|
357
|
+
let dimension = worksheet.dimension();
|
|
358
|
+
Ok((
|
|
359
|
+
dimension.min_row,
|
|
360
|
+
dimension.max_row,
|
|
361
|
+
dimension.min_column,
|
|
362
|
+
dimension.max_column,
|
|
363
|
+
))
|
|
364
|
+
}
|
|
365
|
+
}
|