The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

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