use crate::{
ActionEffect, AppData, BasicError, BlockDataRow, BlockField, BlockId, BlockSortOrder,
CellCoordinateWithSheet, CellInfo, ColId, DisplayWindow, EditAction, Error, ErrorMessage,
FormulaDisplayInfo, PayloadsAction, PivotExcelNote, PivotPlan, PivotSpecParts, RowId, RowInfo,
SaveFileResult, ShadowCellInfo, SheetCellId, SheetId, SheetInfo, TempStatusDiff, Workbook,
lex_and_fmt, lex_success,
};
use super::{Manager, Transaction};
pub fn new_workbook(mgr: &mut Manager) -> usize {
mgr.new_workbook()
}
pub fn read_file(
mgr: &mut Manager,
id: usize,
name: String,
buf: &[u8],
) -> Result<(), ErrorMessage> {
let wb = Workbook::from_file(buf, name).map_err(ErrorMessage::from)?;
mgr.replace_workbook(id, wb);
Ok(())
}
pub fn save_file(
mgr: &mut Manager,
id: usize,
app_data: String,
resolve_block_refs: bool,
) -> Result<SaveFileResult, ErrorMessage> {
let ctrl = mgr.workbook_mut(id)?;
ctrl.set_app_data(vec![AppData {
name: "logisheets".to_string(),
data: app_data,
}]);
let format = if resolve_block_refs {
logisheets_controller::FormulaFormat::Coordinates
} else {
logisheets_controller::FormulaFormat::Named
};
let data = ctrl.save_with_format(format).map_err(ErrorMessage::from)?;
Ok(SaveFileResult { data })
}
pub fn get_app_data(mgr: &Manager, id: usize) -> Result<Vec<AppData>, ErrorMessage> {
Ok(mgr.workbook(id)?.get_app_data())
}
pub fn release(mgr: &mut Manager, id: usize) {
mgr.remove(id)
}
pub fn undo(mgr: &mut Manager, id: usize) -> Result<bool, ErrorMessage> {
Ok(mgr.workbook_mut(id)?.undo())
}
pub fn redo(mgr: &mut Manager, id: usize) -> Result<bool, ErrorMessage> {
Ok(mgr.workbook_mut(id)?.redo())
}
pub fn clean_history(mgr: &mut Manager, id: usize) -> Result<(), ErrorMessage> {
mgr.workbook_mut(id)?.clear_history();
Ok(())
}
pub fn commit_temp_status(mgr: &mut Manager, id: usize) -> Result<(), ErrorMessage> {
mgr.workbook_mut(id)?.commit_temp_status();
Ok(())
}
pub fn clean_temp_status(mgr: &mut Manager, id: usize) -> Result<(), ErrorMessage> {
mgr.workbook_mut(id)?.clean_temp_status();
Ok(())
}
pub fn is_in_temp_mode(mgr: &Manager, id: usize) -> Result<bool, ErrorMessage> {
Ok(mgr.workbook(id)?.is_in_temp_mode())
}
pub fn toggle_status(mgr: &mut Manager, id: usize, use_temp: bool) -> Result<(), ErrorMessage> {
mgr.workbook_mut(id)?.toggle_status(use_temp);
Ok(())
}
pub fn batch_get_cell_info_by_id(
mgr: &mut Manager,
id: usize,
ids: Vec<SheetCellId>,
) -> Result<Vec<CellInfo>, ErrorMessage> {
let wb = mgr.workbook_mut(id)?;
wb.batch_get_cell_info_by_id(ids)
.map_err(ErrorMessage::from)
}
pub fn batch_get_cell_coordinate_with_sheet_by_id(
mgr: &mut Manager,
id: usize,
ids: Vec<SheetCellId>,
) -> Result<Vec<CellCoordinateWithSheet>, ErrorMessage> {
let wb = mgr.workbook_mut(id)?;
wb.batch_get_cell_coordinate_with_sheet_by_id(ids)
.map_err(ErrorMessage::from)
}
pub fn get_sheet_name_by_idx(
mgr: &mut Manager,
id: usize,
idx: usize,
) -> Result<String, ErrorMessage> {
let wb = mgr.workbook_mut(id)?;
wb.get_sheet_name_by_idx(idx).map_err(ErrorMessage::from)
}
pub fn get_sheet_count(mgr: &Manager, id: usize) -> Result<usize, ErrorMessage> {
Ok(mgr.workbook(id)?.get_sheet_count())
}
pub fn get_version(mgr: &Manager, id: usize) -> Result<u32, ErrorMessage> {
Ok(mgr.workbook(id)?.get_version())
}
pub fn get_all_sheet_info(mgr: &Manager, id: usize) -> Result<Vec<SheetInfo>, ErrorMessage> {
Ok(mgr.workbook(id)?.get_all_sheet_info())
}
pub fn get_formula_function_names(mgr: &Manager, id: usize) -> Result<Vec<String>, ErrorMessage> {
Ok(mgr.workbook(id)?.get_formula_function_names())
}
pub fn get_row_info(
mgr: &Manager,
id: usize,
sheet_idx: usize,
row_idx: usize,
) -> Result<RowInfo, ErrorMessage> {
let wb = mgr.workbook(id)?;
let ws = wb.get_sheet_by_idx(sheet_idx).map_err(ErrorMessage::from)?;
Ok(ws
.get_row_info(row_idx)
.unwrap_or(RowInfo::default(row_idx)))
}
pub fn check_formula(mgr: &Manager, id: usize, f: String) -> Result<bool, ErrorMessage> {
Ok(mgr.workbook(id)?.check_formula(f))
}
pub fn calc_condition(
mgr: &mut Manager,
id: usize,
sheet_idx: usize,
f: String,
) -> Result<bool, ErrorMessage> {
let wb = mgr.workbook_mut(id)?;
wb.calc_condition(sheet_idx, f).map_err(ErrorMessage::from)
}
pub fn get_cell_id_by_block_ref(
mgr: &Manager,
id: usize,
ref_name: String,
key: String,
field: String,
) -> Result<SheetCellId, ErrorMessage> {
let wb = mgr.workbook(id)?;
wb.get_cell_id_by_block_ref(&ref_name, &key, &field)
.map_err(ErrorMessage::from)
}
pub fn export_block_data(
mgr: &Manager,
id: usize,
ref_name: String,
key_filter: Option<Vec<String>>,
field_filter: Option<Vec<String>>,
) -> Result<Vec<BlockDataRow>, ErrorMessage> {
let wb = mgr.workbook(id)?;
wb.export_block_data(&ref_name, key_filter, field_filter)
.map_err(ErrorMessage::from)
}
pub fn get_temp_status_changes(mgr: &Manager, id: usize) -> Result<TempStatusDiff, ErrorMessage> {
let wb = mgr.workbook(id)?;
wb.get_temp_status_changes().map_err(ErrorMessage::from)
}
pub fn check_bind_block(
mgr: &mut Manager,
id: usize,
sheet_idx: usize,
block_id: usize,
row_count: usize,
col_count: usize,
) -> Result<bool, ErrorMessage> {
Ok(mgr
.workbook_mut(id)?
.check_bind_block(sheet_idx, block_id, row_count, col_count)
.is_ok())
}
pub fn get_available_block_id(
mgr: &mut Manager,
id: usize,
sheet_idx: usize,
) -> Result<BlockId, ErrorMessage> {
let wb = mgr.workbook_mut(id)?;
wb.get_available_block_id(sheet_idx)
.map_err(ErrorMessage::from)
}
pub fn get_sheet_id(
mgr: &mut Manager,
id: usize,
sheet_idx: usize,
) -> Result<SheetId, ErrorMessage> {
let wb = mgr.workbook_mut(id)?;
wb.get_worksheet_id(sheet_idx).map_err(ErrorMessage::from)
}
pub fn get_sheet_idx(mgr: &Manager, id: usize, sheet_id: SheetId) -> Result<usize, ErrorMessage> {
let wb = mgr.workbook(id)?;
wb.get_sheet_idx_by_id(sheet_id).map_err(ErrorMessage::from)
}
pub fn get_block_values(
mgr: &Manager,
id: usize,
sheet_id: SheetId,
block_id: BlockId,
row_ids: Vec<RowId>,
col_ids: Vec<ColId>,
) -> Result<Vec<String>, ErrorMessage> {
let wb = mgr.workbook(id)?;
wb.get_block_values(sheet_id, block_id, &row_ids, &col_ids)
.map_err(ErrorMessage::from)
}
pub fn get_block_sort_order(
mgr: &Manager,
id: usize,
sheet_idx: usize,
block_id: BlockId,
field: String,
asc: bool,
) -> Result<BlockSortOrder, ErrorMessage> {
let wb = mgr.workbook(id)?;
wb.get_block_sort_order(sheet_idx, block_id, &field, asc)
.map_err(ErrorMessage::from)
}
pub fn pivot_plan(
mgr: &Manager,
id: usize,
sheet_idx: usize,
block_id: BlockId,
) -> Result<PivotPlan, ErrorMessage> {
let wb = mgr.workbook(id)?;
wb.pivot_plan(sheet_idx, block_id)
.map_err(ErrorMessage::from)
}
pub fn pivot_excel_note(
mgr: &Manager,
id: usize,
sheet_idx: usize,
block_id: BlockId,
) -> Result<PivotExcelNote, ErrorMessage> {
let wb = mgr.workbook(id)?;
wb.pivot_excel_note(sheet_idx, block_id)
.map_err(ErrorMessage::from)
}
pub fn pivot_plan_for(
mgr: &Manager,
id: usize,
sheet_idx: usize,
source_block: BlockId,
spec: PivotSpecParts,
) -> Result<PivotPlan, ErrorMessage> {
let wb = mgr.workbook(id)?;
wb.pivot_plan_for(sheet_idx, source_block, &spec)
.map_err(ErrorMessage::from)
}
pub fn may_modify_block(
mgr: &Manager,
id: usize,
sheet_idx: usize,
block_id: BlockId,
op: crate::BlockOp,
actor: crate::BlockActor,
) -> Result<bool, ErrorMessage> {
let wb = mgr.workbook(id)?;
wb.may_modify_block(sheet_idx, block_id, op, &actor)
.map_err(ErrorMessage::from)
}
pub fn check_field_validation(
mgr: &mut Manager,
id: usize,
sheet_idx: usize,
row: usize,
col: usize,
proposed: String,
) -> Result<logisheets_controller::FieldValidationVerdict, ErrorMessage> {
let wb = mgr.workbook_mut(id)?;
wb.check_field_validation(sheet_idx, row, col, proposed)
.map_err(ErrorMessage::from)
}
pub fn get_block_modify_info(
mgr: &Manager,
id: usize,
sheet_idx: usize,
block_id: BlockId,
) -> Result<crate::BlockModifyInfo, ErrorMessage> {
let wb = mgr.workbook(id)?;
wb.get_block_modify_info(sheet_idx, block_id)
.map_err(ErrorMessage::from)
}
pub fn get_block_row_id(
mgr: &mut Manager,
id: usize,
sheet_id: SheetId,
block_id: BlockId,
row_idx: usize,
) -> Result<RowId, ErrorMessage> {
let wb = mgr.workbook_mut(id)?;
let ws = wb.get_sheet_by_id(sheet_id).map_err(ErrorMessage::from)?;
ws.get_block_row_id(block_id, row_idx)
.map_err(ErrorMessage::from)
}
pub fn get_block_col_id(
mgr: &mut Manager,
id: usize,
sheet_id: SheetId,
block_id: BlockId,
col_idx: usize,
) -> Result<ColId, ErrorMessage> {
let wb = mgr.workbook_mut(id)?;
let ws = wb.get_sheet_by_id(sheet_id).map_err(ErrorMessage::from)?;
ws.get_block_col_id(block_id, col_idx)
.map_err(ErrorMessage::from)
}
pub fn get_display_window_for_block(
mgr: &mut Manager,
id: usize,
sheet_id: SheetId,
block_id: BlockId,
) -> Result<DisplayWindow, ErrorMessage> {
let wb = mgr.workbook_mut(id)?;
let ws = wb.get_sheet_by_id(sheet_id).map_err(ErrorMessage::from)?;
ws.get_display_window_for_block(block_id)
.map_err(ErrorMessage::from)
}
pub fn get_shadow_cell_id(
mgr: &mut Manager,
id: usize,
sheet_idx: usize,
row_idx: usize,
col_idx: usize,
kind: crate::ShadowKind,
) -> Result<SheetCellId, ErrorMessage> {
let wb = mgr.workbook_mut(id)?;
wb.get_shadow_cell_id(sheet_idx, row_idx, col_idx, kind)
.map_err(ErrorMessage::from)
}
pub fn get_shadow_cell_ids(
mgr: &mut Manager,
id: usize,
sheet_idx: usize,
row_idx: Vec<usize>,
col_idx: Vec<usize>,
kind: crate::ShadowKind,
) -> Result<Vec<SheetCellId>, ErrorMessage> {
let wb = mgr.workbook_mut(id)?;
wb.get_shawdow_cell_ids(sheet_idx, row_idx, col_idx, kind)
.map_err(ErrorMessage::from)
}
pub fn get_shadow_info_by_id(
mgr: &mut Manager,
id: usize,
shadow_id: u64,
) -> Result<ShadowCellInfo, ErrorMessage> {
let wb = mgr.workbook_mut(id)?;
wb.get_shadow_info_by_id(shadow_id)
.map_err(ErrorMessage::from)
}
pub fn get_cell_id(
mgr: &mut Manager,
id: usize,
sheet_idx: usize,
row_idx: usize,
col_idx: usize,
) -> Result<SheetCellId, ErrorMessage> {
let wb = mgr.workbook_mut(id)?;
let sheet_id = wb.get_worksheet_id(sheet_idx).map_err(ErrorMessage::from)?;
let ws = wb.get_sheet_by_id(sheet_id).map_err(ErrorMessage::from)?;
let cell_id = ws
.get_cell_id(row_idx, col_idx)
.map_err(ErrorMessage::from)?;
Ok(SheetCellId { sheet_id, cell_id })
}
pub fn get_all_block_fields(mgr: &mut Manager, id: usize) -> Result<Vec<BlockField>, ErrorMessage> {
let wb = mgr.workbook_mut(id)?;
wb.get_all_block_fields().map_err(ErrorMessage::from)
}
pub fn get_block_op_for_payloads(
mgr: &Manager,
id: usize,
) -> Result<Vec<crate::BlockOpForPayload>, ErrorMessage> {
let wb = mgr.workbook(id)?;
Ok(wb.get_block_op_for_payloads())
}
pub fn get_block_op_policies(
mgr: &Manager,
id: usize,
sheet_idx: usize,
block_id: BlockId,
) -> Result<Vec<crate::BlockOpPolicy>, ErrorMessage> {
let wb = mgr.workbook(id)?;
wb.get_block_op_policies(sheet_idx, block_id)
.map_err(ErrorMessage::from)
}
pub fn get_enum_sets(mgr: &Manager, id: usize) -> Result<Vec<crate::EnumSetInfo>, ErrorMessage> {
let wb = mgr.workbook(id)?;
Ok(wb.get_enum_sets())
}
pub fn get_defined_names(
mgr: &Manager,
id: usize,
) -> Result<Vec<crate::DefinedNameInfo>, ErrorMessage> {
let wb = mgr.workbook(id)?;
Ok(wb.get_defined_names())
}
pub fn duplicate_block_keys(
mgr: &Manager,
id: usize,
) -> Result<Vec<crate::DuplicateBlockKey>, ErrorMessage> {
let wb = mgr.workbook(id)?;
Ok(wb.duplicate_block_keys())
}
pub fn handle_transaction(
mgr: &mut Manager,
id: usize,
transaction: Transaction,
) -> Result<ActionEffect, ErrorMessage> {
let payloads_action = PayloadsAction {
payloads: transaction.payloads,
undoable: transaction.undoable,
init: false,
};
let wb = mgr.workbook_mut(id)?;
Ok(if transaction.temp {
wb.handle_action_in_temp_status(payloads_action)
} else {
wb.handle_action(EditAction::Payloads(payloads_action))
})
}
pub fn formula_check(f: &str) -> bool {
f.trim().strip_prefix('=').is_some_and(lex_success)
}
pub fn get_display_units_of_formula(f: &str) -> Result<FormulaDisplayInfo, ErrorMessage> {
lex_and_fmt(f)
.ok_or_else(|| ErrorMessage::from(Error::from(BasicError::InvalidFormula(f.to_string()))))
}