Skip to content

Commit

Permalink
Spreadsheet: change PropertySheet to be based on PropertyLinkBase
Browse files Browse the repository at this point in the history
PropertySheet is now derived from PropertyLinkBase, and implements all
link related APIs to support import/export, label and geometry
reference auto update, and auto link tear down on delete.
  • Loading branch information
realthunder committed Oct 14, 2018
1 parent 649dc5d commit f24cfd8
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 90 deletions.
1 change: 1 addition & 0 deletions src/Mod/Part/TestPartApp.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ def testIssue2671(self):
Box = self.Doc.addObject("Part::Box","Box")
Mirroring = self.Doc.addObject("Part::Mirroring", 'Mirroring')
Spreadsheet = self.Doc.addObject('Spreadsheet::Sheet', 'Spreadsheet')
Mirroring.Source = Box
Mirroring.Base = (8, 5, 25)
Mirroring.Normal = (0.5, 0.2, 0.9)
Spreadsheet.set('A1', '=Mirroring.Base.x')
Expand Down
17 changes: 13 additions & 4 deletions src/Mod/Spreadsheet/App/Cell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,6 @@ void Cell::setExpression(App::Expression *expr)

/* Update dependencies */
owner->addDependencies(address);

owner->rebuildDocDepList();
}

/**
Expand All @@ -185,7 +183,7 @@ const App::Expression *Cell::getExpression() const
*
*/

bool Cell::getStringContent(std::string & s) const
bool Cell::getStringContent(std::string & s, bool persistent) const
{
if (expression) {
auto sexpr = freecad_dynamic_cast<App::StringExpression>(expression);
Expand All @@ -206,7 +204,7 @@ bool Cell::getStringContent(std::string & s) const
else if (freecad_dynamic_cast<App::NumberExpression>(expression))
s = expression->toString();
else
s = "=" + expression->toString();
s = "=" + expression->toString(persistent);

return true;
}
Expand All @@ -216,13 +214,24 @@ bool Cell::getStringContent(std::string & s) const
}
}

void Cell::afterRestore() {
auto expr = dynamic_cast<StringExpression*>(expression);
if(expr)
setContent(expr->getText().c_str());
}

void Cell::setContent(const char * value)
{
PropertySheet::AtomicPropertyChange signaller(*owner);
App::Expression * expr = 0;

setUsed(PARSE_EXCEPTION_SET, false);
if (value != 0) {
if(owner->sheet()->isRestoring()) {
expression = new StringExpression(owner->sheet(),value);
setUsed(EXPRESSION_SET, true);
return;
}
if (*value == '=') {
try {
expr = App::ExpressionParser::parse(owner->sheet(), value + 1);
Expand Down
6 changes: 5 additions & 1 deletion src/Mod/Spreadsheet/App/Cell.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class SpreadsheetExport Cell {

const App::Expression * getExpression() const;

bool getStringContent(std::string & s) const;
bool getStringContent(std::string & s, bool persistent=false) const;

void setContent(const char * value);

Expand Down Expand Up @@ -107,6 +107,8 @@ class SpreadsheetExport Cell {

void restore(Base::XMLReader &reader);

void afterRestore();

void save(Base::Writer &writer) const;

bool isUsed() const;
Expand Down Expand Up @@ -190,6 +192,8 @@ class SpreadsheetExport Cell {
int colSpan;
std::string exceptionStr;
App::CellAddress anchor;

friend class PropertySheet;
};

}
Expand Down
194 changes: 164 additions & 30 deletions src/Mod/Spreadsheet/App/PropertySheet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ using namespace App;
using namespace Base;
using namespace Spreadsheet;

TYPESYSTEM_SOURCE(Spreadsheet::PropertySheet , App::Property);
TYPESYSTEM_SOURCE(Spreadsheet::PropertySheet , App::PropertyLinkBase);

void PropertySheet::clear()
{
Expand All @@ -66,7 +66,15 @@ void PropertySheet::clear()

propertyNameToCellMap.clear();
documentObjectToCellMap.clear();

if(getContainer()==owner && owner && owner->getNameInDocument()) {
for(auto obj : docDeps) {
if(obj && obj->getNameInDocument())
obj->_removeBackLink(owner);
}
}
docDeps.clear();

aliasProp.clear();
revAliasProp.clear();
}
Expand Down Expand Up @@ -167,27 +175,24 @@ Cell * PropertySheet::createCell(CellAddress address)
}

PropertySheet::PropertySheet(Sheet *_owner)
: Property()
, AtomicPropertyChangeInterface()
, owner(_owner)
: owner(_owner)
, updateCount(0)
{
}

PropertySheet::PropertySheet(const PropertySheet &other)
: Property()
, AtomicPropertyChangeInterface()
, dirty(other.dirty)
: dirty(other.dirty)
, mergedCells(other.mergedCells)
, owner(other.owner)
, propertyNameToCellMap(other.propertyNameToCellMap)
, cellToPropertyNameMap(other.cellToPropertyNameMap)
, documentObjectToCellMap(other.documentObjectToCellMap)
, cellToDocumentObjectMap(other.cellToDocumentObjectMap)
, docDeps(other.docDeps)
, documentObjectName(other.documentObjectName)
, documentName(other.documentName)
, aliasProp(other.aliasProp)
, revAliasProp(other.revAliasProp)
, updateCount(other.updateCount)
{
std::map<CellAddress, Cell* >::const_iterator i = other.data.begin();

Expand Down Expand Up @@ -504,8 +509,6 @@ void PropertySheet::clear(CellAddress address)

// Erase from internal struct
data.erase(i);

rebuildDocDepList();
}

void PropertySheet::moveCell(CellAddress currPos, CellAddress newPos, std::map<App::ObjectIdentifier, App::ObjectIdentifier> & renames)
Expand Down Expand Up @@ -549,8 +552,6 @@ void PropertySheet::moveCell(CellAddress currPos, CellAddress newPos, std::map<A
setDirty(newPos);

renames[ObjectIdentifier(owner, currPos.toString())] = ObjectIdentifier(owner, newPos.toString());

rebuildDocDepList();
}
}

Expand Down Expand Up @@ -925,13 +926,13 @@ void PropertySheet::addDependencies(CellAddress key)
std::string docName = doc->Label.getValue();
std::string docObjName = docName + "#" + docObj->getNameInDocument();

documentObjectName[docObj] = docObj->Label.getValue();
documentName[doc] = docName;

owner->observeDocument(doc);

documentObjectToCellMap[docObjName].insert(key);
cellToDocumentObjectMap[key].insert(docObjName);
++updateCount;

for(auto &props : dep.second) {
std::string propName = docObjName + "." + props.first;
Expand Down Expand Up @@ -1006,6 +1007,7 @@ void PropertySheet::removeDependencies(CellAddress key)
}

cellToDocumentObjectMap.erase(i2);
++updateCount;
}
}

Expand Down Expand Up @@ -1078,6 +1080,9 @@ void PropertySheet::invalidateDependants(const App::DocumentObject *docObj)

void PropertySheet::renamedDocumentObject(const App::DocumentObject * docObj)
{
#if 1
(void)docObj;
#else
if (documentObjectName.find(docObj) == documentObjectName.end())
return;
Expand All @@ -1092,6 +1097,7 @@ void PropertySheet::renamedDocumentObject(const App::DocumentObject * docObj)
}
++i;
}
#endif
}

void PropertySheet::renamedDocument(const App::Document * doc)
Expand Down Expand Up @@ -1158,18 +1164,52 @@ void PropertySheet::recomputeDependencies(CellAddress key)

removeDependencies(key);
addDependencies(key);
rebuildDocDepList();
}

