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.

juce_FileChooserDialogBox.cpp 9.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  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 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. class FileChooserDialogBox::ContentComponent : public Component
  21. {
  22. public:
  23. ContentComponent (const String& name, const String& desc, FileBrowserComponent& chooser)
  24. : Component (name),
  25. chooserComponent (chooser),
  26. okButton (chooser.getActionVerb()),
  27. cancelButton (TRANS ("Cancel")),
  28. newFolderButton (TRANS ("New Folder")),
  29. instructions (desc)
  30. {
  31. addAndMakeVisible (chooserComponent);
  32. addAndMakeVisible (okButton);
  33. okButton.addShortcut (KeyPress (KeyPress::returnKey));
  34. addAndMakeVisible (cancelButton);
  35. cancelButton.addShortcut (KeyPress (KeyPress::escapeKey));
  36. addChildComponent (newFolderButton);
  37. setInterceptsMouseClicks (false, true);
  38. }
  39. void paint (Graphics& g) override
  40. {
  41. text.draw (g, getLocalBounds().reduced (6)
  42. .removeFromTop ((int) text.getHeight()).toFloat());
  43. }
  44. void resized() override
  45. {
  46. const int buttonHeight = 26;
  47. auto area = getLocalBounds();
  48. text.createLayout (getLookAndFeel().createFileChooserHeaderText (getName(), instructions),
  49. (float) getWidth() - 12.0f);
  50. area.removeFromTop (roundToInt (text.getHeight()) + 10);
  51. chooserComponent.setBounds (area.removeFromTop (area.getHeight() - buttonHeight - 20));
  52. auto buttonArea = area.reduced (16, 10);
  53. okButton.changeWidthToFitText (buttonHeight);
  54. okButton.setBounds (buttonArea.removeFromRight (okButton.getWidth() + 16));
  55. buttonArea.removeFromRight (16);
  56. cancelButton.changeWidthToFitText (buttonHeight);
  57. cancelButton.setBounds (buttonArea.removeFromRight (cancelButton.getWidth()));
  58. newFolderButton.changeWidthToFitText (buttonHeight);
  59. newFolderButton.setBounds (buttonArea.removeFromLeft (newFolderButton.getWidth()));
  60. }
  61. FileBrowserComponent& chooserComponent;
  62. TextButton okButton, cancelButton, newFolderButton;
  63. String instructions;
  64. TextLayout text;
  65. };
  66. //==============================================================================
  67. FileChooserDialogBox::FileChooserDialogBox (const String& name,
  68. const String& instructions,
  69. FileBrowserComponent& chooserComponent,
  70. bool shouldWarn,
  71. Colour backgroundColour,
  72. Component* parentComp)
  73. : ResizableWindow (name, backgroundColour, parentComp == nullptr),
  74. warnAboutOverwritingExistingFiles (shouldWarn)
  75. {
  76. content = new ContentComponent (name, instructions, chooserComponent);
  77. setContentOwned (content, false);
  78. setResizable (true, true);
  79. setResizeLimits (300, 300, 1200, 1000);
  80. content->okButton.onClick = [this] { okButtonPressed(); };
  81. content->cancelButton.onClick = [this] { closeButtonPressed(); };
  82. content->newFolderButton.onClick = [this] { createNewFolder(); };
  83. content->chooserComponent.addListener (this);
  84. FileChooserDialogBox::selectionChanged();
  85. if (parentComp != nullptr)
  86. parentComp->addAndMakeVisible (this);
  87. }
  88. FileChooserDialogBox::~FileChooserDialogBox()
  89. {
  90. content->chooserComponent.removeListener (this);
  91. }
  92. //==============================================================================
  93. #if JUCE_MODAL_LOOPS_PERMITTED
  94. bool FileChooserDialogBox::show (int w, int h)
  95. {
  96. return showAt (-1, -1, w, h);
  97. }
  98. bool FileChooserDialogBox::showAt (int x, int y, int w, int h)
  99. {
  100. if (w <= 0) w = getDefaultWidth();
  101. if (h <= 0) h = 500;
  102. if (x < 0 || y < 0)
  103. centreWithSize (w, h);
  104. else
  105. setBounds (x, y, w, h);
  106. const bool ok = (runModalLoop() != 0);
  107. setVisible (false);
  108. return ok;
  109. }
  110. #endif
  111. void FileChooserDialogBox::centreWithDefaultSize (Component* componentToCentreAround)
  112. {
  113. centreAroundComponent (componentToCentreAround, getDefaultWidth(), 500);
  114. }
  115. int FileChooserDialogBox::getDefaultWidth() const
  116. {
  117. if (auto* previewComp = content->chooserComponent.getPreviewComponent())
  118. return 400 + previewComp->getWidth();
  119. return 600;
  120. }
  121. //==============================================================================
  122. void FileChooserDialogBox::closeButtonPressed()
  123. {
  124. setVisible (false);
  125. }
  126. void FileChooserDialogBox::selectionChanged()
  127. {
  128. content->okButton.setEnabled (content->chooserComponent.currentFileIsValid());
  129. content->newFolderButton.setVisible (content->chooserComponent.isSaveMode()
  130. && content->chooserComponent.getRoot().isDirectory());
  131. }
  132. void FileChooserDialogBox::fileDoubleClicked (const File&)
  133. {
  134. selectionChanged();
  135. content->okButton.triggerClick();
  136. }
  137. void FileChooserDialogBox::fileClicked (const File&, const MouseEvent&) {}
  138. void FileChooserDialogBox::browserRootChanged (const File&) {}
  139. void FileChooserDialogBox::okToOverwriteFileCallback (int result, FileChooserDialogBox* box)
  140. {
  141. if (result != 0 && box != nullptr)
  142. box->exitModalState (1);
  143. }
  144. void FileChooserDialogBox::okButtonPressed()
  145. {
  146. if (warnAboutOverwritingExistingFiles
  147. && content->chooserComponent.isSaveMode()
  148. && content->chooserComponent.getSelectedFile(0).exists())
  149. {
  150. AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
  151. TRANS("File already exists"),
  152. TRANS("There's already a file called: FLNM")
  153. .replace ("FLNM", content->chooserComponent.getSelectedFile(0).getFullPathName())
  154. + "\n\n"
  155. + TRANS("Are you sure you want to overwrite it?"),
  156. TRANS("Overwrite"),
  157. TRANS("Cancel"),
  158. this,
  159. ModalCallbackFunction::forComponent (okToOverwriteFileCallback, this));
  160. }
  161. else
  162. {
  163. exitModalState (1);
  164. }
  165. }
  166. void FileChooserDialogBox::createNewFolderCallback (int result, FileChooserDialogBox* box,
  167. Component::SafePointer<AlertWindow> alert)
  168. {
  169. if (result != 0 && alert != nullptr && box != nullptr)
  170. {
  171. alert->setVisible (false);
  172. box->createNewFolderConfirmed (alert->getTextEditorContents ("Folder Name"));
  173. }
  174. }
  175. void FileChooserDialogBox::createNewFolder()
  176. {
  177. auto parent = content->chooserComponent.getRoot();
  178. if (parent.isDirectory())
  179. {
  180. auto* aw = new AlertWindow (TRANS("New Folder"),
  181. TRANS("Please enter the name for the folder"),
  182. AlertWindow::NoIcon, this);
  183. aw->addTextEditor ("Folder Name", String(), String(), false);
  184. aw->addButton (TRANS("Create Folder"), 1, KeyPress (KeyPress::returnKey));
  185. aw->addButton (TRANS("Cancel"), 0, KeyPress (KeyPress::escapeKey));
  186. aw->enterModalState (true,
  187. ModalCallbackFunction::forComponent (createNewFolderCallback, this,
  188. Component::SafePointer<AlertWindow> (aw)),
  189. true);
  190. }
  191. }
  192. void FileChooserDialogBox::createNewFolderConfirmed (const String& nameFromDialog)
  193. {
  194. auto name = File::createLegalFileName (nameFromDialog);
  195. if (! name.isEmpty())
  196. {
  197. auto parent = content->chooserComponent.getRoot();
  198. if (! parent.getChildFile (name).createDirectory())
  199. AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
  200. TRANS ("New Folder"),
  201. TRANS ("Couldn't create the folder!"));
  202. content->chooserComponent.refresh();
  203. }
  204. }
  205. } // namespace juce