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.

283 lines
8.6KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #include "../../../../juce_core/basics/juce_StandardHeader.h"
  24. BEGIN_JUCE_NAMESPACE
  25. #include "juce_FileTreeComponent.h"
  26. #include "../lookandfeel/juce_LookAndFeel.h"
  27. #include "../../graphics/imaging/juce_ImageCache.h"
  28. #include "../../../events/juce_AsyncUpdater.h"
  29. Image* juce_createIconForFile (const File& file);
  30. //==============================================================================
  31. class FileListTreeItem : public TreeViewItem,
  32. public TimeSliceClient,
  33. public AsyncUpdater,
  34. public ChangeListener
  35. {
  36. public:
  37. //==============================================================================
  38. FileListTreeItem (FileTreeComponent& owner_,
  39. DirectoryContentsList* const parentContentsList_,
  40. const int indexInContentsList_,
  41. const File& file_,
  42. TimeSliceThread& thread_) throw()
  43. : file (file_),
  44. owner (owner_),
  45. parentContentsList (parentContentsList_),
  46. indexInContentsList (indexInContentsList_),
  47. subContentsList (0),
  48. canDeleteSubContentsList (false),
  49. thread (thread_),
  50. icon (0)
  51. {
  52. DirectoryContentsList::FileInfo fileInfo;
  53. if (parentContentsList_ != 0
  54. && parentContentsList_->getFileInfo (indexInContentsList_, fileInfo))
  55. {
  56. fileSize = File::descriptionOfSizeInBytes (fileInfo.fileSize);
  57. modTime = fileInfo.modificationTime.formatted (T("%d %b '%y %H:%M"));
  58. isDirectory = fileInfo.isDirectory;
  59. }
  60. else
  61. {
  62. isDirectory = true;
  63. }
  64. }
  65. ~FileListTreeItem() throw()
  66. {
  67. thread.removeTimeSliceClient (this);
  68. clearSubItems();
  69. ImageCache::release (icon);
  70. if (canDeleteSubContentsList)
  71. delete subContentsList;
  72. }
  73. //==============================================================================
  74. bool mightContainSubItems() { return isDirectory; }
  75. const String getUniqueName() const { return file.getFullPathName(); }
  76. int getItemHeight() const { return 22; }
  77. const String getDragSourceDescription() { return owner.getDragAndDropDescription(); }
  78. void itemOpennessChanged (bool isNowOpen)
  79. {
  80. if (isNowOpen)
  81. {
  82. clearSubItems();
  83. isDirectory = file.isDirectory();
  84. if (isDirectory)
  85. {
  86. if (subContentsList == 0)
  87. {
  88. jassert (parentContentsList != 0);
  89. DirectoryContentsList* const l = new DirectoryContentsList (parentContentsList->getFilter(), thread);
  90. l->setDirectory (file, true, true);
  91. setSubContentsList (l);
  92. canDeleteSubContentsList = true;
  93. }
  94. changeListenerCallback (0);
  95. }
  96. }
  97. }
  98. void setSubContentsList (DirectoryContentsList* newList) throw()
  99. {
  100. jassert (subContentsList == 0);
  101. subContentsList = newList;
  102. newList->addChangeListener (this);
  103. }
  104. void changeListenerCallback (void*)
  105. {
  106. clearSubItems();
  107. if (isOpen() && subContentsList != 0)
  108. {
  109. for (int i = 0; i < subContentsList->getNumFiles(); ++i)
  110. {
  111. FileListTreeItem* const item
  112. = new FileListTreeItem (owner, subContentsList, i, subContentsList->getFile(i), thread);
  113. addSubItem (item);
  114. }
  115. }
  116. }
  117. void paintItem (Graphics& g, int width, int height)
  118. {
  119. if (file != File::nonexistent && ! isDirectory)
  120. {
  121. updateIcon (true);
  122. if (icon == 0)
  123. thread.addTimeSliceClient (this);
  124. }
  125. owner.getLookAndFeel()
  126. .drawFileBrowserRow (g, width, height,
  127. file.getFileName(),
  128. icon,
  129. fileSize, modTime,
  130. isDirectory, isSelected(),
  131. indexInContentsList);
  132. }
  133. void itemClicked (const MouseEvent& e)
  134. {
  135. owner.sendMouseClickMessage (file, e);
  136. }
  137. void itemDoubleClicked (const MouseEvent& e)
  138. {
  139. TreeViewItem::itemDoubleClicked (e);
  140. owner.sendDoubleClickMessage (file);
  141. }
  142. void itemSelectionChanged (bool)
  143. {
  144. owner.sendSelectionChangeMessage();
  145. }
  146. bool useTimeSlice()
  147. {
  148. updateIcon (false);
  149. thread.removeTimeSliceClient (this);
  150. return false;
  151. }
  152. void handleAsyncUpdate()
  153. {
  154. owner.repaint();
  155. }
  156. const File file;
  157. //==============================================================================
  158. juce_UseDebuggingNewOperator
  159. private:
  160. FileTreeComponent& owner;
  161. DirectoryContentsList* parentContentsList;
  162. int indexInContentsList;
  163. DirectoryContentsList* subContentsList;
  164. bool isDirectory, canDeleteSubContentsList;
  165. TimeSliceThread& thread;
  166. Image* icon;
  167. String fileSize;
  168. String modTime;
  169. void updateIcon (const bool onlyUpdateIfCached) throw()
  170. {
  171. if (icon == 0)
  172. {
  173. const int hashCode = (file.getFullPathName() + T("_iconCacheSalt")).hashCode();
  174. Image* im = ImageCache::getFromHashCode (hashCode);
  175. if (im == 0 && ! onlyUpdateIfCached)
  176. {
  177. im = juce_createIconForFile (file);
  178. if (im != 0)
  179. ImageCache::addImageToCache (im, hashCode);
  180. }
  181. if (im != 0)
  182. {
  183. icon = im;
  184. triggerAsyncUpdate();
  185. }
  186. }
  187. }
  188. };
  189. //==============================================================================
  190. FileTreeComponent::FileTreeComponent (DirectoryContentsList& listToShow)
  191. : DirectoryContentsDisplayComponent (listToShow)
  192. {
  193. FileListTreeItem* const root
  194. = new FileListTreeItem (*this, 0, 0, listToShow.getDirectory(),
  195. listToShow.getTimeSliceThread());
  196. root->setSubContentsList (&listToShow);
  197. setRootItemVisible (false);
  198. setRootItem (root);
  199. }
  200. FileTreeComponent::~FileTreeComponent()
  201. {
  202. TreeViewItem* const root = getRootItem();
  203. setRootItem (0);
  204. delete root;
  205. }
  206. //==============================================================================
  207. const File FileTreeComponent::getSelectedFile() const
  208. {
  209. return getSelectedFile (0);
  210. }
  211. const File FileTreeComponent::getSelectedFile (const int index) const throw()
  212. {
  213. const FileListTreeItem* const item = dynamic_cast <const FileListTreeItem*> (getSelectedItem (index));
  214. if (item != 0)
  215. return item->file;
  216. return File::nonexistent;
  217. }
  218. void FileTreeComponent::scrollToTop()
  219. {
  220. getViewport()->getVerticalScrollBar()->setCurrentRangeStart (0);
  221. }
  222. void FileTreeComponent::setDragAndDropDescription (const String& description) throw()
  223. {
  224. dragAndDropDescription = description;
  225. }
  226. END_JUCE_NAMESPACE