Improved hide / show functionality of dock widgets

This commit is contained in:
Uwe Kindler 2017-03-22 16:08:44 +01:00
parent 0d6f469a36
commit b6ee26adc2
8 changed files with 165 additions and 101 deletions

View File

@ -26,7 +26,7 @@ static ads::CDockWidget* createLongTextLabelDockWidget(QMenu* ViewMenu)
QLabel* l = new QLabel(); QLabel* l = new QLabel();
l->setWordWrap(true); l->setWordWrap(true);
l->setAlignment(Qt::AlignTop | Qt::AlignLeft); l->setAlignment(Qt::AlignTop | Qt::AlignLeft);
l->setText(QString("Lorem Ipsum ist ein einfacher Demo-Text für die Print- " l->setText(QString("Label %1 %2 - Lorem Ipsum ist ein einfacher Demo-Text für die Print- "
"und Schriftindustrie. Lorem Ipsum ist in der Industrie bereits der " "und Schriftindustrie. Lorem Ipsum ist in der Industrie bereits der "
"Standard Demo-Text seit 1500, als ein unbekannter Schriftsteller eine " "Standard Demo-Text seit 1500, als ein unbekannter Schriftsteller eine "
"Hand voll Wörter nahm und diese durcheinander warf um ein Musterbuch zu " "Hand voll Wörter nahm und diese durcheinander warf um ein Musterbuch zu "
@ -34,7 +34,9 @@ static ads::CDockWidget* createLongTextLabelDockWidget(QMenu* ViewMenu)
"Spruch in die elektronische Schriftbearbeitung geschafft (bemerke, nahezu " "Spruch in die elektronische Schriftbearbeitung geschafft (bemerke, nahezu "
"unverändert). Bekannt wurde es 1960, mit dem erscheinen von Letrase, " "unverändert). Bekannt wurde es 1960, mit dem erscheinen von Letrase, "
"welches Passagen von Lorem Ipsum enhielt, so wie Desktop Software wie " "welches Passagen von Lorem Ipsum enhielt, so wie Desktop Software wie "
"Aldus PageMaker - ebenfalls mit Lorem Ipsum.")); "Aldus PageMaker - ebenfalls mit Lorem Ipsum.")
.arg(LabelCount)
.arg(QTime::currentTime().toString("hh:mm:ss:zzz")));
ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Label %1").arg(LabelCount++)); ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Label %1").arg(LabelCount++));
DockWidget->setWidget(l); DockWidget->setWidget(l);

View File

