App: fix memory leaks in Enumeration class and simplify code
This commit is contained in:
@@ -28,76 +28,81 @@
|
||||
|
||||
#include <Base/Exception.h>
|
||||
#include "Enumeration.h"
|
||||
#include <string_view>
|
||||
|
||||
using namespace App;
|
||||
|
||||
namespace {
|
||||
struct StringCopy {
|
||||
StringCopy(const char* str) : d(str) {
|
||||
}
|
||||
const char* data() const {
|
||||
return d.data();
|
||||
}
|
||||
bool isEqual(const char* str) const {
|
||||
return d == str;
|
||||
}
|
||||
bool isCustom() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string d;
|
||||
};
|
||||
|
||||
struct StringView {
|
||||
StringView(const char* str) : d(str) {
|
||||
}
|
||||
const char* data() const {
|
||||
return d.data();
|
||||
}
|
||||
bool isEqual(const char* str) const {
|
||||
return d == str;
|
||||
}
|
||||
bool isCustom() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string_view d;
|
||||
};
|
||||
}
|
||||
|
||||
Enumeration::Enumeration()
|
||||
: _EnumArray(nullptr), _ownEnumArray(false), _index(0), _maxVal(-1)
|
||||
: _index(0)
|
||||
{
|
||||
}
|
||||
|
||||
Enumeration::Enumeration(const Enumeration &other)
|
||||
: _EnumArray(nullptr), _ownEnumArray(false), _index(0), _maxVal(-1)
|
||||
{
|
||||
if (other._ownEnumArray) {
|
||||
setEnums(other.getEnumVector());
|
||||
} else {
|
||||
_EnumArray = other._EnumArray;
|
||||
}
|
||||
|
||||
_ownEnumArray = other._ownEnumArray;
|
||||
enumArray = other.enumArray;
|
||||
_index = other._index;
|
||||
_maxVal = other._maxVal;
|
||||
}
|
||||
|
||||
Enumeration::Enumeration(const char *valStr)
|
||||
: _ownEnumArray(true), _index(0), _maxVal(0)
|
||||
: _index(0)
|
||||
{
|
||||
_EnumArray = new const char*[2];
|
||||
#if defined (_MSC_VER)
|
||||
_EnumArray[0] = _strdup(valStr);
|
||||
#else
|
||||
_EnumArray[0] = strdup(valStr);
|
||||
#endif
|
||||
_EnumArray[1] = nullptr;
|
||||
enumArray.push_back(StringCopy(valStr));
|
||||
setValue(valStr);
|
||||
}
|
||||
|
||||
Enumeration::Enumeration(const char **list, const char *valStr)
|
||||
: _EnumArray(list), _ownEnumArray(false)
|
||||
: _index(0)
|
||||
{
|
||||
findMaxVal();
|
||||
while (list && *list) {
|
||||
enumArray.push_back(StringView(*list));
|
||||
list++;
|
||||
}
|
||||
setValue(valStr);
|
||||
}
|
||||
|
||||
Enumeration::~Enumeration()
|
||||
{
|
||||
if (_ownEnumArray) {
|
||||
if (_EnumArray != nullptr) {
|
||||
tearDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Enumeration::tearDown(void)
|
||||
{
|
||||
// Ugly...
|
||||
for(char **plEnums = (char **)_EnumArray; *plEnums != nullptr; ++plEnums) {
|
||||
// Delete C Strings first
|
||||
free(*plEnums);
|
||||
}
|
||||
|
||||
delete [] _EnumArray;
|
||||
|
||||
_EnumArray = nullptr;
|
||||
_ownEnumArray = false;
|
||||
_maxVal = -1;
|
||||
enumArray.clear();
|
||||
}
|
||||
|
||||
void Enumeration::setEnums(const char **plEnums)
|
||||
{
|
||||
if(plEnums == _EnumArray)
|
||||
return;
|
||||
|
||||
std::string oldValue;
|
||||
bool preserve = (isValid() && plEnums != nullptr);
|
||||
if (preserve) {
|
||||
@@ -106,23 +111,15 @@ void Enumeration::setEnums(const char **plEnums)
|
||||
oldValue = str;
|
||||
}
|
||||
|
||||
// set _ownEnumArray
|
||||
if (isValid() && _ownEnumArray) {
|
||||
tearDown();
|
||||
enumArray.clear();
|
||||
while (plEnums && *plEnums) {
|
||||
enumArray.push_back(StringView(*plEnums));
|
||||
plEnums++;
|
||||
}
|
||||
|
||||
// set...
|
||||
_EnumArray = plEnums;
|
||||
|
||||
// set _maxVal
|
||||
findMaxVal();
|
||||
|
||||
// set _index
|
||||
if (_index < 0)
|
||||
_index = 0;
|
||||
else if (_index > _maxVal)
|
||||
_index = _maxVal;
|
||||
|
||||
if (preserve) {
|
||||
setValue(oldValue);
|
||||
}
|
||||
@@ -143,30 +140,14 @@ void Enumeration::setEnums(const std::vector<std::string> &values)
|
||||
oldValue = str;
|
||||
}
|
||||
|
||||
if (isValid() && _ownEnumArray) {
|
||||
tearDown();
|
||||
}
|
||||
|
||||
_EnumArray = new const char*[values.size() + 1];
|
||||
int i = 0;
|
||||
enumArray.clear();
|
||||
for (std::vector<std::string>::const_iterator it = values.begin(); it != values.end(); ++it) {
|
||||
#if defined (_MSC_VER)
|
||||
_EnumArray[i++] = _strdup(it->c_str());
|
||||
#else
|
||||
_EnumArray[i++] = strdup(it->c_str());
|
||||
#endif
|
||||
enumArray.push_back(StringCopy(it->c_str()));
|
||||
}
|
||||
|
||||
_EnumArray[i] = nullptr; // null termination
|
||||
|
||||
// Other state variables
|
||||
_maxVal = static_cast<int>(values.size() - 1);
|
||||
_ownEnumArray = true;
|
||||
// set _index
|
||||
if (_index < 0)
|
||||
_index = 0;
|
||||
else if (_index > _maxVal)
|
||||
_index = _maxVal;
|
||||
|
||||
if (preserve) {
|
||||
setValue(oldValue);
|
||||
}
|
||||
@@ -174,36 +155,18 @@ void Enumeration::setEnums(const std::vector<std::string> &values)
|
||||
|
||||
void Enumeration::setValue(const char *value)
|
||||
{
|
||||
// using string methods without set, use setEnums(const char** plEnums) first!
|
||||
//assert(_EnumArray);
|
||||
|
||||
if (!_EnumArray) {
|
||||
_index = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
const char **plEnums = _EnumArray;
|
||||
|
||||
// search for the right entry
|
||||
while (1) {
|
||||
// end of list? set zero
|
||||
if (*plEnums == nullptr) {
|
||||
_index = 0;
|
||||
_index = 0;
|
||||
for (std::size_t i = 0; i < enumArray.size(); i++) {
|
||||
if (enumArray[i].isEqual(value)) {
|
||||
_index = static_cast<int>(i);
|
||||
break;
|
||||
}
|
||||
if (strcmp(*plEnums, value) == 0) {
|
||||
_index = i;
|
||||
break;
|
||||
}
|
||||
++plEnums;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void Enumeration::setValue(long value, bool checkRange)
|
||||
{
|
||||
if (value >= 0 && value <= _maxVal) {
|
||||
if (value >= 0 && value < countItems()) {
|
||||
_index = value;
|
||||
} else {
|
||||
if (checkRange) {
|
||||
@@ -216,116 +179,104 @@ void Enumeration::setValue(long value, bool checkRange)
|
||||
|
||||
bool Enumeration::isValue(const char *value) const
|
||||
{
|
||||
// using string methods without set, use setEnums(const char** plEnums) first!
|
||||
//assert(_EnumArray);
|
||||
|
||||
int i = getInt();
|
||||
|
||||
if (i == -1) {
|
||||
return false;
|
||||
} else {
|
||||
return strcmp(_EnumArray[i], value) == 0;
|
||||
return enumArray[i].isEqual(value);
|
||||
}
|
||||
}
|
||||
|
||||
bool Enumeration::contains(const char *value) const
|
||||
{
|
||||
// using string methods without set, use setEnums(const char** plEnums) first!
|
||||
//assert(_EnumArray);
|
||||
|
||||
if (!getEnums()) {
|
||||
if (!isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char **plEnums = _EnumArray;
|
||||
|
||||
// search for the right entry
|
||||
while (1) {
|
||||
// end of list?
|
||||
if (*plEnums == nullptr)
|
||||
return false;
|
||||
if (strcmp(*plEnums, value) == 0)
|
||||
for (const auto& it : enumArray) {
|
||||
if (it.isEqual(value))
|
||||
return true;
|
||||
++plEnums;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char * Enumeration::getCStr(void) const
|
||||
const char * Enumeration::getCStr() const
|
||||
{
|
||||
// using string methods without set, use setEnums(const char** plEnums) first!
|
||||
//assert(_EnumArray);
|
||||
|
||||
if (!isValid() || _index < 0 || _index > _maxVal) {
|
||||
if (!isValid() || _index < 0 || _index >= countItems()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return _EnumArray[_index];
|
||||
return enumArray[_index].data();
|
||||
}
|
||||
|
||||
int Enumeration::getInt(void) const
|
||||
int Enumeration::getInt() const
|
||||
{
|
||||
if (!isValid() || _index < 0 || _index > _maxVal) {
|
||||
if (!isValid() || _index < 0 || _index >= countItems()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _index;
|
||||
}
|
||||
|
||||
std::vector<std::string> Enumeration::getEnumVector(void) const
|
||||
std::vector<std::string> Enumeration::getEnumVector() const
|
||||
{
|
||||
// using string methods without set, use setEnums(const char** plEnums) first!
|
||||
if (!_EnumArray)
|
||||
return std::vector<std::string>();
|
||||
std::vector<std::string> list;
|
||||
for (const auto& it : enumArray)
|
||||
list.emplace_back(it.data());
|
||||
return list;
|
||||
}
|
||||
|
||||
std::vector<std::string> result;
|
||||
const char **plEnums = _EnumArray;
|
||||
bool Enumeration::hasEnums() const
|
||||
{
|
||||
return (!enumArray.empty());
|
||||
}
|
||||
|
||||
// end of list?
|
||||
while (*plEnums != nullptr) {
|
||||
result.push_back(*plEnums);
|
||||
++plEnums;
|
||||
bool Enumeration::isValid() const
|
||||
{
|
||||
return (!enumArray.empty() && _index >= 0 && _index < countItems());
|
||||
}
|
||||
|
||||
int Enumeration::maxValue() const
|
||||
{
|
||||
int num = -1;
|
||||
if (!enumArray.empty())
|
||||
num = static_cast<int>(enumArray.size()) - 1;
|
||||
return num;
|
||||
}
|
||||
|
||||
bool Enumeration::isCustom() const
|
||||
{
|
||||
for (const auto& it : enumArray) {
|
||||
if (it.isCustom())
|
||||
return true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const char ** Enumeration::getEnums(void) const
|
||||
{
|
||||
return _EnumArray;
|
||||
}
|
||||
|
||||
bool Enumeration::isValid(void) const
|
||||
{
|
||||
return (_EnumArray != nullptr && _index >= 0 && _index <= _maxVal);
|
||||
return false;
|
||||
}
|
||||
|
||||
Enumeration & Enumeration::operator=(const Enumeration &other)
|
||||
{
|
||||
if (other._ownEnumArray) {
|
||||
setEnums(other.getEnumVector());
|
||||
} else {
|
||||
_EnumArray = other._EnumArray;
|
||||
}
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
_ownEnumArray = other._ownEnumArray;
|
||||
enumArray = other.enumArray;
|
||||
_index = other._index;
|
||||
_maxVal = other._maxVal;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Enumeration::operator==(const Enumeration &other) const
|
||||
{
|
||||
if(_index != other._index || _maxVal != other._maxVal)
|
||||
if (_index != other._index || enumArray.size() != other.enumArray.size()) {
|
||||
return false;
|
||||
if (_EnumArray == other._EnumArray)
|
||||
return true;
|
||||
for (int i=0; i<=_maxVal; ++i) {
|
||||
if (_EnumArray[i] == other._EnumArray[i])
|
||||
}
|
||||
for (size_t i = 0; i < enumArray.size(); ++i) {
|
||||
if (enumArray[i].data() == other.enumArray[i].data())
|
||||
continue;
|
||||
if (_EnumArray[i] == nullptr || other._EnumArray[i] == nullptr)
|
||||
if (enumArray[i].data() == nullptr || other.enumArray[i].data() == nullptr)
|
||||
return false;
|
||||
if (strcmp(_EnumArray[i], other._EnumArray[i]) != 0)
|
||||
if (!enumArray[i].isEqual(other.enumArray[i].data()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -340,24 +291,7 @@ bool Enumeration::operator==(const char *other) const
|
||||
return (strcmp(getCStr(), other) == 0);
|
||||
}
|
||||
|
||||
void Enumeration::findMaxVal(void)
|
||||
int Enumeration::countItems() const
|
||||
{
|
||||
if (_EnumArray == nullptr) {
|
||||
_maxVal = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
const char **plEnums = _EnumArray;
|
||||
|
||||
// the NULL terminator doesn't belong to the range of
|
||||
// valid values
|
||||
int i = -1;
|
||||
while (*(plEnums++) != nullptr) {
|
||||
++i;
|
||||
// very unlikely to have enums with more then 5000 entries!
|
||||
assert(i < 5000);
|
||||
}
|
||||
|
||||
_maxVal = i;
|
||||
return static_cast<int>(enumArray.size());
|
||||
}
|
||||
|
||||
|
||||
@@ -24,14 +24,13 @@
|
||||
#ifndef BASE_ENUMERATION_H
|
||||
#define BASE_ENUMERATION_H
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <FCGlobal.h>
|
||||
|
||||
namespace App
|
||||
{
|
||||
class PropertyEnumeration;
|
||||
|
||||
/// A bidirectional string-integer mapping
|
||||
/*!
|
||||
* This is mainly intended for two purposes: working around the difficulty
|
||||
@@ -52,144 +51,172 @@ namespace App
|
||||
*/
|
||||
class AppExport Enumeration
|
||||
{
|
||||
friend class App::PropertyEnumeration;
|
||||
protected:
|
||||
class Object {
|
||||
public:
|
||||
/// Constructs an empty Enumeration object
|
||||
Enumeration();
|
||||
template <typename T>
|
||||
Object(T&& obj): object(std::make_shared<Model<T>>(std::forward<T>(obj))){}
|
||||
const char* data() const {
|
||||
return object->data();
|
||||
}
|
||||
bool isEqual(const char* str) const {
|
||||
return object->isEqual(str);
|
||||
}
|
||||
bool isCustom() const {
|
||||
return object->isCustom();
|
||||
}
|
||||
|
||||
/// Standard copy constructor
|
||||
Enumeration(const Enumeration& other);
|
||||
struct Concept {
|
||||
virtual ~Concept() {}
|
||||
virtual const char* data() const = 0;
|
||||
virtual bool isEqual(const char*) const = 0;
|
||||
virtual bool isCustom() const = 0;
|
||||
};
|
||||
|
||||
/// Constructs an Enumeration with a single element
|
||||
Enumeration(const char *valStr);
|
||||
template< typename T >
|
||||
struct Model : Concept {
|
||||
Model(const T& t) : object(t) {}
|
||||
const char* data() const override {
|
||||
return object.data();
|
||||
}
|
||||
bool isEqual(const char* str) const override {
|
||||
return object.isEqual(str);
|
||||
}
|
||||
bool isCustom() const override {
|
||||
return object.isCustom();
|
||||
}
|
||||
private:
|
||||
T object;
|
||||
};
|
||||
|
||||
/// Constructs an Enumeration using val within list
|
||||
Enumeration(const char **list, const char *valStr);
|
||||
std::shared_ptr<Concept> object;
|
||||
};
|
||||
|
||||
/// Standard destructor
|
||||
~Enumeration();
|
||||
public:
|
||||
/// Constructs an empty Enumeration object
|
||||
Enumeration();
|
||||
|
||||
/** Sets the enumeration string list
|
||||
* The list is a NULL terminated array of pointers to const
|
||||
* char* strings.
|
||||
* \code
|
||||
* const char enums[] = {"Black","White","Other",NULL}
|
||||
* \endcode
|
||||
*
|
||||
* If Enumeration was already valid, will attempt to preserve
|
||||
* the string-representation value of the Enumeration
|
||||
*
|
||||
* Enumeration does not take ownership of the passed object
|
||||
*/
|
||||
void setEnums(const char **plEnums);
|
||||
/// Standard copy constructor
|
||||
Enumeration(const Enumeration& other);
|
||||
|
||||
/// Set all enum values as vector of strings
|
||||
/*!
|
||||
* This method causes the Enumeration to dynamically allocate
|
||||
* it's own array of C Strings, which will be deleted by the
|
||||
* destructor or subsequent calls to setEnums(). So, it is
|
||||
* important to make sure the Enumeration stays in scope as
|
||||
* long as values returned by getCStr are in use.
|
||||
*
|
||||
* If Enumeration was already valid, will attempt to preserve
|
||||
* the string-representation value of the Enumeration
|
||||
*/
|
||||
void setEnums(const std::vector<std::string> &values);
|
||||
/// Constructs an Enumeration with a single element
|
||||
Enumeration(const char *valStr);
|
||||
|
||||
/// Set the enum using a C string
|
||||
void setValue(const char *value);
|
||||
/// Constructs an Enumeration using val within list
|
||||
Enumeration(const char **list, const char *valStr);
|
||||
|
||||
/// Overload of setValue(const char *value)
|
||||
void setValue(const std::string &value) {setValue(value.c_str());}
|
||||
/// Standard destructor
|
||||
~Enumeration();
|
||||
|
||||
/// Set the enum using a long
|
||||
/*!
|
||||
* if checkRange is set to true, throws Base::ValueError when
|
||||
* values are set out of range
|
||||
*
|
||||
* Checks for boundaries via assert()
|
||||
*/
|
||||
void setValue(long value, bool checkRange = false);
|
||||
/** Sets the enumeration string list
|
||||
* The list is a NULL terminated array of pointers to const
|
||||
* char* strings.
|
||||
* \code
|
||||
* const char enums[] = {"Black","White","Other",NULL}
|
||||
* \endcode
|
||||
*
|
||||
* If Enumeration was already valid, will attempt to preserve
|
||||
* the string-representation value of the Enumeration
|
||||
*
|
||||
* Enumeration does not take ownership of the passed object
|
||||
*/
|
||||
void setEnums(const char **plEnums);
|
||||
|
||||
/// Checks if the property is set to a certain string value
|
||||
bool isValue(const char *value) const;
|
||||
/// Set all enum values as vector of strings
|
||||
/*!
|
||||
* This method causes the Enumeration to dynamically allocate
|
||||
* it's own array of C Strings, which will be deleted by the
|
||||
* destructor or subsequent calls to setEnums(). So, it is
|
||||
* important to make sure the Enumeration stays in scope as
|
||||
* long as values returned by getCStr are in use.
|
||||
*
|
||||
* If Enumeration was already valid, will attempt to preserve
|
||||
* the string-representation value of the Enumeration
|
||||
*/
|
||||
void setEnums(const std::vector<std::string> &values);
|
||||
|
||||
/// Checks if a string is included in the enumeration
|
||||
bool contains(const char *value) const;
|
||||
/// Set the enum using a C string
|
||||
void setValue(const char *value);
|
||||
|
||||
/// Return the value as C string
|
||||
/*!
|
||||
* Returns NULL if the enumeration is invalid.
|
||||
*/
|
||||
const char * getCStr(void) const;
|
||||
/// Overload of setValue(const char *value)
|
||||
void setValue(const std::string &value) {setValue(value.c_str());}
|
||||
|
||||
/// Return value as integer
|
||||
/*!
|
||||
* Returns -1 if the Enumeration isn't valid
|
||||
*/
|
||||
int getInt(void) const;
|
||||
/// Set the enum using a long
|
||||
/*!
|
||||
* if checkRange is set to true, throws Base::ValueError when
|
||||
* values are set out of range
|
||||
*
|
||||
* Checks for boundaries via assert()
|
||||
*/
|
||||
void setValue(long value, bool checkRange = false);
|
||||
|
||||
/// get all possible enum values as vector of strings
|
||||
std::vector<std::string> getEnumVector(void) const;
|
||||
/// Checks if the property is set to a certain string value
|
||||
bool isValue(const char *value) const;
|
||||
|
||||
/// get pointer to the enum list
|
||||
const char ** getEnums(void) const;
|
||||
/// Checks if a string is included in the enumeration
|
||||
bool contains(const char *value) const;
|
||||
|
||||
/// Returns true if the instance is in a usable state
|
||||
bool isValid(void) const;
|
||||
/// Return the value as C string
|
||||
/*!
|
||||
* Returns NULL if the enumeration is invalid.
|
||||
*/
|
||||
const char * getCStr() const;
|
||||
|
||||
/// Returns the highest usable integer value for this enum
|
||||
/*!
|
||||
* Returns -1 if the enumeration is not valid according to isValid()
|
||||
*/
|
||||
int maxValue(void) const {return _maxVal;}
|
||||
/// Return value as integer
|
||||
/*!
|
||||
* Returns -1 if the Enumeration isn't valid
|
||||
*/
|
||||
int getInt() const;
|
||||
|
||||
/// Assignment operator
|
||||
Enumeration & operator=(const Enumeration &other);
|
||||
/// get all possible enum values as vector of strings
|
||||
std::vector<std::string> getEnumVector() const;
|
||||
|
||||
/// true iff our string representation matches other's
|
||||
/*!
|
||||
* Returns false if either Enumeration is not valid.
|
||||
*/
|
||||
bool operator==(const Enumeration &other) const;
|
||||
/// returns true if the enum list is non-empty, false otherwise
|
||||
bool hasEnums() const;
|
||||
|
||||
/// true iff our string representation matches other
|
||||
/*!
|
||||
* Returns false if Enumeration is not valid.
|
||||
*/
|
||||
bool operator==(const char *other) const;
|
||||
protected:
|
||||
/// Returns true if instance was not initialized via static string list
|
||||
bool isCustom(void) const {return _ownEnumArray;}
|
||||
/// Returns true if the instance is in a usable state
|
||||
bool isValid() const;
|
||||
|
||||
/// Updates _maxVal
|
||||
void findMaxVal(void);
|
||||
/// Returns the highest usable integer value for this enum
|
||||
/*!
|
||||
* Returns -1 if the enumeration is not valid according to isValid()
|
||||
*/
|
||||
int maxValue() const;
|
||||
|
||||
/// De-allocates memory used in _EnumArray
|
||||
/*!
|
||||
* Important to not call this unless this Enumeration owns array.
|
||||
*/
|
||||
void tearDown(void);
|
||||
/// Returns true if any of the items is a user-defined string
|
||||
bool isCustom() const;
|
||||
|
||||
private:
|
||||
/// Handle to C Strings of possible enumeration values
|
||||
const char **_EnumArray;
|
||||
/// Assignment operator
|
||||
Enumeration & operator=(const Enumeration &other);
|
||||
|
||||
/// Whether instance owns _EnumArray
|
||||
bool _ownEnumArray;
|
||||
/// true iff our string representation matches other's
|
||||
/*!
|
||||
* Returns false if either Enumeration is not valid.
|
||||
*/
|
||||
bool operator==(const Enumeration &other) const;
|
||||
|
||||
/// Integer value of the enumeration
|
||||
/*!
|
||||
* This serves as an index into _EnumArray to get the string
|
||||
* representation.
|
||||
*/
|
||||
int _index;
|
||||
/// true iff our string representation matches other
|
||||
/*!
|
||||
* Returns false if Enumeration is not valid.
|
||||
*/
|
||||
bool operator==(const char *other) const;
|
||||
protected:
|
||||
|
||||
/*! Cached result from findMaxVal()
|
||||
* Value should either be the maximum allowable integer value for
|
||||
* the Enumeration, or -1 if not initialized
|
||||
*/
|
||||
int _maxVal;
|
||||
/// Number of items
|
||||
int countItems() const;
|
||||
|
||||
private:
|
||||
/// Handle to C Strings of possible enumeration values
|
||||
std::vector<Object> enumArray;
|
||||
|
||||
/// Integer value of the enumeration
|
||||
/*!
|
||||
* This serves as an index into enumArray to get the string
|
||||
* representation.
|
||||
*/
|
||||
int _index;
|
||||
|
||||
friend class PropertyEnumeration;
|
||||
}; // class Enumeration
|
||||
} // namespace App
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ FeatureTest::FeatureTest()
|
||||
ADD_PROPERTY_TYPE(TypeTransient,(4711),group,Prop_Transient ,"An example property which has the type 'Transient'" );
|
||||
ADD_PROPERTY_TYPE(TypeNoRecompute,(4711),group,Prop_NoRecompute,"An example property which has the type 'NoRecompute'");
|
||||
ADD_PROPERTY_TYPE(TypeAll ,(4711),group,(App::PropertyType) (Prop_Output|Prop_ReadOnly |Prop_Hidden ),
|
||||
"An example property which has the types 'Output', 'ReadOnly', and 'Hidden'");
|
||||
"An example property which has the types 'Output', 'ReadOnly' and 'Hidden'");
|
||||
|
||||
ADD_PROPERTY(QuantityLength,(1.0));
|
||||
QuantityLength.setUnit(Base::Unit::Length);
|
||||
@@ -118,13 +118,46 @@ FeatureTest::~FeatureTest()
|
||||
|
||||
}
|
||||
|
||||
short FeatureTest::mustExecute(void) const
|
||||
short FeatureTest::mustExecute() const
|
||||
{
|
||||
return DocumentObject::mustExecute();
|
||||
}
|
||||
|
||||
DocumentObjectExecReturn *FeatureTest::execute(void)
|
||||
DocumentObjectExecReturn *FeatureTest::execute()
|
||||
{
|
||||
// Enum handling
|
||||
Enumeration enumObj1 = Enum.getEnum();
|
||||
enumObj1.setValue(7, false);
|
||||
enumObj1.setValue(4, true);
|
||||
|
||||
Enumeration enumObj2 = Enum.getEnum();
|
||||
enumObj2.setValue(4, true);
|
||||
|
||||
Enumeration enumObj3(enumObj2);
|
||||
const char* val = enumObj3.getCStr();
|
||||
enumObj3.isValue(val);
|
||||
enumObj3.getEnumVector();
|
||||
|
||||
Enumeration enumObj4("Single item");
|
||||
enumObj4.setEnums(enums);
|
||||
std::ignore = enumObj4 == enumObj2;
|
||||
enumObj4.setEnums(nullptr);
|
||||
enumObj4 = enumObj2;
|
||||
std::ignore = enumObj4 == enumObj4.getCStr();
|
||||
|
||||
Enumeration enumObj5(enums, enums[3]);
|
||||
enumObj5.isValue(enums[2]);
|
||||
enumObj5.isValue(enums[3]);
|
||||
enumObj5.contains(enums[1]);
|
||||
|
||||
Enumeration enumObj6;
|
||||
enumObj6.setEnums(enums);
|
||||
enumObj6.setValue(enums[1]);
|
||||
std::vector<std::string> list;
|
||||
list.emplace_back("Hello");
|
||||
list.emplace_back("World");
|
||||
enumObj6.setEnums(list);
|
||||
enumObj6.setValue(list.back());
|
||||
/*
|
||||
doc=App.newDocument()
|
||||
obj=doc.addObject("App::FeatureTest")
|
||||
@@ -189,7 +222,7 @@ FeatureTestException::FeatureTestException()
|
||||
ADD_PROPERTY(ExceptionType,(Base::Exception::getClassTypeId().getKey()) );
|
||||
}
|
||||
|
||||
DocumentObjectExecReturn *FeatureTestException::execute(void)
|
||||
DocumentObjectExecReturn *FeatureTestException::execute()
|
||||
{
|
||||
//ExceptionType;
|
||||
throw Base::RuntimeError("FeatureTestException::execute(): Testexception ;-)");
|
||||
|
||||
@@ -232,14 +232,14 @@ void LinkBaseExtension::setProperty(int idx, Property *prop) {
|
||||
case PropLinkMode: {
|
||||
static const char *linkModeEnums[] = {"None","Auto Delete","Auto Link","Auto Unlink",nullptr};
|
||||
auto propLinkMode = static_cast<PropertyEnumeration*>(prop);
|
||||
if(!propLinkMode->getEnums())
|
||||
if(!propLinkMode->hasEnums())
|
||||
propLinkMode->setEnums(linkModeEnums);
|
||||
break;
|
||||
}
|
||||
case PropLinkCopyOnChange: {
|
||||
static const char *enums[] = {"Disabled","Enabled","Owned","Tracking",nullptr};
|
||||
auto propEnum = static_cast<PropertyEnumeration*>(prop);
|
||||
if(!propEnum->getEnums())
|
||||
if(!propEnum->hasEnums())
|
||||
propEnum->setEnums(enums);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -392,9 +392,9 @@ void PropertyEnumeration::setEnumVector(const std::vector<std::string> &values)
|
||||
hasSetValue();
|
||||
}
|
||||
|
||||
const char ** PropertyEnumeration::getEnums() const
|
||||
bool PropertyEnumeration::hasEnums() const
|
||||
{
|
||||
return _enum.getEnums();
|
||||
return _enum.hasEnums();
|
||||
}
|
||||
|
||||
bool PropertyEnumeration::isValid() const
|
||||
@@ -447,7 +447,7 @@ void PropertyEnumeration::Restore(Base::XMLReader &reader)
|
||||
|
||||
if (val < 0) {
|
||||
// If the enum is empty at this stage do not print a warning
|
||||
if (_enum.getEnums())
|
||||
if (_enum.hasEnums())
|
||||
Base::Console().Warning("Enumeration index %d is out of range, ignore it\n", val);
|
||||
val = getValue();
|
||||
}
|
||||
@@ -598,13 +598,13 @@ bool PropertyEnumeration::getPyPathValue(const ObjectIdentifier &path, Py::Objec
|
||||
if (p == ".Enum" || p == ".All") {
|
||||
Base::PyGILStateLocker lock;
|
||||
Py::Tuple res(_enum.maxValue()+1);
|
||||
const char **enums = _enum.getEnums();
|
||||
std::vector<std::string> enums = _enum.getEnumVector();
|
||||
PropertyString tmp;
|
||||
for(int i=0;i<=_enum.maxValue();++i) {
|
||||
for(int i=0;i< int(enums.size());++i) {
|
||||
tmp.setValue(enums[i]);
|
||||
res.setItem(i,Py::asObject(tmp.getPyObject()));
|
||||
}
|
||||
if(p == ".Enum")
|
||||
if (p == ".Enum")
|
||||
r = res;
|
||||
else {
|
||||
Py::Tuple tuple(2);
|
||||
@@ -1374,7 +1374,7 @@ PropertyString::~PropertyString()
|
||||
|
||||
void PropertyString::setValue(const char* newLabel)
|
||||
{
|
||||
if(!newLabel)
|
||||
if(!newLabel)
|
||||
return;
|
||||
|
||||
if(_cValue == newLabel)
|
||||
|
||||
@@ -206,7 +206,7 @@ public:
|
||||
/// set enum values as vector of strings
|
||||
void setEnumVector(const std::vector<std::string> &);
|
||||
/// get the pointer to the enum list
|
||||
const char ** getEnums(void) const;
|
||||
bool hasEnums() const;
|
||||
|
||||
/// Returns true if the instance is in a usable state
|
||||
bool isValid(void) const;
|
||||
|
||||
@@ -398,9 +398,9 @@ void DlgDisplayPropertiesImp::setDisplayModes(const std::vector<Gui::ViewProvide
|
||||
App::Property* prop = (*it)->getPropertyByName("DisplayMode");
|
||||
if (prop && prop->getTypeId() == App::PropertyEnumeration::getClassTypeId()) {
|
||||
App::PropertyEnumeration* display = static_cast<App::PropertyEnumeration*>(prop);
|
||||
if (!display->getEnums())
|
||||
if (!display->hasEnums())
|
||||
return;
|
||||
const std::vector<std::string>& value = display->getEnumVector();
|
||||
std::vector<std::string> value = display->getEnumVector();
|
||||
if (it == views.begin()) {
|
||||
for (std::vector<std::string>::const_iterator jt = value.begin(); jt != value.end(); ++jt)
|
||||
commonModes << QLatin1String(jt->c_str());
|
||||
|
||||
@@ -202,9 +202,9 @@ void TaskAppearance::setDisplayModes(const std::vector<Gui::ViewProvider*>& view
|
||||
App::Property* prop = (*it)->getPropertyByName("DisplayMode");
|
||||
if (prop && prop->getTypeId() == App::PropertyEnumeration::getClassTypeId()) {
|
||||
App::PropertyEnumeration* display = static_cast<App::PropertyEnumeration*>(prop);
|
||||
if (!display->getEnums())
|
||||
if (!display->hasEnums())
|
||||
return;
|
||||
const std::vector<std::string>& value = display->getEnumVector();
|
||||
std::vector<std::string> value = display->getEnumVector();
|
||||
if (it == views.begin()) {
|
||||
for (std::vector<std::string>::const_iterator jt = value.begin(); jt != value.end(); ++jt)
|
||||
commonModes << QLatin1String(jt->c_str());
|
||||
|
||||
@@ -2800,8 +2800,9 @@ QStringList PropertyEnumItem::getEnum() const
|
||||
auto prop = getFirstProperty();
|
||||
if (prop && prop->getTypeId().isDerivedFrom(App::PropertyEnumeration::getClassTypeId())) {
|
||||
const App::PropertyEnumeration* prop_enum = static_cast<const App::PropertyEnumeration*>(prop);
|
||||
for(int i=0; i<prop_enum->getEnum().maxValue(); ++i)
|
||||
res.push_back(QString::fromUtf8(prop_enum->getEnums()[i]));
|
||||
std::vector<std::string> enums = prop_enum->getEnumVector();
|
||||
for (const auto& it : enums)
|
||||
res.push_back(QString::fromStdString(it));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -2887,7 +2888,7 @@ QWidget* PropertyEnumItem::createEditor(QWidget* parent, const QObject* receiver
|
||||
for (std::vector<App::Property*>::const_iterator it = items.begin(); it != items.end(); ++it) {
|
||||
if ((*it)->getTypeId() == App::PropertyEnumeration::getClassTypeId()) {
|
||||
App::PropertyEnumeration* prop = static_cast<App::PropertyEnumeration*>(*it);
|
||||
if (prop->getEnums() == nullptr) {
|
||||
if (!prop->hasEnums()) {
|
||||
commonModes.clear();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -459,7 +459,7 @@ FemPostScalarClipFilter::~FemPostScalarClipFilter() {
|
||||
DocumentObjectExecReturn* FemPostScalarClipFilter::execute(void) {
|
||||
|
||||
std::string val;
|
||||
if (m_scalarFields.getEnums() && Scalars.getValue() >= 0)
|
||||
if (m_scalarFields.hasEnums() && Scalars.getValue() >= 0)
|
||||
val = Scalars.getValueAsString();
|
||||
|
||||
std::vector<std::string> array;
|
||||
@@ -562,7 +562,7 @@ FemPostWarpVectorFilter::~FemPostWarpVectorFilter() {
|
||||
DocumentObjectExecReturn* FemPostWarpVectorFilter::execute(void) {
|
||||
|
||||
std::string val;
|
||||
if (m_vectorFields.getEnums() && Vector.getValue() >= 0)
|
||||
if (m_vectorFields.hasEnums() && Vector.getValue() >= 0)
|
||||
val = Vector.getValueAsString();
|
||||
|
||||
std::vector<std::string> array;
|
||||
|
||||
@@ -249,7 +249,7 @@ void ViewProviderFemPostObject::updateProperties() {
|
||||
|
||||
//coloring
|
||||
std::string val;
|
||||
if (Field.getEnums() && Field.getValue() >= 0)
|
||||
if (Field.hasEnums() && Field.getValue() >= 0)
|
||||
val = Field.getValueAsString();
|
||||
|
||||
std::vector<std::string> colorArrays;
|
||||
@@ -278,7 +278,7 @@ void ViewProviderFemPostObject::updateProperties() {
|
||||
Field.purgeTouched();
|
||||
|
||||
//Vector mode
|
||||
if (VectorMode.getEnums() && VectorMode.getValue() >= 0)
|
||||
if (VectorMode.hasEnums() && VectorMode.getValue() >= 0)
|
||||
val = VectorMode.getValueAsString();
|
||||
|
||||
colorArrays.clear();
|
||||
|
||||
@@ -78,17 +78,15 @@ TaskHoleParameters::TaskHoleParameters(ViewProviderHole* HoleView, QWidget* pare
|
||||
ui->ThreadType->setCurrentIndex(pcHole->ThreadType.getValue());
|
||||
|
||||
ui->ThreadSize->clear();
|
||||
const char** cursor = pcHole->ThreadSize.getEnums();
|
||||
while (*cursor) {
|
||||
ui->ThreadSize->addItem(tr(*cursor));
|
||||
++cursor;
|
||||
std::vector<std::string> cursor = pcHole->ThreadSize.getEnumVector();
|
||||
for (const auto& it : cursor) {
|
||||
ui->ThreadSize->addItem(tr(it.c_str()));
|
||||
}
|
||||
ui->ThreadSize->setCurrentIndex(pcHole->ThreadSize.getValue());
|
||||
ui->ThreadClass->clear();
|
||||
cursor = pcHole->ThreadClass.getEnums();
|
||||
while (*cursor) {
|
||||
ui->ThreadClass->addItem(tr(*cursor));
|
||||
++cursor;
|
||||
cursor = pcHole->ThreadClass.getEnumVector();
|
||||
for (const auto& it : cursor) {
|
||||
ui->ThreadClass->addItem(tr(it.c_str()));
|
||||
}
|
||||
ui->ThreadClass->setCurrentIndex(pcHole->ThreadClass.getValue());
|
||||
// Class is only enabled (sensible) if threaded
|
||||
@@ -109,10 +107,9 @@ TaskHoleParameters::TaskHoleParameters(ViewProviderHole* HoleView, QWidget* pare
|
||||
ui->directionRightHand->setEnabled(pcHole->Threaded.getValue());
|
||||
ui->directionLeftHand->setEnabled(pcHole->Threaded.getValue());
|
||||
ui->HoleCutType->clear();
|
||||
cursor = pcHole->HoleCutType.getEnums();
|
||||
while (*cursor) {
|
||||
ui->HoleCutType->addItem(tr(*cursor));
|
||||
++cursor;
|
||||
cursor = pcHole->HoleCutType.getEnumVector();
|
||||
for (const auto& it : cursor) {
|
||||
ui->HoleCutType->addItem(tr(it.c_str()));
|
||||
}
|
||||
ui->HoleCutType->setCurrentIndex(pcHole->HoleCutType.getValue());
|
||||
ui->HoleCutCustomValues->setChecked(pcHole->HoleCutCustomValues.getValue());
|
||||
@@ -714,10 +711,9 @@ void TaskHoleParameters::changedObject(const App::Document&, const App::Property
|
||||
|
||||
ui->ThreadSize->blockSignals(true);
|
||||
ui->ThreadSize->clear();
|
||||
const char** cursor = pcHole->ThreadSize.getEnums();
|
||||
while (*cursor) {
|
||||
ui->ThreadSize->addItem(QString::fromLatin1(*cursor));
|
||||
++cursor;
|
||||
std::vector<std::string> cursor = pcHole->ThreadSize.getEnumVector();
|
||||
for (const auto& it : cursor) {
|
||||
ui->ThreadSize->addItem(QString::fromStdString(it));
|
||||
}
|
||||
ui->ThreadSize->setCurrentIndex(pcHole->ThreadSize.getValue());
|
||||
ui->ThreadSize->blockSignals(false);
|
||||
@@ -725,20 +721,18 @@ void TaskHoleParameters::changedObject(const App::Document&, const App::Property
|
||||
// Thread type also updates HoleCutType and ThreadClass
|
||||
ui->HoleCutType->blockSignals(true);
|
||||
ui->HoleCutType->clear();
|
||||
cursor = pcHole->HoleCutType.getEnums();
|
||||
while (*cursor) {
|
||||
ui->HoleCutType->addItem(QString::fromLatin1(*cursor));
|
||||
++cursor;
|
||||
cursor = pcHole->HoleCutType.getEnumVector();
|
||||
for (const auto& it: cursor) {
|
||||
ui->HoleCutType->addItem(QString::fromStdString(it));
|
||||
}
|
||||
ui->HoleCutType->setCurrentIndex(pcHole->HoleCutType.getValue());
|
||||
ui->HoleCutType->blockSignals(false);
|
||||
|
||||
ui->ThreadClass->blockSignals(true);
|
||||
ui->ThreadClass->clear();
|
||||
cursor = pcHole->ThreadClass.getEnums();
|
||||
while (*cursor) {
|
||||
ui->ThreadClass->addItem(QString::fromLatin1(*cursor));
|
||||
++cursor;
|
||||
cursor = pcHole->ThreadClass.getEnumVector();
|
||||
for (const auto& it : cursor) {
|
||||
ui->ThreadClass->addItem(QString::fromStdString(it));
|
||||
}
|
||||
ui->ThreadClass->setCurrentIndex(pcHole->ThreadClass.getValue());
|
||||
ui->ThreadClass->blockSignals(false);
|
||||
|
||||
Reference in New Issue
Block a user