ADS: Integrate newest base repository commits

998fe9fa11939eb28dd021ca11d5302c4fe2a005
28dc374fc25fcf5a4100c7ad929cb8da690530ed
0e88467f94194d5bea209f6ddc364358ab92899e
d0f4ce324890197683869eafda0f3938ae619b8d
c541f2c69b519eceb76ffc54589175c9fd0da8a6
37d305e50d2c0829f031b71a61e290361eea9f07

- Fix/workaround for escape key issue with remaining overlays
- Clean up if statements according to style guide

Task-number: QDS-1883
Change-Id: I44ddaed67458a75aca91bdd74cd2b5890bd23c38
Reviewed-by: Aleksei German <aleksei.german@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Henning Gruendl
2020-04-06 14:25:11 +02:00
committed by Thomas Hartmann
parent d5ac552314
commit 92c7662acb
6 changed files with 151 additions and 51 deletions

View File

@@ -215,6 +215,7 @@ namespace ADS
DockManager *m_dockManager = nullptr; DockManager *m_dockManager = nullptr;
bool m_updateTitleBarButtons = false; bool m_updateTitleBarButtons = false;
DockWidgetAreas m_allowedAreas = AllDockAreas; DockWidgetAreas m_allowedAreas = AllDockAreas;
QSize m_minSizeHint;
/** /**
* Private data constructor * Private data constructor
@@ -264,6 +265,22 @@ namespace ADS
* Udpates the enable state of the close and detach button * Udpates the enable state of the close and detach button
*/ */
void updateTitleBarButtonStates(); void updateTitleBarButtonStates();
/**
* Scans all contained dock widgets for the max. minimum size hint
*/
void updateMinimumSizeHint()
{
m_minSizeHint = QSize();
for (int i = 0; i < m_contentsLayout->count(); ++i)
{
auto widget = m_contentsLayout->widget(i);
m_minSizeHint.setHeight(qMax(m_minSizeHint.height(),
widget->minimumSizeHint().height()));
m_minSizeHint.setWidth(qMax(m_minSizeHint.width(),
widget->minimumSizeHint().width()));
}
}
}; };
// struct DockAreaWidgetPrivate // struct DockAreaWidgetPrivate
@@ -349,6 +366,10 @@ namespace ADS
d->tabBar()->blockSignals(false); d->tabBar()->blockSignals(false);
tabWidget->setVisible(!dockWidget->isClosed()); tabWidget->setVisible(!dockWidget->isClosed());
dockWidget->setProperty(INDEX_PROPERTY, index); dockWidget->setProperty(INDEX_PROPERTY, index);
d->m_minSizeHint.setHeight(qMax(d->m_minSizeHint.height(),
dockWidget->minimumSizeHint().height()));
d->m_minSizeHint.setWidth(qMax(d->m_minSizeHint.width(),
dockWidget->minimumSizeHint().width()));
if (activate) { if (activate) {
setCurrentIndex(index); setCurrentIndex(index);
} }
@@ -381,6 +402,7 @@ namespace ADS
d->updateTitleBarButtonStates(); d->updateTitleBarButtonStates();
updateTitleBarVisibility(); updateTitleBarVisibility();
d->updateMinimumSizeHint();
auto topLevelDockWidget = dockContainerWidget->topLevelDockWidget(); auto topLevelDockWidget = dockContainerWidget->topLevelDockWidget();
if (topLevelDockWidget) { if (topLevelDockWidget) {
topLevelDockWidget->emitTopLevelChanged(true); topLevelDockWidget->emitTopLevelChanged(true);
@@ -683,4 +705,9 @@ namespace ADS
DockAreaTitleBar *DockAreaWidget::titleBar() const { return d->m_titleBar; } DockAreaTitleBar *DockAreaWidget::titleBar() const { return d->m_titleBar; }
QSize DockAreaWidget::minimumSizeHint() const
{
return d->m_minSizeHint.isValid() ? d->m_minSizeHint : Super::minimumSizeHint();
}
} // namespace ADS } // namespace ADS

View File

@@ -291,6 +291,13 @@ public:
*/ */
void closeOtherAreas(); void closeOtherAreas();
/**
* Returns the largest minimumSizeHint() of the dock widgets in this
* area.
* The minimum size hint is updated if a dock widget is removed or added.
*/
virtual QSize minimumSizeHint() const override;
signals: signals:
/** /**
* This signal is emitted when user clicks on a tab at an index. * This signal is emitted when user clicks on a tab at an index.

View File

@@ -83,6 +83,7 @@ namespace ADS
QSize m_toolBarIconSizeFloating = QSize(24, 24); QSize m_toolBarIconSizeFloating = QSize(24, 24);
bool m_isFloatingTopLevel = false; bool m_isFloatingTopLevel = false;
QList<QAction *> m_titleBarActions; QList<QAction *> m_titleBarActions;
DockWidget::eMinimumSizeHintMode m_minimumSizeHintMode = DockWidget::MinimumSizeHintFromDockWidget;
/** /**
* Private data constructor * Private data constructor
@@ -317,6 +318,11 @@ namespace ADS
} }
} }
void DockWidget::setMinimumSizeHintMode(eMinimumSizeHintMode mode)
{
d->m_minimumSizeHintMode = mode;
}
void DockWidget::toggleView(bool open) void DockWidget::toggleView(bool open)
{ {
// If the toggle view action mode is ActionModeShow, then Open is always // If the toggle view action mode is ActionModeShow, then Open is always
@@ -545,7 +551,13 @@ namespace ADS
void DockWidget::setClosedState(bool closed) { d->m_closed = closed; } void DockWidget::setClosedState(bool closed) { d->m_closed = closed; }
QSize DockWidget::minimumSizeHint() const { return QSize(60, 40); } QSize DockWidget::minimumSizeHint() const
{
if (d->m_minimumSizeHintMode == DockWidget::MinimumSizeHintFromDockWidget || !d->m_widget)
return QSize(60, 40);
else
return d->m_widget->minimumSizeHint();
}
void DockWidget::setFloating() void DockWidget::setFloating()
{ {
@@ -587,6 +599,7 @@ namespace ADS
floatingWidget->hide(); floatingWidget->hide();
} }
deleteDockWidget(); deleteDockWidget();
emit closed();
} else { } else {
toggleView(false); toggleView(false);
} }

View File

@@ -184,6 +184,17 @@ public:
*/ */
enum eInsertMode { AutoScrollArea, ForceScrollArea, ForceNoScrollArea }; enum eInsertMode { AutoScrollArea, ForceScrollArea, ForceNoScrollArea };
/**
* The mode of the minimumSizeHint() that is returned by the DockWidget
* minimumSizeHint() function.
* To ensure, that a dock widget does not block resizing, the dock widget
* reimplements minimumSizeHint() function to return a very small minimum
* size hint. If you would like to adhere the minimumSizeHint() from the
* content widget, the set the minimumSizeHintMode() to
* MinimumSizeHintFromContent.
*/
enum eMinimumSizeHintMode { MinimumSizeHintFromDockWidget, MinimumSizeHintFromContent };
/** /**
* This mode configures the behavior of the toggle view action. * This mode configures the behavior of the toggle view action.
* If the mode if ActionModeToggle, then the toggle view action is * If the mode if ActionModeToggle, then the toggle view action is
@@ -218,7 +229,8 @@ public:
virtual ~DockWidget() override; virtual ~DockWidget() override;
/** /**
* We return a fixed minimum size hint for all dock widgets * We return a fixed minimum size hint or the size hint of the content
* widget if minimum size hint mode is MinimumSizeHintFromContent
*/ */
virtual QSize minimumSizeHint() const override; virtual QSize minimumSizeHint() const override;
@@ -327,6 +339,13 @@ public:
*/ */
void setToggleViewActionMode(eToggleViewActionMode mode); void setToggleViewActionMode(eToggleViewActionMode mode);
/**
* Configures the minimum size hint that is returned by the
* minimumSizeHint() function.
* \see eMinimumSizeHintMode for a detailed description
*/
void setMinimumSizeHintMode(eMinimumSizeHintMode mode);
/** /**
* Sets the dock widget icon that is shown in tabs and in toggle view * Sets the dock widget icon that is shown in tabs and in toggle view
* actions * actions
@@ -339,13 +358,10 @@ public:
QIcon icon() const; QIcon icon() const;
/** /**
* If the WithToolBar layout flag is enabled, then this function returns
* the dock widget toolbar. If the flag is disabled, the function returns
* a nullptr.
* This function returns the dock widget top tool bar. * This function returns the dock widget top tool bar.
* If no toolbar is assigned, this function returns nullptr. To get a valid * If no toolbar is assigned, this function returns nullptr. To get a valid
* toolbar you either need to create a default empty toolbar via * toolbar you either need to create a default empty toolbar via
* createDefaultToolBar() function or you need to assign you custom * createDefaultToolBar() function or you need to assign your custom
* toolbar via setToolBar(). * toolbar via setToolBar().
*/ */
QToolBar *toolBar() const; QToolBar *toolBar() const;

View File

@@ -73,6 +73,7 @@ namespace ADS
QPoint m_dragStartMousePosition; QPoint m_dragStartMousePosition;
DockContainerWidget *m_dropContainer = nullptr; DockContainerWidget *m_dropContainer = nullptr;
DockAreaWidget *m_singleDockArea = nullptr; DockAreaWidget *m_singleDockArea = nullptr;
QPoint m_dragStartPos;
QWidget *m_mouseEventHandler = nullptr; QWidget *m_mouseEventHandler = nullptr;
FloatingWidgetTitleBar *m_titleBar = nullptr; FloatingWidgetTitleBar *m_titleBar = nullptr;
@@ -107,25 +108,30 @@ namespace ADS
q->setWindowTitle(text); q->setWindowTitle(text);
} }
/**
* Reflect the current dock widget title in the floating widget windowTitle()
* depending on the DockManager::FloatingContainerHasWidgetTitle flag
*/
void reflectCurrentWidget(DockWidget *currentWidget) void reflectCurrentWidget(DockWidget *currentWidget)
{ {
// reflect CurrentWidget's title if configured to do so, otherwise display application name as window title // reflect CurrentWidget's title if configured to do so, otherwise display application name as window title
if (testConfigFlag(DockManager::FloatingContainerHasWidgetTitle)) { if (testConfigFlag(DockManager::FloatingContainerHasWidgetTitle))
setWindowTitle(currentWidget->windowTitle()); setWindowTitle(currentWidget->windowTitle());
} else { else
setWindowTitle(QApplication::applicationDisplayName()); setWindowTitle(QApplication::applicationDisplayName());
}
// reflect CurrentWidget's icon if configured to do so, otherwise display application icon as window icon // reflect currentWidget's icon if configured to do so, otherwise display application icon as window icon
QIcon CurrentWidgetIcon = currentWidget->icon(); QIcon currentWidgetIcon = currentWidget->icon();
if (testConfigFlag(DockManager::FloatingContainerHasWidgetIcon) if (testConfigFlag(DockManager::FloatingContainerHasWidgetIcon) && !currentWidgetIcon.isNull())
&& !CurrentWidgetIcon.isNull())
{
q->setWindowIcon(currentWidget->icon()); q->setWindowIcon(currentWidget->icon());
} else { else
q->setWindowIcon(QApplication::windowIcon()); q->setWindowIcon(QApplication::windowIcon());
} }
}
/**
* Handles escape key press when dragging around the floating widget
*/
void handleEscapeKey();
}; // class FloatingDockContainerPrivate }; // class FloatingDockContainerPrivate
FloatingDockContainerPrivate::FloatingDockContainerPrivate(FloatingDockContainer *parent) FloatingDockContainerPrivate::FloatingDockContainerPrivate(FloatingDockContainer *parent)
@@ -135,17 +141,15 @@ namespace ADS
void FloatingDockContainerPrivate::titleMouseReleaseEvent() void FloatingDockContainerPrivate::titleMouseReleaseEvent()
{ {
setState(DraggingInactive); setState(DraggingInactive);
if (!m_dropContainer) { if (!m_dropContainer)
return; return;
}
if (m_dockManager->dockAreaOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea if (m_dockManager->dockAreaOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea
|| m_dockManager->containerOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea) { || m_dockManager->containerOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea) {
// Resize the floating widget to the size of the highlighted drop area rectangle // Resize the floating widget to the size of the highlighted drop area rectangle
DockOverlay *overlay = m_dockManager->containerOverlay(); DockOverlay *overlay = m_dockManager->containerOverlay();
if (!overlay->dropOverlayRect().isValid()) { if (!overlay->dropOverlayRect().isValid())
overlay = m_dockManager->dockAreaOverlay(); overlay = m_dockManager->dockAreaOverlay();
}
QRect rect = overlay->dropOverlayRect(); QRect rect = overlay->dropOverlayRect();
int frameWidth = (q->frameSize().width() - q->rect().width()) / 2; int frameWidth = (q->frameSize().width() - q->rect().width()) / 2;
@@ -165,28 +169,24 @@ namespace ADS
void FloatingDockContainerPrivate::updateDropOverlays(const QPoint &globalPosition) void FloatingDockContainerPrivate::updateDropOverlays(const QPoint &globalPosition)
{ {
if (!q->isVisible() || !m_dockManager) { if (!q->isVisible() || !m_dockManager)
return; return;
}
auto containers = m_dockManager->dockContainers(); auto containers = m_dockManager->dockContainers();
DockContainerWidget *topContainer = nullptr; DockContainerWidget *topContainer = nullptr;
for (auto containerWidget : containers) { for (auto containerWidget : containers) {
if (!containerWidget->isVisible()) { if (!containerWidget->isVisible())
continue; continue;
}
if (m_dockContainer == containerWidget) { if (m_dockContainer == containerWidget)
continue; continue;
}
QPoint mappedPos = containerWidget->mapFromGlobal(globalPosition); QPoint mappedPos = containerWidget->mapFromGlobal(globalPosition);
if (containerWidget->rect().contains(mappedPos)) { if (containerWidget->rect().contains(mappedPos)) {
if (!topContainer || containerWidget->isInFrontOf(topContainer)) { if (!topContainer || containerWidget->isInFrontOf(topContainer))
topContainer = containerWidget; topContainer = containerWidget;
} }
} }
}
m_dropContainer = topContainer; m_dropContainer = topContainer;
auto containerOverlay = m_dockManager->containerOverlay(); auto containerOverlay = m_dockManager->containerOverlay();
@@ -223,6 +223,14 @@ namespace ADS
} }
} }
void FloatingDockContainerPrivate::handleEscapeKey()
{
qCInfo(adsLog) << Q_FUNC_INFO;
setState(DraggingInactive);
m_dockManager->containerOverlay()->hideOverlay();
m_dockManager->dockAreaOverlay()->hideOverlay();
}
FloatingDockContainer::FloatingDockContainer(DockManager *dockManager) FloatingDockContainer::FloatingDockContainer(DockManager *dockManager)
: FloatingWidgetBaseType(dockManager) : FloatingWidgetBaseType(dockManager)
, d(new FloatingDockContainerPrivate(this)) , d(new FloatingDockContainerPrivate(this))
@@ -268,10 +276,9 @@ namespace ADS
d->m_titleBar->enableCloseButton(isClosable()); d->m_titleBar->enableCloseButton(isClosable());
auto dw = topLevelDockWidget(); auto dw = topLevelDockWidget();
if (dw) { if (dw)
dw->emitTopLevelChanged(true); dw->emitTopLevelChanged(true);
} }
}
FloatingDockContainer::FloatingDockContainer(DockWidget *dockWidget) FloatingDockContainer::FloatingDockContainer(DockWidget *dockWidget)
: FloatingDockContainer(dockWidget->dockManager()) : FloatingDockContainer(dockWidget->dockManager())
@@ -281,17 +288,16 @@ namespace ADS
d->m_titleBar->enableCloseButton(isClosable()); d->m_titleBar->enableCloseButton(isClosable());
auto dw = topLevelDockWidget(); auto dw = topLevelDockWidget();
if (dw) { if (dw)
dw->emitTopLevelChanged(true); dw->emitTopLevelChanged(true);
} }
}
FloatingDockContainer::~FloatingDockContainer() FloatingDockContainer::~FloatingDockContainer()
{ {
qCInfo(adsLog) << Q_FUNC_INFO; qCInfo(adsLog) << Q_FUNC_INFO;
if (d->m_dockManager) { if (d->m_dockManager)
d->m_dockManager->removeFloatingWidget(this); d->m_dockManager->removeFloatingWidget(this);
}
delete d; delete d;
} }
@@ -312,6 +318,10 @@ namespace ADS
QWidget::moveEvent(event); QWidget::moveEvent(event);
switch (d->m_draggingState) { switch (d->m_draggingState) {
case DraggingMousePressed: case DraggingMousePressed:
// TODO Is checking for windows only sufficient or has macOS also problems?
if (Utils::HostOsInfo::isWindowsHost())
QApplication::instance()->installEventFilter(this);
d->setState(DraggingFloatingWidget); d->setState(DraggingFloatingWidget);
d->updateDropOverlays(QCursor::pos()); d->updateDropOverlays(QCursor::pos());
break; break;
@@ -340,10 +350,9 @@ namespace ADS
if (isClosable()) { if (isClosable()) {
auto dw = topLevelDockWidget(); auto dw = topLevelDockWidget();
if (dw && dw->features().testFlag(DockWidget::DockWidgetDeleteOnClose)) { if (dw && dw->features().testFlag(DockWidget::DockWidgetDeleteOnClose)) {
if (!dw->closeDockWidgetInternal()) { if (!dw->closeDockWidgetInternal())
return; return;
} }
}
this->hide(); this->hide();
} }
@@ -352,21 +361,18 @@ namespace ADS
void FloatingDockContainer::hideEvent(QHideEvent *event) void FloatingDockContainer::hideEvent(QHideEvent *event)
{ {
Super::hideEvent(event); Super::hideEvent(event);
if (event->spontaneous()) { if (event->spontaneous())
return; return;
}
// Prevent toogleView() events during restore state // Prevent toogleView() events during restore state
if (d->m_dockManager->isRestoringState()) { if (d->m_dockManager->isRestoringState())
return; return;
}
for (auto dockArea : d->m_dockContainer->openedDockAreas()) { for (auto dockArea : d->m_dockContainer->openedDockAreas()) {
for (auto dockWidget : dockArea->openedDockWidgets()) { for (auto dockWidget : dockArea->openedDockWidgets())
dockWidget->toggleView(false); dockWidget->toggleView(false);
} }
} }
}
void FloatingDockContainer::showEvent(QShowEvent *event) { Super::showEvent(event); } void FloatingDockContainer::showEvent(QShowEvent *event) { Super::showEvent(event); }
@@ -379,22 +385,21 @@ namespace ADS
// QEvent::NonClientAreaMouseButtonPress return the wrong mouse button // QEvent::NonClientAreaMouseButtonPress return the wrong mouse button
// The event always returns Qt::RightButton even if the left button is clicked. // The event always returns Qt::RightButton even if the left button is clicked.
// It is really great to work around the whole NonClientMouseArea bugs // It is really great to work around the whole NonClientMouseArea bugs
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 2)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 2))
if (event->type() if (event->type() == QEvent::NonClientAreaMouseButtonPress
== QEvent:: /*&& QGuiApplication::mouseButtons().testFlag(Qt::LeftButton)*/)
NonClientAreaMouseButtonPress /*&& QGuiApplication::mouseButtons().testFlag(Qt::LeftButton)*/) {
qCInfo(adsLog) << Q_FUNC_INFO << "QEvent::NonClientAreaMouseButtonPress"
<< event->type();
d->setState(DraggingMousePressed);
}
#else #else
if (event->type() == QEvent::NonClientAreaMouseButtonPress if (event->type() == QEvent::NonClientAreaMouseButtonPress
&& QGuiApplication::mouseButtons().testFlag(Qt::LeftButton)) { && QGuiApplication::mouseButtons().testFlag(Qt::LeftButton))
#endif
{
qCInfo(adsLog) << Q_FUNC_INFO << "QEvent::NonClientAreaMouseButtonPress" qCInfo(adsLog) << Q_FUNC_INFO << "QEvent::NonClientAreaMouseButtonPress"
<< event->type(); << event->type();
d->m_dragStartPos = pos();
d->setState(DraggingMousePressed); d->setState(DraggingMousePressed);
} }
#endif
} break; } break;
case DraggingMousePressed: case DraggingMousePressed:
@@ -440,6 +445,37 @@ namespace ADS
return QWidget::event(event); return QWidget::event(event);
} }
bool FloatingDockContainer::eventFilter(QObject *watched, QEvent *event)
{
Q_UNUSED(watched);
// I have not found a way to detect non client area key press events to
// handle escape key presses. On Windows, if the escape key is pressed while
// dragging around a widget, the widget position is reset to its start position
// which in turn generates a QEvent::NonClientAreaMouseButtonRelease event
// if the mouse is outside of the widget after the move to its initial position
// or a QEvent::MouseButtonRelease event, if the mouse is inside of the widget
// after the position has been reset.
// So we can install an event filter on the application to get these events
// here to properly cancel dragging and hide the overlays.
// If we are in DraggingFloatingWidget state, it means the widget
// has been dragged already but if the position is the same like
// the start position, then this is an indication that the escape
// key has been pressed.
if (event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::NonClientAreaMouseButtonRelease)
{
qCInfo(adsLog) << Q_FUNC_INFO << "QEvent::MouseButtonRelease or QEvent::NonClientAreaMouseButtonRelease"
<< "d->m_draggingState " << d->m_draggingState;
QApplication::instance()->removeEventFilter(this);
if (d->m_dragStartPos == pos())
{
d->handleEscapeKey();
return true;
}
return false;
}
return false;
}
void FloatingDockContainer::startFloating(const QPoint &dragStartMousePos, void FloatingDockContainer::startFloating(const QPoint &dragStartMousePos,
const QSize &size, const QSize &size,
eDragState dragState, eDragState dragState,

View File

@@ -188,6 +188,7 @@ protected: // reimplements QWidget
virtual void closeEvent(QCloseEvent *event) override; virtual void closeEvent(QCloseEvent *event) override;
virtual void hideEvent(QHideEvent *event) override; virtual void hideEvent(QHideEvent *event) override;
virtual void showEvent(QShowEvent *event) override; virtual void showEvent(QShowEvent *event) override;
virtual bool eventFilter(QObject *watched, QEvent *event) override;
public: public:
using Super = QWidget; using Super = QWidget;