The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

307 lines
9.7KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-10 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #ifndef __JUCER_DRAWABLETREEVIEWITEM_JUCEHEADER__
  19. #define __JUCER_DRAWABLETREEVIEWITEM_JUCEHEADER__
  20. //==============================================================================
  21. /**
  22. */
  23. class DrawableTreeViewItem : public JucerTreeViewBase,
  24. public ValueTree::Listener,
  25. public ChangeListener,
  26. public AsyncUpdater
  27. {
  28. public:
  29. DrawableTreeViewItem (DrawableEditor& editor_, const ValueTree& drawableRoot)
  30. : editor (editor_), node (drawableRoot), typeName (drawableRoot.getType().toString())
  31. {
  32. node.getState().addListener (this);
  33. editor.getSelection().addChangeListener (this);
  34. }
  35. ~DrawableTreeViewItem()
  36. {
  37. editor.getSelection().removeChangeListener (this);
  38. node.getState().removeListener (this);
  39. }
  40. //==============================================================================
  41. void valueTreePropertyChanged (ValueTree& tree, const Identifier& property)
  42. {
  43. if (property == Drawable::ValueTreeWrapperBase::idProperty)
  44. repaintItem();
  45. }
  46. void valueTreeChildrenChanged (ValueTree& tree)
  47. {
  48. if (tree == node.getState() || tree.isAChildOf (node.getState()))
  49. triggerAsyncUpdate();
  50. }
  51. void valueTreeParentChanged (ValueTree& tree)
  52. {
  53. }
  54. void handleAsyncUpdate()
  55. {
  56. refreshSubItems();
  57. }
  58. //==============================================================================
  59. // TreeViewItem stuff..
  60. bool mightContainSubItems()
  61. {
  62. return node.getState().getType() == DrawableComposite::valueTreeType;
  63. }
  64. const String getUniqueName() const
  65. {
  66. jassert (node.getID().isNotEmpty());
  67. return node.getID();
  68. }
  69. void itemOpennessChanged (bool isNowOpen)
  70. {
  71. if (isNowOpen)
  72. refreshSubItems();
  73. }
  74. void refreshSubItems()
  75. {
  76. if (node.getState().getType() == DrawableComposite::valueTreeType)
  77. {
  78. ScopedPointer <XmlElement> oldOpenness (getOpennessState());
  79. clearSubItems();
  80. DrawableComposite::ValueTreeWrapper composite (node.getState());
  81. for (int i = 0; i < composite.getNumDrawables(); ++i)
  82. {
  83. ValueTree subNode (composite.getDrawableState (i));
  84. DrawableTreeViewItem* const item = new DrawableTreeViewItem (editor, subNode);
  85. addSubItem (item);
  86. }
  87. if (oldOpenness != 0)
  88. restoreOpennessState (*oldOpenness);
  89. editor.getSelection().changed();
  90. }
  91. }
  92. const String getDisplayName() const
  93. {
  94. const String name (getRenamingName());
  95. return typeName + (name.isEmpty() ? String::empty
  96. : (" \"" + name + "\""));
  97. }
  98. const String getRenamingName() const
  99. {
  100. return node.getID();
  101. }
  102. void setName (const String& newName)
  103. {
  104. }
  105. bool isMissing() { return false; }
  106. const Image getIcon() const
  107. {
  108. return LookAndFeel::getDefaultLookAndFeel().getDefaultDocumentFileImage();
  109. }
  110. void itemClicked (const MouseEvent& e)
  111. {
  112. }
  113. void itemDoubleClicked (const MouseEvent& e)
  114. {
  115. }
  116. void itemSelectionChanged (bool isNowSelected)
  117. {
  118. const String objectId (node.getID());
  119. if (isNowSelected)
  120. editor.getSelection().addToSelection (objectId);
  121. else
  122. editor.getSelection().deselect (objectId);
  123. }
  124. void changeListenerCallback (void*)
  125. {
  126. setSelected (editor.getSelection().isSelected (node.getID()), false);
  127. }
  128. const String getTooltip()
  129. {
  130. return String::empty;
  131. }
  132. static const String getDragIdFor (DrawableEditor& editor)
  133. {
  134. return drawableItemDragType + editor.getDocument().getUniqueId();
  135. }
  136. const String getDragSourceDescription()
  137. {
  138. return getDragIdFor (editor);
  139. }
  140. //==============================================================================
  141. // Drag-and-drop stuff..
  142. bool isInterestedInFileDrag (const StringArray& files)
  143. {
  144. return false;
  145. }
  146. void filesDropped (const StringArray& files, int insertIndex)
  147. {
  148. }
  149. bool isInterestedInDragSource (const String& sourceDescription, Component* sourceComponent)
  150. {
  151. return node.getState().getType() == DrawableComposite::valueTreeType
  152. && sourceDescription == getDragIdFor (editor)
  153. && editor.getSelection().getNumSelected() > 0;
  154. }
  155. void itemDropped (const String& sourceDescription, Component* sourceComponent, int insertIndex)
  156. {
  157. if (editor.getSelection().getNumSelected() > 0)
  158. {
  159. TreeView* tree = getOwnerView();
  160. const ScopedPointer <XmlElement> oldOpenness (tree->getOpennessState (false));
  161. Array <ValueTree> selectedComps;
  162. // scan the source tree rather than look at the selection manager, because it might
  163. // be from a different editor, and the order needs to be correct.
  164. getAllSelectedNodesInTree (sourceComponent, selectedComps);
  165. insertItems (selectedComps, insertIndex);
  166. if (oldOpenness != 0)
  167. tree->restoreOpennessState (*oldOpenness);
  168. }
  169. }
  170. static void getAllSelectedNodesInTree (Component* componentInTree, Array<ValueTree>& selectedItems)
  171. {
  172. TreeView* tree = dynamic_cast <TreeView*> (componentInTree);
  173. if (tree == 0)
  174. tree = componentInTree->findParentComponentOfClass ((TreeView*) 0);
  175. if (tree != 0)
  176. {
  177. const int numSelected = tree->getNumSelectedItems();
  178. for (int i = 0; i < numSelected; ++i)
  179. {
  180. DrawableTreeViewItem* const item = dynamic_cast <DrawableTreeViewItem*> (tree->getSelectedItem (i));
  181. if (item != 0)
  182. selectedItems.add (item->node.getState());
  183. }
  184. }
  185. }
  186. void insertItems (Array <ValueTree>& items, int insertIndex)
  187. {
  188. DrawableComposite::ValueTreeWrapper composite (node.getState());
  189. int i;
  190. for (i = items.size(); --i >= 0;)
  191. if (node.getState() == items.getReference(i) || composite.getState().isAChildOf (items.getReference(i))) // Check for recursion.
  192. return;
  193. // Don't include any nodes that are children of other selected nodes..
  194. for (i = items.size(); --i >= 0;)
  195. {
  196. const ValueTree& n = items.getReference(i);
  197. for (int j = items.size(); --j >= 0;)
  198. {
  199. if (j != i && n.isAChildOf (items.getReference(j)))
  200. {
  201. items.remove (i);
  202. break;
  203. }
  204. }
  205. }
  206. // Remove and re-insert them one at a time..
  207. for (i = 0; i < items.size(); ++i)
  208. {
  209. ValueTree& n = items.getReference(i);
  210. int index = composite.indexOfDrawable (n);
  211. if (index >= 0 && index < insertIndex)
  212. --insertIndex;
  213. if (index >= 0)
  214. {
  215. composite.moveDrawableOrder (index, insertIndex++, editor.getDocument().getUndoManager());
  216. }
  217. else
  218. {
  219. n.getParent().removeChild (n, editor.getDocument().getUndoManager());
  220. composite.addDrawable (n, insertIndex++, editor.getDocument().getUndoManager());
  221. }
  222. }
  223. }
  224. //==============================================================================
  225. void showRenameBox()
  226. {
  227. }
  228. // Text editor listener for renaming..
  229. void textEditorTextChanged (TextEditor& textEditor) {}
  230. void textEditorReturnKeyPressed (TextEditor& textEditor) { textEditor.exitModalState (1); }
  231. void textEditorEscapeKeyPressed (TextEditor& textEditor) { textEditor.exitModalState (0); }
  232. void textEditorFocusLost (TextEditor& textEditor) { textEditor.exitModalState (0); }
  233. //==============================================================================
  234. DrawableEditor& editor;
  235. Drawable::ValueTreeWrapperBase node;
  236. private:
  237. String typeName;
  238. DrawableEditor* getEditor() const
  239. {
  240. return getOwnerView()->findParentComponentOfClass ((DrawableEditor*) 0);
  241. }
  242. };
  243. #endif // __JUCER_DRAWABLETREEVIEWITEM_JUCEHEADER__