Spreadsheet: Implement infinite-scroll for rows
Every time the scrollbar reaches the end, we append 100 more rows (seamlessly!). As a result of defaulting to 100 rows, we can also save with the smallest number of rows required. This partially deals with #4170.
This commit is contained in:
parent
71de8b7480
commit
f6ae4edbd2
Notes:
sideshowbarker
2024-07-19 01:09:38 +09:00
Author: https://github.com/alimpfard Commit: https://github.com/SerenityOS/serenity/commit/f6ae4edbd23 Pull-request: https://github.com/SerenityOS/serenity/pull/4177 Issue: https://github.com/SerenityOS/serenity/issues/4167 Issue: https://github.com/SerenityOS/serenity/issues/4168 Issue: https://github.com/SerenityOS/serenity/issues/4170 Issue: https://github.com/SerenityOS/serenity/issues/4171 Reviewed-by: https://github.com/awesomekling
5 changed files with 69 additions and 11 deletions
|
@ -49,10 +49,10 @@ Sheet::Sheet(const StringView& name, Workbook& workbook)
|
|||
{
|
||||
m_name = name;
|
||||
|
||||
for (size_t i = 0; i < 20; ++i)
|
||||
for (size_t i = 0; i < default_row_count; ++i)
|
||||
add_row();
|
||||
|
||||
for (size_t i = 0; i < 16; ++i)
|
||||
for (size_t i = 0; i < default_column_count; ++i)
|
||||
add_column();
|
||||
}
|
||||
|
||||
|
@ -318,7 +318,7 @@ void Sheet::copy_cells(Vector<Position> from, Vector<Position> to, Optional<Posi
|
|||
RefPtr<Sheet> Sheet::from_json(const JsonObject& object, Workbook& workbook)
|
||||
{
|
||||
auto sheet = adopt(*new Sheet(workbook));
|
||||
auto rows = object.get("rows").to_u32(20);
|
||||
auto rows = object.get("rows").to_u32(default_row_count);
|
||||
auto columns = object.get("columns");
|
||||
if (!columns.is_array())
|
||||
return nullptr;
|
||||
|
@ -326,7 +326,7 @@ RefPtr<Sheet> Sheet::from_json(const JsonObject& object, Workbook& workbook)
|
|||
|
||||
sheet->set_name(name);
|
||||
|
||||
for (size_t i = 0; i < rows; ++i)
|
||||
for (size_t i = 0; i < max(rows, (unsigned)Sheet::default_row_count); ++i)
|
||||
sheet->add_row();
|
||||
|
||||
// FIXME: Better error checking.
|
||||
|
@ -421,6 +421,19 @@ RefPtr<Sheet> Sheet::from_json(const JsonObject& object, Workbook& workbook)
|
|||
return sheet;
|
||||
}
|
||||
|
||||
Position Sheet::written_data_bounds() const
|
||||
{
|
||||
Position bound;
|
||||
for (auto& entry : m_cells) {
|
||||
if (entry.key.row > bound.row)
|
||||
bound.row = entry.key.row;
|
||||
if (entry.key.column > bound.column)
|
||||
bound.column = entry.key.column;
|
||||
}
|
||||
|
||||
return bound;
|
||||
}
|
||||
|
||||
JsonObject Sheet::to_json() const
|
||||
{
|
||||
JsonObject object;
|
||||
|
@ -433,12 +446,14 @@ JsonObject Sheet::to_json() const
|
|||
obj.set("background_color", format.background_color.value().to_string());
|
||||
};
|
||||
|
||||
auto bottom_right = written_data_bounds();
|
||||
|
||||
auto columns = JsonArray();
|
||||
for (auto& column : m_columns)
|
||||
columns.append(column);
|
||||
object.set("columns", move(columns));
|
||||
|
||||
object.set("rows", m_rows);
|
||||
object.set("rows", bottom_right.row);
|
||||
|
||||
JsonObject cells;
|
||||
for (auto& it : m_cells) {
|
||||
|
@ -502,10 +517,12 @@ Vector<Vector<String>> Sheet::to_xsv() const
|
|||
{
|
||||
Vector<Vector<String>> data;
|
||||
|
||||
auto bottom_right = written_data_bounds();
|
||||
|
||||
// First row = headers.
|
||||
data.append(m_columns);
|
||||
|
||||
for (size_t i = 0; i < m_rows; ++i) {
|
||||
for (size_t i = 0; i <= bottom_right.row; ++i) {
|
||||
Vector<String> row;
|
||||
row.resize(m_columns.size());
|
||||
for (size_t j = 0; j < m_columns.size(); ++j) {
|
||||
|
@ -527,7 +544,7 @@ RefPtr<Sheet> Sheet::from_xsv(const Reader::XSV& xsv, Workbook& workbook)
|
|||
|
||||
auto sheet = adopt(*new Sheet(workbook));
|
||||
sheet->m_columns = cols;
|
||||
for (size_t i = 0; i < rows; ++i)
|
||||
for (size_t i = 0; i < max(rows, Sheet::default_row_count); ++i)
|
||||
sheet->add_row();
|
||||
|
||||
for (auto row : xsv) {
|
||||
|
|
|
@ -46,6 +46,9 @@ class Sheet : public Core::Object {
|
|||
C_OBJECT(Sheet);
|
||||
|
||||
public:
|
||||
constexpr static size_t default_row_count = 100;
|
||||
constexpr static size_t default_column_count = 26;
|
||||
|
||||
~Sheet();
|
||||
|
||||
static Optional<Position> parse_cell_name(const StringView&);
|
||||
|
@ -124,6 +127,9 @@ public:
|
|||
|
||||
void copy_cells(Vector<Position> from, Vector<Position> to, Optional<Position> resolve_relative_to = {});
|
||||
|
||||
/// Gives the bottom-right corner of the smallest bounding box containing all the written data.
|
||||
Position written_data_bounds() const;
|
||||
|
||||
private:
|
||||
explicit Sheet(Workbook&);
|
||||
explicit Sheet(const StringView& name, Workbook&);
|
||||
|
|
|
@ -170,6 +170,7 @@ void SheetModel::set_data(const GUI::ModelIndex& index, const GUI::Variant& valu
|
|||
void SheetModel::update()
|
||||
{
|
||||
m_sheet->update();
|
||||
did_update(UpdateFlag::DontInvalidateIndexes);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <LibGUI/Menu.h>
|
||||
#include <LibGUI/ModelEditingDelegate.h>
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibGUI/ScrollBar.h>
|
||||
#include <LibGUI/TableView.h>
|
||||
#include <LibGfx/Palette.h>
|
||||
|
||||
|
@ -57,17 +58,40 @@ void SpreadsheetView::EditingDelegate::set_value(const GUI::Variant& value)
|
|||
StringModelEditingDelegate::set_value("");
|
||||
}
|
||||
|
||||
void InfinitelyScrollableTableView::did_scroll()
|
||||
{
|
||||
TableView::did_scroll();
|
||||
auto& vscrollbar = vertical_scrollbar();
|
||||
if (vscrollbar.is_visible() && vscrollbar.value() == vscrollbar.max()) {
|
||||
if (on_reaching_vertical_end)
|
||||
on_reaching_vertical_end();
|
||||
}
|
||||
}
|
||||
|
||||
void SpreadsheetView::update_with_model()
|
||||
{
|
||||
m_table_view->model()->update();
|
||||
m_table_view->update();
|
||||
}
|
||||
|
||||
SpreadsheetView::SpreadsheetView(Sheet& sheet)
|
||||
: m_sheet(sheet)
|
||||
{
|
||||
set_layout<GUI::VerticalBoxLayout>().set_margins({ 2, 2, 2, 2 });
|
||||
m_table_view = add<GUI::TableView>();
|
||||
m_table_view = add<InfinitelyScrollableTableView>();
|
||||
m_table_view->set_grid_style(GUI::TableView::GridStyle::Both);
|
||||
m_table_view->set_cursor_style(GUI::TableView::CursorStyle::Item);
|
||||
m_table_view->set_edit_triggers(GUI::AbstractView::EditTrigger::EditKeyPressed | GUI::AbstractView::AnyKeyPressed | GUI::AbstractView::DoubleClicked);
|
||||
m_table_view->set_tab_key_navigation_enabled(true);
|
||||
m_table_view->row_header().set_visible(true);
|
||||
m_table_view->set_model(SheetModel::create(*m_sheet));
|
||||
m_table_view->on_reaching_vertical_end = [&]() {
|
||||
for (size_t i = 0; i < 100; ++i) {
|
||||
auto index = m_sheet->add_row();
|
||||
m_table_view->set_column_painting_delegate(index, make<TableCellPainter>(*m_table_view));
|
||||
};
|
||||
update_with_model();
|
||||
};
|
||||
|
||||
set_focus_proxy(m_table_view);
|
||||
|
||||
|
@ -107,8 +131,7 @@ SpreadsheetView::SpreadsheetView(Sheet& sheet)
|
|||
|
||||
if (on_selection_changed) {
|
||||
on_selection_changed(move(selected_positions));
|
||||
m_table_view->model()->update();
|
||||
m_table_view->update();
|
||||
update_with_model();
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -79,6 +79,15 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
class InfinitelyScrollableTableView : public GUI::TableView {
|
||||
C_OBJECT(InfinitelyScrollableTableView)
|
||||
public:
|
||||
Function<void()> on_reaching_vertical_end;
|
||||
|
||||
private:
|
||||
virtual void did_scroll() override;
|
||||
};
|
||||
|
||||
class SpreadsheetView final : public GUI::Widget {
|
||||
C_OBJECT(SpreadsheetView);
|
||||
|
||||
|
@ -100,6 +109,8 @@ private:
|
|||
virtual void hide_event(GUI::HideEvent&) override;
|
||||
virtual void show_event(GUI::ShowEvent&) override;
|
||||
|
||||
void update_with_model();
|
||||
|
||||
SpreadsheetView(Sheet&);
|
||||
|
||||
class EditingDelegate final : public GUI::StringModelEditingDelegate {
|
||||
|
@ -143,7 +154,7 @@ private:
|
|||
};
|
||||
|
||||
NonnullRefPtr<Sheet> m_sheet;
|
||||
RefPtr<GUI::TableView> m_table_view;
|
||||
RefPtr<InfinitelyScrollableTableView> m_table_view;
|
||||
RefPtr<GUI::Menu> m_cell_range_context_menu;
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue