Spreadsheet: fix range checking (#6997)

* App: add option to normalize a Range

- To make sure the range starts from top left and ends with bottom right
corner.
- Default is to not normalize on construction for backward compatibility.
-  fix range checking in range binding
This commit is contained in:
Zheng Lei
2022-06-09 18:20:08 +08:00
committed by GitHub
parent 28c269cc5f
commit 9d7b7af48c
4 changed files with 37 additions and 19 deletions

View File

@@ -37,7 +37,7 @@ using namespace App;
const int App::CellAddress::MAX_ROWS = 16384;
const int App::CellAddress::MAX_COLUMNS = 26 * 26 + 26;
Range::Range(const char * range)
Range::Range(const char * range, bool normalize)
{
std::string from;
std::string to;
@@ -62,28 +62,42 @@ Range::Range(const char * range)
row_end = end.row();
col_end = end.col();
if (normalize)
this->normalize();
row_curr = row_begin;
col_curr = col_begin;
}
Range::Range(int _row_begin, int _col_begin, int _row_end, int _col_end)
: row_curr(_row_begin)
, col_curr(_col_begin)
, row_begin(_row_begin)
Range::Range(int _row_begin, int _col_begin, int _row_end, int _col_end, bool normalize)
: row_begin(_row_begin)
, col_begin(_col_begin)
, row_end(_row_end)
, col_end(_col_end)
{
if (normalize)
this->normalize();
row_curr = row_begin;
col_curr = col_begin;
}
Range::Range(const CellAddress &from, const CellAddress &to)
: row_curr(from.row())
, col_curr(from.col())
, row_begin(from.row())
Range::Range(const CellAddress &from, const CellAddress &to, bool normalize)
: row_begin(from.row())
, col_begin(from.col())
, row_end(to.row())
, col_end(to.col())
{
if (normalize)
this->normalize();
row_curr = row_begin;
col_curr = col_begin;
}
void Range::normalize()
{
if (row_begin > row_end)
std::swap(row_begin, row_end);
if (col_begin > col_end)
std::swap(col_begin, col_end);
}
bool Range::next()

View File

@@ -117,14 +117,17 @@ protected:
class AppExport Range {
public:
Range(const char *range);
Range(const char *range, bool normalize=false);
Range(int _row_begin, int _col_begin, int _row_end, int _col_end);
Range(int _row_begin, int _col_begin, int _row_end, int _col_end, bool normalize=false);
Range(const CellAddress & from, const CellAddress & to);
Range(const CellAddress & from, const CellAddress & to, bool normalize=false);
bool next();
/** Make sure the range starts from top left and ends with bottom right corner **/
void normalize();
/** Current row */
inline int row() const { return row_curr; }

View File

@@ -830,9 +830,10 @@ Sheet::getCellBinding(Range &range,
ExpressionPtr *pEnd,
App::ObjectIdentifier *pTarget) const
{
range.normalize();
do {
CellAddress addr = *range;
for(auto &r : boundRanges) {
for(const auto &r : boundRanges) {
if(addr.row()>=r.from().row()
&& addr.row()<=r.to().row()
&& addr.col()>=r.from().col()
@@ -885,20 +886,20 @@ void Sheet::updateBindings()
std::set<Range> newRangeSet;
std::set<Range> rangeSet;
boundRanges.clear();
for(auto &v : ExpressionEngine.getExpressions()) {
for(const auto &v : ExpressionEngine.getExpressions()) {
CellAddress from,to;
if(!cells.isBindingPath(v.first,&from,&to))
continue;
App::Range range(from,to);
App::Range range(from,to,true);
if(!oldRangeSet.erase(range))
newRangeSet.insert(range);
rangeSet.insert(range);
}
boundRanges.reserve(rangeSet.size());
boundRanges.insert(boundRanges.end(),rangeSet.begin(),rangeSet.end());
for(auto &range : oldRangeSet)
for(const auto &range : oldRangeSet)
rangeUpdated(range);
for(auto &range : newRangeSet)
for(const auto &range : newRangeSet)
rangeUpdated(range);
}

View File

@@ -188,8 +188,8 @@ void DlgBindSheet::accept()
else {
checkAddress(toEnd, toCellEnd, true);
if (toCellStart.isValid()) {
App::Range fromRange(fromCellStart, fromCellEnd);
App::Range toRange(toCellStart, toCellEnd);
App::Range fromRange(fromCellStart, fromCellEnd, true);
App::Range toRange(toCellStart, toCellEnd, true);
if (fromRange.size() != toRange.size()) {
auto res = QMessageBox::warning(this, tr("Bind cells"),
tr("Source and target cell count mismatch. Partial binding may still work.\n\n"