Spreadsheet: change alias handling
No longer add dynamic property for alias, simply rely on get(Dynamic)PropertyByName() to check for aliases. Add new API PropertyContainer::getPropertyNamedList() so that ExpressionCompleter can discover properties with aliases.
This commit is contained in:
@@ -65,6 +65,12 @@ void DynamicProperty::getPropertyList(std::vector<Property*> &List) const
|
||||
List.push_back(v.property);
|
||||
}
|
||||
|
||||
void DynamicProperty::getPropertyNamedList(std::vector<std::pair<const char*, Property*> > &List) const
|
||||
{
|
||||
for (auto &v : props.get<0>())
|
||||
List.emplace_back(v.getName(),v.property);
|
||||
}
|
||||
|
||||
void DynamicProperty::getPropertyMap(std::map<std::string,Property*> &Map) const
|
||||
{
|
||||
for (auto &v : props.get<0>())
|
||||
|
||||
@@ -75,6 +75,8 @@ public:
|
||||
//@{
|
||||
/// Get all properties of the class (including parent)
|
||||
void getPropertyList(std::vector<Property*> &List) const;
|
||||
/// get all properties with their names
|
||||
void getPropertyNamedList(std::vector<std::pair<const char*,Property*> > &List) const;
|
||||
/// Get all properties of the class (including parent)
|
||||
void getPropertyMap(std::map<std::string,Property*> &Map) const;
|
||||
/// Find a dynamic property by its name
|
||||
|
||||
@@ -101,6 +101,12 @@ void PropertyContainer::getPropertyList(std::vector<Property*> &List) const
|
||||
getPropertyData().getPropertyList(this,List);
|
||||
}
|
||||
|
||||
void PropertyContainer::getPropertyNamedList(std::vector<std::pair<const char*, Property*> > &List) const
|
||||
{
|
||||
dynamicProps.getPropertyNamedList(List);
|
||||
getPropertyData().getPropertyNamedList(this,List);
|
||||
}
|
||||
|
||||
void PropertyContainer::setPropertyStatus(unsigned char bit,bool value)
|
||||
{
|
||||
std::vector<Property*> List;
|
||||
@@ -586,6 +592,18 @@ void PropertyData::getPropertyList(OffsetBase offsetBase,std::vector<Property*>
|
||||
List.push_back((Property *) (spec.Offset + offsetBase.getOffset()));
|
||||
}
|
||||
|
||||
void PropertyData::getPropertyNamedList(OffsetBase offsetBase,
|
||||
std::vector<std::pair<const char*,Property*> > &List) const
|
||||
{
|
||||
merge();
|
||||
size_t base = List.size();
|
||||
List.reserve(base+propertyData.size());
|
||||
for (auto &spec : propertyData.get<0>()) {
|
||||
auto prop = (Property *) (spec.Offset + offsetBase.getOffset());
|
||||
List.emplace_back(prop->getName(),prop);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** \defgroup PropFrame Property framework
|
||||
|
||||
@@ -130,6 +130,7 @@ struct AppExport PropertyData
|
||||
Property *getPropertyByName(OffsetBase offsetBase,const char* name) const;
|
||||
void getPropertyMap(OffsetBase offsetBase,std::map<std::string,Property*> &Map) const;
|
||||
void getPropertyList(OffsetBase offsetBase,std::vector<Property*> &List) const;
|
||||
void getPropertyNamedList(OffsetBase offsetBase, std::vector<std::pair<const char*,Property*> > &List) const;
|
||||
|
||||
void merge(PropertyData *other=0) const;
|
||||
void split(PropertyData *other);
|
||||
@@ -168,6 +169,8 @@ public:
|
||||
virtual void getPropertyMap(std::map<std::string,Property*> &Map) const;
|
||||
/// get all properties of the class (including properties of the parent)
|
||||
virtual void getPropertyList(std::vector<Property*> &List) const;
|
||||
/// get all properties with their names
|
||||
virtual void getPropertyNamedList(std::vector<std::pair<const char*,Property*> > &List) const;
|
||||
/// set the Status bit of all properties at once
|
||||
void setPropertyStatus(unsigned char bit,bool value);
|
||||
|
||||
|
||||
@@ -159,10 +159,10 @@ public:
|
||||
int docSize = (int)docs.size()*2;
|
||||
int objSize = 0;
|
||||
int propSize = 0;
|
||||
std::vector<App::Property*> props;
|
||||
std::vector<std::pair<const char*, App::Property*> > props;
|
||||
App::Document *doc = 0;
|
||||
App::DocumentObject *obj = 0;
|
||||
App::Property *prop = 0;
|
||||
const char *propName = nullptr;
|
||||
if(idx>=0 && idx<docSize)
|
||||
doc = docs[idx/2];
|
||||
else {
|
||||
@@ -184,13 +184,13 @@ public:
|
||||
idx -= objSize;
|
||||
if(info.d.doc<0)
|
||||
row = idx;
|
||||
cobj->getPropertyList(props);
|
||||
cobj->getPropertyNamedList(props);
|
||||
propSize = (int)props.size();
|
||||
if(idx >= propSize)
|
||||
return;
|
||||
if(idx>=0) {
|
||||
obj = cobj;
|
||||
prop = props[idx];
|
||||
propName = props[idx].first;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,8 +200,8 @@ public:
|
||||
*count = docSize + objSize + propSize;
|
||||
if(idx>=0 && v) {
|
||||
QString res;
|
||||
if(prop)
|
||||
res = QString::fromLatin1(prop->getName());
|
||||
if(propName)
|
||||
res = QString::fromLatin1(propName);
|
||||
else if(obj) {
|
||||
if(idx & 1)
|
||||
res = QString::fromUtf8(quote(obj->Label.getStrValue()).c_str());
|
||||
@@ -248,18 +248,18 @@ public:
|
||||
|
||||
if(noProperty)
|
||||
return;
|
||||
if(!prop) {
|
||||
if(!propName) {
|
||||
idx = row;
|
||||
obj->getPropertyList(props);
|
||||
obj->getPropertyNamedList(props);
|
||||
propSize = (int)props.size();
|
||||
if(idx<0 || idx>=propSize)
|
||||
return;
|
||||
prop = props[idx];
|
||||
propName = props[idx].first;
|
||||
if(count)
|
||||
*count = propSize;
|
||||
}
|
||||
if(v)
|
||||
*v = QString::fromLatin1(prop->getName());
|
||||
if(v)
|
||||
*v = QString::fromLatin1(propName);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -131,12 +131,12 @@ Cell::Cell(PropertySheet *_owner, const Cell &other)
|
||||
, foregroundColor(other.foregroundColor)
|
||||
, backgroundColor(other.backgroundColor)
|
||||
, displayUnit(other.displayUnit)
|
||||
, alias(other.alias)
|
||||
, computedUnit(other.computedUnit)
|
||||
, rowSpan(other.rowSpan)
|
||||
, colSpan(other.colSpan)
|
||||
{
|
||||
setUsed(MARK_SET, false);
|
||||
setAlias(other.alias);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
|
||||
@@ -120,6 +120,17 @@ const Cell * PropertySheet::getValueFromAlias(const std::string &alias) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
Cell * PropertySheet::getValueFromAlias(const std::string &alias)
|
||||
{
|
||||
std::map<std::string, CellAddress>::const_iterator it = revAliasProp.find(alias);
|
||||
|
||||
if (it != revAliasProp.end())
|
||||
return getValue(it->second);
|
||||
else
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
bool PropertySheet::isValidAlias(const std::string &candidate)
|
||||
{
|
||||
static const boost::regex gen("^[A-Za-z][_A-Za-z0-9]*$");
|
||||
@@ -615,9 +626,14 @@ void PropertySheet::setAlias(CellAddress address, const std::string &alias)
|
||||
Cell * cell = nonNullCellAt(address);
|
||||
assert(cell != 0);
|
||||
|
||||
if (aliasedCell != 0 && cell != aliasedCell)
|
||||
if(aliasedCell == cell)
|
||||
return;
|
||||
|
||||
if (aliasedCell)
|
||||
throw Base::ValueError("Alias already defined.");
|
||||
|
||||
AtomicPropertyChange signaller(*this);
|
||||
|
||||
/* Mark cells depending on this cell dirty; they need to be resolved when an alias changes or disappears */
|
||||
std::string fullName = owner->getFullName() + "." + address.toString();
|
||||
|
||||
@@ -632,23 +648,21 @@ void PropertySheet::setAlias(CellAddress address, const std::string &alias)
|
||||
}
|
||||
|
||||
std::string oldAlias;
|
||||
|
||||
if (cell->getAlias(oldAlias))
|
||||
owner->aliasRemoved(address, oldAlias);
|
||||
|
||||
cell->getAlias(oldAlias);
|
||||
cell->setAlias(alias);
|
||||
|
||||
if (oldAlias.size() > 0 && alias.size() > 0) {
|
||||
if (oldAlias.size() > 0) {
|
||||
std::map<App::ObjectIdentifier, App::ObjectIdentifier> m;
|
||||
|
||||
App::ObjectIdentifier key(owner, oldAlias);
|
||||
App::ObjectIdentifier value(owner, alias);
|
||||
App::ObjectIdentifier value(owner, alias.empty()?address.toString():alias);
|
||||
|
||||
m[key] = value;
|
||||
|
||||
owner->getDocument()->renameObjectIdentifiers(m);
|
||||
}
|
||||
|
||||
signaller.tryInvoke();
|
||||
}
|
||||
|
||||
void PropertySheet::setComputedUnit(CellAddress address, const Base::Unit &unit)
|
||||
|
||||
@@ -112,6 +112,8 @@ public:
|
||||
|
||||
const Cell * getValueFromAlias(const std::string &alias) const;
|
||||
|
||||
Cell * getValueFromAlias(const std::string &alias);
|
||||
|
||||
bool isValidAlias(const std::string &candidate);
|
||||
|
||||
std::set<App::CellAddress> getUsedCells() const;
|
||||
@@ -178,6 +180,9 @@ public:
|
||||
|
||||
void documentSet();
|
||||
|
||||
App::CellAddress getCellAddress(const char *addr, bool silent=false) const;
|
||||
App::Range getRange(const char *range, bool silent=false) const;
|
||||
|
||||
std::string getRow(int offset=0) const;
|
||||
|
||||
std::string getColumn(int offset=0) const;
|
||||
|
||||
@@ -120,7 +120,6 @@ void Sheet::clearAll()
|
||||
cellErrors.clear();
|
||||
columnWidths.clear();
|
||||
rowHeights.clear();
|
||||
removedAliases.clear();
|
||||
|
||||
for (ObserverMap::iterator i = observers.begin(); i != observers.end(); ++i)
|
||||
delete i->second;
|
||||
@@ -464,6 +463,14 @@ bool Sheet::getCellAddress(const Property *prop, CellAddress & address)
|
||||
return false;
|
||||
}
|
||||
|
||||
App::CellAddress Sheet::getCellAddress(const char *name, bool silent) const {
|
||||
return cells.getCellAddress(name,silent);
|
||||
}
|
||||
|
||||
App::Range Sheet::getRange(const char *name, bool silent) const {
|
||||
return cells.getRange(name,silent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a map with column indices and widths.
|
||||
* @return Map with results.
|
||||
@@ -485,22 +492,6 @@ std::map<int, int> Sheet::getRowHeights() const
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Remove all aliases.
|
||||
*
|
||||
*/
|
||||
|
||||
void Sheet::removeAliases()
|
||||
{
|
||||
std::map<CellAddress, std::string>::iterator i = removedAliases.begin();
|
||||
|
||||
while (i != removedAliases.end()) {
|
||||
this->removeDynamicProperty(i->second.c_str());
|
||||
++i;
|
||||
}
|
||||
removedAliases.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update internal structure when document is set for this property.
|
||||
*/
|
||||
@@ -646,42 +637,6 @@ Property * Sheet::setObjectProperty(CellAddress key, Py::Object object)
|
||||
return pyProp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Update the alias for the cell at \a key.
|
||||
* @param key Cell to update.
|
||||
*/
|
||||
|
||||
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)) {
|
||||
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()) {
|
||||
this->removeDynamicProperty(alias.c_str());
|
||||
aliasProp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!aliasProp) {
|
||||
aliasProp = addDynamicProperty(prop->getTypeId().getName(), alias.c_str(), 0, 0, Prop_ReadOnly | Prop_NoPersist);
|
||||
aliasProp->setStatus(App::Property::Hidden,true);
|
||||
}
|
||||
|
||||
aliasProp->Paste(*prop);
|
||||
}
|
||||
}
|
||||
|
||||
struct CurrentAddressLock {
|
||||
CurrentAddressLock(int &r, int &c, const CellAddress &addr)
|
||||
:row(r),col(c)
|
||||
@@ -772,20 +727,37 @@ void Sheet::updateProperty(CellAddress key)
|
||||
|
||||
Property *Sheet::getPropertyByName(const char* name) const
|
||||
{
|
||||
std::string _name;
|
||||
CellAddress addr;
|
||||
if(addr.parseAbsoluteAddress(name)) {
|
||||
_name = addr.toString(true);
|
||||
name = _name.c_str();
|
||||
}
|
||||
Property * prop = getProperty(name);
|
||||
|
||||
CellAddress addr = getCellAddress(name,true);
|
||||
Property *prop = 0;
|
||||
if(addr.isValid())
|
||||
prop = getProperty(addr);
|
||||
if (prop)
|
||||
return prop;
|
||||
else
|
||||
return DocumentObject::getPropertyByName(name);
|
||||
}
|
||||
|
||||
Property *Sheet::getDynamicPropertyByName(const char* name) const {
|
||||
CellAddress addr = getCellAddress(name,true);
|
||||
Property *prop = 0;
|
||||
if(addr.isValid())
|
||||
prop = getProperty(addr);
|
||||
if (prop)
|
||||
return prop;
|
||||
else
|
||||
return DocumentObject::getDynamicPropertyByName(name);
|
||||
}
|
||||
|
||||
void Sheet::getPropertyNamedList(std::vector<std::pair<const char*,Property*> > &List) const {
|
||||
DocumentObject::getPropertyNamedList(List);
|
||||
List.reserve(List.size()+cells.aliasProp.size());
|
||||
for(auto &v : cells.aliasProp) {
|
||||
auto prop = getProperty(v.first);
|
||||
if(prop)
|
||||
List.emplace_back(v.second.c_str(),prop);
|
||||
}
|
||||
}
|
||||
|
||||
void Sheet::touchCells(Range range) {
|
||||
do {
|
||||
cells.setDirty(*range);
|
||||
@@ -838,8 +810,6 @@ void Sheet::recomputeCell(CellAddress p)
|
||||
throw;
|
||||
}
|
||||
|
||||
updateAlias(p);
|
||||
|
||||
if (!cell || cell->spansChanged())
|
||||
cellSpanChanged(p);
|
||||
}
|
||||
@@ -897,8 +867,6 @@ unsigned Sheet::getCellBindingBorder(App::CellAddress address) const {
|
||||
|
||||
DocumentObjectExecReturn *Sheet::execute(void)
|
||||
{
|
||||
// Remove all aliases first
|
||||
removeAliases();
|
||||
boundRanges.clear();
|
||||
for(auto &v : ExpressionEngine.getExpressions()) {
|
||||
CellAddress from,to;
|
||||
@@ -1443,17 +1411,6 @@ void Sheet::setSpans(CellAddress address, int rows, int columns)
|
||||
cells.setSpans(address, rows, columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Called when alias \a alias at \a address is removed.
|
||||
* @param address Address of alias.
|
||||
* @param alias Removed alias.
|
||||
*/
|
||||
|
||||
void Sheet::aliasRemoved(CellAddress address, const std::string & alias)
|
||||
{
|
||||
removedAliases[address] = alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return a set of dependencies links for cell at \a address.
|
||||
* @param address Address of cell
|
||||
|
||||
@@ -175,12 +175,20 @@ public:
|
||||
|
||||
App::Property *getPropertyByName(const char *name) const;
|
||||
|
||||
App::Property *getDynamicPropertyByName(const char* name) const;
|
||||
|
||||
virtual void getPropertyNamedList(std::vector<std::pair<const char*,App::Property*> > &List) const;
|
||||
|
||||
virtual short mustExecute(void) const;
|
||||
|
||||
App::DocumentObjectExecReturn *execute(void);
|
||||
|
||||
bool getCellAddress(const App::Property *prop, App::CellAddress &address);
|
||||
|
||||
App::CellAddress getCellAddress(const char *name, bool silent=false) const;
|
||||
|
||||
App::Range getRange(const char *name, bool silent=false) const;
|
||||
|
||||
std::map<int, int> getColumnWidths() const;
|
||||
|
||||
std::map<int, int> getRowHeights() const;
|
||||
@@ -223,8 +231,6 @@ protected:
|
||||
|
||||
App::Property *getProperty(const char * addr) const;
|
||||
|
||||
void updateAlias(App::CellAddress key);
|
||||
|
||||
void updateProperty(App::CellAddress key);
|
||||
|
||||
App::Property *setStringProperty(App::CellAddress key, const std::string & value) ;
|
||||
@@ -237,10 +243,6 @@ protected:
|
||||
|
||||
App::Property *setQuantityProperty(App::CellAddress key, double value, const Base::Unit &unit);
|
||||
|
||||
void aliasRemoved(App::CellAddress address, const std::string &alias);
|
||||
|
||||
void removeAliases();
|
||||
|
||||
virtual void onSettingDocument();
|
||||
|
||||
/* Properties for used cells */
|
||||
@@ -249,9 +251,6 @@ protected:
|
||||
/* Mapping of properties to cell position */
|
||||
std::map<const App::Property*, App::CellAddress > propAddress;
|
||||
|
||||
/* Removed (unprocessed) aliases */
|
||||
std::map<App::CellAddress, std::string> removedAliases;
|
||||
|
||||
/* Set of cells with errors */
|
||||
std::set<App::CellAddress> cellErrors;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user