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.

272 lines
9.2KB

  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. class FileChooserDialogBox::ContentComponent : public Component
  20. {
  21. public:
  22. ContentComponent (const String& name, const String& desc, FileBrowserComponent& chooser)
  23. : Component (name),
  24. chooserComponent (chooser),
  25. okButton (chooser.getActionVerb()),
  26. cancelButton (TRANS ("Cancel")),
  27. newFolderButton (TRANS ("New Folder")),
  28. instructions (desc)
  29. {
  30. addAndMakeVisible (chooserComponent);
  31. addAndMakeVisible (okButton);
  32. okButton.addShortcut (KeyPress (KeyPress::returnKey));
  33. addAndMakeVisible (cancelButton);
  34. cancelButton.addShortcut (KeyPress (KeyPress::escapeKey));
  35. addChildComponent (newFolderButton);
  36. setInterceptsMouseClicks (false, true);
  37. }
  38. void paint (Graphics& g) override
  39. {
  40. text.draw (g, getLocalBounds().reduced (6)
  41. .removeFromTop ((int) text.getHeight()).toFloat());
  42. }
  43. void resized() override
  44. {
  45. const int buttonHeight = 26;
  46. Rectangle<int> area (getLocalBounds());
  47. text.createLayout (getLookAndFeel().createFileChooserHeaderText (getName(), instructions),
  48. getWidth() - 12.0f);
  49. area.removeFromTop (roundToInt (text.getHeight()) + 10);
  50. chooserComponent.setBounds (area.removeFromTop (area.getHeight() - buttonHeight - 20));
  51. Rectangle<int> buttonArea (area.reduced (16, 10));
  52. okButton.changeWidthToFitText (buttonHeight);
  53. okButton.setBounds (buttonArea.removeFromRight (okButton.getWidth() + 16));
  54. buttonArea.removeFromRight (16);
  55. cancelButton.changeWidthToFitText (buttonHeight);
  56. cancelButton.setBounds (buttonArea.removeFromRight (cancelButton.getWidth()));
  57. newFolderButton.changeWidthToFitText (buttonHeight);
  58. newFolderButton.setBounds (buttonArea.removeFromLeft (newFolderButton.getWidth()));
  59. }
  60. FileBrowserComponent& chooserComponent;
  61. TextButton okButton, cancelButton, newFolderButton;
  62. private:
  63. String instructions;
  64. TextLayout text;
  65. };
  66. //==============================================================================
  67. FileChooserDialogBox::FileChooserDialogBox (const String& name,
  68. const String& instructions,
  69. FileBrowserComponent& chooserComponent,
  70. const bool warnAboutOverwritingExistingFiles_,
  71. Colour backgroundColour)
  72. : ResizableWindow (name, backgroundColour, true),
  73. warnAboutOverwritingExistingFiles (warnAboutOverwritingExistingFiles_)
  74. {
  75. content = new ContentComponent (name, instructions, chooserComponent);
  76. setContentOwned (content, false);
  77. setResizable (true, true);
  78. setResizeLimits (300, 300, 1200, 1000);
  79. content->okButton.addListener (this);
  80. content->cancelButton.addListener (this);
  81. content->newFolderButton.addListener (this);
  82. content->chooserComponent.addListener (this);
  83. FileChooserDialogBox::selectionChanged();
  84. }
  85. FileChooserDialogBox::~FileChooserDialogBox()
  86. {
  87. content->chooserComponent.removeListener (this);
  88. }
  89. //==============================================================================
  90. #if JUCE_MODAL_LOOPS_PERMITTED
  91. bool FileChooserDialogBox::show (int w, int h)
  92. {
  93. return showAt (-1, -1, w, h);
  94. }
  95. bool FileChooserDialogBox::showAt (int x, int y, int w, int h)
  96. {
  97. if (w <= 0) w = getDefaultWidth();
  98. if (h <= 0) h = 500;
  99. if (x < 0 || y < 0)
  100. centreWithSize (w, h);
  101. else
  102. setBounds (x, y, w, h);
  103. const bool ok = (runModalLoop() != 0);
  104. setVisible (false);
  105. return ok;
  106. }
  107. #endif
  108. void FileChooserDialogBox::centreWithDefaultSize (Component* componentToCentreAround)
  109. {
  110. centreAroundComponent (componentToCentreAround, getDefaultWidth(), 500);
  111. }
  112. int FileChooserDialogBox::getDefaultWidth() const
  113. {
  114. if (Component* const previewComp = content->chooserComponent.getPreviewComponent())
  115. return 400 + previewComp->getWidth();
  116. return 600;
  117. }
  118. //==============================================================================
  119. void FileChooserDialogBox::buttonClicked (Button* button)
  120. {
  121. if (button == &(content->okButton))
  122. {
  123. okButtonPressed();
  124. }
  125. else if (button == &(content->cancelButton))
  126. {
  127. closeButtonPressed();
  128. }
  129. else if (button == &(content->newFolderButton))
  130. {
  131. createNewFolder();
  132. }
  133. }
  134. void FileChooserDialogBox::closeButtonPressed()
  135. {
  136. setVisible (false);
  137. }
  138. void FileChooserDialogBox::selectionChanged()
  139. {
  140. content->okButton.setEnabled (content->chooserComponent.currentFileIsValid());
  141. content->newFolderButton.setVisible (content->chooserComponent.isSaveMode()
  142. && content->chooserComponent.getRoot().isDirectory());
  143. }
  144. void FileChooserDialogBox::fileDoubleClicked (const File&)
  145. {
  146. selectionChanged();
  147. content->okButton.triggerClick();
  148. }
  149. void FileChooserDialogBox::fileClicked (const File&, const MouseEvent&) {}
  150. void FileChooserDialogBox::browserRootChanged (const File&) {}
  151. void FileChooserDialogBox::okToOverwriteFileCallback (int result, FileChooserDialogBox* box)
  152. {
  153. if (result != 0 && box != nullptr)
  154. box->exitModalState (1);
  155. }
  156. void FileChooserDialogBox::okButtonPressed()
  157. {
  158. if (warnAboutOverwritingExistingFiles
  159. && content->chooserComponent.isSaveMode()
  160. && content->chooserComponent.getSelectedFile(0).exists())
  161. {
  162. AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
  163. TRANS("File already exists"),
  164. TRANS("There's already a file called: FLNM")
  165. .replace ("FLNM", content->chooserComponent.getSelectedFile(0).getFullPathName())
  166. + "\n\n"
  167. + TRANS("Are you sure you want to overwrite it?"),
  168. TRANS("Overwrite"),
  169. TRANS("Cancel"),
  170. this,
  171. ModalCallbackFunction::forComponent (okToOverwriteFileCallback, this));
  172. }
  173. else
  174. {
  175. exitModalState (1);
  176. }
  177. }
  178. void FileChooserDialogBox::createNewFolderCallback (int result, FileChooserDialogBox* box,
  179. Component::SafePointer<AlertWindow> alert)
  180. {
  181. if (result != 0 && alert != nullptr && box != nullptr)
  182. {
  183. alert->setVisible (false);
  184. box->createNewFolderConfirmed (alert->getTextEditorContents ("Folder Name"));
  185. }
  186. }
  187. void FileChooserDialogBox::createNewFolder()
  188. {
  189. File parent (content->chooserComponent.getRoot());
  190. if (parent.isDirectory())
  191. {
  192. AlertWindow* aw = new AlertWindow (TRANS("New Folder"),
  193. TRANS("Please enter the name for the folder"),
  194. AlertWindow::NoIcon, this);
  195. aw->addTextEditor ("Folder Name", String(), String(), false);
  196. aw->addButton (TRANS("Create Folder"), 1, KeyPress (KeyPress::returnKey));
  197. aw->addButton (TRANS("Cancel"), 0, KeyPress (KeyPress::escapeKey));
  198. aw->enterModalState (true,
  199. ModalCallbackFunction::forComponent (createNewFolderCallback, this,
  200. Component::SafePointer<AlertWindow> (aw)),
  201. true);
  202. }
  203. }
  204. void FileChooserDialogBox::createNewFolderConfirmed (const String& nameFromDialog)
  205. {
  206. const String name (File::createLegalFileName (nameFromDialog));
  207. if (! name.isEmpty())
  208. {
  209. const File parent (content->chooserComponent.getRoot());
  210. if (! parent.getChildFile (name).createDirectory())
  211. {
  212. AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
  213. TRANS ("New Folder"),
  214. TRANS ("Couldn't create the folder!"));
  215. }
  216. content->chooserComponent.refresh();
  217. }
  218. }