Fixed DefinitionWatcher receiving changes after destruction
This commit is contained in:
parent
9b3251ee54
commit
c74b6cbdda
37 changed files with 275 additions and 154 deletions
|
@ -134,29 +134,6 @@ void DefinitionNode::generateInitDiffs(vector<const DefinitionDiff *> *diffs) co
|
||||||
// TODO add children diffs in cascade ?
|
// TODO add children diffs in cascade ?
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefinitionNode::addWatcher(DefinitionWatcher *watcher, bool init_diff) {
|
|
||||||
if (root && root->diffs) {
|
|
||||||
if (init_diff) {
|
|
||||||
vector<const DefinitionDiff *> diffs;
|
|
||||||
generateInitDiffs(&diffs);
|
|
||||||
|
|
||||||
for (auto diff : diffs) {
|
|
||||||
watcher->nodeChanged(this, diff, this);
|
|
||||||
delete diff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
root->diffs->addWatcher(this, watcher);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long DefinitionNode::getWatcherCount() const {
|
|
||||||
if (root && root->diffs) {
|
|
||||||
return root->diffs->getWatcherCount(this);
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DefinitionNode::save(PackStream *stream) const {
|
void DefinitionNode::save(PackStream *stream) const {
|
||||||
int children_count = static_cast<int>(children.size());
|
int children_count = static_cast<int>(children.size());
|
||||||
stream->write(&children_count);
|
stream->write(&children_count);
|
||||||
|
@ -222,6 +199,7 @@ void DefinitionNode::copy(DefinitionNode *destination) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefinitionNode::validate() {
|
void DefinitionNode::validate() {
|
||||||
|
// TODO This should be deprecated in favor of onChildChange
|
||||||
for (auto child : children) {
|
for (auto child : children) {
|
||||||
child->validate();
|
child->validate();
|
||||||
}
|
}
|
||||||
|
@ -255,6 +233,18 @@ DefinitionNode *DefinitionNode::findChildByName(const string &name) const {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DefinitionNode::tellChanged() {
|
||||||
|
if (parent) {
|
||||||
|
parent->onChildChanged(0, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefinitionNode::onChildChanged(int depth, const string &relpath) {
|
||||||
|
if (parent) {
|
||||||
|
parent->onChildChanged(depth + 1, name + "/" + relpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int DefinitionNode::getStreamSize() const {
|
int DefinitionNode::getStreamSize() const {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,25 +82,26 @@ class DEFINITIONSHARED_EXPORT DefinitionNode {
|
||||||
*/
|
*/
|
||||||
virtual void generateInitDiffs(vector<const DefinitionDiff *> *diffs) const;
|
virtual void generateInitDiffs(vector<const DefinitionDiff *> *diffs) const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a watcher over this node.
|
|
||||||
*
|
|
||||||
* The watcher will receive DefinitionDiff objects when this node changes.
|
|
||||||
*
|
|
||||||
* If 'init_diff' is set to true, a first diff (or several) will be be pushed immediately to initialize the state.
|
|
||||||
*/
|
|
||||||
void addWatcher(DefinitionWatcher *watcher, bool init_diff = false);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current number of watchers.
|
|
||||||
*/
|
|
||||||
unsigned long getWatcherCount() const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void addChild(DefinitionNode *child);
|
void addChild(DefinitionNode *child);
|
||||||
void removeChild(DefinitionNode *child);
|
void removeChild(DefinitionNode *child);
|
||||||
virtual DefinitionNode *findChildByName(const string &name) const;
|
virtual DefinitionNode *findChildByName(const string &name) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The subclass should call this method when the direct value of the node (not a child node) changed.
|
||||||
|
*/
|
||||||
|
void tellChanged();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a child changed in the definition tree.
|
||||||
|
*
|
||||||
|
* The base implementation propagates the event up the definition tree.
|
||||||
|
*
|
||||||
|
* "depth" is the depth level the node is in (0 for a direct child, 1 for a grandchild...).
|
||||||
|
* "relpath" is the relative path of the changed node.
|
||||||
|
*/
|
||||||
|
virtual void onChildChanged(int depth, const string &relpath);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the size in bytes this child will consume when serialized to a stream.
|
* Get the size in bytes this child will consume when serialized to a stream.
|
||||||
*
|
*
|
||||||
|
|
|
@ -3,13 +3,26 @@
|
||||||
#include "IntDiff.h"
|
#include "IntDiff.h"
|
||||||
#include "FloatDiff.h"
|
#include "FloatDiff.h"
|
||||||
#include "DefinitionNode.h"
|
#include "DefinitionNode.h"
|
||||||
|
#include "DiffManager.h"
|
||||||
#include "Logs.h"
|
#include "Logs.h"
|
||||||
|
|
||||||
DefinitionWatcher::DefinitionWatcher() {
|
DefinitionWatcher::DefinitionWatcher(const string &name) : name(name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DefinitionWatcher::~DefinitionWatcher() {
|
DefinitionWatcher::~DefinitionWatcher() {
|
||||||
// FIXME watcher is not removed from the diff manager !
|
if (registered_to.size() > 0) {
|
||||||
|
Logs::error("Definition")
|
||||||
|
<< "Watcher still registered at destruction, forcing potentially harmful unregister : " << name << endl;
|
||||||
|
unregister();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefinitionWatcher::unregister() {
|
||||||
|
set<DiffManager *> copy_registered_to = registered_to;
|
||||||
|
registered_to.clear();
|
||||||
|
for (auto diff_manager : copy_registered_to) {
|
||||||
|
diff_manager->removeWatcher(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefinitionWatcher::nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *) {
|
void DefinitionWatcher::nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *) {
|
||||||
|
@ -30,15 +43,27 @@ void DefinitionWatcher::intNodeChanged(const string &, int, int) {
|
||||||
void DefinitionWatcher::floatNodeChanged(const string &, double, double) {
|
void DefinitionWatcher::floatNodeChanged(const string &, double, double) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefinitionWatcher::startWatching(const DefinitionNode *root, const string &path, bool init_diff) {
|
void DefinitionWatcher::startWatchingPath(const DefinitionNode *root, const string &path, bool init_diff) {
|
||||||
DefinitionNode *node = root->findByPath(path);
|
DefinitionNode *node = root->findByPath(path);
|
||||||
if (node) {
|
if (node) {
|
||||||
node->addWatcher(this, init_diff);
|
startWatching(node, init_diff);
|
||||||
} else {
|
} else {
|
||||||
Logs::warning("Definition") << "Node not found for watching : " << path << endl;
|
Logs::warning("Definition") << "Node not found for watching : " << path << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefinitionWatcher::startWatching(const DefinitionNode *node, bool init_diff) {
|
void DefinitionWatcher::startWatching(const DefinitionNode *node, bool init_diff) {
|
||||||
startWatching(node->getRoot(), node->getPath(), init_diff);
|
if (auto diff_manager = node->getRoot()->getDiffManager()) {
|
||||||
|
if (init_diff) {
|
||||||
|
vector<const DefinitionDiff *> diffs;
|
||||||
|
node->generateInitDiffs(&diffs);
|
||||||
|
|
||||||
|
for (auto diff : diffs) {
|
||||||
|
nodeChanged(node, diff, node);
|
||||||
|
delete diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff_manager->addWatcher(node, this);
|
||||||
|
registered_to.insert(diff_manager);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "definition_global.h"
|
#include "definition_global.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
namespace definition {
|
namespace definition {
|
||||||
|
@ -15,9 +16,19 @@ namespace definition {
|
||||||
*/
|
*/
|
||||||
class DEFINITIONSHARED_EXPORT DefinitionWatcher {
|
class DEFINITIONSHARED_EXPORT DefinitionWatcher {
|
||||||
public:
|
public:
|
||||||
DefinitionWatcher();
|
DefinitionWatcher(const string &name);
|
||||||
virtual ~DefinitionWatcher();
|
virtual ~DefinitionWatcher();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister from all watched nodes.
|
||||||
|
*
|
||||||
|
* This MUST be called before destructor.
|
||||||
|
*
|
||||||
|
* A watcher should also make sure it is not unregistered as a direct result of a nodeChanged call,
|
||||||
|
* or this may cause a deadlock.
|
||||||
|
*/
|
||||||
|
void unregister();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract method called when a node changed.
|
* Abstract method called when a node changed.
|
||||||
*
|
*
|
||||||
|
@ -29,12 +40,10 @@ class DEFINITIONSHARED_EXPORT DefinitionWatcher {
|
||||||
/**
|
/**
|
||||||
* Start watching a path in a definition tree.
|
* Start watching a path in a definition tree.
|
||||||
*/
|
*/
|
||||||
void startWatching(const DefinitionNode *root, const string &path, bool init_diff = true);
|
void startWatchingPath(const DefinitionNode *root, const string &path, bool init_diff = true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start watching a node.
|
* Start watching a node.
|
||||||
*
|
|
||||||
* Overloaded for convenience.
|
|
||||||
*/
|
*/
|
||||||
void startWatching(const DefinitionNode *node, bool init_diff = true);
|
void startWatching(const DefinitionNode *node, bool init_diff = true);
|
||||||
|
|
||||||
|
@ -47,6 +56,10 @@ class DEFINITIONSHARED_EXPORT DefinitionWatcher {
|
||||||
* Abstract convenience to receive float node changes.
|
* Abstract convenience to receive float node changes.
|
||||||
*/
|
*/
|
||||||
virtual void floatNodeChanged(const string &path, double new_value, double old_value);
|
virtual void floatNodeChanged(const string &path, double new_value, double old_value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
string name;
|
||||||
|
set<DiffManager *> registered_to;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <mutex>
|
||||||
#include "DefinitionNode.h"
|
#include "DefinitionNode.h"
|
||||||
#include "DefinitionDiff.h"
|
#include "DefinitionDiff.h"
|
||||||
#include "DefinitionWatcher.h"
|
#include "DefinitionWatcher.h"
|
||||||
|
@ -13,6 +14,7 @@ class DiffManager::pimpl {
|
||||||
pimpl(DefinitionNode *tree) : tree(tree), undone(0) {
|
pimpl(DefinitionNode *tree) : tree(tree), undone(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recursive_mutex lock;
|
||||||
DefinitionNode *tree;
|
DefinitionNode *tree;
|
||||||
unsigned long undone;
|
unsigned long undone;
|
||||||
vector<const DefinitionDiff *> diffs;
|
vector<const DefinitionDiff *> diffs;
|
||||||
|
@ -35,10 +37,21 @@ unsigned long DiffManager::getDiffCount(int include_undone) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiffManager::addWatcher(const DefinitionNode *node, DefinitionWatcher *watcher) {
|
void DiffManager::addWatcher(const DefinitionNode *node, DefinitionWatcher *watcher) {
|
||||||
|
impl->lock.lock();
|
||||||
auto &watchers = impl->watchers[node];
|
auto &watchers = impl->watchers[node];
|
||||||
if (find(watchers.begin(), watchers.end(), watcher) == watchers.end()) {
|
if (find(watchers.begin(), watchers.end(), watcher) == watchers.end()) {
|
||||||
watchers.push_back(watcher);
|
watchers.push_back(watcher);
|
||||||
}
|
}
|
||||||
|
impl->lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiffManager::removeWatcher(DefinitionWatcher *watcher) {
|
||||||
|
impl->lock.lock();
|
||||||
|
for (auto &item : impl->watchers) {
|
||||||
|
auto &node_watchers = item.second;
|
||||||
|
node_watchers.erase(remove(node_watchers.begin(), node_watchers.end(), watcher), node_watchers.end());
|
||||||
|
}
|
||||||
|
impl->lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long DiffManager::getWatcherCount(const DefinitionNode *node) {
|
unsigned long DiffManager::getWatcherCount(const DefinitionNode *node) {
|
||||||
|
@ -102,12 +115,16 @@ void DiffManager::redo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiffManager::publishToWatchers(const DefinitionNode *node, const DefinitionDiff *diff) {
|
void DiffManager::publishToWatchers(const DefinitionNode *node, const DefinitionDiff *diff) {
|
||||||
// TODO Parent node signaling should be aggregated (to not receive many nodeChanged calls)
|
impl->lock.lock();
|
||||||
|
|
||||||
const DefinitionNode *cnode = node;
|
const DefinitionNode *cnode = node;
|
||||||
do {
|
do {
|
||||||
for (auto watcher : impl->watchers[cnode]) {
|
for (auto watcher : impl->watchers[cnode]) {
|
||||||
watcher->nodeChanged(node, diff, cnode);
|
watcher->nodeChanged(node, diff, cnode);
|
||||||
}
|
}
|
||||||
|
// TODO Parent node signaling should be aggregated (to not receive many nodeChanged calls)
|
||||||
cnode = cnode->getParent();
|
cnode = cnode->getParent();
|
||||||
} while (cnode);
|
} while (cnode);
|
||||||
|
|
||||||
|
impl->lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,11 @@ class DEFINITIONSHARED_EXPORT DiffManager {
|
||||||
*/
|
*/
|
||||||
void addWatcher(const DefinitionNode *node, DefinitionWatcher *watcher);
|
void addWatcher(const DefinitionNode *node, DefinitionWatcher *watcher);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a watcher from all nodes.
|
||||||
|
*/
|
||||||
|
void removeWatcher(DefinitionWatcher *watcher);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of watchers registered for a given node.
|
* Get the number of watchers registered for a given node.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -61,6 +61,7 @@ bool FloatNode::applyDiff(const DefinitionDiff *diff, bool backward) {
|
||||||
|
|
||||||
if (value == previous) {
|
if (value == previous) {
|
||||||
value = next;
|
value = next;
|
||||||
|
tellChanged();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Logs::error("Definition") << "Can't apply float diff " << previous << " => " << next << " to " << getName()
|
Logs::error("Definition") << "Can't apply float diff " << previous << " => " << next << " to " << getName()
|
||||||
|
|
|
@ -61,6 +61,7 @@ bool IntNode::applyDiff(const DefinitionDiff *diff, bool backward) {
|
||||||
|
|
||||||
if (value == previous) {
|
if (value == previous) {
|
||||||
value = next;
|
value = next;
|
||||||
|
tellChanged();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Logs::error("Definition") << "Can't apply int diff " << previous << " => " << next << " to " << getName()
|
Logs::error("Definition") << "Can't apply int diff " << previous << " => " << next << " to " << getName()
|
||||||
|
|
|
@ -32,6 +32,6 @@ void VegetationDefinition::applyPreset(VegetationPreset preset, RandomGenerator
|
||||||
if (preset == VEGETATION_PRESET_TEMPERATE) {
|
if (preset == VEGETATION_PRESET_TEMPERATE) {
|
||||||
layer.applyPreset(VegetationLayerDefinition::VEGETATION_BASIC_TREES, random);
|
layer.applyPreset(VegetationLayerDefinition::VEGETATION_BASIC_TREES, random);
|
||||||
layer.setName("Basic tree");
|
layer.setName("Basic tree");
|
||||||
//addLayer(layer);
|
// addLayer(layer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,6 @@ WaterDefinition::WaterDefinition(DefinitionNode *parent) : DefinitionNode(parent
|
||||||
detail_height = 0.0;
|
detail_height = 0.0;
|
||||||
turbulence = 0.0;
|
turbulence = 0.0;
|
||||||
foam_coverage = 0.0;
|
foam_coverage = 0.0;
|
||||||
|
|
||||||
model->addWatcher(this, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WaterDefinition::~WaterDefinition() {
|
WaterDefinition::~WaterDefinition() {
|
||||||
|
@ -79,18 +77,19 @@ void WaterDefinition::load(PackStream *stream) {
|
||||||
void WaterDefinition::copy(DefinitionNode *_destination) const {
|
void WaterDefinition::copy(DefinitionNode *_destination) const {
|
||||||
DefinitionNode::copy(_destination);
|
DefinitionNode::copy(_destination);
|
||||||
|
|
||||||
WaterDefinition *destination = (WaterDefinition *)_destination;
|
if (auto destination = static_cast<WaterDefinition *>(_destination)) {
|
||||||
*destination->material = *material;
|
*destination->material = *material;
|
||||||
destination->transparency_depth = transparency_depth;
|
destination->transparency_depth = transparency_depth;
|
||||||
destination->transparency = transparency;
|
destination->transparency = transparency;
|
||||||
destination->lighting_depth = lighting_depth;
|
destination->lighting_depth = lighting_depth;
|
||||||
destination->scaling = scaling;
|
destination->scaling = scaling;
|
||||||
destination->waves_height = waves_height;
|
destination->waves_height = waves_height;
|
||||||
destination->detail_height = detail_height;
|
destination->detail_height = detail_height;
|
||||||
destination->turbulence = turbulence;
|
destination->turbulence = turbulence;
|
||||||
destination->foam_coverage = foam_coverage;
|
destination->foam_coverage = foam_coverage;
|
||||||
*destination->foam_material = *foam_material;
|
*destination->foam_material = *foam_material;
|
||||||
noise_state->copy(destination->noise_state);
|
noise_state->copy(destination->noise_state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterDefinition::validate() {
|
void WaterDefinition::validate() {
|
||||||
|
@ -109,8 +108,18 @@ void WaterDefinition::validate() {
|
||||||
foam_material->validate();
|
foam_material->validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterDefinition::nodeChanged(const DefinitionNode *node, const DefinitionDiff *, const DefinitionNode *) {
|
void WaterDefinition::applyPreset(WaterPreset preset, RandomGenerator &random) {
|
||||||
if (node == model) {
|
noise_state->randomizeOffsets(random);
|
||||||
|
|
||||||
|
if (preset == WATER_PRESET_LAKE) {
|
||||||
|
model->setValue(0);
|
||||||
|
} else if (preset == WATER_PRESET_SEA) {
|
||||||
|
model->setValue(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaterDefinition::onChildChanged(int, const string &relpath) {
|
||||||
|
if (relpath == "model") {
|
||||||
switch (model->getValue()) {
|
switch (model->getValue()) {
|
||||||
case 1:
|
case 1:
|
||||||
transparency = 0.3;
|
transparency = 0.3;
|
||||||
|
@ -142,13 +151,3 @@ void WaterDefinition::nodeChanged(const DefinitionNode *node, const DefinitionDi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterDefinition::applyPreset(WaterPreset preset, RandomGenerator &random) {
|
|
||||||
noise_state->randomizeOffsets(random);
|
|
||||||
|
|
||||||
if (preset == WATER_PRESET_LAKE) {
|
|
||||||
model->setValue(0);
|
|
||||||
} else if (preset == WATER_PRESET_SEA) {
|
|
||||||
model->setValue(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
namespace definition {
|
namespace definition {
|
||||||
|
|
||||||
class DEFINITIONSHARED_EXPORT WaterDefinition : public DefinitionNode, public DefinitionWatcher {
|
class DEFINITIONSHARED_EXPORT WaterDefinition : public DefinitionNode {
|
||||||
public:
|
public:
|
||||||
WaterDefinition(DefinitionNode *parent);
|
WaterDefinition(DefinitionNode *parent);
|
||||||
virtual ~WaterDefinition();
|
virtual ~WaterDefinition();
|
||||||
|
@ -36,12 +36,12 @@ class DEFINITIONSHARED_EXPORT WaterDefinition : public DefinitionNode, public De
|
||||||
return depth_color;
|
return depth_color;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff,
|
|
||||||
const DefinitionNode *parent) override;
|
|
||||||
|
|
||||||
typedef enum { WATER_PRESET_LAKE, WATER_PRESET_SEA } WaterPreset;
|
typedef enum { WATER_PRESET_LAKE, WATER_PRESET_SEA } WaterPreset;
|
||||||
void applyPreset(WaterPreset preset, RandomGenerator &random = RandomGeneratorDefault);
|
void applyPreset(WaterPreset preset, RandomGenerator &random = RandomGeneratorDefault);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void onChildChanged(int depth, const string &relpath) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
double transparency;
|
double transparency;
|
||||||
SurfaceMaterial *material;
|
SurfaceMaterial *material;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
namespace modeler {
|
namespace modeler {
|
||||||
|
|
||||||
class AtmosphereModeler : protected BaseModelerTool {
|
class AtmosphereModeler : public BaseModelerTool {
|
||||||
public:
|
public:
|
||||||
AtmosphereModeler(MainModelerWindow *ui);
|
AtmosphereModeler(MainModelerWindow *ui);
|
||||||
|
|
||||||
|
|
|
@ -14,19 +14,30 @@ class BaseModelerTool::pimpl {
|
||||||
vector<unique_ptr<FloatPropertyBind>> float_bindings;
|
vector<unique_ptr<FloatPropertyBind>> float_bindings;
|
||||||
};
|
};
|
||||||
|
|
||||||
BaseModelerTool::BaseModelerTool(MainModelerWindow *ui) : impl(new pimpl), ui(ui) {
|
BaseModelerTool::BaseModelerTool(MainModelerWindow *ui)
|
||||||
|
: DefinitionWatcher("BaseModelerTool"), impl(new pimpl), ui(ui) {
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseModelerTool::~BaseModelerTool() {
|
BaseModelerTool::~BaseModelerTool() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BaseModelerTool::destroy() {
|
||||||
|
for (auto &binding : impl->int_bindings) {
|
||||||
|
binding->unregister();
|
||||||
|
}
|
||||||
|
for (auto &binding : impl->float_bindings) {
|
||||||
|
binding->unregister();
|
||||||
|
}
|
||||||
|
unregister();
|
||||||
|
}
|
||||||
|
|
||||||
void BaseModelerTool::addIntBinding(const string &object, const string &property, const string &path, bool monitor) {
|
void BaseModelerTool::addIntBinding(const string &object, const string &property, const string &path, bool monitor) {
|
||||||
auto node = static_cast<IntNode *>(ui->getScenery()->findByPath(path));
|
auto node = static_cast<IntNode *>(ui->getScenery()->findByPath(path));
|
||||||
if (node) {
|
if (node) {
|
||||||
impl->int_bindings.push_back(make_unique<IntPropertyBind>(ui, object, property, node));
|
impl->int_bindings.push_back(make_unique<IntPropertyBind>(ui, object, property, node));
|
||||||
|
|
||||||
if (monitor) {
|
if (monitor) {
|
||||||
startWatching(ui->getScenery(), path, false);
|
startWatchingPath(ui->getScenery(), path, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Logs::error("UI") << "Can't find int node for binding : " << path << endl;
|
Logs::error("UI") << "Can't find int node for binding : " << path << endl;
|
||||||
|
@ -39,7 +50,7 @@ void BaseModelerTool::addFloatBinding(const string &object, const string &proper
|
||||||
impl->float_bindings.push_back(make_unique<FloatPropertyBind>(ui, object, property, node));
|
impl->float_bindings.push_back(make_unique<FloatPropertyBind>(ui, object, property, node));
|
||||||
|
|
||||||
if (monitor) {
|
if (monitor) {
|
||||||
startWatching(ui->getScenery(), path, false);
|
startWatchingPath(ui->getScenery(), path, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Logs::error("UI") << "Can't find float node for binding : " << path << endl;
|
Logs::error("UI") << "Can't find float node for binding : " << path << endl;
|
||||||
|
|
|
@ -10,11 +10,16 @@
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
namespace modeler {
|
namespace modeler {
|
||||||
|
|
||||||
class BaseModelerTool : public DefinitionWatcher {
|
class BaseModelerTool : protected DefinitionWatcher {
|
||||||
public:
|
public:
|
||||||
BaseModelerTool(MainModelerWindow *ui);
|
BaseModelerTool(MainModelerWindow *ui);
|
||||||
virtual ~BaseModelerTool();
|
virtual ~BaseModelerTool();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call before destructor, to allow for proper release of resources.
|
||||||
|
*/
|
||||||
|
virtual void destroy();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an automated two-way binding between a QML int property and a scenery IntNode.
|
* Add an automated two-way binding between a QML int property and a scenery IntNode.
|
||||||
*
|
*
|
||||||
|
|
|
@ -8,10 +8,11 @@
|
||||||
|
|
||||||
FloatPropertyBind::FloatPropertyBind(MainModelerWindow *window, const string &object_name, const string &property_name,
|
FloatPropertyBind::FloatPropertyBind(MainModelerWindow *window, const string &object_name, const string &property_name,
|
||||||
FloatNode *node)
|
FloatNode *node)
|
||||||
: QObject(window), node(node), property(property_name) {
|
: QObject(window), DefinitionWatcher("FloatPropertyBind " + object_name + "." + property_name), node(node),
|
||||||
|
property(property_name) {
|
||||||
item = window->findQmlObject(object_name);
|
item = window->findQmlObject(object_name);
|
||||||
if (item) {
|
if (item) {
|
||||||
node->addWatcher(this, true);
|
startWatching(node);
|
||||||
string signal_name("2" + property_name + "Changed()");
|
string signal_name("2" + property_name + "Changed()");
|
||||||
connect(item, signal_name.c_str(), this, SLOT(propertyChanged()));
|
connect(item, signal_name.c_str(), this, SLOT(propertyChanged()));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -6,10 +6,11 @@
|
||||||
|
|
||||||
IntPropertyBind::IntPropertyBind(MainModelerWindow *window, const string &object_name, const string &property_name,
|
IntPropertyBind::IntPropertyBind(MainModelerWindow *window, const string &object_name, const string &property_name,
|
||||||
IntNode *node)
|
IntNode *node)
|
||||||
: QObject(window), node(node), property(property_name) {
|
: QObject(window), DefinitionWatcher("IntPropertyBind " + object_name + "." + property_name), node(node),
|
||||||
|
property(property_name) {
|
||||||
item = window->findQmlObject(object_name);
|
item = window->findQmlObject(object_name);
|
||||||
if (item) {
|
if (item) {
|
||||||
node->addWatcher(this, true);
|
startWatching(node);
|
||||||
string signal_name("2" + property_name + "Changed()");
|
string signal_name("2" + property_name + "Changed()");
|
||||||
connect(item, signal_name.c_str(), this, SLOT(propertyChanged()));
|
connect(item, signal_name.c_str(), this, SLOT(propertyChanged()));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -27,8 +27,8 @@ class IntPropertyBind : public QObject, public DefinitionWatcher {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IntNode *node;
|
IntNode *node;
|
||||||
string property;
|
|
||||||
QObject *item;
|
QObject *item;
|
||||||
|
string property;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,11 @@ MainModelerWindow::MainModelerWindow() {
|
||||||
}
|
}
|
||||||
|
|
||||||
MainModelerWindow::~MainModelerWindow() {
|
MainModelerWindow::~MainModelerWindow() {
|
||||||
|
// TODO Should be done automatically for all tools
|
||||||
|
cameras->unregister();
|
||||||
|
atmosphere->destroy();
|
||||||
|
water->destroy();
|
||||||
|
|
||||||
delete atmosphere;
|
delete atmosphere;
|
||||||
delete water;
|
delete water;
|
||||||
delete cameras;
|
delete cameras;
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
#include "AtmosphereRenderer.h"
|
#include "AtmosphereRenderer.h"
|
||||||
#include "Timing.h"
|
#include "Timing.h"
|
||||||
|
|
||||||
ModelerCameras::ModelerCameras(MainModelerWindow *parent) : QObject(parent), parent(parent) {
|
ModelerCameras::ModelerCameras(MainModelerWindow *parent)
|
||||||
|
: QObject(parent), DefinitionWatcher("ModelerCameras"), parent(parent) {
|
||||||
render = new CameraDefinition();
|
render = new CameraDefinition();
|
||||||
topdown = new CameraDefinition();
|
topdown = new CameraDefinition();
|
||||||
current = new CameraDefinition();
|
current = new CameraDefinition();
|
||||||
|
|
|
@ -9,24 +9,17 @@
|
||||||
#include "OpenGLRenderer.h"
|
#include "OpenGLRenderer.h"
|
||||||
#include "OpenGLWater.h"
|
#include "OpenGLWater.h"
|
||||||
|
|
||||||
WaterModeler::WaterModeler(MainModelerWindow *ui) : ui(ui) {
|
WaterModeler::WaterModeler(MainModelerWindow *ui) : BaseModelerTool(ui) {
|
||||||
QObject *toggle_water = ui->findQmlObject("camera_toggle_water");
|
QObject *toggle_water = ui->findQmlObject("camera_toggle_water");
|
||||||
if (toggle_water) {
|
if (toggle_water) {
|
||||||
connect(toggle_water, SIGNAL(toggled(bool)), this, SLOT(enableRendering(bool)));
|
connect(toggle_water, SIGNAL(toggled(bool)), this, SLOT(enableRendering(bool)));
|
||||||
}
|
}
|
||||||
|
|
||||||
prop_model = new IntPropertyBind(ui, "water_model", "value", ui->getScenery()->getWater()->propModel());
|
addIntBinding("water_model", "value", "/water/model");
|
||||||
prop_height = new FloatPropertyBind(ui, "water_height", "value", ui->getScenery()->getTerrain()->propWaterHeight());
|
addFloatBinding("water_height", "value", "/terrain/water_height");
|
||||||
prop_reflexion =
|
addFloatBinding("water_reflection", "value", "/water/reflection");
|
||||||
new FloatPropertyBind(ui, "water_reflection", "value", ui->getScenery()->getWater()->propReflection());
|
|
||||||
}
|
|
||||||
|
|
||||||
WaterModeler::~WaterModeler() {
|
|
||||||
delete prop_model;
|
|
||||||
delete prop_height;
|
|
||||||
delete prop_reflexion;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaterModeler::enableRendering(bool enable) {
|
void WaterModeler::enableRendering(bool enable) {
|
||||||
ui->getRenderer()->getWater()->setEnabled(enable);
|
getWindow()->getRenderer()->getWater()->setEnabled(enable);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,21 @@
|
||||||
#ifndef WATERMODELER_H
|
#ifndef WATERMODELER_H
|
||||||
#define WATERMODELER_H
|
#define WATERMODELER_H
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
#include "modeler_global.h"
|
#include "modeler_global.h"
|
||||||
|
|
||||||
|
#include "BaseModelerTool.h"
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
namespace modeler {
|
namespace modeler {
|
||||||
|
|
||||||
class WaterModeler : public QObject {
|
class WaterModeler : public QObject, public BaseModelerTool {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
WaterModeler(MainModelerWindow *ui);
|
WaterModeler(MainModelerWindow *ui);
|
||||||
~WaterModeler();
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void enableRendering(bool enable);
|
void enableRendering(bool enable);
|
||||||
|
|
||||||
private:
|
|
||||||
MainModelerWindow *ui;
|
|
||||||
IntPropertyBind *prop_model;
|
|
||||||
FloatPropertyBind *prop_height;
|
|
||||||
FloatPropertyBind *prop_reflexion;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
#include "OpenGLShaderProgram.h"
|
#include "OpenGLShaderProgram.h"
|
||||||
#include "OpenGLVertexArray.h"
|
#include "OpenGLVertexArray.h"
|
||||||
|
|
||||||
OpenGLPart::OpenGLPart(OpenGLRenderer *renderer, const string &name) : renderer(renderer), name(name) {
|
OpenGLPart::OpenGLPart(OpenGLRenderer *renderer, const string &name)
|
||||||
|
: DefinitionWatcher("OpenGLPart/" + name), renderer(renderer), name(name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLPart::~OpenGLPart() {
|
OpenGLPart::~OpenGLPart() {
|
||||||
|
@ -25,6 +26,7 @@ void OpenGLPart::destroy() {
|
||||||
for (auto array : arrays) {
|
for (auto array : arrays) {
|
||||||
array->destroy(functions);
|
array->destroy(functions);
|
||||||
}
|
}
|
||||||
|
unregister();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLPart::interrupt() {
|
void OpenGLPart::interrupt() {
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "opengl_global.h"
|
#include "opengl_global.h"
|
||||||
|
|
||||||
|
#include "DefinitionWatcher.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -12,7 +14,7 @@ namespace opengl {
|
||||||
/**
|
/**
|
||||||
* Class that can be inherited by scenery parts, to use OpenGL features.
|
* Class that can be inherited by scenery parts, to use OpenGL features.
|
||||||
*/
|
*/
|
||||||
class OPENGLSHARED_EXPORT OpenGLPart {
|
class OPENGLSHARED_EXPORT OpenGLPart : protected DefinitionWatcher {
|
||||||
public:
|
public:
|
||||||
OpenGLPart(OpenGLRenderer *renderer, const string &name);
|
OpenGLPart(OpenGLRenderer *renderer, const string &name);
|
||||||
virtual ~OpenGLPart();
|
virtual ~OpenGLPart();
|
||||||
|
|
|
@ -58,10 +58,10 @@ OpenGLSkybox::~OpenGLSkybox() {
|
||||||
void OpenGLSkybox::initialize() {
|
void OpenGLSkybox::initialize() {
|
||||||
// Watch for definition changes
|
// Watch for definition changes
|
||||||
Scenery *scenery = renderer->getScenery();
|
Scenery *scenery = renderer->getScenery();
|
||||||
startWatching(scenery, path_sun_phi);
|
startWatchingPath(scenery, path_sun_phi);
|
||||||
startWatching(scenery, path_sun_theta);
|
startWatchingPath(scenery, path_sun_theta);
|
||||||
startWatching(scenery, path_sun_radius);
|
startWatchingPath(scenery, path_sun_radius);
|
||||||
startWatching(scenery, path_humidity);
|
startWatchingPath(scenery, path_humidity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLSkybox::update() {
|
void OpenGLSkybox::update() {
|
||||||
|
|
|
@ -4,12 +4,11 @@
|
||||||
#include "opengl_global.h"
|
#include "opengl_global.h"
|
||||||
|
|
||||||
#include "OpenGLPart.h"
|
#include "OpenGLPart.h"
|
||||||
#include "DefinitionWatcher.h"
|
|
||||||
|
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
namespace opengl {
|
namespace opengl {
|
||||||
|
|
||||||
class OPENGLSHARED_EXPORT OpenGLSkybox : public OpenGLPart, public DefinitionWatcher {
|
class OPENGLSHARED_EXPORT OpenGLSkybox : public OpenGLPart {
|
||||||
public:
|
public:
|
||||||
OpenGLSkybox(OpenGLRenderer *renderer);
|
OpenGLSkybox(OpenGLRenderer *renderer);
|
||||||
virtual ~OpenGLSkybox();
|
virtual ~OpenGLSkybox();
|
||||||
|
|
|
@ -117,6 +117,7 @@ void OpenGLTerrain::destroy() {
|
||||||
for (auto &chunk : pv->chunks) {
|
for (auto &chunk : pv->chunks) {
|
||||||
chunk->destroy(functions);
|
chunk->destroy(functions);
|
||||||
}
|
}
|
||||||
|
OpenGLPart::destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLTerrain::pause() {
|
void OpenGLTerrain::pause() {
|
||||||
|
|
|
@ -4,14 +4,13 @@
|
||||||
#include "opengl_global.h"
|
#include "opengl_global.h"
|
||||||
|
|
||||||
#include "OpenGLPart.h"
|
#include "OpenGLPart.h"
|
||||||
#include "DefinitionWatcher.h"
|
|
||||||
|
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
namespace opengl {
|
namespace opengl {
|
||||||
|
|
||||||
class OpenGLTerrainPV;
|
class OpenGLTerrainPV;
|
||||||
|
|
||||||
class OPENGLSHARED_EXPORT OpenGLTerrain : public OpenGLPart, public DefinitionWatcher {
|
class OPENGLSHARED_EXPORT OpenGLTerrain : public OpenGLPart {
|
||||||
public:
|
public:
|
||||||
OpenGLTerrain(OpenGLRenderer *renderer);
|
OpenGLTerrain(OpenGLRenderer *renderer);
|
||||||
virtual ~OpenGLTerrain();
|
virtual ~OpenGLTerrain();
|
||||||
|
|
|
@ -46,7 +46,7 @@ OpenGLVegetation::OpenGLVegetation(OpenGLRenderer *renderer) : OpenGLPart(render
|
||||||
enabled = true;
|
enabled = true;
|
||||||
|
|
||||||
// Watch scenery changes
|
// Watch scenery changes
|
||||||
renderer->getScenery()->getVegetation()->addWatcher(this, true);
|
startWatching(renderer->getScenery()->getVegetation());
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLVegetation::~OpenGLVegetation() {
|
OpenGLVegetation::~OpenGLVegetation() {
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include "opengl_global.h"
|
#include "opengl_global.h"
|
||||||
|
|
||||||
#include "OpenGLPart.h"
|
#include "OpenGLPart.h"
|
||||||
#include "DefinitionWatcher.h"
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -13,7 +12,7 @@ namespace opengl {
|
||||||
|
|
||||||
class VegetationUpdater;
|
class VegetationUpdater;
|
||||||
|
|
||||||
class OPENGLSHARED_EXPORT OpenGLVegetation : public OpenGLPart, public DefinitionWatcher {
|
class OPENGLSHARED_EXPORT OpenGLVegetation : public OpenGLPart {
|
||||||
public:
|
public:
|
||||||
OpenGLVegetation(OpenGLRenderer *renderer);
|
OpenGLVegetation(OpenGLRenderer *renderer);
|
||||||
virtual ~OpenGLVegetation();
|
virtual ~OpenGLVegetation();
|
||||||
|
|
|
@ -43,9 +43,9 @@ OpenGLWater::~OpenGLWater() {
|
||||||
void OpenGLWater::initialize() {
|
void OpenGLWater::initialize() {
|
||||||
// Watch for definition changes
|
// Watch for definition changes
|
||||||
Scenery *scenery = renderer->getScenery();
|
Scenery *scenery = renderer->getScenery();
|
||||||
startWatching(scenery, path_height);
|
startWatchingPath(scenery, path_height);
|
||||||
startWatching(scenery, path_reflection);
|
startWatchingPath(scenery, path_reflection);
|
||||||
startWatching(scenery, path_model, false);
|
startWatchingPath(scenery, path_model, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLWater::update() {
|
void OpenGLWater::update() {
|
||||||
|
|
|
@ -4,12 +4,11 @@
|
||||||
#include "opengl_global.h"
|
#include "opengl_global.h"
|
||||||
|
|
||||||
#include "OpenGLPart.h"
|
#include "OpenGLPart.h"
|
||||||
#include "DefinitionWatcher.h"
|
|
||||||
|
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
namespace opengl {
|
namespace opengl {
|
||||||
|
|
||||||
class OPENGLSHARED_EXPORT OpenGLWater : public OpenGLPart, public DefinitionWatcher {
|
class OPENGLSHARED_EXPORT OpenGLWater : public OpenGLPart {
|
||||||
public:
|
public:
|
||||||
OpenGLWater(OpenGLRenderer *renderer);
|
OpenGLWater(OpenGLRenderer *renderer);
|
||||||
virtual ~OpenGLWater();
|
virtual ~OpenGLWater();
|
||||||
|
|
|
@ -19,8 +19,8 @@ class MoonRenderer::pimpl {
|
||||||
NoiseFunctionSimplex noise;
|
NoiseFunctionSimplex noise;
|
||||||
};
|
};
|
||||||
|
|
||||||
MoonRenderer::MoonRenderer(CelestialBodyDefinition *moon_node) : impl(new pimpl()) {
|
MoonRenderer::MoonRenderer(CelestialBodyDefinition *moon_node) : DefinitionWatcher("MoonRenderer"), impl(new pimpl()) {
|
||||||
startWatching(moon_node->getRoot(), moon_node->getPath());
|
startWatchingPath(moon_node->getRoot(), moon_node->getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
MoonRenderer::~MoonRenderer() {
|
MoonRenderer::~MoonRenderer() {
|
||||||
|
|
|
@ -55,6 +55,8 @@ SoftwareRenderer::SoftwareRenderer(Scenery *scenery) : scenery(scenery) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SoftwareRenderer::~SoftwareRenderer() {
|
SoftwareRenderer::~SoftwareRenderer() {
|
||||||
|
moon_renderer->unregister();
|
||||||
|
|
||||||
delete render_camera;
|
delete render_camera;
|
||||||
|
|
||||||
delete fluid_medium;
|
delete fluid_medium;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "BaseTestCase.h"
|
#include "BaseTestCase.h"
|
||||||
|
|
||||||
#include "DefinitionNode.h"
|
#include "DefinitionNode.h"
|
||||||
|
#include "IntNode.h"
|
||||||
#include "FloatNode.h"
|
#include "FloatNode.h"
|
||||||
#include "PackStream.h"
|
#include "PackStream.h"
|
||||||
#include "DefinitionWatcher.h"
|
#include "DefinitionWatcher.h"
|
||||||
|
@ -25,22 +26,6 @@ TEST(DefinitionNode, getPath) {
|
||||||
EXPECT_EQ("/branch/leaf", leaf.getPath());
|
EXPECT_EQ("/branch/leaf", leaf.getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DefinitionNode, addWatcher) {
|
|
||||||
class FakeWatcher : public DefinitionWatcher {
|
|
||||||
virtual void nodeChanged(const DefinitionNode *, const DefinitionDiff *, const DefinitionNode *) override {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
DefinitionNode root(NULL, "root");
|
|
||||||
FakeWatcher watcher;
|
|
||||||
|
|
||||||
EXPECT_EQ(0u, root.getWatcherCount());
|
|
||||||
root.addWatcher(&watcher);
|
|
||||||
EXPECT_EQ(1u, root.getWatcherCount());
|
|
||||||
root.addWatcher(&watcher);
|
|
||||||
EXPECT_EQ(1u, root.getWatcherCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(DefinitionNode, findByPath) {
|
TEST(DefinitionNode, findByPath) {
|
||||||
DefinitionNode root(NULL, "root");
|
DefinitionNode root(NULL, "root");
|
||||||
DefinitionNode branch(&root, "branch");
|
DefinitionNode branch(&root, "branch");
|
||||||
|
@ -132,3 +117,30 @@ TEST(DefinitionNode, saveLoadCopy) {
|
||||||
delete before;
|
delete before;
|
||||||
delete after;
|
delete after;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(DefinitionNode, onChildChange) {
|
||||||
|
class CapturingNode : public DefinitionNode {
|
||||||
|
public:
|
||||||
|
CapturingNode(DefinitionNode *parent, const string &name) : DefinitionNode(parent, name) {
|
||||||
|
}
|
||||||
|
virtual void onChildChanged(int depth, const string &relpath) override {
|
||||||
|
changes.push_back(pair<int, string>(depth, relpath));
|
||||||
|
DefinitionNode::onChildChanged(depth, relpath);
|
||||||
|
}
|
||||||
|
vector<pair<int, string>> changes;
|
||||||
|
};
|
||||||
|
|
||||||
|
CapturingNode root(NULL, "root");
|
||||||
|
CapturingNode branch(&root, "branch");
|
||||||
|
IntNode leaf(&branch, "leaf");
|
||||||
|
|
||||||
|
leaf.setValue(5.0);
|
||||||
|
|
||||||
|
ASSERT_EQ(1u, root.changes.size());
|
||||||
|
EXPECT_EQ(1, root.changes[0].first);
|
||||||
|
EXPECT_EQ("branch/leaf", root.changes[0].second);
|
||||||
|
|
||||||
|
ASSERT_EQ(1u, branch.changes.size());
|
||||||
|
EXPECT_EQ(0, branch.changes[0].first);
|
||||||
|
EXPECT_EQ("leaf", branch.changes[0].second);
|
||||||
|
}
|
||||||
|
|
33
src/tests/DefinitionWatcher_Test.cpp
Normal file
33
src/tests/DefinitionWatcher_Test.cpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include "BaseTestCase.h"
|
||||||
|
#include "DefinitionWatcher.h"
|
||||||
|
|
||||||
|
#include "IntNode.h"
|
||||||
|
|
||||||
|
TEST(DefinitionWatcher, destructor) {
|
||||||
|
class FakeWatcher : public DefinitionWatcher {
|
||||||
|
public:
|
||||||
|
FakeWatcher(DefinitionNode *node, int &counter) : DefinitionWatcher("FakeWatcher"), counter(counter) {
|
||||||
|
startWatching(node, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void nodeChanged(const DefinitionNode *, const DefinitionDiff *, const DefinitionNode *) override {
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int &counter;
|
||||||
|
};
|
||||||
|
|
||||||
|
IntNode root(NULL, "test", 5);
|
||||||
|
int counter = 0;
|
||||||
|
auto watcher = new FakeWatcher(&root, counter);
|
||||||
|
|
||||||
|
EXPECT_EQ(0, counter);
|
||||||
|
|
||||||
|
root.setValue(3);
|
||||||
|
EXPECT_EQ(1, counter);
|
||||||
|
|
||||||
|
// When the watcher is destroyed, it should stop receiving diffs
|
||||||
|
delete watcher;
|
||||||
|
root.setValue(8);
|
||||||
|
EXPECT_EQ(1, counter);
|
||||||
|
}
|
|
@ -111,18 +111,23 @@ TEST(DiffManager, undoBranch) {
|
||||||
EXPECT_DOUBLE_EQ(4.4, leaf.getValue());
|
EXPECT_DOUBLE_EQ(4.4, leaf.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
class TestWatcher : public DefinitionWatcher {
|
class TestWatcher : public DefinitionWatcher {
|
||||||
public:
|
public:
|
||||||
TestWatcher(DefinitionNode *expected_node, double expected_old_value, double expected_new_value)
|
TestWatcher(DefinitionNode *expected_node, double expected_old_value, double expected_new_value)
|
||||||
: DefinitionWatcher(), expected_node(expected_node), expected_old_value(expected_old_value),
|
: DefinitionWatcher("TestWatcher"), expected_node(expected_node), expected_old_value(expected_old_value),
|
||||||
expected_new_value(expected_new_value) {
|
expected_new_value(expected_new_value) {
|
||||||
calls = 0;
|
calls = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void start(bool init_diffs) {
|
||||||
|
startWatching(expected_node, init_diffs);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *) override {
|
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *) override {
|
||||||
EXPECT_EQ(expected_node, node);
|
EXPECT_EQ(expected_node, node);
|
||||||
ASSERT_EQ("float", diff->getTypeName());
|
ASSERT_EQ("float", diff->getTypeName());
|
||||||
const FloatDiff *float_diff = (const FloatDiff *)diff;
|
auto float_diff = static_cast<const FloatDiff *>(diff);
|
||||||
EXPECT_EQ(expected_old_value, float_diff->getOldValue());
|
EXPECT_EQ(expected_old_value, float_diff->getOldValue());
|
||||||
EXPECT_EQ(expected_new_value, float_diff->getNewValue());
|
EXPECT_EQ(expected_new_value, float_diff->getNewValue());
|
||||||
calls++;
|
calls++;
|
||||||
|
@ -133,6 +138,7 @@ class TestWatcher : public DefinitionWatcher {
|
||||||
double expected_old_value;
|
double expected_old_value;
|
||||||
double expected_new_value;
|
double expected_new_value;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
TEST(DiffManager, addWatcher) {
|
TEST(DiffManager, addWatcher) {
|
||||||
FloatNode node(NULL, "node");
|
FloatNode node(NULL, "node");
|
||||||
|
@ -141,7 +147,7 @@ TEST(DiffManager, addWatcher) {
|
||||||
node.setValue(1.3);
|
node.setValue(1.3);
|
||||||
EXPECT_EQ(0, watcher.calls);
|
EXPECT_EQ(0, watcher.calls);
|
||||||
|
|
||||||
node.addWatcher(&watcher);
|
watcher.start(false);
|
||||||
EXPECT_EQ(0, watcher.calls);
|
EXPECT_EQ(0, watcher.calls);
|
||||||
|
|
||||||
node.setValue(-4.0);
|
node.setValue(-4.0);
|
||||||
|
@ -152,7 +158,7 @@ TEST(DiffManager, addWatcherWithInitDiffs) {
|
||||||
FloatNode node(NULL, "node", 1.3);
|
FloatNode node(NULL, "node", 1.3);
|
||||||
TestWatcher watcher(&node, 1.3, 1.3);
|
TestWatcher watcher(&node, 1.3, 1.3);
|
||||||
|
|
||||||
node.addWatcher(&watcher, true);
|
watcher.start(true);
|
||||||
EXPECT_EQ(1, watcher.calls);
|
EXPECT_EQ(1, watcher.calls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,12 +169,12 @@ TEST(DiffManager, publishToWatcher) {
|
||||||
|
|
||||||
EXPECT_EQ(0u, watcher.changes.size());
|
EXPECT_EQ(0u, watcher.changes.size());
|
||||||
|
|
||||||
root.addWatcher(&watcher, true);
|
watcher.start(&root);
|
||||||
ASSERT_EQ(1u, watcher.changes.size());
|
ASSERT_EQ(1u, watcher.changes.size());
|
||||||
EXPECT_EQ(&root, watcher.changes[0].node);
|
EXPECT_EQ(&root, watcher.changes[0].node);
|
||||||
EXPECT_EQ(&root, watcher.changes[0].parent);
|
EXPECT_EQ(&root, watcher.changes[0].parent);
|
||||||
|
|
||||||
node.addWatcher(&watcher, true);
|
watcher.start(&node);
|
||||||
ASSERT_EQ(2u, watcher.changes.size());
|
ASSERT_EQ(2u, watcher.changes.size());
|
||||||
EXPECT_EQ(&node, watcher.changes[1].node);
|
EXPECT_EQ(&node, watcher.changes[1].node);
|
||||||
EXPECT_EQ(&node, watcher.changes[1].parent);
|
EXPECT_EQ(&node, watcher.changes[1].parent);
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace {
|
||||||
*/
|
*/
|
||||||
class RecordingDefinitionWatcher : public DefinitionWatcher {
|
class RecordingDefinitionWatcher : public DefinitionWatcher {
|
||||||
public:
|
public:
|
||||||
RecordingDefinitionWatcher() {
|
RecordingDefinitionWatcher() : DefinitionWatcher("RecordingDefinitionWatcher") {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff,
|
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff,
|
||||||
|
@ -23,6 +23,10 @@ class RecordingDefinitionWatcher : public DefinitionWatcher {
|
||||||
changes.push_back(change);
|
changes.push_back(change);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void start(DefinitionNode *node, bool init_diffs = true) {
|
||||||
|
startWatching(node, init_diffs);
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const DefinitionNode *node;
|
const DefinitionNode *node;
|
||||||
const DefinitionDiff *diff;
|
const DefinitionDiff *diff;
|
||||||
|
|
Loading…
Reference in a new issue