| @@ -26,19 +26,22 @@ | |||
| namespace juce | |||
| { | |||
| class FileChooser::Native : private Component, | |||
| public FileChooser::Pimpl | |||
| class FileChooser::Native : public FileChooser::Pimpl, | |||
| public Component, | |||
| private AsyncUpdater | |||
| { | |||
| public: | |||
| Native (FileChooser& fileChooser, int flags) | |||
| : owner (fileChooser) | |||
| { | |||
| String firstFileExtension; | |||
| static FileChooserDelegateClass cls; | |||
| delegate.reset ([cls.createInstance() init]); | |||
| 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) | |||
| @@ -69,47 +72,51 @@ public: | |||
| } | |||
| auto url = [[NSURL alloc] initFileURLWithPath: juceStringToNS (currentFileOrDirectory.getFullPathName())]; | |||
| controller.reset ([[UIDocumentPickerViewController alloc] initWithURL: url | |||
| inMode: pickerMode]); | |||
| controller.reset ([controllerClassInstance initWithURL: url | |||
| inMode: pickerMode]); | |||
| [url release]; | |||
| } | |||
| else | |||
| { | |||
| controller.reset ([[UIDocumentPickerViewController alloc] initWithDocumentTypes: utTypeArray | |||
| inMode: UIDocumentPickerModeOpen]); | |||
| controller.reset ([controllerClassInstance initWithDocumentTypes: utTypeArray | |||
| inMode: UIDocumentPickerModeOpen]); | |||
| } | |||
| FileChooserControllerClass::setOwner (controller.get(), this); | |||
| [controller.get() setDelegate: delegate.get()]; | |||
| [controller.get() setModalTransitionStyle: UIModalTransitionStyleCrossDissolve]; | |||
| setOpaque (false); | |||
| if (SystemStats::isRunningInAppExtensionSandbox()) | |||
| if (fileChooser.parent != nullptr) | |||
| { | |||
| if (fileChooser.parent != nullptr) | |||
| { | |||
| [controller.get() setModalPresentationStyle:UIModalPresentationFullScreen]; | |||
| [controller.get() setModalPresentationStyle: UIModalPresentationFullScreen]; | |||
| auto chooserBounds = fileChooser.parent->getBounds(); | |||
| setBounds (chooserBounds); | |||
| auto chooserBounds = fileChooser.parent->getBounds(); | |||
| setBounds (chooserBounds); | |||
| setAlwaysOnTop (true); | |||
| fileChooser.parent->addAndMakeVisible (this); | |||
| } | |||
| else | |||
| 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! | |||
| jassert (fileChooser.parent != nullptr); | |||
| jassertfalse; | |||
| return; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| auto chooserBounds = Desktop::getInstance().getDisplays().getMainDisplay().userArea; | |||
| setBounds (chooserBounds); | |||
| setAlwaysOnTop (true); | |||
| setVisible (true); | |||
| addToDesktop (0); | |||
| } | |||
| } | |||
| @@ -131,8 +138,6 @@ public: | |||
| #endif | |||
| } | |||
| private: | |||
| //============================================================================== | |||
| void parentHierarchyChanged() override | |||
| { | |||
| auto* newPeer = dynamic_cast<UIViewComponentPeer*> (getPeer()); | |||
| @@ -141,11 +146,23 @@ private: | |||
| { | |||
| peer = newPeer; | |||
| if (auto* parentController = peer->controller) | |||
| [parentController showViewController: controller.get() sender: parentController]; | |||
| 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) | |||
| { | |||
| @@ -182,7 +199,9 @@ private: | |||
| } | |||
| } | |||
| else | |||
| { | |||
| result.add ("public.data"); | |||
| } | |||
| return result; | |||
| } | |||
| @@ -207,6 +226,8 @@ private: | |||
| //============================================================================== | |||
| void didPickDocumentAtURL (NSURL* url) | |||
| { | |||
| cancelPendingUpdate(); | |||
| bool isWriting = controller.get().documentPickerMode == UIDocumentPickerModeExportToService | |||
| | controller.get().documentPickerMode == UIDocumentPickerModeMoveToService; | |||
| @@ -267,9 +288,9 @@ private: | |||
| void pickerWasCancelled() | |||
| { | |||
| Array<URL> chooserResults; | |||
| cancelPendingUpdate(); | |||
| owner.finished (chooserResults); | |||
| owner.finished ({}); | |||
| exitModalState (0); | |||
| } | |||
| @@ -294,21 +315,40 @@ private: | |||
| //============================================================================== | |||
| static void didPickDocumentAtURL (id self, SEL, UIDocumentPickerViewController*, NSURL* url) | |||
| { | |||
| auto picker = getOwner (self); | |||
| if (picker != nullptr) | |||
| if (auto* picker = getOwner (self)) | |||
| picker->didPickDocumentAtURL (url); | |||
| } | |||
| static void documentPickerWasCancelled (id self, SEL, UIDocumentPickerViewController*) | |||
| { | |||
| auto picker = getOwner (self); | |||
| if (picker != nullptr) | |||
| if (auto* picker = getOwner (self)) | |||
| picker->pickerWasCancelled(); | |||
| } | |||
| }; | |||
| struct FileChooserControllerClass : public ObjCClass<UIDocumentPickerViewController> | |||
| { | |||
| FileChooserControllerClass() : ObjCClass<UIDocumentPickerViewController> ("FileChooserController_") | |||
| { | |||
| addIvar<Native*> ("owner"); | |||
| addMethod (@selector (viewDidDisappear:), viewDidDisappear, "v@:@c"); | |||
| 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; | |||
| std::unique_ptr<NSObject<UIDocumentPickerDelegate>, NSObjectDeleter> delegate; | |||
| @@ -316,6 +356,7 @@ private: | |||
| UIViewComponentPeer* peer = nullptr; | |||
| static FileChooserDelegateClass fileChooserDelegateClass; | |||
| static FileChooserControllerClass fileChooserControllerClass; | |||
| //============================================================================== | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Native) | |||