void CtrlrPanelComponentProperties::changeListenerCallback (ChangeBroadcaster* source)
{
    if (owner.getSelection() == nullptr)
        return;

	if (selectedItems != owner.getSelection()->getNumSelected() && owner.getSelection()->getNumSelected() > 1)
	{
		selectedItems = owner.getSelection()->getNumSelected();
		msTree = ValueTree(Ids::modulator);
		msTree.removeListener (this);

		for (int i=0; i<owner.getSelection()->getNumSelected(); i++)
		{
			ValueTree modTree = owner.getSelection()->getSelectedItem(i)->getOwner().getModulatorTree();

			copyProperties (modTree, msTree);

			for (int i=0; i<modTree.getNumChildren(); i++)
			{
				if (!msTree.getChildWithName(modTree.getChild(i).getType()).isValid())
					msTree.addChild (modTree.getChild(i).createCopy(), i, 0);
			}
		}

		if (msTree.getChildWithName(Ids::component).isValid())
		{
			msTree.getChildWithName(Ids::component).setProperty (Ids::uiType, "uiMultipleSelection", 0);
		}

		msTree.addListener (this);
		setTree (msTree);
	}

	if (owner.getSelection()->getNumSelected() == 0)
	{
		setTree (owner.getOwner().getPanelTree());
		propertyPanel->restoreOpennessState(panelPropertyOpennessState);
	}

	if (owner.getSelection()->getNumSelected() == 1)
	{
	    refreshTargetModulationPropertyList(owner.getSelection()->getSelectedItem(0)->getOwner().getModulatorTree());
		refreshDynamicData();
		setTree (owner.getSelection()->getSelectedItem(0)->getOwner().getModulatorTree());
		propertyPanel->restoreOpennessState(modulatorPropertyOpennessState);
	}
}
void CtrlrPanelComponentProperties::setTree (const ValueTree &_treeToEdit, const bool force)
{
	if (_treeToEdit == treeToEdit && force == false)
	{
		return;
	}

	ScopedPointer <XmlElement> xml(propertyPanel->getOpennessState());
	if (treeToEdit.hasType(Ids::panel))
	{
		panelPropertyOpennessState		= *xml;
	}
	else if (treeToEdit.hasType(Ids::modulator))
	{
		modulatorPropertyOpennessState	= *xml;
	}

	treeToEdit = _treeToEdit;

	/** Panel properties **/
	if (treeToEdit.hasType (Ids::panel))
	{
		Array <PropertyComponent*> panelProperties;
		Array <PropertyComponent*> panelEditorProperties;
		Array <PropertyComponent*> panelMidiProperties;

		for (int i=0; i<treeToEdit.getNumProperties(); i++)
		{
			if (treeToEdit.getPropertyName(i) == Ids::uiPanelImageResource)
			{
				panelProperties.add
				(
					owner.getOwner().getOwner().getIDManager().createComponentForProperty
					(	treeToEdit.getPropertyName(i),
						treeToEdit,
						&owner.getOwner(),
						&resourceList,
						&resourceList
					)
				);
			}
			else if (treeToEdit.getPropertyName(i) == Ids::panelMidiInputDevice)
			{
				panelMidiProperties.add
				(
					owner.getOwner().getOwner().getIDManager().createComponentForProperty
					(
						treeToEdit.getPropertyName(i),
						treeToEdit,
						&owner.getOwner(),
						&midiInputDevices,
						&midiInputDevices
					)
				);
			}
			else if (treeToEdit.getPropertyName(i) == Ids::panelMidiOutputDevice)
			{
				panelMidiProperties.add
				(
					owner.getOwner().getOwner().getIDManager().createComponentForProperty
					(
						treeToEdit.getPropertyName(i),
						treeToEdit,
						&owner.getOwner(),
						&midiOutputDevices,
						&midiOutputDevices
					)
				);
			}
			else if (treeToEdit.getPropertyName(i) == Ids::panelMidiControllerDevice)
			{
				panelMidiProperties.add
				(
					owner.getOwner().getOwner().getIDManager().createComponentForProperty
					(
						treeToEdit.getPropertyName(i),
						treeToEdit,
						&owner.getOwner(),
						&midiInputDevices,
						&midiInputDevices
					)
				);
			}
			else if (treeToEdit.getPropertyName(i).toString().startsWith("panelMidi"))
			{
				panelMidiProperties.add
				(
					owner.getOwner().getOwner().getIDManager().createComponentForProperty
					(
						treeToEdit.getPropertyName(i),
						treeToEdit,
						&owner.getOwner()
					)
				);
			}
			else
			{
				panelProperties.add
				(
					owner.getOwner().getOwner().getIDManager().createComponentForProperty
					(
						treeToEdit.getPropertyName(i),
						treeToEdit,
						&owner.getOwner()
					)
				);
			}
		}

		/** Panel editor properties **/
		if (treeToEdit.getChildWithName (Ids::uiPanelEditor).isValid())
		{
			for (int i=0; i<treeToEdit.getChildWithName (Ids::uiPanelEditor).getNumProperties(); i++)
			{
				if (treeToEdit.getChildWithName (Ids::uiPanelEditor).getPropertyName(i) == Ids::uiPanelImageResource)
				{
					panelEditorProperties.add
					(
						owner.getOwner().getOwner().getIDManager().createComponentForProperty
						(
							treeToEdit.getChildWithName (Ids::uiPanelEditor).getPropertyName(i),
							treeToEdit.getChildWithName(Ids::uiPanelEditor),
							&owner.getOwner(),
							&resourceList,
							&resourceList
						)
					);
				}
				else
				{
					panelEditorProperties.add
					(
						owner.getOwner().getOwner().getIDManager().createComponentForProperty
						(
							treeToEdit.getChildWithName (Ids::uiPanelEditor).getPropertyName(i),
							treeToEdit.getChildWithName(Ids::uiPanelEditor),
							&owner.getOwner()
						)
					);
				}
			}
		}

		propertyPanel->clear();

		if (panelProperties.size() != 0)
			propertyPanel->addSection ("Panel", panelProperties);

		if (panelMidiProperties.size() != 0)
			propertyPanel->addSection ("MIDI", panelMidiProperties);

		if (panelMidiProperties.size() != 0)
			propertyPanel->addSection ("Editor", panelEditorProperties);
	}

	/** Modulator properties **/

	if (treeToEdit.hasType (Ids::modulator))
	{
		propertyPanel->clear();

		refreshTargetModulationPropertyList (treeToEdit);

		Array <PropertyComponent*> modulatorProperties;
		Array <PropertyComponent*> componentProperties;
		Array <PropertyComponent*> midiProperties;
		Array <PropertyComponent*> componentUIProperties;

		for (int i=0; i<treeToEdit.getNumProperties(); i++)
		{
			if (treeToEdit.getPropertyName(i) == Ids::modulatorLinkedToModulator)
			{
				modulatorProperties.add
				(
					owner.getOwner().getOwner().getIDManager().createComponentForProperty
					(
						treeToEdit.getPropertyName(i),
						treeToEdit,
						&owner.getOwner(),
						&modulatorList,
						&modulatorList
					)
				);
			}
			else if (treeToEdit.getPropertyName(i) == Ids::modulatorLinkedToModulatorProperty)
			{
				modulatorProperties.add
				(
					owner.getOwner().getOwner().getIDManager().createComponentForProperty
					(
						treeToEdit.getPropertyName(i),
						treeToEdit,
						&owner.getOwner(),
						&modulatorPropertyList,
						&modulatorPropertyList
					)
				);
			}
			else if (treeToEdit.getPropertyName(i) == Ids::modulatorLinkedToPanelProperty)
			{
				modulatorProperties.add
				(
					owner.getOwner().getOwner().getIDManager().createComponentForProperty
					(
						treeToEdit.getPropertyName(i),
						treeToEdit,
						&owner.getOwner(),
						&panelPropertyList,
						&panelPropertyList
					)
				);
			}
			else
			{
				modulatorProperties.add
				(
					owner.getOwner().getOwner().getIDManager().createComponentForProperty
					(
						treeToEdit.getPropertyName(i),
						treeToEdit,
						&owner.getOwner(),
						&emptyValueSet,
						&emptyValueSet
					)
				);
			}
		}

		for (int i=0; i<treeToEdit.getNumChildren(); i++)
		{
			/** MIDI properties **/
			if (treeToEdit.getChild(i).hasType(Ids::midi))
			{
				for (int j=0; j<treeToEdit.getChild(i).getNumProperties(); j++)
				{
					const Identifier n = treeToEdit.getChild(i).getPropertyName(j);

					if (treeToEdit.getChild(i).getPropertyName(j) == Ids::midiMessageType)
					{
						midiProperties.add
						(
							owner.getOwner().getOwner().getIDManager().createComponentForProperty
							(
								treeToEdit.getChild(i).getPropertyName(j),
								treeToEdit.getChild(i),
								&owner.getOwner(),
								&midiTemplateNames,
								&emptyValueSet)
							);
					}
					else
					{
						midiProperties.add
						(
							owner.getOwner().getOwner().getIDManager().createComponentForProperty
							(
								treeToEdit.getChild(i).getPropertyName(j),
								treeToEdit.getChild(i),
								&owner.getOwner()
							)
						);
					}
				}
			}

			/** Component properties **/
			if (treeToEdit.getChild(i).hasType(Ids::component))
			{
				if (treeToEdit.getChild(i).getNumChildren() >= 0)
				{
					for (int j=0; j<treeToEdit.getChild(i).getNumChildren(); j++)
					{
						ValueTree child = treeToEdit.getChild(i).getChild(j);

						for (int k=0; k<child.getNumProperties(); k++)
						{
							if (child.getPropertyName(k) == Ids::uiTabsTabBackgroundImage)
							{
								componentProperties.add
								(
									owner.getOwner().getOwner().getIDManager().createComponentForProperty
									(
										child.getPropertyName(k),
										child,
										&owner.getOwner(),
										&resourceList,
										&resourceList
									)
								);
							}
							else if (child.getPropertyName(k) == Ids::uiEnvelopePointLinkX || child.getPropertyName(k) == Ids::uiEnvelopePointLinkY)
							{
								componentProperties.add
								(
									owner.getOwner().getOwner().getIDManager().createComponentForProperty
									(
										child.getPropertyName(k),
										child,
										&owner.getOwner(),
										&modulatorList,
										&modulatorList
									)
								);
							}
							else
							{
								componentProperties.add
								(
									owner.getOwner().getOwner().getIDManager().createComponentForProperty
									(
										child.getPropertyName(k),
										child,
										&owner.getOwner()
									)
								);
							}
						}
					}
				}

				for (int j=0; j<treeToEdit.getChild(i).getNumProperties(); j++)
				{
					const Identifier n = treeToEdit.getChild(i).getPropertyName(j);

					if (n == Ids::uiImageResource
						|| n == Ids::uiImageSliderResource
						|| n == Ids::uiImageButtonResource
						|| n == Ids::uiGroupBackgroundImage
						|| n == Ids::uiTabsTabBackgroundImage
						|| n == Ids::uiXYSurfaceBgImageResource)
					{
						componentProperties.add
						(
							owner.getOwner().getOwner().getIDManager().createComponentForProperty
							(
								treeToEdit.getChild(i).getPropertyName(j),
								treeToEdit.getChild(i),
								&owner.getOwner(),
								&resourceList,
								&resourceList
							)
						);
					}
					else if (n.toString().startsWith("ui"))
					{
						componentUIProperties.add
						(
							owner.getOwner().getOwner().getIDManager().createComponentForProperty
							(
								treeToEdit.getChild(i).getPropertyName(j),
								treeToEdit.getChild(i),
								&owner.getOwner()
							)
						);
					}
					else
					{
						componentProperties.add
						(
							owner.getOwner().getOwner().getIDManager().createComponentForProperty
							(
								treeToEdit.getChild(i).getPropertyName(j),
								treeToEdit.getChild(i),
								&owner.getOwner()
							)
						);
					}
				}
			}
		}

		if (modulatorProperties.size() != 0)
			propertyPanel->addSection ("Modulator", modulatorProperties);

		if (midiProperties.size() != 0)
			propertyPanel->addSection ("MIDI", midiProperties);

		if (componentProperties.size() != 0)
			propertyPanel->addSection ("Component generic", componentProperties);

		if (componentUIProperties.size() != 0)
			propertyPanel->addSection ("Component", componentUIProperties);
	}
}