2020-06-06 03:03:47 +08:00
|
|
|
//============================================================================
|
|
|
|
/// \file DockFocusController.cpp
|
|
|
|
/// \author Uwe Kindler
|
|
|
|
/// \date 05.06.2020
|
|
|
|
/// \brief Implementation of CDockFocusController class
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
// INCLUDES
|
|
|
|
//============================================================================
|
|
|
|
#include "DockFocusController.h"
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
#include <QPointer>
|
|
|
|
#include <QApplication>
|
2020-07-08 14:08:50 +08:00
|
|
|
#include <QAbstractButton>
|
2020-06-06 03:03:47 +08:00
|
|
|
|
|
|
|
#include "DockWidget.h"
|
|
|
|
#include "DockAreaWidget.h"
|
|
|
|
#include "DockWidgetTab.h"
|
|
|
|
#include "DockContainerWidget.h"
|
|
|
|
#include "FloatingDockContainer.h"
|
|
|
|
#include "DockManager.h"
|
|
|
|
#include "DockAreaTitleBar.h"
|
|
|
|
|
2020-06-07 23:28:23 +08:00
|
|
|
#ifdef Q_OS_LINUX
|
|
|
|
#include "linux/FloatingWidgetTitleBar.h"
|
|
|
|
#endif
|
|
|
|
|
2020-06-06 03:03:47 +08:00
|
|
|
namespace ads
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Private data class of CDockFocusController class (pimpl)
|
|
|
|
*/
|
|
|
|
struct DockFocusControllerPrivate
|
|
|
|
{
|
|
|
|
CDockFocusController *_this;
|
|
|
|
QPointer<CDockWidget> FocusedDockWidget = nullptr;
|
|
|
|
QPointer<CDockAreaWidget> FocusedArea = nullptr;
|
2020-07-04 05:24:20 +08:00
|
|
|
CDockWidget* OldFocusedDockWidget = nullptr;
|
2020-06-07 23:28:23 +08:00
|
|
|
#ifdef Q_OS_LINUX
|
2020-07-11 04:08:28 +08:00
|
|
|
QPointer<CFloatingDockContainer> FloatingWidget = nullptr;
|
2020-06-07 23:28:23 +08:00
|
|
|
#endif
|
2020-06-06 03:03:47 +08:00
|
|
|
CDockManager* DockManager;
|
2020-07-13 14:41:30 +08:00
|
|
|
bool ForceFocusChangedSignal = false;
|
2020-06-06 03:03:47 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Private data constructor
|
|
|
|
*/
|
|
|
|
DockFocusControllerPrivate(CDockFocusController *_public);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function updates the focus style of the given dock widget and
|
|
|
|
* the dock area that it belongs to
|
|
|
|
*/
|
|
|
|
void updateDockWidgetFocus(CDockWidget* DockWidget);
|
|
|
|
};
|
|
|
|
// struct DockFocusControllerPrivate
|
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
static void updateDockWidgetFocusStyle(CDockWidget* DockWidget, bool Focused)
|
|
|
|
{
|
|
|
|
DockWidget->setProperty("focused", Focused);
|
|
|
|
DockWidget->tabWidget()->setProperty("focused", Focused);
|
|
|
|
DockWidget->tabWidget()->updateStyle();
|
|
|
|
internal::repolishStyle(DockWidget);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
static void updateDockAreaFocusStyle(CDockAreaWidget* DockArea, bool Focused)
|
|
|
|
{
|
|
|
|
DockArea->setProperty("focused", Focused);
|
|
|
|
internal::repolishStyle(DockArea);
|
|
|
|
internal::repolishStyle(DockArea->titleBar());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
#ifdef Q_OS_LINUX
|
|
|
|
static void updateFloatingWidgetFocusStyle(CFloatingDockContainer* FloatingWidget, bool Focused)
|
|
|
|
{
|
|
|
|
auto TitleBar = qobject_cast<CFloatingWidgetTitleBar*>(FloatingWidget->titleBarWidget());
|
|
|
|
if (!TitleBar)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
TitleBar->setProperty("focused", Focused);
|
|
|
|
TitleBar->updateStyle();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
DockFocusControllerPrivate::DockFocusControllerPrivate(
|
|
|
|
CDockFocusController *_public) :
|
|
|
|
_this(_public)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void DockFocusControllerPrivate::updateDockWidgetFocus(CDockWidget* DockWidget)
|
|
|
|
{
|
2020-07-03 20:55:33 +08:00
|
|
|
if (!DockWidget->features().testFlag(CDockWidget::DockWidgetFocusable))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-06-06 03:03:47 +08:00
|
|
|
CDockAreaWidget* NewFocusedDockArea = nullptr;
|
|
|
|
if (FocusedDockWidget)
|
|
|
|
{
|
|
|
|
updateDockWidgetFocusStyle(FocusedDockWidget, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
CDockWidget* old = FocusedDockWidget;
|
|
|
|
FocusedDockWidget = DockWidget;
|
|
|
|
updateDockWidgetFocusStyle(FocusedDockWidget, true);
|
|
|
|
NewFocusedDockArea = FocusedDockWidget->dockAreaWidget();
|
|
|
|
if (NewFocusedDockArea && (FocusedArea != NewFocusedDockArea))
|
|
|
|
{
|
|
|
|
if (FocusedArea)
|
|
|
|
{
|
|
|
|
QObject::disconnect(FocusedArea, SIGNAL(viewToggled(bool)), _this, SLOT(onFocusedDockAreaViewToggled(bool)));
|
|
|
|
updateDockAreaFocusStyle(FocusedArea, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
FocusedArea = NewFocusedDockArea;
|
|
|
|
updateDockAreaFocusStyle(FocusedArea, true);
|
|
|
|
QObject::connect(FocusedArea, SIGNAL(viewToggled(bool)), _this, SLOT(onFocusedDockAreaViewToggled(bool)));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
auto NewFloatingWidget = FocusedDockWidget->dockContainer()->floatingWidget();
|
|
|
|
if (NewFloatingWidget)
|
|
|
|
{
|
|
|
|
NewFloatingWidget->setProperty("FocusedDockWidget", QVariant::fromValue(DockWidget));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef Q_OS_LINUX
|
|
|
|
// This code is required for styling the floating widget titlebar for linux
|
|
|
|
// depending on the current focus state
|
|
|
|
if (FloatingWidget == NewFloatingWidget)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FloatingWidget)
|
|
|
|
{
|
|
|
|
updateFloatingWidgetFocusStyle(FloatingWidget, false);
|
|
|
|
}
|
|
|
|
FloatingWidget = NewFloatingWidget;
|
|
|
|
|
|
|
|
if (FloatingWidget)
|
|
|
|
{
|
|
|
|
updateFloatingWidgetFocusStyle(FloatingWidget, true);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-07-13 14:41:30 +08:00
|
|
|
if (old == DockWidget && !ForceFocusChangedSignal)
|
2020-07-07 20:38:03 +08:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-13 14:41:30 +08:00
|
|
|
ForceFocusChangedSignal = false;
|
2020-07-04 05:24:20 +08:00
|
|
|
if (DockWidget->isVisible())
|
2020-06-06 03:03:47 +08:00
|
|
|
{
|
|
|
|
emit DockManager->focusedDockWidgetChanged(old, DockWidget);
|
|
|
|
}
|
2020-07-04 05:24:20 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
OldFocusedDockWidget = old;
|
|
|
|
QObject::connect(DockWidget, SIGNAL(visibilityChanged(bool)), _this, SLOT(onDockWidgetVisibilityChanged(bool)));
|
|
|
|
}
|
2020-06-06 03:03:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-07-04 05:24:20 +08:00
|
|
|
//============================================================================
|
|
|
|
void CDockFocusController::onDockWidgetVisibilityChanged(bool Visible)
|
|
|
|
{
|
|
|
|
auto Sender = sender();
|
|
|
|
auto DockWidget = qobject_cast<ads::CDockWidget*>(Sender);
|
|
|
|
disconnect(Sender, SIGNAL(visibilityChanged(bool)), this, SLOT(onDockWidgetVisibilityChanged(bool)));
|
|
|
|
if (DockWidget && Visible)
|
|
|
|
{
|
|
|
|
emit d->DockManager->focusedDockWidgetChanged(d->OldFocusedDockWidget, DockWidget);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-06-06 03:03:47 +08:00
|
|
|
//============================================================================
|
|
|
|
CDockFocusController::CDockFocusController(CDockManager* DockManager) :
|
|
|
|
Super(DockManager),
|
|
|
|
d(new DockFocusControllerPrivate(this))
|
|
|
|
{
|
|
|
|
d->DockManager = DockManager;
|
|
|
|
connect(QApplication::instance(), SIGNAL(focusChanged(QWidget*, QWidget*)),
|
|
|
|
this, SLOT(onApplicationFocusChanged(QWidget*, QWidget*)));
|
|
|
|
connect(d->DockManager, SIGNAL(stateRestored()), SLOT(onStateRestored()));
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
CDockFocusController::~CDockFocusController()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
void CDockFocusController::onApplicationFocusChanged(QWidget* focusedOld, QWidget* focusedNow)
|
|
|
|
{
|
|
|
|
if (d->DockManager->isRestoringState())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-06-09 20:40:13 +08:00
|
|
|
|
2020-07-11 04:08:28 +08:00
|
|
|
ADS_PRINT("CDockFocusController::onApplicationFocusChanged "
|
|
|
|
<< " old: " << focusedOld << " new: " << focusedNow);
|
2020-06-06 03:03:47 +08:00
|
|
|
if (!focusedNow)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-08 14:08:50 +08:00
|
|
|
// If the close button in another tab steals the focus from the current
|
2020-07-08 14:10:27 +08:00
|
|
|
// active dock widget content, i.e. if the user clicks its close button,
|
|
|
|
// then we immediately give the focus back to the previous focused widget
|
|
|
|
// focusedOld
|
2020-07-08 14:08:50 +08:00
|
|
|
if (CDockManager::testConfigFlag(CDockManager::AllTabsHaveCloseButton))
|
|
|
|
{
|
|
|
|
auto OtherDockWidgetTab = internal::findParent<CDockWidgetTab*>(focusedNow);
|
|
|
|
if (OtherDockWidgetTab && focusedOld)
|
|
|
|
{
|
|
|
|
focusedOld->setFocus();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CDockWidget* DockWidget = nullptr;
|
2020-06-06 03:03:47 +08:00
|
|
|
auto DockWidgetTab = qobject_cast<CDockWidgetTab*>(focusedNow);
|
|
|
|
if (DockWidgetTab)
|
|
|
|
{
|
2020-07-13 14:41:30 +08:00
|
|
|
DockWidget = DockWidgetTab->dockWidget();
|
|
|
|
// If the DockWidgetTab "steals" the focus from a widget in the same
|
|
|
|
// DockWidget, then we immediately give the focus back to the previous
|
|
|
|
// focused widget focusedOld
|
|
|
|
if (focusedOld)
|
|
|
|
{
|
|
|
|
auto OldFocusedDockWidget = internal::findParent<CDockWidget*>(focusedOld);
|
|
|
|
if (OldFocusedDockWidget && OldFocusedDockWidget == DockWidget)
|
|
|
|
{
|
|
|
|
focusedOld->setFocus();
|
|
|
|
}
|
|
|
|
}
|
2020-06-06 03:03:47 +08:00
|
|
|
}
|
2020-06-06 20:59:03 +08:00
|
|
|
|
|
|
|
if (!DockWidget)
|
|
|
|
{
|
|
|
|
DockWidget = qobject_cast<CDockWidget*>(focusedNow);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!DockWidget)
|
2020-06-06 03:03:47 +08:00
|
|
|
{
|
|
|
|
DockWidget = internal::findParent<CDockWidget*>(focusedNow);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef Q_OS_LINUX
|
|
|
|
if (!DockWidget)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (!DockWidget || DockWidget->tabWidget()->isHidden())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
d->updateDockWidgetFocus(DockWidget);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-06-06 20:59:03 +08:00
|
|
|
//===========================================================================
|
|
|
|
void CDockFocusController::setDockWidgetFocused(CDockWidget* focusedNow)
|
|
|
|
{
|
|
|
|
d->updateDockWidgetFocus(focusedNow);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-06-06 03:03:47 +08:00
|
|
|
//===========================================================================
|
|
|
|
void CDockFocusController::onFocusedDockAreaViewToggled(bool Open)
|
|
|
|
{
|
|
|
|
if (d->DockManager->isRestoringState())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CDockAreaWidget* DockArea = qobject_cast<CDockAreaWidget*>(sender());
|
|
|
|
if (!DockArea || Open)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto Container = DockArea->dockContainer();
|
|
|
|
auto OpenedDockAreas = Container->openedDockAreas();
|
|
|
|
if (OpenedDockAreas.isEmpty())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-11 04:08:28 +08:00
|
|
|
CDockManager::setWidgetFocus(OpenedDockAreas[0]->currentDockWidget()->tabWidget());
|
2020-06-06 03:03:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
void CDockFocusController::notifyWidgetOrAreaRelocation(QWidget* DroppedWidget)
|
|
|
|
{
|
|
|
|
if (d->DockManager->isRestoringState())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-06-09 20:40:13 +08:00
|
|
|
|
2020-06-06 03:03:47 +08:00
|
|
|
CDockWidget* DockWidget = qobject_cast<CDockWidget*>(DroppedWidget);
|
2020-07-13 14:43:51 +08:00
|
|
|
if (!DockWidget)
|
|
|
|
{
|
|
|
|
CDockAreaWidget* DockArea = qobject_cast<CDockAreaWidget*>(DroppedWidget);
|
|
|
|
if (DockArea)
|
|
|
|
{
|
|
|
|
DockWidget = DockArea->currentDockWidget();
|
|
|
|
}
|
|
|
|
}
|
2020-06-06 03:03:47 +08:00
|
|
|
|
2020-07-13 14:43:51 +08:00
|
|
|
if (!DockWidget)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-06-06 03:03:47 +08:00
|
|
|
|
2020-07-13 14:41:30 +08:00
|
|
|
d->ForceFocusChangedSignal = true;
|
2020-07-13 14:43:51 +08:00
|
|
|
CDockManager::setWidgetFocus(DockWidget->tabWidget());
|
2020-06-06 03:03:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
void CDockFocusController::notifyFloatingWidgetDrop(CFloatingDockContainer* FloatingWidget)
|
|
|
|
{
|
|
|
|
if (!FloatingWidget || d->DockManager->isRestoringState())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto vDockWidget = FloatingWidget->property("FocusedDockWidget");
|
|
|
|
if (!vDockWidget.isValid())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2020-06-09 20:40:13 +08:00
|
|
|
|
2020-06-06 03:03:47 +08:00
|
|
|
auto DockWidget = vDockWidget.value<CDockWidget*>();
|
|
|
|
if (DockWidget)
|
|
|
|
{
|
2020-07-07 20:38:03 +08:00
|
|
|
d->FocusedDockWidget = nullptr;
|
2020-06-06 03:03:47 +08:00
|
|
|
DockWidget->dockAreaWidget()->setCurrentDockWidget(DockWidget);
|
2020-07-11 04:08:28 +08:00
|
|
|
CDockManager::setWidgetFocus(DockWidget->tabWidget());
|
2020-06-06 03:03:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
void CDockFocusController::onStateRestored()
|
|
|
|
{
|
|
|
|
if (d->FocusedDockWidget)
|
|
|
|
{
|
|
|
|
updateDockWidgetFocusStyle(d->FocusedDockWidget, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace ads
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// EOF DockFocusController.cpp
|