| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE 7 technical preview.
 -    Copyright (c) 2022 - Raw Material Software Limited
 - 
 -    You may use this code under the terms of the GPL v3
 -    (see www.gnu.org/licenses).
 - 
 -    For the technical preview this file cannot be licensed commercially.
 - 
 -    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
 - {
 - 
 - #if ! (defined (__IPHONE_16_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_16_0)
 -  JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
 -  #define JUCE_DEPRECATION_IGNORED 1
 - #endif
 - 
 - class FileChooser::Native  : public FileChooser::Pimpl,
 -                              public Component,
 -                              private AsyncUpdater
 - {
 - public:
 -     Native (FileChooser& fileChooser, int flags)
 -         : owner (fileChooser)
 -     {
 -         static FileChooserDelegateClass delegateClass;
 -         delegate.reset ([delegateClass.createInstance() init]);
 -         FileChooserDelegateClass::setOwner (delegate.get(), this);
 - 
 -         static FileChooserControllerClass controllerClass;
 -         auto* controllerClassInstance = controllerClass.createInstance();
 - 
 -         String firstFileExtension;
 -         auto utTypeArray = createNSArrayFromStringArray (getUTTypesForWildcards (owner.filters, firstFileExtension));
 - 
 -         if ((flags & FileBrowserComponent::saveMode) != 0)
 -         {
 -             auto currentFileOrDirectory = owner.startingFile;
 - 
 -             UIDocumentPickerMode pickerMode = currentFileOrDirectory.existsAsFile()
 -                                                 ? UIDocumentPickerModeExportToService
 -                                                 : UIDocumentPickerModeMoveToService;
 - 
 -             if (! currentFileOrDirectory.existsAsFile())
 -             {
 -                 auto filename = getFilename (currentFileOrDirectory, firstFileExtension);
 -                 auto tmpDirectory = File::createTempFile ("JUCE-filepath");
 - 
 -                 if (tmpDirectory.createDirectory().wasOk())
 -                 {
 -                     currentFileOrDirectory = tmpDirectory.getChildFile (filename);
 -                     currentFileOrDirectory.replaceWithText ("");
 -                 }
 -                 else
 -                 {
 -                     // Temporary directory creation failed! You need to specify a
 -                     // path you have write access to. Saving will not work for
 -                     // current path.
 -                     jassertfalse;
 -                 }
 -             }
 - 
 -             auto url = [[NSURL alloc] initFileURLWithPath: juceStringToNS (currentFileOrDirectory.getFullPathName())];
 - 
 -             controller.reset ([controllerClassInstance initWithURL: url
 -                                                             inMode: pickerMode]);
 - 
 -             [url release];
 -         }
 -         else
 -         {
 -             controller.reset ([controllerClassInstance initWithDocumentTypes: utTypeArray
 -                                                                       inMode: UIDocumentPickerModeOpen]);
 -             if (@available (iOS 11.0, *))
 -                 [controller.get() setAllowsMultipleSelection: (flags & FileBrowserComponent::canSelectMultipleItems) != 0];
 -         }
 - 
 -         FileChooserControllerClass::setOwner (controller.get(), this);
 - 
 -         [controller.get() setDelegate: delegate.get()];
 -         [controller.get() setModalTransitionStyle: UIModalTransitionStyleCrossDissolve];
 - 
 -         setOpaque (false);
 - 
 -         if (fileChooser.parent != nullptr)
 -         {
 -             [controller.get() setModalPresentationStyle: UIModalPresentationFullScreen];
 - 
 -             auto chooserBounds = fileChooser.parent->getBounds();
 -             setBounds (chooserBounds);
 - 
 -             setAlwaysOnTop (true);
 -             fileChooser.parent->addAndMakeVisible (this);
 -         }
 -         else
 -         {
 -             if (SystemStats::isRunningInAppExtensionSandbox())
 -             {
 -                 // Opening a native top-level window in an AUv3 is not allowed (sandboxing). You need to specify a
 -                 // parent component (for example your editor) to parent the native file chooser window. To do this
 -                 // specify a parent component in the FileChooser's constructor!
 -                 jassertfalse;
 -                 return;
 -             }
 - 
 -             auto chooserBounds = Desktop::getInstance().getDisplays().getPrimaryDisplay()->userArea;
 -             setBounds (chooserBounds);
 - 
 -             setAlwaysOnTop (true);
 -             setVisible (true);
 -             addToDesktop (0);
 -         }
 -     }
 - 
 -     ~Native() override
 -     {
 -         exitModalState (0);
 - 
 -         // Our old peer may not have received a becomeFirstResponder call at this point,
 -         // so the static currentlyFocusedPeer may be null.
 -         // We'll try to find an appropriate peer to focus.
 - 
 -         for (auto i = 0; i < ComponentPeer::getNumPeers(); ++i)
 -             if (auto* p = ComponentPeer::getPeer (i))
 -                 if (p != getPeer())
 -                     if (auto* view = (UIView*) p->getNativeHandle())
 -                         [view becomeFirstResponder];
 -     }
 - 
 -     void launch() override
 -     {
 -         enterModalState (true, nullptr, true);
 -     }
 - 
 -     void runModally() override
 -     {
 -        #if JUCE_MODAL_LOOPS_PERMITTED
 -         runModalLoop();
 -        #else
 -         jassertfalse;
 -        #endif
 -     }
 - 
 -     void parentHierarchyChanged() override
 -     {
 -         auto* newPeer = dynamic_cast<UIViewComponentPeer*> (getPeer());
 - 
 -         if (peer != newPeer)
 -         {
 -             peer = newPeer;
 - 
 -             if (peer != nullptr)
 -             {
 -                 if (auto* parentController = peer->controller)
 -                     [parentController showViewController: controller.get() sender: parentController];
 - 
 -                 peer->toFront (false);
 -             }
 -         }
 -     }
 - 
 - private:
 -     //==============================================================================
 -     void handleAsyncUpdate() override
 -     {
 -         pickerWasCancelled();
 -     }
 - 
 -     //==============================================================================
 -     static StringArray getUTTypesForWildcards (const String& filterWildcards, String& firstExtension)
 -     {
 -         auto filters = StringArray::fromTokens (filterWildcards, ";", "");
 -         StringArray result;
 - 
 -         firstExtension = {};
 - 
 -         if (! filters.contains ("*") && filters.size() > 0)
 -         {
 -             for (auto filter : filters)
 -             {
 -                 if (filter.isEmpty())
 -                     continue;
 - 
 -                 // iOS only supports file extension wild cards
 -                 jassert (filter.upToLastOccurrenceOf (".", true, false) == "*.");
 - 
 -                 auto fileExtension = filter.fromLastOccurrenceOf (".", false, false);
 -                 CFUniquePtr<CFStringRef> fileExtensionCF (fileExtension.toCFString());
 - 
 -                 if (firstExtension.isEmpty())
 -                     firstExtension = fileExtension;
 - 
 -                 if (auto tag = CFUniquePtr<CFStringRef> (UTTypeCreatePreferredIdentifierForTag (kUTTagClassFilenameExtension, fileExtensionCF.get(), nullptr)))
 -                     result.add (String::fromCFString (tag.get()));
 -             }
 -         }
 -         else
 -         {
 -             result.add ("public.data");
 -         }
 - 
 -         return result;
 -     }
 - 
 -     static String getFilename (const File& path, const String& fallbackExtension)
 -     {
 -         auto filename  = path.getFileNameWithoutExtension();
 -         auto extension = path.getFileExtension().substring (1);
 - 
 -         if (filename.isEmpty())
 -             filename = "Untitled";
 - 
 -         if (extension.isEmpty())
 -             extension = fallbackExtension;
 - 
 -         if (extension.isNotEmpty())
 -             filename += "." + extension;
 - 
 -         return filename;
 -     }
 - 
 -     //==============================================================================
 -     void didPickDocumentsAtURLs (NSArray<NSURL*>* urls)
 -     {
 -         cancelPendingUpdate();
 - 
 -         const auto isWriting =  controller.get().documentPickerMode == UIDocumentPickerModeExportToService
 -                              || controller.get().documentPickerMode == UIDocumentPickerModeMoveToService;
 -         const auto accessOptions = isWriting ? 0 : NSFileCoordinatorReadingWithoutChanges;
 - 
 -         auto* fileCoordinator = [[[NSFileCoordinator alloc] initWithFilePresenter: nil] autorelease];
 -         auto* intents = [[[NSMutableArray alloc] init] autorelease];
 - 
 -         for (NSURL* url in urls)
 -         {
 -             auto* fileAccessIntent = isWriting
 -                                    ? [NSFileAccessIntent writingIntentWithURL: url options: accessOptions]
 -                                    : [NSFileAccessIntent readingIntentWithURL: url options: accessOptions];
 -             [intents addObject: fileAccessIntent];
 -         }
 - 
 -         [fileCoordinator coordinateAccessWithIntents: intents queue: [NSOperationQueue mainQueue] byAccessor: ^(NSError* err)
 -         {
 -             if (err != nil)
 -             {
 -                 auto desc = [err localizedDescription];
 -                 ignoreUnused (desc);
 -                 jassertfalse;
 -                 return;
 -             }
 - 
 -             Array<URL> result;
 - 
 -             for (NSURL* url in urls)
 -             {
 -                 [url startAccessingSecurityScopedResource];
 - 
 -                 NSError* error = nil;
 - 
 -                 auto* bookmark = [url bookmarkDataWithOptions: 0
 -                                includingResourceValuesForKeys: nil
 -                                                 relativeToURL: nil
 -                                                         error: &error];
 - 
 -                 [bookmark retain];
 - 
 -                 [url stopAccessingSecurityScopedResource];
 - 
 -                 URL juceUrl (nsStringToJuce ([url absoluteString]));
 - 
 -                 if (error == nil)
 -                 {
 -                     setURLBookmark (juceUrl, (void*) bookmark);
 -                 }
 -                 else
 -                 {
 -                     auto desc = [error localizedDescription];
 -                     ignoreUnused (desc);
 -                     jassertfalse;
 -                 }
 - 
 -                 result.add (std::move (juceUrl));
 -             }
 - 
 -             owner.finished (std::move (result));
 -         }];
 -     }
 - 
 -     void didPickDocumentAtURL (NSURL* url)
 -     {
 -         didPickDocumentsAtURLs (@[url]);
 -     }
 - 
 -     void pickerWasCancelled()
 -     {
 -         cancelPendingUpdate();
 -         owner.finished ({});
 -         // Calling owner.finished will delete this Pimpl instance, so don't call any more member functions here!
 -     }
 - 
 -     //==============================================================================
 -     struct FileChooserDelegateClass  : public ObjCClass<NSObject<UIDocumentPickerDelegate>>
 -     {
 -         FileChooserDelegateClass()  : ObjCClass<NSObject<UIDocumentPickerDelegate>> ("FileChooserDelegate_")
 -         {
 -             addIvar<Native*> ("owner");
 - 
 -             addMethod (@selector (documentPicker:didPickDocumentAtURL:),   didPickDocumentAtURL);
 -             addMethod (@selector (documentPicker:didPickDocumentsAtURLs:), didPickDocumentsAtURLs);
 -             addMethod (@selector (documentPickerWasCancelled:),            documentPickerWasCancelled);
 - 
 -             addProtocol (@protocol (UIDocumentPickerDelegate));
 - 
 -             registerClass();
 -         }
 - 
 -         static void setOwner (id self, Native* owner)   { object_setInstanceVariable (self, "owner", owner); }
 -         static Native* getOwner (id self)               { return getIvar<Native*> (self, "owner"); }
 - 
 -         //==============================================================================
 -         static void didPickDocumentAtURL (id self, SEL, UIDocumentPickerViewController*, NSURL* url)
 -         {
 -             if (auto* picker = getOwner (self))
 -                 picker->didPickDocumentAtURL (url);
 -         }
 - 
 -         static void didPickDocumentsAtURLs (id self, SEL, UIDocumentPickerViewController*, NSArray<NSURL*>* urls)
 -         {
 -             if (auto* picker = getOwner (self))
 -                 picker->didPickDocumentsAtURLs (urls);
 -         }
 - 
 -         static void documentPickerWasCancelled (id self, SEL, UIDocumentPickerViewController*)
 -         {
 -             if (auto* picker = getOwner (self))
 -                 picker->pickerWasCancelled();
 -         }
 -     };
 - 
 -     struct FileChooserControllerClass  : public ObjCClass<UIDocumentPickerViewController>
 -     {
 -         FileChooserControllerClass()  : ObjCClass<UIDocumentPickerViewController> ("FileChooserController_")
 -         {
 -             addIvar<Native*> ("owner");
 -             addMethod (@selector (viewDidDisappear:), viewDidDisappear);
 - 
 -             registerClass();
 -         }
 - 
 -         static void setOwner (id self, Native* owner)   { object_setInstanceVariable (self, "owner", owner); }
 -         static Native* getOwner (id self)               { return getIvar<Native*> (self, "owner"); }
 - 
 -         //==============================================================================
 -         static void viewDidDisappear (id self, SEL, BOOL animated)
 -         {
 -             sendSuperclassMessage<void> (self, @selector (viewDidDisappear:), animated);
 - 
 -             if (auto* picker = getOwner (self))
 -                 picker->triggerAsyncUpdate();
 -         }
 -     };
 - 
 -     //==============================================================================
 -     FileChooser& owner;
 -     NSUniquePtr<NSObject<UIDocumentPickerDelegate>> delegate;
 -     NSUniquePtr<UIDocumentPickerViewController> controller;
 -     UIViewComponentPeer* peer = nullptr;
 - 
 -     static FileChooserDelegateClass fileChooserDelegateClass;
 -     static FileChooserControllerClass fileChooserControllerClass;
 - 
 -     //==============================================================================
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Native)
 - };
 - 
 - //==============================================================================
 - bool FileChooser::isPlatformDialogAvailable()
 - {
 -    #if JUCE_DISABLE_NATIVE_FILECHOOSERS
 -     return false;
 -    #else
 -     return true;
 -    #endif
 - }
 - 
 - std::shared_ptr<FileChooser::Pimpl> FileChooser::showPlatformDialog (FileChooser& owner, int flags,
 -                                                                      FilePreviewComponent*)
 - {
 -     return std::make_shared<FileChooser::Native> (owner, flags);
 - }
 - 
 - #if JUCE_DEPRECATION_IGNORED
 -  JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 - #endif
 - 
 - } // namespace juce
 
 
  |