Skip to content

Commit

Permalink
Merge pull request #265 from logisky/jh/merge
Browse files Browse the repository at this point in the history
Support merge cells and split merged cells
  • Loading branch information
ImJeremyHe authored Jan 26, 2025
2 parents 6e0ea1f + e6d5900 commit dd3a023
Show file tree
Hide file tree
Showing 37 changed files with 831 additions and 92 deletions.
73 changes: 62 additions & 11 deletions crates/controller/src/api/worksheet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,11 +201,11 @@ impl<'a> Worksheet<'a> {
cells.push(info);
}
}
self.get_merge_cells().into_iter().for_each(|m| {
if m.row_start >= start_row
&& m.row_end <= end_row
&& m.col_start >= start_col
&& m.col_end <= end_col
self.get_all_merged_cells().into_iter().for_each(|m| {
if m.start_row >= start_row
&& m.end_row <= end_row
&& m.start_col >= start_col
&& m.end_col <= end_col
{
merge_cells.push(m);
}
Expand Down Expand Up @@ -326,7 +326,7 @@ impl<'a> Worksheet<'a> {
self.get_style_by_id(cell_id)
}

pub fn get_merge_cells(&self) -> Vec<MergeCell> {
pub fn get_all_merged_cells(&self) -> Vec<MergeCell> {
let merges = self
.controller
.status
Expand All @@ -350,12 +350,12 @@ impl<'a> Worksheet<'a> {
.navigator
.fetch_normal_cell_idx(&self.sheet_id, end);
match (s, e) {
(Ok((row_start, col_start)), Ok((row_end, col_end))) => {
(Ok((start_row, start_col)), Ok((end_row, end_col))) => {
let m = MergeCell {
row_start,
col_start,
row_end,
col_end,
start_row,
start_col,
end_row,
end_col,
};
prev.push(m);
prev
Expand All @@ -368,6 +368,57 @@ impl<'a> Worksheet<'a> {
}
}

pub fn get_merged_cells(
&self,
t_start_row: usize,
t_start_col: usize,
t_end_row: usize,
t_end_col: usize,
) -> Vec<MergeCell> {
let merged_cells = self
.controller
.status
.cell_attachment_manager
.merge_cells
.get_all_merged_cells(&self.sheet_id);
let result = merged_cells
.into_iter()
.flat_map(|(s, e)| {
let s = self
.controller
.status
.navigator
.fetch_normal_cell_idx(&self.sheet_id, &s);
if s.is_err() {
return None;
}
let (start_row, start_col) = s.unwrap();
let e = self
.controller
.status
.navigator
.fetch_normal_cell_idx(&self.sheet_id, &e);
if e.is_err() {
return None;
}
let (end_row, end_col) = e.unwrap();
if start_col > t_end_col || start_row > t_end_row {
return None;
}
if end_col < t_start_col || end_row < t_start_row {
return None;
}
return Some(MergeCell {
start_row,
start_col,
end_row,
end_col,
});
})
.collect::<Vec<_>>();
return result;
}

pub fn get_comments(&self) -> Vec<Comment> {
let comments = self
.controller
Expand Down
3 changes: 3 additions & 0 deletions crates/controller/src/cell_attachments/ctx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
use logisheets_base::id_fetcher::{IdFetcherTrait, SheetIdFetcherByIdxTrait};

pub trait CellAttachmentsExecCtx: IdFetcherTrait + SheetIdFetcherByIdxTrait {}
62 changes: 62 additions & 0 deletions crates/controller/src/cell_attachments/executor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use logisheets_base::errors::BasicError;

use crate::{edit_action::EditPayload, Error};

use super::{ctx::CellAttachmentsExecCtx, CellAttachmentsManager};

pub struct CellAttachmentsExecutor {
pub manager: CellAttachmentsManager,
}

impl CellAttachmentsExecutor {
pub fn new(manager: CellAttachmentsManager) -> Self {
Self { manager }
}

pub fn execute<C: CellAttachmentsExecCtx>(
mut self,
ctx: &mut C,
payload: EditPayload,
) -> Result<(Self, bool), Error> {
match payload {
EditPayload::MergeCells(merge_cells) => {
let sheet_id = ctx
.fetch_sheet_id_by_index(merge_cells.sheet_idx)
.map_err(|l| BasicError::SheetIdxExceed(l))?;
let start_cell_id = ctx.fetch_norm_cell_id(
&sheet_id,
merge_cells.start_row,
merge_cells.start_col,
)?;
let end_cell_id =
ctx.fetch_norm_cell_id(&sheet_id, merge_cells.end_row, merge_cells.end_col)?;
self.manager
.merge_cells
.add_merge_cell(sheet_id, start_cell_id, end_cell_id);
Ok((self, true))
}
EditPayload::SplitMergedCells(p) => {
let sheet_id = ctx
.fetch_sheet_id_by_index(p.sheet_idx)
.map_err(|l| BasicError::SheetIdxExceed(l))?;
let cell_id = ctx.fetch_norm_cell_id(&sheet_id, p.row, p.col)?;

if self
.manager
.merge_cells
.get_merge_cell(&sheet_id, &cell_id)
.is_some()
{
self.manager.merge_cells = self
.manager
.merge_cells
.remove_merge_cell(sheet_id, cell_id);
Ok((self, true))
} else {
Ok((self, false))
}
}
_ => Ok((self, false)),
}
}
}
14 changes: 14 additions & 0 deletions crates/controller/src/cell_attachments/merge_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,18 @@ impl MergeCells {
let end_cell = self.data.get(sheet_id)?.get(start_cell)?;
Some((start_cell.clone(), end_cell.clone()))
}

pub fn get_all_merged_cells(&self, sheet_id: &SheetId) -> Vec<(NormalCellId, NormalCellId)> {
let sheet_data = self.data.get(sheet_id);
if sheet_data.is_none() {
return vec![];
}

let sheet_data = sheet_data.unwrap();
let result = sheet_data
.iter()
.map(|(s, e)| (s.clone(), e.clone()))
.collect::<Vec<_>>();
result
}
}
2 changes: 2 additions & 0 deletions crates/controller/src/cell_attachments/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pub mod comment;
pub mod ctx;
pub mod executor;
pub mod merge_cell;

use comment::Comments;
Expand Down
1 change: 1 addition & 0 deletions crates/controller/src/connectors/calc_connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use crate::{

use crate::errors::Result;

#[allow(unused)]
pub struct CalcConnector<'a> {
pub range_manager: &'a RangeManager,
pub cube_manager: &'a CubeManager,
Expand Down
98 changes: 98 additions & 0 deletions crates/controller/src/connectors/cell_attachments_connector.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use logisheets_base::{
errors::BasicError,
id_fetcher::{IdFetcherTrait, SheetIdFetcherByIdxTrait},
BlockId, CellId, ColId, ExtBookId, RowId, SheetId,
};

use crate::{
cell_attachments::ctx::CellAttachmentsExecCtx,
ext_book_manager::ExtBooksManager,
id_manager::{FuncIdManager, NameIdManager, SheetIdManager, TextIdManager},
navigator::Navigator,
workbook::sheet_pos_manager::SheetPosManager,
};

pub struct CellAttachmentsConnector<'a> {
pub sheet_pos_manager: &'a SheetPosManager,
pub navigator: &'a Navigator,
pub sheet_id_manager: &'a mut SheetIdManager,
pub name_id_manager: &'a mut NameIdManager,
pub external_links_manager: &'a mut ExtBooksManager,
pub func_id_manager: &'a mut FuncIdManager,
pub text_id_manager: &'a mut TextIdManager,
}

impl<'a> SheetIdFetcherByIdxTrait for CellAttachmentsConnector<'a> {
fn fetch_sheet_id_by_index(&self, idx: usize) -> Result<SheetId, usize> {
self.sheet_pos_manager
.get_sheet_id(idx)
.ok_or(self.sheet_pos_manager.pos.len())
}
}

impl<'a> IdFetcherTrait for CellAttachmentsConnector<'a> {
fn fetch_row_id(&self, sheet_id: &SheetId, row_idx: usize) -> Result<RowId, BasicError> {
self.navigator.fetch_row_id(sheet_id, row_idx)
}

fn fetch_col_id(&self, sheet_id: &SheetId, col_idx: usize) -> Result<ColId, BasicError> {
self.navigator.fetch_col_id(sheet_id, col_idx)
}

fn fetch_cell_id(
&self,
sheet_id: &SheetId,
row_idx: usize,
col_idx: usize,
) -> Result<CellId, BasicError> {
self.navigator.fetch_cell_id(sheet_id, row_idx, col_idx)
}

fn fetch_sheet_id(&mut self, sheet_name: &str) -> SheetId {
self.sheet_id_manager.get_or_register_id(sheet_name)
}

fn fetch_name_id(&mut self, workbook: &Option<&str>, name: &str) -> logisheets_base::NameId {
let book_id = match workbook {
Some(book) => self.fetch_ext_book_id(book),
None => 0 as ExtBookId,
};
self.name_id_manager.get_id(&(book_id, name.to_owned()))
}

fn fetch_ext_book_id(&mut self, book: &str) -> logisheets_base::ExtBookId {
self.external_links_manager.fetch_ext_book_id(book)
}

fn fetch_text_id(&mut self, text: &str) -> logisheets_base::TextId {
self.text_id_manager.get_or_register_id(text)
}

fn fetch_func_id(&mut self, func_name: &str) -> logisheets_base::FuncId {
self.func_id_manager.get_func_id(func_name)
}

fn fetch_norm_cell_id(
&self,
sheet_id: &SheetId,
row_idx: usize,
col_idx: usize,
) -> Result<logisheets_base::NormalCellId, BasicError> {
self.navigator
.fetch_norm_cell_id(sheet_id, row_idx, col_idx)
}

fn fetch_block_cell_id(
&self,
sheet_id: &SheetId,
block_id: &BlockId,
row: usize,
col: usize,
) -> std::prelude::v1::Result<logisheets_base::BlockCellId, logisheets_base::errors::BasicError>
{
self.navigator
.fetch_block_cell_id(sheet_id, block_id, row, col)
}
}

impl<'a> CellAttachmentsExecCtx for CellAttachmentsConnector<'a> {}
2 changes: 2 additions & 0 deletions crates/controller/src/connectors/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod calc_connector;
mod cell_attachments_connector;
mod container_connector;
mod cube_connector;
mod formula_connector;
Expand All @@ -10,6 +11,7 @@ mod range_connector;
mod sheet_pos_connector;

pub use calc_connector::CalcConnector;
pub use cell_attachments_connector::CellAttachmentsConnector;
pub use container_connector::ContainerConnector;
pub use cube_connector::CubeConnector;
pub use formula_connector::FormulaConnector;
Expand Down
8 changes: 4 additions & 4 deletions crates/controller/src/controller/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,10 @@ pub struct SheetComments {
gents_derives::gents_header(file_name = "merge_cell.ts")
)]
pub struct MergeCell {
pub row_start: usize,
pub col_start: usize,
pub row_end: usize,
pub col_end: usize,
pub start_row: usize,
pub start_col: usize,
pub end_row: usize,
pub end_col: usize,
}

#[derive(Debug, Clone)]
Expand Down
30 changes: 26 additions & 4 deletions crates/controller/src/controller/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ use logisheets_base::{errors::BasicError, Addr, CellId, CubeId, RangeId, SheetId
use crate::{
async_func_manager::AsyncFuncManager,
calc_engine::CalcEngine,
cell_attachments::executor::CellAttachmentsExecutor,
connectors::{
CalcConnector, ContainerConnector, CubeConnector, FormulaConnector, NavigatorConnector,
RangeConnector, SheetPosConnector,
CalcConnector, CellAttachmentsConnector, ContainerConnector, CubeConnector,
FormulaConnector, NavigatorConnector, RangeConnector, SheetPosConnector,
},
container::ContainerExecutor,
cube_manager::executors::CubeExecutor,
Expand Down Expand Up @@ -100,9 +101,13 @@ impl<'a> Executor<'a> {
let range_executor = result.execute_range(payload.clone())?;
let cube_executor = result.execute_cube(payload.clone())?;

let (container_executor, updated) = result.execute_container(payload.clone())?;
let (container_executor, cell_attatchment_updated) =
result.execute_container(payload.clone())?;
result.status.container = container_executor.container;

let (cell_attachments, updated) = result.execute_cell_attachments(payload.clone())?;
result.status.cell_attachment_manager = cell_attachments.manager;

let mut dirty_ranges = range_executor.dirty_ranges;
range_executor.removed_ranges.into_iter().for_each(|e| {
dirty_ranges.insert(e);
Expand All @@ -119,7 +124,7 @@ impl<'a> Executor<'a> {
let formula_executor =
result.execute_formula(payload, &old_navigator, dirty_ranges, dirty_cubes)?;

let cell_updated = if updated || nav_updated {
let cell_updated = if updated || nav_updated || cell_attatchment_updated {
true
} else {
result.updated_cells.len() > 0
Expand Down Expand Up @@ -225,6 +230,23 @@ impl<'a> Executor<'a> {
executor.execute(&ctx, payload)
}

fn execute_cell_attachments(
&mut self,
payload: EditPayload,
) -> Result<(CellAttachmentsExecutor, bool), Error> {
let mut ctx = CellAttachmentsConnector {
sheet_pos_manager: &self.status.sheet_pos_manager,
navigator: &self.status.navigator,
sheet_id_manager: &mut self.status.sheet_id_manager,
name_id_manager: &mut self.status.name_id_manager,
external_links_manager: &mut self.status.external_links_manager,
func_id_manager: &mut self.status.func_id_manager,
text_id_manager: &mut self.status.text_id_manager,
};
let executor = CellAttachmentsExecutor::new(self.status.cell_attachment_manager.clone());
executor.execute(&mut ctx, payload)
}

fn execute_container(
&mut self,
payload: EditPayload,
Expand Down
Loading

0 comments on commit dd3a023

Please sign in to comment.