mirror of
https://github.com/RGBCube/serenity
synced 2025-05-30 22:08:12 +00:00
Spreadsheet: Improve sheet update efficiency
There's no need to leave the cell dirty when not updating it, and there's definitely no need to update the cells as we're selecting them. This makes navigating a sheet and selecting cells significantly faster as we no longer update unrelated cells just because they appear to have a cyclic update dependency :^)
This commit is contained in:
parent
bfb25855cb
commit
8f05e4e765
5 changed files with 35 additions and 6 deletions
|
@ -84,8 +84,10 @@ struct Cell : public Weakable<Cell> {
|
||||||
const Position& position() const { return m_position; }
|
const Position& position() const { return m_position; }
|
||||||
void set_position(Position position, Badge<Sheet>)
|
void set_position(Position position, Badge<Sheet>)
|
||||||
{
|
{
|
||||||
m_dirty = true;
|
if (position != m_position) {
|
||||||
m_position = move(position);
|
m_dirty = true;
|
||||||
|
m_position = move(position);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Format& evaluated_formats() const { return m_evaluated_formats; }
|
const Format& evaluated_formats() const { return m_evaluated_formats; }
|
||||||
|
|
|
@ -154,12 +154,18 @@ String Sheet::add_column()
|
||||||
|
|
||||||
void Sheet::update()
|
void Sheet::update()
|
||||||
{
|
{
|
||||||
|
if (m_should_ignore_updates) {
|
||||||
|
m_update_requested = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_visited_cells_in_update.clear();
|
m_visited_cells_in_update.clear();
|
||||||
Vector<Cell*> cells_copy;
|
Vector<Cell*> cells_copy;
|
||||||
|
|
||||||
// Grab a copy as updates might insert cells into the table.
|
// Grab a copy as updates might insert cells into the table.
|
||||||
for (auto& it : m_cells)
|
for (auto& it : m_cells) {
|
||||||
cells_copy.append(it.value);
|
if (it.value->dirty())
|
||||||
|
cells_copy.append(it.value);
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& cell : cells_copy)
|
for (auto& cell : cells_copy)
|
||||||
update(*cell);
|
update(*cell);
|
||||||
|
@ -169,10 +175,15 @@ void Sheet::update()
|
||||||
|
|
||||||
void Sheet::update(Cell& cell)
|
void Sheet::update(Cell& cell)
|
||||||
{
|
{
|
||||||
|
if (m_should_ignore_updates) {
|
||||||
|
m_update_requested = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (cell.dirty()) {
|
if (cell.dirty()) {
|
||||||
if (has_been_visited(&cell)) {
|
if (has_been_visited(&cell)) {
|
||||||
// This may be part of an cyclic reference chain
|
// This may be part of an cyclic reference chain,
|
||||||
// just break the chain, but leave the cell dirty.
|
// so just ignore it.
|
||||||
|
cell.clear_dirty();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_visited_cells_in_update.set(&cell);
|
m_visited_cells_in_update.set(&cell);
|
||||||
|
|
|
@ -117,6 +117,15 @@ public:
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
void update(Cell&);
|
void update(Cell&);
|
||||||
|
void disable_updates() { m_should_ignore_updates = true; }
|
||||||
|
void enable_updates()
|
||||||
|
{
|
||||||
|
m_should_ignore_updates = false;
|
||||||
|
if (m_update_requested) {
|
||||||
|
m_update_requested = false;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct ValueAndException {
|
struct ValueAndException {
|
||||||
JS::Value value;
|
JS::Value value;
|
||||||
|
@ -154,6 +163,8 @@ private:
|
||||||
Cell* m_current_cell_being_evaluated { nullptr };
|
Cell* m_current_cell_being_evaluated { nullptr };
|
||||||
|
|
||||||
HashTable<Cell*> m_visited_cells_in_update;
|
HashTable<Cell*> m_visited_cells_in_update;
|
||||||
|
bool m_should_ignore_updates { false };
|
||||||
|
bool m_update_requested { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ public:
|
||||||
virtual void update() override;
|
virtual void update() override;
|
||||||
virtual bool is_column_sortable(int) const override { return false; }
|
virtual bool is_column_sortable(int) const override { return false; }
|
||||||
virtual StringView drag_data_type() const override { return "text/x-spreadsheet-data"; }
|
virtual StringView drag_data_type() const override { return "text/x-spreadsheet-data"; }
|
||||||
|
Sheet& sheet() { return *m_sheet; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit SheetModel(Sheet& sheet)
|
explicit SheetModel(Sheet& sheet)
|
||||||
|
|
|
@ -86,6 +86,10 @@ void InfinitelyScrollableTableView::mousemove_event(GUI::MouseEvent& event)
|
||||||
if (!index.is_valid())
|
if (!index.is_valid())
|
||||||
return TableView::mousemove_event(event);
|
return TableView::mousemove_event(event);
|
||||||
|
|
||||||
|
auto& sheet = static_cast<SheetModel&>(*model).sheet();
|
||||||
|
sheet.disable_updates();
|
||||||
|
ScopeGuard sheet_update_enabler { [&] { sheet.enable_updates(); } };
|
||||||
|
|
||||||
auto holding_left_button = !!(event.buttons() & GUI::MouseButton::Left);
|
auto holding_left_button = !!(event.buttons() & GUI::MouseButton::Left);
|
||||||
auto rect = content_rect(index);
|
auto rect = content_rect(index);
|
||||||
auto distance = rect.center().absolute_relative_distance_to(event.position());
|
auto distance = rect.center().absolute_relative_distance_to(event.position());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue