Issues with ValueTreeSynchronizer

I fiddled around a bit with the ValueTreeSynchronizer.

First, I found out that it does not synchronize removal of properties - the implementation for this is simply missing.
I filed an issue for this.

Then, I found out that calling <myValueTreeSynchroniser>.sendFullSyncCallback() results in the affected tree never ever getting stateChanged anymore (i.e. my trees send and receive changes!).
See my below test case (uncomment one of the lines to fail the test).
Without calling it, everything seems to work fine! (starting with an empty tree).

Is this a bug or am I getting something wrong here?
Am I using it other than intended?
(If it is not allowed to have ValueTrees synchronized biderectionally, that would be a pity… we would need one input tree and one output tree…)

If it is a bug, I can file an issue with this test case.

#include "../JuceLibraryCode/JuceHeader.h"

// create 2 ValueTrees
ValueTree treeA("A"), treeB("B");

// Simple Synchroniser just applying all changes to a specified other tree
class ValueTreeSyncTest : public ValueTreeSynchroniser {
public:
    ValueTreeSyncTest(String name, ValueTree& valueTree, ValueTree& target) : ValueTreeSynchroniser(valueTree), 
        target(&target), name(name) {
    }

private:
    ValueTree * target;
    String name;
    void stateChanged(const void * encodedChange, size_t encodedChangeSize)
    {
       Logger::outputDebugString("Apply from " + name + " to other tree...");
       ValueTreeSynchroniser::applyChange(*target, encodedChange, encodedChangeSize, nullptr);
    }
};

// create 2 Syncers to have bidirectional sync
ValueTreeSyncTest syncA ("treeA", treeA, treeB), syncB ("treeB", treeB, treeA);

//==============================================================================
int main (int argc, char* argv[])
{
    // if you uncomment one of these, the according tree will never receive stateChanged anymore...
    //syncA.sendFullSyncCallback();
    //syncB.sendFullSyncCallback();

    // adding properties works fine
    Logger::outputDebugString("# Set property testA on treeA");
    treeA.setProperty("testA", "valA", nullptr);
    jassert (treeB.hasProperty("testA"));
    Logger::outputDebugString("# Set property testB on treeB");
    treeB.setProperty("testB", "valB", nullptr);
    jassert(treeA.hasProperty("testB"));
    Logger::outputDebugString("# Set property testC on treeA");
    treeA.setProperty("testC", "valC", nullptr);
    jassert(treeB.hasProperty("testC"));
    Logger::outputDebugString("# Set property testD on treeB");
    treeB.setProperty("testD", "valD", nullptr);
    jassert(treeA.hasProperty("testD"));
    return 0;
}
1 Like

We are having a look at this use case and will answer soon. Hang in there…

2 Likes

Hi @Fabian, now that ADC was successfully done (congratulations, wish I had been there, maybe next time!), do you have some time to look into this issue?
It’s not urgent for me, but maybe others would also be interested…

Thanks!

2 Likes

I believe this issue still affects the latest JUCE (5.4.2, at least). I was unable to get a ValueTreeSynchroniser working after running ValueTreeSynchroniser::sendFullSyncCallback().

I was able to fix it locally by changing the code in juce_ValueTreeSynchroniser.cpp, ValueTreeSynchroniser::applyChange that deals with fullSync:

if (type == ValueTreeSynchroniserHelpers::fullSync)
{
    root.copyPropertiesAndChildrenFrom(ValueTree::readFromStream (input), undoManager);
    return true;
}

This way, ValueTreeSynchorniser.root isn’t being changed out from under the original target. I’m not sure if this is the correct way to fix it in the long run, however.

Came Across the same issue:

As long as I don’t call applyChange the stateChanged callback works fine,
but as soon as I send a fullSync the stateChanged function never ever gets called again.

Is this still an open issue or have I missed something? :slight_smile:

Using Juce 6.0.8

I believe this might have to do with the fact that ValueTreeSynchroniser doesn’t implement valueTreeRedirected.

If I remember correctly I implemented valueTreeRedirected in the subclass and made the ValueTreeListener superclass listen to this new ValueTree, but I don’t have the code lying around anymore.

If you could provide a quick workable example (as pip or one file) I could have a look.

Thanks for the reply!

The workaround from ryanavery would also solve this problem for me but in combination with the “feedback” problem in the other thread (thanks for the answer there aswell), I think I have to come up with a different system to keep my server and clients in sync. :face_with_thermometer: