1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 11:28:12 +00:00

Spreadsheet: Add support for copying ranges of cells to other cells

Now the entire range is copied to the area around the target cell,
translating the current cursor to the target.
This commit is contained in:
AnotherTest 2020-11-07 23:18:41 +03:30 committed by Andreas Kling
parent 7878596532
commit e99c2261e3
8 changed files with 187 additions and 53 deletions

View file

@ -31,6 +31,7 @@
#include <AK/JsonArray.h>
#include <AK/JsonObject.h>
#include <AK/JsonParser.h>
#include <AK/ScopeGuard.h>
#include <AK/TemporaryChange.h>
#include <AK/URL.h>
#include <LibCore/File.h>
@ -38,6 +39,8 @@
#include <LibJS/Runtime/Function.h>
#include <ctype.h>
//#define COPY_DEBUG
namespace Spreadsheet {
Sheet::Sheet(const StringView& name, Workbook& workbook)
@ -204,21 +207,99 @@ Optional<Position> Sheet::parse_cell_name(const StringView& name)
}
Cell* Sheet::from_url(const URL& url)
{
auto maybe_position = position_from_url(url);
if (!maybe_position.has_value())
return nullptr;
return at(maybe_position.value());
}
Optional<Position> Sheet::position_from_url(const URL& url) const
{
if (!url.is_valid()) {
dbgln("Invalid url: {}", url.to_string());
return nullptr;
return {};
}
if (url.protocol() != "spreadsheet" || url.host() != "cell") {
dbgln("Bad url: {}", url.to_string());
return nullptr;
return {};
}
// FIXME: Figure out a way to do this cross-process.
ASSERT(url.path() == String::formatted("/{}", getpid()));
return at(url.fragment());
return parse_cell_name(url.fragment());
}
Position Sheet::offset_relative_to(const Position& base, const Position& offset, const Position& offset_base) const
{
auto offset_column_it = m_columns.find(offset.column);
auto offset_base_column_it = m_columns.find(offset_base.column);
auto base_column_it = m_columns.find(base.column);
if (offset_column_it.is_end()) {
dbg() << "Column '" << offset.column << "' does not exist!";
return base;
}
if (offset_base_column_it.is_end()) {
dbg() << "Column '" << offset_base.column << "' does not exist!";
return base;
}
if (base_column_it.is_end()) {
dbg() << "Column '" << base.column << "' does not exist!";
return offset;
}
auto new_column = column(offset_column_it.index() + base_column_it.index() - offset_base_column_it.index());
auto new_row = offset.row + base.row - offset_base.row;
return { move(new_column), new_row };
}
void Sheet::copy_cells(Vector<Position> from, Vector<Position> to, Optional<Position> resolve_relative_to)
{
auto copy_to = [&](auto& source_position, Position target_position) {
auto& target_cell = ensure(target_position);
auto* source_cell = at(source_position);
if (!source_cell) {
target_cell.set_data("");
return;
}
auto ref_cells = target_cell.referencing_cells;
target_cell = *source_cell;
target_cell.dirty = true;
target_cell.referencing_cells = move(ref_cells);
};
if (from.size() == to.size()) {
auto from_it = from.begin();
// FIXME: Ordering.
for (auto& position : to)
copy_to(*from_it++, position);
return;
}
if (to.size() == 1) {
// Resolve each index as relative to the first index offset from the selection.
auto& target = to.first();
for (auto& position : from) {
#ifdef COPY_DEBUG
dbg() << "Paste from '" << position.to_url() << "' to '" << target.to_url() << "'";
#endif
copy_to(position, resolve_relative_to.has_value() ? offset_relative_to(target, position, resolve_relative_to.value()) : target);
}
return;
}
// Just disallow misaligned copies.
dbg() << "Cannot copy " << from.size() << " cells to " << to.size() << " cells";
}
RefPtr<Sheet> Sheet::from_json(const JsonObject& object, Workbook& workbook)