ladybird/Userland/Applications/Spreadsheet/SpreadsheetModel.cpp
sin-ack ca2c81251a Everywhere: Replace Model::update() with Model::invalidate()
Most of the models were just calling did_update anyway, which is
pointless since it can be unified to the base Model class. Instead, code
calling update() will now call invalidate(), which functions identically
and is more obvious in what it does.

Additionally, a default implementation is provided, which removes the
need to add empty implementations of update() for each model subclass.

Co-Authored-By: Ali Mohammad Pur <ali.mpfard@gmail.com>
2021-08-06 19:14:31 +02:00

158 lines
4.5 KiB
C++

/*
* Copyright (c) 2020, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "SpreadsheetModel.h"
#include "ConditionalFormatting.h"
#include <AK/URL.h>
#include <LibGUI/AbstractView.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/Object.h>
namespace Spreadsheet {
SheetModel::~SheetModel()
{
}
GUI::Variant SheetModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
{
if (!index.is_valid())
return {};
if (role == GUI::ModelRole::Display) {
const auto* cell = m_sheet->at({ (size_t)index.column(), (size_t)index.row() });
if (!cell)
return String::empty();
if (cell->kind() == Spreadsheet::Cell::Formula) {
if (auto exception = cell->exception()) {
StringBuilder builder;
builder.append("Error: ");
auto value = exception->value();
if (value.is_object()) {
auto& object = value.as_object();
if (is<JS::Error>(object)) {
auto error = object.get("message").to_string_without_side_effects();
builder.append(error);
return builder.to_string();
}
}
auto error = value.to_string(cell->sheet().global_object());
// This is annoying, but whatever.
cell->sheet().interpreter().vm().clear_exception();
builder.append(error);
return builder.to_string();
}
}
return cell->typed_display();
}
if (role == GUI::ModelRole::MimeData)
return Position { (size_t)index.column(), (size_t)index.row() }.to_url(m_sheet).to_string();
if (role == GUI::ModelRole::TextAlignment) {
const auto* cell = m_sheet->at({ (size_t)index.column(), (size_t)index.row() });
if (!cell)
return {};
return cell->type_metadata().alignment;
}
if (role == GUI::ModelRole::ForegroundColor) {
const auto* cell = m_sheet->at({ (size_t)index.column(), (size_t)index.row() });
if (!cell)
return {};
if (cell->kind() == Spreadsheet::Cell::Formula) {
if (cell->exception())
return Color(Color::Red);
}
if (cell->evaluated_formats().foreground_color.has_value())
return cell->evaluated_formats().foreground_color.value();
if (auto color = cell->type_metadata().static_format.foreground_color; color.has_value())
return color.value();
return {};
}
if (role == GUI::ModelRole::BackgroundColor) {
const auto* cell = m_sheet->at({ (size_t)index.column(), (size_t)index.row() });
if (!cell)
return {};
if (cell->evaluated_formats().background_color.has_value())
return cell->evaluated_formats().background_color.value();
if (auto color = cell->type_metadata().static_format.background_color; color.has_value())
return color.value();
return {};
}
return {};
}
RefPtr<Core::MimeData> SheetModel::mime_data(const GUI::ModelSelection& selection) const
{
auto mime_data = GUI::Model::mime_data(selection);
bool first = true;
const GUI::ModelIndex* cursor = nullptr;
const_cast<SheetModel*>(this)->for_each_view([&](const GUI::AbstractView& view) {
if (!first)
return;
cursor = &view.cursor_index();
first = false;
});
VERIFY(cursor);
Position cursor_position { (size_t)cursor->column(), (size_t)cursor->row() };
auto new_data = String::formatted("{}\n{}",
cursor_position.to_url(m_sheet).to_string(),
StringView(mime_data->data("text/x-spreadsheet-data")));
mime_data->set_data("text/x-spreadsheet-data", new_data.to_byte_buffer());
return mime_data;
}
String SheetModel::column_name(int index) const
{
if (index < 0)
return {};
return m_sheet->column(index);
}
bool SheetModel::is_editable(const GUI::ModelIndex& index) const
{
if (!index.is_valid())
return false;
return true;
}
void SheetModel::set_data(const GUI::ModelIndex& index, const GUI::Variant& value)
{
if (!index.is_valid())
return;
auto& cell = m_sheet->ensure({ (size_t)index.column(), (size_t)index.row() });
cell.set_data(value.to_string());
invalidate();
}
void SheetModel::update()
{
m_sheet->update();
did_update(UpdateFlag::DontInvalidateIndices);
}
}