@ -504,6 +504,18 @@ CDockWidget* CDockAreaWidget::currentDockWidget() const
} }
//============================================================================
void CDockAreaWidget::setCurrentDockWidget(CDockWidget* DockWidget)
{
int Index = tabIndex(DockWidget);
if (Index < 0)
{
return;
}
setCurrentIndex(Index);
}
//============================================================================ //============================================================================
void CDockAreaWidget::setCurrentIndex(int index) void CDockAreaWidget::setCurrentIndex(int index)
{ {
@ -530,6 +542,7 @@ void CDockAreaWidget::setCurrentIndex(int index)
if (i == index) if (i == index)
{ {
TitleWidget->show();
TitleWidget->setActiveTab(true); TitleWidget->setActiveTab(true);
d->TabsScrollArea->ensureWidgetVisible(TitleWidget); d->TabsScrollArea->ensureWidgetVisible(TitleWidget);
auto Features = TitleWidget->dockWidget()->features(); auto Features = TitleWidget->dockWidget()->features();
@ -542,6 +555,7 @@ void CDockAreaWidget::setCurrentIndex(int index)
} }
d->ContentsLayout->setCurrentIndex(index); d->ContentsLayout->setCurrentIndex(index);
d->ContentsLayout->currentWidget()->show();
emit currentChanged(index); emit currentChanged(index);
} }
@ -585,6 +599,22 @@ QList<CDockWidget*> CDockAreaWidget::dockWidgets() const
} }
//============================================================================
QList<CDockWidget*> CDockAreaWidget::openDockWidgets() const
{
QList<CDockWidget*> DockWidgetList;
for (int i = 0; i < d->ContentsLayout->count(); ++i)
{
CDockWidget* DockWidget = dockWidget(i);
if (!DockWidget->isClosed())
{
DockWidgetList.append(dockWidget(i));
}
}
return DockWidgetList;
}
//============================================================================ //============================================================================
int CDockAreaWidget::indexOfContentByTitlePos(const QPoint& p, QWidget* exclude) const int CDockAreaWidget::indexOfContentByTitlePos(const QPoint& p, QWidget* exclude) const
{ {
@ -665,6 +695,22 @@ void CDockAreaWidget::updateDockArea()
d->updateTabBar(); d->updateTabBar();
} }
//============================================================================
void CDockAreaWidget::hideEvent(QHideEvent* event)
{
QFrame::hideEvent(event);
emit visibilityChanged(isVisible());
}
//============================================================================
void CDockAreaWidget::showEvent(QShowEvent* event)
{
QFrame::showEvent(event);
emit visibilityChanged(isVisible());
}
} // namespace ads } // namespace ads
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@ -56,6 +56,10 @@ private slots:
void onTabsMenuActionTriggered(QAction* Action); void onTabsMenuActionTriggered(QAction* Action);
void onCloseButtonClicked(); void onCloseButtonClicked();
protected:
virtual void hideEvent(QHideEvent *) override;
virtual void showEvent(QShowEvent *) override;
public: public:
/** /**
* Default Constructor * Default Constructor
@ -120,10 +124,16 @@ public:
int indexOfContentByTitlePos(const QPoint& pos, QWidget* exclude = nullptr) const; int indexOfContentByTitlePos(const QPoint& pos, QWidget* exclude = nullptr) const;
/** /**
* Returns a list of all dock widgets in this dock area * Returns a list of all dock widgets in this dock area.
* This list contains open and closed dock widgets.
*/ */
QList<CDockWidget*> dockWidgets() const; QList<CDockWidget*> dockWidgets() const;
/**
* Returns a list of dock widgets that are not closed
*/
QList<CDockWidget*> openDockWidgets() const;
/** /**
* Returns the number of dock widgets in this area * Returns the number of dock widgets in this area
*/ */
@ -149,6 +159,11 @@ public:
*/ */
CDockWidget* currentDockWidget() const; CDockWidget* currentDockWidget() const;
/**
* Shows the tab with tghe given dock widget
*/
void setCurrentDockWidget(CDockWidget* DockWidget);
public slots: public slots:
/** /**
* This sets the index position of the current tab page. * This sets the index position of the current tab page.
@ -172,6 +187,14 @@ signals:
* @param index * @param index
*/ */
void currentChanged(int index); void currentChanged(int index);
/**
* This signal is emitted if a dock areas visibility changed.
* The visibility changes, if the last dock widget in a dock area is closed
* or if one dock widget in a dock area with only closed dock widgets
* becomes visible
*/
void visibilityChanged(bool Visible);
}; // class DockAreaWidget }; // class DockAreaWidget
} }
// namespace ads // namespace ads

View File

