From c1f4f5501f2bf2183c962786d74cb44b8df1ed5a Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Thu, 22 Apr 2010 11:52:53 +0100 Subject: [PATCH] Added a couple of methods to ValueTree. Added a MidiBuffer::ensureSize method and used it in the audio plugin wrapper code to preallocate their midi buffers. --- .../Source/model/jucer_ComponentDocument.cpp | 100 ++++++++++---- .../Source/model/jucer_ComponentDocument.h | 13 +- .../jucer_ComponentEditorCanvas.cpp | 121 +++++++++-------- .../jucer_ComponentEditorCanvas.h | 5 +- .../wrapper/AU/juce_AU_Wrapper.mm | 2 + .../wrapper/RTAS/juce_RTAS_Wrapper.cpp | 2 + .../wrapper/VST/juce_VST_Wrapper.cpp | 2 + juce_amalgamated.cpp | 124 +++++++++++++++--- juce_amalgamated.h | 51 ++++--- src/audio/midi/juce_MidiBuffer.cpp | 5 + src/audio/midi/juce_MidiBuffer.h | 6 + .../plugins/formats/juce_VSTPluginFormat.cpp | 2 +- src/containers/juce_ValueTree.cpp | 117 ++++++++++++++--- src/containers/juce_ValueTree.h | 64 ++++++--- 14 files changed, 445 insertions(+), 169 deletions(-) diff --git a/extras/Jucer (experimental)/Source/model/jucer_ComponentDocument.cpp b/extras/Jucer (experimental)/Source/model/jucer_ComponentDocument.cpp index ce1a5db8e3..fb75cd32c8 100644 --- a/extras/Jucer (experimental)/Source/model/jucer_ComponentDocument.cpp +++ b/extras/Jucer (experimental)/Source/model/jucer_ComponentDocument.cpp @@ -282,16 +282,12 @@ const ValueTree ComponentDocument::getComponent (int index) const const ValueTree ComponentDocument::getComponentWithMemberName (const String& name) const { - const ValueTree comps (getComponentGroup()); - - for (int i = comps.getNumChildren(); --i >= 0;) - { - const ValueTree v (comps.getChild(i)); - if (v [memberNameProperty] == name) - return v; - } + return getComponentGroup().getChildWithProperty (memberNameProperty, name); +} - return ValueTree::invalid; +const ValueTree ComponentDocument::getComponentWithID (const String& uid) const +{ + return getComponentGroup().getChildWithProperty (idProperty, uid); } Component* ComponentDocument::createComponent (int index) @@ -301,8 +297,8 @@ Component* ComponentDocument::createComponent (int index) if (v.isValid()) { Component* c = ComponentTypeManager::getInstance()->createFromStoredType (*this, v); - c->getProperties().set (idProperty, v[idProperty]); - jassert (c->getProperties()[idProperty].toString().isNotEmpty()); + c->getProperties().set (jucerIDProperty, v[idProperty]); + jassert (getJucerIDFor (c).isNotEmpty()); return c; } @@ -490,25 +486,11 @@ const ValueTree ComponentDocument::getComponentState (Component* comp) const return ValueTree::invalid; } -void ComponentDocument::getComponentProperties (Array & props, Component* comp) -{ - ValueTree v (getComponentState (comp)); - - if (v.isValid()) - { - ComponentTypeHandler* handler = ComponentTypeManager::getInstance()->getHandlerFor (v.getType()); - jassert (handler != 0); - - if (handler != 0) - handler->createPropertyEditors (*this, v, props); - } -} - bool ComponentDocument::isStateForComponent (const ValueTree& storedState, Component* comp) const { jassert (comp != 0); jassert (! storedState [idProperty].isVoid()); - return storedState [idProperty] == comp->getProperties() [idProperty]; + return storedState [idProperty] == getJucerIDFor (comp); } void ComponentDocument::removeComponent (const ValueTree& state) @@ -594,6 +576,7 @@ void ComponentDocument::MarkerList::createMarker (const String& name, int positi ValueTree marker (markerTag); marker.setProperty (markerNameProperty, document.getNonexistentMarkerName (name), 0); marker.setProperty (markerPosProperty, Coordinate (position, isX).toString(), 0); + marker.setProperty (idProperty, createAlphaNumericUID(), 0); group.addChild (marker, -1, document.getUndoManager()); } @@ -617,6 +600,24 @@ const Coordinate ComponentDocument::MarkerList::findMarker (const String& name, return Coordinate (isX); } +void ComponentDocument::MarkerList::createMarkerProperties (Array & props, ValueTree& marker) +{ + props.add (new TextPropertyComponent (getNameAsValue (marker), "Marker Name", 256, false)); +} + +bool ComponentDocument::MarkerList::createProperties (Array & props, const String& itemId) +{ + ValueTree marker (group.getChildWithProperty (idProperty, itemId)); + + if (marker.isValid()) + { + createMarkerProperties (props, marker); + return true; + } + + return false; +} + const String ComponentDocument::getNonexistentMarkerName (const String& name) { String n (makeValidCppIdentifier (name, false, true, false)); @@ -628,12 +629,59 @@ const String ComponentDocument::getNonexistentMarkerName (const String& name) return n; } +//============================================================================== +bool ComponentDocument::createItemProperties (Array & props, const String& itemId) +{ + ValueTree comp (getComponentWithID (itemId)); + + if (comp.isValid()) + { + ComponentTypeHandler* handler = ComponentTypeManager::getInstance()->getHandlerFor (comp.getType()); + jassert (handler != 0); + + if (handler != 0) + handler->createPropertyEditors (*this, comp, props); + + return true; + } + + if (markersX->createProperties (props, itemId) + || markersY->createProperties (props, itemId)) + return true; + + return false; +} + +void ComponentDocument::createItemProperties (Array & props, const StringArray& selectedItemIds) +{ + if (selectedItemIds.size() != 1) + return; //xxx + + for (int i = 0; i < selectedItemIds.size(); ++i) + createItemProperties (props, selectedItemIds[i]); +} + //============================================================================== UndoManager* ComponentDocument::getUndoManager() const { return &undoManager; } +//============================================================================== +const char* const ComponentDocument::jucerIDProperty = "jucerID"; + +const String ComponentDocument::getJucerIDFor (Component* c) +{ + if (c == 0) + { + jassertfalse; + return String::empty; + } + + jassert (c->getProperties().contains (jucerIDProperty)); + return c->getProperties() [jucerIDProperty]; +} + //============================================================================== void ComponentDocument::createClassProperties (Array & props) { diff --git a/extras/Jucer (experimental)/Source/model/jucer_ComponentDocument.h b/extras/Jucer (experimental)/Source/model/jucer_ComponentDocument.h index 539d4083f3..0077f98933 100644 --- a/extras/Jucer (experimental)/Source/model/jucer_ComponentDocument.h +++ b/extras/Jucer (experimental)/Source/model/jucer_ComponentDocument.h @@ -61,11 +61,11 @@ public: int getNumComponents() const; const ValueTree getComponent (int index) const; const ValueTree getComponentWithMemberName (const String& name) const; + const ValueTree getComponentWithID (const String& uid) const; Component* createComponent (int index); void updateComponent (Component* comp); bool containsComponent (Component* comp) const; const ValueTree getComponentState (Component* comp) const; - void getComponentProperties (Array & props, Component* comp); bool isStateForComponent (const ValueTree& storedState, Component* comp) const; void removeComponent (const ValueTree& state); const RectangleCoordinates getCoordsFor (const ValueTree& componentState) const; @@ -102,6 +102,9 @@ public: // for Coordinate::MarkerResolver: const Coordinate findMarker (const String& name, bool isHorizontal) const; + bool createProperties (Array & props, const String& itemId); + void createMarkerProperties (Array & props, ValueTree& marker); + private: ComponentDocument& document; ValueTree group; @@ -117,6 +120,9 @@ public: const String getNonexistentMarkerName (const String& name); + //============================================================================== + void createItemProperties (Array & props, const StringArray& selectedItemIds); + //============================================================================== void beginDrag (const Array& items, const MouseEvent& e, Component* parentForOverlays, const ResizableBorderComponent::Zone& zone); @@ -139,6 +145,9 @@ public: static const char* const markerNameProperty; static const char* const markerPosProperty; + static const char* const jucerIDProperty; + static const String getJucerIDFor (Component* c); + private: Project* project; File cppFile; @@ -158,6 +167,8 @@ private: void writeCode (OutputStream& cpp, OutputStream& header); void writeMetadata (OutputStream& out); + + bool createItemProperties (Array & props, const String& itemId); }; diff --git a/extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditorCanvas.cpp b/extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditorCanvas.cpp index e38dd4fbef..1baadb2c35 100644 --- a/extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditorCanvas.cpp +++ b/extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditorCanvas.cpp @@ -104,7 +104,7 @@ public: setBoundsInTargetSpace (component->getBounds().expanded (borderThickness, borderThickness)); } - uint32 getTargetComponentUID() const { return component == 0 ? 0 : component->getComponentUID(); } + const String getTargetComponentID() const { return component == 0 ? String::empty : ComponentDocument::getJucerIDFor (component); } //============================================================================== class SizeGuideComponent : public OverlayItemComponent, @@ -300,6 +300,8 @@ public: toFront (false); updateLabel(); + canvas.getSelection().selectOnly (marker [ComponentDocument::idProperty]); + if (e.mods.isPopupMenu()) { isDragging = false; @@ -394,7 +396,7 @@ public: if (! doc.containsComponent (c)) { - selection.deselect (c->getComponentUID()); + selection.deselect (ComponentDocument::getJucerIDFor (c)); delete c; } } @@ -418,11 +420,16 @@ public: } // Make sure the z-order is correct.. - for (i = 0; i < num - 1; ++i) - componentsInOrder.getUnchecked(i)->toBehind (componentsInOrder.getUnchecked (i + 1)); + if (num > 0) + { + componentsInOrder.getLast()->toFront (false); + + for (i = num - 1; --i >= 0;) + componentsInOrder.getUnchecked(i)->toBehind (componentsInOrder.getUnchecked (i + 1)); + } } - Component* getComponentForState (ComponentDocument& doc, const ValueTree& state) + Component* getComponentForState (ComponentDocument& doc, const ValueTree& state) const { for (int i = getNumChildComponents(); --i >= 0;) { @@ -435,6 +442,19 @@ public: return 0; } + Component* findComponentWithID (const String& uid) const + { + for (int i = getNumChildComponents(); --i >= 0;) + { + Component* const c = getChildComponent(i); + + if (ComponentDocument::getJucerIDFor (c) == uid) + return c; + } + + return 0; + } + Component* findComponentAt (const Point& pos) const { for (int i = getNumChildComponents(); --i >= 0;) @@ -453,7 +473,7 @@ public: { Component* c = getChildComponent(i); if (c->getBounds().intersects (lassoArea)) - itemsFound.add (c->getComponentUID()); + itemsFound.add (ComponentDocument::getJucerIDFor (c)); } } }; @@ -493,7 +513,7 @@ public: void mouseDown (const MouseEvent& e) { lasso = 0; - mouseDownCompUID = 0; + mouseDownCompUID = String::empty; isDraggingClickedComp = false; Component* underMouse = canvas.getComponentHolder()->findComponentAt (e.getEventRelativeTo (canvas.getComponentHolder()).getPosition()); @@ -502,8 +522,8 @@ public: { if (underMouse != 0) { - if (! canvas.getSelection().isSelected (underMouse->getComponentUID())) - canvas.getSelection().selectOnly (underMouse->getComponentUID()); + if (! canvas.getSelection().isSelected (ComponentDocument::getJucerIDFor (underMouse))) + canvas.getSelection().selectOnly (ComponentDocument::getJucerIDFor (underMouse)); } PopupMenu m; @@ -528,12 +548,14 @@ public: { if (underMouse == 0 || e.mods.isAltDown()) { + canvas.deselectNonComponents(); addAndMakeVisible (lasso = new LassoComponent ()); lasso->beginLasso (e, this); } else { - mouseDownCompUID = underMouse->getComponentUID(); + mouseDownCompUID = ComponentDocument::getJucerIDFor (underMouse); + canvas.deselectNonComponents(); mouseDownResult = canvas.getSelection().addToSelectionOnMouseDown (mouseDownCompUID, e.mods); updateResizeFrames(); @@ -549,7 +571,7 @@ public: { lasso->dragLasso (e); } - else if (mouseDownCompUID != 0 && (! e.mouseWasClicked()) && (! e.mods.isPopupMenu())) + else if (mouseDownCompUID.isNotEmpty() && (! e.mouseWasClicked()) && (! e.mods.isPopupMenu())) { if (! isDraggingClickedComp) { @@ -653,40 +675,24 @@ private: ValueTree markerRootX, markerRootY; ScopedPointer > lasso; bool mouseDownResult, isDraggingClickedComp; - uint32 mouseDownCompUID; + SelectedItems::ItemType mouseDownCompUID; ComponentDocument& getDocument() { return canvas.getDocument(); } - Component* getComponentWithUID (const uint32 uid) const - { - for (int i = canvas.getComponentHolder()->getNumChildComponents(); --i >= 0;) - { - Component* c = canvas.getComponentHolder()->getChildComponent(i); - - if (c->getComponentUID() == uid) - return c; - } - - return 0; - } - void updateResizeFrames() { SelectedItems& selection = canvas.getSelection(); + StringArray requiredIds (canvas.getSelectedIds()); - Array requiredIds; int i; - for (i = selection.getNumSelected(); --i >= 0;) - requiredIds.add (selection.getSelectedItem(i)); - for (i = getNumChildComponents(); --i >= 0;) { ComponentResizeFrame* resizer = dynamic_cast (getChildComponent(i)); if (resizer != 0) { - if (selection.isSelected (resizer->getTargetComponentUID())) - requiredIds.removeValue (resizer->getTargetComponentUID()); + if (selection.isSelected (resizer->getTargetComponentID())) + requiredIds.removeString (resizer->getTargetComponentID()); else delete resizer; } @@ -694,7 +700,7 @@ private: for (i = requiredIds.size(); --i >= 0;) { - Component* c = getComponentWithUID (requiredIds.getUnchecked(i)); + Component* c = canvas.getComponentHolder()->findComponentWithID (requiredIds[i]); if (c != 0) { @@ -951,16 +957,19 @@ void ComponentEditorCanvas::updateComponents() } //============================================================================== -void ComponentEditorCanvas::getSelectedItemProperties (Array & props) +const StringArray ComponentEditorCanvas::getSelectedIds() const { - //xxx needs to handle multiple selections.. + StringArray ids; + const int num = selection.getNumSelected(); + for (int i = 0; i < num; ++i) + ids.add (selection.getSelectedItem(i)); - if (selection.getNumSelected() == 1) - { - Component* c = getComponentForUID (selection.getSelectedItem (0)); - jassert (c != 0); - getDocument().getComponentProperties (props, c); - } + return ids; +} + +void ComponentEditorCanvas::getSelectedItemProperties (Array & props) +{ + getDocument().createItemProperties (props, getSelectedIds()); } void ComponentEditorCanvas::deleteSelection() @@ -969,7 +978,7 @@ void ComponentEditorCanvas::deleteSelection() for (int i = selection.getNumSelected(); --i >= 0;) { - Component* c = getComponentForUID (selection.getSelectedItem (0)); + Component* c = componentHolder->findComponentWithID (selection.getSelectedItem (0)); if (c != 0) getDocument().removeComponent (getDocument().getComponentState (c)); @@ -980,6 +989,13 @@ void ComponentEditorCanvas::deleteSelection() getDocument().beginNewTransaction(); } +void ComponentEditorCanvas::deselectNonComponents() +{ + for (int i = getSelection().getNumSelected(); --i >= 0;) + if (! getDocument().getComponentWithID (getSelection().getSelectedItem (i)).isValid()) + getSelection().deselect (getSelection().getSelectedItem (i)); +} + void ComponentEditorCanvas::selectionToFront() { getDocument().beginNewTransaction(); @@ -990,11 +1006,10 @@ void ComponentEditorCanvas::selectionToFront() const ValueTree comp (getDocument().getComponent (index)); Component* c = componentHolder->getComponentForState (getDocument(), comp); - if (c != 0 && selection.isSelected (c->getComponentUID())) + if (c != 0 && selection.isSelected (ComponentDocument::getJucerIDFor (c))) { ValueTree parent (comp.getParent()); - parent.removeChild (comp, getDocument().getUndoManager()); - parent.addChild (comp, -1, getDocument().getUndoManager()); + parent.moveChild (parent.indexOf (comp), -1, getDocument().getUndoManager()); } else { @@ -1015,11 +1030,10 @@ void ComponentEditorCanvas::selectionToBack() const ValueTree comp (getDocument().getComponent (index)); Component* c = componentHolder->getComponentForState (getDocument(), comp); - if (c != 0 && selection.isSelected (c->getComponentUID())) + if (c != 0 && selection.isSelected (ComponentDocument::getJucerIDFor (c))) { ValueTree parent (comp.getParent()); - parent.removeChild (comp, getDocument().getUndoManager()); - parent.addChild (comp, 0, getDocument().getUndoManager()); + parent.moveChild (parent.indexOf (comp), 0, getDocument().getUndoManager()); } else { @@ -1036,22 +1050,13 @@ void ComponentEditorCanvas::hideSizeGuides() { overlay->hideSizeGuides(); } //============================================================================== -Component* ComponentEditorCanvas::getComponentForUID (const uint32 uid) const -{ - for (int i = componentHolder->getNumChildComponents(); --i >= 0;) - if (componentHolder->getChildComponent (i)->getComponentUID() == uid) - return componentHolder->getChildComponent (i); - - return 0; -} - const Array ComponentEditorCanvas::getSelectedComps() const { Array comps; for (int i = 0; i < selection.getNumSelected(); ++i) { - Component* c = getComponentForUID (selection.getSelectedItem (i)); + Component* c = componentHolder->findComponentWithID (selection.getSelectedItem (i)); jassert (c != 0); if (c != 0) comps.add (c); @@ -1065,7 +1070,7 @@ const Array ComponentEditorCanvas::getUnselectedComps() const Array comps; for (int i = componentHolder->getNumChildComponents(); --i >= 0;) - if (! selection.isSelected (componentHolder->getChildComponent(i)->getComponentUID())) + if (! selection.isSelected (ComponentDocument::getJucerIDFor (componentHolder->getChildComponent(i)))) comps.add (componentHolder->getChildComponent(i)); return comps; diff --git a/extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditorCanvas.h b/extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditorCanvas.h index 5900a476be..7d90fc493b 100644 --- a/extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditorCanvas.h +++ b/extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditorCanvas.h @@ -45,7 +45,7 @@ public: ComponentEditor& getEditor(); ComponentDocument& getDocument(); - typedef SelectedItemSet SelectedItems; + typedef SelectedItemSet SelectedItems; SelectedItems& getSelection(); class ComponentHolder; @@ -67,8 +67,10 @@ public: void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged) {} //============================================================================== + const StringArray getSelectedIds() const; void getSelectedItemProperties (Array & props); void deleteSelection(); + void deselectNonComponents(); void selectionToFront(); void selectionToBack(); @@ -114,7 +116,6 @@ private: WholeComponentResizer* resizeFrame; SelectedItems selection; - Component* getComponentForUID (const uint32 uid) const; const Array getSelectedComps() const; const Array getUnselectedComps() const; }; diff --git a/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm b/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm index 3b9ac11e82..2b237ffc3c 100644 --- a/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm +++ b/extras/audio plugins/wrapper/AU/juce_AU_Wrapper.mm @@ -654,7 +654,9 @@ public: juceFilter->prepareToPlay (GetSampleRate(), GetMaxFramesPerSlice()); + midiEvents.ensureSize (2048); midiEvents.clear(); + incomingEvents.ensureSize (2048); incomingEvents.clear(); channels.calloc (jmax (juceFilter->getNumInputChannels(), diff --git a/extras/audio plugins/wrapper/RTAS/juce_RTAS_Wrapper.cpp b/extras/audio plugins/wrapper/RTAS/juce_RTAS_Wrapper.cpp index e1bd8784d4..9e1d135524 100644 --- a/extras/audio plugins/wrapper/RTAS/juce_RTAS_Wrapper.cpp +++ b/extras/audio plugins/wrapper/RTAS/juce_RTAS_Wrapper.cpp @@ -506,6 +506,8 @@ protected: juceFilter->setPlayHead (this); juceFilter->addListener (this); + + midiEvents.ensureSize (2048); } void handleAsyncUpdate() diff --git a/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp b/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp index 51c1b13caa..82246b3dea 100644 --- a/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp +++ b/extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp @@ -779,6 +779,8 @@ public: deleteTempChannels(); filter->prepareToPlay (rate, blockSize); + + midiEvents.ensureSize (2048); midiEvents.clear(); setInitialDelay (filter->getLatencySamples()); diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index a96c03850a..77c5cd3908 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -15704,11 +15704,11 @@ END_JUCE_NAMESPACE /*** Start of inlined file: juce_ValueTree.cpp ***/ BEGIN_JUCE_NAMESPACE -class ValueTreeSetPropertyAction : public UndoableAction +class ValueTree::SetPropertyAction : public UndoableAction { public: - ValueTreeSetPropertyAction (const ValueTree::SharedObjectPtr& target_, const var::identifier& name_, - const var& newValue_, const bool isAddingNewProperty_, const bool isDeletingProperty_) + SetPropertyAction (const SharedObjectPtr& target_, const var::identifier& name_, + const var& newValue_, const bool isAddingNewProperty_, const bool isDeletingProperty_) : target (target_), name (name_), newValue (newValue_), isAddingNewProperty (isAddingNewProperty_), isDeletingProperty (isDeletingProperty_) @@ -15717,7 +15717,7 @@ public: oldValue = target_->getProperty (name_); } - ~ValueTreeSetPropertyAction() {} + ~SetPropertyAction() {} bool perform() { @@ -15747,21 +15747,21 @@ public: } private: - const ValueTree::SharedObjectPtr target; + const SharedObjectPtr target; const var::identifier name; const var newValue; var oldValue; const bool isAddingNewProperty, isDeletingProperty; - ValueTreeSetPropertyAction (const ValueTreeSetPropertyAction&); - ValueTreeSetPropertyAction& operator= (const ValueTreeSetPropertyAction&); + SetPropertyAction (const SetPropertyAction&); + SetPropertyAction& operator= (const SetPropertyAction&); }; -class ValueTreeChildChangeAction : public UndoableAction +class ValueTree::AddOrRemoveChildAction : public UndoableAction { public: - ValueTreeChildChangeAction (const ValueTree::SharedObjectPtr& target_, const int childIndex_, - const ValueTree::SharedObjectPtr& newChild_) + AddOrRemoveChildAction (const SharedObjectPtr& target_, const int childIndex_, + const SharedObjectPtr& newChild_) : target (target_), child (newChild_ != 0 ? newChild_ : target_->children [childIndex_]), childIndex (childIndex_), @@ -15770,7 +15770,7 @@ public: jassert (child != 0); } - ~ValueTreeChildChangeAction() {} + ~AddOrRemoveChildAction() {} bool perform() { @@ -15805,12 +15805,50 @@ public: } private: - const ValueTree::SharedObjectPtr target, child; + const SharedObjectPtr target, child; const int childIndex; const bool isDeleting; - ValueTreeChildChangeAction (const ValueTreeChildChangeAction&); - ValueTreeChildChangeAction& operator= (const ValueTreeChildChangeAction&); + AddOrRemoveChildAction (const AddOrRemoveChildAction&); + AddOrRemoveChildAction& operator= (const AddOrRemoveChildAction&); +}; + +class ValueTree::MoveChildAction : public UndoableAction +{ +public: + MoveChildAction (const SharedObjectPtr& target_, + const int startIndex_, const int endIndex_) + : target (target_), + startIndex (startIndex_), + endIndex (endIndex_) + { + } + + ~MoveChildAction() {} + + bool perform() + { + target->moveChild (startIndex, endIndex, 0); + return true; + } + + bool undo() + { + target->moveChild (endIndex, startIndex, 0); + return true; + } + + int getSizeInUnits() + { + return (int) sizeof (*this); //xxx should be more accurate + } + +private: + const SharedObjectPtr target, child; + const int startIndex, endIndex; + + MoveChildAction (const MoveChildAction&); + MoveChildAction& operator= (const MoveChildAction&); }; ValueTree::SharedObject::SharedObject (const String& type_) @@ -15926,11 +15964,11 @@ void ValueTree::SharedObject::setProperty (const var::identifier& name, const va if (existingValue != 0) { if (*existingValue != newValue) - undoManager->perform (new ValueTreeSetPropertyAction (this, name, newValue, false, false)); + undoManager->perform (new SetPropertyAction (this, name, newValue, false, false)); } else { - undoManager->perform (new ValueTreeSetPropertyAction (this, name, newValue, true, false)); + undoManager->perform (new SetPropertyAction (this, name, newValue, true, false)); } } } @@ -15950,7 +15988,7 @@ void ValueTree::SharedObject::removeProperty (const var::identifier& name, UndoM else { if (properties.contains (name)) - undoManager->perform (new ValueTreeSetPropertyAction (this, name, var::null, false, true)); + undoManager->perform (new SetPropertyAction (this, name, var::null, false, true)); } } @@ -15968,7 +16006,7 @@ void ValueTree::SharedObject::removeAllProperties (UndoManager* const undoManage else { for (int i = properties.size(); --i >= 0;) - undoManager->perform (new ValueTreeSetPropertyAction (this, properties.getName(i), var::null, false, true)); + undoManager->perform (new SetPropertyAction (this, properties.getName(i), var::null, false, true)); } } @@ -16005,6 +16043,11 @@ bool ValueTree::SharedObject::isAChildOf (const SharedObject* const possiblePare return false; } +int ValueTree::SharedObject::indexOf (const ValueTree& child) const +{ + return children.indexOf (child.object); +} + void ValueTree::SharedObject::addChild (SharedObject* child, int index, UndoManager* const undoManager) { if (child != 0 && child->parent != this) @@ -16034,7 +16077,7 @@ void ValueTree::SharedObject::addChild (SharedObject* child, int index, UndoMana if (index < 0) index = children.size(); - undoManager->perform (new ValueTreeChildChangeAction (this, index, child)); + undoManager->perform (new AddOrRemoveChildAction (this, index, child)); } } else @@ -16061,7 +16104,7 @@ void ValueTree::SharedObject::removeChild (const int childIndex, UndoManager* co } else { - undoManager->perform (new ValueTreeChildChangeAction (this, childIndex, 0)); + undoManager->perform (new AddOrRemoveChildAction (this, childIndex, 0)); } } } @@ -16072,6 +16115,29 @@ void ValueTree::SharedObject::removeAllChildren (UndoManager* const undoManager) removeChild (children.size() - 1, undoManager); } +void ValueTree::SharedObject::moveChild (int currentIndex, int newIndex, UndoManager* undoManager) +{ + // The source index must be a valid index! + jassert (((unsigned int) currentIndex) < (unsigned int) children.size()); + + if (currentIndex != newIndex + && ((unsigned int) currentIndex) < (unsigned int) children.size()) + { + if (undoManager == 0) + { + children.move (currentIndex, newIndex); + sendChildChangeMessage(); + } + else + { + if (((unsigned int) newIndex) >= (unsigned int) children.size()) + newIndex = children.size() - 1; + + undoManager->perform (new MoveChildAction (this, currentIndex, newIndex)); + } + } +} + ValueTree::ValueTree() throw() : object (0) { @@ -16274,6 +16340,11 @@ bool ValueTree::isAChildOf (const ValueTree& possibleParent) const return object != 0 && object->isAChildOf (possibleParent.object); } +int ValueTree::indexOf (const ValueTree& child) const +{ + return object != 0 ? object->indexOf (child) : -1; +} + void ValueTree::addChild (ValueTree child, int index, UndoManager* const undoManager) { if (object != 0) @@ -16298,6 +16369,12 @@ void ValueTree::removeAllChildren (UndoManager* const undoManager) object->removeAllChildren (undoManager); } +void ValueTree::moveChild (int currentIndex, int newIndex, UndoManager* undoManager) +{ + if (object != 0) + object->moveChild (currentIndex, newIndex, undoManager); +} + void ValueTree::addListener (Listener* listener) { if (listener != 0) @@ -26435,6 +26512,11 @@ void MidiBuffer::addEvents (const MidiBuffer& otherBuffer, } } +void MidiBuffer::ensureSize (size_t minimumNumBytes) +{ + data.ensureSize (minimumNumBytes); +} + bool MidiBuffer::isEmpty() const throw() { return bytesUsed == 0; @@ -32340,7 +32422,7 @@ void VSTPluginInstance::processBlock (AudioSampleBuffer& buffer, // copy any incoming midi.. const ScopedLock sl (midiInLock); - midiMessages = incomingMidi; + midiMessages.swapWith (incomingMidi); incomingMidi.clear(); } } diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 34ee78c3ac..29aa1408b8 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -6726,19 +6726,19 @@ public: const var& operator[] (const var::identifier& name) const; - void setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager); + void setProperty (const var::identifier& name, const var& newValue, UndoManager* undoManager); bool hasProperty (const var::identifier& name) const; - void removeProperty (const var::identifier& name, UndoManager* const undoManager); + void removeProperty (const var::identifier& name, UndoManager* undoManager); - void removeAllProperties (UndoManager* const undoManager); + void removeAllProperties (UndoManager* undoManager); int getNumProperties() const; const var::identifier getPropertyName (int index) const; - Value getPropertyAsValue (const var::identifier& name, UndoManager* const undoManager) const; + Value getPropertyAsValue (const var::identifier& name, UndoManager* undoManager) const; int getNumChildren() const; @@ -6748,16 +6748,20 @@ public: ValueTree getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const; - void addChild (ValueTree child, int index, UndoManager* const undoManager); + void addChild (ValueTree child, int index, UndoManager* undoManager); - void removeChild (const ValueTree& child, UndoManager* const undoManager); + void removeChild (const ValueTree& child, UndoManager* undoManager); - void removeChild (const int childIndex, UndoManager* const undoManager); + void removeChild (int childIndex, UndoManager* undoManager); - void removeAllChildren (UndoManager* const undoManager); + void removeAllChildren (UndoManager* undoManager); + + void moveChild (int currentIndex, int newIndex, UndoManager* undoManager); bool isAChildOf (const ValueTree& possibleParent) const; + int indexOf (const ValueTree& child) const; + ValueTree getParent() const; XmlElement* createXml() const; @@ -6801,8 +6805,12 @@ public: juce_UseDebuggingNewOperator private: - friend class ValueTreeSetPropertyAction; - friend class ValueTreeChildChangeAction; + class SetPropertyAction; + friend class SetPropertyAction; + class AddOrRemoveChildAction; + friend class AddOrRemoveChildAction; + class MoveChildAction; + friend class MoveChildAction; class JUCE_API SharedObject : public ReferenceCountedObject { @@ -6824,16 +6832,18 @@ private: void sendParentChangeMessage(); const var& getProperty (const var::identifier& name) const; const var getProperty (const var::identifier& name, const var& defaultReturnValue) const; - void setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager); + void setProperty (const var::identifier& name, const var& newValue, UndoManager*); bool hasProperty (const var::identifier& name) const; - void removeProperty (const var::identifier& name, UndoManager* const undoManager); - void removeAllProperties (UndoManager* const undoManager); - bool isAChildOf (const SharedObject* const possibleParent) const; + void removeProperty (const var::identifier& name, UndoManager*); + void removeAllProperties (UndoManager*); + bool isAChildOf (const SharedObject* possibleParent) const; + int indexOf (const ValueTree& child) const; ValueTree getChildWithName (const String& type) const; ValueTree getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const; - void addChild (SharedObject* child, int index, UndoManager* const undoManager); - void removeChild (const int childIndex, UndoManager* const undoManager); - void removeAllChildren (UndoManager* const undoManager); + void addChild (SharedObject* child, int index, UndoManager*); + void removeChild (int childIndex, UndoManager*); + void removeAllChildren (UndoManager*); + void moveChild (int currentIndex, int newIndex, UndoManager*); XmlElement* createXml() const; juce_UseDebuggingNewOperator @@ -6861,14 +6871,13 @@ private: }; friend class SharedObject; - typedef ReferenceCountedObjectPtr SharedObjectPtr; - ReferenceCountedObjectPtr object; + SharedObjectPtr object; ListenerList listeners; public: - explicit ValueTree (SharedObject* const object_); // (can be made private when VC6 support is finally dropped) + explicit ValueTree (SharedObject*); // (can be made private when VC6 support is finally dropped) }; #endif // __JUCE_VALUETREE_JUCEHEADER__ @@ -15723,6 +15732,8 @@ public: void swapWith (MidiBuffer& other); + void ensureSize (size_t minimumNumBytes); + class Iterator { public: diff --git a/src/audio/midi/juce_MidiBuffer.cpp b/src/audio/midi/juce_MidiBuffer.cpp index 09ecaa4537..75638d06b6 100644 --- a/src/audio/midi/juce_MidiBuffer.cpp +++ b/src/audio/midi/juce_MidiBuffer.cpp @@ -191,6 +191,11 @@ void MidiBuffer::addEvents (const MidiBuffer& otherBuffer, } } +void MidiBuffer::ensureSize (size_t minimumNumBytes) +{ + data.ensureSize (minimumNumBytes); +} + bool MidiBuffer::isEmpty() const throw() { return bytesUsed == 0; diff --git a/src/audio/midi/juce_MidiBuffer.h b/src/audio/midi/juce_MidiBuffer.h index 88901b44ee..4b256b67af 100644 --- a/src/audio/midi/juce_MidiBuffer.h +++ b/src/audio/midi/juce_MidiBuffer.h @@ -157,6 +157,12 @@ public: */ void swapWith (MidiBuffer& other); + /** Preallocates some memory for the buffer to use. + This helps to avoid needing to reallocate space when the buffer has messages + added to it. + */ + void ensureSize (size_t minimumNumBytes); + //============================================================================== /** Used to iterate through the events in a MidiBuffer. diff --git a/src/audio/plugins/formats/juce_VSTPluginFormat.cpp b/src/audio/plugins/formats/juce_VSTPluginFormat.cpp index 752fab17b7..f2f81e20fe 100644 --- a/src/audio/plugins/formats/juce_VSTPluginFormat.cpp +++ b/src/audio/plugins/formats/juce_VSTPluginFormat.cpp @@ -1140,7 +1140,7 @@ void VSTPluginInstance::processBlock (AudioSampleBuffer& buffer, // copy any incoming midi.. const ScopedLock sl (midiInLock); - midiMessages = incomingMidi; + midiMessages.swapWith (incomingMidi); incomingMidi.clear(); } } diff --git a/src/containers/juce_ValueTree.cpp b/src/containers/juce_ValueTree.cpp index 2714f96903..1974fc256e 100644 --- a/src/containers/juce_ValueTree.cpp +++ b/src/containers/juce_ValueTree.cpp @@ -31,11 +31,11 @@ BEGIN_JUCE_NAMESPACE //============================================================================== -class ValueTreeSetPropertyAction : public UndoableAction +class ValueTree::SetPropertyAction : public UndoableAction { public: - ValueTreeSetPropertyAction (const ValueTree::SharedObjectPtr& target_, const var::identifier& name_, - const var& newValue_, const bool isAddingNewProperty_, const bool isDeletingProperty_) + SetPropertyAction (const SharedObjectPtr& target_, const var::identifier& name_, + const var& newValue_, const bool isAddingNewProperty_, const bool isDeletingProperty_) : target (target_), name (name_), newValue (newValue_), isAddingNewProperty (isAddingNewProperty_), isDeletingProperty (isDeletingProperty_) @@ -44,7 +44,7 @@ public: oldValue = target_->getProperty (name_); } - ~ValueTreeSetPropertyAction() {} + ~SetPropertyAction() {} bool perform() { @@ -74,22 +74,22 @@ public: } private: - const ValueTree::SharedObjectPtr target; + const SharedObjectPtr target; const var::identifier name; const var newValue; var oldValue; const bool isAddingNewProperty, isDeletingProperty; - ValueTreeSetPropertyAction (const ValueTreeSetPropertyAction&); - ValueTreeSetPropertyAction& operator= (const ValueTreeSetPropertyAction&); + SetPropertyAction (const SetPropertyAction&); + SetPropertyAction& operator= (const SetPropertyAction&); }; //============================================================================== -class ValueTreeChildChangeAction : public UndoableAction +class ValueTree::AddOrRemoveChildAction : public UndoableAction { public: - ValueTreeChildChangeAction (const ValueTree::SharedObjectPtr& target_, const int childIndex_, - const ValueTree::SharedObjectPtr& newChild_) + AddOrRemoveChildAction (const SharedObjectPtr& target_, const int childIndex_, + const SharedObjectPtr& newChild_) : target (target_), child (newChild_ != 0 ? newChild_ : target_->children [childIndex_]), childIndex (childIndex_), @@ -98,7 +98,7 @@ public: jassert (child != 0); } - ~ValueTreeChildChangeAction() {} + ~AddOrRemoveChildAction() {} bool perform() { @@ -133,12 +133,51 @@ public: } private: - const ValueTree::SharedObjectPtr target, child; + const SharedObjectPtr target, child; const int childIndex; const bool isDeleting; - ValueTreeChildChangeAction (const ValueTreeChildChangeAction&); - ValueTreeChildChangeAction& operator= (const ValueTreeChildChangeAction&); + AddOrRemoveChildAction (const AddOrRemoveChildAction&); + AddOrRemoveChildAction& operator= (const AddOrRemoveChildAction&); +}; + +//============================================================================== +class ValueTree::MoveChildAction : public UndoableAction +{ +public: + MoveChildAction (const SharedObjectPtr& target_, + const int startIndex_, const int endIndex_) + : target (target_), + startIndex (startIndex_), + endIndex (endIndex_) + { + } + + ~MoveChildAction() {} + + bool perform() + { + target->moveChild (startIndex, endIndex, 0); + return true; + } + + bool undo() + { + target->moveChild (endIndex, startIndex, 0); + return true; + } + + int getSizeInUnits() + { + return (int) sizeof (*this); //xxx should be more accurate + } + +private: + const SharedObjectPtr target, child; + const int startIndex, endIndex; + + MoveChildAction (const MoveChildAction&); + MoveChildAction& operator= (const MoveChildAction&); }; @@ -258,11 +297,11 @@ void ValueTree::SharedObject::setProperty (const var::identifier& name, const va if (existingValue != 0) { if (*existingValue != newValue) - undoManager->perform (new ValueTreeSetPropertyAction (this, name, newValue, false, false)); + undoManager->perform (new SetPropertyAction (this, name, newValue, false, false)); } else { - undoManager->perform (new ValueTreeSetPropertyAction (this, name, newValue, true, false)); + undoManager->perform (new SetPropertyAction (this, name, newValue, true, false)); } } } @@ -282,7 +321,7 @@ void ValueTree::SharedObject::removeProperty (const var::identifier& name, UndoM else { if (properties.contains (name)) - undoManager->perform (new ValueTreeSetPropertyAction (this, name, var::null, false, true)); + undoManager->perform (new SetPropertyAction (this, name, var::null, false, true)); } } @@ -300,7 +339,7 @@ void ValueTree::SharedObject::removeAllProperties (UndoManager* const undoManage else { for (int i = properties.size(); --i >= 0;) - undoManager->perform (new ValueTreeSetPropertyAction (this, properties.getName(i), var::null, false, true)); + undoManager->perform (new SetPropertyAction (this, properties.getName(i), var::null, false, true)); } } @@ -337,6 +376,11 @@ bool ValueTree::SharedObject::isAChildOf (const SharedObject* const possiblePare return false; } +int ValueTree::SharedObject::indexOf (const ValueTree& child) const +{ + return children.indexOf (child.object); +} + void ValueTree::SharedObject::addChild (SharedObject* child, int index, UndoManager* const undoManager) { if (child != 0 && child->parent != this) @@ -366,7 +410,7 @@ void ValueTree::SharedObject::addChild (SharedObject* child, int index, UndoMana if (index < 0) index = children.size(); - undoManager->perform (new ValueTreeChildChangeAction (this, index, child)); + undoManager->perform (new AddOrRemoveChildAction (this, index, child)); } } else @@ -393,7 +437,7 @@ void ValueTree::SharedObject::removeChild (const int childIndex, UndoManager* co } else { - undoManager->perform (new ValueTreeChildChangeAction (this, childIndex, 0)); + undoManager->perform (new AddOrRemoveChildAction (this, childIndex, 0)); } } } @@ -404,6 +448,28 @@ void ValueTree::SharedObject::removeAllChildren (UndoManager* const undoManager) removeChild (children.size() - 1, undoManager); } +void ValueTree::SharedObject::moveChild (int currentIndex, int newIndex, UndoManager* undoManager) +{ + // The source index must be a valid index! + jassert (((unsigned int) currentIndex) < (unsigned int) children.size()); + + if (currentIndex != newIndex + && ((unsigned int) currentIndex) < (unsigned int) children.size()) + { + if (undoManager == 0) + { + children.move (currentIndex, newIndex); + sendChildChangeMessage(); + } + else + { + if (((unsigned int) newIndex) >= (unsigned int) children.size()) + newIndex = children.size() - 1; + + undoManager->perform (new MoveChildAction (this, currentIndex, newIndex)); + } + } +} //============================================================================== ValueTree::ValueTree() throw() @@ -610,6 +676,11 @@ bool ValueTree::isAChildOf (const ValueTree& possibleParent) const return object != 0 && object->isAChildOf (possibleParent.object); } +int ValueTree::indexOf (const ValueTree& child) const +{ + return object != 0 ? object->indexOf (child) : -1; +} + void ValueTree::addChild (ValueTree child, int index, UndoManager* const undoManager) { if (object != 0) @@ -634,6 +705,12 @@ void ValueTree::removeAllChildren (UndoManager* const undoManager) object->removeAllChildren (undoManager); } +void ValueTree::moveChild (int currentIndex, int newIndex, UndoManager* undoManager) +{ + if (object != 0) + object->moveChild (currentIndex, newIndex, undoManager); +} + //============================================================================== void ValueTree::addListener (Listener* listener) { diff --git a/src/containers/juce_ValueTree.h b/src/containers/juce_ValueTree.h index fdc0c228f1..07f212cc5f 100644 --- a/src/containers/juce_ValueTree.h +++ b/src/containers/juce_ValueTree.h @@ -159,7 +159,7 @@ public: so that this change can be undone. @see var, getProperty, removeProperty */ - void setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager); + void setProperty (const var::identifier& name, const var& newValue, UndoManager* undoManager); /** Returns true if the node contains a named property. */ bool hasProperty (const var::identifier& name) const; @@ -168,13 +168,13 @@ public: If the undoManager parameter is non-null, its UndoManager::perform() method will be used, so that this change can be undone. */ - void removeProperty (const var::identifier& name, UndoManager* const undoManager); + void removeProperty (const var::identifier& name, UndoManager* undoManager); /** Removes all properties from the node. If the undoManager parameter is non-null, its UndoManager::perform() method will be used, so that this change can be undone. */ - void removeAllProperties (UndoManager* const undoManager); + void removeAllProperties (UndoManager* undoManager); /** Returns the total number of properties that the node contains. @see getProperty. @@ -192,7 +192,7 @@ public: it needs to change the value. Attaching a Value::Listener to the value object will provide callbacks whenever the property changes. */ - Value getPropertyAsValue (const var::identifier& name, UndoManager* const undoManager) const; + Value getPropertyAsValue (const var::identifier& name, UndoManager* undoManager) const; //============================================================================== /** Returns the number of child nodes belonging to this one. @@ -233,31 +233,50 @@ public: If the undoManager parameter is non-null, its UndoManager::perform() method will be used, so that this change can be undone. */ - void addChild (ValueTree child, int index, UndoManager* const undoManager); + void addChild (ValueTree child, int index, UndoManager* undoManager); /** Removes the specified child from this node's child-list. If the undoManager parameter is non-null, its UndoManager::perform() method will be used, so that this change can be undone. */ - void removeChild (const ValueTree& child, UndoManager* const undoManager); + void removeChild (const ValueTree& child, UndoManager* undoManager); /** Removes a child from this node's child-list. If the undoManager parameter is non-null, its UndoManager::perform() method will be used, so that this change can be undone. */ - void removeChild (const int childIndex, UndoManager* const undoManager); + void removeChild (int childIndex, UndoManager* undoManager); /** Removes all child-nodes from this node. If the undoManager parameter is non-null, its UndoManager::perform() method will be used, so that this change can be undone. */ - void removeAllChildren (UndoManager* const undoManager); + void removeAllChildren (UndoManager* undoManager); + + /** Moves one of the children to a different index. + + This will move the child to a specified index, shuffling along any intervening + items as required. So for example, if you have a list of { 0, 1, 2, 3, 4, 5 }, then + calling move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }. + + @param currentIndex the index of the item to be moved. If this isn't a + valid index, then nothing will be done + @param newIndex the index at which you'd like this item to end up. If this + is less than zero, the value will be moved to the end + of the list + */ + void moveChild (int currentIndex, int newIndex, UndoManager* undoManager); /** Returns true if this node is anywhere below the specified parent node. This returns true if the node is a child-of-a-child, as well as a direct child. */ bool isAChildOf (const ValueTree& possibleParent) const; + /** Returns the index of a child item in this parent. + If the child isn't found, this returns -1. + */ + int indexOf (const ValueTree& child) const; + /** Returns the parent node that contains this one. If the node has no parent, this will return an invalid node. (See isValid() to find out whether a node is valid). @@ -403,8 +422,12 @@ public: juce_UseDebuggingNewOperator private: - friend class ValueTreeSetPropertyAction; - friend class ValueTreeChildChangeAction; + class SetPropertyAction; + friend class SetPropertyAction; + class AddOrRemoveChildAction; + friend class AddOrRemoveChildAction; + class MoveChildAction; + friend class MoveChildAction; class JUCE_API SharedObject : public ReferenceCountedObject { @@ -426,16 +449,18 @@ private: void sendParentChangeMessage(); const var& getProperty (const var::identifier& name) const; const var getProperty (const var::identifier& name, const var& defaultReturnValue) const; - void setProperty (const var::identifier& name, const var& newValue, UndoManager* const undoManager); + void setProperty (const var::identifier& name, const var& newValue, UndoManager*); bool hasProperty (const var::identifier& name) const; - void removeProperty (const var::identifier& name, UndoManager* const undoManager); - void removeAllProperties (UndoManager* const undoManager); - bool isAChildOf (const SharedObject* const possibleParent) const; + void removeProperty (const var::identifier& name, UndoManager*); + void removeAllProperties (UndoManager*); + bool isAChildOf (const SharedObject* possibleParent) const; + int indexOf (const ValueTree& child) const; ValueTree getChildWithName (const String& type) const; ValueTree getChildWithProperty (const var::identifier& propertyName, const var& propertyValue) const; - void addChild (SharedObject* child, int index, UndoManager* const undoManager); - void removeChild (const int childIndex, UndoManager* const undoManager); - void removeAllChildren (UndoManager* const undoManager); + void addChild (SharedObject* child, int index, UndoManager*); + void removeChild (int childIndex, UndoManager*); + void removeAllChildren (UndoManager*); + void moveChild (int currentIndex, int newIndex, UndoManager*); XmlElement* createXml() const; juce_UseDebuggingNewOperator @@ -463,15 +488,14 @@ private: }; friend class SharedObject; - typedef ReferenceCountedObjectPtr SharedObjectPtr; - ReferenceCountedObjectPtr object; + SharedObjectPtr object; ListenerList listeners; public: /** @internal */ - explicit ValueTree (SharedObject* const object_); // (can be made private when VC6 support is finally dropped) + explicit ValueTree (SharedObject*); // (can be made private when VC6 support is finally dropped) };