- Self-reference bug
- Refactoring/clean-up of code - Dependency tracking of aliased cells - Various resolution errors - Rewriting of ranges when columns/rows are inserted/removed - References to aliases keep their units.
This commit is contained in:
parent
1b7c0e2a51
commit
3743008cda
|
@ -31,6 +31,7 @@ void SpreadsheetExport initSpreadsheet() {
|
|||
(void) Py_InitModule("Spreadsheet", Spreadsheet_methods); /* mod name, table ptr */
|
||||
Base::Console().Log("Loading Spreadsheet module... done\n");
|
||||
|
||||
Spreadsheet::PropertySpreadsheetQuantity::init();
|
||||
Spreadsheet::PropertyColumnWidths::init();
|
||||
Spreadsheet::PropertyRowHeights::init();
|
||||
Spreadsheet::PropertySheet::init();
|
||||
|
|
|
@ -395,8 +395,20 @@ void Cell::setAlias(const std::string &n)
|
|||
if (alias != n) {
|
||||
PropertySheet::Signaller signaller(*owner);
|
||||
|
||||
owner->revAliasProp.erase(alias);
|
||||
|
||||
alias = n;
|
||||
|
||||
// Update owner
|
||||
if (alias != "") {
|
||||
owner->aliasProp[address] = n;
|
||||
owner->revAliasProp[n] = address;
|
||||
}
|
||||
else
|
||||
owner->aliasProp.erase(address);
|
||||
|
||||
setUsed(ALIAS_SET, !alias.empty());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -590,7 +602,7 @@ void Cell::save(Base::Writer &writer) const
|
|||
|
||||
writer.Stream() << writer.ind() << "<Cell ";
|
||||
|
||||
writer.Stream() << "address=\"" << addressToString(address) << "\" ";
|
||||
writer.Stream() << "address=\"" << address.toString() << "\" ";
|
||||
|
||||
if (isUsed(EXPRESSION_SET)) {
|
||||
std::string content;
|
||||
|
@ -663,7 +675,7 @@ bool Cell::isUsed() const
|
|||
void Cell::visit(ExpressionVisitor &v)
|
||||
{
|
||||
if (expression)
|
||||
v.visit(expression);
|
||||
expression->visit(v);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -116,6 +116,8 @@ public:
|
|||
|
||||
void visit(ExpressionVisitor & v);
|
||||
|
||||
CellAddress getAddress() const { return address; }
|
||||
|
||||
/* Alignment */
|
||||
static const int ALIGNMENT_LEFT;
|
||||
static const int ALIGNMENT_HCENTER;
|
||||
|
|
|
@ -176,7 +176,7 @@ std::string Path::getPythonAccessor() const
|
|||
const Property * prop = getProperty();
|
||||
|
||||
if (!prop)
|
||||
throw Exception("Property not found");
|
||||
throw Exception(std::string("Property '") + getPropertyName() + std::string("' not found."));
|
||||
|
||||
const DocumentObject * docObj = freecad_dynamic_cast<DocumentObject>(prop->getContainer());
|
||||
|
||||
|
@ -1309,6 +1309,16 @@ Document * Path::getDocument() const
|
|||
return doc;
|
||||
}
|
||||
|
||||
const DocumentObject *Path::getDocumentObject() const
|
||||
{
|
||||
const App::Document * doc = getDocument();
|
||||
|
||||
if (!doc)
|
||||
return 0;
|
||||
|
||||
return getDocumentObject(doc, documentObjectName);
|
||||
}
|
||||
|
||||
const Property *Path::getProperty() const
|
||||
{
|
||||
const App::Document * doc = getDocument();
|
||||
|
@ -1346,7 +1356,7 @@ const Property * VariableExpression::getProperty() const
|
|||
if (prop)
|
||||
return prop;
|
||||
else
|
||||
throw Base::Exception("Property not found.");
|
||||
throw Base::Exception(std::string("Property '") + var.getPropertyName() + std::string("' not found."));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1785,6 +1795,11 @@ Expression *RangeExpression::simplify() const
|
|||
return copy();
|
||||
}
|
||||
|
||||
void RangeExpression::setRange(const Range &r)
|
||||
{
|
||||
range = r;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -158,6 +158,8 @@ public:
|
|||
|
||||
App::Document *getDocument() const;
|
||||
|
||||
const App::DocumentObject *getDocumentObject() const;
|
||||
|
||||
protected:
|
||||
|
||||
const App::DocumentObject *getDocumentObject(const App::Document *doc, const std::string &name) const;
|
||||
|
@ -367,6 +369,8 @@ public:
|
|||
|
||||
Range getRange() const { return range; }
|
||||
|
||||
void setRange(const Range & r);
|
||||
|
||||
protected:
|
||||
Range range;
|
||||
};
|
||||
|
|
|
@ -155,3 +155,14 @@ PyObject *PropertyColumnWidths::getPyObject()
|
|||
}
|
||||
return Py::new_reference_to(PythonObject);
|
||||
}
|
||||
|
||||
void PropertyColumnWidths::clear()
|
||||
{
|
||||
std::map<int, int>::const_iterator i = begin();
|
||||
|
||||
while (i != end()) {
|
||||
dirty.insert(i->first);
|
||||
++i;
|
||||
}
|
||||
std::map<int,int>::clear();
|
||||
}
|
||||
|
|
|
@ -35,8 +35,6 @@ class SpreadsheetExport PropertyColumnWidths : public App::Property, std::map<in
|
|||
public:
|
||||
PropertyColumnWidths();
|
||||
|
||||
PropertyColumnWidths(const PropertyColumnWidths & other);
|
||||
|
||||
void setValue() { }
|
||||
|
||||
void setValue(int col, int width);
|
||||
|
@ -66,11 +64,15 @@ public:
|
|||
|
||||
PyObject *getPyObject(void);
|
||||
|
||||
void clear();
|
||||
|
||||
static const int defaultWidth;
|
||||
static const int defaultHeaderWidth;
|
||||
|
||||
private:
|
||||
|
||||
PropertyColumnWidths(const PropertyColumnWidths & other);
|
||||
|
||||
std::set<int> dirty;
|
||||
|
||||
Py::Object PythonObject;
|
||||
|
|
|
@ -148,3 +148,14 @@ PyObject *PropertyRowHeights::getPyObject()
|
|||
}
|
||||
return Py::new_reference_to(PythonObject);
|
||||
}
|
||||
|
||||
void PropertyRowHeights::clear()
|
||||
{
|
||||
std::map<int, int>::const_iterator i = begin();
|
||||
|
||||
while (i != end()) {
|
||||
dirty.insert(i->first);
|
||||
++i;
|
||||
}
|
||||
std::map<int,int>::clear();
|
||||
}
|
||||
|
|
|
@ -35,8 +35,6 @@ class SpreadsheetExport PropertyRowHeights : public App::Property, std::map<int,
|
|||
public:
|
||||
PropertyRowHeights();
|
||||
|
||||
PropertyRowHeights(const PropertyRowHeights & other);
|
||||
|
||||
void setValue() { }
|
||||
|
||||
void setValue(int row, int height);
|
||||
|
@ -68,8 +66,12 @@ public:
|
|||
|
||||
static const int defaultHeight;
|
||||
|
||||
void clear();
|
||||
|
||||
private:
|
||||
|
||||
PropertyRowHeights(const PropertyRowHeights & other);
|
||||
|
||||
std::set<int> dirty;
|
||||
|
||||
Py::Object PythonObject;
|
||||
|
|
|
@ -149,6 +149,8 @@ void PropertySheet::clear()
|
|||
propertyNameToCellMap.clear();
|
||||
documentObjectToCellMap.clear();
|
||||
docDeps.clear();
|
||||
aliasProp.clear();
|
||||
revAliasProp.clear();
|
||||
}
|
||||
|
||||
Cell *PropertySheet::getValue(CellAddress key)
|
||||
|
@ -429,8 +431,30 @@ void PropertySheet::setDisplayUnit(CellAddress address, const std::string &unit)
|
|||
|
||||
void PropertySheet::setAlias(CellAddress address, const std::string &alias)
|
||||
{
|
||||
assert(nonNullCellAt(address) != 0);
|
||||
nonNullCellAt(address)->setAlias(alias);
|
||||
Cell * cell = nonNullCellAt(address);
|
||||
assert(cell != 0);
|
||||
|
||||
/* Mark cells depending on this cell dirty; they need to be resolved when an alias changes or disappears */
|
||||
const char * docName = owner->getDocument()->Label.getValue();
|
||||
const char * docObjName = owner->getNameInDocument();
|
||||
std::string fullName = std::string(docName) + "#" + std::string(docObjName) + "." + address.toString();
|
||||
|
||||
std::map<std::string, std::set< CellAddress > >::const_iterator j = propertyNameToCellMap.find(fullName);
|
||||
if (j != propertyNameToCellMap.end()) {
|
||||
std::set< CellAddress >::const_iterator k = j->second.begin();
|
||||
|
||||
while (k != j->second.end()) {
|
||||
setDirty(*k);
|
||||
++k;
|
||||
}
|
||||
}
|
||||
|
||||
std::string oldAlias;
|
||||
|
||||
if (cell->getAlias(oldAlias))
|
||||
owner->aliasRemoved(address, oldAlias);
|
||||
|
||||
cell->setAlias(alias);
|
||||
}
|
||||
|
||||
void PropertySheet::setComputedUnit(CellAddress address, const Base::Unit &unit)
|
||||
|
@ -464,6 +488,13 @@ void PropertySheet::clear(CellAddress address)
|
|||
// Mark as dirty
|
||||
dirty.insert(i->first);
|
||||
|
||||
// Remove alias if it exists
|
||||
std::map<CellAddress, std::string>::iterator j = aliasProp.find(address);
|
||||
if (j != aliasProp.end()) {
|
||||
revAliasProp.erase(j->second);
|
||||
aliasProp.erase(j);
|
||||
}
|
||||
|
||||
// Erase from internal struct
|
||||
data.erase(i);
|
||||
|
||||
|
@ -524,13 +555,15 @@ public:
|
|||
bool changed() const { return mChanged; }
|
||||
|
||||
void visit(Expression * node) {
|
||||
VariableExpression *expr = freecad_dynamic_cast<VariableExpression>(node);
|
||||
VariableExpression *varExpr = freecad_dynamic_cast<VariableExpression>(node);
|
||||
RangeExpression *rangeExpr = freecad_dynamic_cast<RangeExpression>(node);
|
||||
|
||||
if (expr) {
|
||||
|
||||
if (varExpr) {
|
||||
static const boost::regex e("(\\${0,1})([A-Za-z]+)(\\${0,1})([0-9]+)");
|
||||
boost::cmatch cm;
|
||||
|
||||
if (boost::regex_match(expr->name().c_str(), cm, e)) {
|
||||
if (boost::regex_match(varExpr->name().c_str(), cm, e)) {
|
||||
const boost::sub_match<const char *> colstr = cm[2];
|
||||
const boost::sub_match<const char *> rowstr = cm[4];
|
||||
int thisRow, thisCol;
|
||||
|
@ -541,11 +574,26 @@ public:
|
|||
if (thisRow >= mRow || thisCol >= mCol) {
|
||||
thisRow += mRowCount;
|
||||
thisCol += mColCount;
|
||||
expr->setName(columnName(thisCol) + rowName(thisRow));
|
||||
varExpr->setName(columnName(thisCol) + rowName(thisRow));
|
||||
mChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (rangeExpr) {
|
||||
Range r = rangeExpr->getRange();
|
||||
CellAddress from(r.from());
|
||||
CellAddress to(r.to());
|
||||
|
||||
if (from.row() >= mRow || from.col() >= mCol) {
|
||||
from = CellAddress(from.row() + mRowCount, from.col() + mColCount);
|
||||
mChanged = true;
|
||||
}
|
||||
if (to.row() >= mRow || to.col() >= mCol) {
|
||||
to = CellAddress(to.row() + mRowCount, to.col() + mColCount);
|
||||
mChanged = true;
|
||||
}
|
||||
rangeExpr->setRange(Range(from, to));
|
||||
}
|
||||
}
|
||||
private:
|
||||
int mRow;
|
||||
|
@ -832,13 +880,13 @@ void PropertySheet::addDependencies(CellAddress key)
|
|||
|
||||
std::set<Path>::const_iterator i = expressionDeps.begin();
|
||||
while (i != expressionDeps.end()) {
|
||||
const Property * prop = (*i).getProperty();
|
||||
DocumentObject * docObj = prop ? freecad_dynamic_cast<DocumentObject>(prop->getContainer()) : 0;
|
||||
Document * doc = docObj ? docObj->getDocument() : 0;
|
||||
const Property * prop = i->getProperty();
|
||||
const DocumentObject * docObj = i->getDocumentObject();
|
||||
Document * doc = i->getDocument();
|
||||
|
||||
std::string docName = doc ? doc->Label.getValue() : (*i).getDocumentName().getString();
|
||||
std::string docObjName = docName + "#" + (docObj ? docObj->getNameInDocument() : (*i).getDocumentObjectName().getString());
|
||||
std::string propName = docObjName + "." + (*i).getPropertyName();
|
||||
std::string docName = doc ? doc->Label.getValue() : i->getDocumentName().getString();
|
||||
std::string docObjName = docName + "#" + (docObj ? docObj->getNameInDocument() : i->getDocumentObjectName().getString());
|
||||
std::string propName = docObjName + "." + i->getPropertyName();
|
||||
|
||||
if (!prop)
|
||||
cell->setResolveException("Unresolved dependency");
|
||||
|
@ -857,6 +905,19 @@ void PropertySheet::addDependencies(CellAddress key)
|
|||
propertyNameToCellMap[propName].insert(key);
|
||||
cellToPropertyNameMap[key].insert(propName);
|
||||
|
||||
// Also an alias?
|
||||
if (docObj == owner) {
|
||||
std::map<std::string, CellAddress>::const_iterator j = revAliasProp.find(i->getPropertyName());
|
||||
|
||||
if (j != revAliasProp.end()) {
|
||||
propName = docObjName + "." + j->second.toString();
|
||||
|
||||
// Insert into maps
|
||||
propertyNameToCellMap[propName].insert(key);
|
||||
cellToPropertyNameMap[key].insert(propName);
|
||||
}
|
||||
}
|
||||
|
||||
documentObjectToCellMap[docObjName].insert(key);
|
||||
cellToDocumentObjectMap[key].insert(docObjName);
|
||||
|
||||
|
@ -874,50 +935,47 @@ void PropertySheet::addDependencies(CellAddress key)
|
|||
|
||||
void PropertySheet::removeDependencies(CellAddress key)
|
||||
{
|
||||
std::map<CellAddress, std::set< std::string > >::iterator i1 = cellToPropertyNameMap.find(key);
|
||||
std::set< std::string >::iterator j;
|
||||
|
||||
/* Remove from Property <-> Key maps */
|
||||
|
||||
if (i1 == cellToPropertyNameMap.end())
|
||||
return;
|
||||
std::map<CellAddress, std::set< std::string > >::iterator i1 = cellToPropertyNameMap.find(key);
|
||||
|
||||
j = i1->second.begin();
|
||||
if (i1 != cellToPropertyNameMap.end()) {
|
||||
std::set< std::string >::const_iterator j = i1->second.begin();
|
||||
|
||||
while (j != i1->second.end()) {
|
||||
std::map<std::string, std::set< CellAddress > >::iterator k = propertyNameToCellMap.find(*j);
|
||||
while (j != i1->second.end()) {
|
||||
std::map<std::string, std::set< CellAddress > >::iterator k = propertyNameToCellMap.find(*j);
|
||||
|
||||
assert(k != propertyNameToCellMap.end());
|
||||
assert(k != propertyNameToCellMap.end());
|
||||
|
||||
k->second.erase(key);
|
||||
++j;
|
||||
k->second.erase(key);
|
||||
++j;
|
||||
}
|
||||
|
||||
cellToPropertyNameMap.erase(i1);
|
||||
}
|
||||
|
||||
cellToPropertyNameMap.erase(i1);
|
||||
|
||||
/* Remove from DocumentObject <-> Key maps */
|
||||
|
||||
std::map<CellAddress, std::set< std::string > >::iterator i2 = cellToDocumentObjectMap.find(key);
|
||||
|
||||
if (i2 == cellToDocumentObjectMap.end())
|
||||
return;
|
||||
if (i2 != cellToDocumentObjectMap.end()) {
|
||||
std::set< std::string >::const_iterator j = i2->second.begin();
|
||||
|
||||
j = i2->second.begin();
|
||||
while (j != i2->second.end()) {
|
||||
std::map<std::string, std::set< CellAddress > >::iterator k = documentObjectToCellMap.find(*j);
|
||||
|
||||
while (j != i2->second.end()) {
|
||||
std::map<std::string, std::set< CellAddress > >::iterator k = documentObjectToCellMap.find(*j);
|
||||
assert(k != documentObjectToCellMap.end());
|
||||
|
||||
assert(k != documentObjectToCellMap.end());
|
||||
k->second.erase(key);
|
||||
|
||||
k->second.erase(key);
|
||||
if (k->second.size() == 0)
|
||||
documentObjectToCellMap.erase(*j);
|
||||
|
||||
if (k->second.size() == 0)
|
||||
documentObjectToCellMap.erase(*j);
|
||||
++j;
|
||||
}
|
||||
|
||||
++j;
|
||||
cellToDocumentObjectMap.erase(i2);
|
||||
}
|
||||
|
||||
cellToDocumentObjectMap.erase(i2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1028,6 +1086,11 @@ void PropertySheet::renamedDocument(const Document * doc)
|
|||
}
|
||||
}
|
||||
|
||||
void PropertySheet::documentSet()
|
||||
{
|
||||
documentName[owner->getDocument()] = owner->getDocument()->Label.getValue();
|
||||
}
|
||||
|
||||
void PropertySheet::recomputeDependants(const DocumentObject *docObj)
|
||||
{
|
||||
const char * docName = docObj->getDocument()->Label.getValue();
|
||||
|
|
|
@ -43,8 +43,6 @@ public:
|
|||
|
||||
PropertySheet(Sheet * _owner = 0);
|
||||
|
||||
PropertySheet(const PropertySheet & other);
|
||||
|
||||
~PropertySheet();
|
||||
|
||||
virtual Property *Copy(void) const;
|
||||
|
@ -145,8 +143,12 @@ public:
|
|||
|
||||
void renamedDocument(const App::Document *doc);
|
||||
|
||||
void documentSet();
|
||||
|
||||
private:
|
||||
|
||||
PropertySheet(const PropertySheet & other);
|
||||
|
||||
friend class Signaller;
|
||||
|
||||
friend class SheetObserver;
|
||||
|
@ -211,6 +213,12 @@ private:
|
|||
/* Name of documents, used for renaming */
|
||||
std::map<const App::Document*, std::string> documentName;
|
||||
|
||||
/* Mapping of cell position to alias property */
|
||||
std::map<CellAddress, std::string> aliasProp;
|
||||
|
||||
/* Mapping of alias property to cell position */
|
||||
std::map<std::string, CellAddress> revAliasProp;
|
||||
|
||||
int signalCounter;
|
||||
|
||||
Py::Object PythonObject;
|
||||
|
|
|
@ -66,6 +66,16 @@ Range::Range(int _row_begin, int _col_begin, int _row_end, int _col_end)
|
|||
{
|
||||
}
|
||||
|
||||
Range::Range(const CellAddress &from, const CellAddress &to)
|
||||
: row_curr(from.row())
|
||||
, col_curr(from.col())
|
||||
, row_begin(from.row())
|
||||
, col_begin(from.col())
|
||||
, row_end(to.row())
|
||||
, col_end(to.col())
|
||||
{
|
||||
}
|
||||
|
||||
bool Range::next()
|
||||
{
|
||||
if (row_curr < row_end) {
|
||||
|
|
|
@ -45,6 +45,8 @@ public:
|
|||
|
||||
Range(int _row_begin, int _col_begin, int _row_end, int _col_end);
|
||||
|
||||
Range(const CellAddress & from, const CellAddress & to);
|
||||
|
||||
bool next();
|
||||
|
||||
/** Current row */
|
||||
|
@ -60,17 +62,17 @@ public:
|
|||
inline CellAddress to() const { return CellAddress(row_end, col_end); }
|
||||
|
||||
/** Start of range as a string */
|
||||
inline std::string fromCellString() const { return addressToString(CellAddress(row_begin, col_begin)); }
|
||||
inline std::string fromCellString() const { return CellAddress(row_begin, col_begin).toString(); }
|
||||
|
||||
/** End of range as a string */
|
||||
inline std::string toCellString() const { return addressToString(CellAddress(row_end, col_end)); }
|
||||
inline std::string toCellString() const { return CellAddress(row_end, col_end).toString(); }
|
||||
|
||||
/** Current cell as a string */
|
||||
inline std::string address() const { return addressToString(CellAddress(row_curr, col_curr)); }
|
||||
inline std::string address() const { return CellAddress(row_curr, col_curr).toString(); }
|
||||
|
||||
/** The raneg as a string */
|
||||
inline std::string rangeString() const {
|
||||
return addressToString(CellAddress(row_begin, col_begin)) + ":" + addressToString(CellAddress(row_end, col_end));
|
||||
return CellAddress(row_begin, col_begin).toString() + ":" + CellAddress(row_end, col_end).toString();
|
||||
}
|
||||
|
||||
CellAddress operator*() const { return CellAddress(row_curr, col_curr); }
|
||||
|
|
|
@ -110,9 +110,15 @@ void Sheet::clearAll()
|
|||
props.removeDynamicProperty((*i).c_str());
|
||||
|
||||
propAddress.clear();
|
||||
cellErrors.clear();
|
||||
columnWidths.clear();
|
||||
rowHeights.clear();
|
||||
removedAliases.clear();
|
||||
docDeps.setValues(std::vector<DocumentObject*>());
|
||||
|
||||
for (ObserverMap::iterator i = observers.begin(); i != observers.end(); ++i)
|
||||
delete i->second;
|
||||
observers.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -315,19 +321,6 @@ Cell *Sheet::getNewCell(CellAddress address)
|
|||
return cell;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert given \a key address to string.
|
||||
*
|
||||
* @param key Address of cell.
|
||||
*
|
||||
* @returns Address given as a string.
|
||||
*/
|
||||
|
||||
std::string Sheet::toAddress(CellAddress key)
|
||||
{
|
||||
return Spreadsheet::addressToString(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cell given by \a address to \a contents.
|
||||
*
|
||||
|
@ -400,7 +393,7 @@ PyObject *Sheet::getPyObject(void)
|
|||
|
||||
Property * Sheet::getProperty(CellAddress key) const
|
||||
{
|
||||
return props.getDynamicPropertyByName(toAddress(key).c_str());
|
||||
return props.getDynamicPropertyByName(key.toString().c_str());
|
||||
}
|
||||
|
||||
Property * Sheet::getProperty(const char * addr) const
|
||||
|
@ -442,6 +435,22 @@ void Sheet::setPosition(CellAddress address)
|
|||
currColumn.purgeTouched();
|
||||
}
|
||||
|
||||
void Sheet::removeAliases()
|
||||
{
|
||||
std::map<CellAddress, std::string>::iterator i = removedAliases.begin();
|
||||
|
||||
while (i != removedAliases.end()) {
|
||||
props.removeDynamicProperty(i->second.c_str());
|
||||
++i;
|
||||
}
|
||||
removedAliases.clear();
|
||||
}
|
||||
|
||||
void Sheet::onSettingDocument()
|
||||
{
|
||||
cells.documentSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the property for cell \key to a PropertyFloat with the value \a value.
|
||||
* If the Property exists, but of wrong type, the previous Property is destroyed and recreated as the correct type.
|
||||
|
@ -453,21 +462,15 @@ void Sheet::setPosition(CellAddress address)
|
|||
|
||||
Property * Sheet::setFloatProperty(CellAddress key, double value)
|
||||
{
|
||||
Property * prop = props.getPropertyByName(toAddress(key).c_str());
|
||||
Property * prop = props.getPropertyByName(key.toString().c_str());
|
||||
PropertyFloat * floatProp;
|
||||
|
||||
if (!prop || prop->getTypeId() != PropertyFloat::getClassTypeId()) {
|
||||
if (prop) {
|
||||
props.removeDynamicProperty(toAddress(key).c_str());
|
||||
props.removeDynamicProperty(key.toString().c_str());
|
||||
propAddress.erase(prop);
|
||||
|
||||
std::map<CellAddress, App::Property*>::iterator i = aliasProp.find(key);
|
||||
if (i != aliasProp.end()) {
|
||||
props.removeDynamicProperty(props.getPropertyName(i->second));
|
||||
aliasProp.erase(i);
|
||||
}
|
||||
}
|
||||
floatProp = freecad_dynamic_cast<PropertyFloat>(props.addDynamicProperty("App::PropertyFloat", toAddress(key).c_str(), 0, 0, Prop_ReadOnly | Prop_Transient, true, true));
|
||||
floatProp = freecad_dynamic_cast<PropertyFloat>(props.addDynamicProperty("App::PropertyFloat", key.toString().c_str(), 0, 0, Prop_ReadOnly | Prop_Transient, true, true));
|
||||
floatProp->StatusBits.set(3);
|
||||
}
|
||||
else
|
||||
|
@ -491,26 +494,20 @@ Property * Sheet::setFloatProperty(CellAddress key, double value)
|
|||
|
||||
Property * Sheet::setQuantityProperty(CellAddress key, double value, const Base::Unit & unit)
|
||||
{
|
||||
Property * prop = props.getPropertyByName(toAddress(key).c_str());
|
||||
PropertyQuantity * quantityProp;
|
||||
Property * prop = props.getPropertyByName(key.toString().c_str());
|
||||
PropertySpreadsheetQuantity * quantityProp;
|
||||
|
||||
if (!prop || prop->getTypeId() != PropertyQuantity::getClassTypeId()) {
|
||||
if (!prop || prop->getTypeId() != PropertySpreadsheetQuantity::getClassTypeId()) {
|
||||
if (prop) {
|
||||
props.removeDynamicProperty(toAddress(key).c_str());
|
||||
props.removeDynamicProperty(key.toString().c_str());
|
||||
propAddress.erase(prop);
|
||||
|
||||
std::map<CellAddress, App::Property*>::iterator i = aliasProp.find(key);
|
||||
if (i != aliasProp.end()) {
|
||||
props.removeDynamicProperty(props.getPropertyName(i->second));
|
||||
aliasProp.erase(i);
|
||||
}
|
||||
}
|
||||
Property * p = props.addDynamicProperty("App::PropertyQuantity", toAddress(key).c_str(), 0, 0, Prop_ReadOnly | Prop_Transient, true, true);
|
||||
quantityProp = freecad_dynamic_cast<PropertyQuantity>(p);
|
||||
Property * p = props.addDynamicProperty("Spreadsheet::PropertySpreadsheetQuantity", key.toString().c_str(), 0, 0, Prop_ReadOnly | Prop_Transient, true, true);
|
||||
quantityProp = freecad_dynamic_cast<PropertySpreadsheetQuantity>(p);
|
||||
quantityProp->StatusBits.set(3);
|
||||
}
|
||||
else
|
||||
quantityProp = static_cast<PropertyQuantity*>(prop);
|
||||
quantityProp = static_cast<PropertySpreadsheetQuantity*>(prop);
|
||||
|
||||
propAddress[quantityProp] = key;
|
||||
quantityProp->setValue(value);
|
||||
|
@ -532,21 +529,15 @@ Property * Sheet::setQuantityProperty(CellAddress key, double value, const Base:
|
|||
|
||||
Property * Sheet::setStringProperty(CellAddress key, const std::string & value)
|
||||
{
|
||||
Property * prop = props.getPropertyByName(toAddress(key).c_str());
|
||||
Property * prop = props.getPropertyByName(key.toString().c_str());
|
||||
PropertyString * stringProp = freecad_dynamic_cast<PropertyString>(prop);
|
||||
|
||||
if (!stringProp) {
|
||||
if (prop) {
|
||||
props.removeDynamicProperty(toAddress(key).c_str());
|
||||
props.removeDynamicProperty(key.toString().c_str());
|
||||
propAddress.erase(prop);
|
||||
|
||||
std::map<CellAddress, App::Property*>::iterator i = aliasProp.find(key);
|
||||
if (i != aliasProp.end()) {
|
||||
props.removeDynamicProperty(props.getPropertyName(i->second));
|
||||
aliasProp.erase(i);
|
||||
}
|
||||
}
|
||||
stringProp = freecad_dynamic_cast<PropertyString>(props.addDynamicProperty("App::PropertyString", toAddress(key).c_str(), 0, 0, Prop_ReadOnly | Prop_Transient, true, true));
|
||||
stringProp = freecad_dynamic_cast<PropertyString>(props.addDynamicProperty("App::PropertyString", key.toString().c_str(), 0, 0, Prop_ReadOnly | Prop_Transient, true, true));
|
||||
stringProp->StatusBits.set(3);
|
||||
}
|
||||
|
||||
|
@ -556,6 +547,35 @@ Property * Sheet::setStringProperty(CellAddress key, const std::string & value)
|
|||
return stringProp;
|
||||
}
|
||||
|
||||
void Sheet::updateAlias(CellAddress key)
|
||||
{
|
||||
std::string alias;
|
||||
Property * prop = props.getDynamicPropertyByName(key.toString().c_str());
|
||||
|
||||
if (!prop)
|
||||
return;
|
||||
|
||||
Cell * cell = getCell(key);
|
||||
|
||||
if (cell && cell->getAlias(alias)) {
|
||||
App::Property * aliasProp = props.getDynamicPropertyByName(alias.c_str());
|
||||
|
||||
/* Update or create alias? */
|
||||
if (aliasProp) {
|
||||
// Type of alias and property must always be the same
|
||||
if (aliasProp->getTypeId() != prop->getTypeId()) {
|
||||
props.removeDynamicProperty(alias.c_str());
|
||||
aliasProp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!aliasProp)
|
||||
aliasProp = props.addDynamicProperty(prop->getTypeId().getName(), alias.c_str(), 0, 0, Prop_ReadOnly | Prop_Transient, true, true);
|
||||
|
||||
aliasProp->Paste(*prop);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the Propery given by \a key. This will also eventually trigger recomputations of cells depending on \a key.
|
||||
*
|
||||
|
@ -566,10 +586,8 @@ Property * Sheet::setStringProperty(CellAddress key, const std::string & value)
|
|||
void Sheet::updateProperty(CellAddress key)
|
||||
{
|
||||
const Property * prop;
|
||||
const char * aliasType = 0;
|
||||
|
||||
Cell * cell = getCell(key);
|
||||
std::string alias;
|
||||
|
||||
if (cell != 0) {
|
||||
Expression * output;
|
||||
|
@ -590,40 +608,19 @@ void Sheet::updateProperty(CellAddress key)
|
|||
/* Eval returns either NumberExpression or StringExpression objects */
|
||||
if (freecad_dynamic_cast<NumberExpression>(output)) {
|
||||
NumberExpression * number = static_cast<NumberExpression*>(output);
|
||||
if (number->getUnit().isEmpty()) {
|
||||
if (number->getUnit().isEmpty())
|
||||
prop = setFloatProperty(key, number->getValue());
|
||||
aliasType = "App::PropertyFloat";
|
||||
}
|
||||
else {
|
||||
else
|
||||
prop = setQuantityProperty(key, number->getValue(), number->getUnit());
|
||||
aliasType = "App::PropertyQuantity";
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
prop = setStringProperty(key, freecad_dynamic_cast<StringExpression>(output)->getText().c_str());
|
||||
aliasType = "App::PropertyString";
|
||||
}
|
||||
|
||||
delete output;
|
||||
}
|
||||
else
|
||||
clear(key);
|
||||
|
||||
if (cell && cell->getAlias(alias)) {
|
||||
/* Update or create alias? */
|
||||
if (aliasProp.find(key) == aliasProp.end())
|
||||
aliasProp[key] = props.addDynamicProperty(aliasType, alias.c_str(), 0, 0, Prop_ReadOnly | Prop_Transient, true, true);
|
||||
aliasProp[key]->Paste(*prop);
|
||||
}
|
||||
else {
|
||||
/* Remove alias? */
|
||||
std::map<CellAddress, App::Property*>::iterator i = aliasProp.find(key);
|
||||
if (i != aliasProp.end()) {
|
||||
props.removeDynamicProperty(props.getPropertyName(i->second));
|
||||
aliasProp.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
cellUpdated(key);
|
||||
}
|
||||
|
||||
|
@ -661,7 +658,7 @@ void Sheet::recomputeCell(CellAddress p)
|
|||
Cell * cell = cells.getValue(p);
|
||||
std::string docName = getDocument()->Label.getValue();
|
||||
std::string docObjName = std::string(getNameInDocument());
|
||||
std::string name = docName + "#" + docObjName + "." + toAddress(p);
|
||||
std::string name = docName + "#" + docObjName + "." + p.toString();
|
||||
|
||||
try {
|
||||
if (cell) {
|
||||
|
@ -683,6 +680,8 @@ void Sheet::recomputeCell(CellAddress p)
|
|||
cellErrors.insert(p);
|
||||
}
|
||||
|
||||
updateAlias(p);
|
||||
|
||||
if (!cell || cell->spansChanged())
|
||||
cellSpanChanged(p);
|
||||
}
|
||||
|
@ -694,6 +693,9 @@ void Sheet::recomputeCell(CellAddress p)
|
|||
|
||||
App::DocumentObjectExecReturn *Sheet::execute(void)
|
||||
{
|
||||
// Remove all aliases first
|
||||
removeAliases();
|
||||
|
||||
// Get dirty cells that we have to recompute
|
||||
std::set<CellAddress> dirtyCells = cells.getDirty();
|
||||
|
||||
|
@ -769,6 +771,8 @@ App::DocumentObjectExecReturn *Sheet::execute(void)
|
|||
if (cell)
|
||||
cell->setException("Circular dependency.");
|
||||
updateProperty(i->first);
|
||||
updateAlias(i->first);
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
@ -797,6 +801,10 @@ App::DocumentObjectExecReturn *Sheet::execute(void)
|
|||
currColumn.purgeTouched();
|
||||
|
||||
std::set<App::DocumentObject*> ds(cells.getDocDeps());
|
||||
|
||||
// Make sure we don't reference ourselves
|
||||
ds.erase(this);
|
||||
|
||||
std::vector<App::DocumentObject*> dv(ds.begin(), ds.end());
|
||||
docDeps.setValues(dv);
|
||||
|
||||
|
@ -837,9 +845,15 @@ short Sheet::mustExecute(void) const
|
|||
|
||||
void Sheet::clear(CellAddress address, bool all)
|
||||
{
|
||||
std::string addr = toAddress(address);
|
||||
Cell * cell = getCell(address);
|
||||
std::string addr = address.toString();
|
||||
Property * prop = props.getDynamicPropertyByName(addr.c_str());
|
||||
|
||||
// Remove alias, if defined
|
||||
std::string aliasStr;
|
||||
if (cell && cell->getAlias(aliasStr))
|
||||
props.removeDynamicProperty(aliasStr.c_str());
|
||||
|
||||
cells.clear(address);
|
||||
|
||||
propAddress.erase(prop);
|
||||
|
@ -911,7 +925,7 @@ std::vector<std::string> Sheet::getUsedCells() const
|
|||
std::set<CellAddress> usedSet = cells.getUsedCells();
|
||||
|
||||
for (std::set<CellAddress>::const_iterator i = usedSet.begin(); i != usedSet.end(); ++i)
|
||||
usedCells.push_back(toAddress(*i));
|
||||
usedCells.push_back(i->toString());
|
||||
|
||||
return usedCells;
|
||||
}
|
||||
|
@ -1031,6 +1045,11 @@ void Sheet::renamedDocumentObject(const App::DocumentObject * docObj)
|
|||
cells.touch();
|
||||
}
|
||||
|
||||
void Sheet::aliasRemoved(CellAddress address, const std::string & alias)
|
||||
{
|
||||
removedAliases[address] = alias;
|
||||
}
|
||||
|
||||
std::set<std::string> Sheet::dependsOn(CellAddress address) const
|
||||
{
|
||||
return cells.getDeps(address);
|
||||
|
@ -1040,18 +1059,18 @@ void Sheet::providesTo(CellAddress address, std::set<std::string> & result) cons
|
|||
{
|
||||
const char * docName = getDocument()->Label.getValue();
|
||||
const char * docObjName = getNameInDocument();
|
||||
std::string fullName = std::string(docName) + "#" + std::string(docObjName) + "." + toAddress(address);
|
||||
std::string fullName = std::string(docName) + "#" + std::string(docObjName) + "." + address.toString();
|
||||
std::set<CellAddress> tmpResult = cells.getDeps(fullName);
|
||||
|
||||
for (std::set<CellAddress>::const_iterator i = tmpResult.begin(); i != tmpResult.end(); ++i)
|
||||
result.insert(std::string(docName) + "#" + std::string(docObjName) + "." + toAddress(*i));
|
||||
result.insert(std::string(docName) + "#" + std::string(docObjName) + "." + i->toString());
|
||||
}
|
||||
|
||||
void Sheet::providesTo(CellAddress address, std::set<CellAddress> & result) const
|
||||
{
|
||||
const char * docName = getDocument()->Label.getValue();
|
||||
const char * docObjName = getNameInDocument();
|
||||
std::string fullName = std::string(docName) + "#" + std::string(docObjName) + "." + toAddress(address);
|
||||
std::string fullName = std::string(docName) + "#" + std::string(docObjName) + "." + address.toString();
|
||||
result = cells.getDeps(fullName);
|
||||
}
|
||||
|
||||
|
@ -1086,3 +1105,23 @@ void Sheet::observeDocument(Document * document)
|
|||
observers[document->getName()] = observer;
|
||||
}
|
||||
}
|
||||
|
||||
TYPESYSTEM_SOURCE(Spreadsheet::PropertySpreadsheetQuantity, App::PropertyQuantity);
|
||||
|
||||
Property *PropertySpreadsheetQuantity::Copy() const
|
||||
{
|
||||
PropertySpreadsheetQuantity * obj = new PropertySpreadsheetQuantity();
|
||||
|
||||
obj->_dValue = _dValue;
|
||||
obj->_Unit = _Unit;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
void PropertySpreadsheetQuantity::Paste(const Property &from)
|
||||
{
|
||||
aboutToSetValue();
|
||||
_dValue = static_cast<const PropertySpreadsheetQuantity*>(&from)->_dValue;
|
||||
_Unit = static_cast<const PropertySpreadsheetQuantity*>(&from)->_Unit;
|
||||
hasSetValue();
|
||||
}
|
||||
|
|
|
@ -52,10 +52,25 @@ class Expression;
|
|||
class Range;
|
||||
class SheetObserver;
|
||||
|
||||
/** Spreadsheet quantity property
|
||||
* This is a property for quantities, and unlike its ancestor implements
|
||||
* Copy() and Paste() methods. It is used by the spreadsheet to
|
||||
* create aliases in a generic way.
|
||||
*/
|
||||
class SpreadsheetExport PropertySpreadsheetQuantity : public App::PropertyQuantity
|
||||
{
|
||||
TYPESYSTEM_HEADER();
|
||||
public:
|
||||
PropertySpreadsheetQuantity(void){}
|
||||
virtual ~PropertySpreadsheetQuantity(){}
|
||||
|
||||
virtual Property *Copy(void) const;
|
||||
virtual void Paste(const Property &from);
|
||||
};
|
||||
|
||||
class SpreadsheetExport Sheet : public App::DocumentObject
|
||||
{
|
||||
PROPERTY_HEADER(Sheet::Sheet);
|
||||
PROPERTY_HEADER(Spreadsheet::Sheet);
|
||||
|
||||
public:
|
||||
|
||||
|
@ -220,6 +235,8 @@ protected:
|
|||
|
||||
App::Property *getProperty(const char * addr) const;
|
||||
|
||||
void updateAlias(CellAddress key);
|
||||
|
||||
void updateProperty(CellAddress key);
|
||||
|
||||
App::Property *setStringProperty(CellAddress key, const std::string & value) ;
|
||||
|
@ -228,20 +245,24 @@ protected:
|
|||
|
||||
App::Property *setQuantityProperty(CellAddress key, double value, const Base::Unit &unit);
|
||||
|
||||
static std::string toAddress(CellAddress key);
|
||||
|
||||
void moveCell(CellAddress currPos, CellAddress newPos);
|
||||
|
||||
void renamedDocumentObject(const App::DocumentObject * docObj);
|
||||
|
||||
void aliasRemoved(CellAddress address, const std::string &alias);
|
||||
|
||||
void removeAliases();
|
||||
|
||||
virtual void onSettingDocument();
|
||||
|
||||
/* Properties for used cells */
|
||||
App::DynamicProperty props;
|
||||
|
||||
/* Mapping of properties to cell position */
|
||||
std::map<const App::Property*, CellAddress > propAddress;
|
||||
|
||||
/* Mapping of cell position to alias property */
|
||||
std::map<CellAddress, App::Property*> aliasProp;
|
||||
/* Removed (unprocessed) aliases */
|
||||
std::map<CellAddress, std::string> removedAliases;
|
||||
|
||||
/* Set of cells with errors */
|
||||
std::set<CellAddress> cellErrors;
|
||||
|
|
|
@ -161,33 +161,6 @@ Spreadsheet::CellAddress Spreadsheet::stringToAddress(const char * strAddress)
|
|||
throw Base::Exception("Invalid cell specifier.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert given \a row and \a col into a string address.
|
||||
*
|
||||
* @param row Row address.
|
||||
* @param col Column address.
|
||||
*
|
||||
* @returns Address given as a string.
|
||||
*/
|
||||
|
||||
std::string Spreadsheet::addressToString(const CellAddress &address)
|
||||
{
|
||||
std::stringstream s;
|
||||
|
||||
if (address.col() < 26)
|
||||
s << (char)('A' + address.col());
|
||||
else {
|
||||
int col = address.col() - 26;
|
||||
|
||||
s << (char)('A' + (col / 26));
|
||||
s << (char)('A' + (col % 26));
|
||||
}
|
||||
|
||||
s << (address.row() + 1);
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
void Spreadsheet::createRectangles(std::set<std::pair<int, int> > & cells, std::map<std::pair<int, int>, std::pair<int, int> > & rectangles)
|
||||
{
|
||||
while (cells.size() != 0) {
|
||||
|
@ -342,3 +315,28 @@ std::string Spreadsheet::unquote(const std::string & input)
|
|||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert given \a cell address into its string representation.
|
||||
*
|
||||
* @returns Address given as a string.
|
||||
*/
|
||||
|
||||
std::string Spreadsheet::CellAddress::toString() const
|
||||
{
|
||||
std::stringstream s;
|
||||
|
||||
if (col() < 26)
|
||||
s << (char)('A' + col());
|
||||
else {
|
||||
int colnum = col() - 26;
|
||||
|
||||
s << (char)('A' + (colnum / 26));
|
||||
s << (char)('A' + (colnum % 26));
|
||||
}
|
||||
|
||||
s << (row() + 1);
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
|
|
@ -42,12 +42,9 @@ SpreadsheetExport void createRectangles(std::set<std::pair<int, int> > & cells,
|
|||
SpreadsheetExport std::string quote(const std::string &input);
|
||||
SpreadsheetExport std::string unquote(const std::string & input);
|
||||
|
||||
SpreadsheetExport std::string addressToString(const CellAddress & address);
|
||||
struct SpreadsheetExport CellAddress {
|
||||
|
||||
struct CellAddress {
|
||||
CellAddress(unsigned int _value) : value(_value) { }
|
||||
|
||||
CellAddress(int row = -1, int col = -1) : value(((row & 0xffff) << 16) | (col & 0xffff)) { }
|
||||
CellAddress(int row = -1, int col = -1) : _row(row), _col(col) { }
|
||||
|
||||
CellAddress(const char * address) {
|
||||
*this = stringToAddress(address);
|
||||
|
@ -57,18 +54,20 @@ struct CellAddress {
|
|||
*this = stringToAddress(address.c_str());
|
||||
}
|
||||
|
||||
inline int row() const { return (value >> 16) & 0xffff; }
|
||||
inline int row() const { return _row; }
|
||||
|
||||
inline int col() const { return value & 0xffff; }
|
||||
inline int col() const { return _col; }
|
||||
|
||||
inline bool operator<(const CellAddress & other) const { return value < other.value; }
|
||||
inline bool operator<(const CellAddress & other) const { return asInt() < other.asInt(); }
|
||||
|
||||
inline bool operator==(const CellAddress & other) const { return value == other.value; }
|
||||
inline bool operator==(const CellAddress & other) const { return asInt() == other.asInt(); }
|
||||
|
||||
inline bool operator!=(const CellAddress & other) const { return value != other.value; }
|
||||
inline bool operator!=(const CellAddress & other) const { return asInt() != other.asInt(); }
|
||||
|
||||
inline bool isValid() { return (row() >=0 && row() < MAX_ROWS && col() >= 0 && col() < MAX_COLUMNS); }
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
// Static members
|
||||
|
||||
static const int MAX_ROWS;
|
||||
|
@ -76,7 +75,11 @@ struct CellAddress {
|
|||
static const int MAX_COLUMNS;
|
||||
|
||||
protected:
|
||||
unsigned int value;
|
||||
|
||||
inline unsigned int asInt() const { return ((_row << 16) | _col); }
|
||||
|
||||
short _row;
|
||||
short _col;
|
||||
};
|
||||
|
||||
template<typename T> T * freecad_dynamic_cast(Base::BaseClass * t)
|
||||
|
|
|
@ -125,7 +125,7 @@ void CmdSpreadsheetSplitCell::activated(int iMsg)
|
|||
QModelIndex current = sheetView->currentIndex();
|
||||
|
||||
if (current.isValid()) {
|
||||
std::string address = addressToString(CellAddress(current.row(), current.column()));
|
||||
std::string address = CellAddress(current.row(), current.column()).toString();
|
||||
Gui::Command::openCommand("Split cell");
|
||||
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.splitCell('%s')", sheet->getNameInDocument(),
|
||||
address.c_str());
|
||||
|
|
|
@ -147,10 +147,10 @@ QVariant SheetModel::data(const QModelIndex &index, int role) const
|
|||
if (role == Qt::ToolTipRole) {
|
||||
QString v;
|
||||
|
||||
std::set<std::string> deps = sheet->dependsOn(row, col);
|
||||
std::set<std::string> deps = sheet->dependsOn(CellAddress(row, col));
|
||||
std::set<std::string> provides;
|
||||
|
||||
sheet->providesTo(row, col, provides);
|
||||
sheet->providesTo(CellAddress(row, col), provides);
|
||||
|
||||
if (deps.size() > 0) {
|
||||
v += QString::fromUtf8("Depends on:");
|
||||
|
@ -196,7 +196,7 @@ QVariant SheetModel::data(const QModelIndex &index, int role) const
|
|||
}
|
||||
|
||||
// Get display value as computed property
|
||||
std::string address = addressToString(CellAddress(row, col));
|
||||
std::string address = CellAddress(row, col).toString();
|
||||
Property * prop = sheet->getPropertyByName(address.c_str());
|
||||
|
||||
if (prop == 0)
|
||||
|
@ -394,8 +394,8 @@ bool SheetModel::setData(const QModelIndex & index, const QVariant & value, int
|
|||
CellAddress address(index.row(), index.column());
|
||||
|
||||
try {
|
||||
std::string strAddress = addressToString(address);
|
||||
std::string next_address = addressToString(CellAddress(address.row() + 1, address.col()));
|
||||
std::string strAddress = address.toString();
|
||||
std::string next_address = CellAddress(address.row() + 1, address.col()).toString();
|
||||
QString str = value.toString();
|
||||
std::string content;
|
||||
Cell * cell = sheet->getCell(address);
|
||||
|
|
|
@ -158,7 +158,7 @@ bool ViewProviderSheet::onDelete(const std::vector<std::string> &)
|
|||
if (selection.size() > 0) {
|
||||
Gui::Command::openCommand("Clear cell(s)");
|
||||
for (QModelIndexList::const_iterator it = selection.begin(); it != selection.end(); ++it) {
|
||||
std::string address = Spreadsheet::addressToString(CellAddress((*it).row(), (*it).column()));
|
||||
std::string address = CellAddress((*it).row(), (*it).column()).toString();
|
||||
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.clear('%s')", sheet->getNameInDocument(),
|
||||
address.c_str());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user