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.

282 lines
9.8KB

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