upgrade to JUCE 5.4.3. Remove (probably) unused JUCE modules. Remove VST2 target (it's been end-of-life'd by Steinberg and by JUCE)
This commit is contained in:
@ -58,10 +58,13 @@ File PropertiesFile::Options::getDefaultFile() const
|
||||
File dir (commonToAllUsers ? "/Library/"
|
||||
: "~/Library/");
|
||||
|
||||
if (osxLibrarySubFolder != "Preferences" && ! osxLibrarySubFolder.startsWith ("Application Support"))
|
||||
if (osxLibrarySubFolder != "Preferences"
|
||||
&& ! osxLibrarySubFolder.startsWith ("Application Support")
|
||||
&& ! osxLibrarySubFolder.startsWith ("Containers"))
|
||||
{
|
||||
/* The PropertiesFile class always used to put its settings files in "Library/Preferences", but Apple
|
||||
have changed their advice, and now stipulate that settings should go in "Library/Application Support".
|
||||
have changed their advice, and now stipulate that settings should go in "Library/Application Support",
|
||||
or Library/Containers/[app_bundle_id] for a sandboxed app.
|
||||
|
||||
Because older apps would be broken by a silent change in this class's behaviour, you must now
|
||||
explicitly set the osxLibrarySubFolder value to indicate which path you want to use.
|
||||
|
@ -180,7 +180,7 @@ public:
|
||||
/** Destructor.
|
||||
When deleted, the file will first call saveIfNeeded() to flush any changes to disk.
|
||||
*/
|
||||
~PropertiesFile();
|
||||
~PropertiesFile() override;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if this file was created from a valid (or non-existent) file.
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "values/juce_ValueTree.cpp"
|
||||
#include "values/juce_ValueTreeSynchroniser.cpp"
|
||||
#include "values/juce_CachedValue.cpp"
|
||||
#include "values/juce_ValueWithDefault.cpp"
|
||||
#include "undomanager/juce_UndoManager.cpp"
|
||||
#include "app_properties/juce_ApplicationProperties.cpp"
|
||||
#include "app_properties/juce_PropertiesFile.cpp"
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
ID: juce_data_structures
|
||||
vendor: juce
|
||||
version: 5.3.2
|
||||
version: 5.4.3
|
||||
name: JUCE data model helper classes
|
||||
description: Classes for undo/redo management, and smart data structures.
|
||||
website: http://www.juce.com/juce
|
||||
|
@ -29,9 +29,7 @@ namespace juce
|
||||
|
||||
struct UndoManager::ActionSet
|
||||
{
|
||||
ActionSet (const String& transactionName)
|
||||
: name (transactionName),
|
||||
time (Time::getCurrentTime())
|
||||
ActionSet (const String& transactionName) : name (transactionName)
|
||||
{}
|
||||
|
||||
bool perform() const
|
||||
@ -64,7 +62,7 @@ struct UndoManager::ActionSet
|
||||
|
||||
OwnedArray<UndoableAction> actions;
|
||||
String name;
|
||||
Time time;
|
||||
Time time { Time::getCurrentTime() };
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
@ -117,9 +115,9 @@ bool UndoManager::perform (UndoableAction* newAction)
|
||||
{
|
||||
std::unique_ptr<UndoableAction> action (newAction);
|
||||
|
||||
if (reentrancyCheck)
|
||||
if (isPerformingUndoRedo())
|
||||
{
|
||||
jassertfalse; // don't call perform() recursively from the UndoableAction::perform()
|
||||
jassertfalse; // Don't call perform() recursively from the UndoableAction::perform()
|
||||
// or undo() methods, or else these actions will be discarded!
|
||||
return false;
|
||||
}
|
||||
@ -209,18 +207,18 @@ void UndoManager::dropOldTransactionsIfTooLarge()
|
||||
}
|
||||
}
|
||||
|
||||
void UndoManager::beginNewTransaction() noexcept
|
||||
void UndoManager::beginNewTransaction()
|
||||
{
|
||||
beginNewTransaction ({});
|
||||
}
|
||||
|
||||
void UndoManager::beginNewTransaction (const String& actionName) noexcept
|
||||
void UndoManager::beginNewTransaction (const String& actionName)
|
||||
{
|
||||
newTransaction = true;
|
||||
newTransactionName = actionName;
|
||||
}
|
||||
|
||||
void UndoManager::setCurrentTransactionName (const String& newName) noexcept
|
||||
void UndoManager::setCurrentTransactionName (const String& newName)
|
||||
{
|
||||
if (newTransaction)
|
||||
newTransactionName = newName;
|
||||
@ -228,7 +226,7 @@ void UndoManager::setCurrentTransactionName (const String& newName) noexcept
|
||||
action->name = newName;
|
||||
}
|
||||
|
||||
String UndoManager::getCurrentTransactionName() const noexcept
|
||||
String UndoManager::getCurrentTransactionName() const
|
||||
{
|
||||
if (auto* action = getCurrentSet())
|
||||
return action->name;
|
||||
@ -237,17 +235,19 @@ String UndoManager::getCurrentTransactionName() const noexcept
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
UndoManager::ActionSet* UndoManager::getCurrentSet() const noexcept { return transactions[nextIndex - 1]; }
|
||||
UndoManager::ActionSet* UndoManager::getNextSet() const noexcept { return transactions[nextIndex]; }
|
||||
UndoManager::ActionSet* UndoManager::getCurrentSet() const { return transactions[nextIndex - 1]; }
|
||||
UndoManager::ActionSet* UndoManager::getNextSet() const { return transactions[nextIndex]; }
|
||||
|
||||
bool UndoManager::canUndo() const noexcept { return getCurrentSet() != nullptr; }
|
||||
bool UndoManager::canRedo() const noexcept { return getNextSet() != nullptr; }
|
||||
bool UndoManager::isPerformingUndoRedo() const { return isInsideUndoRedoCall; }
|
||||
|
||||
bool UndoManager::canUndo() const { return getCurrentSet() != nullptr; }
|
||||
bool UndoManager::canRedo() const { return getNextSet() != nullptr; }
|
||||
|
||||
bool UndoManager::undo()
|
||||
{
|
||||
if (auto* s = getCurrentSet())
|
||||
{
|
||||
const ScopedValueSetter<bool> setter (reentrancyCheck, true);
|
||||
const ScopedValueSetter<bool> setter (isInsideUndoRedoCall, true);
|
||||
|
||||
if (s->undo())
|
||||
--nextIndex;
|
||||
@ -266,7 +266,7 @@ bool UndoManager::redo()
|
||||
{
|
||||
if (auto* s = getNextSet())
|
||||
{
|
||||
const ScopedValueSetter<bool> setter (reentrancyCheck, true);
|
||||
const ScopedValueSetter<bool> setter (isInsideUndoRedoCall, true);
|
||||
|
||||
if (s->perform())
|
||||
++nextIndex;
|
||||
|
@ -70,7 +70,7 @@ public:
|
||||
int minimumTransactionsToKeep = 30);
|
||||
|
||||
/** Destructor. */
|
||||
~UndoManager();
|
||||
~UndoManager() override;
|
||||
|
||||
//==============================================================================
|
||||
/** Deletes all stored actions in the list. */
|
||||
@ -126,7 +126,7 @@ public:
|
||||
method are grouped together and undone/redone together by a single call to
|
||||
undo() or redo().
|
||||
*/
|
||||
void beginNewTransaction() noexcept;
|
||||
void beginNewTransaction();
|
||||
|
||||
/** Starts a new group of actions that together will be treated as a single transaction.
|
||||
|
||||
@ -137,7 +137,7 @@ public:
|
||||
@param actionName a description of the transaction that is about to be
|
||||
performed
|
||||
*/
|
||||
void beginNewTransaction (const String& actionName) noexcept;
|
||||
void beginNewTransaction (const String& actionName);
|
||||
|
||||
/** Changes the name stored for the current transaction.
|
||||
|
||||
@ -145,18 +145,18 @@ public:
|
||||
called, but this can be used to change that name without starting a new
|
||||
transaction.
|
||||
*/
|
||||
void setCurrentTransactionName (const String& newName) noexcept;
|
||||
void setCurrentTransactionName (const String& newName);
|
||||
|
||||
/** Returns the name of the current transaction.
|
||||
@see setCurrentTransactionName
|
||||
*/
|
||||
String getCurrentTransactionName() const noexcept;
|
||||
String getCurrentTransactionName() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns true if there's at least one action in the list to undo.
|
||||
@see getUndoDescription, undo, canRedo
|
||||
*/
|
||||
bool canUndo() const noexcept;
|
||||
bool canUndo() const;
|
||||
|
||||
/** Tries to roll-back the last transaction.
|
||||
@returns true if the transaction can be undone, and false if it fails, or
|
||||
@ -217,7 +217,7 @@ public:
|
||||
/** Returns true if there's at least one action in the list to redo.
|
||||
@see getRedoDescription, redo, canUndo
|
||||
*/
|
||||
bool canRedo() const noexcept;
|
||||
bool canRedo() const;
|
||||
|
||||
/** Tries to redo the last transaction that was undone.
|
||||
@returns true if the transaction can be redone, and false if it fails, or
|
||||
@ -243,16 +243,18 @@ public:
|
||||
*/
|
||||
Time getTimeOfRedoTransaction() const;
|
||||
|
||||
/** Returns true if the caller code is in the middle of an undo or redo action. */
|
||||
bool isPerformingUndoRedo() const;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct ActionSet;
|
||||
friend struct ContainerDeletePolicy<ActionSet>;
|
||||
OwnedArray<ActionSet> transactions, stashedFutureTransactions;
|
||||
String newTransactionName;
|
||||
int totalUnitsStored = 0, maxNumUnitsToKeep = 0, minimumTransactionsToKeep = 0, nextIndex = 0;
|
||||
bool newTransaction = true, reentrancyCheck = false;
|
||||
ActionSet* getCurrentSet() const noexcept;
|
||||
ActionSet* getNextSet() const noexcept;
|
||||
bool newTransaction = true, isInsideUndoRedoCall = false;
|
||||
ActionSet* getCurrentSet() const;
|
||||
ActionSet* getNextSet() const;
|
||||
void moveFutureTransactionsToStash();
|
||||
void restoreStashedFutureTransactions();
|
||||
void dropOldTransactionsIfTooLarge();
|
||||
|
@ -40,11 +40,11 @@ class JUCE_API UndoableAction
|
||||
{
|
||||
protected:
|
||||
/** Creates an action. */
|
||||
UndoableAction() noexcept {}
|
||||
UndoableAction() = default;
|
||||
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~UndoableAction() {}
|
||||
virtual ~UndoableAction() = default;
|
||||
|
||||
//==============================================================================
|
||||
/** Overridden by a subclass to perform the action.
|
||||
|
@ -144,11 +144,6 @@ public:
|
||||
|
||||
expect (t["testkey"] == var());
|
||||
}
|
||||
|
||||
beginTest ("reset value");
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -181,11 +181,14 @@ public:
|
||||
/** Returns the property ID of the referenced property. */
|
||||
const Identifier& getPropertyID() const noexcept { return targetProperty; }
|
||||
|
||||
/** Returns the UndoManager that is being used. */
|
||||
UndoManager* getUndoManager() noexcept { return undoManager; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ValueTree targetTree;
|
||||
Identifier targetProperty;
|
||||
UndoManager* undoManager;
|
||||
UndoManager* undoManager = nullptr;
|
||||
Type defaultValue;
|
||||
Type cachedValue;
|
||||
|
||||
@ -199,13 +202,15 @@ private:
|
||||
void valueTreeChildOrderChanged (ValueTree&, int, int) override {}
|
||||
void valueTreeParentChanged (ValueTree&) override {}
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_WEAK_REFERENCEABLE (CachedValue)
|
||||
JUCE_DECLARE_NON_COPYABLE (CachedValue)
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
template <typename Type>
|
||||
inline CachedValue<Type>::CachedValue() : undoManager (nullptr) {}
|
||||
inline CachedValue<Type>::CachedValue() = default;
|
||||
|
||||
template <typename Type>
|
||||
inline CachedValue<Type>::CachedValue (ValueTree& v, const Identifier& i, UndoManager* um)
|
||||
|
@ -123,7 +123,7 @@ Value::Value (Value&& other) noexcept
|
||||
jassert (other.listeners.size() == 0);
|
||||
|
||||
other.removeFromListenerList();
|
||||
value = static_cast<ReferenceCountedObjectPtr<ValueSource>&&> (other.value);
|
||||
value = std::move (other.value);
|
||||
}
|
||||
|
||||
Value& Value::operator= (Value&& other) noexcept
|
||||
@ -133,7 +133,7 @@ Value& Value::operator= (Value&& other) noexcept
|
||||
jassert (other.listeners.size() == 0);
|
||||
|
||||
other.removeFromListenerList();
|
||||
value = static_cast<ReferenceCountedObjectPtr<ValueSource>&&> (other.value);
|
||||
value = std::move (other.value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -138,8 +138,8 @@ public:
|
||||
class JUCE_API Listener
|
||||
{
|
||||
public:
|
||||
Listener() {}
|
||||
virtual ~Listener() {}
|
||||
Listener() = default;
|
||||
virtual ~Listener() = default;
|
||||
|
||||
/** Called when a Value object is changed.
|
||||
|
||||
@ -180,7 +180,7 @@ public:
|
||||
{
|
||||
public:
|
||||
ValueSource();
|
||||
virtual ~ValueSource();
|
||||
~ValueSource() override;
|
||||
|
||||
/** Returns the current value of this object. */
|
||||
virtual var getValue() const = 0;
|
||||
|
@ -39,7 +39,7 @@ public:
|
||||
{
|
||||
for (auto* c : other.children)
|
||||
{
|
||||
auto child = new SharedObject (*c);
|
||||
auto* child = new SharedObject (*c);
|
||||
child->parent = this;
|
||||
children.add (child);
|
||||
}
|
||||
@ -51,18 +51,18 @@ public:
|
||||
{
|
||||
jassert (parent == nullptr); // this should never happen unless something isn't obeying the ref-counting!
|
||||
|
||||
for (int i = children.size(); --i >= 0;)
|
||||
for (auto i = children.size(); --i >= 0;)
|
||||
{
|
||||
const Ptr c (children.getObjectPointerUnchecked(i));
|
||||
const Ptr c (children.getObjectPointerUnchecked (i));
|
||||
c->parent = nullptr;
|
||||
children.remove (i);
|
||||
c->sendParentChangeMessage();
|
||||
}
|
||||
}
|
||||
|
||||
SharedObject* getRoot() noexcept
|
||||
SharedObject& getRoot() noexcept
|
||||
{
|
||||
return parent == nullptr ? this : parent->getRoot();
|
||||
return parent == nullptr ? *this : parent->getRoot();
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
@ -72,7 +72,7 @@ public:
|
||||
|
||||
if (numListeners == 1)
|
||||
{
|
||||
valueTreesWithListeners.getUnchecked(0)->listeners.callExcluding (listenerToExclude, fn);
|
||||
valueTreesWithListeners.getUnchecked (0)->listeners.callExcluding (listenerToExclude, fn);
|
||||
}
|
||||
else if (numListeners > 0)
|
||||
{
|
||||
@ -80,7 +80,7 @@ public:
|
||||
|
||||
for (int i = 0; i < numListeners; ++i)
|
||||
{
|
||||
auto* v = listenersCopy.getUnchecked(i);
|
||||
auto* v = listenersCopy.getUnchecked (i);
|
||||
|
||||
if (i == 0 || valueTreesWithListeners.contains (v))
|
||||
v->listeners.callExcluding (listenerToExclude, fn);
|
||||
@ -97,33 +97,33 @@ public:
|
||||
|
||||
void sendPropertyChangeMessage (const Identifier& property, ValueTree::Listener* listenerToExclude = nullptr)
|
||||
{
|
||||
ValueTree tree (this);
|
||||
ValueTree tree (*this);
|
||||
callListenersForAllParents (listenerToExclude, [&] (Listener& l) { l.valueTreePropertyChanged (tree, property); });
|
||||
}
|
||||
|
||||
void sendChildAddedMessage (ValueTree child)
|
||||
{
|
||||
ValueTree tree (this);
|
||||
ValueTree tree (*this);
|
||||
callListenersForAllParents (nullptr, [&] (Listener& l) { l.valueTreeChildAdded (tree, child); });
|
||||
}
|
||||
|
||||
void sendChildRemovedMessage (ValueTree child, int index)
|
||||
{
|
||||
ValueTree tree (this);
|
||||
ValueTree tree (*this);
|
||||
callListenersForAllParents (nullptr, [=, &tree, &child] (Listener& l) { l.valueTreeChildRemoved (tree, child, index); });
|
||||
}
|
||||
|
||||
void sendChildOrderChangedMessage (int oldIndex, int newIndex)
|
||||
{
|
||||
ValueTree tree (this);
|
||||
ValueTree tree (*this);
|
||||
callListenersForAllParents (nullptr, [=, &tree] (Listener& l) { l.valueTreeChildOrderChanged (tree, oldIndex, newIndex); });
|
||||
}
|
||||
|
||||
void sendParentChangeMessage()
|
||||
{
|
||||
ValueTree tree (this);
|
||||
ValueTree tree (*this);
|
||||
|
||||
for (int j = children.size(); --j >= 0;)
|
||||
for (auto j = children.size(); --j >= 0;)
|
||||
if (auto* child = children.getObjectPointer (j))
|
||||
child->sendParentChangeMessage();
|
||||
|
||||
@ -143,12 +143,12 @@ public:
|
||||
if (auto* existingValue = properties.getVarPointer (name))
|
||||
{
|
||||
if (*existingValue != newValue)
|
||||
undoManager->perform (new SetPropertyAction (this, name, newValue, *existingValue,
|
||||
undoManager->perform (new SetPropertyAction (*this, name, newValue, *existingValue,
|
||||
false, false, listenerToExclude));
|
||||
}
|
||||
else
|
||||
{
|
||||
undoManager->perform (new SetPropertyAction (this, name, newValue, {},
|
||||
undoManager->perform (new SetPropertyAction (*this, name, newValue, {},
|
||||
true, false, listenerToExclude));
|
||||
}
|
||||
}
|
||||
@ -169,7 +169,7 @@ public:
|
||||
else
|
||||
{
|
||||
if (properties.contains (name))
|
||||
undoManager->perform (new SetPropertyAction (this, name, {}, properties [name], false, true));
|
||||
undoManager->perform (new SetPropertyAction (*this, name, {}, properties[name], false, true));
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,27 +186,27 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = properties.size(); --i >= 0;)
|
||||
undoManager->perform (new SetPropertyAction (this, properties.getName(i), {},
|
||||
properties.getValueAt(i), false, true));
|
||||
for (auto i = properties.size(); --i >= 0;)
|
||||
undoManager->perform (new SetPropertyAction (*this, properties.getName (i), {},
|
||||
properties.getValueAt (i), false, true));
|
||||
}
|
||||
}
|
||||
|
||||
void copyPropertiesFrom (const SharedObject& source, UndoManager* undoManager)
|
||||
{
|
||||
for (int i = properties.size(); --i >= 0;)
|
||||
for (auto i = properties.size(); --i >= 0;)
|
||||
if (! source.properties.contains (properties.getName (i)))
|
||||
removeProperty (properties.getName (i), undoManager);
|
||||
|
||||
for (int i = 0; i < source.properties.size(); ++i)
|
||||
setProperty (source.properties.getName(i), source.properties.getValueAt(i), undoManager);
|
||||
setProperty (source.properties.getName (i), source.properties.getValueAt (i), undoManager);
|
||||
}
|
||||
|
||||
ValueTree getChildWithName (const Identifier& typeToMatch) const
|
||||
{
|
||||
for (auto* s : children)
|
||||
if (s->type == typeToMatch)
|
||||
return ValueTree (s);
|
||||
return ValueTree (*s);
|
||||
|
||||
return {};
|
||||
}
|
||||
@ -215,18 +215,18 @@ public:
|
||||
{
|
||||
for (auto* s : children)
|
||||
if (s->type == typeToMatch)
|
||||
return ValueTree (s);
|
||||
return ValueTree (*s);
|
||||
|
||||
auto newObject = new SharedObject (typeToMatch);
|
||||
addChild (newObject, -1, undoManager);
|
||||
return ValueTree (newObject);
|
||||
return ValueTree (*newObject);
|
||||
}
|
||||
|
||||
ValueTree getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const
|
||||
{
|
||||
for (auto* s : children)
|
||||
if (s->properties[propertyName] == propertyValue)
|
||||
return ValueTree (s);
|
||||
return ValueTree (*s);
|
||||
|
||||
return {};
|
||||
}
|
||||
@ -266,7 +266,7 @@ public:
|
||||
{
|
||||
children.insert (index, child);
|
||||
child->parent = this;
|
||||
sendChildAddedMessage (ValueTree (child));
|
||||
sendChildAddedMessage (ValueTree (*child));
|
||||
child->sendParentChangeMessage();
|
||||
}
|
||||
else
|
||||
@ -274,7 +274,7 @@ public:
|
||||
if (! isPositiveAndBelow (index, children.size()))
|
||||
index = children.size();
|
||||
|
||||
undoManager->perform (new AddOrRemoveChildAction (this, index, child));
|
||||
undoManager->perform (new AddOrRemoveChildAction (*this, index, child));
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -288,7 +288,7 @@ public:
|
||||
|
||||
void removeChild (int childIndex, UndoManager* undoManager)
|
||||
{
|
||||
if (Ptr child = children.getObjectPointer (childIndex))
|
||||
if (auto child = Ptr (children.getObjectPointer (childIndex)))
|
||||
{
|
||||
if (undoManager == nullptr)
|
||||
{
|
||||
@ -299,7 +299,7 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
undoManager->perform (new AddOrRemoveChildAction (this, childIndex, nullptr));
|
||||
undoManager->perform (new AddOrRemoveChildAction (*this, childIndex, {}));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -328,7 +328,7 @@ public:
|
||||
if (! isPositiveAndBelow (newIndex, children.size()))
|
||||
newIndex = children.size() - 1;
|
||||
|
||||
undoManager->perform (new MoveChildAction (this, currentIndex, newIndex));
|
||||
undoManager->perform (new MoveChildAction (*this, currentIndex, newIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -339,7 +339,7 @@ public:
|
||||
|
||||
for (int i = 0; i < children.size(); ++i)
|
||||
{
|
||||
auto* child = newOrder.getUnchecked(i)->object.get();
|
||||
auto* child = newOrder.getUnchecked (i)->object.get();
|
||||
|
||||
if (children.getObjectPointerUnchecked (i) != child)
|
||||
{
|
||||
@ -359,7 +359,7 @@ public:
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < children.size(); ++i)
|
||||
if (! children.getObjectPointerUnchecked(i)->isEquivalentTo (*other.children.getObjectPointerUnchecked(i)))
|
||||
if (! children.getObjectPointerUnchecked (i)->isEquivalentTo (*other.children.getObjectPointerUnchecked (i)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -367,12 +367,12 @@ public:
|
||||
|
||||
XmlElement* createXml() const
|
||||
{
|
||||
auto xml = new XmlElement (type);
|
||||
auto* xml = new XmlElement (type);
|
||||
properties.copyToXmlAttributes (*xml);
|
||||
|
||||
// (NB: it's faster to add nodes to XML elements in reverse order)
|
||||
for (int i = children.size(); --i >= 0;)
|
||||
xml->prependChildElement (children.getObjectPointerUnchecked(i)->createXml());
|
||||
for (auto i = children.size(); --i >= 0;)
|
||||
xml->prependChildElement (children.getObjectPointerUnchecked (i)->createXml());
|
||||
|
||||
return xml;
|
||||
}
|
||||
@ -385,13 +385,13 @@ public:
|
||||
for (int j = 0; j < properties.size(); ++j)
|
||||
{
|
||||
output.writeString (properties.getName (j).toString());
|
||||
properties.getValueAt(j).writeToStream (output);
|
||||
properties.getValueAt (j).writeToStream (output);
|
||||
}
|
||||
|
||||
output.writeCompressedInt (children.size());
|
||||
|
||||
for (int i = 0; i < children.size(); ++i)
|
||||
writeObjectToStream (output, children.getObjectPointerUnchecked(i));
|
||||
for (auto* c : children)
|
||||
writeObjectToStream (output, c);
|
||||
}
|
||||
|
||||
static void writeObjectToStream (OutputStream& output, const SharedObject* object)
|
||||
@ -411,10 +411,11 @@ public:
|
||||
//==============================================================================
|
||||
struct SetPropertyAction : public UndoableAction
|
||||
{
|
||||
SetPropertyAction (SharedObject* so, const Identifier& propertyName,
|
||||
SetPropertyAction (Ptr targetObject, const Identifier& propertyName,
|
||||
const var& newVal, const var& oldVal, bool isAdding, bool isDeleting,
|
||||
ValueTree::Listener* listenerToExclude = nullptr)
|
||||
: target (so), name (propertyName), newValue (newVal), oldValue (oldVal),
|
||||
: target (std::move (targetObject)),
|
||||
name (propertyName), newValue (newVal), oldValue (oldVal),
|
||||
isAddingNewProperty (isAdding), isDeletingProperty (isDeleting),
|
||||
excludeListener (listenerToExclude)
|
||||
{
|
||||
@ -454,7 +455,7 @@ public:
|
||||
if (auto* next = dynamic_cast<SetPropertyAction*> (nextAction))
|
||||
if (next->target == target && next->name == name
|
||||
&& ! (next->isAddingNewProperty || next->isDeletingProperty))
|
||||
return new SetPropertyAction (target, name, next->newValue, oldValue, false, false);
|
||||
return new SetPropertyAction (*target, name, next->newValue, oldValue, false, false);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@ -474,9 +475,9 @@ public:
|
||||
//==============================================================================
|
||||
struct AddOrRemoveChildAction : public UndoableAction
|
||||
{
|
||||
AddOrRemoveChildAction (SharedObject* parentObject, int index, SharedObject* newChild)
|
||||
: target (parentObject),
|
||||
child (newChild != nullptr ? newChild : parentObject->children.getObjectPointer (index)),
|
||||
AddOrRemoveChildAction (Ptr parentObject, int index, SharedObject* newChild)
|
||||
: target (std::move (parentObject)),
|
||||
child (newChild != nullptr ? newChild : target->children.getObjectPointer (index)),
|
||||
childIndex (index),
|
||||
isDeleting (newChild == nullptr)
|
||||
{
|
||||
@ -488,7 +489,7 @@ public:
|
||||
if (isDeleting)
|
||||
target->removeChild (childIndex, nullptr);
|
||||
else
|
||||
target->addChild (child, childIndex, nullptr);
|
||||
target->addChild (child.get(), childIndex, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -497,7 +498,7 @@ public:
|
||||
{
|
||||
if (isDeleting)
|
||||
{
|
||||
target->addChild (child, childIndex, nullptr);
|
||||
target->addChild (child.get(), childIndex, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -526,8 +527,8 @@ public:
|
||||
//==============================================================================
|
||||
struct MoveChildAction : public UndoableAction
|
||||
{
|
||||
MoveChildAction (SharedObject* parentObject, int fromIndex, int toIndex) noexcept
|
||||
: parent (parentObject), startIndex (fromIndex), endIndex (toIndex)
|
||||
MoveChildAction (Ptr parentObject, int fromIndex, int toIndex) noexcept
|
||||
: parent (std::move (parentObject)), startIndex (fromIndex), endIndex (toIndex)
|
||||
{
|
||||
}
|
||||
|
||||
@ -587,20 +588,18 @@ ValueTree::ValueTree (const Identifier& type) : object (new ValueTree::SharedOb
|
||||
}
|
||||
|
||||
ValueTree::ValueTree (const Identifier& type,
|
||||
std::initializer_list<std::pair<Identifier, var>> properties,
|
||||
std::initializer_list<NamedValueSet::NamedValue> properties,
|
||||
std::initializer_list<ValueTree> subTrees)
|
||||
: ValueTree (type)
|
||||
{
|
||||
for (auto& prop : properties)
|
||||
setProperty (prop.first, prop.second, nullptr);
|
||||
object->properties = NamedValueSet (std::move (properties));
|
||||
|
||||
for (auto& tree : subTrees)
|
||||
addChild (tree, -1, nullptr);
|
||||
}
|
||||
|
||||
ValueTree::ValueTree (SharedObject* so) noexcept : object (so)
|
||||
{
|
||||
}
|
||||
ValueTree::ValueTree (SharedObject::Ptr so) noexcept : object (std::move (so)) {}
|
||||
ValueTree::ValueTree (SharedObject& so) noexcept : object (so) {}
|
||||
|
||||
ValueTree::ValueTree (const ValueTree& other) noexcept : object (other.object)
|
||||
{
|
||||
@ -632,7 +631,7 @@ ValueTree& ValueTree::operator= (const ValueTree& other)
|
||||
}
|
||||
|
||||
ValueTree::ValueTree (ValueTree&& other) noexcept
|
||||
: object (static_cast<SharedObject::Ptr&&> (other.object))
|
||||
: object (std::move (other.object))
|
||||
{
|
||||
if (object != nullptr)
|
||||
object->valueTreesWithListeners.removeValue (&other);
|
||||
@ -663,7 +662,32 @@ bool ValueTree::isEquivalentTo (const ValueTree& other) const
|
||||
|
||||
ValueTree ValueTree::createCopy() const
|
||||
{
|
||||
return ValueTree (createCopyIfNotNull (object.get()));
|
||||
if (object != nullptr)
|
||||
return ValueTree (*new SharedObject (*object));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void ValueTree::copyPropertiesFrom (const ValueTree& source, UndoManager* undoManager)
|
||||
{
|
||||
jassert (object != nullptr || source.object == nullptr); // Trying to add properties to a null ValueTree will fail!
|
||||
|
||||
if (source.object == nullptr)
|
||||
removeAllProperties (undoManager);
|
||||
else if (object != nullptr)
|
||||
object->copyPropertiesFrom (*(source.object), undoManager);
|
||||
}
|
||||
|
||||
void ValueTree::copyPropertiesAndChildrenFrom (const ValueTree& source, UndoManager* undoManager)
|
||||
{
|
||||
jassert (object != nullptr || source.object == nullptr); // Trying to copy to a null ValueTree will fail!
|
||||
|
||||
copyPropertiesFrom (source, undoManager);
|
||||
removeAllChildren (undoManager);
|
||||
|
||||
if (object != nullptr && source.object != nullptr)
|
||||
for (auto& child : source.object->children)
|
||||
object->addChild (createCopyIfNotNull (child), -1, undoManager);
|
||||
}
|
||||
|
||||
bool ValueTree::hasType (const Identifier& typeName) const noexcept
|
||||
@ -678,23 +702,29 @@ Identifier ValueTree::getType() const noexcept
|
||||
|
||||
ValueTree ValueTree::getParent() const noexcept
|
||||
{
|
||||
return ValueTree (object != nullptr ? object->parent
|
||||
: static_cast<SharedObject*> (nullptr));
|
||||
if (object != nullptr)
|
||||
if (auto p = object->parent)
|
||||
return ValueTree (*p);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ValueTree ValueTree::getRoot() const noexcept
|
||||
{
|
||||
return ValueTree (object != nullptr ? object->getRoot()
|
||||
: static_cast<SharedObject*> (nullptr));
|
||||
if (object != nullptr)
|
||||
return ValueTree (object->getRoot());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ValueTree ValueTree::getSibling (int delta) const noexcept
|
||||
{
|
||||
if (object == nullptr || object->parent == nullptr)
|
||||
return {};
|
||||
if (object != nullptr)
|
||||
if (auto* p = object->parent)
|
||||
if (auto* c = p->children.getObjectPointer (p->indexOf (*this) + delta))
|
||||
return ValueTree (*c);
|
||||
|
||||
auto index = object->parent->indexOf (*this) + delta;
|
||||
return ValueTree (object->parent->children.getObjectPointer (index));
|
||||
return {};
|
||||
}
|
||||
|
||||
static const var& getNullVarRef() noexcept
|
||||
@ -770,16 +800,6 @@ Identifier ValueTree::getPropertyName (int index) const noexcept
|
||||
: object->properties.getName (index);
|
||||
}
|
||||
|
||||
void ValueTree::copyPropertiesFrom (const ValueTree& source, UndoManager* undoManager)
|
||||
{
|
||||
jassert (object != nullptr || source.object == nullptr); // Trying to add properties to a null ValueTree will fail!
|
||||
|
||||
if (source.object == nullptr)
|
||||
removeAllProperties (undoManager);
|
||||
else if (object != nullptr)
|
||||
object->copyPropertiesFrom (*(source.object), undoManager);
|
||||
}
|
||||
|
||||
int ValueTree::getReferenceCount() const noexcept
|
||||
{
|
||||
return object != nullptr ? object->getReferenceCount() : 0;
|
||||
@ -795,12 +815,12 @@ struct ValueTreePropertyValueSource : public Value::ValueSource,
|
||||
tree.addListener (this);
|
||||
}
|
||||
|
||||
~ValueTreePropertyValueSource()
|
||||
~ValueTreePropertyValueSource() override
|
||||
{
|
||||
tree.removeListener (this);
|
||||
}
|
||||
|
||||
var getValue() const override { return tree [property]; }
|
||||
var getValue() const override { return tree[property]; }
|
||||
void setValue (const var& newValue) override { tree.setProperty (property, newValue, undoManager); }
|
||||
|
||||
private:
|
||||
@ -836,29 +856,30 @@ int ValueTree::getNumChildren() const noexcept
|
||||
|
||||
ValueTree ValueTree::getChild (int index) const
|
||||
{
|
||||
return ValueTree (object != nullptr ? object->children.getObjectPointer (index)
|
||||
: static_cast<SharedObject*> (nullptr));
|
||||
if (object != nullptr)
|
||||
if (auto* c = object->children.getObjectPointer (index))
|
||||
return ValueTree (*c);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ValueTree::Iterator::Iterator (const ValueTree& v, bool isEnd) noexcept
|
||||
ValueTree::Iterator::Iterator (const ValueTree& v, bool isEnd)
|
||||
: internal (v.object != nullptr ? (isEnd ? v.object->children.end() : v.object->children.begin()) : nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ValueTree::Iterator& ValueTree::Iterator::operator++() noexcept
|
||||
ValueTree::Iterator& ValueTree::Iterator::operator++()
|
||||
{
|
||||
internal = static_cast<SharedObject**> (internal) + 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool ValueTree::Iterator::operator!= (const Iterator& other) const noexcept
|
||||
{
|
||||
return internal != other.internal;
|
||||
}
|
||||
bool ValueTree::Iterator::operator== (const Iterator& other) const { return internal == other.internal; }
|
||||
bool ValueTree::Iterator::operator!= (const Iterator& other) const { return internal != other.internal; }
|
||||
|
||||
ValueTree ValueTree::Iterator::operator*() const
|
||||
{
|
||||
return ValueTree (*static_cast<SharedObject**> (internal));
|
||||
return ValueTree (SharedObject::Ptr (*static_cast<SharedObject**> (internal)));
|
||||
}
|
||||
|
||||
ValueTree::Iterator ValueTree::begin() const noexcept { return Iterator (*this, false); }
|
||||
@ -881,7 +902,7 @@ ValueTree ValueTree::getChildWithProperty (const Identifier& propertyName, const
|
||||
|
||||
bool ValueTree::isAChildOf (const ValueTree& possibleParent) const noexcept
|
||||
{
|
||||
return object != nullptr && object->isAChildOf (possibleParent.object);
|
||||
return object != nullptr && object->isAChildOf (possibleParent.object.get());
|
||||
}
|
||||
|
||||
int ValueTree::indexOf (const ValueTree& child) const noexcept
|
||||
@ -894,7 +915,7 @@ void ValueTree::addChild (const ValueTree& child, int index, UndoManager* undoMa
|
||||
jassert (object != nullptr); // Trying to add a child to a null ValueTree!
|
||||
|
||||
if (object != nullptr)
|
||||
object->addChild (child.object, index, undoManager);
|
||||
object->addChild (child.object.get(), index, undoManager);
|
||||
}
|
||||
|
||||
void ValueTree::appendChild (const ValueTree& child, UndoManager* undoManager)
|
||||
@ -932,7 +953,10 @@ void ValueTree::createListOfChildren (OwnedArray<ValueTree>& list) const
|
||||
jassert (object != nullptr);
|
||||
|
||||
for (auto* o : object->children)
|
||||
list.add (new ValueTree (o));
|
||||
{
|
||||
jassert (o != nullptr);
|
||||
list.add (new ValueTree (*o));
|
||||
}
|
||||
}
|
||||
|
||||
void ValueTree::reorderChildren (const OwnedArray<ValueTree>& newOrder, UndoManager* undoManager)
|
||||
@ -1004,7 +1028,7 @@ String ValueTree::toXmlString() const
|
||||
//==============================================================================
|
||||
void ValueTree::writeToStream (OutputStream& output) const
|
||||
{
|
||||
SharedObject::writeObjectToStream (output, object);
|
||||
SharedObject::writeObjectToStream (output, object.get());
|
||||
}
|
||||
|
||||
ValueTree ValueTree::readFromStream (InputStream& input)
|
||||
@ -1045,7 +1069,7 @@ ValueTree ValueTree::readFromStream (InputStream& input)
|
||||
return v;
|
||||
|
||||
v.object->children.add (child.object);
|
||||
child.object->parent = v.object;
|
||||
child.object->parent = v.object.get();
|
||||
}
|
||||
|
||||
return v;
|
||||
@ -1080,7 +1104,7 @@ public:
|
||||
const char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-:";
|
||||
|
||||
for (int i = 1 + r.nextInt (numElementsInArray (buffer) - 2); --i >= 0;)
|
||||
buffer[i] = chars [r.nextInt (sizeof (chars) - 1)];
|
||||
buffer[i] = chars[r.nextInt (sizeof (chars) - 1)];
|
||||
|
||||
String result (buffer);
|
||||
|
||||
@ -1133,32 +1157,68 @@ public:
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
beginTest ("ValueTree");
|
||||
auto r = getRandom();
|
||||
|
||||
for (int i = 10; --i >= 0;)
|
||||
{
|
||||
MemoryOutputStream mo;
|
||||
auto v1 = createRandomTree (nullptr, 0, r);
|
||||
v1.writeToStream (mo);
|
||||
beginTest ("ValueTree");
|
||||
|
||||
MemoryInputStream mi (mo.getData(), mo.getDataSize(), false);
|
||||
auto v2 = ValueTree::readFromStream (mi);
|
||||
expect (v1.isEquivalentTo (v2));
|
||||
auto r = getRandom();
|
||||
|
||||
MemoryOutputStream zipped;
|
||||
for (int i = 10; --i >= 0;)
|
||||
{
|
||||
GZIPCompressorOutputStream zippedOut (zipped);
|
||||
v1.writeToStream (zippedOut);
|
||||
MemoryOutputStream mo;
|
||||
auto v1 = createRandomTree (nullptr, 0, r);
|
||||
v1.writeToStream (mo);
|
||||
|
||||
MemoryInputStream mi (mo.getData(), mo.getDataSize(), false);
|
||||
auto v2 = ValueTree::readFromStream (mi);
|
||||
expect (v1.isEquivalentTo (v2));
|
||||
|
||||
MemoryOutputStream zipped;
|
||||
{
|
||||
GZIPCompressorOutputStream zippedOut (zipped);
|
||||
v1.writeToStream (zippedOut);
|
||||
}
|
||||
expect (v1.isEquivalentTo (ValueTree::readFromGZIPData (zipped.getData(), zipped.getDataSize())));
|
||||
|
||||
std::unique_ptr<XmlElement> xml1 (v1.createXml());
|
||||
std::unique_ptr<XmlElement> xml2 (v2.createCopy().createXml());
|
||||
expect (xml1->isEquivalentTo (xml2.get(), false));
|
||||
|
||||
auto v4 = v2.createCopy();
|
||||
expect (v1.isEquivalentTo (v4));
|
||||
}
|
||||
expect (v1.isEquivalentTo (ValueTree::readFromGZIPData (zipped.getData(), zipped.getDataSize())));
|
||||
}
|
||||
|
||||
std::unique_ptr<XmlElement> xml1 (v1.createXml());
|
||||
std::unique_ptr<XmlElement> xml2 (v2.createCopy().createXml());
|
||||
expect (xml1->isEquivalentTo (xml2.get(), false));
|
||||
{
|
||||
beginTest ("Float formatting");
|
||||
|
||||
auto v4 = v2.createCopy();
|
||||
expect (v1.isEquivalentTo (v4));
|
||||
ValueTree testVT ("Test");
|
||||
Identifier number ("number");
|
||||
|
||||
std::map<double, String> tests;
|
||||
tests[1] = "1.0";
|
||||
tests[1.1] = "1.1";
|
||||
tests[1.01] = "1.01";
|
||||
tests[0.76378] = "0.76378";
|
||||
tests[-10] = "-10.0";
|
||||
tests[10.01] = "10.01";
|
||||
tests[0.0123] = "0.0123";
|
||||
tests[-3.7e-27] = "-3.7e-27";
|
||||
tests[1e+40] = "1.0e40";
|
||||
tests[-12345678901234567.0] = "-1.234567890123457e16";
|
||||
tests[192000] = "192000.0";
|
||||
tests[1234567] = "1.234567e6";
|
||||
tests[0.00006] = "0.00006";
|
||||
tests[0.000006] = "6.0e-6";
|
||||
|
||||
for (auto& test : tests)
|
||||
{
|
||||
testVT.setProperty (number, test.first, nullptr);
|
||||
auto lines = StringArray::fromLines (testVT.toXmlString());
|
||||
lines.removeEmptyStrings();
|
||||
auto numLines = lines.size();
|
||||
expect (numLines > 1);
|
||||
expectEquals (lines[numLines - 1], "<Test number=\"" + test.second + "\"/>");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -128,18 +128,23 @@ public:
|
||||
@endverbatim
|
||||
*/
|
||||
ValueTree (const Identifier& type,
|
||||
std::initializer_list<std::pair<Identifier, var>> properties,
|
||||
std::initializer_list<NamedValueSet::NamedValue> properties,
|
||||
std::initializer_list<ValueTree> subTrees = {});
|
||||
|
||||
/** Creates a reference to another ValueTree. */
|
||||
ValueTree (const ValueTree&) noexcept;
|
||||
|
||||
/** Changes this object to be a reference to the given tree. */
|
||||
ValueTree& operator= (const ValueTree&);
|
||||
|
||||
/** Move constructor */
|
||||
ValueTree (ValueTree&&) noexcept;
|
||||
|
||||
/** Changes this object to be a reference to the given tree.
|
||||
Note that calling this just points this at the new object and invokes the
|
||||
Listener::valueTreeRedirected callback, but it's not an undoable operation. If
|
||||
you're trying to replace an entire tree in an undoable way, you probably want
|
||||
to use copyPropertiesAndChildrenFrom() instead.
|
||||
*/
|
||||
ValueTree& operator= (const ValueTree&);
|
||||
|
||||
/** Destructor. */
|
||||
~ValueTree();
|
||||
|
||||
@ -172,6 +177,19 @@ public:
|
||||
/** Returns a deep copy of this tree and all its sub-trees. */
|
||||
ValueTree createCopy() const;
|
||||
|
||||
/** Overwrites all the properties in this tree with the properties of the source tree.
|
||||
Any properties that already exist will be updated; and new ones will be added, and
|
||||
any that are not present in the source tree will be removed.
|
||||
@see copyPropertiesAndChildrenFrom
|
||||
*/
|
||||
void copyPropertiesFrom (const ValueTree& source, UndoManager* undoManager);
|
||||
|
||||
/** Replaces all children and properties of this object with copies of those from
|
||||
the source object.
|
||||
@see copyPropertiesFrom
|
||||
*/
|
||||
void copyPropertiesAndChildrenFrom (const ValueTree& source, UndoManager* undoManager);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the type of this tree.
|
||||
The type is specified when the ValueTree is created.
|
||||
@ -261,12 +279,6 @@ public:
|
||||
Value getPropertyAsValue (const Identifier& name, UndoManager* undoManager,
|
||||
bool shouldUpdateSynchronously = false);
|
||||
|
||||
/** Overwrites all the properties in this tree with the properties of the source tree.
|
||||
Any properties that already exist will be updated; and new ones will be added, and
|
||||
any that are not present in the source tree will be removed.
|
||||
*/
|
||||
void copyPropertiesFrom (const ValueTree& source, UndoManager* undoManager);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the number of child trees inside this one.
|
||||
@see getChild
|
||||
@ -388,10 +400,11 @@ public:
|
||||
*/
|
||||
struct Iterator
|
||||
{
|
||||
Iterator (const ValueTree&, bool isEnd) noexcept;
|
||||
Iterator& operator++() noexcept;
|
||||
Iterator (const ValueTree&, bool isEnd);
|
||||
Iterator& operator++();
|
||||
|
||||
bool operator!= (const Iterator&) const noexcept;
|
||||
bool operator== (const Iterator&) const;
|
||||
bool operator!= (const Iterator&) const;
|
||||
ValueTree operator*() const;
|
||||
|
||||
using difference_type = std::ptrdiff_t;
|
||||
@ -462,7 +475,7 @@ public:
|
||||
{
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~Listener() {}
|
||||
virtual ~Listener() = default;
|
||||
|
||||
/** This method is called when a property of this tree (or of one of its sub-trees) is changed.
|
||||
Note that when you register a listener to a tree, it will receive this callback for
|
||||
@ -620,7 +633,8 @@ private:
|
||||
void createListOfChildren (OwnedArray<ValueTree>&) const;
|
||||
void reorderChildren (const OwnedArray<ValueTree>&, UndoManager*);
|
||||
|
||||
explicit ValueTree (SharedObject*) noexcept;
|
||||
explicit ValueTree (ReferenceCountedObjectPtr<SharedObject>) noexcept;
|
||||
explicit ValueTree (SharedObject&) noexcept;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
@ -55,7 +55,7 @@ public:
|
||||
ValueTreeSynchroniser (const ValueTree& tree);
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~ValueTreeSynchroniser();
|
||||
~ValueTreeSynchroniser() override;
|
||||
|
||||
/** This callback happens when the ValueTree changes and the given state-change message
|
||||
needs to be applied to any other trees that need to stay in sync with it.
|
||||
|
100
modules/juce_data_structures/values/juce_ValueWithDefault.cpp
Normal file
100
modules/juce_data_structures/values/juce_ValueWithDefault.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2017 - ROLI Ltd.
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
|
||||
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
|
||||
27th April 2017).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-5-licence
|
||||
Privacy Policy: www.juce.com/juce-5-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
#if JUCE_UNIT_TESTS
|
||||
|
||||
class ValueWithDefaultTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
ValueWithDefaultTests() : UnitTest ("ValueWithDefault", "Values") {}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
beginTest ("default constructor");
|
||||
{
|
||||
ValueWithDefault vwd;
|
||||
expect (vwd.isUsingDefault());
|
||||
expect (vwd.get() == var());
|
||||
}
|
||||
|
||||
beginTest ("missing property");
|
||||
{
|
||||
ValueTree t ("root");
|
||||
ValueWithDefault vwd (t, "testKey", nullptr, "default");
|
||||
|
||||
expect (vwd.isUsingDefault());
|
||||
expectEquals (vwd.get().toString(), String ("default"));
|
||||
}
|
||||
|
||||
beginTest ("non-empty property");
|
||||
{
|
||||
ValueTree t ("root");
|
||||
t.setProperty ("testKey", "non-default", nullptr);
|
||||
|
||||
ValueWithDefault vwd (t, "testKey", nullptr, "default");
|
||||
|
||||
expect (! vwd.isUsingDefault());
|
||||
expectEquals (vwd.get().toString(), String ("non-default"));
|
||||
}
|
||||
|
||||
beginTest ("set default");
|
||||
{
|
||||
ValueTree t ("root");
|
||||
|
||||
ValueWithDefault vwd (t, "testkey", nullptr);
|
||||
vwd.setDefault ("default");
|
||||
|
||||
expect (vwd.isUsingDefault());
|
||||
expectEquals (vwd.get().toString(), String ("default"));
|
||||
}
|
||||
|
||||
beginTest ("set value");
|
||||
{
|
||||
ValueTree t ("root");
|
||||
t.setProperty ("testkey", "testvalue", nullptr);
|
||||
|
||||
ValueWithDefault vwd (t, "testkey", nullptr, "default");
|
||||
vwd = "newvalue";
|
||||
|
||||
expect (! vwd.isUsingDefault());
|
||||
expectEquals (t["testkey"].toString(), String ("newvalue"));
|
||||
|
||||
vwd.resetToDefault();
|
||||
|
||||
expect (vwd.isUsingDefault());
|
||||
expect (t["testkey"] == var());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static ValueWithDefaultTests valueWithDefaultTests;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
@ -41,7 +41,7 @@ class ValueWithDefault
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an unitialised ValueWithDefault. Initialise it using one of the referTo() methods. */
|
||||
ValueWithDefault() : undoManager (nullptr) {}
|
||||
ValueWithDefault() = default;
|
||||
|
||||
/** Creates an ValueWithDefault object. The default value will be an empty var. */
|
||||
ValueWithDefault (ValueTree& tree, const Identifier& propertyID, UndoManager* um)
|
||||
@ -121,13 +121,13 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns true if the property does not exist or is empty. */
|
||||
/** Returns true if the property does not exist in the referenced ValueTree. */
|
||||
bool isUsingDefault() const
|
||||
{
|
||||
return ! targetTree.hasProperty (targetProperty);
|
||||
}
|
||||
|
||||
/** Resets the property to an empty var. */
|
||||
/** Removes the property from the referenced ValueTree. */
|
||||
void resetToDefault() noexcept
|
||||
{
|
||||
targetTree.removeProperty (targetProperty, nullptr);
|
||||
@ -181,17 +181,29 @@ public:
|
||||
/** Returns the property ID of the referenced property. */
|
||||
Identifier& getPropertyID() noexcept { return targetProperty; }
|
||||
|
||||
/** Returns the UndoManager that is being used. */
|
||||
UndoManager* getUndoManager() noexcept { return undoManager; }
|
||||
|
||||
//==============================================================================
|
||||
ValueWithDefault& operator= (const ValueWithDefault& other)
|
||||
{
|
||||
referToWithDefault (other.targetTree, other.targetProperty, other.undoManager,
|
||||
other.defaultValue, other.delimiter);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ValueTree targetTree;
|
||||
Identifier targetProperty;
|
||||
UndoManager* undoManager;
|
||||
UndoManager* undoManager = nullptr;
|
||||
var defaultValue;
|
||||
|
||||
String delimiter;
|
||||
|
||||
//==============================================================================
|
||||
void referToWithDefault (ValueTree& v, const Identifier& i, UndoManager* um,
|
||||
void referToWithDefault (const ValueTree& v, const Identifier& i, UndoManager* um,
|
||||
const var& defaultVal, StringRef del)
|
||||
{
|
||||
targetTree = v;
|
||||
@ -209,6 +221,7 @@ private:
|
||||
jassert (delimiter.isNotEmpty());
|
||||
|
||||
StringArray elements;
|
||||
|
||||
for (auto& v : input)
|
||||
elements.add (v.toString());
|
||||
|
||||
@ -224,6 +237,9 @@ private:
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_WEAK_REFERENCEABLE (ValueWithDefault)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
Reference in New Issue
Block a user