void PropertySheet::rebuildDocDepList()
void PropertySheet::hasSetValue()
{
AtomicPropertyChange signaller(*this);

docDeps.clear();
for(auto &v : data) {
if(v.second->getExpression())
v.second->getExpression()->getDepObjects(docDeps);
if(!updateCount ||
!owner || !owner->getNameInDocument() || owner->isRestoring() ||
this!=&owner->cells)
{
PropertyLinkBase::hasSetValue();
return;
}
updateCount = 0;

std::set<App::DocumentObject*> deps;
std::vector<std::string> labels;
unregisterElementReference();
UpdateElementReferenceExpressionVisitor<PropertySheet> v(*this);
for(auto &d : data) {
auto expr = d.second->expression;
if(expr) {
expr->getDepObjects(deps,&labels);
expr->visit(v);
}
}
registerLabelReferences(labels);

deps.erase(owner);

#ifndef USE_OLD_DAG
for(auto obj : deps) {
if(obj && obj->getNameInDocument()) {
auto it = docDeps.find(obj);
if(it == docDeps.end())
obj->_addBackLink(owner);
else
docDeps.erase(it);
}
}
for(auto obj : docDeps) {
if(obj && obj->getNameInDocument())
obj->_removeBackLink(owner);
}
#endif
docDeps.swap(deps);

PropertyLinkBase::hasSetValue();
}

PyObject *PropertySheet::getPyObject()
Expand All @@ -1181,16 +1221,110 @@ PyObject *PropertySheet::getPyObject()
return Py::new_reference_to(PythonObject);
}

void PropertySheet::resolveAll()
void PropertySheet::afterRestore()
{
std::map<CellAddress, Cell* >::iterator i = data.begin();

/* Resolve all cells */
AtomicPropertyChange signaller(*this);
while (i != data.end()) {
recomputeDependencies(i->first);
setDirty(i->first);
++i;
for(auto &d : data)
d.second->afterRestore();
}

void PropertySheet::breakLink(App::DocumentObject *obj, bool) {
invalidateDependants(obj);
deletedDocumentObject(obj);
}

bool PropertySheet::adjustLink(const std::set<DocumentObject*> &inList) {
std::unique_ptr<AtomicPropertyChange> signaler;

for(auto &d : data) {
auto expr = d.second->expression;
if(!expr)
continue;
try {
bool need_adjust = false;
for(auto docObj : expr->getDepObjects()) {
if (docObj && docObj != owner && inList.count(docObj)) {
need_adjust = true;
break;
}
}
if(!need_adjust)
continue;
if(!signaler)
signaler.reset(new AtomicPropertyChange(*this));

removeDependencies(d.first);
expr->adjustLinks(inList);
addDependencies(d.first);

}catch(Base::Exception &e) {
addDependencies(d.first);
std::ostringstream ss;
ss << "Failed to adjust link for " << owner->getFullName() << " in expression "
<< expr->toString() << ": " << e.what();
throw Base::RuntimeError(ss.str());
}
}
touch();
return !!signaler;
}

void PropertySheet::updateElementReference(DocumentObject *feature,bool reverse) {
unregisterElementReference();
UpdateElementReferenceExpressionVisitor<PropertySheet> visitor(*this,feature,reverse);
for(auto &d : data) {
auto expr = d.second->expression;
if(!expr)
continue;
expr->visit(visitor);
}
}

bool PropertySheet::referenceChanged() const {
return false;
}

void PropertySheet::getLinks(std::vector<App::DocumentObject *> &objs,
bool, std::vector<std::string> * /*subs*/, bool /*newStyle*/) const
{
objs.insert(objs.end(),docDeps.begin(),docDeps.end());
}

Property *PropertySheet::CopyOnImportExternal(
const std::map<std::string,std::string> &nameMap) const
{
std::map<CellAddress,std::unique_ptr<Expression> > changed;
for(auto &d : data) {
auto expr = d.second->expression;
if(expr)
expr = expr->importSubNames(nameMap);
if(!expr)
continue;
changed[d.first].reset(expr);
}
if(changed.empty())
return 0;
std::unique_ptr<PropertySheet> copy(new PropertySheet(*this));
for(auto &change : changed)
copy->data[change.first]->setExpression(change.second.release());
return copy.release();
}

Property *PropertySheet::CopyOnLabelChange(App::DocumentObject *obj,
const std::string &ref, const char *newLabel) const
{
std::map<CellAddress,std::unique_ptr<Expression> > changed;
for(auto &d : data) {
auto expr = d.second->expression;
if(expr)
expr = expr->updateLabelReference(obj,ref,newLabel);
if(!expr)
continue;
changed[d.first].reset(expr);
}
if(changed.empty())
return 0;
std::unique_ptr<PropertySheet> copy(new PropertySheet(*this));
for(auto &change : changed)
copy->data[change.first]->setExpression(change.second.release());
return copy.release();
}
Loading

0 comments on commit f24cfd8

Please sign in to comment.