|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2020 - Raw Material Software Limited
-
- JUCE is an open source library subject to commercial or open-source
- licensing.
-
- By using JUCE, you agree to the terms of both the JUCE 6 End-User License
- Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
-
- End User License Agreement: www.juce.com/juce-6-licence
- Privacy Policy: www.juce.com/juce-privacy-policy
-
- Or: You may also use this code under the terms of the GPL v3 (see
- www.gnu.org/licenses).
-
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
-
- ==============================================================================
- */
-
- namespace juce
- {
-
- //==============================================================================
- class FileListTreeItem : public TreeViewItem,
- private TimeSliceClient,
- private AsyncUpdater,
- private ChangeListener
- {
- public:
- FileListTreeItem (FileTreeComponent& treeComp,
- DirectoryContentsList* parentContents,
- int indexInContents,
- const File& f,
- TimeSliceThread& t)
- : file (f),
- owner (treeComp),
- parentContentsList (parentContents),
- indexInContentsList (indexInContents),
- subContentsList (nullptr, false),
- thread (t)
- {
- DirectoryContentsList::FileInfo fileInfo;
-
- if (parentContents != nullptr
- && parentContents->getFileInfo (indexInContents, fileInfo))
- {
- fileSize = File::descriptionOfSizeInBytes (fileInfo.fileSize);
- modTime = fileInfo.modificationTime.formatted ("%d %b '%y %H:%M");
- isDirectory = fileInfo.isDirectory;
- }
- else
- {
- isDirectory = true;
- }
- }
-
- ~FileListTreeItem() override
- {
- thread.removeTimeSliceClient (this);
- clearSubItems();
- removeSubContentsList();
- }
-
- //==============================================================================
- bool mightContainSubItems() override { return isDirectory; }
- String getUniqueName() const override { return file.getFullPathName(); }
- int getItemHeight() const override { return owner.getItemHeight(); }
-
- var getDragSourceDescription() override { return owner.getDragAndDropDescription(); }
-
- void itemOpennessChanged (bool isNowOpen) override
- {
- if (isNowOpen)
- {
- clearSubItems();
-
- isDirectory = file.isDirectory();
-
- if (isDirectory)
- {
- if (subContentsList == nullptr)
- {
- jassert (parentContentsList != nullptr);
-
- auto l = new DirectoryContentsList (parentContentsList->getFilter(), thread);
-
- l->setDirectory (file,
- parentContentsList->isFindingDirectories(),
- parentContentsList->isFindingFiles());
-
- setSubContentsList (l, true);
- }
-
- changeListenerCallback (nullptr);
- }
- }
- }
-
- void removeSubContentsList()
- {
- if (subContentsList != nullptr)
- {
- subContentsList->removeChangeListener (this);
- subContentsList.reset();
- }
- }
-
- void setSubContentsList (DirectoryContentsList* newList, const bool canDeleteList)
- {
- removeSubContentsList();
-
- subContentsList = OptionalScopedPointer<DirectoryContentsList> (newList, canDeleteList);
- newList->addChangeListener (this);
- }
-
- bool selectFile (const File& target)
- {
- if (file == target)
- {
- setSelected (true, true);
- return true;
- }
-
- if (target.isAChildOf (file))
- {
- setOpen (true);
-
- for (int maxRetries = 500; --maxRetries > 0;)
- {
- for (int i = 0; i < getNumSubItems(); ++i)
- if (auto* f = dynamic_cast<FileListTreeItem*> (getSubItem (i)))
- if (f->selectFile (target))
- return true;
-
- // if we've just opened and the contents are still loading, wait for it..
- if (subContentsList != nullptr && subContentsList->isStillLoading())
- {
- Thread::sleep (10);
- rebuildItemsFromContentList();
- }
- else
- {
- break;
- }
- }
- }
-
- return false;
- }
-
- void changeListenerCallback (ChangeBroadcaster*) override
- {
- rebuildItemsFromContentList();
- }
-
- void rebuildItemsFromContentList()
- {
- clearSubItems();
-
- if (isOpen() && subContentsList != nullptr)
- {
- for (int i = 0; i < subContentsList->getNumFiles(); ++i)
- addSubItem (new FileListTreeItem (owner, subContentsList, i,
- subContentsList->getFile(i), thread));
- }
- }
-
- void paintItem (Graphics& g, int width, int height) override
- {
- ScopedLock lock (iconUpdate);
-
- if (file != File())
- {
- updateIcon (true);
-
- if (icon.isNull())
- thread.addTimeSliceClient (this);
- }
-
- owner.getLookAndFeel().drawFileBrowserRow (g, width, height,
- file, file.getFileName(),
- &icon, fileSize, modTime,
- isDirectory, isSelected(),
- indexInContentsList, owner);
- }
-
- void itemClicked (const MouseEvent& e) override
- {
- owner.sendMouseClickMessage (file, e);
- }
-
- void itemDoubleClicked (const MouseEvent& e) override
- {
- TreeViewItem::itemDoubleClicked (e);
-
- owner.sendDoubleClickMessage (file);
- }
-
- void itemSelectionChanged (bool) override
- {
- owner.sendSelectionChangeMessage();
- }
-
- int useTimeSlice() override
- {
- updateIcon (false);
- return -1;
- }
-
- void handleAsyncUpdate() override
- {
- owner.repaint();
- }
-
- const File file;
-
- private:
- FileTreeComponent& owner;
- DirectoryContentsList* parentContentsList;
- int indexInContentsList;
- OptionalScopedPointer<DirectoryContentsList> subContentsList;
- bool isDirectory;
- TimeSliceThread& thread;
- CriticalSection iconUpdate;
- Image icon;
- String fileSize, modTime;
-
- void updateIcon (const bool onlyUpdateIfCached)
- {
- if (icon.isNull())
- {
- auto hashCode = (file.getFullPathName() + "_iconCacheSalt").hashCode();
- auto im = ImageCache::getFromHashCode (hashCode);
-
- if (im.isNull() && ! onlyUpdateIfCached)
- {
- im = juce_createIconForFile (file);
-
- if (im.isValid())
- ImageCache::addImageToCache (im, hashCode);
- }
-
- if (im.isValid())
- {
- {
- ScopedLock lock (iconUpdate);
- icon = im;
- }
-
- triggerAsyncUpdate();
- }
- }
- }
-
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileListTreeItem)
- };
-
- //==============================================================================
- FileTreeComponent::FileTreeComponent (DirectoryContentsList& listToShow)
- : DirectoryContentsDisplayComponent (listToShow),
- itemHeight (22)
- {
- setRootItemVisible (false);
- refresh();
- }
-
- FileTreeComponent::~FileTreeComponent()
- {
- deleteRootItem();
- }
-
- void FileTreeComponent::refresh()
- {
- deleteRootItem();
-
- auto root = new FileListTreeItem (*this, nullptr, 0, directoryContentsList.getDirectory(),
- directoryContentsList.getTimeSliceThread());
-
- root->setSubContentsList (&directoryContentsList, false);
- setRootItem (root);
- }
-
- //==============================================================================
- File FileTreeComponent::getSelectedFile (const int index) const
- {
- if (auto* item = dynamic_cast<const FileListTreeItem*> (getSelectedItem (index)))
- return item->file;
-
- return {};
- }
-
- void FileTreeComponent::deselectAllFiles()
- {
- clearSelectedItems();
- }
-
- void FileTreeComponent::scrollToTop()
- {
- getViewport()->getVerticalScrollBar().setCurrentRangeStart (0);
- }
-
- void FileTreeComponent::setDragAndDropDescription (const String& description)
- {
- dragAndDropDescription = description;
- }
-
- void FileTreeComponent::setSelectedFile (const File& target)
- {
- if (auto* t = dynamic_cast<FileListTreeItem*> (getRootItem()))
- if (! t->selectFile (target))
- clearSelectedItems();
- }
-
- void FileTreeComponent::setItemHeight (int newHeight)
- {
- if (itemHeight != newHeight)
- {
- itemHeight = newHeight;
-
- if (auto* root = getRootItem())
- root->treeHasChanged();
- }
- }
-
- } // namespace juce
|