FIX: Renaming a sheet updates formula in defined name
This commit is contained in:
committed by
Nicolás Hatcher Andrés
parent
acdf85dbc3
commit
c554d929f4
@@ -8,7 +8,7 @@ use crate::{
|
|||||||
expressions::{
|
expressions::{
|
||||||
lexer::LexerMode,
|
lexer::LexerMode,
|
||||||
parser::{
|
parser::{
|
||||||
stringify::{rename_sheet_in_node, to_rc_format},
|
stringify::{rename_sheet_in_node, to_rc_format, to_string},
|
||||||
Parser,
|
Parser,
|
||||||
},
|
},
|
||||||
types::CellReferenceRC,
|
types::CellReferenceRC,
|
||||||
@@ -17,7 +17,8 @@ use crate::{
|
|||||||
locale::get_locale,
|
locale::get_locale,
|
||||||
model::{get_milliseconds_since_epoch, Model, ParsedDefinedName},
|
model::{get_milliseconds_since_epoch, Model, ParsedDefinedName},
|
||||||
types::{
|
types::{
|
||||||
Metadata, SheetState, Workbook, WorkbookSettings, WorkbookView, Worksheet, WorksheetView,
|
DefinedName, Metadata, SheetState, Workbook, WorkbookSettings, WorkbookView, Worksheet,
|
||||||
|
WorksheetView,
|
||||||
},
|
},
|
||||||
utils::ParsedReference,
|
utils::ParsedReference,
|
||||||
};
|
};
|
||||||
@@ -238,7 +239,7 @@ impl Model {
|
|||||||
|
|
||||||
/// Renames a sheet and updates all existing references to that sheet.
|
/// Renames a sheet and updates all existing references to that sheet.
|
||||||
/// It can fail if:
|
/// It can fail if:
|
||||||
/// * The original index is too large
|
/// * The original index is out of bounds
|
||||||
/// * The target sheet name already exists
|
/// * The target sheet name already exists
|
||||||
/// * The target sheet name is invalid
|
/// * The target sheet name is invalid
|
||||||
pub fn rename_sheet_by_index(
|
pub fn rename_sheet_by_index(
|
||||||
@@ -252,17 +253,15 @@ impl Model {
|
|||||||
if self.get_sheet_index_by_name(new_name).is_some() {
|
if self.get_sheet_index_by_name(new_name).is_some() {
|
||||||
return Err(format!("Sheet already exists: '{}'.", new_name));
|
return Err(format!("Sheet already exists: '{}'.", new_name));
|
||||||
}
|
}
|
||||||
let worksheets = &self.workbook.worksheets;
|
// Gets the new name and checks that a sheet with that index exists
|
||||||
let sheet_count = worksheets.len() as u32;
|
let old_name = self.workbook.worksheet(sheet_index)?.get_name();
|
||||||
if sheet_index >= sheet_count {
|
|
||||||
return Err("Sheet index out of bounds".to_string());
|
|
||||||
}
|
|
||||||
// Parse all formulas with the old name
|
// Parse all formulas with the old name
|
||||||
// All internal formulas are R1C1
|
// All internal formulas are R1C1
|
||||||
self.parser.set_lexer_mode(LexerMode::R1C1);
|
self.parser.set_lexer_mode(LexerMode::R1C1);
|
||||||
// We use iter because the default would be a mut_iter and we don't need a mutable reference
|
|
||||||
let worksheets = &mut self.workbook.worksheets;
|
for worksheet in &mut self.workbook.worksheets {
|
||||||
for worksheet in worksheets {
|
// R1C1 formulas are not tied to a cell (but are tied to a cell)
|
||||||
let cell_reference = &CellReferenceRC {
|
let cell_reference = &CellReferenceRC {
|
||||||
sheet: worksheet.get_name(),
|
sheet: worksheet.get_name(),
|
||||||
row: 1,
|
row: 1,
|
||||||
@@ -276,11 +275,32 @@ impl Model {
|
|||||||
}
|
}
|
||||||
worksheet.shared_formulas = formulas;
|
worksheet.shared_formulas = formulas;
|
||||||
}
|
}
|
||||||
// Se the mode back to A1
|
|
||||||
|
// Set the mode back to A1
|
||||||
self.parser.set_lexer_mode(LexerMode::A1);
|
self.parser.set_lexer_mode(LexerMode::A1);
|
||||||
|
|
||||||
|
// We reparse all the defined names formulas
|
||||||
|
let mut defined_names = Vec::new();
|
||||||
|
// Defined names do not have a context, we can use anything
|
||||||
|
let cell_reference = &CellReferenceRC {
|
||||||
|
sheet: old_name.clone(),
|
||||||
|
row: 1,
|
||||||
|
column: 1,
|
||||||
|
};
|
||||||
|
for defined_name in &mut self.workbook.defined_names {
|
||||||
|
let mut t = self.parser.parse(&defined_name.formula, cell_reference);
|
||||||
|
rename_sheet_in_node(&mut t, sheet_index, new_name);
|
||||||
|
let formula = to_string(&t, cell_reference);
|
||||||
|
defined_names.push(DefinedName {
|
||||||
|
name: defined_name.name.clone(),
|
||||||
|
formula,
|
||||||
|
sheet_id: defined_name.sheet_id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
self.workbook.defined_names = defined_names;
|
||||||
|
|
||||||
// Update the name of the worksheet
|
// Update the name of the worksheet
|
||||||
let worksheets = &mut self.workbook.worksheets;
|
self.workbook.worksheet_mut(sheet_index)?.set_name(new_name);
|
||||||
worksheets[sheet_index as usize].set_name(new_name);
|
|
||||||
self.reset_parsed_structures();
|
self.reset_parsed_structures();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -423,3 +423,30 @@ fn change_scope_to_first_sheet() {
|
|||||||
Ok("#NAME?".to_string())
|
Ok("#NAME?".to_string())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rename_sheet() {
|
||||||
|
let mut model = UserModel::new_empty("model", "en", "UTC").unwrap();
|
||||||
|
model.new_sheet().unwrap();
|
||||||
|
model.set_user_input(0, 1, 1, "Hello").unwrap();
|
||||||
|
|
||||||
|
model
|
||||||
|
.new_defined_name("myName", None, "Sheet1!$A$1")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
model
|
||||||
|
.set_user_input(0, 2, 1, r#"=CONCATENATE(MyName, " world!")"#)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
model.get_formatted_cell_value(0, 2, 1),
|
||||||
|
Ok("Hello world!".to_string())
|
||||||
|
);
|
||||||
|
|
||||||
|
model.rename_sheet(0, "AnotherName").unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
model.get_formatted_cell_value(0, 2, 1),
|
||||||
|
Ok("Hello world!".to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user