@ -497,6 +497,7 @@ void CDockContainerWidget::removeDockArea(CDockAreaWidget* area)
area->setParent(0); area->setParent(0);
if (!(Splitter && Splitter->count() == 1)) if (!(Splitter && Splitter->count() == 1))
{ {
emit dockAreasRemoved();
return; return;
} }
@ -586,6 +587,7 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi
} }
} }
} // namespace ads } // namespace ads
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@ -52,6 +52,7 @@ class CDockContainerWidget : public QFrame
private: private:
DockContainerWidgetPrivate* d; ///< private data (pimpl) DockContainerWidgetPrivate* d; ///< private data (pimpl)
friend class DockContainerWidgetPrivate; friend class DockContainerWidgetPrivate;
protected: protected:
/** /**
* Handles activation events to update zOrderIndex * Handles activation events to update zOrderIndex

View File

@ -62,6 +62,7 @@ struct DockWidgetPrivate
CDockManager* DockManager = nullptr; CDockManager* DockManager = nullptr;
CDockAreaWidget* DockArea = nullptr; CDockAreaWidget* DockArea = nullptr;
QAction* ToggleViewAction; QAction* ToggleViewAction;
bool Closed = false;
struct CapturedState struct CapturedState
{ {
QString DockTreePosition; QString DockTreePosition;
@ -83,6 +84,16 @@ struct DockWidgetPrivate
* Show dock widget * Show dock widget
*/ */
void showDockWidget(); void showDockWidget();
/**
* Hides a parent splitter if all dock widgets in the splitter are closed
*/
void hideEmptyParentSplitter();
/**
* Hides a dock area if all dock widgets in the area are closed
*/
void hideEmptyParentDockArea();
}; };
// struct DockWidgetPrivate // struct DockWidgetPrivate
@ -131,32 +142,8 @@ void DockWidgetPrivate::capturedState()
//============================================================================ //============================================================================
void DockWidgetPrivate::showDockWidget() void DockWidgetPrivate::showDockWidget()
{ {
/*if (!CapturedState.DockContainer)
{
auto FloatingWidget = new CFloatingDockContainer(_this);
FloatingWidget->setGeometry(CapturedState.GlobalGeometry);
FloatingWidget->show();
return;
}
CDockContainerWidget* DockContainer = CapturedState.DockContainer.data();
QStringList DockTree = this->CapturedState.DockTreePosition.split(' ');
QSplitter* splitter = DockContainer->findChild<QSplitter*>(QString(), Qt::FindDirectChildrenOnly);
while (splitter)
{
}
for (const auto& TreeItem : DockTree)
{
}*/
std::cout << "DockWidgetPrivate::showDockWidget()" << std::endl;
_this->show();
DockArea->show(); DockArea->show();
DockArea->setCurrentIndex(DockArea->tabIndex(_this));
QSplitter* Splitter = internal::findParent<QSplitter*>(_this); QSplitter* Splitter = internal::findParent<QSplitter*>(_this);
if (Splitter) if (Splitter)
{ {
@ -165,6 +152,53 @@ void DockWidgetPrivate::showDockWidget()
} }
//============================================================================
void DockWidgetPrivate::hideEmptyParentSplitter()
{
QSplitter* Splitter = internal::findParent<QSplitter*>(_this);
if (!Splitter)
{
return;
}
for (int i = 0; i < Splitter->count(); ++i)
{
if (Splitter->widget(i)->isVisible())
{
return;
}
}
Splitter->hide();
}
//============================================================================
void DockWidgetPrivate::hideEmptyParentDockArea()
{
auto OpenDockWidgets = DockArea->openDockWidgets();
if (OpenDockWidgets.count() > 1)
{
CDockWidget* NextDockWidget;
if (OpenDockWidgets.last() == _this)
{
NextDockWidget = OpenDockWidgets[OpenDockWidgets.count() - 2];
}
else
{
int NextIndex = OpenDockWidgets.indexOf(_this) + 1;
NextDockWidget = OpenDockWidgets[NextIndex];
}
DockArea->setCurrentDockWidget(NextDockWidget);
}
else
{
DockArea->hide();
}
}
//============================================================================ //============================================================================
CDockWidget::CDockWidget(const QString &title, QWidget *parent) : CDockWidget::CDockWidget(const QString &title, QWidget *parent) :
QFrame(parent), QFrame(parent),
@ -270,6 +304,13 @@ bool CDockWidget::isFloating() const
} }
//============================================================================
bool CDockWidget::isClosed() const
{
return d->Closed;
}
//============================================================================ //============================================================================
QAction* CDockWidget::toggleViewAction() const QAction* CDockWidget::toggleViewAction() const
{ {
@ -280,28 +321,15 @@ QAction* CDockWidget::toggleViewAction() const
//============================================================================ //============================================================================
void CDockWidget::toggleView(bool Open) void CDockWidget::toggleView(bool Open)
{ {
/*if ((d->DockArea != nullptr) == Open)
{
return;
}
if (!Open && d->DockArea)
{
hideDockWidget(true);
}
else if (Open && !d->DockArea)
{
d->showDockWidget();
}*/
if (Open) if (Open)
{ {
d->showDockWidget(); d->showDockWidget();
} }
else else
{ {
hideDockWidget(true); hideDockWidget();
} }
d->Closed = !Open;
} }
@ -315,59 +343,13 @@ void CDockWidget::setDockArea(CDockAreaWidget* DockArea)
//============================================================================ //============================================================================
void CDockWidget::hideDockWidget(bool RemoveFromDockArea) void CDockWidget::hideDockWidget()
{ {
/*d->capturedState(); CDockAreaWidget* DockArea = d->DockArea;
if (d->DockArea && RemoveFromDockArea)
{
d->DockArea->removeDockWidget(this);
}
this->setParent(d->DockManager);
this->setDockArea(nullptr);
// Remove title from dock area widget to prevent its deletion if dock
// area is deleted
d->TitleWidget->setParent(this);*/
std::cout << "CDockWidget::hideDockWidget" << std::endl;
this->hide();
d->ToggleViewAction->setChecked(false); d->ToggleViewAction->setChecked(false);
d->TitleWidget->hide(); d->TitleWidget->hide();
CDockAreaWidget* DockArea = d->DockArea; d->hideEmptyParentDockArea();
for (int i = 0; i < DockArea->count(); ++i) d->hideEmptyParentSplitter();
{
if (DockArea->dockWidget(i)->isVisible())
{
return;
}
}
if (DockArea->count() > 1)
{
if (DockArea->currentIndex() == (DockArea->count() - 1))
{
DockArea->setCurrentIndex(DockArea->currentIndex() - 1);
}
else
{
DockArea->setCurrentIndex(DockArea->currentIndex() + 1);
}
}
QSplitter* Splitter = internal::findParent<QSplitter*>(this);
if (!Splitter)
{
return;
}
std::cout << "DockWidgets " << Splitter->count() << std::endl;
for (int i = 0; i < Splitter->count(); ++i)
{
if (Splitter->widget(i)->isVisible())
{
return;
}
}
Splitter->hide();
} }
} // namespace ads } // namespace ads

View File

@ -71,10 +71,8 @@ protected:
/** /**
* Hide dock widget. * Hide dock widget.
* If RemoveFromDockArea is true, the dock widget will be properly removed
* from dock area.
*/ */
void hideDockWidget(bool RemoveFromDockArea = true); void hideDockWidget();
public: public:
enum DockWidgetFeature enum DockWidgetFeature
@ -157,6 +155,11 @@ public:
*/ */
bool isFloating() const; bool isFloating() const;
/**
* Returns true, if this dock widget is closed.
*/
bool isClosed() const;
/** /**
* Returns a checkable action that can be used to show or close this dock widget. * Returns a checkable action that can be used to show or close this dock widget.
* The action's text is set to the dock widget's window title. * The action's text is set to the dock widget's window title.

View File

@ -172,7 +172,7 @@ CFloatingDockContainer::CFloatingDockContainer(CDockManager* DockManager) :
QWidget(DockManager, Qt::Window), QWidget(DockManager, Qt::Window),
d(new FloatingDockContainerPrivate(this)) d(new FloatingDockContainerPrivate(this))
{ {
setAttribute(Qt::WA_DeleteOnClose); //setAttribute(Qt::WA_DeleteOnClose);
d->DockManager = DockManager; d->DockManager = DockManager;
QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom); QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom);
l->setContentsMargins(0, 0, 0, 0); l->setContentsMargins(0, 0, 0, 0);
@ -210,6 +210,7 @@ CFloatingDockContainer::CFloatingDockContainer(CDockWidget* DockWidget) :
//============================================================================ //============================================================================
CFloatingDockContainer::~CFloatingDockContainer() CFloatingDockContainer::~CFloatingDockContainer()
{ {
std::cout << "~CFloatingDockContainer" << std::endl;
if (d->DockManager) if (d->DockManager)
{ {
d->DockManager->removeFloatingWidget(this); d->DockManager->removeFloatingWidget(this);
@ -269,17 +270,21 @@ void CFloatingDockContainer::closeEvent(QCloseEvent *event)
auto DockWidgets = dockContainer()->dockArea(i)->dockWidgets(); auto DockWidgets = dockContainer()->dockArea(i)->dockWidgets();
for (auto DockWidget : DockWidgets) for (auto DockWidget : DockWidgets)
{ {
DockWidget->hideDockWidget(false); DockWidget->hideDockWidget();
} }
} }
QWidget::closeEvent(event); QWidget::closeEvent(event);
} }
else else
{ {
std::cout << "Closing single tab" << std::endl;
event->ignore();
auto DockArea = dockContainer()->dockArea(0); auto DockArea = dockContainer()->dockArea(0);
DockArea->currentDockWidget()->hideDockWidget(true); DockArea->currentDockWidget()->hideDockWidget();
// As long as there are open dock widgets, we do not close the floating
// window
if (DockArea->openDockWidgets().count())
{
event->ignore();
}
} }
} }