Spreadsheet: Refactored alias checking code, so GUI and Python error messages are aligned.
This commit is contained in:
parent
e5f1e298a6
commit
53dcaccd4e
|
@ -176,6 +176,33 @@ const Cell * PropertySheet::getValueFromAlias(const std::string &alias) const
|
|||
return getValue(it->second);
|
||||
else
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
bool PropertySheet::isValidAlias(const std::string &candidate)
|
||||
{
|
||||
static const boost::regex gen("^[A-Za-z][_A-Za-z0-9]*$");
|
||||
boost::cmatch cm;
|
||||
|
||||
/* Check if it is used before */
|
||||
if (getValueFromAlias(candidate) != 0)
|
||||
return false;
|
||||
|
||||
if (boost::regex_match(candidate.c_str(), cm, gen)) {
|
||||
static const boost::regex e("\\${0,1}([A-Z]{1,2})\\${0,1}([0-9]{1,5})");
|
||||
|
||||
if (boost::regex_match(candidate.c_str(), cm, e)) {
|
||||
const boost::sub_match<const char *> colstr = cm[1];
|
||||
const boost::sub_match<const char *> rowstr = cm[2];
|
||||
|
||||
// A valid cell address?
|
||||
if (Spreadsheet::validRow(rowstr.str()) >= 0 && Spreadsheet::validColumn(colstr.str()) >= 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
std::set<CellAddress> PropertySheet::getUsedCells() const
|
||||
|
@ -452,7 +479,15 @@ void PropertySheet::setDisplayUnit(CellAddress address, const std::string &unit)
|
|||
|
||||
void PropertySheet::setAlias(CellAddress address, const std::string &alias)
|
||||
{
|
||||
if (alias.size() > 0 && !isValidAlias(alias))
|
||||
throw Base::Exception("Invalid alias");
|
||||
|
||||
const Cell * aliasedCell = getValueFromAlias(alias);
|
||||
Cell * cell = nonNullCellAt(address);
|
||||
|
||||
if (aliasedCell != 0 && cell != aliasedCell)
|
||||
throw Base::Exception("Alias already defined.");
|
||||
|
||||
assert(cell != 0);
|
||||
|
||||
/* Mark cells depending on this cell dirty; they need to be resolved when an alias changes or disappears */
|
||||
|
|
|
@ -85,6 +85,8 @@ public:
|
|||
|
||||
const Cell * getValueFromAlias(const std::string &alias) const;
|
||||
|
||||
bool isValidAlias(const std::string &candidate);
|
||||
|
||||
std::set<CellAddress> getUsedCells() const;
|
||||
|
||||
Sheet * sheet() const { return owner; }
|
||||
|
|
|
@ -1123,19 +1123,28 @@ void Sheet::setComputedUnit(CellAddress address, const Base::Unit &unit)
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Set alias for cell at address \a address to \a alias.
|
||||
* @brief Set alias for cell at address \a address to \a alias. If the alias
|
||||
* is an empty string, the existing alias is removed.
|
||||
* @param address Address of cell
|
||||
* @param alias New alias.
|
||||
*/
|
||||
|
||||
void Sheet::setAlias(CellAddress address, const std::string &alias)
|
||||
{
|
||||
const Cell * cell = cells.getValueFromAlias(alias);
|
||||
std::string existingAlias = getAddressFromAlias(alias);
|
||||
|
||||
if (cell != 0)
|
||||
throw Base::Exception("Alias already defined.");
|
||||
if (existingAlias.size() > 0) {
|
||||
if (existingAlias == address.toString()) // Same as old?
|
||||
return;
|
||||
else
|
||||
throw Base::Exception("Alias already defined");
|
||||
}
|
||||
else if (alias.size() == 0) // Empty?
|
||||
cells.setAlias(address, "");
|
||||
else if (isValidAlias(alias)) // Valid?
|
||||
cells.setAlias(address, alias);
|
||||
else
|
||||
throw Base::Exception("Invalid alias");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1155,6 +1164,31 @@ std::string Sheet::getAddressFromAlias(const std::string &alias) const
|
|||
return std::string();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determine whether a given alias candiate is valid or not.
|
||||
*
|
||||
* A candidate is valid is the string is syntactically correct,
|
||||
* and the alias does not conflict with an existing property.
|
||||
*
|
||||
*/
|
||||
|
||||
bool Sheet::isValidAlias(const std::string & candidate)
|
||||
{
|
||||
// Valid syntactically?
|
||||
if (!cells.isValidAlias(candidate))
|
||||
return false;
|
||||
|
||||
// Existing alias? Then it's ok
|
||||
if (getAddressFromAlias(candidate).size() > 0 )
|
||||
return true;
|
||||
|
||||
// Check to see that is does not crash with any other property in the Sheet object.
|
||||
if (getPropertyByName(candidate.c_str()))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set row and column span for the cell at address \a address to \a rows and \a columns.
|
||||
* @param address Address to upper right corner of cell
|
||||
|
|
|
@ -142,6 +142,8 @@ public:
|
|||
|
||||
std::string getAddressFromAlias(const std::string & alias) const;
|
||||
|
||||
bool isValidAlias(const std::string &candidate);
|
||||
|
||||
void setSpans(CellAddress address, int rows, int columns);
|
||||
|
||||
std::set<std::string> dependsOn(CellAddress address) const;
|
||||
|
|
|
@ -84,13 +84,12 @@ std::string Spreadsheet::rowName(int row)
|
|||
|
||||
int Spreadsheet::decodeRow(const std::string &rowstr)
|
||||
{
|
||||
char * end;
|
||||
int i = strtol(rowstr.c_str(), &end, 10);
|
||||
int row = validRow(rowstr);
|
||||
|
||||
if (i <0 || i >= CellAddress::MAX_ROWS || *end)
|
||||
if (row >= 0)
|
||||
return row;
|
||||
else
|
||||
throw Base::Exception("Invalid row specification.");
|
||||
|
||||
return i - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -103,6 +102,44 @@ int Spreadsheet::decodeRow(const std::string &rowstr)
|
|||
*/
|
||||
|
||||
int Spreadsheet::decodeColumn(const std::string &colstr)
|
||||
{
|
||||
int col = validColumn(colstr);
|
||||
|
||||
if (col >= 0)
|
||||
return col;
|
||||
else
|
||||
throw Base::Exception("Invalid column specification");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine wheter a row specification is valid or not.
|
||||
*
|
||||
* @param rowstr Row specified as a string, with "1" being the first row.
|
||||
*
|
||||
* @returns 0 or positive on success, -1 on error.
|
||||
*/
|
||||
|
||||
int Spreadsheet::validRow(const std::string &rowstr)
|
||||
{
|
||||
char * end;
|
||||
int i = strtol(rowstr.c_str(), &end, 10);
|
||||
|
||||
if (i <0 || i >= CellAddress::MAX_ROWS || *end)
|
||||
return -1;
|
||||
|
||||
return i - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a column specification is valid or not.
|
||||
*
|
||||
* @param colstr Column specified as a string, with "A" begin the first column.
|
||||
*
|
||||
* @returns 0 or positive on success, -1 on error.
|
||||
*
|
||||
*/
|
||||
|
||||
int Spreadsheet::validColumn(const std::string &colstr)
|
||||
{
|
||||
int col = 0;
|
||||
|
||||
|
@ -110,7 +147,7 @@ int Spreadsheet::decodeColumn(const std::string &colstr)
|
|||
if ((colstr[0] >= 'A' && colstr[0] <= 'Z'))
|
||||
col = colstr[0] - 'A';
|
||||
else
|
||||
throw Base::Exception("Invalid column specification");
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
col = 0;
|
||||
|
@ -120,7 +157,7 @@ int Spreadsheet::decodeColumn(const std::string &colstr)
|
|||
if ((*i >= 'A' && *i <= 'Z'))
|
||||
v = *i - 'A';
|
||||
else
|
||||
throw Base::Exception("Invalid column specification");
|
||||
return -1;
|
||||
|
||||
col = col * 26 + v;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,9 @@ SpreadsheetExport std::string columnName(int col);
|
|||
SpreadsheetExport std::string rowName(int row);
|
||||
int decodeColumn(const std::string &colstr);
|
||||
int decodeRow(const std::string &rowstr);
|
||||
int validColumn(const std::string &colstr);
|
||||
int validRow(const std::string &rowstr);
|
||||
|
||||
SpreadsheetExport CellAddress stringToAddress(const char *strAddress);
|
||||
SpreadsheetExport void createRectangles(std::set<std::pair<int, int> > & cells, std::map<std::pair<int, int>, std::pair<int, int> > & rectangles);
|
||||
SpreadsheetExport std::string quote(const std::string &input);
|
||||
|
|
|
@ -204,22 +204,7 @@ void PropertiesDialog::aliasChanged(const QString & text)
|
|||
{
|
||||
QPalette palette = ui->alias->palette();
|
||||
|
||||
aliasOk = true;
|
||||
|
||||
if (sheet->getAddressFromAlias(Base::Tools::toStdString(text)).size() > 0)
|
||||
aliasOk = false;
|
||||
|
||||
if (text.indexOf(QRegExp(QString::fromLatin1("^[A-Za-z][_A-Za-z0-9]*$"))) >= 0) {
|
||||
try {
|
||||
CellAddress address(text.toUtf8().constData());
|
||||
aliasOk = false;
|
||||
}
|
||||
catch (...) { }
|
||||
}
|
||||
else {
|
||||
if (!text.isEmpty())
|
||||
aliasOk = false;
|
||||
}
|
||||
aliasOk = text.isEmpty() || sheet->isValidAlias(Base::Tools::toStdString(text));
|
||||
|
||||
alias = aliasOk ? Base::Tools::toStdString(text) : "";
|
||||
palette.setColor(QPalette::Text, aliasOk ? Qt::black : Qt::red);
|
||||
|
|
Loading…
Reference in New Issue
Block a user