29MultiDocumentPanelWindow::MultiDocumentPanelWindow (Colour backgroundColour)
30 : DocumentWindow (String(), backgroundColour,
31 DocumentWindow::maximiseButton | DocumentWindow::closeButton,
false)
35MultiDocumentPanelWindow::~MultiDocumentPanelWindow()
40void MultiDocumentPanelWindow::maximiseButtonPressed()
42 if (
auto* owner = getOwner())
43 owner->setLayoutMode (MultiDocumentPanel::MaximisedWindowsWithTabs);
48void MultiDocumentPanelWindow::closeButtonPressed()
50 if (
auto* owner = getOwner())
51 owner->closeDocumentAsync (getContentComponent(),
true,
nullptr);
56void MultiDocumentPanelWindow::activeWindowStatusChanged()
58 DocumentWindow::activeWindowStatusChanged();
59 updateActiveDocument();
62void MultiDocumentPanelWindow::broughtToFront()
64 DocumentWindow::broughtToFront();
65 updateActiveDocument();
68void MultiDocumentPanelWindow::updateActiveDocument()
70 if (
auto* owner = getOwner())
71 owner->updateActiveDocumentFromUIState();
74MultiDocumentPanel* MultiDocumentPanelWindow::getOwner() const noexcept
76 return findParentComponentOfClass<MultiDocumentPanel>();
86 if (
auto* owner = findParentComponentOfClass<MultiDocumentPanel>())
87 owner->updateActiveDocumentFromUIState();
93MultiDocumentPanel::MultiDocumentPanel()
98MultiDocumentPanel::~MultiDocumentPanel()
100 for (
int i = components.size(); --i >= 0;)
101 if (
auto* component = components[i])
102 closeDocumentInternal (component);
106namespace MultiDocHelpers
108 static bool shouldDeleteComp (
Component*
const c)
114#if JUCE_MODAL_LOOPS_PERMITTED
115bool MultiDocumentPanel::closeAllDocuments (
const bool checkItsOkToCloseFirst)
117 while (! components.isEmpty())
118 if (! closeDocument (components.getLast(), checkItsOkToCloseFirst))
125void MultiDocumentPanel::closeLastDocumentRecursive (SafePointer<MultiDocumentPanel> parent,
126 bool checkItsOkToCloseFirst,
129 if (parent->components.isEmpty())
131 NullCheckedInvocation::invoke (callback,
true);
135 parent->closeDocumentAsync (parent->components.getLast(),
136 checkItsOkToCloseFirst,
137 [parent, checkItsOkToCloseFirst, callback] (
bool closeResult)
139 if (parent == nullptr)
144 NullCheckedInvocation::invoke (callback, false);
148 parent->closeLastDocumentRecursive (parent, checkItsOkToCloseFirst, std::move (callback));
152void MultiDocumentPanel::closeAllDocumentsAsync (
bool checkItsOkToCloseFirst,
std::function<
void (
bool)> callback)
154 closeLastDocumentRecursive (
this, checkItsOkToCloseFirst, std::move (callback));
157#if JUCE_MODAL_LOOPS_PERMITTED
158bool MultiDocumentPanel::tryToCloseDocument (
Component*)
171void MultiDocumentPanel::addWindow (
Component* component)
173 auto* dw = createNewDocumentWindow();
175 dw->setResizable (
true,
false);
176 dw->setContentNonOwned (component,
true);
177 dw->setName (component->
getName());
180 dw->setBackgroundColour (bkg.isVoid() ? backgroundColour :
Colour ((
uint32) static_cast<
int> (bkg)));
184 if (
auto* topComp = getChildren().getLast())
185 if (topComp->getX() == x && topComp->getY() == x)
188 dw->setTopLeftPosition (x, x);
191 if (pos.toString().isNotEmpty())
192 dw->restoreWindowStateFromString (pos.toString());
194 addAndMakeVisible (dw);
198bool MultiDocumentPanel::addDocument (
Component*
const component,
200 const bool deleteWhenRemoved)
206 if (component ==
nullptr || (maximumNumDocuments > 0 && components.size() >= maximumNumDocuments))
209 components.add (component);
214 if (mode == FloatingWindows)
216 if (isFullscreenWhenOneDocument())
218 if (components.size() == 1)
220 addAndMakeVisible (component);
224 if (components.size() == 2)
225 addWindow (components.getFirst());
227 addWindow (component);
232 addWindow (component);
237 if (tabComponent ==
nullptr && components.size() > numDocsBeforeTabsUsed)
240 addAndMakeVisible (tabComponent.get());
242 auto temp = components;
245 tabComponent->addTab (c->getName(), docColour, c,
false);
251 if (tabComponent !=
nullptr)
252 tabComponent->addTab (component->
getName(), docColour, component,
false);
254 addAndMakeVisible (component);
257 setActiveDocument (component);
261 updateActiveDocument (component);
265void MultiDocumentPanel::recreateLayout()
267 tabComponent.reset();
269 for (
int i = getNumChildComponents(); --i >= 0;)
275 dw->getContentComponent()->getProperties().set (
"mdiDocumentPos_", dw->getWindowStateAsString());
276 dw->clearContentComponent();
282 auto tempComps = components;
288 const ScopedValueSetter<bool> scope { isLayoutBeingChanged,
true };
290 for (
auto* c : tempComps)
292 Colour ((uint32) static_cast<
int> (c->getProperties().getWithDefault (
"mdiDocumentBkg_",
293 (
int) Colours::white.getARGB()))),
294 MultiDocHelpers::shouldDeleteComp (c));
297 if (activeComponent !=
nullptr)
298 setActiveDocument (activeComponent);
300 updateActiveDocumentFromUIState();
303void MultiDocumentPanel::closeDocumentInternal (Component* componentToClose)
307 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6001)
309 const OptionalScopedPointer<Component> component { componentToClose,
310 MultiDocHelpers::shouldDeleteComp (componentToClose) };
317 const auto removedIndex = components.indexOf (component);
319 if (removedIndex < 0)
325 components.remove (removedIndex);
330 if (component == activeComponent)
332 auto* newActiveComponent = components[
jmin (removedIndex, components.size() - 1)];
333 updateActiveDocument (newActiveComponent);
338 const ScopedValueSetter<bool> scope { isLayoutBeingChanged,
true };
340 if (mode == FloatingWindows)
342 for (
auto* child : getChildren())
344 if (
auto* dw =
dynamic_cast<MultiDocumentPanelWindow*
> (child))
346 if (dw->getContentComponent() == component)
354 if (isFullscreenWhenOneDocument() && components.size() == 1)
356 for (
int i = getNumChildComponents(); --i >= 0;)
361 dw->clearContentComponent();
364 addAndMakeVisible (getActiveDocument());
369 if (tabComponent !=
nullptr)
371 for (
int i = tabComponent->getNumTabs(); --i >= 0;)
372 if (tabComponent->getTabContentComponent (i) == component)
373 tabComponent->removeTab (i);
377 removeChildComponent (component);
380 if (components.size() <= numDocsBeforeTabsUsed && getActiveDocument() !=
nullptr)
382 tabComponent.reset();
383 addAndMakeVisible (getActiveDocument());
390 if (
auto* activeDocument = getActiveDocument())
391 setActiveDocument (activeDocument);
393 JUCE_END_IGNORE_WARNINGS_MSVC
396#if JUCE_MODAL_LOOPS_PERMITTED
397bool MultiDocumentPanel::closeDocument (Component* component,
398 const bool checkItsOkToCloseFirst)
402 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6001)
404 if (component ==
nullptr)
407 if (components.contains (component))
409 if (checkItsOkToCloseFirst && ! tryToCloseDocument (component))
412 closeDocumentInternal (component);
421 JUCE_END_IGNORE_WARNINGS_MSVC
425void MultiDocumentPanel::closeDocumentAsync (
Component* component,
426 const bool checkItsOkToCloseFirst,
431 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6001)
433 if (component ==
nullptr)
435 NullCheckedInvocation::invoke (callback,
true);
439 if (components.contains (component))
441 if (checkItsOkToCloseFirst)
443 tryToCloseDocumentAsync (component,
446 if (parent ==
nullptr)
449 if (closedSuccessfully)
450 parent->closeDocumentInternal (component);
452 NullCheckedInvocation::invoke (callback, closedSuccessfully);
458 closeDocumentInternal (component);
465 NullCheckedInvocation::invoke (callback,
true);
467 JUCE_END_IGNORE_WARNINGS_MSVC
470int MultiDocumentPanel::getNumDocuments() const noexcept
472 return components.size();
475Component* MultiDocumentPanel::getDocument (
const int index)
const noexcept
477 return components [index];
480Component* MultiDocumentPanel::getActiveDocument() const noexcept
482 return activeComponent;
485void MultiDocumentPanel::setActiveDocument (
Component* component)
487 jassert (component !=
nullptr);
489 if (mode == FloatingWindows)
491 component = getContainerComp (component);
493 if (component !=
nullptr)
496 else if (tabComponent !=
nullptr)
498 jassert (components.indexOf (component) >= 0);
500 for (
int i = tabComponent->getNumTabs(); --i >= 0;)
502 if (tabComponent->getTabContentComponent (i) == component)
504 tabComponent->setCurrentTabIndex (i);
515void MultiDocumentPanel::activeDocumentChanged()
519void MultiDocumentPanel::setMaximumNumDocuments (
const int newNumber)
521 maximumNumDocuments = newNumber;
524void MultiDocumentPanel::useFullscreenWhenOneDocument (
const bool shouldUseTabs)
526 const auto newNumDocsBeforeTabsUsed = shouldUseTabs ? 1 : 0;
528 if (
std::exchange (numDocsBeforeTabsUsed, newNumDocsBeforeTabsUsed) != newNumDocsBeforeTabsUsed)
532bool MultiDocumentPanel::isFullscreenWhenOneDocument() const noexcept
534 return numDocsBeforeTabsUsed != 0;
538void MultiDocumentPanel::setLayoutMode (
const LayoutMode newLayoutMode)
544void MultiDocumentPanel::setBackgroundColour (
Colour newBackgroundColour)
546 if (backgroundColour != newBackgroundColour)
548 backgroundColour = newBackgroundColour;
549 setOpaque (newBackgroundColour.
isOpaque());
560void MultiDocumentPanel::resized()
562 if (mode == MaximisedWindowsWithTabs || components.size() == numDocsBeforeTabsUsed)
564 for (
auto* child : getChildren())
565 child->setBounds (getLocalBounds());
568 setWantsKeyboardFocus (components.size() == 0);
573 if (mode == FloatingWindows)
575 for (
auto* child : getChildren())
577 if (dw->getContentComponent() == c)
584void MultiDocumentPanel::componentNameChanged (
Component&)
586 if (mode == FloatingWindows)
588 for (
auto* child : getChildren())
590 dw->
setName (dw->getContentComponent()->getName());
592 else if (tabComponent !=
nullptr)
594 for (
int i = tabComponent->getNumTabs(); --i >= 0;)
595 tabComponent->setTabName (i, tabComponent->getTabContentComponent (i)->getName());
599void MultiDocumentPanel::updateActiveDocumentFromUIState()
601 auto* newActiveComponent = [&]() ->
Component*
603 if (mode == FloatingWindows)
605 for (
auto* c : components)
608 if (window->isActiveWindow())
613 if (tabComponent !=
nullptr)
614 if (
auto* current = tabComponent->getCurrentContentComponent())
617 return activeComponent;
620 updateActiveDocument (newActiveComponent);
623void MultiDocumentPanel::updateActiveDocument (Component* component)
625 if (isLayoutBeingChanged)
629 activeDocumentChanged();
Represents a colour, also including a transparency value.
bool isOpaque() const noexcept
Returns true if this colour is completely opaque.
uint32 getARGB() const noexcept
Returns a 32-bit integer that represents this colour.
Holds a pointer to some type of Component, which automatically becomes null if the component is delet...
The base class for all JUCE user-interface objects.
void removeComponentListener(ComponentListener *listenerToRemove)
Removes a component listener.
Component * getParentComponent() const noexcept
Returns the component which this component is inside.
void grabKeyboardFocus()
Tries to give keyboard focus to this component.
void toFront(bool shouldAlsoGainKeyboardFocus)
Brings the component to the front of its siblings.
void addComponentListener(ComponentListener *newListener)
Adds a listener to be told about changes to the component hierarchy or position.
NamedValueSet & getProperties() noexcept
Returns the set of properties that belong to this component.
virtual void setName(const String &newName)
Sets the name of this component.
String getName() const noexcept
Returns the name of this component.
A graphics context, used for drawing a component or image.
void fillAll() const
Fills the context's entire clip region with the current colour or brush.
This is a derivative of DocumentWindow that is used inside a MultiDocumentPanel component.
LayoutMode
The different layout modes available.
bool set(const Identifier &name, const var &newValue)
Changes or adds a named value.
bool remove(const Identifier &name)
Removes a value from the set.
A base class for top-level windows that can be dragged around and resized.
A component with a TabbedButtonBar along one of its sides.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
void currentTabChanged(int, const String &) override
Callback method to indicate the selected tab has been changed.