Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

281 lines
10KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace juce
  20. {
  21. #if JUCE_MAC
  22. struct FileChooserDelegateClass : public ObjCClass <NSObject>
  23. {
  24. FileChooserDelegateClass() : ObjCClass <NSObject> ("JUCEFileChooser_")
  25. {
  26. addIvar<StringArray*> ("filters");
  27. addIvar<FilePreviewComponent*> ("filePreviewComponent");
  28. addMethod (@selector (dealloc), dealloc, "v@:");
  29. addMethod (@selector (panel:shouldShowFilename:), shouldShowFilename, "c@:@@");
  30. addMethod (@selector (panelSelectionDidChange:), panelSelectionDidChange, "c@");
  31. #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  32. addProtocol (@protocol (NSOpenSavePanelDelegate));
  33. #endif
  34. registerClass();
  35. }
  36. static void setFilters (id self, StringArray* filters) { object_setInstanceVariable (self, "filters", filters); }
  37. static void setFilePreviewComponent (id self, FilePreviewComponent* comp) { object_setInstanceVariable (self, "filePreviewComponent", comp); }
  38. static StringArray* getFilters (id self) { return getIvar<StringArray*> (self, "filters"); }
  39. static FilePreviewComponent* getFilePreviewComponent (id self) { return getIvar<FilePreviewComponent*> (self, "filePreviewComponent"); }
  40. private:
  41. static void dealloc (id self, SEL)
  42. {
  43. delete getFilters (self);
  44. sendSuperclassMessage (self, @selector (dealloc));
  45. }
  46. static BOOL shouldShowFilename (id self, SEL, id /*sender*/, NSString* filename)
  47. {
  48. StringArray* const filters = getFilters (self);
  49. const File f (nsStringToJuce (filename));
  50. for (int i = filters->size(); --i >= 0;)
  51. if (f.getFileName().matchesWildcard ((*filters)[i], true))
  52. return true;
  53. #if (! defined (MAC_OS_X_VERSION_10_7)) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
  54. NSError* error;
  55. NSString* name = [[NSWorkspace sharedWorkspace] typeOfFile: filename error: &error];
  56. if ([name isEqualToString: nsStringLiteral ("com.apple.alias-file")])
  57. {
  58. FSRef ref;
  59. FSPathMakeRef ((const UInt8*) [filename fileSystemRepresentation], &ref, nullptr);
  60. Boolean targetIsFolder = false, wasAliased = false;
  61. FSResolveAliasFileWithMountFlags (&ref, true, &targetIsFolder, &wasAliased, 0);
  62. return wasAliased && targetIsFolder;
  63. }
  64. #endif
  65. return f.isDirectory()
  66. && ! [[NSWorkspace sharedWorkspace] isFilePackageAtPath: filename];
  67. }
  68. static StringArray getSelectedPaths (id sender)
  69. {
  70. StringArray paths;
  71. if ([sender isKindOfClass: [NSOpenPanel class]])
  72. {
  73. NSArray* urls = [(NSOpenPanel*) sender URLs];
  74. for (NSUInteger i = 0; i < [urls count]; ++i)
  75. paths.add (nsStringToJuce ([[urls objectAtIndex: i] path]));
  76. }
  77. else if ([sender isKindOfClass: [NSSavePanel class]])
  78. {
  79. paths.add (nsStringToJuce ([[(NSSavePanel*) sender URL] path]));
  80. }
  81. return paths;
  82. }
  83. static void panelSelectionDidChange (id self, SEL, id sender)
  84. {
  85. // NB: would need to extend FilePreviewComponent to handle the full list rather than just the first one
  86. if (FilePreviewComponent* const previewComp = getFilePreviewComponent (self))
  87. previewComp->selectedFileChanged (File (getSelectedPaths (sender)[0]));
  88. }
  89. };
  90. static NSMutableArray* createAllowedTypesArray (const StringArray& filters)
  91. {
  92. if (filters.size() == 0)
  93. return nil;
  94. NSMutableArray* filterArray = [[[NSMutableArray alloc] init] autorelease];
  95. for (int i = 0; i < filters.size(); ++i)
  96. {
  97. const String f (filters[i].replace ("*.", ""));
  98. if (f == "*")
  99. return nil;
  100. [filterArray addObject: juceStringToNS (f)];
  101. }
  102. return filterArray;
  103. }
  104. //==============================================================================
  105. void FileChooser::showPlatformDialog (Array<File>& results,
  106. const String& title,
  107. const File& currentFileOrDirectory,
  108. const String& filter,
  109. bool selectsDirectory,
  110. bool selectsFiles,
  111. bool isSaveDialogue,
  112. bool /*warnAboutOverwritingExistingFiles*/,
  113. bool selectMultipleFiles,
  114. bool treatFilePackagesAsDirs,
  115. FilePreviewComponent* extraInfoComponent)
  116. {
  117. JUCE_AUTORELEASEPOOL
  118. {
  119. ScopedPointer<TemporaryMainMenuWithStandardCommands> tempMenu;
  120. if (JUCEApplicationBase::isStandaloneApp())
  121. tempMenu = new TemporaryMainMenuWithStandardCommands();
  122. StringArray* filters = new StringArray();
  123. filters->addTokens (filter.replaceCharacters (",:", ";;"), ";", String());
  124. filters->trim();
  125. filters->removeEmptyStrings();
  126. #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  127. typedef NSObject<NSOpenSavePanelDelegate> DelegateType;
  128. #else
  129. typedef NSObject DelegateType;
  130. #endif
  131. static FileChooserDelegateClass cls;
  132. DelegateType* delegate = (DelegateType*) [[cls.createInstance() init] autorelease];
  133. FileChooserDelegateClass::setFilters (delegate, filters);
  134. NSSavePanel* panel = isSaveDialogue ? [NSSavePanel savePanel]
  135. : [NSOpenPanel openPanel];
  136. [panel setTitle: juceStringToNS (title)];
  137. [panel setAllowedFileTypes: createAllowedTypesArray (*filters)];
  138. if (! isSaveDialogue)
  139. {
  140. NSOpenPanel* openPanel = (NSOpenPanel*) panel;
  141. [openPanel setCanChooseDirectories: selectsDirectory];
  142. [openPanel setCanChooseFiles: selectsFiles];
  143. [openPanel setAllowsMultipleSelection: selectMultipleFiles];
  144. [openPanel setResolvesAliases: YES];
  145. if (treatFilePackagesAsDirs)
  146. [openPanel setTreatsFilePackagesAsDirectories: YES];
  147. }
  148. if (extraInfoComponent != nullptr)
  149. {
  150. NSView* view = [[[NSView alloc] initWithFrame: makeNSRect (extraInfoComponent->getLocalBounds())] autorelease];
  151. extraInfoComponent->addToDesktop (0, (void*) view);
  152. extraInfoComponent->setVisible (true);
  153. FileChooserDelegateClass::setFilePreviewComponent (delegate, extraInfoComponent);
  154. [panel setAccessoryView: view];
  155. }
  156. [panel setDelegate: delegate];
  157. if (isSaveDialogue || selectsDirectory)
  158. [panel setCanCreateDirectories: YES];
  159. String directory, filename;
  160. if (currentFileOrDirectory.isDirectory())
  161. {
  162. directory = currentFileOrDirectory.getFullPathName();
  163. }
  164. else
  165. {
  166. directory = currentFileOrDirectory.getParentDirectory().getFullPathName();
  167. filename = currentFileOrDirectory.getFileName();
  168. }
  169. #if defined (MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6)
  170. [panel setDirectoryURL: createNSURLFromFile (directory)];
  171. [panel setNameFieldStringValue: juceStringToNS (filename)];
  172. if ([panel runModal] == 1 /*NSModalResponseOK*/)
  173. #else
  174. if ([panel runModalForDirectory: juceStringToNS (directory)
  175. file: juceStringToNS (filename)] == 1 /*NSModalResponseOK*/)
  176. #endif
  177. {
  178. if (isSaveDialogue)
  179. {
  180. results.add (File (nsStringToJuce ([[panel URL] path])));
  181. }
  182. else
  183. {
  184. NSOpenPanel* openPanel = (NSOpenPanel*) panel;
  185. NSArray* urls = [openPanel URLs];
  186. for (unsigned int i = 0; i < [urls count]; ++i)
  187. results.add (File (nsStringToJuce ([[urls objectAtIndex: i] path])));
  188. }
  189. }
  190. [panel setDelegate: nil];
  191. }
  192. }
  193. bool FileChooser::isPlatformDialogAvailable()
  194. {
  195. #if JUCE_DISABLE_NATIVE_FILECHOOSERS
  196. return false;
  197. #else
  198. return true;
  199. #endif
  200. }
  201. #else
  202. //==============================================================================
  203. bool FileChooser::isPlatformDialogAvailable()
  204. {
  205. return false;
  206. }
  207. void FileChooser::showPlatformDialog (Array<File>&,
  208. const String& /*title*/,
  209. const File& /*currentFileOrDirectory*/,
  210. const String& /*filter*/,
  211. bool /*selectsDirectory*/,
  212. bool /*selectsFiles*/,
  213. bool /*isSaveDialogue*/,
  214. bool /*warnAboutOverwritingExistingFiles*/,
  215. bool /*selectMultipleFiles*/,
  216. bool /*treatFilePackagesAsDirs*/,
  217. FilePreviewComponent*)
  218. {
  219. jassertfalse; //there's no such thing in iOS
  220. }
  221. #endif
  222. } // namespace juce