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
9.4KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. class FileChooserDialogBox::ContentComponent : public Component
  18. {
  19. public:
  20. ContentComponent (const String& name, const String& desc, FileBrowserComponent& chooser)
  21. : Component (name),
  22. chooserComponent (chooser),
  23. okButton (chooser.getActionVerb()),
  24. cancelButton (TRANS ("Cancel")),
  25. newFolderButton (TRANS ("New Folder")),
  26. instructions (desc)
  27. {
  28. addAndMakeVisible (&chooserComponent);
  29. addAndMakeVisible (&okButton);
  30. okButton.addShortcut (KeyPress (KeyPress::returnKey));
  31. addAndMakeVisible (&cancelButton);
  32. cancelButton.addShortcut (KeyPress (KeyPress::escapeKey));
  33. addChildComponent (&newFolderButton);
  34. setInterceptsMouseClicks (false, true);
  35. }
  36. void paint (Graphics& g) override
  37. {
  38. text.draw (g, getLocalBounds().reduced (6)
  39. .removeFromTop ((int) text.getHeight()).toFloat());
  40. }
  41. void resized() override
  42. {
  43. const int buttonHeight = 26;
  44. Rectangle<int> area (getLocalBounds());
  45. text.createLayout (getLookAndFeel().createFileChooserHeaderText (getName(), instructions),
  46. getWidth() - 12.0f);
  47. area.removeFromTop (roundToInt (text.getHeight()) + 10);
  48. chooserComponent.setBounds (area.removeFromTop (area.getHeight() - buttonHeight - 20));
  49. Rectangle<int> buttonArea (area.reduced (16, 10));
  50. okButton.changeWidthToFitText (buttonHeight);
  51. okButton.setBounds (buttonArea.removeFromRight (okButton.getWidth() + 16));
  52. buttonArea.removeFromRight (16);
  53. cancelButton.changeWidthToFitText (buttonHeight);
  54. cancelButton.setBounds (buttonArea.removeFromRight (cancelButton.getWidth()));
  55. newFolderButton.changeWidthToFitText (buttonHeight);
  56. newFolderButton.setBounds (buttonArea.removeFromLeft (newFolderButton.getWidth()));
  57. }
  58. FileBrowserComponent& chooserComponent;
  59. TextButton okButton, cancelButton, newFolderButton;
  60. private:
  61. String instructions;
  62. TextLayout text;
  63. };
  64. //==============================================================================
  65. FileChooserDialogBox::FileChooserDialogBox (const String& name,
  66. const String& instructions,
  67. FileBrowserComponent& chooserComponent,
  68. const bool warnAboutOverwritingExistingFiles_,
  69. Colour backgroundColour)
  70. : ResizableWindow (name, backgroundColour, true),
  71. warnAboutOverwritingExistingFiles (warnAboutOverwritingExistingFiles_)
  72. {
  73. content = new ContentComponent (name, instructions, chooserComponent);
  74. setContentOwned (content, false);
  75. setResizable (true, true);
  76. setResizeLimits (300, 300, 1200, 1000);
  77. content->okButton.addListener (this);
  78. content->cancelButton.addListener (this);
  79. content->newFolderButton.addListener (this);
  80. content->chooserComponent.addListener (this);
  81. FileChooserDialogBox::selectionChanged();
  82. }
  83. FileChooserDialogBox::~FileChooserDialogBox()
  84. {
  85. content->chooserComponent.removeListener (this);
  86. }
  87. //==============================================================================
  88. #if JUCE_MODAL_LOOPS_PERMITTED
  89. bool FileChooserDialogBox::show (int w, int h)
  90. {
  91. return showAt (-1, -1, w, h);
  92. }
  93. bool FileChooserDialogBox::showAt (int x, int y, int w, int h)
  94. {
  95. if (w <= 0)
  96. {
  97. Component* const previewComp = content->chooserComponent.getPreviewComponent();
  98. if (previewComp != nullptr)
  99. w = 400 + previewComp->getWidth();
  100. else
  101. w = 600;
  102. }
  103. if (h <= 0)
  104. h = 500;
  105. if (x < 0 || y < 0)
  106. centreWithSize (w, h);
  107. else
  108. setBounds (x, y, w, h);
  109. const bool ok = (runModalLoop() != 0);
  110. setVisible (false);
  111. return ok;
  112. }
  113. #endif
  114. void FileChooserDialogBox::centreWithDefaultSize (Component* componentToCentreAround)
  115. {
  116. Component* const previewComp = content->chooserComponent.getPreviewComponent();
  117. centreAroundComponent (componentToCentreAround,
  118. previewComp != nullptr ? 400 + previewComp->getWidth() : 600,
  119. 500);
  120. }
  121. //==============================================================================
  122. void FileChooserDialogBox::buttonClicked (Button* button)
  123. {
  124. if (button == &(content->okButton))
  125. {
  126. okButtonPressed();
  127. }
  128. else if (button == &(content->cancelButton))
  129. {
  130. closeButtonPressed();
  131. }
  132. else if (button == &(content->newFolderButton))
  133. {
  134. createNewFolder();
  135. }
  136. }
  137. void FileChooserDialogBox::closeButtonPressed()
  138. {
  139. setVisible (false);
  140. }
  141. void FileChooserDialogBox::selectionChanged()
  142. {
  143. content->okButton.setEnabled (content->chooserComponent.currentFileIsValid());
  144. content->newFolderButton.setVisible (content->chooserComponent.isSaveMode()
  145. && content->chooserComponent.getRoot().isDirectory());
  146. }
  147. void FileChooserDialogBox::fileDoubleClicked (const File&)
  148. {
  149. selectionChanged();
  150. content->okButton.triggerClick();
  151. }
  152. void FileChooserDialogBox::fileClicked (const File&, const MouseEvent&) {}
  153. void FileChooserDialogBox::browserRootChanged (const File&) {}
  154. void FileChooserDialogBox::okToOverwriteFileCallback (int result, FileChooserDialogBox* box)
  155. {
  156. if (result != 0 && box != nullptr)
  157. box->exitModalState (1);
  158. }
  159. void FileChooserDialogBox::okButtonPressed()
  160. {
  161. if (warnAboutOverwritingExistingFiles
  162. && content->chooserComponent.isSaveMode()
  163. && content->chooserComponent.getSelectedFile(0).exists())
  164. {
  165. AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
  166. TRANS("File already exists"),
  167. TRANS("There's already a file called: FLMN")
  168. .replace ("FLNM", content->chooserComponent.getSelectedFile(0).getFullPathName())
  169. + "\n\n"
  170. + TRANS("Are you sure you want to overwrite it?"),
  171. TRANS("Overwrite"),
  172. TRANS("Cancel"),
  173. this,
  174. ModalCallbackFunction::forComponent (okToOverwriteFileCallback, this));
  175. }
  176. else
  177. {
  178. exitModalState (1);
  179. }
  180. }
  181. void FileChooserDialogBox::createNewFolderCallback (int result, FileChooserDialogBox* box,
  182. Component::SafePointer<AlertWindow> alert)
  183. {
  184. if (result != 0 && alert != nullptr && box != nullptr)
  185. {
  186. alert->setVisible (false);
  187. box->createNewFolderConfirmed (alert->getTextEditorContents ("Folder Name"));
  188. }
  189. }
  190. void FileChooserDialogBox::createNewFolder()
  191. {
  192. File parent (content->chooserComponent.getRoot());
  193. if (parent.isDirectory())
  194. {
  195. AlertWindow* aw = new AlertWindow (TRANS("New Folder"),
  196. TRANS("Please enter the name for the folder"),
  197. AlertWindow::NoIcon, this);
  198. aw->addTextEditor ("Folder Name", String::empty, String::empty, false);
  199. aw->addButton (TRANS("Create Folder"), 1, KeyPress (KeyPress::returnKey));
  200. aw->addButton (TRANS("Cancel"), 0, KeyPress (KeyPress::escapeKey));
  201. aw->enterModalState (true,
  202. ModalCallbackFunction::forComponent (createNewFolderCallback, this,
  203. Component::SafePointer<AlertWindow> (aw)),
  204. true);
  205. }
  206. }
  207. void FileChooserDialogBox::createNewFolderConfirmed (const String& nameFromDialog)
  208. {
  209. const String name (File::createLegalFileName (nameFromDialog));
  210. if (! name.isEmpty())
  211. {
  212. const File parent (content->chooserComponent.getRoot());
  213. if (! parent.getChildFile (name).createDirectory())
  214. {
  215. AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
  216. TRANS ("New Folder"),
  217. TRANS ("Couldn't create the folder!"));
  218. }
  219. content->chooserComponent.refresh();
  220. }
  221. }