ADS: Fix repeatedly dropping in same area crash

6c687d28def5c24f3eeb67c9e13d5cfab40cebd0
1c2383f8eb94bc8570e554efa5f842a8ab1461ea

Task-number: QDS-1751
Change-Id: I933b1f53da8ce423cd5d38ff2863f58606006596
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Henning Gruendl
2020-03-13 10:44:37 +01:00
committed by Henning Gründl
parent 206e7d3e70
commit 0b7970feb4
7 changed files with 67 additions and 37 deletions

View File

@@ -595,7 +595,7 @@ namespace ADS
{ {
DockWidget *droppedDockWidget = qobject_cast<DockWidget *>(widget); DockWidget *droppedDockWidget = qobject_cast<DockWidget *>(widget);
DockAreaWidget *droppedDockArea = qobject_cast<DockAreaWidget *>(widget); DockAreaWidget *droppedDockArea = qobject_cast<DockAreaWidget *>(widget);
DockAreaWidget *newDockArea; DockAreaWidget *newDockArea = nullptr;
if (droppedDockWidget) { if (droppedDockWidget) {
newDockArea = new DockAreaWidget(m_dockManager, q); newDockArea = new DockAreaWidget(m_dockManager, q);
@@ -605,6 +605,18 @@ namespace ADS
} }
newDockArea->addDockWidget(droppedDockWidget); newDockArea->addDockWidget(droppedDockWidget);
} else { } else {
// We check, if we insert the dropped widget into the same place that
// it already has and do nothing, if it is the same place. It would
// also work without this check, but it looks nicer with the check
// because there will be no layout updates
auto splitter = internal::findParent<DockSplitter*>(droppedDockArea);
auto insertParam = internal::dockAreaInsertParameters(area);
if (splitter == m_rootSplitter && insertParam.orientation() == splitter->orientation()) {
if (insertParam.append() && splitter->lastWidget() == droppedDockArea)
return;
else if (!insertParam.append() && splitter->firstWidget() == droppedDockArea)
return;
}
droppedDockArea->dockContainer()->removeDockArea(droppedDockArea); droppedDockArea->dockContainer()->removeDockArea(droppedDockArea);
newDockArea = droppedDockArea; newDockArea = droppedDockArea;
} }
@@ -1217,36 +1229,13 @@ namespace ADS
} }
} }
void DockContainerWidget::dropWidget(QWidget *widget, const QPoint &targetPosition) void DockContainerWidget::dropWidget(QWidget *widget, DockWidgetArea dropArea, DockAreaWidget *targetAreaWidget)
{ {
qCInfo(adsLog) << Q_FUNC_INFO;
DockWidget *singleDockWidget = topLevelDockWidget(); DockWidget *singleDockWidget = topLevelDockWidget();
DockAreaWidget *dockArea = dockAreaAt(targetPosition); if (targetAreaWidget)
auto dropArea = InvalidDockWidgetArea; d->moveToNewSection(widget, targetAreaWidget, dropArea);
auto containerDropArea = d->m_dockManager->containerOverlay()->dropAreaUnderCursor(); else
d->moveToContainer(widget, dropArea);
if (dockArea) {
auto dropOverlay = d->m_dockManager->dockAreaOverlay();
dropOverlay->setAllowedAreas(dockArea->allowedAreas());
dropArea = dropOverlay->showOverlay(dockArea);
if (containerDropArea != InvalidDockWidgetArea && containerDropArea != dropArea) {
dropArea = InvalidDockWidgetArea;
}
if (dropArea != InvalidDockWidgetArea) {
qCInfo(adsLog) << "Dock Area Drop Content: " << dropArea;
d->moveToNewSection(widget, dockArea, dropArea);
}
}
// mouse is over container
if (InvalidDockWidgetArea == dropArea) {
dropArea = containerDropArea;
qCInfo(adsLog) << "Container Drop Content: " << dropArea;
if (dropArea != InvalidDockWidgetArea) {
d->moveToContainer(widget, dropArea);
}
}
// If there was a top level widget before the drop, then it is not top // If there was a top level widget before the drop, then it is not top
// level widget anymore // level widget anymore

View File

@@ -104,9 +104,13 @@ protected:
void dropFloatingWidget(FloatingDockContainer *floatingWidget, const QPoint &targetPos); void dropFloatingWidget(FloatingDockContainer *floatingWidget, const QPoint &targetPos);
/** /**
* Drop a dock area or a dock widget given in widget parameter * Drop a dock area or a dock widget given in widget parameter.
* If the TargetAreaWidget is a nullptr, then the DropArea indicates
* the drop area for the container. If the given TargetAreaWidget is not
* a nullptr, then the DropArea indicates the drop area in the given
* TargetAreaWidget
*/ */
void dropWidget(QWidget *widget, const QPoint &targetPos); void dropWidget(QWidget *widget, DockWidgetArea dropArea, DockAreaWidget *targetAreaWidget);
/** /**
* Adds the given dock area to this container widget * Adds the given dock area to this container widget

View File

@@ -399,6 +399,14 @@ namespace ADS {
return result; return result;
} }
DockWidgetArea DockOverlay::visibleDropAreaUnderCursor() const
{
if (isHidden() || !d->m_dropPreviewEnabled)
return InvalidDockWidgetArea;
else
return dropAreaUnderCursor();
}
DockWidgetArea DockOverlay::showOverlay(QWidget *target) DockWidgetArea DockOverlay::showOverlay(QWidget *target)
{ {
if (d->m_targetWidget == target) { if (d->m_targetWidget == target) {

View File

@@ -93,6 +93,13 @@ public:
*/ */
DockWidgetArea dropAreaUnderCursor() const; DockWidgetArea dropAreaUnderCursor() const;
/**
* This function returns the same like dropAreaUnderCursor() if this
* overlay is not hidden and if drop preview is enabled and returns
* InvalidDockWidgetArea if it is hidden or drop preview is disabled.
*/
DockWidgetArea visibleDropAreaUnderCursor() const;
/** /**
* Show the drop overly for the given target widget * Show the drop overly for the given target widget
*/ */

View File

@@ -89,4 +89,14 @@ namespace ADS
return false; return false;
} }
QWidget *DockSplitter::firstWidget() const
{
return (count() > 0) ? widget(0) : nullptr;
}
QWidget *DockSplitter::lastWidget() const
{
return (count() > 0) ? widget(count() - 1) : nullptr;
}
} // namespace ADS } // namespace ADS

