Fixed some bugs that caused problems when calling toggleView() with the same state, some refactorings to improve code

This commit is contained in:
Uwe Kindler 2018-09-26 09:57:36 +02:00
parent fcb1846bf5
commit b9b72df9d4
14 changed files with 193 additions and 98 deletions

View File

@ -1,4 +1,5 @@
TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS = \
src \

View File

@ -167,9 +167,10 @@ void CDockAreaTabBar::startFloating(const QPoint& Pos)
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(d->DockArea);
FloatingWidget->startFloating(Pos, Size);
d->FloatingWidget = FloatingWidget;
if (d->FloatingWidget->hasSingleDockWidget())
auto TopLevelDockWidget = d->FloatingWidget->topLevelDockWidget();
if (TopLevelDockWidget)
{
emit d->FloatingWidget->firstDockWidget()->topLevelChanged(true);
TopLevelDockWidget->emitTopLevelChanged(true);
}
}
} // namespace ads

View File

@ -216,7 +216,7 @@ void DockAreaWidgetPrivate::updateTabBar()
return;
}
TitleBar->setVisible(!Container->isFloating() || !Container->hasSingleVisibleDockWidget());
TitleBar->setVisible(!Container->isFloating() || !Container->hasTopLevelDockWidget());
}
@ -287,6 +287,7 @@ CDockAreaWidget::CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget
d->ContentsLayout = new QStackedLayout();
d->ContentsLayout->setContentsMargins(0, 0, 0, 0);
d->ContentsLayout->setSpacing(0);
d->ContentsLayout->setSizeConstraint(QLayout::SetNoConstraint);
d->Layout->addLayout(d->ContentsLayout, 1);
}
@ -651,7 +652,7 @@ void CDockAreaWidget::toggleDockWidgetView(CDockWidget* DockWidget, bool Open)
{
Q_UNUSED(DockWidget);
Q_UNUSED(Open);
updateDockArea();
updateTabBarVisibility();
d->markTabsMenuOutdated();
}
@ -666,7 +667,7 @@ void CDockAreaWidget::onTabsMenuActionTriggered(QAction* Action)
//============================================================================
void CDockAreaWidget::updateDockArea()
void CDockAreaWidget::updateTabBarVisibility()
{
d->updateTabBar();
}
@ -692,7 +693,7 @@ void CDockAreaWidget::saveState(QXmlStreamWriter& s) const
CDockWidget* CDockAreaWidget::nextOpenDockWidget(CDockWidget* DockWidget) const
{
auto OpenDockWidgets = openedDockWidgets();
if (OpenDockWidgets.count() > 1)
if (OpenDockWidgets.count() > 1 || (OpenDockWidgets.count() == 1 && OpenDockWidgets[0] != DockWidget))
{
CDockWidget* NextDockWidget;
if (OpenDockWidgets.last() == DockWidget)

View File

@ -131,6 +131,11 @@ protected:
*/
void hideAreaIfNoVisibleContent();
/**
* Updates the dock area layout and components visibility
*/
void updateTabBarVisibility();
public:
/**
* Default Constructor
@ -217,11 +222,6 @@ public slots:
*/
void setCurrentIndex(int index);
/**
* Updates the dock area layout and components visibility
*/
void updateDockArea();
signals:
/**
* This signal is emitted when user clicks on a tab at an index.

View File

@ -192,8 +192,8 @@ void DockContainerWidgetPrivate::dropIntoContainer(CFloatingDockContainer* Float
CDockContainerWidget* FloatingDockContainer = FloatingWidget->dockContainer();
auto NewDockAreas = FloatingDockContainer->findChildren<CDockAreaWidget*>(
QString(), Qt::FindChildrenRecursively);
CDockWidget* SingleDoppedDockWidget = FloatingDockContainer->singleVisibleDockWidget();
CDockWidget* SingleDockWidget = _this->singleVisibleDockWidget();
CDockWidget* SingleDroppedDockWidget = FloatingDockContainer->topLevelDockWidget();
CDockWidget* SingleDockWidget = _this->topLevelDockWidget();
QSplitter* Splitter = RootSplitter;
if (DockAreas.count() <= 1)
@ -230,15 +230,9 @@ void DockContainerWidgetPrivate::dropIntoContainer(CFloatingDockContainer* Float
RootSplitter = Splitter;
addDockAreasToList(NewDockAreas);
FloatingWidget->deleteLater();
if (SingleDoppedDockWidget)
{
SingleDoppedDockWidget->dockAreaWidget()->updateDockArea();
}
CDockWidget::emitTopLevelEventForWidget(SingleDroppedDockWidget, false);
CDockWidget::emitTopLevelEventForWidget(SingleDockWidget, false);
if (SingleDockWidget)
{
SingleDockWidget->dockAreaWidget()->updateDockArea();
}
// If we dropped the floating widget into the main dock container that does
// not contain any dock widgets, then splitter is invisible and we need to
// show it to display the docked widgets
@ -265,7 +259,7 @@ void DockContainerWidgetPrivate::dropIntoSection(CFloatingDockContainer* Floatin
}
TargetArea->setCurrentIndex(0); // make the topmost widget active
FloatingWidget->deleteLater();
TargetArea->updateDockArea();
TargetArea->updateTabBarVisibility();
return;
}
@ -336,12 +330,12 @@ void DockContainerWidgetPrivate::addDockAreasToList(const QList<CDockAreaWidget*
// is invisible, if the dock are is a single dock area in a floating widget.
if (1 == CountBefore)
{
DockAreas.at(0)->updateDockArea();
DockAreas.at(0)->updateTabBarVisibility();
}
if (1 == NewAreaCount)
{
DockAreas.last()->updateDockArea();
DockAreas.last()->updateTabBarVisibility();
}
emit _this->dockAreasAdded();
@ -539,6 +533,7 @@ bool DockContainerWidgetPrivate::restoreDockArea(QXmlStreamReader& s,
// of the dock areas during application startup
DockArea->hide();
DockWidget->setToggleViewActionChecked(!Closed);
DockWidget->setClosedState(Closed);
DockWidget->setProperty("closed", Closed);
DockWidget->setProperty("dirty", false);
}
@ -599,7 +594,7 @@ CDockAreaWidget* DockContainerWidgetPrivate::dockWidgetIntoContainer(DockWidgetA
CDockAreaWidget* NewDockArea = new CDockAreaWidget(DockManager, _this);
NewDockArea->addDockWidget(Dockwidget);
addDockArea(NewDockArea, area);
NewDockArea->updateDockArea();
NewDockArea->updateTabBarVisibility();
LastAddedAreaCache[areaIdToIndex(area)] = NewDockArea;
return NewDockArea;
}
@ -642,7 +637,7 @@ void DockContainerWidgetPrivate::addDockArea(CDockAreaWidget* NewDockArea, DockW
}
DockAreas.append(NewDockArea);
NewDockArea->updateDockArea();
NewDockArea->updateTabBarVisibility();
emit _this->dockAreasAdded();
}
@ -876,12 +871,11 @@ void CDockContainerWidget::removeDockArea(CDockAreaWidget* area)
delete Splitter;
emitAndExit:
// Updated the title bar visibility of the dock widget if there is only
CDockWidget* TopLevelWidget = topLevelDockWidget();
// Updated the title bar visibility of the dock widget if there is only
// one single visible dock widget
if (hasSingleVisibleDockWidget())
{
openedDockAreas()[0]->updateDockArea();
}
CDockWidget::emitTopLevelEventForWidget(TopLevelWidget, true);
dumpLayout();
emit dockAreasRemoved();
}
@ -931,7 +925,7 @@ int CDockContainerWidget::visibleDockAreaCount() const
int Result = 0;
for (auto DockArea : d->DockAreas)
{
Result += DockArea->isVisible() ? 1 : 0;
Result += DockArea->isVisibleTo(this) ? 1 : 0;
}
return Result;
@ -946,8 +940,8 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi
CDockAreaWidget* DockArea = dockAreaAt(TargetPos);
auto dropArea = InvalidDockWidgetArea;
auto ContainerDropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor();
CDockWidget* TopLevelDockWidget = FloatingWidget->hasSingleDockWidget() ?
FloatingWidget->firstDockWidget() : nullptr;
CDockWidget* TopLevelDockWidget = FloatingWidget->hasTopLevelDockWidget() ?
FloatingWidget->topLevelDockWidget() : nullptr;
if (DockArea)
{
auto dropOverlay = d->DockManager->dockAreaOverlay();
@ -981,7 +975,7 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi
// drop a top level widget that changes from floating to docked now
if (TopLevelDockWidget)
{
emit TopLevelDockWidget->topLevelChanged(false);
TopLevelDockWidget->emitTopLevelChanged(false);
}
}
@ -1107,7 +1101,7 @@ CDockAreaWidget* CDockContainerWidget::lastAddedDockAreaWidget(DockWidgetArea ar
//============================================================================
bool CDockContainerWidget::hasSingleVisibleDockWidget() const
bool CDockContainerWidget::hasTopLevelDockWidget() const
{
auto DockAreas = openedDockAreas();
if (DockAreas.count() != 1)
@ -1120,14 +1114,7 @@ bool CDockContainerWidget::hasSingleVisibleDockWidget() const
//============================================================================
CDockWidget* CDockContainerWidget::firstVisibleDockWidget() const
{
return openedDockAreas()[0]->openedDockWidgets()[0];
}
//============================================================================
CDockWidget* CDockContainerWidget::singleVisibleDockWidget() const
CDockWidget* CDockContainerWidget::topLevelDockWidget() const
{
auto DockAreas = openedDockAreas();
if (DockAreas.count() != 1)
@ -1145,6 +1132,7 @@ CDockWidget* CDockContainerWidget::singleVisibleDockWidget() const
}
} // namespace ads
//---------------------------------------------------------------------------

View File

@ -115,21 +115,16 @@ protected:
/**
* This function returns true if this dock area has only one single
* visible dock widget.
* A top level widget is a real floating widget. Only the isFloating()
* function of top level widgets may returns true.
*/
bool hasSingleVisibleDockWidget() const;
bool hasTopLevelDockWidget() const;
/**
* If hasSingleVisibleDockWidget() returns true, this function returns the
* one and only visible dock widget. Otherwise it returns a nullptr.
*/
CDockWidget* singleVisibleDockWidget() const;
/**
* Returns the first visible dock widget.
* If the function hasSingleVisibleDockWidget() returns true, then this
* function returns the one and only visible dock widget
*/
CDockWidget* firstVisibleDockWidget() const;
CDockWidget* topLevelDockWidget() const;
public:
/**

View File

@ -54,7 +54,6 @@
#include "DockStateSerialization.h"
#include "DockAreaWidget.h"
#include <iostream>
namespace ads
{
@ -390,7 +389,7 @@ bool CDockManager::restoreState(const QByteArray &state, int version)
}
else
{
DockWidget->toggleView(!DockWidget->property("closed").toBool());
DockWidget->toggleViewInternal(!DockWidget->property("closed").toBool());
}
}
@ -403,14 +402,40 @@ bool CDockManager::restoreState(const QByteArray &state, int version)
{
CDockAreaWidget* DockArea = DockContainer->dockArea(i);
int CurrentIndex = DockArea->property("currentIndex").toInt();
int OpenDockWidgetCount = DockArea->openedDockWidgets().count();
if (CurrentIndex < OpenDockWidgetCount && OpenDockWidgetCount > 1 && CurrentIndex > -1)
int DockWidgetCount = DockArea->dockWidgetsCount();
if (CurrentIndex < DockWidgetCount && DockWidgetCount > 1 && CurrentIndex > -1)
{
DockArea->setCurrentIndex(CurrentIndex);
auto DockWidget = DockArea->dockWidget(CurrentIndex);
if (!DockWidget->isClosed())
{
DockArea->setCurrentIndex(CurrentIndex);
}
}
}
}
// Finally we need to send the topLevelChanged() signals for all dock
// widgets if top level changed
for (auto DockContainer : d->Containers)
{
CDockWidget* TopLevelDockWidget = DockContainer->topLevelDockWidget();
if (TopLevelDockWidget)
{
TopLevelDockWidget->emitTopLevelChanged(true);
}
else
{
for (int i = 0; i < DockContainer->dockAreaCount(); ++i)
{
auto DockArea = DockContainer->dockArea(i);
for (auto DockWidget : DockArea->dockWidgets())
{
DockWidget->emitTopLevelChanged(false);
}
}
}
}
emit stateChanged();
return true;
}
@ -528,7 +553,7 @@ void CDockManager::loadPerspectives(QSettings& Settings)
}
//============================================================================
void CDockManager::addToggleViewActionToMenu(QAction* ToggleViewAction,
QAction* CDockManager::addToggleViewActionToMenu(QAction* ToggleViewAction,
const QString& Group, const QIcon& GroupIcon)
{
bool AlphabeticallySorted = (MenuAlphabeticallySorted == d->MenuInsertionOrder);
@ -544,10 +569,12 @@ void CDockManager::addToggleViewActionToMenu(QAction* ToggleViewAction,
}
d->addActionToMenu(ToggleViewAction, GroupMenu, AlphabeticallySorted);
return GroupMenu->menuAction();
}
else
{
d->addActionToMenu(ToggleViewAction, d->ViewMenu, AlphabeticallySorted);
return ToggleViewAction;
}
}

View File

@ -240,8 +240,11 @@ public:
* view menu. I.e. if there is a workbench for each device
* like for spectrometer devices, it is good to group all these
* workbenches under a menu item
* \return If Group is not empty, this function returns the GroupAction
* for this group. If the group is empty, the function returns
* the given ToggleViewAction.
*/
void addToggleViewActionToMenu(QAction* ToggleViewAction,
QAction* addToggleViewActionToMenu(QAction* ToggleViewAction,
const QString& Group = QString(), const QIcon& GroupIcon = QIcon());
/**

View File

@ -37,6 +37,7 @@
#include "DockAreaWidget.h"
namespace ads
{
@ -428,9 +429,16 @@ void CDockOverlay::paintEvent(QPaintEvent* event)
}
QPainter painter(this);
QColor Color = palette().color(QPalette::Active, QPalette::Highlight);
QPen Pen = painter.pen();
Pen.setColor(Color.darker(120));
Pen.setStyle(Qt::SolidLine);
Pen.setWidth(1);
Pen.setCosmetic(true);
painter.setPen(Pen);
Color = Color.lighter(130);
Color.setAlpha(64);
painter.setPen(Qt::NoPen);
painter.fillRect(r, Color);
painter.setBrush(Color);
painter.drawRect(r.adjusted(0, 0, -1, -1));
d->DropAreaRect = r;
}

View File

@ -75,6 +75,7 @@ struct DockWidgetPrivate
Qt::ToolButtonStyle ToolBarStyleFloating = Qt::ToolButtonTextUnderIcon;
QSize ToolBarIconSizeDocked = QSize(16, 16);
QSize ToolBarIconSizeFloating = QSize(24, 24);
bool IsFloatingTopLevel = false;
/**
* Private data constructor
@ -160,6 +161,11 @@ void DockWidgetPrivate::hideDockWidget()
//============================================================================
void DockWidgetPrivate::updateParentDockArea()
{
if (!DockArea)
{
return;
}
auto NextDockWidget = DockArea->nextOpenDockWidget(_this);
if (NextDockWidget)
{
@ -340,17 +346,7 @@ bool CDockWidget::isFloating() const
return false;
}
if (dockContainer()->dockAreaCount() != 1)
{
return false;
}
if (d->DockArea->openDockWidgetsCount() != 1)
{
return false;
}
return true;
return dockContainer()->topLevelDockWidget() == this;
}
@ -405,18 +401,37 @@ void CDockWidget::setToggleViewActionMode(eToggleViewActionMode Mode)
//============================================================================
void CDockWidget::toggleView(bool Open)
{
// If the toggle view action mode is ActionModeShow, then Open is always
// true if the sender is the toggle view action
QAction* Sender = qobject_cast<QAction*>(sender());
CDockContainerWidget* DockContainer = dockContainer();
CDockWidget* SingleDockWidget = nullptr;;
if (Open)
{
SingleDockWidget = DockContainer->singleVisibleDockWidget();
}
if (Sender == d->ToggleViewAction && !d->ToggleViewAction->isCheckable())
{
Open = true;
}
// If the dock widget state is different, then we really need to toggle
// the state. If we are in the right state, then we simply make this
// dock widget the current dock widget
if (d->Closed != !Open)
{
toggleViewInternal(Open);
}
else if (Open && d->DockArea)
{
d->DockArea->setCurrentDockWidget(this);
}
}
//============================================================================
void CDockWidget::toggleViewInternal(bool Open)
{
CDockContainerWidget* DockContainer = dockContainer();
CDockWidget* TopLevelDockWidget = nullptr;;
if (Open)
{
TopLevelDockWidget = DockContainer->topLevelDockWidget();
}
if (Open)
{
@ -430,16 +445,19 @@ void CDockWidget::toggleView(bool Open)
d->ToggleViewAction->blockSignals(true);
d->ToggleViewAction->setChecked(Open);
d->ToggleViewAction->blockSignals(false);
d->DockArea->toggleDockWidgetView(this, Open);
if (d->DockArea)
{
d->DockArea->toggleDockWidgetView(this, Open);
}
if (!Open)
{
SingleDockWidget = DockContainer->singleVisibleDockWidget();
TopLevelDockWidget = DockContainer->topLevelDockWidget();
}
if (SingleDockWidget)
if (TopLevelDockWidget)
{
SingleDockWidget->dockAreaWidget()->updateDockArea();
CDockWidget::emitTopLevelEventForWidget(TopLevelDockWidget, !Open);
}
if (!Open)
@ -471,6 +489,7 @@ void CDockWidget::saveState(QXmlStreamWriter& s) const
//============================================================================
void CDockWidget::flagAsUnassigned()
{
d->Closed = true;
setParent(d->DockManager);
setDockArea(nullptr);
tabWidget()->setParent(this);
@ -610,6 +629,34 @@ void CDockWidget::setToolbarFloatingStyle(bool Floating)
}
//============================================================================
void CDockWidget::emitTopLevelEventForWidget(CDockWidget* TopLevelDockWidget, bool Floating)
{
if (TopLevelDockWidget)
{
TopLevelDockWidget->dockAreaWidget()->updateTabBarVisibility();
TopLevelDockWidget->emitTopLevelChanged(Floating);
}
}
//============================================================================
void CDockWidget::emitTopLevelChanged(bool Floating)
{
if (Floating != d->IsFloatingTopLevel)
{
d->IsFloatingTopLevel = Floating;
emit topLevelChanged(d->IsFloatingTopLevel);
}
}
//============================================================================
void CDockWidget::setClosedState(bool Closed)
{
d->Closed = Closed;
}
} // namespace ads
//---------------------------------------------------------------------------

View File

@ -69,6 +69,9 @@ protected:
friend class CFloatingDockContainer;
friend class CDockManager;
friend struct DockContainerWidgetPrivate;
friend class CDockAreaTabBar;
friend class CDockWidgetTab;
friend struct DockWidgetTabPrivate;
/**
* Assigns the dock manager that manages this dock widget
@ -105,6 +108,31 @@ protected:
*/
void flagAsUnassigned();
/**
* Call this function to emit a topLevelChanged() signal and to update
* the dock area tool bar visibility
*/
static void emitTopLevelEventForWidget(CDockWidget* TopLevelDockWidget, bool Floating);
/**
* Use this function to emit a top level changed event.
* Do never use emit topLevelChanged(). Always use this function because
* it only emits a signal if the floating state has really changed
*/
void emitTopLevelChanged(bool Floating);
/**
* Internal function for modifying the closed state when restoring
* a saved docking state
*/
void setClosedState(bool Closed);
/**
* Internal toggle view function that does not check if the widget
* already is in the given state
*/
void toggleViewInternal(bool Open);
public:
enum DockWidgetFeature
{

View File

@ -197,7 +197,7 @@ bool DockWidgetTabPrivate::startFloating()
auto Overlay = DockWidget->dockManager()->containerOverlay();
Overlay->setAllowedAreas(OuterDockAreas);
this->FloatingWidget = FloatingWidget;
emit DockWidget->topLevelChanged(true);
DockWidget->emitTopLevelChanged(true);
return true;
}

View File

@ -43,6 +43,7 @@
#include "DockWidget.h"
#include "DockOverlay.h"
namespace ads
{
static unsigned int zOrderCounter = 0;
@ -190,7 +191,7 @@ void FloatingDockContainerPrivate::updateDropOverlays(const QPoint& GlobalPos)
ContainerOverlay->setAllowedAreas(VisibleDockAreas > 1 ?
OuterDockAreas : AllDockAreas);
DockWidgetArea ContainerArea = ContainerOverlay->showOverlay(TopContainer);
ContainerOverlay->enableDropPreview(ContainerArea != InvalidDockWidgetArea);
auto DockArea = TopContainer->dockAreaAt(GlobalPos);
if (DockArea && DockArea->isVisible() && VisibleDockAreas > 0)
{
@ -520,21 +521,16 @@ bool CFloatingDockContainer::restoreState(QXmlStreamReader& Stream, bool Testing
//============================================================================
bool CFloatingDockContainer::hasSingleDockWidget() const
bool CFloatingDockContainer::hasTopLevelDockWidget() const
{
if (d->DockContainer->dockAreaCount() != 1)
{
return false;
}
return d->DockContainer->dockArea(0)->dockWidgetsCount() == 1;
return d->DockContainer->hasTopLevelDockWidget();
}
//============================================================================
CDockWidget* CFloatingDockContainer::firstDockWidget() const
CDockWidget* CFloatingDockContainer::topLevelDockWidget() const
{
return d->DockContainer->dockArea(0)->dockWidget(0);
return d->DockContainer->topLevelDockWidget();
}

View File

@ -135,18 +135,18 @@ public:
/**
* This function returns true, if this floating widget has only one single
* dock widget in a single dock area.
* visible dock widget in a single visible dock area.
* The single dock widget is a real top level floating widget because no
* other widgets are docked.
*/
bool hasSingleDockWidget() const;
bool hasTopLevelDockWidget() const;
/**
* This function returns the first dock widget in the first dock area.
* If the function hasSingleDockWidget() returns true, then this function
* returns this single dock widget.
*/
CDockWidget* firstDockWidget() const;
CDockWidget* topLevelDockWidget() const;
}; // class FloatingDockContainer
}
// namespace ads