use std::sync::Arc;
use parking_lot::Mutex;
use frontend::commands::{block_commands, frame_commands, table_cell_commands, table_commands};
use frontend::common::types::EntityId;
use crate::convert::to_usize;
use crate::flow::{BlockSnapshot, CellFormat, TableFormat, TableSnapshot};
use crate::inner::TextDocumentInner;
use crate::text_block::TextBlock;
use crate::text_frame::{cell_dto_to_format, table_dto_to_format};
#[derive(Clone)]
pub struct TextTable {
pub(crate) doc: Arc<Mutex<TextDocumentInner>>,
pub(crate) table_id: usize,
}
impl TextTable {
pub fn id(&self) -> usize {
self.table_id
}
pub fn rows(&self) -> usize {
let inner = self.doc.lock();
table_commands::get_table(&inner.ctx, &(self.table_id as u64))
.ok()
.flatten()
.map(|t| to_usize(t.rows))
.unwrap_or(0)
}
pub fn columns(&self) -> usize {
let inner = self.doc.lock();
table_commands::get_table(&inner.ctx, &(self.table_id as u64))
.ok()
.flatten()
.map(|t| to_usize(t.columns))
.unwrap_or(0)
}
pub fn cell(&self, row: usize, col: usize) -> Option<TextTableCell> {
let inner = self.doc.lock();
let table_dto = table_commands::get_table(&inner.ctx, &(self.table_id as u64))
.ok()
.flatten()?;
for &cell_id in &table_dto.cells {
if let Some(cell_dto) = table_cell_commands::get_table_cell(&inner.ctx, &{ cell_id })
.ok()
.flatten()
&& cell_dto.row as usize == row
&& cell_dto.column as usize == col
{
return Some(TextTableCell {
doc: Arc::clone(&self.doc),
cell_id: cell_dto.id as usize,
});
}
}
None
}
pub fn column_widths(&self) -> Vec<i32> {
let inner = self.doc.lock();
table_commands::get_table(&inner.ctx, &(self.table_id as u64))
.ok()
.flatten()
.map(|t| t.column_widths.iter().map(|&v| v as i32).collect())
.unwrap_or_default()
}
pub fn format(&self) -> TableFormat {
let inner = self.doc.lock();
table_commands::get_table(&inner.ctx, &(self.table_id as u64))
.ok()
.flatten()
.map(|t| table_dto_to_format(&t))
.unwrap_or_default()
}
pub fn snapshot(&self) -> TableSnapshot {
let inner = self.doc.lock();
crate::text_frame::build_table_snapshot(&inner, self.table_id as u64).unwrap_or_else(|| {
TableSnapshot {
table_id: self.table_id,
rows: 0,
columns: 0,
column_widths: Vec::new(),
format: TableFormat::default(),
cells: Vec::new(),
}
})
}
}
#[derive(Clone)]
pub struct TextTableCell {
pub(crate) doc: Arc<Mutex<TextDocumentInner>>,
pub(crate) cell_id: usize,
}
impl TextTableCell {
pub fn id(&self) -> usize {
self.cell_id
}
pub fn row(&self) -> usize {
let inner = self.doc.lock();
table_cell_commands::get_table_cell(&inner.ctx, &(self.cell_id as u64))
.ok()
.flatten()
.map(|c| to_usize(c.row))
.unwrap_or(0)
}
pub fn column(&self) -> usize {
let inner = self.doc.lock();
table_cell_commands::get_table_cell(&inner.ctx, &(self.cell_id as u64))
.ok()
.flatten()
.map(|c| to_usize(c.column))
.unwrap_or(0)
}
pub fn row_span(&self) -> usize {
let inner = self.doc.lock();
table_cell_commands::get_table_cell(&inner.ctx, &(self.cell_id as u64))
.ok()
.flatten()
.map(|c| to_usize(c.row_span))
.unwrap_or(1)
}
pub fn column_span(&self) -> usize {
let inner = self.doc.lock();
table_cell_commands::get_table_cell(&inner.ctx, &(self.cell_id as u64))
.ok()
.flatten()
.map(|c| to_usize(c.column_span))
.unwrap_or(1)
}
pub fn format(&self) -> CellFormat {
let inner = self.doc.lock();
table_cell_commands::get_table_cell(&inner.ctx, &(self.cell_id as u64))
.ok()
.flatten()
.map(|c| cell_dto_to_format(&c))
.unwrap_or_default()
}
pub fn blocks(&self) -> Vec<TextBlock> {
let inner = self.doc.lock();
let cell_dto = match table_cell_commands::get_table_cell(&inner.ctx, &(self.cell_id as u64))
.ok()
.flatten()
{
Some(c) => c,
None => return Vec::new(),
};
let cell_frame_id = match cell_dto.cell_frame {
Some(id) => id,
None => return Vec::new(),
};
let frame_dto = match frame_commands::get_frame(&inner.ctx, &(cell_frame_id as EntityId))
.ok()
.flatten()
{
Some(f) => f,
None => return Vec::new(),
};
let mut block_dtos: Vec<_> = frame_dto
.blocks
.iter()
.filter_map(|&id| {
block_commands::get_block(&inner.ctx, &{ id })
.ok()
.flatten()
})
.collect();
block_dtos.sort_by_key(|b| b.document_position);
block_dtos
.iter()
.map(|b| TextBlock {
doc: Arc::clone(&self.doc),
block_id: b.id as usize,
})
.collect()
}
pub fn snapshot_blocks(&self) -> Vec<BlockSnapshot> {
let inner = self.doc.lock();
let cell_dto = match table_cell_commands::get_table_cell(&inner.ctx, &(self.cell_id as u64))
.ok()
.flatten()
{
Some(c) => c,
None => return Vec::new(),
};
match cell_dto.cell_frame {
Some(frame_id) => crate::text_block::build_blocks_snapshot_for_frame(&inner, frame_id),
None => Vec::new(),
}
}
}