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:
AnotherTest 2020-12-22 12:52:59 +03:30 committed by Andreas Kling
parent bfb25855cb
commit 8f05e4e765
Notes: sideshowbarker 2024-07-19 00:40:14 +09:00
5 changed files with 35 additions and 6 deletions

View file

@ -84,8 +84,10 @@ struct Cell : public Weakable<Cell> {
const Position& position() const { return m_position; }
void set_position(Position position, Badge<Sheet>)
{
m_dirty = true;
m_position = move(position);
if (position != m_position) {
m_dirty = true;
m_position = move(position);
}
}
const Format& evaluated_formats() const { return m_evaluated_formats; }

View file

@ -154,12 +154,18 @@ String Sheet::add_column()
void Sheet::update()
{
if (m_should_ignore_updates) {
m_update_requested = true;
return;
}
m_visited_cells_in_update.clear();
Vector<Cell*> cells_copy;
// Grab a copy as updates might insert cells into the table.
for (auto& it : m_cells)
cells_copy.append(it.value);
for (auto& it : m_cells) {
if (it.value->dirty())
cells_copy.append(it.value);
}
for (auto& cell : cells_copy)
update(*cell);
@ -169,10 +175,15 @@ void Sheet::update()
void Sheet::update(Cell& cell)
{
if (m_should_ignore_updates) {
m_update_requested = true;
return;
}
if (cell.dirty()) {
if (has_been_visited(&cell)) {
// This may be part of an cyclic reference chain
// just break the chain, but leave the cell dirty.
// This may be part of an cyclic reference chain,
// so just ignore it.
cell.clear_dirty();
return;
}
m_visited_cells_in_update.set(&cell);

View file

@ -117,6 +117,15 @@ public:
void update();
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 {
JS::Value value;
@ -154,6 +163,8 @@ private:
Cell* m_current_cell_being_evaluated { nullptr };
HashTable<Cell*> m_visited_cells_in_update;
bool m_should_ignore_updates { false };
bool m_update_requested { false };
};
}

View file

@ -46,6 +46,7 @@ public:
virtual void update() override;
virtual bool is_column_sortable(int) const override { return false; }
virtual StringView drag_data_type() const override { return "text/x-spreadsheet-data"; }
Sheet& sheet() { return *m_sheet; }
private:
explicit SheetModel(Sheet& sheet)

View file

@ -86,6 +86,10 @@ void InfinitelyScrollableTableView::mousemove_event(GUI::MouseEvent& event)
if (!index.is_valid())
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 rect = content_rect(index);
auto distance = rect.center().absolute_relative_distance_to(event.position());