Compare commits
1 Commits
testing/ni
...
feature-ni
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9699e45a70 |
@@ -418,6 +418,7 @@ impl Model {
|
|||||||
CalcResult::new_error(Error::NIMPL, cell, "Arrays not implemented".to_string())
|
CalcResult::new_error(Error::NIMPL, cell, "Arrays not implemented".to_string())
|
||||||
}
|
}
|
||||||
VariableKind(defined_name) => {
|
VariableKind(defined_name) => {
|
||||||
|
println!("{:?}", defined_name);
|
||||||
let parsed_defined_name = self
|
let parsed_defined_name = self
|
||||||
.parsed_defined_names
|
.parsed_defined_names
|
||||||
.get(&(Some(cell.sheet), defined_name.to_lowercase())) // try getting local defined name
|
.get(&(Some(cell.sheet), defined_name.to_lowercase())) // try getting local defined name
|
||||||
@@ -426,9 +427,11 @@ impl Model {
|
|||||||
.get(&(None, defined_name.to_lowercase()))
|
.get(&(None, defined_name.to_lowercase()))
|
||||||
}); // fallback to global
|
}); // fallback to global
|
||||||
|
|
||||||
|
println!("Parsed: {:?}", defined_name);
|
||||||
if let Some(parsed_defined_name) = parsed_defined_name {
|
if let Some(parsed_defined_name) = parsed_defined_name {
|
||||||
match parsed_defined_name {
|
match parsed_defined_name {
|
||||||
ParsedDefinedName::CellReference(reference) => {
|
ParsedDefinedName::CellReference(reference) => {
|
||||||
|
println!("Here: {}", reference);
|
||||||
self.evaluate_cell(*reference)
|
self.evaluate_cell(*reference)
|
||||||
}
|
}
|
||||||
ParsedDefinedName::RangeReference(range) => CalcResult::Range {
|
ParsedDefinedName::RangeReference(range) => CalcResult::Range {
|
||||||
@@ -1986,6 +1989,95 @@ impl Model {
|
|||||||
.worksheet_mut(sheet)?
|
.worksheet_mut(sheet)?
|
||||||
.set_row_height(column, height)
|
.set_row_height(column, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds a new defined name
|
||||||
|
pub fn new_defined_name(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
scope: Option<u32>,
|
||||||
|
formula: &str,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let name_upper = name.to_uppercase();
|
||||||
|
let defined_names = &self.workbook.defined_names;
|
||||||
|
// if the defined name already exist return error
|
||||||
|
for df in defined_names {
|
||||||
|
if df.name.to_uppercase() == name_upper && df.sheet_id == scope {
|
||||||
|
return Err("Defined name already exists".to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.workbook.defined_names.push(DefinedName {
|
||||||
|
name: name.to_string(),
|
||||||
|
formula: formula.to_string(),
|
||||||
|
sheet_id: scope,
|
||||||
|
});
|
||||||
|
self.reset_parsed_structures();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete defined name of name and scope
|
||||||
|
pub fn delete_defined_name(&mut self, name: &str, scope: Option<u32>) -> Result<(), String> {
|
||||||
|
let name_upper = name.to_uppercase();
|
||||||
|
let defined_names = &self.workbook.defined_names;
|
||||||
|
let mut index = None;
|
||||||
|
for (i, df) in defined_names.iter().enumerate() {
|
||||||
|
if df.name.to_uppercase() == name_upper && df.sheet_id == scope {
|
||||||
|
index = Some(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(i) = index {
|
||||||
|
self.workbook.defined_names.remove(i);
|
||||||
|
self.reset_parsed_structures();
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err("Defined name not found".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns the formula for a defined name
|
||||||
|
pub fn get_defined_name_formula(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
scope: Option<u32>,
|
||||||
|
) -> Result<String, String> {
|
||||||
|
let name_upper = name.to_uppercase();
|
||||||
|
let defined_names = &self.workbook.defined_names;
|
||||||
|
for df in defined_names {
|
||||||
|
if df.name.to_uppercase() == name_upper && df.sheet_id == scope {
|
||||||
|
return Ok(df.formula.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err("Defined name not found".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// update defined name
|
||||||
|
pub fn update_defined_name(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
scope: Option<u32>,
|
||||||
|
new_name: &str,
|
||||||
|
new_scope: Option<u32>,
|
||||||
|
new_formula: &str,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let name_upper = name.to_uppercase();
|
||||||
|
let defined_names = &self.workbook.defined_names;
|
||||||
|
let mut index = None;
|
||||||
|
for (i, df) in defined_names.iter().enumerate() {
|
||||||
|
if df.name.to_uppercase() == name_upper && df.sheet_id == scope {
|
||||||
|
index = Some(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(i) = index {
|
||||||
|
if let Some(df) = self.workbook.defined_names.get_mut(i) {
|
||||||
|
df.name = new_name.to_string();
|
||||||
|
df.sheet_id = new_scope;
|
||||||
|
df.formula = new_formula.to_string();
|
||||||
|
self.reset_parsed_structures();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err("Defined name not found".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ mod test_autofill_columns;
|
|||||||
mod test_autofill_rows;
|
mod test_autofill_rows;
|
||||||
mod test_border;
|
mod test_border;
|
||||||
mod test_clear_cells;
|
mod test_clear_cells;
|
||||||
|
mod test_defined_names;
|
||||||
mod test_diff_queue;
|
mod test_diff_queue;
|
||||||
mod test_evaluation;
|
mod test_evaluation;
|
||||||
mod test_general;
|
mod test_general;
|
||||||
|
|||||||
40
base/src/test/user_model/test_defined_names.rs
Normal file
40
base/src/test/user_model/test_defined_names.rs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#![allow(clippy::unwrap_used)]
|
||||||
|
|
||||||
|
use crate::UserModel;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_defined_name() {
|
||||||
|
let mut model = UserModel::new_empty("model", "en", "UTC").unwrap();
|
||||||
|
model.set_user_input(0, 1, 1, "42").unwrap();
|
||||||
|
model.new_defined_name("myName", None, "$A$1").unwrap();
|
||||||
|
model.set_user_input(0, 5, 7, "=myName").unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
model.get_formatted_cell_value(0, 5, 7),
|
||||||
|
Ok("42".to_string())
|
||||||
|
);
|
||||||
|
|
||||||
|
// rename it
|
||||||
|
model
|
||||||
|
.update_defined_name("myName", None, "myName", None, "$A$1*2")
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
model.get_formatted_cell_value(0, 5, 7),
|
||||||
|
Ok("42".to_string())
|
||||||
|
);
|
||||||
|
|
||||||
|
// delete it
|
||||||
|
model.delete_defined_name("myName", None).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
model.get_formatted_cell_value(0, 5, 7),
|
||||||
|
Ok("#REF!".to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rename_defined_name() {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn delete_sheet() {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn change_scope() {}
|
||||||
@@ -13,8 +13,8 @@ use crate::{
|
|||||||
},
|
},
|
||||||
model::Model,
|
model::Model,
|
||||||
types::{
|
types::{
|
||||||
Alignment, BorderItem, CellType, Col, HorizontalAlignment, SheetProperties, Style,
|
Alignment, BorderItem, CellType, Col, DefinedName, HorizontalAlignment, SheetProperties,
|
||||||
VerticalAlignment,
|
Style, VerticalAlignment,
|
||||||
},
|
},
|
||||||
utils::is_valid_hex_color,
|
utils::is_valid_hex_color,
|
||||||
};
|
};
|
||||||
@@ -1689,6 +1689,66 @@ impl UserModel {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the list of defined names
|
||||||
|
pub fn get_defined_name_list(&self) -> Vec<DefinedName> {
|
||||||
|
self.model.workbook.defined_names.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete an existing defined name
|
||||||
|
pub fn delete_defined_name(&mut self, name: &str, scope: Option<u32>) -> Result<(), String> {
|
||||||
|
let old_value = self.model.get_defined_name_formula(name, scope)?;
|
||||||
|
let diff_list = vec![Diff::DeleteDefinedName {
|
||||||
|
name: name.to_string(),
|
||||||
|
scope,
|
||||||
|
old_value,
|
||||||
|
}];
|
||||||
|
self.push_diff_list(diff_list);
|
||||||
|
self.model.delete_defined_name(name, scope)?;
|
||||||
|
self.evaluate_if_not_paused();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new defined name
|
||||||
|
pub fn new_defined_name(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
scope: Option<u32>,
|
||||||
|
formula: &str,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
self.model.new_defined_name(name, scope, formula)?;
|
||||||
|
let diff_list = vec![Diff::CreateDefinedName {
|
||||||
|
name: name.to_string(),
|
||||||
|
scope,
|
||||||
|
value: formula.to_string(),
|
||||||
|
}];
|
||||||
|
self.push_diff_list(diff_list);
|
||||||
|
self.evaluate_if_not_paused();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates a defined name
|
||||||
|
pub fn update_defined_name(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
scope: Option<u32>,
|
||||||
|
new_name: &str,
|
||||||
|
new_scope: Option<u32>,
|
||||||
|
new_formula: &str,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let old_formula = self.model.get_defined_name_formula(name, scope)?;
|
||||||
|
let diff_list = vec![Diff::UpdateDefinedName {
|
||||||
|
name: name.to_string(),
|
||||||
|
scope,
|
||||||
|
old_formula: old_formula.to_string(),
|
||||||
|
new_name: new_name.to_string(),
|
||||||
|
new_scope,
|
||||||
|
new_formula: new_formula.to_string(),
|
||||||
|
}];
|
||||||
|
self.push_diff_list(diff_list);
|
||||||
|
self.evaluate_if_not_paused();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// **** Private methods ****** //
|
// **** Private methods ****** //
|
||||||
|
|
||||||
fn push_diff_list(&mut self, diff_list: DiffList) {
|
fn push_diff_list(&mut self, diff_list: DiffList) {
|
||||||
@@ -1859,6 +1919,20 @@ impl UserModel {
|
|||||||
} => {
|
} => {
|
||||||
self.model.set_show_grid_lines(*sheet, *old_value)?;
|
self.model.set_show_grid_lines(*sheet, *old_value)?;
|
||||||
}
|
}
|
||||||
|
Diff::CreateDefinedName { name, scope, value } => todo!(),
|
||||||
|
Diff::DeleteDefinedName {
|
||||||
|
name,
|
||||||
|
scope,
|
||||||
|
old_value,
|
||||||
|
} => todo!(),
|
||||||
|
Diff::UpdateDefinedName {
|
||||||
|
name,
|
||||||
|
scope,
|
||||||
|
old_formula,
|
||||||
|
new_name,
|
||||||
|
new_scope,
|
||||||
|
new_formula,
|
||||||
|
} => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if needs_evaluation {
|
if needs_evaluation {
|
||||||
@@ -1986,6 +2060,20 @@ impl UserModel {
|
|||||||
} => {
|
} => {
|
||||||
self.model.set_show_grid_lines(*sheet, *new_value)?;
|
self.model.set_show_grid_lines(*sheet, *new_value)?;
|
||||||
}
|
}
|
||||||
|
Diff::CreateDefinedName { name, scope, value } => todo!(),
|
||||||
|
Diff::DeleteDefinedName {
|
||||||
|
name,
|
||||||
|
scope,
|
||||||
|
old_value,
|
||||||
|
} => todo!(),
|
||||||
|
Diff::UpdateDefinedName {
|
||||||
|
name,
|
||||||
|
scope,
|
||||||
|
old_formula,
|
||||||
|
new_name,
|
||||||
|
new_scope,
|
||||||
|
new_formula,
|
||||||
|
} => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -108,7 +108,26 @@ pub(crate) enum Diff {
|
|||||||
sheet: u32,
|
sheet: u32,
|
||||||
old_value: bool,
|
old_value: bool,
|
||||||
new_value: bool,
|
new_value: bool,
|
||||||
}, // FIXME: we are missing SetViewDiffs
|
},
|
||||||
|
CreateDefinedName {
|
||||||
|
name: String,
|
||||||
|
scope: Option<u32>,
|
||||||
|
value: String,
|
||||||
|
},
|
||||||
|
DeleteDefinedName {
|
||||||
|
name: String,
|
||||||
|
scope: Option<u32>,
|
||||||
|
old_value: String,
|
||||||
|
},
|
||||||
|
UpdateDefinedName {
|
||||||
|
name: String,
|
||||||
|
scope: Option<u32>,
|
||||||
|
old_formula: String,
|
||||||
|
new_name: String,
|
||||||
|
new_scope: Option<u32>,
|
||||||
|
new_formula: String,
|
||||||
|
},
|
||||||
|
// FIXME: we are missing SetViewDiffs
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type DiffList = Vec<Diff>;
|
pub(crate) type DiffList = Vec<Diff>;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use serde::Serialize;
|
||||||
use wasm_bindgen::{
|
use wasm_bindgen::{
|
||||||
prelude::{wasm_bindgen, JsError},
|
prelude::{wasm_bindgen, JsError},
|
||||||
JsValue,
|
JsValue,
|
||||||
@@ -29,6 +30,13 @@ pub fn column_name_from_number(column: i32) -> Result<String, JsError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct DefinedName {
|
||||||
|
name: String,
|
||||||
|
scope: Option<u32>,
|
||||||
|
formula: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
model: BaseModel,
|
model: BaseModel,
|
||||||
@@ -541,4 +549,43 @@ impl Model {
|
|||||||
.paste_csv_string(&range, csv)
|
.paste_csv_string(&range, csv)
|
||||||
.map_err(|e| to_js_error(e.to_string()))
|
.map_err(|e| to_js_error(e.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_name = "getDefinedNameList")]
|
||||||
|
pub fn get_defined_name_list(&self) -> Result<JsValue, JsError> {
|
||||||
|
let data: DefinedNameList =
|
||||||
|
self.model
|
||||||
|
.get_defined_name_list()
|
||||||
|
.iter()
|
||||||
|
.map(|s| DefinedName {
|
||||||
|
name: s.name.to_string(),
|
||||||
|
scope: s.sheet_id,
|
||||||
|
formula: s.formula.to_string(),
|
||||||
|
});
|
||||||
|
// Ok(data)
|
||||||
|
serde_wasm_bindgen::to_value(&data).map_err(|e| to_js_error(e.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_name = "newDefinedName")]
|
||||||
|
pub fn new_defined_name(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
scope: Option<u32>,
|
||||||
|
formula: &str,
|
||||||
|
) -> Result<(), JsError> {
|
||||||
|
self.model
|
||||||
|
.new_defined_name(name, scope, formula)
|
||||||
|
.map_err(|e| to_js_error(e.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_name = "updateDefinedName")]
|
||||||
|
pub fn update_defined_name(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
scope: Option<u32>,
|
||||||
|
new_name: &str,
|
||||||
|
new_scope: Option<u32>,
|
||||||
|
new_formula: &str,
|
||||||
|
) -> Result<(), JsError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user