Fixxed isse #131 - Crash on dropping in same area multiple times

This commit is contained in:
Uwe Kindler 2020-03-12 10:23:41 +01:00
parent 708add3ff5
commit 6c687d28de
7 changed files with 103 additions and 38 deletions

View File

@ -679,6 +679,23 @@ void DockContainerWidgetPrivate::moveToContainer(QWidget* Widget, DockWidgetArea
}
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<CDockSplitter*>(DroppedDockArea);
auto InsertParam = internal::dockAreaInsertParameters(area);
if (Splitter == RootSplitter && InsertParam.orientation() == Splitter->orientation())
{
if (InsertParam.append() && Splitter->lastWidget() == DroppedDockArea)
{
return;
}
else if (!InsertParam.append() && Splitter->firstWidget() == DroppedDockArea)
{
return;
}
}
DroppedDockArea->dockContainer()->removeDockArea(DroppedDockArea);
NewDockArea = DroppedDockArea;
}
@ -1435,42 +1452,38 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi
}
//============================================================================
void CDockContainerWidget::dropWidget(QWidget* Widget, const QPoint& TargetPos)
/**
* Returns the dock area for a dropped widget.
*/
CDockAreaWidget* droppedDockArea(QWidget* Widget)
{
ADS_PRINT("CDockContainerWidget::dropFloatingWidget");
CDockWidget* SingleDockWidget = topLevelDockWidget();
CDockAreaWidget* DockArea = dockAreaAt(TargetPos);
auto dropArea = InvalidDockWidgetArea;
auto ContainerDropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor();
if (DockArea)
auto DroppedArea = qobject_cast<CDockAreaWidget*>(Widget);
if (!DroppedArea)
{
auto dropOverlay = d->DockManager->dockAreaOverlay();
dropOverlay->setAllowedAreas(DockArea->allowedAreas());
dropArea = dropOverlay->showOverlay(DockArea);
if (ContainerDropArea != InvalidDockWidgetArea &&
ContainerDropArea != dropArea)
{
dropArea = InvalidDockWidgetArea;
}
if (dropArea != InvalidDockWidgetArea)
{
ADS_PRINT("Dock Area Drop Content: " << dropArea);
d->moveToNewSection(Widget, DockArea, dropArea);
}
auto DroppedWidget = qobject_cast<CDockWidget*>(Widget);
DroppedArea = DroppedWidget->dockAreaWidget();
}
// mouse is over container
if (InvalidDockWidgetArea == dropArea)
return DroppedArea;
}
//============================================================================
void CDockContainerWidget::dropWidget(QWidget* Widget, DockWidgetArea DropArea, CDockAreaWidget* TargetAreaWidget)
{
if (TargetAreaWidget && TargetAreaWidget == droppedDockArea(Widget))
{
dropArea = ContainerDropArea;
ADS_PRINT("Container Drop Content: " << dropArea);
if (dropArea != InvalidDockWidgetArea)
{
d->moveToContainer(Widget, dropArea);
}
return;
}
CDockWidget* SingleDockWidget = topLevelDockWidget();
if (TargetAreaWidget)
{
d->moveToNewSection(Widget, TargetAreaWidget, DropArea);
}
else
{
d->moveToContainer(Widget, DropArea);
}
// If there was a top level widget before the drop, then it is not top

View File

@ -96,9 +96,13 @@ protected:
void dropFloatingWidget(CFloatingDockContainer* 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, CDockAreaWidget* TargetAreaWidget);
/**
* Adds the given dock area to this container widget

View File

@ -396,6 +396,20 @@ DockWidgetArea CDockOverlay::dropAreaUnderCursor() const
}
//============================================================================
DockWidgetArea CDockOverlay::visibleDropAreaUnderCursor() const
{
if (isHidden() || !d->DropPreviewEnabled)
{
return InvalidDockWidgetArea;
}
else
{
return dropAreaUnderCursor();
}
}
//============================================================================
DockWidgetArea CDockOverlay::showOverlay(QWidget* target)
{

View File

@ -81,6 +81,13 @@ public:
*/
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
*/

View File

@ -88,6 +88,20 @@ bool CDockSplitter::hasVisibleContent() const
return false;
}
//============================================================================
QWidget* CDockSplitter::firstWidget() const
{
return (count() > 0) ? widget(0) : nullptr;
}
//============================================================================
QWidget* CDockSplitter::lastWidget() const
{
return (count() > 0) ? widget(count() - 1) : nullptr;
}
} // namespace ads
//---------------------------------------------------------------------------

View File

@ -61,6 +61,16 @@ public:
* Returns true, if any of the internal widgets is visible
*/
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 CDockSplitter
} // namespace ads

View File

@ -286,12 +286,15 @@ void CFloatingDragPreview::moveEvent(QMoveEvent *event)
void CFloatingDragPreview::finishDragging()
{
ADS_PRINT("CFloatingDragPreview::finishDragging");
auto DockDropArea = d->DockManager->dockAreaOverlay()->dropAreaUnderCursor();
auto ContainerDropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor();
bool DropPossible = (DockDropArea != InvalidDockWidgetArea) || (ContainerDropArea != InvalidDockWidgetArea);
if (d->DropContainer && DropPossible)
auto DockDropArea = d->DockManager->dockAreaOverlay()->visibleDropAreaUnderCursor();
auto ContainerDropArea = d->DockManager->containerOverlay()->visibleDropAreaUnderCursor();
if (d->DropContainer && (DockDropArea != InvalidDockWidgetArea))
{
d->DropContainer->dropWidget(d->Content, QCursor::pos());
d->DropContainer->dropWidget(d->Content, DockDropArea, d->DropContainer->dockAreaAt(QCursor::pos()));
}
else if (d->DropContainer && (ContainerDropArea != InvalidDockWidgetArea))
{
d->DropContainer->dropWidget(d->Content, ContainerDropArea, nullptr);
}
else
{