Browse Source

FileChoosers: Added a file-chooser save mode where the caller already supplies a temporary file which should be saved. JUCE will automatically move the temporary file to the location selected by the user

tags/2021-05-28
hogliux 8 years ago
parent
commit
df8fc9b910
8 changed files with 86 additions and 37 deletions
  1. +10
    -2
      examples/Demo/Source/Demos/DialogsDemo.cpp
  2. +23
    -6
      modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp
  3. +41
    -6
      modules/juce_gui_basics/filebrowser/juce_FileChooser.h
  4. +1
    -1
      modules/juce_gui_basics/native/juce_android_FileChooser.cpp
  5. +7
    -18
      modules/juce_gui_basics/native/juce_ios_FileChooser.mm
  6. +1
    -1
      modules/juce_gui_basics/native/juce_linux_FileChooser.cpp
  7. +1
    -1
      modules/juce_gui_basics/native/juce_mac_FileChooser.mm
  8. +2
    -2
      modules/juce_gui_basics/native/juce_win32_FileChooser.cpp

+ 10
- 2
examples/Demo/Source/Demos/DialogsDemo.cpp View File

@@ -317,8 +317,16 @@ private:
} }
else if (type == saveChooser) else if (type == saveChooser)
{ {
File fileToSave = File::createTempFile ("saveChooserDemo");
if (fileToSave.createDirectory().wasOk())
{
fileToSave = fileToSave.getChildFile ("JUCE.png");
fileToSave.replaceWithData (BinaryData::juce_icon_png, BinaryData::juce_icon_pngSize);
}
fc = new FileChooser ("Choose a file to save...", fc = new FileChooser ("Choose a file to save...",
File::getCurrentWorkingDirectory(),
File::getCurrentWorkingDirectory().getChildFile (fileToSave.getFileName()),
"*", "*",
useNativeVersion); useNativeVersion);
@@ -333,7 +341,7 @@ private:
AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon, AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
"File Chooser...", "File Chooser...",
"You picked: " + name); "You picked: " + name);
});
}, nullptr, fileToSave);
} }
else if (type == directoryChooser) else if (type == directoryChooser)
{ {


+ 23
- 6
modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp View File

@@ -73,7 +73,7 @@ private:
result.add (URL (browserComponent.getSelectedFile (i))); result.add (URL (browserComponent.getSelectedFile (i)));
} }
owner.finished (result);
owner.finished (result, true);
} }
//============================================================================== //==============================================================================
@@ -137,12 +137,13 @@ bool FileChooser::browseForMultipleFilesOrDirectories (FilePreviewComponent* pre
previewComp); previewComp);
} }
bool FileChooser::browseForFileToSave (const bool warnAboutOverwrite)
bool FileChooser::browseForFileToSave (const bool warnAboutOverwrite,
const File& fileWhichShouldBeSaved)
{ {
return showDialog (FileBrowserComponent::saveMode return showDialog (FileBrowserComponent::saveMode
| FileBrowserComponent::canSelectFiles | FileBrowserComponent::canSelectFiles
| (warnAboutOverwrite ? FileBrowserComponent::warnAboutOverwriting : 0), | (warnAboutOverwrite ? FileBrowserComponent::warnAboutOverwriting : 0),
nullptr);
nullptr, fileWhichShouldBeSaved);
} }
bool FileChooser::browseForDirectory() bool FileChooser::browseForDirectory()
@@ -152,8 +153,11 @@ bool FileChooser::browseForDirectory()
nullptr); nullptr);
} }
bool FileChooser::showDialog (const int flags, FilePreviewComponent* const previewComp)
bool FileChooser::showDialog (const int flags, FilePreviewComponent* const previewComp,
const File& fileWhichShouldBeSaved)
{ {
fileToSave = (flags & FileBrowserComponent::saveMode) != 0 ? fileWhichShouldBeSaved : File();
FocusRestorer focusRestorer; FocusRestorer focusRestorer;
pimpl = createPimpl (flags, previewComp); pimpl = createPimpl (flags, previewComp);
@@ -167,7 +171,8 @@ bool FileChooser::showDialog (const int flags, FilePreviewComponent* const previ
#endif #endif
void FileChooser::launchAsync (int flags, std::function<void (const FileChooser&)> callback, void FileChooser::launchAsync (int flags, std::function<void (const FileChooser&)> callback,
FilePreviewComponent* previewComp)
FilePreviewComponent* previewComp,
const File& fileWhichShouldBeSaved)
{ {
// You must specify a callback when using launchAsync // You must specify a callback when using launchAsync
jassert (callback); jassert (callback);
@@ -175,6 +180,8 @@ void FileChooser::launchAsync (int flags, std::function<void (const FileChooser&
// you cannot run two file chooser dialog boxes at the same time // you cannot run two file chooser dialog boxes at the same time
jassert (asyncCallback == nullptr); jassert (asyncCallback == nullptr);
fileToSave = (flags & FileBrowserComponent::saveMode) != 0 ? fileWhichShouldBeSaved : File();
asyncCallback = static_cast<std::function<void (const FileChooser&)>&&> (callback); asyncCallback = static_cast<std::function<void (const FileChooser&)>&&> (callback);
pimpl = createPimpl (flags, previewComp); pimpl = createPimpl (flags, previewComp);
@@ -249,13 +256,23 @@ URL FileChooser::getURLResult() const
return results.getFirst(); return results.getFirst();
} }
void FileChooser::finished (const Array<URL>& asyncResults)
void FileChooser::finished (const Array<URL>& asyncResults, bool shouldMove)
{ {
std::function<void (const FileChooser&)> callback; std::function<void (const FileChooser&)> callback;
std::swap (callback, asyncCallback); std::swap (callback, asyncCallback);
results = asyncResults; results = asyncResults;
if (shouldMove && fileToSave.existsAsFile() && results.size() > 0)
{
// The user either selected multiple files or wants to save the file to a URL
// Both are not supported
jassert (results.size() == 1 && results.getReference (0).isLocalFile());
if (! fileToSave.moveFileTo (results.getReference (0).getLocalFile()))
results.clear();
}
pimpl = nullptr; pimpl = nullptr;
if (callback) if (callback)


+ 41
- 6
modules/juce_gui_basics/filebrowser/juce_FileChooser.h View File

@@ -66,7 +66,8 @@ public:
@param initialFileOrDirectory the file or directory that should be selected @param initialFileOrDirectory the file or directory that should be selected
when the dialog box opens. If this parameter is when the dialog box opens. If this parameter is
set to File(), a sensible default directory will set to File(), a sensible default directory will
be used instead.
be used instead. This parameter is ignored for native
iOS file choosers.
@param filePatternsAllowed a set of file patterns to specify which files @param filePatternsAllowed a set of file patterns to specify which files
can be selected - each pattern should be can be selected - each pattern should be
separated by a comma or semi-colon, e.g. "*" or separated by a comma or semi-colon, e.g. "*" or
@@ -122,12 +123,22 @@ public:
@param warnAboutOverwritingExistingFiles if true, the dialog box will ask @param warnAboutOverwritingExistingFiles if true, the dialog box will ask
the user if they're sure they want to overwrite a file that already the user if they're sure they want to overwrite a file that already
exists exists
@param fileWhichShouldBeSaved if this parameter is specified, then, if the the user
selects a valid location to save the file, fileWhichShouldBeSaved will
automaitcally be moved to the location selected by the user when the user
clicks 'ok'. If you do not specify this parameter, then it is your
responsibility to save your file at the location that is returned from this
file chooser. Typically, when using this parameter, you already write the
file you wish to save to a temporary location and then supply the path to
this file to this parameter. This parameter is required on iOS when using
native file save dialogs but can be used on all other platforms.
@returns true if the user chose a file and pressed 'ok', in which case, use @returns true if the user chose a file and pressed 'ok', in which case, use
the getResult() method to find out what the file was. Returns false the getResult() method to find out what the file was. Returns false
if they cancelled instead. if they cancelled instead.
@see browseForFileToOpen, browseForDirectory @see browseForFileToOpen, browseForDirectory
*/ */
bool browseForFileToSave (bool warnAboutOverwritingExistingFiles);
bool browseForFileToSave (bool warnAboutOverwritingExistingFiles,
const File& fileWhichShouldBeSaved = File());
/** Shows a dialog box to choose a directory. /** Shows a dialog box to choose a directory.
@@ -152,12 +163,24 @@ public:
/** Runs a dialog box for the given set of option flags. /** Runs a dialog box for the given set of option flags.
The flag values used are those in FileBrowserComponent::FileChooserFlags. The flag values used are those in FileBrowserComponent::FileChooserFlags.
@param fileWhichShouldBeSaved if this parameter is specified and saveMode is
specified, then, if the the user selects a valid location to save the file,
fileWhichShouldBeSaved will automaitcally be moved to the location selected
by the user when the user clicks 'ok'. If you do not specify this parameter,
then it is your responsibility to save your file at the location that is
returned from this file chooser. Typically, when using this parameter,
you already write the file you wish to save to a temporary location and
then supply the path to this file to this parameter. This parameter is
required on iOS when using native file save dialogs but can be used on all
other platforms.
@returns true if the user chose a directory and pressed 'ok', in which case, use @returns true if the user chose a directory and pressed 'ok', in which case, use
the getResult() method to find out what they chose. Returns false the getResult() method to find out what they chose. Returns false
if they cancelled instead. if they cancelled instead.
@see FileBrowserComponent::FileChooserFlags @see FileBrowserComponent::FileChooserFlags
*/ */
bool showDialog (int flags, FilePreviewComponent* previewComponent);
bool showDialog (int flags, FilePreviewComponent* previewComponent,
const File& fileWhichShouldBeSaved = File());
/** Use this method to launch the file browser window asynchronously. /** Use this method to launch the file browser window asynchronously.
@@ -173,10 +196,22 @@ public:
You must ensure that the lifetime of the callback object is longer than You must ensure that the lifetime of the callback object is longer than
the lifetime of the file-chooser. the lifetime of the file-chooser.
@param fileWhichShouldBeSaved if this parameter is specified and saveMode is
specified, then, if the the user selects a valid location to save the file,
fileWhichShouldBeSaved will automaitcally be moved to the location selected
by the user when the user clicks 'ok'. If you do not specify this parameter,
then it is your responsibility to save your file at the location that is
returned from this file chooser. Typically, when using this parameter,
you already write the file you wish to save to a temporary location and
then supply the path to this file to this parameter. This parameter is
required on iOS when using native file save dialogs but can be used on all
other platforms.
*/ */
void launchAsync (int flags, void launchAsync (int flags,
std::function<void (const FileChooser&)>, std::function<void (const FileChooser&)>,
FilePreviewComponent* previewComponent = nullptr);
FilePreviewComponent* previewComponent = nullptr,
const File& fileWhichShouldBeSaved = File());
//============================================================================== //==============================================================================
/** Returns the last file that was chosen by one of the browseFor methods. /** Returns the last file that was chosen by one of the browseFor methods.
@@ -253,14 +288,14 @@ public:
private: private:
//============================================================================== //==============================================================================
String title, filters; String title, filters;
const File startingFile;
File startingFile, fileToSave;
Array<URL> results; Array<URL> results;
const bool useNativeDialogBox; const bool useNativeDialogBox;
const bool treatFilePackagesAsDirs; const bool treatFilePackagesAsDirs;
std::function<void (const FileChooser&)> asyncCallback; std::function<void (const FileChooser&)> asyncCallback;
//============================================================================== //==============================================================================
void finished (const Array<URL>&);
void finished (const Array<URL>&, bool);
//============================================================================== //==============================================================================
struct Pimpl struct Pimpl


+ 1
- 1
modules/juce_gui_basics/native/juce_android_FileChooser.cpp View File

@@ -168,7 +168,7 @@ public:
} }
} }
owner.finished (chosenURLs);
owner.finished (chosenURLs, true);
} }
static Native* currentFileChooser; static Native* currentFileChooser;


+ 7
- 18
modules/juce_gui_basics/native/juce_ios_FileChooser.mm View File

@@ -45,25 +45,14 @@ public:
if ((flags & FileBrowserComponent::saveMode) != 0) if ((flags & FileBrowserComponent::saveMode) != 0)
{ {
auto currentFileOrDirectory = owner.startingFile;
// You must specify the fileWhichShouldBeSaved parameter when using
// the native save dialog on iOS!
jassert (owner.fileToSave.existsAsFile());
if (! currentFileOrDirectory.existsAsFile())
{
auto filename = (currentFileOrDirectory.isDirectory() ? "Untitled" : currentFileOrDirectory.getFileName());
auto tmpDirectory = File::createTempFile ("iosDummyFiles");
if (tmpDirectory.createDirectory().wasOk())
{
currentFileOrDirectory = tmpDirectory.getChildFile (filename);
currentFileOrDirectory.replaceWithText ("");
}
}
auto url = [[NSURL alloc] initFileURLWithPath:juceStringToNS (currentFileOrDirectory.getFullPathName())];
auto url = [[NSURL alloc] initFileURLWithPath:juceStringToNS (owner.fileToSave.getFullPathName())];
controller = [[UIDocumentPickerViewController alloc] initWithURL:url controller = [[UIDocumentPickerViewController alloc] initWithURL:url
inMode:UIDocumentPickerModeMoveToService];
inMode:UIDocumentPickerModeExportToService];
[url release]; [url release];
} }
else else
@@ -158,7 +147,7 @@ private:
Array<URL> chooserResults; Array<URL> chooserResults;
chooserResults.add (URL (nsStringToJuce ([url absoluteString]))); chooserResults.add (URL (nsStringToJuce ([url absoluteString])));
owner.finished (chooserResults);
owner.finished (chooserResults, false);
exitModalState (1); exitModalState (1);
} }
@@ -166,7 +155,7 @@ private:
{ {
Array<URL> chooserResults; Array<URL> chooserResults;
owner.finished (chooserResults);
owner.finished (chooserResults, false);
exitModalState (0); exitModalState (0);
} }


+ 1
- 1
modules/juce_gui_basics/native/juce_linux_FileChooser.cpp View File

@@ -122,7 +122,7 @@ private:
if (! shouldKill) if (! shouldKill)
{ {
child.waitForProcessToFinish (60 * 1000); child.waitForProcessToFinish (60 * 1000);
owner.finished (selection);
owner.finished (selection, true);
} }
} }


+ 1
- 1
modules/juce_gui_basics/native/juce_mac_FileChooser.mm View File

@@ -213,7 +213,7 @@ private:
} }
} }
owner.finished (chooserResults);
owner.finished (chooserResults, true);
} }
bool shouldShowFilename (const String& filenameToTest) bool shouldShowFilename (const String& filenameToTest)


+ 2
- 2
modules/juce_gui_basics/native/juce_win32_FileChooser.cpp View File

@@ -535,7 +535,7 @@ public:
[safeThis] (int) [safeThis] (int)
{ {
if (safeThis != nullptr) if (safeThis != nullptr)
safeThis->owner.finished (safeThis->nativeFileChooser->results);
safeThis->owner.finished (safeThis->nativeFileChooser->results, true);
})); }));
nativeFileChooser->open (true); nativeFileChooser->open (true);
@@ -548,7 +548,7 @@ public:
exitModalState (nativeFileChooser->results.size() > 0 ? 1 : 0); exitModalState (nativeFileChooser->results.size() > 0 ? 1 : 0);
nativeFileChooser->cancel(); nativeFileChooser->cancel();
owner.finished (nativeFileChooser->results);
owner.finished (nativeFileChooser->results, true);
} }
private: private:


Loading…
Cancel
Save