Using the FileTreeComponent


#1

I’m setting up the FileTreeComponent to display the computer folder structure and files, so the user can pick the files. So far things are working correctly. The only thing I have no clue on how to do is how to know when a file was selected. I couldn’t find any examples of it. I know that a good programmer would know how to do it, but I’m doing so many things at once here, that my brain is melting and I can’t seem to figure it out… :expressionless: :oops:

File folder (File::getSpecialLocation (File::userDocumentsDirectory)); WildcardFileFilter* fileFilter=new WildcardFileFilter("*.dll;*.WusikPRST","Files"); directoryList = new DirectoryContentsList (fileFilter, thread); directoryList->setDirectory(folder, true, true); thread.startThread (3); addAndMakeVisible(cTreeView = new = FileTreeComponent(*directoryList)); cTreeView->setRootItemVisible(true);

Don’t forget to call “thread.stopThread (10000);” at the destructor.

Best Regards, WilliamK


#2

A FileTreeComponent is just a TreeView, so you can override its itemSelectionChanged() method to handle the selection changes.


#3

Sorry to be dense, but you mean like this?

[code]//-----------------------------------------------------------------------------------------------------------
class JUCE_API FileTreeComponentEx : public FileTreeComponent
{
public:

FileTreeComponentEx (DirectoryContentsList& listToShow);

[/code]

And instead of using

FileTreeComponent * tView

I use

FileTreeComponentEx* tView

?

It works for some things. But

itemSelectionChanged()

is part of TreeViewItem which I can’t seem to find a way to override. :frowning:


#4

Wait, I think I get it now. I need to override and copy a lot of things. :wink:

I see the example TreeViewDemo.cpp used by the Juce Demo application.

I will use that as a base.

Sorry again. :oops:

Wk


#5

I’m posting my partial solution here, just so any n00b people can also take a look at it. I’m still implementing the rest of the stuff I want to add. Like Loading, Deleting, Insert-new-directory, Move (copy and Paste) and so on…

Header:

[code]
class FileTreeComponentEx : public FileTreeComponent
{
public:
FileTreeComponentEx (DirectoryContentsList& listToShow);

const File getSelectedFile (const int index) const throw();

};[/code]

Cpp

[code]#define MessageBox(dd,ds) AlertWindow::showMessageBox(AlertWindow::WarningIcon, dd,ds)

//-----------------------------------------------------------------------------------------------------------
class FileListTreeItemEx : public TreeViewItem,
public TimeSliceClient,
public AsyncUpdater,
public ChangeListener
{
public:

//-----------------------------------------------------------------------------------------------------------
FileListTreeItemEx (FileTreeComponentEx& owner_,
                  DirectoryContentsList* const parentContentsList_,
                  const int indexInContentsList_,
                  const File& file_,
                  TimeSliceThread& thread_) throw()
    : file (file_),
      owner (owner_),
      parentContentsList (parentContentsList_),
      indexInContentsList (indexInContentsList_),
      subContentsList (0),
      canDeleteSubContentsList (false),
      thread (thread_),
      icon (0)
{
    DirectoryContentsList::FileInfo fileInfo;

    if (parentContentsList_ != 0
         && parentContentsList_->getFileInfo (indexInContentsList_, fileInfo))
    {
        fileSize = File::descriptionOfSizeInBytes (fileInfo.fileSize);
        modTime = fileInfo.modificationTime.formatted (T("%d %b '%y %H:%M"));
        isDirectory = fileInfo.isDirectory;
    }
    else
    {
        isDirectory = true;
    }
}

//-----------------------------------------------------------------------------------------------------------
~FileListTreeItemEx() throw()
{
    thread.removeTimeSliceClient (this);

    clearSubItems();
    ImageCache::release (icon);

    if (canDeleteSubContentsList)
        delete subContentsList;
}

bool mightContainSubItems()                 { return isDirectory; }
const String getUniqueName() const          { return file.getFullPathName(); }
int getItemHeight() const                   { return 22; }

const String getDragSourceDescription()     { return owner.getDragAndDropDescription(); }

//-----------------------------------------------------------------------------------------------------------
void itemOpennessChanged (bool isNowOpen)
{
    if (isNowOpen)
    {
        clearSubItems();

        isDirectory = file.isDirectory();

        if (isDirectory)
        {
            if (subContentsList == 0)
            {
                jassert (parentContentsList != 0);

                DirectoryContentsList* const l = new DirectoryContentsList (parentContentsList->getFilter(), thread);
                l->setDirectory (file, true, true);

                setSubContentsList (l);
                canDeleteSubContentsList = true;
            }

            changeListenerCallback (0);
        }
    }
}

//-----------------------------------------------------------------------------------------------------------
void setSubContentsList (DirectoryContentsList* newList) throw()
{
    jassert (subContentsList == 0);
    subContentsList = newList;
    newList->addChangeListener (this);
}

//-----------------------------------------------------------------------------------------------------------
void changeListenerCallback (void*)
{
    clearSubItems();

    if (isOpen() && subContentsList != 0)
    {
        for (int i = 0; i < subContentsList->getNumFiles(); ++i)
        {
            FileListTreeItemEx* const item
                = new FileListTreeItemEx (owner, subContentsList, i, subContentsList->getFile(i), thread);

            addSubItem (item);
        }
    }
}

//-----------------------------------------------------------------------------------------------------------
void paintItem (Graphics& g, int width, int height)
{
    if (file != File::nonexistent && ! isDirectory)
    {
        updateIcon (true);

        if (icon == 0)
            thread.addTimeSliceClient (this);
    }

    owner.getLookAndFeel()
        .drawFileBrowserRow (g, width, height,
                             file.getFileName(),
                             icon,
                             fileSize, modTime,
                             isDirectory, isSelected(),
                             indexInContentsList);
}

//-----------------------------------------------------------------------------------------------------------
void itemClicked (const MouseEvent& e)
{
    owner.sendMouseClickMessage (file, e);

	if (e.mods.isPopupMenu())
	{
		MessageBox(owner.getSelectedFile(0).getFullPathName(),"!");
	}
}

//-----------------------------------------------------------------------------------------------------------
void itemDoubleClicked (const MouseEvent& e)
{
    TreeViewItem::itemDoubleClicked (e);
    owner.sendDoubleClickMessage (file);
	
	if (!owner.getSelectedFile(0).isDirectory()) MessageBox(owner.getSelectedFile(0).getFullPathName(),"!");
}

//-----------------------------------------------------------------------------------------------------------
void itemSelectionChanged (bool)
{
    owner.sendSelectionChangeMessage();
}

//-----------------------------------------------------------------------------------------------------------
bool useTimeSlice()
{
    updateIcon (false);
    thread.removeTimeSliceClient (this);
    return false;
}

//-----------------------------------------------------------------------------------------------------------
void handleAsyncUpdate()
{
    owner.repaint();
}

const File file;

juce_UseDebuggingNewOperator

private:
FileTreeComponentEx& owner;
DirectoryContentsList* parentContentsList;
int indexInContentsList;
DirectoryContentsList* subContentsList;
bool isDirectory, canDeleteSubContentsList;
TimeSliceThread& thread;
Image* icon;
String fileSize;
String modTime;

void updateIcon (const bool onlyUpdateIfCached) throw() { }

};

//-----------------------------------------------------------------------------------------------------------
FileTreeComponentEx::FileTreeComponentEx (DirectoryContentsList& listToShow)
: FileTreeComponent (listToShow)
{
FileListTreeItemEx* const root
= new FileListTreeItemEx (*this, 0, 0, listToShow.getDirectory(),
listToShow.getTimeSliceThread());

root->setSubContentsList (&listToShow);
setRootItemVisible (false);
setRootItem (root);

}

//-----------------------------------------------------------------------------------------------------------
/FileTreeComponentEx::~FileTreeComponentEx()
{
TreeViewItem
const root = getRootItem();
setRootItem (0);
delete root;
}

//-----------------------------------------------------------------------------------------------------------
const File FileTreeComponentEx::getSelectedFile() const
{
return getSelectedFile (0);
}*/

//-----------------------------------------------------------------------------------------------------------
const File FileTreeComponentEx::getSelectedFile (const int index) const throw()
{
const FileListTreeItemEx* const item = dynamic_cast <const FileListTreeItemEx*> (getSelectedItem (index));

if (item != 0)
    return item->file;

return File::nonexistent;

}

//-----------------------------------------------------------------------------------------------------------
/*void FileTreeComponentEx::scrollToTop()
{
getViewport()->getVerticalScrollBar()->setCurrentRangeStart (0);
}

//-----------------------------------------------------------------------------------------------------------
void FileTreeComponentEx::setDragAndDropDescription (const String& description) throw()
{
dragAndDropDescription = description;
}*/[/code]

I’m not using the whole code yet. And I couldn’t really override some of the stuff as the FileListTreeItem class is NOT in the Juce .h files. At least I couldn’t find it… still, since I will do a lot of changes, I don’t mind copying the whole code.

Wk


#6

One thing I still need to figure out, is how to hide folders with no files. Specially when I use a filter like “piano*.sfz” to search for piano sounds…

Wk