| @@ -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) | ||||
| { | { | ||||
| @@ -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) | ||||
| @@ -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 | ||||
| @@ -168,7 +168,7 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| owner.finished (chosenURLs); | |||||
| owner.finished (chosenURLs, true); | |||||
| } | } | ||||
| static Native* currentFileChooser; | static Native* currentFileChooser; | ||||
| @@ -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); | ||||
| } | } | ||||
| @@ -122,7 +122,7 @@ private: | |||||
| if (! shouldKill) | if (! shouldKill) | ||||
| { | { | ||||
| child.waitForProcessToFinish (60 * 1000); | child.waitForProcessToFinish (60 * 1000); | ||||
| owner.finished (selection); | |||||
| owner.finished (selection, true); | |||||
| } | } | ||||
| } | } | ||||
| @@ -213,7 +213,7 @@ private: | |||||
| } | } | ||||
| } | } | ||||
| owner.finished (chooserResults); | |||||
| owner.finished (chooserResults, true); | |||||
| } | } | ||||
| bool shouldShowFilename (const String& filenameToTest) | bool shouldShowFilename (const String& filenameToTest) | ||||
| @@ -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: | ||||