View File

@@ -67,6 +67,16 @@ public:
* Returns true, if any of the internal widgets is visible * Returns true, if any of the internal widgets is visible
*/ */
bool hasVisibleContent() const; bool hasVisibleContent() const;
/**
* Returns first widget or nullptr if splitter is empty
*/
QWidget *firstWidget() const;
/**
* Returns last widget of nullptr is splitter is empty
*/
QWidget *lastWidget() const;
}; // class DockSplitter }; // class DockSplitter
} // namespace ADS } // namespace ADS

View File

@@ -262,12 +262,14 @@ namespace ADS
void FloatingDragPreview::finishDragging() void FloatingDragPreview::finishDragging()
{ {
qCInfo(adsLog) << Q_FUNC_INFO; qCInfo(adsLog) << Q_FUNC_INFO;
auto dockDropArea = d->m_dockManager->dockAreaOverlay()->dropAreaUnderCursor(); auto dockDropArea = d->m_dockManager->dockAreaOverlay()->visibleDropAreaUnderCursor();
auto containerDropArea = d->m_dockManager->containerOverlay()->dropAreaUnderCursor(); auto containerDropArea = d->m_dockManager->containerOverlay()->visibleDropAreaUnderCursor();
bool dropPossible = (dockDropArea != InvalidDockWidgetArea) if (d->m_dropContainer && (dockDropArea != InvalidDockWidgetArea)) {
|| (containerDropArea != InvalidDockWidgetArea); d->m_dropContainer->dropWidget(d->m_content,
if (d->m_dropContainer && dropPossible) { dockDropArea,
d->m_dropContainer->dropWidget(d->m_content, QCursor::pos()); d->m_dropContainer->dockAreaAt(QCursor::pos()));
} else if (d->m_dropContainer && (containerDropArea != InvalidDockWidgetArea)) {
d->m_dropContainer->dropWidget(d->m_content, containerDropArea, nullptr);
} else { } else {
DockWidget *dockWidget = qobject_cast<DockWidget *>(d->m_content); DockWidget *dockWidget = qobject_cast<DockWidget *>(d->m_content);
FloatingDockContainer *floatingWidget = nullptr; FloatingDockContainer *floatingWidget = nullptr;