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.5KB

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