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

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. class FileChooserDialogBox::ContentComponent : public Component
  19. {
  20. public:
  21. //==============================================================================
  22. ContentComponent (const String& name, const String& instructions_, FileBrowserComponent& chooserComponent_)
  23. : Component (name),
  24. chooserComponent (chooserComponent_),
  25. okButton (chooserComponent_.getActionVerb()),
  26. cancelButton (TRANS ("Cancel")),
  27. newFolderButton (TRANS ("New Folder")),
  28. instructions (instructions_)
  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)
  39. {
  40. g.setColour (getLookAndFeel().findColour (FileChooserDialogBox::titleTextColourId));
  41. text.draw (g);
  42. }
  43. void resized()
  44. {
  45. const int buttonHeight = 26;
  46. Rectangle<int> area (getLocalBounds());
  47. getLookAndFeel().createFileChooserHeaderText (getName(), instructions, text, getWidth());
  48. const Rectangle<float> bb (text.getBoundingBox (0, text.getNumGlyphs(), false));
  49. area.removeFromTop (roundToInt (bb.getBottom()) + 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. GlyphArrangement text;
  65. };
  66. //==============================================================================
  67. FileChooserDialogBox::FileChooserDialogBox (const String& name,
  68. const String& instructions,
  69. FileBrowserComponent& chooserComponent,
  70. const bool warnAboutOverwritingExistingFiles_,
  71. const 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)
  98. {
  99. Component* const previewComp = content->chooserComponent.getPreviewComponent();
  100. if (previewComp != nullptr)
  101. w = 400 + previewComp->getWidth();
  102. else
  103. w = 600;
  104. }
  105. if (h <= 0)
  106. h = 500;
  107. if (x < 0 || y < 0)
  108. centreWithSize (w, h);
  109. else
  110. setBounds (x, y, w, h);
  111. const bool ok = (runModalLoop() != 0);
  112. setVisible (false);
  113. return ok;
  114. }
  115. #endif
  116. void FileChooserDialogBox::centreWithDefaultSize (Component* componentToCentreAround)
  117. {
  118. Component* const previewComp = content->chooserComponent.getPreviewComponent();
  119. centreAroundComponent (componentToCentreAround,
  120. previewComp != nullptr ? 400 + previewComp->getWidth() : 600,
  121. 500);
  122. }
  123. //==============================================================================
  124. void FileChooserDialogBox::buttonClicked (Button* button)
  125. {
  126. if (button == &(content->okButton))
  127. {
  128. okButtonPressed();
  129. }
  130. else if (button == &(content->cancelButton))
  131. {
  132. closeButtonPressed();
  133. }
  134. else if (button == &(content->newFolderButton))
  135. {
  136. createNewFolder();
  137. }
  138. }
  139. void FileChooserDialogBox::closeButtonPressed()
  140. {
  141. setVisible (false);
  142. }
  143. void FileChooserDialogBox::selectionChanged()
  144. {
  145. content->okButton.setEnabled (content->chooserComponent.currentFileIsValid());
  146. content->newFolderButton.setVisible (content->chooserComponent.isSaveMode()
  147. && content->chooserComponent.getRoot().isDirectory());
  148. }
  149. void FileChooserDialogBox::fileDoubleClicked (const File&)
  150. {
  151. selectionChanged();
  152. content->okButton.triggerClick();
  153. }
  154. void FileChooserDialogBox::fileClicked (const File&, const MouseEvent&) {}
  155. void FileChooserDialogBox::browserRootChanged (const File&) {}
  156. void FileChooserDialogBox::okToOverwriteFileCallback (int result, FileChooserDialogBox* box)
  157. {
  158. if (result != 0 && box != nullptr)
  159. box->exitModalState (1);
  160. }
  161. void FileChooserDialogBox::okButtonPressed()
  162. {
  163. if (warnAboutOverwritingExistingFiles
  164. && content->chooserComponent.isSaveMode()
  165. && content->chooserComponent.getSelectedFile(0).exists())
  166. {
  167. AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
  168. TRANS("File already exists"),
  169. TRANS("There's already a file called:")
  170. + "\n\n" + content->chooserComponent.getSelectedFile(0).getFullPathName()
  171. + "\n\n" + 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 ("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 ("name", String::empty, String::empty, false);
  200. aw->addButton (TRANS("ok"), 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. }