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.2KB

  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. FileListItemComponent (FileListComponent& owner_, TimeSliceThread& thread_)
  65. : owner (owner_), thread (thread_), index (0), highlighted (false)
  66. {
  67. }
  68. ~FileListItemComponent()
  69. {
  70. thread.removeTimeSliceClient (this);
  71. }
  72. //==============================================================================
  73. void paint (Graphics& g)
  74. {
  75. getLookAndFeel().drawFileBrowserRow (g, getWidth(), getHeight(),
  76. file.getFileName(),
  77. &icon, fileSize, modTime,
  78. isDirectory, highlighted,
  79. index, owner);
  80. }
  81. void mouseDown (const MouseEvent& e)
  82. {
  83. owner.selectRowsBasedOnModifierKeys (index, e.mods, false);
  84. owner.sendMouseClickMessage (file, e);
  85. }
  86. void mouseDoubleClick (const MouseEvent&)
  87. {
  88. owner.sendDoubleClickMessage (file);
  89. }
  90. void update (const File& root,
  91. const DirectoryContentsList::FileInfo* const fileInfo,
  92. const int index_,
  93. const bool highlighted_)
  94. {
  95. thread.removeTimeSliceClient (this);
  96. if (highlighted_ != highlighted || index_ != index)
  97. {
  98. index = index_;
  99. highlighted = highlighted_;
  100. repaint();
  101. }
  102. File newFile;
  103. String newFileSize, newModTime;
  104. if (fileInfo != nullptr)
  105. {
  106. newFile = root.getChildFile (fileInfo->filename);
  107. newFileSize = File::descriptionOfSizeInBytes (fileInfo->fileSize);
  108. newModTime = fileInfo->modificationTime.formatted ("%d %b '%y %H:%M");
  109. }
  110. if (newFile != file
  111. || fileSize != newFileSize
  112. || modTime != newModTime)
  113. {
  114. file = newFile;
  115. fileSize = newFileSize;
  116. modTime = newModTime;
  117. icon = Image::null;
  118. isDirectory = fileInfo != nullptr && fileInfo->isDirectory;
  119. repaint();
  120. }
  121. if (file != File::nonexistent && icon.isNull() && ! isDirectory)
  122. {
  123. updateIcon (true);
  124. if (! icon.isValid())
  125. thread.addTimeSliceClient (this);
  126. }
  127. }
  128. int useTimeSlice()
  129. {
  130. updateIcon (false);
  131. return -1;
  132. }
  133. void handleAsyncUpdate()
  134. {
  135. repaint();
  136. }
  137. private:
  138. //==============================================================================
  139. FileListComponent& owner;
  140. TimeSliceThread& thread;
  141. File file;
  142. String fileSize, modTime;
  143. Image icon;
  144. int index;
  145. bool highlighted, isDirectory;
  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 (FileListItemComponent);
  166. };
  167. //==============================================================================
  168. int FileListComponent::getNumRows()
  169. {
  170. return fileList.getNumFiles();
  171. }
  172. void FileListComponent::paintListBoxItem (int, Graphics&, int, int, bool)
  173. {
  174. }
  175. Component* FileListComponent::refreshComponentForRow (int row, bool isSelected, Component* existingComponentToUpdate)
  176. {
  177. FileListItemComponent* comp = dynamic_cast <FileListItemComponent*> (existingComponentToUpdate);
  178. if (comp == nullptr)
  179. {
  180. delete existingComponentToUpdate;
  181. comp = new FileListItemComponent (*this, fileList.getTimeSliceThread());
  182. }
  183. DirectoryContentsList::FileInfo fileInfo;
  184. comp->update (fileList.getDirectory(),
  185. fileList.getFileInfo (row, fileInfo) ? &fileInfo : nullptr,
  186. row, isSelected);
  187. return comp;
  188. }
  189. void FileListComponent::selectedRowsChanged (int /*lastRowSelected*/)
  190. {
  191. sendSelectionChangeMessage();
  192. }
  193. void FileListComponent::deleteKeyPressed (int /*currentSelectedRow*/)
  194. {
  195. }
  196. void FileListComponent::returnKeyPressed (int currentSelectedRow)
  197. {
  198. sendDoubleClickMessage (fileList.getFile (currentSelectedRow));
  199. }
  200. END_JUCE_NAMESPACE