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.

251 lines
7.8KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 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. BEGIN_JUCE_NAMESPACE
  19. Image juce_createIconForFile (const File& file);
  20. //==============================================================================
  21. class FileListTreeItem : public TreeViewItem,
  22. public TimeSliceClient,
  23. public AsyncUpdater,
  24. public ChangeListener
  25. {
  26. public:
  27. FileListTreeItem (FileTreeComponent& owner_,
  28. DirectoryContentsList* const parentContentsList_,
  29. const int indexInContentsList_,
  30. const File& file_,
  31. TimeSliceThread& thread_)
  32. : file (file_),
  33. owner (owner_),
  34. parentContentsList (parentContentsList_),
  35. indexInContentsList (indexInContentsList_),
  36. subContentsList (nullptr, false),
  37. thread (thread_)
  38. {
  39. DirectoryContentsList::FileInfo fileInfo;
  40. if (parentContentsList_ != nullptr
  41. && parentContentsList_->getFileInfo (indexInContentsList_, fileInfo))
  42. {
  43. fileSize = File::descriptionOfSizeInBytes (fileInfo.fileSize);
  44. modTime = fileInfo.modificationTime.formatted ("%d %b '%y %H:%M");
  45. isDirectory = fileInfo.isDirectory;
  46. }
  47. else
  48. {
  49. isDirectory = true;
  50. }
  51. }
  52. ~FileListTreeItem()
  53. {
  54. thread.removeTimeSliceClient (this);
  55. clearSubItems();
  56. }
  57. //==============================================================================
  58. bool mightContainSubItems() { return isDirectory; }
  59. String getUniqueName() const { return file.getFullPathName(); }
  60. int getItemHeight() const { return 22; }
  61. var getDragSourceDescription() { return owner.getDragAndDropDescription(); }
  62. void itemOpennessChanged (bool isNowOpen)
  63. {
  64. if (isNowOpen)
  65. {
  66. clearSubItems();
  67. isDirectory = file.isDirectory();
  68. if (isDirectory)
  69. {
  70. if (subContentsList == nullptr)
  71. {
  72. jassert (parentContentsList != nullptr);
  73. DirectoryContentsList* const l = new DirectoryContentsList (parentContentsList->getFilter(), thread);
  74. l->setDirectory (file, true, true);
  75. setSubContentsList (l, true);
  76. }
  77. changeListenerCallback (nullptr);
  78. }
  79. }
  80. }
  81. void setSubContentsList (DirectoryContentsList* newList, const bool canDeleteList)
  82. {
  83. OptionalScopedPointer<DirectoryContentsList> newPointer (newList, canDeleteList);
  84. subContentsList = newPointer;
  85. newList->addChangeListener (this);
  86. }
  87. void changeListenerCallback (ChangeBroadcaster*)
  88. {
  89. clearSubItems();
  90. if (isOpen() && subContentsList != nullptr)
  91. {
  92. for (int i = 0; i < subContentsList->getNumFiles(); ++i)
  93. {
  94. FileListTreeItem* const item
  95. = new FileListTreeItem (owner, subContentsList, i, subContentsList->getFile(i), thread);
  96. addSubItem (item);
  97. }
  98. }
  99. }
  100. void paintItem (Graphics& g, int width, int height)
  101. {
  102. if (file != File::nonexistent)
  103. {
  104. updateIcon (true);
  105. if (icon.isNull())
  106. thread.addTimeSliceClient (this);
  107. }
  108. owner.getLookAndFeel().drawFileBrowserRow (g, width, height,
  109. file.getFileName(),
  110. &icon, fileSize, modTime,
  111. isDirectory, isSelected(),
  112. indexInContentsList, owner);
  113. }
  114. void itemClicked (const MouseEvent& e)
  115. {
  116. owner.sendMouseClickMessage (file, e);
  117. }
  118. void itemDoubleClicked (const MouseEvent& e)
  119. {
  120. TreeViewItem::itemDoubleClicked (e);
  121. owner.sendDoubleClickMessage (file);
  122. }
  123. void itemSelectionChanged (bool)
  124. {
  125. owner.sendSelectionChangeMessage();
  126. }
  127. int useTimeSlice()
  128. {
  129. updateIcon (false);
  130. return -1;
  131. }
  132. void handleAsyncUpdate()
  133. {
  134. owner.repaint();
  135. }
  136. const File file;
  137. private:
  138. FileTreeComponent& owner;
  139. DirectoryContentsList* parentContentsList;
  140. int indexInContentsList;
  141. OptionalScopedPointer<DirectoryContentsList> subContentsList;
  142. bool isDirectory;
  143. TimeSliceThread& thread;
  144. Image icon;
  145. String fileSize, modTime;
  146. void updateIcon (const bool onlyUpdateIfCached)
  147. {
  148. if (icon.isNull())
  149. {
  150. const int hashCode = (file.getFullPathName() + "_iconCacheSalt").hashCode();
  151. Image im (ImageCache::getFromHashCode (hashCode));
  152. if (im.isNull() && ! onlyUpdateIfCached)
  153. {
  154. im = juce_createIconForFile (file);
  155. if (im.isValid())
  156. ImageCache::addImageToCache (im, hashCode);
  157. }
  158. if (im.isValid())
  159. {
  160. icon = im;
  161. triggerAsyncUpdate();
  162. }
  163. }
  164. }
  165. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileListTreeItem);
  166. };
  167. //==============================================================================
  168. FileTreeComponent::FileTreeComponent (DirectoryContentsList& listToShow)
  169. : DirectoryContentsDisplayComponent (listToShow)
  170. {
  171. FileListTreeItem* const root
  172. = new FileListTreeItem (*this, 0, 0, listToShow.getDirectory(),
  173. listToShow.getTimeSliceThread());
  174. root->setSubContentsList (&listToShow, false);
  175. setRootItemVisible (false);
  176. setRootItem (root);
  177. }
  178. FileTreeComponent::~FileTreeComponent()
  179. {
  180. deleteRootItem();
  181. }
  182. //==============================================================================
  183. File FileTreeComponent::getSelectedFile (const int index) const
  184. {
  185. const FileListTreeItem* const item = dynamic_cast <const FileListTreeItem*> (getSelectedItem (index));
  186. return item != nullptr ? item->file
  187. : File::nonexistent;
  188. }
  189. void FileTreeComponent::deselectAllFiles()
  190. {
  191. clearSelectedItems();
  192. }
  193. void FileTreeComponent::scrollToTop()
  194. {
  195. getViewport()->getVerticalScrollBar()->setCurrentRangeStart (0);
  196. }
  197. void FileTreeComponent::setDragAndDropDescription (const String& description)
  198. {
  199. dragAndDropDescription = description;
  200. }
  201. END_JUCE_NAMESPACE