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:
Zheng, Lei
2019-12-26 19:02:04 +08:00
committed by Chris Hennes
parent 79cda0a1b7
commit 2a3951ca32
10 changed files with 108 additions and 104 deletions

View File

@@ -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>())

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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)

View File

@@ -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;

View File

@@ -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

View File

@@ -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;