Added node watching on "container" nodes

This commit is contained in:
Michaël Lemaire 2016-01-16 16:21:02 +01:00
parent 5778154aae
commit 69543f76b6
28 changed files with 138 additions and 45 deletions

View file

@ -9,6 +9,20 @@
#include <cassert>
#include <algorithm>
// Diff for abstract nodes
class DefinitionNodeDiff : public DefinitionDiff {
public:
DefinitionNodeDiff(const DefinitionNode *node) : DefinitionDiff(node) {
}
DefinitionNodeDiff(const DefinitionDiff *diff) : DefinitionDiff(diff) {
}
virtual DefinitionDiff *newReversed() const override {
return new DefinitionNodeDiff(this);
}
};
DefinitionNode::DefinitionNode(DefinitionNode *parent, const string &name, const string &type_name)
: parent(parent), type_name(type_name), name(name) {
if (parent) {
@ -115,7 +129,9 @@ bool DefinitionNode::applyDiff(const DefinitionDiff *diff, bool) {
}
}
void DefinitionNode::generateInitDiffs(vector<const DefinitionDiff *> *) const {
void DefinitionNode::generateInitDiffs(vector<const DefinitionDiff *> *diffs) const {
diffs->push_back(new DefinitionNodeDiff(this));
// TODO add children diffs in cascade ?
}
void DefinitionNode::addWatcher(DefinitionWatcher *watcher, bool init_diff) {
@ -125,7 +141,7 @@ void DefinitionNode::addWatcher(DefinitionWatcher *watcher, bool init_diff) {
generateInitDiffs(&diffs);
for (auto diff : diffs) {
watcher->nodeChanged(this, diff);
watcher->nodeChanged(this, diff, this);
delete diff;
}
}

View file

@ -9,9 +9,10 @@ DefinitionWatcher::DefinitionWatcher() {
}
DefinitionWatcher::~DefinitionWatcher() {
// FIXME watcher is not removed from the diff manager !
}
void DefinitionWatcher::nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) {
void DefinitionWatcher::nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *) {
string type_name = node->getTypeName();
if (type_name == "int") {

View file

@ -20,8 +20,10 @@ class DEFINITIONSHARED_EXPORT DefinitionWatcher {
/**
* Abstract method called when a node changed.
*
* *parent* is the node that is watched (useful if *node* is a sub-node).
*/
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff);
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *parent);
protected:
/**

View file

@ -39,11 +39,10 @@ void DiffManager::addDiff(DefinitionNode *node, const DefinitionDiff *diff) {
diffs.push_back(diff);
// TODO Delayed commit (with merge of consecutive diffs)
node->applyDiff(diff);
for (auto watcher : watchers[node]) {
watcher->nodeChanged(node, diff);
}
Logs::debug("Definition") << "Node changed : " << node->getPath() << endl;
node->applyDiff(diff);
publishToWatchers(node, diff);
}
void DiffManager::undo() {
@ -55,12 +54,12 @@ void DiffManager::undo() {
if (node) {
undone++;
node->applyDiff(diff, true);
unique_ptr<DefinitionDiff> reversed(diff->newReversed());
for (auto watcher : watchers[node]) {
unique_ptr<DefinitionDiff> reversed(diff->newReversed());
watcher->nodeChanged(node, reversed.get());
}
Logs::debug("Definition") << "Node undo : " << node->getPath() << endl;
// TODO use reversed ?
node->applyDiff(diff, true);
publishToWatchers(node, reversed.get());
} else {
Logs::error("Definition") << "Can't find node to undo diff : " << diff->getPath() << endl;
}
@ -76,13 +75,22 @@ void DiffManager::redo() {
if (node) {
undone--;
Logs::debug("Definition") << "Node redo : " << node->getPath() << endl;
node->applyDiff(diff);
for (auto watcher : watchers[node]) {
watcher->nodeChanged(node, diff);
}
publishToWatchers(node, diff);
} else {
Logs::error("Definition") << "Can't find node to redo diff : " << diff->getPath() << endl;
}
}
}
void DiffManager::publishToWatchers(const DefinitionNode *node, const DefinitionDiff *diff) {
// TODO Parent node signaling should be aggregated (to not receive many nodeChanged calls)
const DefinitionNode *cnode = node;
do {
for (auto watcher : watchers[cnode]) {
watcher->nodeChanged(node, diff, cnode);
}
cnode = cnode->getParent();
} while (cnode);
}

View file

@ -53,6 +53,15 @@ class DEFINITIONSHARED_EXPORT DiffManager {
*/
void redo();
protected:
/**
* Publish a diff to the registered watchers.
*
* The diff will be published to the watcher of the node, and to the watchers of all
* parents, up to the definition tree root.
*/
void publishToWatchers(const DefinitionNode *node, const DefinitionDiff *diff);
private:
DefinitionNode *tree;
int undone;

View file

@ -109,7 +109,7 @@ void WaterDefinition::validate() {
foam_material->validate();
}
void WaterDefinition::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) {
void WaterDefinition::nodeChanged(const DefinitionNode *node, const DefinitionDiff *, const DefinitionNode *) {
if (node == model) {
switch (model->getValue()) {
case 1:

View file

@ -36,7 +36,7 @@ class DEFINITIONSHARED_EXPORT WaterDefinition : public DefinitionNode, public De
return depth_color;
}
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff);
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *parent) override;
typedef enum { WATER_PRESET_LAKE, WATER_PRESET_SEA } WaterPreset;
void applyPreset(WaterPreset preset, RandomGenerator &random = RandomGeneratorDefault);

View file

@ -18,7 +18,7 @@ AtmosphereModeler::AtmosphereModeler(MainModelerWindow *ui) : BaseModelerTool(ui
ui->setQmlProperty("atmosphere_daytime", "value", ui->getScenery()->getAtmosphere()->getDaytime());
}
void AtmosphereModeler::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) {
void AtmosphereModeler::nodeChanged(const DefinitionNode *node, const DefinitionDiff *, const DefinitionNode *) {
if (node->getPath().find("/atmosphere/sun/") == 0) {
getWindow()->getCamera()->startSunTool(1000);
}

View file

@ -12,7 +12,7 @@ class AtmosphereModeler : protected BaseModelerTool {
public:
AtmosphereModeler(MainModelerWindow *ui);
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override;
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *parent) override;
};
}
}

View file

@ -20,7 +20,7 @@ FloatPropertyBind::FloatPropertyBind(MainModelerWindow *window, const string &ob
}
}
void FloatPropertyBind::nodeChanged(const DefinitionNode *, const DefinitionDiff *) {
void FloatPropertyBind::nodeChanged(const DefinitionNode *, const DefinitionDiff *, const DefinitionNode *) {
if (item) {
item->setProperty(property.c_str(), node->getValue());
}

View file

@ -20,7 +20,7 @@ class FloatPropertyBind : public QObject, public DefinitionWatcher {
FloatPropertyBind(MainModelerWindow *window, const string &object_name, const string &property_name,
FloatNode *node);
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override;
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *parent) override;
private slots:
void propertyChanged();

View file

@ -18,7 +18,7 @@ IntPropertyBind::IntPropertyBind(MainModelerWindow *window, const string &object
}
}
void IntPropertyBind::nodeChanged(const DefinitionNode *, const DefinitionDiff *) {
void IntPropertyBind::nodeChanged(const DefinitionNode *, const DefinitionDiff *, const DefinitionNode *) {
if (item) {
item->setProperty(property.c_str(), node->getValue());
}

View file

@ -19,7 +19,7 @@ class IntPropertyBind : public QObject, public DefinitionWatcher {
public:
IntPropertyBind(MainModelerWindow *window, const string &object_name, const string &property_name, IntNode *node);
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override;
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *parent) override;
private slots:
void propertyChanged();

View file

@ -89,7 +89,7 @@ void ModelerCameras::timerEvent(QTimerEvent *) {
}
}
void ModelerCameras::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) {
void ModelerCameras::nodeChanged(const DefinitionNode *node, const DefinitionDiff *, const DefinitionNode *) {
if (node->getPath().find("/atmosphere/sun/") == 0 and tool_mode == TOOL_SUN) {
tool->setTarget(parent->getRenderer()->getAtmosphereRenderer()->getSunLocation());
}

View file

@ -50,7 +50,7 @@ class ModelerCameras : public QObject, public DefinitionWatcher {
protected:
virtual void timerEvent(QTimerEvent *event) override;
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override;
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *parent) override;
/**
* Validate current camera, pushing it to rendered scenery if needed.

View file

@ -78,7 +78,7 @@ void OpenGLSkybox::render() {
program->draw(vertices);
}
void OpenGLSkybox::nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) {
void OpenGLSkybox::nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *parent) {
OpenGLSharedState *state = renderer->getSharedState();
AtmosphereDefinition *newdef = renderer->getScenery()->getAtmosphere();
@ -92,7 +92,7 @@ void OpenGLSkybox::nodeChanged(const DefinitionNode *node, const DefinitionDiff
state->set("dayTime", newdef->getDaytime());
}
DefinitionWatcher::nodeChanged(node, diff);
DefinitionWatcher::nodeChanged(node, diff, parent);
}
void OpenGLSkybox::floatNodeChanged(const string &path, double new_value, double) {

View file

@ -18,7 +18,7 @@ class OPENGLSHARED_EXPORT OpenGLSkybox : public OpenGLPart, public DefinitionWat
virtual void update() override;
virtual void render() override;
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override;
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *parent) override;
virtual void floatNodeChanged(const string &path, double new_value, double old_value) override;
private:

View file

@ -165,7 +165,7 @@ void OpenGLTerrain::performChunksMaintenance() {
}
}
void OpenGLTerrain::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) {
void OpenGLTerrain::nodeChanged(const DefinitionNode *node, const DefinitionDiff *, const DefinitionNode *) {
if (node->getPath() == "/terrain/water_height") {
resetTextures();
} else if (node->getPath().find("/atmosphere") == 0) {

View file

@ -35,7 +35,7 @@ class OPENGLSHARED_EXPORT OpenGLTerrain : public OpenGLPart, public DefinitionWa
void performChunksMaintenance();
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override;
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *) override;
private:
OpenGLShaderProgram *program;

View file

@ -88,7 +88,7 @@ void OpenGLVegetation::render() {
}
}
void OpenGLVegetation::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) {
void OpenGLVegetation::nodeChanged(const DefinitionNode *node, const DefinitionDiff *, const DefinitionNode *) {
if (node->getPath() == "/vegetation") {
updateLayers();
}

View file

@ -32,7 +32,7 @@ class OPENGLSHARED_EXPORT OpenGLVegetation : public OpenGLPart, public Definitio
virtual void update() override;
virtual void render() override;
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override;
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *parent) override;
/**
* Get the currently rendered scenery.

View file

@ -66,7 +66,7 @@ void OpenGLWater::render() {
}
}
void OpenGLWater::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) {
void OpenGLWater::nodeChanged(const DefinitionNode *node, const DefinitionDiff *, const DefinitionNode *) {
OpenGLSharedState *state = renderer->getSharedState();
if (node->getPath() == path_height) {

View file

@ -18,7 +18,7 @@ class OPENGLSHARED_EXPORT OpenGLWater : public OpenGLPart, public DefinitionWatc
virtual void update() override;
virtual void render() override;
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override;
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *parent) override;
/**
* Enable or disable the water surface rendering.

View file

@ -18,17 +18,13 @@ class MoonRenderer::pimpl {
MoonRenderer::MoonRenderer(CelestialBodyDefinition *moon_node) : impl(new pimpl()) {
startWatching(moon_node->getRoot(), moon_node->getPath());
// FIXME should not be needed because the above watcher should watch the whole node
// and call nodeChanged
moon_node->copy(&impl->definition);
}
MoonRenderer::~MoonRenderer() {
}
void MoonRenderer::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) {
if (auto moon_node = static_cast<const CelestialBodyDefinition *>(node)) {
void MoonRenderer::nodeChanged(const DefinitionNode *, const DefinitionDiff *, const DefinitionNode *parent) {
if (auto moon_node = static_cast<const CelestialBodyDefinition *>(parent)) {
moon_node->copy(&impl->definition);
}
}

View file

@ -19,7 +19,7 @@ class SOFTWARESHARED_EXPORT MoonRenderer : public DefinitionWatcher, public Ligh
MoonRenderer(CelestialBodyDefinition *moon_node);
virtual ~MoonRenderer();
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override;
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *parent) override;
virtual bool getLightsAt(vector<LightComponent> &result, const Vector3 &location) const override;
/**

View file

@ -26,7 +26,7 @@ TEST(DefinitionNode, getPath) {
}
class FakeWatcher : public DefinitionWatcher {
virtual void nodeChanged(const DefinitionNode *, const DefinitionDiff *) override {
virtual void nodeChanged(const DefinitionNode *, const DefinitionDiff *, const DefinitionNode *) override {
}
};

View file

@ -1,5 +1,6 @@
#include "BaseTestCase.h"
#include "TestToolDefinition.h"
#include "DiffManager.h"
#include "DefinitionNode.h"
#include "DefinitionWatcher.h"
@ -118,7 +119,7 @@ class TestWatcher : public DefinitionWatcher {
calls = 0;
}
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override {
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *) override {
EXPECT_EQ(expected_node, node);
ASSERT_EQ("float", diff->getTypeName());
const FloatDiff *float_diff = (const FloatDiff *)diff;
@ -154,3 +155,28 @@ TEST(DiffManager, addWatcherWithInitDiffs) {
node.addWatcher(&watcher, true);
EXPECT_EQ(1, watcher.calls);
}
TEST(DiffManager, publishToWatcher) {
DefinitionNode root(NULL, "root");
FloatNode node(&root, "node", 1.3);
RecordingDefinitionWatcher watcher;
EXPECT_EQ(0u, watcher.changes.size());
root.addWatcher(&watcher, true);
ASSERT_EQ(1u, watcher.changes.size());
EXPECT_EQ(&root, watcher.changes[0].node);
EXPECT_EQ(&root, watcher.changes[0].parent);
node.addWatcher(&watcher, true);
ASSERT_EQ(2u, watcher.changes.size());
EXPECT_EQ(&node, watcher.changes[1].node);
EXPECT_EQ(&node, watcher.changes[1].parent);
node.setValue(2.3);
ASSERT_EQ(4u, watcher.changes.size());
EXPECT_EQ(&node, watcher.changes[2].node);
EXPECT_EQ(&node, watcher.changes[2].parent);
EXPECT_EQ(&node, watcher.changes[3].node);
EXPECT_EQ(&root, watcher.changes[3].parent);
}

View file

@ -0,0 +1,35 @@
#ifndef TESTTOOLDEFINITION_H
#define TESTTOOLDEFINITION_H
#include "DefinitionWatcher.h"
#include <vector>
namespace {
/**
* Definition watcher that registers all calls to nodeChanged.
*/
class RecordingDefinitionWatcher : public DefinitionWatcher {
public:
RecordingDefinitionWatcher() {
}
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff, const DefinitionNode *parent) override {
RecordedChange change;
change.node = node;
change.diff = diff; // FIXME Referenced diff may get deleted by the diff manager
change.parent = parent;
changes.push_back(change);
}
typedef struct {
const DefinitionNode *node;
const DefinitionDiff *diff;
const DefinitionNode *parent;
} RecordedChange;
vector<RecordedChange> changes;
};
}
#endif // TESTTOOLDEFINITION_H