Add remaining files
[juce-lv2.git] / juce / source / src / gui / components / filebrowser / juce_FileBrowserComponent.cpp
blob11569c272f0e119f2c9b0451d21ab393481e3240
1 /*
2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../../core/juce_StandardHeader.h"
28 BEGIN_JUCE_NAMESPACE
30 #include "juce_FileBrowserComponent.h"
31 #include "../lookandfeel/juce_LookAndFeel.h"
32 #include "../../graphics/drawables/juce_DrawablePath.h"
33 #include "../../../text/juce_LocalisedStrings.h"
34 #include "../../../core/juce_SystemStats.h"
35 #include "juce_FileListComponent.h"
36 #include "juce_FileTreeComponent.h"
39 //==============================================================================
40 FileBrowserComponent::FileBrowserComponent (int flags_,
41 const File& initialFileOrDirectory,
42 const FileFilter* fileFilter_,
43 FilePreviewComponent* previewComp_)
44 : FileFilter (String::empty),
45 fileFilter (fileFilter_),
46 flags (flags_),
47 previewComp (previewComp_),
48 currentPathBox ("path"),
49 fileLabel ("f", TRANS ("file:")),
50 thread ("Juce FileBrowser")
52 // You need to specify one or other of the open/save flags..
53 jassert ((flags & (saveMode | openMode)) != 0);
54 jassert ((flags & (saveMode | openMode)) != (saveMode | openMode));
56 // You need to specify at least one of these flags..
57 jassert ((flags & (canSelectFiles | canSelectDirectories)) != 0);
59 String filename;
61 if (initialFileOrDirectory == File::nonexistent)
63 currentRoot = File::getCurrentWorkingDirectory();
65 else if (initialFileOrDirectory.isDirectory())
67 currentRoot = initialFileOrDirectory;
69 else
71 chosenFiles.add (initialFileOrDirectory);
72 currentRoot = initialFileOrDirectory.getParentDirectory();
73 filename = initialFileOrDirectory.getFileName();
76 fileList = new DirectoryContentsList (this, thread);
78 if ((flags & useTreeView) != 0)
80 FileTreeComponent* const tree = new FileTreeComponent (*fileList);
81 fileListComponent = tree;
83 if ((flags & canSelectMultipleItems) != 0)
84 tree->setMultiSelectEnabled (true);
86 addAndMakeVisible (tree);
88 else
90 FileListComponent* const list = new FileListComponent (*fileList);
91 fileListComponent = list;
92 list->setOutlineThickness (1);
94 if ((flags & canSelectMultipleItems) != 0)
95 list->setMultipleSelectionEnabled (true);
97 addAndMakeVisible (list);
100 fileListComponent->addListener (this);
102 addAndMakeVisible (&currentPathBox);
103 currentPathBox.setEditableText (true);
104 resetRecentPaths();
105 currentPathBox.addListener (this);
107 addAndMakeVisible (&filenameBox);
108 filenameBox.setMultiLine (false);
109 filenameBox.setSelectAllWhenFocused (true);
110 filenameBox.setText (filename, false);
111 filenameBox.addListener (this);
112 filenameBox.setReadOnly ((flags & (filenameBoxIsReadOnly | canSelectMultipleItems)) != 0);
114 addAndMakeVisible (&fileLabel);
115 fileLabel.attachToComponent (&filenameBox, true);
117 addAndMakeVisible (goUpButton = getLookAndFeel().createFileBrowserGoUpButton());
118 goUpButton->addListener (this);
119 goUpButton->setTooltip (TRANS ("go up to parent directory"));
121 if (previewComp != nullptr)
122 addAndMakeVisible (previewComp);
124 setRoot (currentRoot);
126 thread.startThread (4);
129 FileBrowserComponent::~FileBrowserComponent()
131 fileListComponent = nullptr;
132 fileList = nullptr;
133 thread.stopThread (10000);
136 //==============================================================================
137 void FileBrowserComponent::addListener (FileBrowserListener* const newListener)
139 listeners.add (newListener);
142 void FileBrowserComponent::removeListener (FileBrowserListener* const listener)
144 listeners.remove (listener);
147 //==============================================================================
148 bool FileBrowserComponent::isSaveMode() const noexcept
150 return (flags & saveMode) != 0;
153 int FileBrowserComponent::getNumSelectedFiles() const noexcept
155 if (chosenFiles.size() == 0 && currentFileIsValid())
156 return 1;
158 return chosenFiles.size();
161 File FileBrowserComponent::getSelectedFile (int index) const noexcept
163 if ((flags & canSelectDirectories) != 0 && filenameBox.getText().isEmpty())
164 return currentRoot;
166 if (! filenameBox.isReadOnly())
167 return currentRoot.getChildFile (filenameBox.getText());
169 return chosenFiles[index];
172 bool FileBrowserComponent::currentFileIsValid() const
174 if (isSaveMode())
175 return ! getSelectedFile (0).isDirectory();
176 else
177 return getSelectedFile (0).exists();
180 File FileBrowserComponent::getHighlightedFile() const noexcept
182 return fileListComponent->getSelectedFile (0);
185 void FileBrowserComponent::deselectAllFiles()
187 fileListComponent->deselectAllFiles();
190 //==============================================================================
191 bool FileBrowserComponent::isFileSuitable (const File& file) const
193 return (flags & canSelectFiles) != 0 && (fileFilter == nullptr || fileFilter->isFileSuitable (file));
196 bool FileBrowserComponent::isDirectorySuitable (const File&) const
198 return true;
201 bool FileBrowserComponent::isFileOrDirSuitable (const File& f) const
203 if (f.isDirectory())
204 return (flags & canSelectDirectories) != 0
205 && (fileFilter == nullptr || fileFilter->isDirectorySuitable (f));
207 return (flags & canSelectFiles) != 0 && f.exists()
208 && (fileFilter == nullptr || fileFilter->isFileSuitable (f));
211 //==============================================================================
212 const File& FileBrowserComponent::getRoot() const
214 return currentRoot;
217 void FileBrowserComponent::setRoot (const File& newRootDirectory)
219 if (currentRoot != newRootDirectory)
221 fileListComponent->scrollToTop();
223 String path (newRootDirectory.getFullPathName());
225 if (path.isEmpty())
226 path = File::separatorString;
228 StringArray rootNames, rootPaths;
229 getRoots (rootNames, rootPaths);
231 if (! rootPaths.contains (path, true))
233 bool alreadyListed = false;
235 for (int i = currentPathBox.getNumItems(); --i >= 0;)
237 if (currentPathBox.getItemText (i).equalsIgnoreCase (path))
239 alreadyListed = true;
240 break;
244 if (! alreadyListed)
245 currentPathBox.addItem (path, currentPathBox.getNumItems() + 2);
249 currentRoot = newRootDirectory;
250 fileList->setDirectory (currentRoot, true, true);
252 String currentRootName (currentRoot.getFullPathName());
253 if (currentRootName.isEmpty())
254 currentRootName = File::separatorString;
256 currentPathBox.setText (currentRootName, true);
258 goUpButton->setEnabled (currentRoot.getParentDirectory().isDirectory()
259 && currentRoot.getParentDirectory() != currentRoot);
262 void FileBrowserComponent::resetRecentPaths()
264 currentPathBox.clear();
266 StringArray rootNames, rootPaths;
267 getRoots (rootNames, rootPaths);
269 for (int i = 0; i < rootNames.size(); ++i)
271 if (rootNames[i].isEmpty())
272 currentPathBox.addSeparator();
273 else
274 currentPathBox.addItem (rootNames[i], i + 1);
277 currentPathBox.addSeparator();
280 void FileBrowserComponent::goUp()
282 setRoot (getRoot().getParentDirectory());
285 void FileBrowserComponent::refresh()
287 fileList->refresh();
290 void FileBrowserComponent::setFileFilter (const FileFilter* const newFileFilter)
292 if (fileFilter != newFileFilter)
294 fileFilter = newFileFilter;
295 refresh();
299 const String FileBrowserComponent::getActionVerb() const
301 return isSaveMode() ? TRANS("Save") : TRANS("Open");
304 FilePreviewComponent* FileBrowserComponent::getPreviewComponent() const noexcept
306 return previewComp;
309 //==============================================================================
310 void FileBrowserComponent::resized()
312 getLookAndFeel()
313 .layoutFileBrowserComponent (*this, fileListComponent, previewComp,
314 &currentPathBox, &filenameBox, goUpButton);
317 //==============================================================================
318 void FileBrowserComponent::sendListenerChangeMessage()
320 Component::BailOutChecker checker (this);
322 if (previewComp != nullptr)
323 previewComp->selectedFileChanged (getSelectedFile (0));
325 // You shouldn't delete the browser when the file gets changed!
326 jassert (! checker.shouldBailOut());
328 listeners.callChecked (checker, &FileBrowserListener::selectionChanged);
331 void FileBrowserComponent::selectionChanged()
333 StringArray newFilenames;
334 bool resetChosenFiles = true;
336 for (int i = 0; i < fileListComponent->getNumSelectedFiles(); ++i)
338 const File f (fileListComponent->getSelectedFile (i));
340 if (isFileOrDirSuitable (f))
342 if (resetChosenFiles)
344 chosenFiles.clear();
345 resetChosenFiles = false;
348 chosenFiles.add (f);
349 newFilenames.add (f.getRelativePathFrom (getRoot()));
353 if (newFilenames.size() > 0)
354 filenameBox.setText (newFilenames.joinIntoString (", "), false);
356 sendListenerChangeMessage();
359 void FileBrowserComponent::fileClicked (const File& f, const MouseEvent& e)
361 Component::BailOutChecker checker (this);
362 listeners.callChecked (checker, &FileBrowserListener::fileClicked, f, e);
365 void FileBrowserComponent::fileDoubleClicked (const File& f)
367 if (f.isDirectory())
369 setRoot (f);
371 if ((flags & canSelectDirectories) != 0)
372 filenameBox.setText (String::empty);
374 else
376 Component::BailOutChecker checker (this);
377 listeners.callChecked (checker, &FileBrowserListener::fileDoubleClicked, f);
381 bool FileBrowserComponent::keyPressed (const KeyPress& key)
383 (void) key;
385 #if JUCE_LINUX || JUCE_WINDOWS
386 if (key.getModifiers().isCommandDown()
387 && (key.getKeyCode() == 'H' || key.getKeyCode() == 'h'))
389 fileList->setIgnoresHiddenFiles (! fileList->ignoresHiddenFiles());
390 fileList->refresh();
391 return true;
393 #endif
395 return false;
398 //==============================================================================
399 void FileBrowserComponent::textEditorTextChanged (TextEditor&)
401 sendListenerChangeMessage();
404 void FileBrowserComponent::textEditorReturnKeyPressed (TextEditor&)
406 if (filenameBox.getText().containsChar (File::separator))
408 const File f (currentRoot.getChildFile (filenameBox.getText()));
410 if (f.isDirectory())
412 setRoot (f);
413 chosenFiles.clear();
414 filenameBox.setText (String::empty);
416 else
418 setRoot (f.getParentDirectory());
419 chosenFiles.clear();
420 chosenFiles.add (f);
421 filenameBox.setText (f.getFileName());
424 else
426 fileDoubleClicked (getSelectedFile (0));
430 void FileBrowserComponent::textEditorEscapeKeyPressed (TextEditor&)
434 void FileBrowserComponent::textEditorFocusLost (TextEditor&)
436 if (! isSaveMode())
437 selectionChanged();
440 //==============================================================================
441 void FileBrowserComponent::buttonClicked (Button*)
443 goUp();
446 void FileBrowserComponent::comboBoxChanged (ComboBox*)
448 const String newText (currentPathBox.getText().trim().unquoted());
450 if (newText.isNotEmpty())
452 const int index = currentPathBox.getSelectedId() - 1;
454 StringArray rootNames, rootPaths;
455 getRoots (rootNames, rootPaths);
457 if (rootPaths [index].isNotEmpty())
459 setRoot (File (rootPaths [index]));
461 else
463 File f (newText);
465 for (;;)
467 if (f.isDirectory())
469 setRoot (f);
470 break;
473 if (f.getParentDirectory() == f)
474 break;
476 f = f.getParentDirectory();
482 void FileBrowserComponent::getRoots (StringArray& rootNames, StringArray& rootPaths)
484 #if JUCE_WINDOWS
485 Array<File> roots;
486 File::findFileSystemRoots (roots);
487 rootPaths.clear();
489 for (int i = 0; i < roots.size(); ++i)
491 const File& drive = roots.getReference(i);
493 String name (drive.getFullPathName());
494 rootPaths.add (name);
496 if (drive.isOnHardDisk())
498 String volume (drive.getVolumeLabel());
500 if (volume.isEmpty())
501 volume = TRANS("Hard Drive");
503 name << " [" << volume << ']';
505 else if (drive.isOnCDRomDrive())
507 name << TRANS(" [CD/DVD drive]");
510 rootNames.add (name);
513 rootPaths.add (String::empty);
514 rootNames.add (String::empty);
516 rootPaths.add (File::getSpecialLocation (File::userDocumentsDirectory).getFullPathName());
517 rootNames.add ("Documents");
518 rootPaths.add (File::getSpecialLocation (File::userDesktopDirectory).getFullPathName());
519 rootNames.add ("Desktop");
521 #elif JUCE_MAC
522 rootPaths.add (File::getSpecialLocation (File::userHomeDirectory).getFullPathName());
523 rootNames.add ("Home folder");
524 rootPaths.add (File::getSpecialLocation (File::userDocumentsDirectory).getFullPathName());
525 rootNames.add ("Documents");
526 rootPaths.add (File::getSpecialLocation (File::userDesktopDirectory).getFullPathName());
527 rootNames.add ("Desktop");
529 rootPaths.add (String::empty);
530 rootNames.add (String::empty);
532 Array <File> volumes;
533 File vol ("/Volumes");
534 vol.findChildFiles (volumes, File::findDirectories, false);
536 for (int i = 0; i < volumes.size(); ++i)
538 const File& volume = volumes.getReference(i);
540 if (volume.isDirectory() && ! volume.getFileName().startsWithChar ('.'))
542 rootPaths.add (volume.getFullPathName());
543 rootNames.add (volume.getFileName());
547 #else
548 rootPaths.add ("/");
549 rootNames.add ("/");
550 rootPaths.add (File::getSpecialLocation (File::userHomeDirectory).getFullPathName());
551 rootNames.add ("Home folder");
552 rootPaths.add (File::getSpecialLocation (File::userDesktopDirectory).getFullPathName());
553 rootNames.add ("Desktop");
554 #endif
558 END_JUCE_NAMESPACE