diff --git a/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp b/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp
index 655a11d473..df9035c202 100644
--- a/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp
+++ b/src/Mod/Fem/Gui/TaskFemConstraintForce.cpp
@@ -138,11 +138,11 @@ void TaskFemConstraintForce::updateUI()
std::string ref = ui->listReferences->item(0)->text().toStdString();
int pos = ref.find_last_of(":");
if (ref.substr(pos+1, 6) == "Vertex")
- ui->labelForce->setText(tr("Point load [N]"));
+ ui->labelForce->setText(tr("Point load"));
else if (ref.substr(pos+1, 4) == "Edge")
- ui->labelForce->setText(tr("Line load [N/mm]"));
+ ui->labelForce->setText(tr("Line load"));
else if (ref.substr(pos+1, 4) == "Face")
- ui->labelForce->setText(trUtf8("Area load [N/mm\xc2\xb2]"));
+ ui->labelForce->setText(tr("Area load"));
}
void TaskFemConstraintForce::onSelectionChanged(const Gui::SelectionChanges& msg)
diff --git a/src/Mod/Fem/MechanicalAnalysis.py b/src/Mod/Fem/MechanicalAnalysis.py
index 642d9c6783..fe64703d32 100644
--- a/src/Mod/Fem/MechanicalAnalysis.py
+++ b/src/Mod/Fem/MechanicalAnalysis.py
@@ -372,37 +372,58 @@ class _JobControlTaskPanel:
self.OutStr = self.OutStr + '{0:4.1f}: '.format(time.time() - self.Start) + 'Write mesh...
'
self.form.textEdit_Output.setText(self.OutStr)
+ # write mesh
MeshObject.FemMesh.writeABAQUS(filename)
+
# reopen file with "append" and add the analysis definition
inpfile = open(filename,'a')
- inpfile.write('\n\n')
self.OutStr = self.OutStr + '{0:4.1f}: '.format(time.time() - self.Start) + 'Write loads & Co...
'
self.form.textEdit_Output.setText(self.OutStr)
- # write the fixed node set
+ # write fixed node set
NodeSetName = FixedObject.Name
+ inpfile.write('\n\n\n\n***********************************************************\n')
+ inpfile.write('** node set for fixed constraint\n')
inpfile.write('*NSET,NSET=' + NodeSetName + '\n')
for o,f in FixedObject.References:
fo = o.Shape.getElement(f)
- n = MeshObject.FemMesh.getNodesByFace(fo)
- for i in n:
- inpfile.write( str(i)+',\n')
- inpfile.write('\n\n')
+ if fo.ShapeType == 'Face':
+ FixedObjectType = 'AreaSupport'
+ n = MeshObject.FemMesh.getNodesByFace(fo)
+ for i in n:
+ inpfile.write( str(i)+',\n')
+ elif fo.ShapeType == 'Edge':
+ FixedObjectType = 'LineSupport'
+ print 'Line Supports are not yet implemented to export to CalculiX'
+ # getNodesByEdge(fo) # not implemented yet
+ elif fo.ShapeType == 'Vertex':
+ FixedObjectType = 'PointSupport'
+ print 'Point Supports are not yet implemented to export to CalculiX'
- # write the load node set
+ # write load node set
NodeSetNameForce = ForceObject.Name
+ inpfile.write('\n\n\n\n***********************************************************\n')
+ inpfile.write('** node set for load\n')
inpfile.write('*NSET,NSET=' + NodeSetNameForce + '\n')
NbrForceNods = 0
for o,f in ForceObject.References:
fo = o.Shape.getElement(f)
- n = MeshObject.FemMesh.getNodesByFace(fo)
- for i in n:
- inpfile.write( str(i)+',\n')
- NbrForceNods = NbrForceNods + 1
- inpfile.write('\n\n')
+ if fo.ShapeType == 'Face':
+ ForceObjectType = 'AreaLoad'
+ n = MeshObject.FemMesh.getNodesByFace(fo)
+ for i in n:
+ inpfile.write( str(i)+',\n')
+ NbrForceNods = NbrForceNods + 1
+ elif fo.ShapeType == 'Edge':
+ ForceObjectType = 'LineLoad'
+ print 'Line Loads are not yet implemented to export to CalculiX'
+ # getNodesByEdge(fo) # not implemented yet
+ elif fo.ShapeType == 'Vertex':
+ ForceObjectType = 'PointLoad'
+ print 'Point Loads are not yet implemented to export to CalculiX'
- # get the material properties
+ # get material properties
YM = FreeCAD.Units.Quantity(MathObject.Material['Mechanical_youngsmodulus'])
if YM.Unit.Type == '':
print 'Material "Mechanical_youngsmodulus" has no Unit, asuming kPa!'
@@ -412,40 +433,83 @@ class _JobControlTaskPanel:
print 'YM = ', YM
PR = float( MathObject.Material['FEM_poissonratio'] )
- print 'PR= ', PR
+ print 'PR = ', PR
- # now open again and write the setup:
+ # write material properties
+ inpfile.write('\n\n\n\n***********************************************************\n')
+ inpfile.write('** material\n')
+ inpfile.write('** unit is kPa = mN/mm2 = (kg*mm/s^2) * 1/mm^2 = kg/mm*s^2 = 10e-3 N/mm2 = 10e-3 MPa\n')
inpfile.write('*MATERIAL, Name='+matmap['General_name'] + '\n')
inpfile.write('*ELASTIC \n')
inpfile.write('{0:.3f}, '.format(YM.Value) )
inpfile.write('{0:.3f}\n'.format(PR) )
inpfile.write('*SOLID SECTION, Elset=Eall, Material='+matmap['General_name'] + '\n')
+
+ # write step beginn
+ inpfile.write('\n\n\n\n***********************************************************\n')
+ inpfile.write('** one step is needed to calculate the mechanical analysis of FreeCAD\n')
+ inpfile.write('** loads are applied quasi-static, means without involving the time dimension\n')
inpfile.write('*STEP\n')
inpfile.write('*STATIC\n')
- inpfile.write('*BOUNDARY\n')
- inpfile.write(NodeSetName + ',1,3,0.0\n')
+
+ # write constaints
+ inpfile.write('\n\n** constaints\n')
+ if FixedObjectType == 'AreaSupport':
+ inpfile.write('*BOUNDARY\n')
+ inpfile.write(NodeSetName + ',1,3,0.0\n')
+ elif FixedObjectType == 'LineSupport':
+ pass # ToDo
+ elif FixedObjectType == 'PointSupport':
+ pass # ToDo
+
+ # write loads
#inpfile.write('*DLOAD\n')
#inpfile.write('Eall,NEWTON\n')
-
- Force = (ForceObject.Force * 1000.0) / NbrForceNods
- vec = ForceObject.DirectionVector
- inpfile.write('*CLOAD\n')
- inpfile.write(NodeSetNameForce + ',1,' + `vec.x * Force` + '\n')
- inpfile.write(NodeSetNameForce + ',2,' + `vec.y * Force` + '\n')
- inpfile.write(NodeSetNameForce + ',3,' + `vec.z * Force` + '\n')
-
+ inpfile.write('\n\n** loads\n')
+ if ForceObjectType == 'AreaLoad':
+ Force = (ForceObject.Force * 1000.0) / NbrForceNods
+ vec = ForceObject.DirectionVector
+ inpfile.write('** direction: ' + str(vec) + '\n')
+ inpfile.write('** concentrated load [N] distributed on the area of the given faces.\n')
+ inpfile.write('** ' + str(ForceObject.Force) + ' N * 1000 / ' + str(NbrForceNods) + ' Nodes = ' + str(Force) + ' mN on each node\n')
+ inpfile.write('*CLOAD\n')
+ inpfile.write(NodeSetNameForce + ',1,' + `vec.x * Force` + '\n')
+ inpfile.write(NodeSetNameForce + ',2,' + `vec.y * Force` + '\n')
+ inpfile.write(NodeSetNameForce + ',3,' + `vec.z * Force` + '\n')
+ elif ForceObjectType == 'LineLoad':
+ pass # ToDo
+ elif ForceObjectType == 'PointLoad':
+ pass # ToDo
+
+ # write outputs, both are needed by FreeCAD
+ inpfile.write('\n\n** outputs --> frd file\n')
inpfile.write('*NODE FILE\n')
inpfile.write('U\n')
inpfile.write('*EL FILE\n')
inpfile.write('S, E\n')
+ inpfile.write('** outputs --> dat file\n')
inpfile.write('*NODE PRINT , NSET=Nall \n')
inpfile.write('U \n')
inpfile.write('*EL PRINT , ELSET=Eall \n')
inpfile.write('S \n')
- inpfile.write('*END STEP \n')
-
+ inpfile.write('\n\n')
- #do not run Calculix
+ # write step end
+ inpfile.write('*END STEP \n')
+
+ # write some informations
+ FcVersionInfo = FreeCAD.Version()
+ inpfile.write('\n\n\n\n***********************************************************\n')
+ inpfile.write('**\n')
+ inpfile.write('** CalculiX Inputfile\n')
+ inpfile.write('**\n')
+ inpfile.write('** written by: FreeCAD ' + FcVersionInfo[0] + '.' + FcVersionInfo[1] + '.' + FcVersionInfo[2] + '\n')
+ inpfile.write('** written on: ' + time.ctime() + '\n')
+ inpfile.write('** file name: ' + os.path.basename(FreeCAD.ActiveDocument.FileName) + '\n')
+ inpfile.write('** analysis name: ' + FemGui.getActiveAnalysis().Name + '\n')
+ inpfile.write('**\n')
+
+ inpfile.close()
QApplication.restoreOverrideCursor()
@@ -543,11 +607,11 @@ class _ResultControlTaskPanel:
self.form.spinBox_DisplacementFactor.setValue(value)
def sliderMaxValue(self,value):
- print 'sliderMaxValue()'
+ #print 'sliderMaxValue()'
self.form.verticalScrollBar_Factor.setMaximum(value)
def displacementFactorValue(self,value):
- print 'displacementFactorValue()'
+ #print 'displacementFactorValue()'
self.form.verticalScrollBar_Factor.setValue(value)
def setDisplacement(self):
@@ -564,7 +628,7 @@ class _ResultControlTaskPanel:
def update(self):
'fills the widgets'
- print "Update-------------------------------"
+ #print "Update-------------------------------"
self.MeshObject = None
if FemGui.getActiveAnalysis():
for i in FemGui.getActiveAnalysis().Member:
diff --git a/src/Mod/Fem/MechanicalMaterial.py b/src/Mod/Fem/MechanicalMaterial.py
index 9537c8b042..0700bac34b 100644
--- a/src/Mod/Fem/MechanicalMaterial.py
+++ b/src/Mod/Fem/MechanicalMaterial.py
@@ -145,9 +145,16 @@ class _MechanicalMaterialTaskPanel:
matmap['Mechanical_youngsmodulus'] = self.form.spinBox_young_modulus.text()
matmap['FEM_poissonratio'] = str(self.form.spinBox_poisson_ratio.value())
-
+ print self.form.comboBox_MaterialsInDir.currentText()
+
self.obj.Material = matmap
- print matmap
+ print 'material data:'
+ if matmap.has_key('General_name'):
+ print ' Name = ', matmap['General_name']
+ if matmap.has_key('Mechanical_youngsmodulus'):
+ print ' YM = ', matmap['Mechanical_youngsmodulus']
+ if matmap.has_key('FEM_poissonratio'):
+ print ' PR = ', matmap['FEM_poissonratio']
def transferFrom(self):
@@ -155,7 +162,7 @@ class _MechanicalMaterialTaskPanel:
matmap = self.obj.Material
if matmap.has_key('Mechanical_youngsmodulus'):
- print matmap['Mechanical_youngsmodulus']
+ #print matmap['Mechanical_youngsmodulus']
self.form.spinBox_young_modulus.setText(matmap['Mechanical_youngsmodulus'])
if matmap.has_key('FEM_poissonratio'):
#print float(matmap['FEM_poissonratio'])
@@ -181,12 +188,20 @@ class _MechanicalMaterialTaskPanel:
return
def accept(self):
- print 'accept(self)'
+ #print 'accept(self)'
self.transferTo()
FreeCADGui.ActiveDocument.resetEdit()
def reject(self):
- print 'reject(self)'
+ #print 'reject(self)'
+ matmap = self.obj.Material
+ print 'material data:'
+ if matmap.has_key('General_name'):
+ print ' Name = ', matmap['General_name']
+ if matmap.has_key('Mechanical_youngsmodulus'):
+ print ' YM = ', matmap['Mechanical_youngsmodulus']
+ if matmap.has_key('FEM_poissonratio'):
+ print ' PR = ', matmap['FEM_poissonratio']
FreeCADGui.ActiveDocument.resetEdit()
def saveMat(self):
diff --git a/src/Mod/Spreadsheet/App/AppSpreadsheet.cpp b/src/Mod/Spreadsheet/App/AppSpreadsheet.cpp
index ff6dc853dd..f12e367269 100644
--- a/src/Mod/Spreadsheet/App/AppSpreadsheet.cpp
+++ b/src/Mod/Spreadsheet/App/AppSpreadsheet.cpp
@@ -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();
diff --git a/src/Mod/Spreadsheet/App/Cell.cpp b/src/Mod/Spreadsheet/App/Cell.cpp
index d2545684dd..0e9a888c5c 100644
--- a/src/Mod/Spreadsheet/App/Cell.cpp
+++ b/src/Mod/Spreadsheet/App/Cell.cpp
@@ -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() << "visit(v);
}
/**
diff --git a/src/Mod/Spreadsheet/App/Cell.h b/src/Mod/Spreadsheet/App/Cell.h
index fd82e85b00..1ce6eeefb3 100644
--- a/src/Mod/Spreadsheet/App/Cell.h
+++ b/src/Mod/Spreadsheet/App/Cell.h
@@ -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;
diff --git a/src/Mod/Spreadsheet/App/Expression.cpp b/src/Mod/Spreadsheet/App/Expression.cpp
index e00ea18abd..45c47eddc4 100644
--- a/src/Mod/Spreadsheet/App/Expression.cpp
+++ b/src/Mod/Spreadsheet/App/Expression.cpp
@@ -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(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;
+}
+
}
/**
diff --git a/src/Mod/Spreadsheet/App/Expression.h b/src/Mod/Spreadsheet/App/Expression.h
index b9e12b9d76..3dfc65695a 100644
--- a/src/Mod/Spreadsheet/App/Expression.h
+++ b/src/Mod/Spreadsheet/App/Expression.h
@@ -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;
};
diff --git a/src/Mod/Spreadsheet/App/PropertyColumnWidths.cpp b/src/Mod/Spreadsheet/App/PropertyColumnWidths.cpp
index b064df9903..cba0ecd20f 100644
--- a/src/Mod/Spreadsheet/App/PropertyColumnWidths.cpp
+++ b/src/Mod/Spreadsheet/App/PropertyColumnWidths.cpp
@@ -155,3 +155,14 @@ PyObject *PropertyColumnWidths::getPyObject()
}
return Py::new_reference_to(PythonObject);
}
+
+void PropertyColumnWidths::clear()
+{
+ std::map::const_iterator i = begin();
+
+ while (i != end()) {
+ dirty.insert(i->first);
+ ++i;
+ }
+ std::map::clear();
+}
diff --git a/src/Mod/Spreadsheet/App/PropertyColumnWidths.h b/src/Mod/Spreadsheet/App/PropertyColumnWidths.h
index 9adfe17c00..d7a282c371 100644
--- a/src/Mod/Spreadsheet/App/PropertyColumnWidths.h
+++ b/src/Mod/Spreadsheet/App/PropertyColumnWidths.h
@@ -35,8 +35,6 @@ class SpreadsheetExport PropertyColumnWidths : public App::Property, std::map dirty;
Py::Object PythonObject;
diff --git a/src/Mod/Spreadsheet/App/PropertyRowHeights.cpp b/src/Mod/Spreadsheet/App/PropertyRowHeights.cpp
index 68a0737e24..9b5aa53cff 100644
--- a/src/Mod/Spreadsheet/App/PropertyRowHeights.cpp
+++ b/src/Mod/Spreadsheet/App/PropertyRowHeights.cpp
@@ -148,3 +148,14 @@ PyObject *PropertyRowHeights::getPyObject()
}
return Py::new_reference_to(PythonObject);
}
+
+void PropertyRowHeights::clear()
+{
+ std::map::const_iterator i = begin();
+
+ while (i != end()) {
+ dirty.insert(i->first);
+ ++i;
+ }
+ std::map::clear();
+}
diff --git a/src/Mod/Spreadsheet/App/PropertyRowHeights.h b/src/Mod/Spreadsheet/App/PropertyRowHeights.h
index 3042c16b20..b44d5d2fce 100644
--- a/src/Mod/Spreadsheet/App/PropertyRowHeights.h
+++ b/src/Mod/Spreadsheet/App/PropertyRowHeights.h
@@ -35,8 +35,6 @@ class SpreadsheetExport PropertyRowHeights : public App::Property, std::map dirty;
Py::Object PythonObject;
diff --git a/src/Mod/Spreadsheet/App/PropertySheet.cpp b/src/Mod/Spreadsheet/App/PropertySheet.cpp
index 0b95dd49a9..3e0425c562 100644
--- a/src/Mod/Spreadsheet/App/PropertySheet.cpp
+++ b/src/Mod/Spreadsheet/App/PropertySheet.cpp
@@ -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 >::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::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(node);
+ VariableExpression *varExpr = freecad_dynamic_cast(node);
+ RangeExpression *rangeExpr = freecad_dynamic_cast(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 colstr = cm[2];
const boost::sub_match 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::const_iterator i = expressionDeps.begin();
while (i != expressionDeps.end()) {
- const Property * prop = (*i).getProperty();
- DocumentObject * docObj = prop ? freecad_dynamic_cast(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::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 >::iterator i1 = cellToPropertyNameMap.find(key);
- std::set< std::string >::iterator j;
-
/* Remove from Property <-> Key maps */
- if (i1 == cellToPropertyNameMap.end())
- return;
+ std::map >::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 >::iterator k = propertyNameToCellMap.find(*j);
+ while (j != i1->second.end()) {
+ std::map >::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 >::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 >::iterator k = documentObjectToCellMap.find(*j);
- while (j != i2->second.end()) {
- std::map >::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();
diff --git a/src/Mod/Spreadsheet/App/PropertySheet.h b/src/Mod/Spreadsheet/App/PropertySheet.h
index 7717ab60f9..c718d549d7 100644
--- a/src/Mod/Spreadsheet/App/PropertySheet.h
+++ b/src/Mod/Spreadsheet/App/PropertySheet.h
@@ -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 documentName;
+ /* Mapping of cell position to alias property */
+ std::map aliasProp;
+
+ /* Mapping of alias property to cell position */
+ std::map revAliasProp;
+
int signalCounter;
Py::Object PythonObject;
diff --git a/src/Mod/Spreadsheet/App/Range.cpp b/src/Mod/Spreadsheet/App/Range.cpp
index c76d1cf384..673b277075 100644
--- a/src/Mod/Spreadsheet/App/Range.cpp
+++ b/src/Mod/Spreadsheet/App/Range.cpp
@@ -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) {
diff --git a/src/Mod/Spreadsheet/App/Range.h b/src/Mod/Spreadsheet/App/Range.h
index 2c94d15b02..5264790afa 100644
--- a/src/Mod/Spreadsheet/App/Range.h
+++ b/src/Mod/Spreadsheet/App/Range.h
@@ -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); }
diff --git a/src/Mod/Spreadsheet/App/Sheet.cpp b/src/Mod/Spreadsheet/App/Sheet.cpp
index 60607fcc66..d2a44dd095 100644
--- a/src/Mod/Spreadsheet/App/Sheet.cpp
+++ b/src/Mod/Spreadsheet/App/Sheet.cpp
@@ -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());
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::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::iterator i = aliasProp.find(key);
- if (i != aliasProp.end()) {
- props.removeDynamicProperty(props.getPropertyName(i->second));
- aliasProp.erase(i);
- }
}
- floatProp = freecad_dynamic_cast(props.addDynamicProperty("App::PropertyFloat", toAddress(key).c_str(), 0, 0, Prop_ReadOnly | Prop_Transient, true, true));
+ floatProp = freecad_dynamic_cast(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::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(p);
+ Property * p = props.addDynamicProperty("Spreadsheet::PropertySpreadsheetQuantity", key.toString().c_str(), 0, 0, Prop_ReadOnly | Prop_Transient, true, true);
+ quantityProp = freecad_dynamic_cast(p);
quantityProp->StatusBits.set(3);
}
else
- quantityProp = static_cast(prop);
+ quantityProp = static_cast(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(prop);
if (!stringProp) {
if (prop) {
- props.removeDynamicProperty(toAddress(key).c_str());
+ props.removeDynamicProperty(key.toString().c_str());
propAddress.erase(prop);
-
- std::map::iterator i = aliasProp.find(key);
- if (i != aliasProp.end()) {
- props.removeDynamicProperty(props.getPropertyName(i->second));
- aliasProp.erase(i);
- }
}
- stringProp = freecad_dynamic_cast(props.addDynamicProperty("App::PropertyString", toAddress(key).c_str(), 0, 0, Prop_ReadOnly | Prop_Transient, true, true));
+ stringProp = freecad_dynamic_cast(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(output)) {
NumberExpression * number = static_cast(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(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::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 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 ds(cells.getDocDeps());
+
+ // Make sure we don't reference ourselves
+ ds.erase(this);
+
std::vector 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 Sheet::getUsedCells() const
std::set usedSet = cells.getUsedCells();
for (std::set::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 Sheet::dependsOn(CellAddress address) const
{
return cells.getDeps(address);
@@ -1040,18 +1059,18 @@ void Sheet::providesTo(CellAddress address, std::set & 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 tmpResult = cells.getDeps(fullName);
for (std::set::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 & 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(&from)->_dValue;
+ _Unit = static_cast(&from)->_Unit;
+ hasSetValue();
+}
diff --git a/src/Mod/Spreadsheet/App/Sheet.h b/src/Mod/Spreadsheet/App/Sheet.h
index 0bde46c55a..a7a109556b 100644
--- a/src/Mod/Spreadsheet/App/Sheet.h
+++ b/src/Mod/Spreadsheet/App/Sheet.h
@@ -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 propAddress;
- /* Mapping of cell position to alias property */
- std::map aliasProp;
+ /* Removed (unprocessed) aliases */
+ std::map removedAliases;
/* Set of cells with errors */
std::set cellErrors;
diff --git a/src/Mod/Spreadsheet/App/Utils.cpp b/src/Mod/Spreadsheet/App/Utils.cpp
index 25ee3b89e2..8eef12e5cb 100644
--- a/src/Mod/Spreadsheet/App/Utils.cpp
+++ b/src/Mod/Spreadsheet/App/Utils.cpp
@@ -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 > & cells, std::map, std::pair > & 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();
+}
diff --git a/src/Mod/Spreadsheet/App/Utils.h b/src/Mod/Spreadsheet/App/Utils.h
index 2d760926d1..411f8b54ea 100644
--- a/src/Mod/Spreadsheet/App/Utils.h
+++ b/src/Mod/Spreadsheet/App/Utils.h
@@ -42,12 +42,9 @@ SpreadsheetExport void createRectangles(std::set > & 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 T * freecad_dynamic_cast(Base::BaseClass * t)
diff --git a/src/Mod/Spreadsheet/Gui/Command.cpp b/src/Mod/Spreadsheet/Gui/Command.cpp
index 96eee18492..3c5a9d7987 100644
--- a/src/Mod/Spreadsheet/Gui/Command.cpp
+++ b/src/Mod/Spreadsheet/Gui/Command.cpp
@@ -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());
diff --git a/src/Mod/Spreadsheet/Gui/SheetModel.cpp b/src/Mod/Spreadsheet/Gui/SheetModel.cpp
index f3a85abd1f..00e38a5bac 100644
--- a/src/Mod/Spreadsheet/Gui/SheetModel.cpp
+++ b/src/Mod/Spreadsheet/Gui/SheetModel.cpp
@@ -147,10 +147,10 @@ QVariant SheetModel::data(const QModelIndex &index, int role) const
if (role == Qt::ToolTipRole) {
QString v;
- std::set deps = sheet->dependsOn(row, col);
+ std::set deps = sheet->dependsOn(CellAddress(row, col));
std::set 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);
diff --git a/src/Mod/Spreadsheet/Gui/ViewProviderSpreadsheet.cpp b/src/Mod/Spreadsheet/Gui/ViewProviderSpreadsheet.cpp
index 5ca86f1fed..93546830a8 100644
--- a/src/Mod/Spreadsheet/Gui/ViewProviderSpreadsheet.cpp
+++ b/src/Mod/Spreadsheet/Gui/ViewProviderSpreadsheet.cpp
@@ -158,7 +158,7 @@ bool ViewProviderSheet::onDelete(const std::vector &)
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());
}
|