summaryrefslogtreecommitdiff
path: root/Userland/Applications/Spreadsheet/Spreadsheet.cpp
diff options
context:
space:
mode:
authormartinfalisse <martinmotteditfalisse@gmail.com>2022-03-06 17:14:51 +0100
committerAli Mohammad Pur <Ali.mpfard@gmail.com>2022-03-19 09:31:29 +0330
commitf6ad98b1a10f16246b0d60c9b5653d61d87fcfe8 (patch)
tree195d4dda687ffaf60a21e87bab8226c72f90540a /Userland/Applications/Spreadsheet/Spreadsheet.cpp
parent2f2a705a8ed41e249ca2190b763ee00712a3af42 (diff)
downloadserenity-f6ad98b1a10f16246b0d60c9b5653d61d87fcfe8.zip
Spreadsheet: Take into account cell order when copying and cutting
Since copying and cutting uses the cell values in the origin to decide which values to paste in the destination, it is necessary to do it in an ordered manner when the origin and destination ranges overlap. Otherwise you may overwrite values in the origin unintentionally before having successfully transferred them to the destination.
Diffstat (limited to 'Userland/Applications/Spreadsheet/Spreadsheet.cpp')
-rw-r--r--Userland/Applications/Spreadsheet/Spreadsheet.cpp67
1 files changed, 40 insertions, 27 deletions
diff --git a/Userland/Applications/Spreadsheet/Spreadsheet.cpp b/Userland/Applications/Spreadsheet/Spreadsheet.cpp
index 91538d068f..a1552a4246 100644
--- a/Userland/Applications/Spreadsheet/Spreadsheet.cpp
+++ b/Userland/Applications/Spreadsheet/Spreadsheet.cpp
@@ -294,6 +294,12 @@ Position Sheet::offset_relative_to(const Position& base, const Position& offset,
void Sheet::copy_cells(Vector<Position> from, Vector<Position> to, Optional<Position> resolve_relative_to, CopyOperation copy_operation)
{
+ // Disallow misaligned copies.
+ if (to.size() > 1 && from.size() != to.size()) {
+ dbgln("Cannot copy {} cells to {} cells", from.size(), to.size());
+ return;
+ }
+
Vector<Position> target_cells;
for (auto& position : from)
target_cells.append(resolve_relative_to.has_value() ? offset_relative_to(to.first(), position, resolve_relative_to.value()) : to.first());
@@ -313,39 +319,46 @@ void Sheet::copy_cells(Vector<Position> from, Vector<Position> to, Optional<Posi
source_cell->set_data("");
};
- if (from.size() == to.size()) {
- auto from_it = from.begin();
- // FIXME: Ordering.
- for (auto& position : to)
- copy_to(*from_it++, position);
-
- return;
+ // Resolve each index as relative to the first index offset from the selection.
+ auto& target = to.first();
+
+ auto top_left_most_position_from = from.first();
+ auto bottom_right_most_position_from = from.first();
+ for (auto& position : from) {
+ if (position.row > bottom_right_most_position_from.row)
+ bottom_right_most_position_from = position;
+ else if (position.column > bottom_right_most_position_from.column)
+ bottom_right_most_position_from = position;
+
+ if (position.row < top_left_most_position_from.row)
+ top_left_most_position_from = position;
+ else if (position.column < top_left_most_position_from.column)
+ top_left_most_position_from = position;
}
- 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) {
- dbgln_if(COPY_DEBUG, "Paste from '{}' to '{}'", position.to_url(*this), target.to_url(*this));
- copy_to(position, resolve_relative_to.has_value() ? offset_relative_to(target, position, resolve_relative_to.value()) : target);
+ Vector<Position> ordered_from;
+ auto current_column = top_left_most_position_from.column;
+ auto current_row = top_left_most_position_from.row;
+ for ([[maybe_unused]] auto& position : from) {
+ for (auto& position : from)
+ if (position.row == current_row && position.column == current_column)
+ ordered_from.append(position);
+
+ if (current_column >= bottom_right_most_position_from.column) {
+ current_column = top_left_most_position_from.column;
+ current_row += 1;
+ } else {
+ current_column += 1;
}
-
- return;
}
- if (from.size() == 1) {
- // Fill the target selection with the single cell.
- auto& source = from.first();
- for (auto& position : to) {
- dbgln_if(COPY_DEBUG, "Paste from '{}' to '{}'", source.to_url(*this), position.to_url(*this));
- copy_to(source, resolve_relative_to.has_value() ? offset_relative_to(position, source, resolve_relative_to.value()) : position);
- }
- return;
- }
+ if (target.row > top_left_most_position_from.row || (target.row >= top_left_most_position_from.row && target.column > top_left_most_position_from.column))
+ ordered_from.reverse();
- // Just disallow misaligned copies.
- dbgln("Cannot copy {} cells to {} cells", from.size(), to.size());
+ for (auto& position : ordered_from) {
+ dbgln_if(COPY_DEBUG, "Paste from '{}' to '{}'", position.to_url(*this), target.to_url(*this));
+ copy_to(position, resolve_relative_to.has_value() ? offset_relative_to(target, position, resolve_relative_to.value()) : target);
+ }
}
RefPtr<Sheet> Sheet::from_json(const JsonObject& object, Workbook& workbook)