mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
MultiDocumentPanel: Fix reporting wrong active document, avoid reordering
This commit is contained in:
parent
0adbfee99d
commit
3acc71f7df
3 changed files with 154 additions and 100 deletions
|
|
@ -151,6 +151,12 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void activeDocumentChanged() override
|
||||
{
|
||||
if (auto* activeDoc = getActiveDocument())
|
||||
Logger::outputDebugString ("activeDocumentChanged() to " + activeDoc->getName());
|
||||
}
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DemoMultiDocumentPanel)
|
||||
};
|
||||
|
|
@ -171,9 +177,26 @@ public:
|
|||
showInTabsButton.onClick = [this] { updateLayoutMode(); };
|
||||
addAndMakeVisible (showInTabsButton);
|
||||
|
||||
addNoteButton.onClick = [this] { addNote ("Note " + String (multiDocumentPanel.getNumDocuments() + 1), "Hello World!"); };
|
||||
oneDocShouldBeFullscreenButton.onClick = [this]
|
||||
{
|
||||
multiDocumentPanel.useFullscreenWhenOneDocument (oneDocShouldBeFullscreenButton.getToggleState());
|
||||
};
|
||||
addAndMakeVisible (oneDocShouldBeFullscreenButton);
|
||||
oneDocShouldBeFullscreenButton.setToggleState (false, juce::sendNotification);
|
||||
|
||||
addNoteButton.onClick = [this]
|
||||
{
|
||||
addNote ("Note " + String (noteCounter), "Hello World! " + String (noteCounter));
|
||||
++noteCounter;
|
||||
};
|
||||
addAndMakeVisible (addNoteButton);
|
||||
|
||||
closeActiveDocumentButton.onClick = [this]
|
||||
{
|
||||
multiDocumentPanel.closeDocumentAsync (multiDocumentPanel.getActiveDocument(), false, [] (auto) {});
|
||||
};
|
||||
addAndMakeVisible (closeActiveDocumentButton);
|
||||
|
||||
closeApplicationButton.onClick = [this]
|
||||
{
|
||||
multiDocumentPanel.closeAllDocumentsAsync (true, [] (bool allSaved)
|
||||
|
|
@ -191,7 +214,7 @@ public:
|
|||
addNote ("Notes Demo", "You can drag-and-drop text files onto this page to open them as notes..");
|
||||
addExistingNotes();
|
||||
|
||||
setSize (500, 500);
|
||||
setSize (650, 500);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
|
|
@ -203,10 +226,15 @@ public:
|
|||
{
|
||||
auto area = getLocalBounds();
|
||||
|
||||
auto buttonArea = area.removeFromTop (28).reduced (2);
|
||||
closeApplicationButton.setBounds (buttonArea.removeFromRight (150));
|
||||
addNoteButton .setBounds (buttonArea.removeFromRight (150));
|
||||
showInTabsButton .setBounds (buttonArea);
|
||||
auto topButtonRow = area.removeFromTop (28).reduced (2);
|
||||
|
||||
showInTabsButton .setBounds (topButtonRow.removeFromLeft (150));
|
||||
|
||||
closeApplicationButton .setBounds (topButtonRow.removeFromRight (150));
|
||||
addNoteButton .setBounds (topButtonRow.removeFromRight (150));
|
||||
closeActiveDocumentButton .setBounds (topButtonRow.removeFromRight (150));
|
||||
|
||||
oneDocShouldBeFullscreenButton.setBounds (area.removeFromTop (28).reduced (2).removeFromLeft (240));
|
||||
|
||||
multiDocumentPanel.setBounds (area);
|
||||
}
|
||||
|
|
@ -262,10 +290,13 @@ private:
|
|||
}
|
||||
|
||||
ToggleButton showInTabsButton { "Show with tabs" };
|
||||
ToggleButton oneDocShouldBeFullscreenButton { "Fill screen when only one note is open" };
|
||||
TextButton addNoteButton { "Create a new note" },
|
||||
closeApplicationButton { "Close app" };
|
||||
closeApplicationButton { "Close app" },
|
||||
closeActiveDocumentButton { "Close active document" };
|
||||
|
||||
DemoMultiDocumentPanel multiDocumentPanel;
|
||||
int noteCounter = 1;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MDIDemo)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -56,19 +56,19 @@ void MultiDocumentPanelWindow::closeButtonPressed()
|
|||
void MultiDocumentPanelWindow::activeWindowStatusChanged()
|
||||
{
|
||||
DocumentWindow::activeWindowStatusChanged();
|
||||
updateOrder();
|
||||
updateActiveDocument();
|
||||
}
|
||||
|
||||
void MultiDocumentPanelWindow::broughtToFront()
|
||||
{
|
||||
DocumentWindow::broughtToFront();
|
||||
updateOrder();
|
||||
updateActiveDocument();
|
||||
}
|
||||
|
||||
void MultiDocumentPanelWindow::updateOrder()
|
||||
void MultiDocumentPanelWindow::updateActiveDocument()
|
||||
{
|
||||
if (auto* owner = getOwner())
|
||||
owner->updateOrder();
|
||||
owner->updateActiveDocumentFromUIState();
|
||||
}
|
||||
|
||||
MultiDocumentPanel* MultiDocumentPanelWindow::getOwner() const noexcept
|
||||
|
|
@ -84,7 +84,7 @@ struct MultiDocumentPanel::TabbedComponentInternal : public TabbedComponent
|
|||
void currentTabChanged (int, const String&) override
|
||||
{
|
||||
if (auto* owner = findParentComponentOfClass<MultiDocumentPanel>())
|
||||
owner->updateOrder();
|
||||
owner->updateActiveDocumentFromUIState();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -262,22 +262,85 @@ bool MultiDocumentPanel::addDocument (Component* const component,
|
|||
}
|
||||
|
||||
resized();
|
||||
activeDocumentChanged();
|
||||
updateActiveDocument (component);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MultiDocumentPanel::closeDocumentInternal (Component* component)
|
||||
void MultiDocumentPanel::recreateLayout()
|
||||
{
|
||||
tabComponent.reset();
|
||||
|
||||
for (int i = getNumChildComponents(); --i >= 0;)
|
||||
{
|
||||
std::unique_ptr<MultiDocumentPanelWindow> dw (dynamic_cast<MultiDocumentPanelWindow*> (getChildComponent (i)));
|
||||
|
||||
if (dw != nullptr)
|
||||
{
|
||||
dw->getContentComponent()->getProperties().set ("mdiDocumentPos_", dw->getWindowStateAsString());
|
||||
dw->clearContentComponent();
|
||||
}
|
||||
}
|
||||
|
||||
resized();
|
||||
|
||||
auto tempComps = components;
|
||||
components.clear();
|
||||
|
||||
{
|
||||
// We want to preserve the activeComponent, so we are blocking the changes originating
|
||||
// from addDocument()
|
||||
const ScopedValueSetter<bool> scope { isLayoutBeingChanged, true };
|
||||
|
||||
for (auto* c : tempComps)
|
||||
addDocument (c,
|
||||
Colour ((uint32) static_cast<int> (c->getProperties().getWithDefault ("mdiDocumentBkg_",
|
||||
(int) Colours::white.getARGB()))),
|
||||
MultiDocHelpers::shouldDeleteComp (c));
|
||||
}
|
||||
|
||||
if (activeComponent != nullptr)
|
||||
setActiveDocument (activeComponent);
|
||||
|
||||
updateActiveDocumentFromUIState();
|
||||
}
|
||||
|
||||
void MultiDocumentPanel::closeDocumentInternal (Component* componentToClose)
|
||||
{
|
||||
// Intellisense warns about component being uninitialised.
|
||||
// I'm not sure how a function argument could be uninitialised.
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6001)
|
||||
|
||||
const OptionalScopedPointer<Component> component { componentToClose,
|
||||
MultiDocHelpers::shouldDeleteComp (componentToClose) };
|
||||
|
||||
component->removeComponentListener (this);
|
||||
|
||||
const bool shouldDelete = MultiDocHelpers::shouldDeleteComp (component);
|
||||
component->getProperties().remove ("mdiDocumentDelete_");
|
||||
component->getProperties().remove ("mdiDocumentBkg_");
|
||||
|
||||
const auto removedIndex = components.indexOf (component);
|
||||
|
||||
if (removedIndex < 0)
|
||||
{
|
||||
jassertfalse;
|
||||
return;
|
||||
}
|
||||
|
||||
components.remove (removedIndex);
|
||||
|
||||
// See if the active document needs to change because of closing a document. It should only
|
||||
// change if we closed the active document. If so, the next active document should be the
|
||||
// subsequent one.
|
||||
if (component == activeComponent)
|
||||
{
|
||||
auto* newActiveComponent = components[jmin (removedIndex, components.size() - 1)];
|
||||
updateActiveDocument (newActiveComponent);
|
||||
}
|
||||
|
||||
// We update the UI to reflect the new state, but we want to prevent the UI state callback
|
||||
// to change the active document.
|
||||
const ScopedValueSetter<bool> scope { isLayoutBeingChanged, true };
|
||||
|
||||
if (mode == FloatingWindows)
|
||||
{
|
||||
for (auto* child : getChildren())
|
||||
|
|
@ -292,11 +355,6 @@ void MultiDocumentPanel::closeDocumentInternal (Component* component)
|
|||
}
|
||||
}
|
||||
|
||||
if (shouldDelete)
|
||||
delete component;
|
||||
|
||||
components.removeFirstMatchingValue (component);
|
||||
|
||||
if (isFullscreenWhenOneDocument() && components.size() == 1)
|
||||
{
|
||||
for (int i = getNumChildComponents(); --i >= 0;)
|
||||
|
|
@ -307,13 +365,11 @@ void MultiDocumentPanel::closeDocumentInternal (Component* component)
|
|||
dw->clearContentComponent();
|
||||
}
|
||||
|
||||
addAndMakeVisible (components.getFirst());
|
||||
addAndMakeVisible (getActiveDocument());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
jassert (components.indexOf (component) >= 0);
|
||||
|
||||
if (tabComponent != nullptr)
|
||||
{
|
||||
for (int i = tabComponent->getNumTabs(); --i >= 0;)
|
||||
|
|
@ -325,25 +381,18 @@ void MultiDocumentPanel::closeDocumentInternal (Component* component)
|
|||
removeChildComponent (component);
|
||||
}
|
||||
|
||||
if (shouldDelete)
|
||||
delete component;
|
||||
|
||||
if (tabComponent != nullptr && tabComponent->getNumTabs() <= numDocsBeforeTabsUsed)
|
||||
if (components.size() <= numDocsBeforeTabsUsed && getActiveDocument() != nullptr)
|
||||
{
|
||||
tabComponent.reset();
|
||||
|
||||
components.removeFirstMatchingValue (component);
|
||||
|
||||
if (components.size() > 0 && tabComponent == nullptr)
|
||||
addAndMakeVisible (components.getFirst());
|
||||
addAndMakeVisible (getActiveDocument());
|
||||
}
|
||||
}
|
||||
|
||||
resized();
|
||||
|
||||
// This ensures that the active tab is painted properly when a tab is closed!
|
||||
if (auto* activeComponent = getActiveDocument())
|
||||
setActiveDocument (activeComponent);
|
||||
|
||||
activeDocumentChanged();
|
||||
if (auto* activeDocument = getActiveDocument())
|
||||
setActiveDocument (activeDocument);
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
}
|
||||
|
|
@ -438,15 +487,7 @@ Component* MultiDocumentPanel::getDocument (const int index) const noexcept
|
|||
|
||||
Component* MultiDocumentPanel::getActiveDocument() const noexcept
|
||||
{
|
||||
if (mode == FloatingWindows)
|
||||
{
|
||||
for (auto* child : getChildren())
|
||||
if (auto* dw = dynamic_cast<MultiDocumentPanelWindow*> (child))
|
||||
if (dw->isActiveWindow())
|
||||
return dw->getContentComponent();
|
||||
}
|
||||
|
||||
return components.getLast();
|
||||
return activeComponent;
|
||||
}
|
||||
|
||||
void MultiDocumentPanel::setActiveDocument (Component* component)
|
||||
|
|
@ -490,7 +531,10 @@ void MultiDocumentPanel::setMaximumNumDocuments (const int newNumber)
|
|||
|
||||
void MultiDocumentPanel::useFullscreenWhenOneDocument (const bool shouldUseTabs)
|
||||
{
|
||||
numDocsBeforeTabsUsed = shouldUseTabs ? 1 : 0;
|
||||
const auto newNumDocsBeforeTabsUsed = shouldUseTabs ? 1 : 0;
|
||||
|
||||
if (std::exchange (numDocsBeforeTabsUsed, newNumDocsBeforeTabsUsed) != newNumDocsBeforeTabsUsed)
|
||||
recreateLayout();
|
||||
}
|
||||
|
||||
bool MultiDocumentPanel::isFullscreenWhenOneDocument() const noexcept
|
||||
|
|
@ -501,38 +545,8 @@ bool MultiDocumentPanel::isFullscreenWhenOneDocument() const noexcept
|
|||
//==============================================================================
|
||||
void MultiDocumentPanel::setLayoutMode (const LayoutMode newLayoutMode)
|
||||
{
|
||||
if (mode != newLayoutMode)
|
||||
{
|
||||
mode = newLayoutMode;
|
||||
|
||||
if (mode == FloatingWindows)
|
||||
{
|
||||
tabComponent.reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = getNumChildComponents(); --i >= 0;)
|
||||
{
|
||||
std::unique_ptr<MultiDocumentPanelWindow> dw (dynamic_cast<MultiDocumentPanelWindow*> (getChildComponent (i)));
|
||||
|
||||
if (dw != nullptr)
|
||||
{
|
||||
dw->getContentComponent()->getProperties().set ("mdiDocumentPos_", dw->getWindowStateAsString());
|
||||
dw->clearContentComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resized();
|
||||
|
||||
auto tempComps = components;
|
||||
components.clear();
|
||||
|
||||
for (auto* c : tempComps)
|
||||
addDocument (c,
|
||||
Colour ((uint32) static_cast<int> (c->getProperties().getWithDefault ("mdiDocumentBkg_", (int) Colours::white.getARGB()))),
|
||||
MultiDocHelpers::shouldDeleteComp (c));
|
||||
}
|
||||
if (std::exchange (mode, newLayoutMode) != newLayoutMode)
|
||||
recreateLayout();
|
||||
}
|
||||
|
||||
void MultiDocumentPanel::setBackgroundColour (Colour newBackgroundColour)
|
||||
|
|
@ -590,31 +604,36 @@ void MultiDocumentPanel::componentNameChanged (Component&)
|
|||
}
|
||||
}
|
||||
|
||||
void MultiDocumentPanel::updateOrder()
|
||||
void MultiDocumentPanel::updateActiveDocumentFromUIState()
|
||||
{
|
||||
auto* newActiveComponent = [&]() -> Component*
|
||||
{
|
||||
auto oldList = components;
|
||||
|
||||
if (mode == FloatingWindows)
|
||||
{
|
||||
components.clear();
|
||||
|
||||
for (auto* child : getChildren())
|
||||
if (auto* dw = dynamic_cast<MultiDocumentPanelWindow*> (child))
|
||||
components.add (dw->getContentComponent());
|
||||
}
|
||||
else
|
||||
for (auto* c : components)
|
||||
{
|
||||
if (auto* window = static_cast<MultiDocumentPanelWindow*> (c->getParentComponent()))
|
||||
if (window->isActiveWindow())
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
if (tabComponent != nullptr)
|
||||
{
|
||||
if (auto* current = tabComponent->getCurrentContentComponent())
|
||||
{
|
||||
components.removeFirstMatchingValue (current);
|
||||
components.add (current);
|
||||
}
|
||||
}
|
||||
return current;
|
||||
|
||||
return activeComponent;
|
||||
}();
|
||||
|
||||
updateActiveDocument (newActiveComponent);
|
||||
}
|
||||
|
||||
if (components != oldList)
|
||||
void MultiDocumentPanel::updateActiveDocument (Component* component)
|
||||
{
|
||||
if (isLayoutBeingChanged)
|
||||
return;
|
||||
|
||||
if (std::exchange (activeComponent, component) != component)
|
||||
activeDocumentChanged();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ public:
|
|||
|
||||
private:
|
||||
//==============================================================================
|
||||
void updateOrder();
|
||||
void updateActiveDocument();
|
||||
MultiDocumentPanel* getOwner() const noexcept;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultiDocumentPanelWindow)
|
||||
|
|
@ -362,11 +362,15 @@ private:
|
|||
friend class MultiDocumentPanelWindow;
|
||||
|
||||
Component* getContainerComp (Component*) const;
|
||||
void updateOrder();
|
||||
void updateActiveDocumentFromUIState();
|
||||
void updateActiveDocument (Component*);
|
||||
void addWindow (Component*);
|
||||
void recreateLayout();
|
||||
|
||||
LayoutMode mode = MaximisedWindowsWithTabs;
|
||||
Array<Component*> components;
|
||||
Component* activeComponent = nullptr;
|
||||
bool isLayoutBeingChanged = false;
|
||||
std::unique_ptr<TabbedComponent> tabComponent;
|
||||
Colour backgroundColour { Colours::lightblue };
|
||||
int maximumNumDocuments = 0, numDocsBeforeTabsUsed = 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue