2 ==============================================================================
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
7 JUCE is an open source library subject to commercial or open-source
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
23 ==============================================================================
29 class FileChooserDialogBox::ContentComponent
: public Component
32 ContentComponent (const String
& name
, const String
& desc
, FileBrowserComponent
& chooser
)
34 chooserComponent (chooser
),
35 okButton (chooser
.getActionVerb()),
36 cancelButton (TRANS ("Cancel")),
37 newFolderButton (TRANS ("New Folder")),
40 addAndMakeVisible (chooserComponent
);
42 addAndMakeVisible (okButton
);
43 okButton
.addShortcut (KeyPress (KeyPress::returnKey
));
45 addAndMakeVisible (cancelButton
);
46 cancelButton
.addShortcut (KeyPress (KeyPress::escapeKey
));
48 addChildComponent (newFolderButton
);
50 setInterceptsMouseClicks (false, true);
53 void paint (Graphics
& g
) override
55 text
.draw (g
, getLocalBounds().reduced (6)
56 .removeFromTop ((int) text
.getHeight()).toFloat());
59 void resized() override
61 const int buttonHeight
= 26;
63 auto area
= getLocalBounds();
65 text
.createLayout (getLookAndFeel().createFileChooserHeaderText (getName(), instructions
),
66 (float) getWidth() - 12.0f
);
68 area
.removeFromTop (roundToInt (text
.getHeight()) + 10);
70 chooserComponent
.setBounds (area
.removeFromTop (area
.getHeight() - buttonHeight
- 20));
71 auto buttonArea
= area
.reduced (16, 10);
73 okButton
.changeWidthToFitText (buttonHeight
);
74 okButton
.setBounds (buttonArea
.removeFromRight (okButton
.getWidth() + 16));
76 buttonArea
.removeFromRight (16);
78 cancelButton
.changeWidthToFitText (buttonHeight
);
79 cancelButton
.setBounds (buttonArea
.removeFromRight (cancelButton
.getWidth()));
81 newFolderButton
.changeWidthToFitText (buttonHeight
);
82 newFolderButton
.setBounds (buttonArea
.removeFromLeft (newFolderButton
.getWidth()));
85 FileBrowserComponent
& chooserComponent
;
86 TextButton okButton
, cancelButton
, newFolderButton
;
91 //==============================================================================
92 FileChooserDialogBox::FileChooserDialogBox (const String
& name
,
93 const String
& instructions
,
94 FileBrowserComponent
& chooserComponent
,
96 Colour backgroundColour
,
97 Component
* parentComp
)
98 : ResizableWindow (name
, backgroundColour
, parentComp
== nullptr),
99 warnAboutOverwritingExistingFiles (shouldWarn
)
101 content
= new ContentComponent (name
, instructions
, chooserComponent
);
102 setContentOwned (content
, false);
104 setResizable (true, true);
105 setResizeLimits (300, 300, 1200, 1000);
107 content
->okButton
.onClick
= [this] { okButtonPressed(); };
108 content
->cancelButton
.onClick
= [this] { closeButtonPressed(); };
109 content
->newFolderButton
.onClick
= [this] { createNewFolder(); };
111 content
->chooserComponent
.addListener (this);
113 FileChooserDialogBox::selectionChanged();
115 if (parentComp
!= nullptr)
116 parentComp
->addAndMakeVisible (this);
118 setAlwaysOnTop (juce_areThereAnyAlwaysOnTopWindows());
121 FileChooserDialogBox::~FileChooserDialogBox()
123 content
->chooserComponent
.removeListener (this);
126 //==============================================================================
127 #if JUCE_MODAL_LOOPS_PERMITTED
128 bool FileChooserDialogBox::show (int w
, int h
)
130 return showAt (-1, -1, w
, h
);
133 bool FileChooserDialogBox::showAt (int x
, int y
, int w
, int h
)
135 if (w
<= 0) w
= getDefaultWidth();
139 centreWithSize (w
, h
);
141 setBounds (x
, y
, w
, h
);
143 const bool ok
= (runModalLoop() != 0);
149 void FileChooserDialogBox::centreWithDefaultSize (Component
* componentToCentreAround
)
151 centreAroundComponent (componentToCentreAround
, getDefaultWidth(), 500);
154 int FileChooserDialogBox::getDefaultWidth() const
156 if (auto* previewComp
= content
->chooserComponent
.getPreviewComponent())
157 return 400 + previewComp
->getWidth();
162 //==============================================================================
163 void FileChooserDialogBox::closeButtonPressed()
168 void FileChooserDialogBox::selectionChanged()
170 content
->okButton
.setEnabled (content
->chooserComponent
.currentFileIsValid());
172 content
->newFolderButton
.setVisible (content
->chooserComponent
.isSaveMode()
173 && content
->chooserComponent
.getRoot().isDirectory());
176 void FileChooserDialogBox::fileDoubleClicked (const File
&)
179 content
->okButton
.triggerClick();
182 void FileChooserDialogBox::fileClicked (const File
&, const MouseEvent
&) {}
183 void FileChooserDialogBox::browserRootChanged (const File
&) {}
185 void FileChooserDialogBox::okToOverwriteFileCallback (int result
, FileChooserDialogBox
* box
)
187 if (result
!= 0 && box
!= nullptr)
188 box
->exitModalState (1);
191 void FileChooserDialogBox::okButtonPressed()
193 if (warnAboutOverwritingExistingFiles
194 && content
->chooserComponent
.isSaveMode()
195 && content
->chooserComponent
.getSelectedFile(0).exists())
197 AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon
,
198 TRANS("File already exists"),
199 TRANS("There's already a file called: FLNM")
200 .replace ("FLNM", content
->chooserComponent
.getSelectedFile(0).getFullPathName())
202 + TRANS("Are you sure you want to overwrite it?"),
206 ModalCallbackFunction::forComponent (okToOverwriteFileCallback
, this));
214 void FileChooserDialogBox::createNewFolderCallback (int result
, FileChooserDialogBox
* box
,
215 Component::SafePointer
<AlertWindow
> alert
)
217 if (result
!= 0 && alert
!= nullptr && box
!= nullptr)
219 alert
->setVisible (false);
220 box
->createNewFolderConfirmed (alert
->getTextEditorContents ("Folder Name"));
224 void FileChooserDialogBox::createNewFolder()
226 auto parent
= content
->chooserComponent
.getRoot();
228 if (parent
.isDirectory())
230 auto* aw
= new AlertWindow (TRANS("New Folder"),
231 TRANS("Please enter the name for the folder"),
232 MessageBoxIconType::NoIcon
, this);
234 aw
->addTextEditor ("Folder Name", String(), String(), false);
235 aw
->addButton (TRANS("Create Folder"), 1, KeyPress (KeyPress::returnKey
));
236 aw
->addButton (TRANS("Cancel"), 0, KeyPress (KeyPress::escapeKey
));
238 aw
->enterModalState (true,
239 ModalCallbackFunction::forComponent (createNewFolderCallback
, this,
240 Component::SafePointer
<AlertWindow
> (aw
)),
245 void FileChooserDialogBox::createNewFolderConfirmed (const String
& nameFromDialog
)
247 auto name
= File::createLegalFileName (nameFromDialog
);
249 if (! name
.isEmpty())
251 auto parent
= content
->chooserComponent
.getRoot();
253 if (! parent
.getChildFile (name
).createDirectory())
254 AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon
,
255 TRANS ("New Folder"),
256 TRANS ("Couldn't create the folder!"));
258 content
->chooserComponent
.refresh();