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.

254 lines
7.4KB

  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. FileListComponent::FileListComponent (DirectoryContentsList& listToShow)
  22. : ListBox (String::empty, nullptr),
  23. DirectoryContentsDisplayComponent (listToShow)
  24. {
  25. setModel (this);
  26. fileList.addChangeListener (this);
  27. }
  28. FileListComponent::~FileListComponent()
  29. {
  30. fileList.removeChangeListener (this);
  31. }
  32. int FileListComponent::getNumSelectedFiles() const
  33. {
  34. return getNumSelectedRows();
  35. }
  36. File FileListComponent::getSelectedFile (int index) const
  37. {
  38. return fileList.getFile (getSelectedRow (index));
  39. }
  40. void FileListComponent::deselectAllFiles()
  41. {
  42. deselectAllRows();
  43. }
  44. void FileListComponent::scrollToTop()
  45. {
  46. getVerticalScrollBar()->setCurrentRangeStart (0);
  47. }
  48. //==============================================================================
  49. void FileListComponent::changeListenerCallback (ChangeBroadcaster*)
  50. {
  51. updateContent();
  52. if (lastDirectory != fileList.getDirectory())
  53. {
  54. lastDirectory = fileList.getDirectory();
  55. deselectAllRows();
  56. }
  57. }
  58. //==============================================================================
  59. class FileListItemComponent : public Component,
  60. public TimeSliceClient,
  61. public AsyncUpdater
  62. {
  63. public:
  64. //==============================================================================
  65. FileListItemComponent (FileListComponent& owner_, TimeSliceThread& thread_)
  66. : owner (owner_), thread (thread_), index (0), highlighted (false)
  67. {
  68. }
  69. ~FileListItemComponent()
  70. {
  71. thread.removeTimeSliceClient (this);
  72. }
  73. //==============================================================================
  74. void paint (Graphics& g)
  75. {
  76. getLookAndFeel().drawFileBrowserRow (g, getWidth(), getHeight(),
  77. file.getFileName(),
  78. &icon, fileSize, modTime,
  79. isDirectory, highlighted,
  80. index, owner);
  81. }
  82. void mouseDown (const MouseEvent& e)
  83. {
  84. owner.selectRowsBasedOnModifierKeys (index, e.mods, false);
  85. owner.sendMouseClickMessage (file, e);
  86. }
  87. void mouseDoubleClick (const MouseEvent&)
  88. {
  89. owner.sendDoubleClickMessage (file);
  90. }
  91. void update (const File& root,
  92. const DirectoryContentsList::FileInfo* const fileInfo,
  93. const int index_,
  94. const bool highlighted_)
  95. {
  96. thread.removeTimeSliceClient (this);
  97. if (highlighted_ != highlighted || index_ != index)
  98. {
  99. index = index_;
  100. highlighted = highlighted_;
  101. repaint();
  102. }
  103. File newFile;
  104. String newFileSize, newModTime;
  105. if (fileInfo != nullptr)
  106. {
  107. newFile = root.getChildFile (fileInfo->filename);
  108. newFileSize = File::descriptionOfSizeInBytes (fileInfo->fileSize);
  109. newModTime = fileInfo->modificationTime.formatted ("%d %b '%y %H:%M");
  110. }
  111. if (newFile != file
  112. || fileSize != newFileSize
  113. || modTime != newModTime)
  114. {
  115. file = newFile;
  116. fileSize = newFileSize;
  117. modTime = newModTime;
  118. icon = Image::null;
  119. isDirectory = fileInfo != nullptr && fileInfo->isDirectory;
  120. repaint();
  121. }
  122. if (file != File::nonexistent && icon.isNull() && ! isDirectory)
  123. {
  124. updateIcon (true);
  125. if (! icon.isValid())
  126. thread.addTimeSliceClient (this);
  127. }
  128. }
  129. int useTimeSlice()
  130. {
  131. updateIcon (false);
  132. return -1;
  133. }
  134. void handleAsyncUpdate()
  135. {
  136. repaint();
  137. }
  138. private:
  139. //==============================================================================
  140. FileListComponent& owner;
  141. TimeSliceThread& thread;
  142. File file;
  143. String fileSize, modTime;
  144. Image icon;
  145. int index;
  146. bool highlighted, isDirectory;
  147. void updateIcon (const bool onlyUpdateIfCached)
  148. {
  149. if (icon.isNull())
  150. {
  151. const int hashCode = (file.getFullPathName() + "_iconCacheSalt").hashCode();
  152. Image im (ImageCache::getFromHashCode (hashCode));
  153. if (im.isNull() && ! onlyUpdateIfCached)
  154. {
  155. im = juce_createIconForFile (file);
  156. if (im.isValid())
  157. ImageCache::addImageToCache (im, hashCode);
  158. }
  159. if (im.isValid())
  160. {
  161. icon = im;
  162. triggerAsyncUpdate();
  163. }
  164. }
  165. }
  166. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileListItemComponent);
  167. };
  168. //==============================================================================
  169. int FileListComponent::getNumRows()
  170. {
  171. return fileList.getNumFiles();
  172. }
  173. void FileListComponent::paintListBoxItem (int, Graphics&, int, int, bool)
  174. {
  175. }
  176. Component* FileListComponent::refreshComponentForRow (int row, bool isSelected, Component* existingComponentToUpdate)
  177. {
  178. FileListItemComponent* comp = dynamic_cast <FileListItemComponent*> (existingComponentToUpdate);
  179. if (comp == nullptr)
  180. {
  181. delete existingComponentToUpdate;
  182. comp = new FileListItemComponent (*this, fileList.getTimeSliceThread());
  183. }
  184. DirectoryContentsList::FileInfo fileInfo;
  185. if (fileList.getFileInfo (row, fileInfo))
  186. comp->update (fileList.getDirectory(), &fileInfo, row, isSelected);
  187. else
  188. comp->update (fileList.getDirectory(), nullptr, row, isSelected);
  189. return comp;
  190. }
  191. void FileListComponent::selectedRowsChanged (int /*lastRowSelected*/)
  192. {
  193. sendSelectionChangeMessage();
  194. }
  195. void FileListComponent::deleteKeyPressed (int /*currentSelectedRow*/)
  196. {
  197. }
  198. void FileListComponent::returnKeyPressed (int currentSelectedRow)
  199. {
  200. sendDoubleClickMessage (fileList.getFile (currentSelectedRow));
  201. }
  202. END_JUCE_NAMESPACE