LibGUI: Add a way for models to update without invalidating indexes

This is really just a workaround to keep SystemMonitor's process table
working right wrt selection retention during resorts (while also doing
full index invalidation on things like ProfileViewer inversion.)

It's starting to feel like the model abstraction is not super great
and we'll need a better approach if we want to actually build some more
dynamic functionality into our views.
This commit is contained in:
Andreas Kling 2020-04-12 12:03:33 +02:00
parent 93f2a4edd3
commit 8e4751a963
17 changed files with 37 additions and 29 deletions

View file

@ -412,5 +412,5 @@ void ProcessModel::update()
if (on_new_cpu_data_point)
on_new_cpu_data_point(total_cpu_percent);
did_update();
did_update(GUI::Model::UpdateFlag::DontInvalidateIndexes);
}

View file

@ -146,5 +146,5 @@ GUI::Variant ProfileModel::data(const GUI::ModelIndex& index, Role role) const
void ProfileModel::update()
{
did_update();
did_update(Model::InvalidateAllIndexes);
}

View file

@ -566,9 +566,9 @@ Gfx::Point AbstractTableView::adjusted_position(const Gfx::Point& position) cons
return position.translated(horizontal_scrollbar().value() - frame_thickness(), vertical_scrollbar().value() - frame_thickness());
}
void AbstractTableView::did_update_model()
void AbstractTableView::did_update_model(unsigned flags)
{
AbstractView::did_update_model();
AbstractView::did_update_model(flags);
update_column_sizes();
update_content_size();
update();

View file

@ -75,7 +75,7 @@ protected:
virtual ~AbstractTableView() override;
AbstractTableView();
virtual void did_update_model() override;
virtual void did_update_model(unsigned flags) override;
virtual void mouseup_event(MouseEvent&) override;
virtual void mousedown_event(MouseEvent&) override;
virtual void mousemove_event(MouseEvent&) override;

View file

@ -55,19 +55,22 @@ void AbstractView::set_model(RefPtr<Model> model)
m_model = move(model);
if (m_model)
m_model->register_view({}, *this);
did_update_model();
did_update_model(GUI::Model::InvalidateAllIndexes);
}
void AbstractView::did_update_model()
void AbstractView::did_update_model(unsigned flags)
{
// FIXME: It's unfortunate that we lose so much view state when the model updates in any way.
stop_editing();
m_edit_index = {};
m_hovered_index = {};
if (model()) {
selection().remove_matching([this](auto& index) { return !model()->is_valid(index); });
} else {
dbg() << "did_update_model, flags=" << flags;
dump_backtrace();
if (!model() || (flags & GUI::Model::InvalidateAllIndexes)) {
selection().clear();
} else {
selection().remove_matching([this](auto& index) { return !model()->is_valid(index); });
}
}

View file

@ -49,7 +49,7 @@ public:
void set_editable(bool editable) { m_editable = editable; }
virtual bool accepts_focus() const override { return true; }
virtual void did_update_model();
virtual void did_update_model(unsigned flags);
virtual void did_update_selection();
virtual Gfx::Rect content_rect(const ModelIndex&) const { return {}; }

View file

@ -259,9 +259,9 @@ void ColumnsView::mousedown_event(MouseEvent& event)
}
}
void ColumnsView::did_update_model()
void ColumnsView::did_update_model(unsigned flags)
{
AbstractView::did_update_model();
AbstractView::did_update_model(flags);
// FIXME: Don't drop the columns on minor updates.
dbg() << "Model was updated; dropping columns :(";

View file

@ -50,7 +50,7 @@ private:
int icon_spacing() const { return 2; }
int text_padding() const { return 2; }
virtual void did_update_model() override;
virtual void did_update_model(unsigned flags) override;
virtual void paint_event(PaintEvent&) override;
virtual void mousedown_event(MouseEvent& event) override;
virtual void keydown_event(KeyEvent& event) override;

View file

@ -68,9 +68,9 @@ void ItemView::resize_event(ResizeEvent& event)
update_content_size();
}
void ItemView::did_update_model()
void ItemView::did_update_model(unsigned flags)
{
AbstractView::did_update_model();
AbstractView::did_update_model(flags);
update_content_size();
update();
}

View file

@ -52,7 +52,7 @@ public:
private:
ItemView();
virtual void did_update_model() override;
virtual void did_update_model(unsigned flags) override;
virtual void paint_event(PaintEvent&) override;
virtual void second_paint_event(PaintEvent&) override;
virtual void resize_event(ResizeEvent&) override;

View file

@ -75,9 +75,9 @@ void ListView::resize_event(ResizeEvent& event)
AbstractView::resize_event(event);
}
void ListView::did_update_model()
void ListView::did_update_model(unsigned flags)
{
AbstractView::did_update_model();
AbstractView::did_update_model(flags);
update_content_size();
update();
}

View file

@ -56,7 +56,7 @@ public:
private:
ListView();
virtual void did_update_model() override;
virtual void did_update_model(unsigned flags) override;
virtual void paint_event(PaintEvent&) override;
virtual void doubleclick_event(MouseEvent&) override;
virtual void keydown_event(KeyEvent&) override;

View file

@ -53,12 +53,12 @@ void Model::for_each_view(Function<void(AbstractView&)> callback)
callback(*view);
}
void Model::did_update()
void Model::did_update(unsigned flags)
{
if (on_update)
on_update();
for_each_view([](auto& view) {
view.did_update_model();
for_each_view([&](auto& view) {
view.did_update_model(flags);
});
}

View file

@ -57,6 +57,11 @@ public:
Sortable sortable { Sortable::True };
};
enum UpdateFlag {
DontInvalidateIndexes = 0,
InvalidateAllIndexes = 1 << 0,
};
enum class Role {
Display,
Sort,
@ -106,7 +111,7 @@ protected:
Model();
void for_each_view(Function<void(AbstractView&)>);
void did_update();
void did_update(unsigned flags = UpdateFlag::InvalidateAllIndexes);
ModelIndex create_index(int row, int column, const void* data = nullptr) const;

View file

@ -118,7 +118,7 @@ void SortingProxyModel::resort()
for (int i = 0; i < row_count; ++i)
m_row_mappings[i] = i;
if (m_key_column == -1) {
did_update();
did_update(Model::UpdateFlag::DontInvalidateIndexes);
return;
}
quick_sort(m_row_mappings, [&](auto row1, auto row2) -> bool {
@ -133,7 +133,7 @@ void SortingProxyModel::resort()
is_less_than = data1 < data2;
return m_sort_order == SortOrder::Ascending ? is_less_than : !is_less_than;
});
did_update();
did_update(Model::UpdateFlag::DontInvalidateIndexes);
for_each_view([&](AbstractView& view) {
auto& selection = view.selection();
Vector<ModelIndex> selected_indexes_in_target;

View file

@ -326,10 +326,10 @@ void TreeView::scroll_into_view(const ModelIndex& a_index, Orientation orientati
ScrollableWidget::scroll_into_view(found_rect, orientation);
}
void TreeView::did_update_model()
void TreeView::did_update_model(unsigned flags)
{
m_view_metadata.clear();
AbstractTableView::did_update_model();
AbstractTableView::did_update_model(flags);
}
void TreeView::did_update_selection()

View file

@ -48,7 +48,7 @@ protected:
virtual void doubleclick_event(MouseEvent&) override;
virtual void keydown_event(KeyEvent&) override;
virtual void did_update_selection() override;
virtual void did_update_model() override;
virtual void did_update_model(unsigned flags) override;
private:
virtual ModelIndex index_at_event_position(const Gfx::Point&, bool& is_toggle) const override;