Compare commits
48 Commits
1.1
...
fix-python
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6fce8e6161 | ||
|
|
6479bcabfb | ||
|
|
a8c9735652 | ||
|
|
93b25b6a31 | ||
|
|
4eb5a0940e | ||
|
|
c2cc914b5c | ||
|
|
1219ba90af | ||
|
|
beef3c7fb5 | ||
|
|
52184ca72b | ||
|
|
78cd7c56f7 | ||
|
|
7805a1dc25 | ||
|
|
92f426e4c0 | ||
|
|
90f10042fd | ||
|
|
3369816d31 | ||
|
|
860cbd29bc | ||
|
|
2fd4f9ce97 | ||
|
|
697cc34c23 | ||
|
|
d50fcb80c5 | ||
|
|
9571ffc30e | ||
|
|
f4a88276b8 | ||
|
|
4ea254029a | ||
|
|
f5e85c2196 | ||
|
|
926103325c | ||
|
|
20b2988165 | ||
|
|
39aefd312b | ||
|
|
b5478bcb0d | ||
|
|
d403557b9e | ||
|
|
db9884ea64 | ||
|
|
74148aabc3 | ||
|
|
7bfac091ae | ||
|
|
60a68817b6 | ||
|
|
a56e6d7fe8 | ||
|
|
1f0b208922 | ||
|
|
9da147f50e | ||
|
|
c175451284 | ||
|
|
9a88cf3a72 | ||
|
|
d0255e5310 | ||
|
|
2a2fb0a4f2 | ||
|
|
b0ad939db8 | ||
|
|
5abf118b8c | ||
|
|
30949bd4c3 | ||
|
|
63279c187e | ||
|
|
fad03f8e0b | ||
|
|
6edfcc4f02 | ||
|
|
62cbd823c9 | ||
|
|
bdcc211308 | ||
|
|
ddeb4611a1 | ||
|
|
ad639c8001 |
@@ -73,9 +73,10 @@ endif()
|
||||
|
||||
set(${PROJECT_NAME}_VERSION_MAJOR 1)
|
||||
set(${PROJECT_NAME}_VERSION_MINOR 1)
|
||||
set(${PROJECT_NAME}_VERSION_PATCH 0)
|
||||
set(${PROJECT_NAME}_VERSION_PATCH 95)
|
||||
|
||||
set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH})
|
||||
set(${PROJECT_NAME}_SOVERSION "1.1")
|
||||
set(${PROJECT_NAME}_SOVERSION "1.2")
|
||||
|
||||
include(FeatureSummary)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ from conans import ConanFile, CMake, tools
|
||||
|
||||
class KDDockWidgetsConan(ConanFile):
|
||||
name = "kddockwidgets"
|
||||
version = "1.1.0"
|
||||
version = "1.1.95"
|
||||
default_user = "kdab"
|
||||
default_channel = "stable"
|
||||
license = ("https://raw.githubusercontent.com/KDAB/KDDockWidgets/master/LICENSES/GPL-2.0-only.txt",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<!-- this is used in a public virtual pure function we need to declare it
|
||||
otherwise shiboken will ignore the function and will fail to create a wrapper -->
|
||||
<primitive-type name="DropAreaWithCentralFrame"/>
|
||||
<primitive-type name="SideBar"/>
|
||||
|
||||
<!-- Some plublic enum and flags -->
|
||||
<enum-type name="Location"/>
|
||||
@@ -19,6 +20,9 @@
|
||||
<enum-type name="RestoreOption" flags="RestoreOptions"/>
|
||||
<enum-type name="DefaultSizeMode"/>
|
||||
<enum-type name="FrameOption" flags="FrameOptions"/>
|
||||
<enum-type name="DropIndicatorType"/>
|
||||
<enum-type name="SideBarLocation"/>
|
||||
<enum-type name="TitleBarButtonType"/>
|
||||
|
||||
<!-- our classes
|
||||
For class we can use two types:
|
||||
@@ -32,6 +36,7 @@
|
||||
<!-- this class contains a internal enum, so it should be declared
|
||||
inside of the object-type -->
|
||||
<enum-type name="Option" flags="Options" />
|
||||
<enum-type name="IconPlace" flags="IconPlaces" />
|
||||
</object-type>
|
||||
|
||||
<object-type name="DockWidget" />
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "multisplitter/Widget_qwidget.h"
|
||||
#include "DockRegistry_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "Utils_p.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
@@ -83,8 +84,11 @@ Config::Flags Config::flags() const
|
||||
|
||||
void Config::setFlags(Flags f)
|
||||
{
|
||||
if (!DockRegistry::self()->isEmpty()) {
|
||||
qWarning() << Q_FUNC_INFO << "Only use this function at startup before creating any DockWidget or MainWindow";
|
||||
auto dr = DockRegistry::self();
|
||||
if (!dr->isEmpty(/*excludeBeingDeleted=*/ true)) {
|
||||
qWarning() << Q_FUNC_INFO << "Only use this function at startup before creating any DockWidget or MainWindow"
|
||||
<< "; These are already created: " << dr->mainWindowsNames()
|
||||
<< dr->dockWidgetNames() << dr->floatingWindows();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -135,7 +139,7 @@ int Config::separatorThickness() const
|
||||
|
||||
void Config::setSeparatorThickness(int value)
|
||||
{
|
||||
if (!DockRegistry::self()->isEmpty()) {
|
||||
if (!DockRegistry::self()->isEmpty(/*excludeBeingDeleted=*/ true)) {
|
||||
qWarning() << Q_FUNC_INFO << "Only use this function at startup before creating any DockWidget or MainWindow";
|
||||
return;
|
||||
}
|
||||
@@ -188,10 +192,18 @@ void Config::Private::fixFlags()
|
||||
// Not supported on macOS:
|
||||
m_flags = m_flags & ~Flag_AeroSnapWithClientDecos;
|
||||
#else
|
||||
// Not supported on linux.
|
||||
// On Linux, dragging the title bar of a window doesn't generate NonClientMouseEvents
|
||||
m_flags = m_flags & ~Flag_NativeTitleBar;
|
||||
m_flags = m_flags & ~Flag_AeroSnapWithClientDecos;
|
||||
if (KDDockWidgets::isWayland()) {
|
||||
// Native title bar is forced on Wayland. Needed for moving the window.
|
||||
// The inner KDDW title bar is used for DnD.
|
||||
m_flags |= Flag_NativeTitleBar;
|
||||
} else {
|
||||
// Not supported on linux/X11
|
||||
// On Linux, dragging the title bar of a window doesn't generate NonClientMouseEvents
|
||||
// at least with KWin anyway. We can make this more granular and allow it for other
|
||||
// X11 window managers
|
||||
m_flags = m_flags & ~Flag_NativeTitleBar;
|
||||
m_flags = m_flags & ~Flag_AeroSnapWithClientDecos;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(Q_OS_WIN) && !defined(Q_OS_MACOS)
|
||||
|
||||
@@ -786,7 +786,7 @@ void DockWidgetBase::onHidden(bool spontaneous)
|
||||
}
|
||||
}
|
||||
|
||||
void DockWidgetBase::onClosed(QCloseEvent *e)
|
||||
void DockWidgetBase::onCloseEvent(QCloseEvent *e)
|
||||
{
|
||||
e->accept(); // By default we accept, means DockWidget closes
|
||||
if (d->widget)
|
||||
|
||||
@@ -411,7 +411,9 @@ protected:
|
||||
void onParentChanged();
|
||||
void onShown(bool spontaneous);
|
||||
void onHidden(bool spontaneous);
|
||||
void onClosed(QCloseEvent *e);
|
||||
#ifndef PYTHON_BINDINGS //Pyside bug: https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-1327
|
||||
void onCloseEvent(QCloseEvent *e) override;
|
||||
#endif
|
||||
|
||||
#if defined(DOCKS_DEVELOPER_MODE)
|
||||
public Q_SLOTS:
|
||||
|
||||
@@ -163,7 +163,7 @@ QByteArray LayoutSaver::serializeLayout() const
|
||||
layout.mainWindows.push_back(mainWindow->serialize());
|
||||
}
|
||||
|
||||
const QVector<KDDockWidgets::FloatingWindow*> floatingWindows = d->m_dockRegistry->nestedwindows();
|
||||
const QVector<KDDockWidgets::FloatingWindow*> floatingWindows = d->m_dockRegistry->floatingWindows();
|
||||
layout.floatingWindows.reserve(floatingWindows.size());
|
||||
for (KDDockWidgets::FloatingWindow *floatingWindow : floatingWindows) {
|
||||
if (d->matchesAffinity(floatingWindow->affinities()))
|
||||
|
||||
@@ -200,7 +200,7 @@ DebugWindow::DebugWindow(QWidget *parent)
|
||||
mainWindow->multiSplitter()->checkSanity();
|
||||
}
|
||||
|
||||
const auto floatingWindows = DockRegistry::self()->nestedwindows();
|
||||
const auto floatingWindows = DockRegistry::self()->floatingWindows();
|
||||
for (FloatingWindow *floatingWindow : floatingWindows) {
|
||||
floatingWindow->multiSplitter()->checkSanity();
|
||||
}
|
||||
@@ -308,7 +308,7 @@ void DebugWindow::repaintWidgetRecursive(QWidget *w)
|
||||
|
||||
void DebugWindow::dumpDockWidgetInfo()
|
||||
{
|
||||
const QVector<FloatingWindow*> floatingWindows = DockRegistry::self()->nestedwindows();
|
||||
const QVector<FloatingWindow*> floatingWindows = DockRegistry::self()->floatingWindows();
|
||||
const MainWindowBase::List mainWindows = DockRegistry::self()->mainwindows();
|
||||
const DockWidgetBase::List dockWidgets = DockRegistry::self()->dockwidgets();
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "QWidgetAdapter.h"
|
||||
#include "Config.h"
|
||||
#include "SideBar_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
|
||||
#include <QPointer>
|
||||
#include <QDebug>
|
||||
@@ -100,9 +101,13 @@ void DockRegistry::onFocusObjectChanged(QObject *obj)
|
||||
Q_EMIT m_focusedDockWidget->isFocusedChanged(true);
|
||||
}
|
||||
|
||||
bool DockRegistry::isEmpty() const
|
||||
bool DockRegistry::isEmpty(bool excludeBeingDeleted) const
|
||||
{
|
||||
return m_dockWidgets.isEmpty() && m_mainWindows.isEmpty() && m_nestedWindows.isEmpty();
|
||||
if (!m_dockWidgets.isEmpty() || !m_mainWindows.isEmpty())
|
||||
return false;
|
||||
|
||||
return excludeBeingDeleted ? !hasFloatingWindows()
|
||||
: m_floatingWindows.isEmpty();
|
||||
}
|
||||
|
||||
void DockRegistry::checkSanityAll(bool dumpLayout)
|
||||
@@ -160,7 +165,7 @@ bool DockRegistry::isProbablyObscured(QWindow *window, FloatingWindow *exclude)
|
||||
return false;
|
||||
|
||||
const QRect geo = window->geometry();
|
||||
for (FloatingWindow *fw : m_nestedWindows) {
|
||||
for (FloatingWindow *fw : m_floatingWindows) {
|
||||
QWindow *fwWindow = fw->QWidgetAdapter::windowHandle();
|
||||
if (fw == exclude || fwWindow == window)
|
||||
continue;
|
||||
@@ -186,6 +191,14 @@ bool DockRegistry::isProbablyObscured(QWindow *window, FloatingWindow *exclude)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DockRegistry::isProbablyObscured(QWindow *target, WindowBeingDragged *exclude) const
|
||||
{
|
||||
FloatingWindow *fw = exclude ? exclude->floatingWindow()
|
||||
: nullptr; // It's null on Wayland. On wayland obscuring never happens anyway, so not a problem.
|
||||
|
||||
return isProbablyObscured(target, fw);
|
||||
}
|
||||
|
||||
SideBarLocation DockRegistry::sideBarLocationForDockWidget(const DockWidgetBase *dw) const
|
||||
{
|
||||
if (SideBar *sb = sideBarForDockWidget(dw))
|
||||
@@ -222,7 +235,7 @@ MultiSplitter *DockRegistry::layoutForItem(const Layouting::Item *item) const
|
||||
if (!item->hostWidget())
|
||||
return nullptr;
|
||||
|
||||
if (auto ms = qobject_cast<MultiSplitter*>(item->hostWidget()->asQWidget()))
|
||||
if (auto ms = qobject_cast<MultiSplitter*>(item->hostWidget()->asQObject()))
|
||||
return ms;
|
||||
|
||||
return nullptr;
|
||||
@@ -284,14 +297,14 @@ void DockRegistry::unregisterMainWindow(MainWindowBase *mainWindow)
|
||||
maybeDelete();
|
||||
}
|
||||
|
||||
void DockRegistry::registerNestedWindow(FloatingWindow *window)
|
||||
void DockRegistry::registerFloatingWindow(FloatingWindow *window)
|
||||
{
|
||||
m_nestedWindows << window;
|
||||
m_floatingWindows << window;
|
||||
}
|
||||
|
||||
void DockRegistry::unregisterNestedWindow(FloatingWindow *window)
|
||||
void DockRegistry::unregisterFloatingWindow(FloatingWindow *window)
|
||||
{
|
||||
m_nestedWindows.removeOne(window);
|
||||
m_floatingWindows.removeOne(window);
|
||||
maybeDelete();
|
||||
}
|
||||
|
||||
@@ -443,12 +456,12 @@ const Frame::List DockRegistry::frames() const
|
||||
return m_frames;
|
||||
}
|
||||
|
||||
const QVector<FloatingWindow *> DockRegistry::nestedwindows() const
|
||||
const QVector<FloatingWindow *> DockRegistry::floatingWindows() const
|
||||
{
|
||||
// Returns all the FloatingWindow which aren't being deleted
|
||||
QVector<FloatingWindow *> result;
|
||||
result.reserve(m_nestedWindows.size());
|
||||
for (FloatingWindow *fw : m_nestedWindows) {
|
||||
result.reserve(m_floatingWindows.size());
|
||||
for (FloatingWindow *fw : m_floatingWindows) {
|
||||
if (!fw->beingDeleted())
|
||||
result.push_back(fw);
|
||||
}
|
||||
@@ -456,11 +469,11 @@ const QVector<FloatingWindow *> DockRegistry::nestedwindows() const
|
||||
return result;
|
||||
}
|
||||
|
||||
const QVector<QWindow *> DockRegistry::floatingWindows() const
|
||||
const QVector<QWindow *> DockRegistry::floatingQWindows() const
|
||||
{
|
||||
QVector<QWindow *> windows;
|
||||
windows.reserve(m_nestedWindows.size());
|
||||
for (FloatingWindow *fw : m_nestedWindows) {
|
||||
windows.reserve(m_floatingWindows.size());
|
||||
for (FloatingWindow *fw : m_floatingWindows) {
|
||||
if (!fw->beingDeleted()) {
|
||||
if (QWindow *window = fw->windowHandle()) {
|
||||
window->setProperty("kddockwidgets_qwidget", QVariant::fromValue<QWidgetOrQuick*>(fw)); // Since QWidgetWindow is private API
|
||||
@@ -474,9 +487,16 @@ const QVector<QWindow *> DockRegistry::floatingWindows() const
|
||||
return windows;
|
||||
}
|
||||
|
||||
bool DockRegistry::hasFloatingWindows() const
|
||||
{
|
||||
return std::any_of(m_floatingWindows.begin(), m_floatingWindows.end(), [] (FloatingWindow *fw) {
|
||||
return !fw->beingDeleted();
|
||||
});
|
||||
}
|
||||
|
||||
FloatingWindow *DockRegistry::floatingWindowForHandle(QWindow *windowHandle) const
|
||||
{
|
||||
for (FloatingWindow *fw : m_nestedWindows) {
|
||||
for (FloatingWindow *fw : m_floatingWindows) {
|
||||
if (fw->windowHandle() == windowHandle)
|
||||
return fw;
|
||||
}
|
||||
@@ -487,10 +507,10 @@ FloatingWindow *DockRegistry::floatingWindowForHandle(QWindow *windowHandle) con
|
||||
QVector<QWindow *> DockRegistry::topLevels(bool excludeFloatingDocks) const
|
||||
{
|
||||
QVector<QWindow *> windows;
|
||||
windows.reserve(m_nestedWindows.size() + m_mainWindows.size());
|
||||
windows.reserve(m_floatingWindows.size() + m_mainWindows.size());
|
||||
|
||||
if (!excludeFloatingDocks) {
|
||||
for (FloatingWindow *fw : m_nestedWindows) {
|
||||
for (FloatingWindow *fw : m_floatingWindows) {
|
||||
if (fw->isVisible()) {
|
||||
if (QWindow *window = fw->windowHandle()) {
|
||||
window->setProperty("kddockwidgets_qwidget", QVariant::fromValue<QWidgetOrQuick*>(fw)); // Since QWidgetWindow is private API
|
||||
@@ -559,8 +579,8 @@ bool DockRegistry::eventFilter(QObject *watched, QEvent *event)
|
||||
if (auto windowHandle = qobject_cast<QWindow*>(watched)) {
|
||||
if (FloatingWindow *fw = floatingWindowForHandle(windowHandle)) {
|
||||
// This floating window was exposed
|
||||
m_nestedWindows.removeOne(fw);
|
||||
m_nestedWindows.append(fw);
|
||||
m_floatingWindows.removeOne(fw);
|
||||
m_floatingWindows.append(fw);
|
||||
}
|
||||
}
|
||||
} else if (event->type() == QEvent::MouseButtonPress) {
|
||||
|
||||
@@ -42,8 +42,8 @@ public:
|
||||
void registerMainWindow(MainWindowBase *);
|
||||
void unregisterMainWindow(MainWindowBase *);
|
||||
|
||||
void registerNestedWindow(FloatingWindow *);
|
||||
void unregisterNestedWindow(FloatingWindow *);
|
||||
void registerFloatingWindow(FloatingWindow *);
|
||||
void unregisterFloatingWindow(FloatingWindow *);
|
||||
|
||||
void registerLayout(MultiSplitter *);
|
||||
void unregisterLayout(MultiSplitter *);
|
||||
@@ -84,10 +84,13 @@ public:
|
||||
|
||||
///@brief returns all FloatingWindow instances. Not necessarily all floating dock widgets,
|
||||
/// As there might be DockWidgets which weren't morphed yet.
|
||||
const QVector<FloatingWindow*> nestedwindows() const;
|
||||
const QVector<FloatingWindow*> floatingWindows() const;
|
||||
|
||||
///@brief overload that returns list of QWindow. This is more friendly for supporting both QtWidgets and QtQuick
|
||||
const QVector<QWindow*> floatingWindows() const;
|
||||
const QVector<QWindow*> floatingQWindows() const;
|
||||
|
||||
///@brief returns whether if there's at least one floating window
|
||||
bool hasFloatingWindows() const;
|
||||
|
||||
///@brief returns the FloatingWindow with handle @p windowHandle
|
||||
FloatingWindow *floatingWindowForHandle(QWindow *windowHandle) const;
|
||||
@@ -127,8 +130,10 @@ public:
|
||||
|
||||
/**
|
||||
* @brief returns true if there's 0 dockwidgets, 0 main windows
|
||||
*
|
||||
* @param excludeBeingDeleted if true, any window currently being deleted won't count
|
||||
*/
|
||||
bool isEmpty() const;
|
||||
bool isEmpty(bool excludeBeingDeleted = false) const;
|
||||
|
||||
/**
|
||||
* @brief Calls MultiSplitter::checkSanity() on all layouts.
|
||||
@@ -174,6 +179,9 @@ public:
|
||||
/// @param exclude This window should not be counted as an obscurer. (It's being dragged).
|
||||
bool isProbablyObscured(QWindow *target, FloatingWindow *exclude) const;
|
||||
|
||||
/// @overload
|
||||
bool isProbablyObscured(QWindow *target, WindowBeingDragged *exclude) const;
|
||||
|
||||
///@brief Returns whether the specified dock widget is in a side bar, and which.
|
||||
/// SideBarLocation::None is returned if it's not in a sidebar.
|
||||
/// This is only relevant when using the auto-hide and side-bar feature.
|
||||
@@ -193,7 +201,7 @@ private:
|
||||
DockWidgetBase::List m_dockWidgets;
|
||||
MainWindowBase::List m_mainWindows;
|
||||
Frame::List m_frames;
|
||||
QVector<FloatingWindow*> m_nestedWindows;
|
||||
QVector<FloatingWindow*> m_floatingWindows;
|
||||
QVector<MultiSplitter*> m_layouts;
|
||||
QPointer<DockWidgetBase> m_focusedDockWidget;
|
||||
};
|
||||
|
||||
@@ -89,6 +89,11 @@ StateBase::StateBase(DragController *parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool StateBase::isActiveState() const
|
||||
{
|
||||
return q->activeState() == this;
|
||||
}
|
||||
|
||||
StateBase::~StateBase() = default;
|
||||
|
||||
StateNone::StateNone(DragController *parent)
|
||||
@@ -175,8 +180,8 @@ void StateDragging::onEntry(QEvent *)
|
||||
|
||||
q->m_windowBeingDragged = q->m_draggable->makeWindow();
|
||||
if (q->m_windowBeingDragged) {
|
||||
#ifdef Q_OS_WIN
|
||||
# if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
# ifdef Q_OS_WIN
|
||||
if (!q->m_nonClientDrag && KDDockWidgets::usesNativeDraggingAndResizing()) {
|
||||
// Started as a client move, as the dock widget was docked,
|
||||
// but now that we're dragging it as a floating window, switch to native drag
|
||||
@@ -233,7 +238,7 @@ bool StateDragging::handleMouseButtonRelease(QPoint globalPos)
|
||||
}
|
||||
|
||||
if (q->m_currentDropArea) {
|
||||
if (q->m_currentDropArea->drop(floatingWindow, globalPos)) {
|
||||
if (q->m_currentDropArea->drop(q->m_windowBeingDragged.get(), globalPos)) {
|
||||
Q_EMIT q->dropped();
|
||||
} else {
|
||||
qCDebug(state) << "StateDragging: Bailling out, drop not accepted";
|
||||
@@ -281,7 +286,7 @@ bool StateDragging::handleMouseMove(QPoint globalPos)
|
||||
}
|
||||
}
|
||||
|
||||
dropArea->hover(fw, globalPos);
|
||||
dropArea->hover(q->m_windowBeingDragged.get(), globalPos);
|
||||
}
|
||||
|
||||
q->m_currentDropArea = dropArea;
|
||||
@@ -289,13 +294,39 @@ bool StateDragging::handleMouseMove(QPoint globalPos)
|
||||
return true;
|
||||
}
|
||||
|
||||
StateDraggingWayland::StateDraggingWayland(DragController *parent)
|
||||
: StateDragging(parent)
|
||||
{
|
||||
}
|
||||
|
||||
StateDraggingWayland::~StateDraggingWayland()
|
||||
{
|
||||
}
|
||||
|
||||
void StateDraggingWayland::onEntry(QEvent *)
|
||||
{
|
||||
// Create a QDrag here
|
||||
}
|
||||
|
||||
bool StateDraggingWayland::handleMouseButtonRelease(QPoint /*globalPos*/)
|
||||
{
|
||||
Q_EMIT q->dragCanceled();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StateDraggingWayland::handleMouseMove(QPoint /*globalPos*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
DragController::DragController(QObject *)
|
||||
{
|
||||
qCDebug(creation) << "DragController()";
|
||||
|
||||
auto stateNone = new StateNone(this);
|
||||
auto statepreDrag = new StatePreDrag(this);
|
||||
auto stateDragging = new StateDragging(this);
|
||||
auto stateDragging = isWayland() ? new StateDraggingWayland(this)
|
||||
: new StateDragging(this);
|
||||
|
||||
stateNone->addTransition(this, &DragController::mousePressed, statepreDrag);
|
||||
statepreDrag->addTransition(this, &DragController::dragCanceled, stateNone);
|
||||
@@ -358,7 +389,7 @@ void DragController::releaseMouse(QWidgetOrQuick *target)
|
||||
}
|
||||
}
|
||||
|
||||
FloatingWindow *DragController::windowBeingDragged() const
|
||||
FloatingWindow *DragController::floatingWindowBeingDragged() const
|
||||
{
|
||||
return m_windowBeingDragged ? m_windowBeingDragged->floatingWindow()
|
||||
: nullptr;
|
||||
@@ -370,6 +401,11 @@ void DragController::enableFallbackMouseGrabber()
|
||||
m_fallbackMouseGrabber = new FallbackMouseGrabber(this);
|
||||
}
|
||||
|
||||
WindowBeingDragged *DragController::windowBeingDragged() const
|
||||
{
|
||||
return m_windowBeingDragged.get();
|
||||
}
|
||||
|
||||
static QMouseEvent *mouseEvent(QEvent *e)
|
||||
{
|
||||
switch (e->type()) {
|
||||
@@ -534,7 +570,7 @@ WidgetType *DragController::qtTopLevelUnderCursor() const
|
||||
// The floating window list is sorted by z-order, as we catch QEvent::Expose and move it to last of the list
|
||||
|
||||
FloatingWindow *tlwBeingDragged = m_windowBeingDragged->floatingWindow();
|
||||
if (auto tl = qtTopLevelUnderCursor_impl(globalPos, DockRegistry::self()->floatingWindows(), tlwBeingDragged))
|
||||
if (auto tl = qtTopLevelUnderCursor_impl(globalPos, DockRegistry::self()->floatingQWindows(), tlwBeingDragged))
|
||||
return tl;
|
||||
|
||||
return qtTopLevelUnderCursor_impl<WidgetType*>(globalPos,
|
||||
|
||||
@@ -52,7 +52,10 @@ public:
|
||||
void grabMouseFor(QWidgetOrQuick *);
|
||||
void releaseMouse(QWidgetOrQuick *);
|
||||
|
||||
FloatingWindow *windowBeingDragged() const;
|
||||
FloatingWindow *floatingWindowBeingDragged() const;
|
||||
|
||||
///@brief Returns the window being dragged
|
||||
WindowBeingDragged* windowBeingDragged() const;
|
||||
|
||||
/// Experimental, internal, not for general use.
|
||||
void enableFallbackMouseGrabber();
|
||||
@@ -101,6 +104,9 @@ public:
|
||||
virtual bool handleMouseMove(QPoint /*globalPos*/) { return false; }
|
||||
virtual bool handleMouseButtonRelease(QPoint /*globalPos*/) { return false; }
|
||||
|
||||
// Returns whether this is the current state
|
||||
bool isActiveState() const;
|
||||
|
||||
DragController *const q;
|
||||
};
|
||||
|
||||
@@ -125,6 +131,7 @@ public:
|
||||
bool handleMouseButtonRelease(QPoint) override;
|
||||
};
|
||||
|
||||
// Used on all platforms except Wayland. @see StateDraggingWayland
|
||||
class StateDragging : public StateBase
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -136,6 +143,18 @@ public:
|
||||
bool handleMouseMove(QPoint globalPos) override;
|
||||
};
|
||||
|
||||
// Used on wayland only to use QDrag instead of setting geometry on mouse-move.
|
||||
class StateDraggingWayland : public StateDragging
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit StateDraggingWayland(DragController *parent);
|
||||
~StateDraggingWayland() override;
|
||||
void onEntry(QEvent *) override;
|
||||
bool handleMouseButtonRelease(QPoint globalPos) override;
|
||||
bool handleMouseMove(QPoint globalPos) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -174,7 +174,7 @@ void DropArea::layoutParentContainerEqually(DockWidgetBase *dw)
|
||||
layoutEqually(item->parentContainer());
|
||||
}
|
||||
|
||||
void DropArea::hover(FloatingWindow *floatingWindow, QPoint globalPos)
|
||||
void DropArea::hover(WindowBeingDragged *floatingWindow, QPoint globalPos)
|
||||
{
|
||||
if (!validateAffinity(floatingWindow))
|
||||
return;
|
||||
@@ -185,7 +185,7 @@ void DropArea::hover(FloatingWindow *floatingWindow, QPoint globalPos)
|
||||
}
|
||||
|
||||
Frame *frame = frameContainingPos(globalPos); // Frame is nullptr if MainWindowOption_HasCentralFrame isn't set
|
||||
m_dropIndicatorOverlay->setWindowBeingDragged(floatingWindow);
|
||||
m_dropIndicatorOverlay->setWindowBeingDragged(floatingWindow != nullptr);
|
||||
m_dropIndicatorOverlay->setHoveredFrame(frame);
|
||||
m_dropIndicatorOverlay->hover(globalPos);
|
||||
}
|
||||
@@ -203,9 +203,12 @@ static bool isOutterLocation(DropIndicatorOverlayInterface::DropLocation locatio
|
||||
}
|
||||
}
|
||||
|
||||
bool DropArea::drop(FloatingWindow *droppedWindow, QPoint globalPos)
|
||||
bool DropArea::drop(WindowBeingDragged *droppedWindow, QPoint globalPos)
|
||||
{
|
||||
if (droppedWindow == window()) {
|
||||
FloatingWindow *floatingWindow = droppedWindow ? droppedWindow->floatingWindow()
|
||||
: nullptr;
|
||||
|
||||
if (floatingWindow == window()) {
|
||||
qWarning() << "Refusing to drop onto itself"; // Doesn't happen
|
||||
return false;
|
||||
}
|
||||
@@ -225,7 +228,7 @@ bool DropArea::drop(FloatingWindow *droppedWindow, QPoint globalPos)
|
||||
return false;
|
||||
}
|
||||
|
||||
return drop(droppedWindow, acceptingFrame, droploc);
|
||||
return drop(floatingWindow, acceptingFrame, droploc);
|
||||
}
|
||||
|
||||
bool DropArea::drop(FloatingWindow *droppedWindow, Frame *acceptingFrame,
|
||||
@@ -314,7 +317,7 @@ bool DropArea::drop(QWidgetOrQuick *droppedWindow, KDDockWidgets::Location locat
|
||||
|
||||
void DropArea::removeHover()
|
||||
{
|
||||
m_dropIndicatorOverlay->setWindowBeingDragged(nullptr);
|
||||
m_dropIndicatorOverlay->setWindowBeingDragged(false);
|
||||
m_dropIndicatorOverlay->setCurrentDropLocation(DropIndicatorOverlayInterface::DropLocation_None);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include "MultiSplitter_p.h"
|
||||
#include "DropIndicatorOverlayInterface_p.h"
|
||||
|
||||
class TestCommon;
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class Frame;
|
||||
@@ -42,9 +44,9 @@ public:
|
||||
~DropArea();
|
||||
|
||||
void removeHover();
|
||||
void hover(FloatingWindow *floatingWindow, QPoint globalPos);
|
||||
void hover(WindowBeingDragged *floatingWindow, QPoint globalPos);
|
||||
///@brief Called when a user drops a widget via DND
|
||||
bool drop(FloatingWindow *droppedWindow, QPoint globalPos);
|
||||
bool drop(WindowBeingDragged *droppedWindow, QPoint globalPos);
|
||||
int numFrames() const;
|
||||
Frame::List frames() const;
|
||||
|
||||
@@ -64,6 +66,7 @@ private:
|
||||
Q_DISABLE_COPY(DropArea)
|
||||
friend class Frame;
|
||||
friend class TestDocks;
|
||||
friend class ::TestCommon;
|
||||
friend class DropIndicatorOverlayInterface;
|
||||
friend class AnimatedIndicators;
|
||||
friend class FloatingWindow;
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
#include "Frame_p.h"
|
||||
#include "DropArea_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
@@ -25,20 +24,20 @@ DropIndicatorOverlayInterface::DropIndicatorOverlayInterface(DropArea *dropArea)
|
||||
setObjectName(QStringLiteral("DropIndicatorOverlayInterface"));
|
||||
}
|
||||
|
||||
void DropIndicatorOverlayInterface::setWindowBeingDragged(const FloatingWindow *window)
|
||||
void DropIndicatorOverlayInterface::setWindowBeingDragged(bool is)
|
||||
{
|
||||
if (window == m_windowBeingDragged)
|
||||
if (is == m_draggedWindowIsHovering)
|
||||
return;
|
||||
|
||||
m_windowBeingDragged = window;
|
||||
if (m_windowBeingDragged) {
|
||||
m_draggedWindowIsHovering = is;
|
||||
if (is) {
|
||||
setGeometry(m_dropArea->QWidgetAdapter::rect());
|
||||
raise();
|
||||
} else {
|
||||
setHoveredFrame(nullptr);
|
||||
}
|
||||
|
||||
setVisible(m_windowBeingDragged != nullptr);
|
||||
setVisible(is);
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
@@ -70,7 +69,7 @@ void DropIndicatorOverlayInterface::setHoveredFrame(Frame *frame)
|
||||
|
||||
bool DropIndicatorOverlayInterface::isHovered() const
|
||||
{
|
||||
return m_windowBeingDragged != nullptr;
|
||||
return m_draggedWindowIsHovering;
|
||||
}
|
||||
|
||||
DropIndicatorOverlayInterface::DropLocation DropIndicatorOverlayInterface::currentDropLocation() const
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class FloatingWindow;
|
||||
class DropArea;
|
||||
|
||||
class DOCKS_EXPORT DropIndicatorOverlayInterface : public QWidgetAdapter
|
||||
@@ -47,7 +46,7 @@ public:
|
||||
|
||||
explicit DropIndicatorOverlayInterface(DropArea *dropArea);
|
||||
void setHoveredFrame(Frame *);
|
||||
void setWindowBeingDragged(const FloatingWindow *);
|
||||
void setWindowBeingDragged(bool);
|
||||
QRect hoveredFrameRect() const;
|
||||
bool isHovered() const;
|
||||
DropLocation currentDropLocation() const;
|
||||
@@ -77,8 +76,8 @@ protected:
|
||||
virtual void updateVisibility() {};
|
||||
|
||||
Frame *m_hoveredFrame = nullptr;
|
||||
QPointer<const FloatingWindow> m_windowBeingDragged;
|
||||
DropArea *const m_dropArea;
|
||||
bool m_draggedWindowIsHovering = false;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ FloatingWindow::FloatingWindow(MainWindowBase *parent)
|
||||
}
|
||||
#endif
|
||||
|
||||
DockRegistry::self()->registerNestedWindow(this);
|
||||
DockRegistry::self()->registerFloatingWindow(this);
|
||||
qCDebug(creation) << "FloatingWindow()" << this;
|
||||
|
||||
maybeCreateResizeHandler();
|
||||
@@ -184,7 +184,7 @@ FloatingWindow::~FloatingWindow()
|
||||
disconnect(m_layoutDestroyedConnection);
|
||||
delete m_nchittestFilter;
|
||||
|
||||
DockRegistry::self()->unregisterNestedWindow(this);
|
||||
DockRegistry::self()->unregisterFloatingWindow(this);
|
||||
qCDebug(creation) << "~FloatingWindow";
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ void FloatingWindow::setSuggestedGeometry(QRect suggestedRect, bool preserveCent
|
||||
void FloatingWindow::scheduleDeleteLater()
|
||||
{
|
||||
m_deleteScheduled = true;
|
||||
DockRegistry::self()->unregisterNestedWindow(this);
|
||||
DockRegistry::self()->unregisterFloatingWindow(this);
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
@@ -350,9 +350,7 @@ void FloatingWindow::updateTitleBarVisibility()
|
||||
|
||||
bool visible = true;
|
||||
|
||||
if (KDDockWidgets::usesNativeTitleBar()) {
|
||||
visible = false;
|
||||
} else {
|
||||
if (KDDockWidgets::usesClientTitleBar()) {
|
||||
const auto flags = Config::self().flags();
|
||||
if ((flags & Config::Flag_HideTitleBarWhenTabsVisible) && !(flags & Config::Flag_AlwaysTitleBarWhenFloating)) {
|
||||
if (hasSingleFrame()) {
|
||||
@@ -362,6 +360,8 @@ void FloatingWindow::updateTitleBarVisibility()
|
||||
|
||||
for (Frame *frame : frames())
|
||||
frame->updateTitleBarVisibility();
|
||||
} else {
|
||||
visible = false;
|
||||
}
|
||||
|
||||
m_titleBar->setVisible(visible);
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
#include "multisplitter/Widget_qwidget.h"
|
||||
#include "DropArea_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
|
||||
#include <QScopedValueRollback>
|
||||
|
||||
@@ -436,17 +437,16 @@ Layouting::ItemContainer *MultiSplitter::rootItem() const
|
||||
return m_rootItem;
|
||||
}
|
||||
|
||||
QRect MultiSplitter::rectForDrop(const FloatingWindow *fw, Location location,
|
||||
QRect MultiSplitter::rectForDrop(const WindowBeingDragged *wbd, Location location,
|
||||
const Layouting::Item *relativeTo) const
|
||||
{
|
||||
Layouting::Item item(nullptr);
|
||||
if (!fw)
|
||||
if (!wbd)
|
||||
return {};
|
||||
|
||||
Layouting::ItemContainer *root = fw->dropArea()->rootItem();
|
||||
item.setSize(fw->size().boundedTo(root->maxSizeHint()));
|
||||
item.setMinSize(root->minSize());
|
||||
item.setMaxSizeHint(root->maxSizeHint());
|
||||
item.setSize(wbd->size().boundedTo(wbd->maxSize()));
|
||||
item.setMinSize(wbd->minSize());
|
||||
item.setMaxSizeHint(wbd->maxSize());
|
||||
|
||||
Layouting::ItemContainer *container = relativeTo ? relativeTo->parentContainer()
|
||||
: m_rootItem;
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace KDDockWidgets {
|
||||
class MainWindowBase;
|
||||
class FloatingWindow;
|
||||
class Frame;
|
||||
|
||||
class WindowBeingDragged;
|
||||
|
||||
/**
|
||||
* MultiSplitter is simply a wrapper around Layouting::Item in which the hosted widgets are
|
||||
@@ -131,7 +131,7 @@ public:
|
||||
* Excludes the Separator thickness, result is actually smaller than what needed. In other words,
|
||||
* the result will be exactly the same as the geometry the widget will get.
|
||||
*/
|
||||
QRect rectForDrop(const FloatingWindow *, KDDockWidgets::Location location,
|
||||
QRect rectForDrop(const WindowBeingDragged *wbd, KDDockWidgets::Location location,
|
||||
const Layouting::Item *relativeTo) const;
|
||||
|
||||
bool deserialize(const LayoutSaver::MultiSplitter &);
|
||||
|
||||
@@ -125,7 +125,7 @@ void Position::deserialize(const LayoutSaver::Position &lp)
|
||||
if (index == -1) {
|
||||
continue; // Skip
|
||||
} else {
|
||||
const auto floatingWindows = DockRegistry::self()->nestedwindows();
|
||||
const auto floatingWindows = DockRegistry::self()->floatingWindows();
|
||||
if (index >= 0 && index < floatingWindows.size()) {
|
||||
FloatingWindow *fw = floatingWindows.at(index);
|
||||
layout = fw->multiSplitter();
|
||||
@@ -170,7 +170,7 @@ LayoutSaver::Position Position::serialize() const
|
||||
p.isFloatingWindow = fw;
|
||||
|
||||
if (p.isFloatingWindow) {
|
||||
p.indexOfFloatingWindow = fw->beingDeleted() ? -1 : DockRegistry::self()->nestedwindows().indexOf(fw); // TODO: Remove once we stop using deleteLater with FloatingWindow. delete would be better
|
||||
p.indexOfFloatingWindow = fw->beingDeleted() ? -1 : DockRegistry::self()->floatingWindows().indexOf(fw); // TODO: Remove once we stop using deleteLater with FloatingWindow. delete would be better
|
||||
} else {
|
||||
p.mainWindowUniqueName = mainWindow->uniqueName();
|
||||
Q_ASSERT(!p.mainWindowUniqueName.isEmpty());
|
||||
|
||||
@@ -27,6 +27,8 @@ class QHBoxLayout;
|
||||
class QLabel;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class TestCommon;
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
class DockWidgetBase;
|
||||
@@ -127,6 +129,7 @@ protected:
|
||||
|
||||
private:
|
||||
friend class TestDocks;
|
||||
friend class ::TestCommon;
|
||||
|
||||
void init();
|
||||
|
||||
|
||||
@@ -30,6 +30,11 @@
|
||||
|
||||
namespace KDDockWidgets {
|
||||
|
||||
inline bool isWayland()
|
||||
{
|
||||
return qApp->platformName() == QLatin1String("wayland");
|
||||
}
|
||||
|
||||
inline bool isLeftButtonPressed()
|
||||
{
|
||||
return qApp->mouseButtons() & Qt::LeftButton;
|
||||
@@ -40,6 +45,17 @@ inline bool usesNativeTitleBar()
|
||||
return Config::self().flags() & Config::Flag_NativeTitleBar;
|
||||
}
|
||||
|
||||
inline bool usesClientTitleBar()
|
||||
{
|
||||
if (isWayland()) {
|
||||
// Wayland has both client and native title bars, due to limitations.
|
||||
return true;
|
||||
}
|
||||
|
||||
// All other platforms have either the OS native title bar or a Qt title bar (aka client title bar).
|
||||
return !usesNativeTitleBar();
|
||||
}
|
||||
|
||||
inline bool usesAeroSnapWithCustomDecos()
|
||||
{
|
||||
return Config::self().flags() & Config::Flag_AeroSnapWithClientDecos;
|
||||
|
||||
@@ -13,11 +13,15 @@
|
||||
#include "DragController_p.h"
|
||||
#include "Logging_p.h"
|
||||
#include "Utils_p.h"
|
||||
#include "DropArea_p.h"
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
|
||||
static Draggable* bestDraggable(Draggable *draggable)
|
||||
{
|
||||
if (!draggable)
|
||||
return nullptr;
|
||||
|
||||
// When de detach a title bar it will get hidden and we only the title bar of the FloatingWindow is visible
|
||||
/// Apparently that causes problems with grabbing the mouse, so instead use a visible draggable.
|
||||
// grabbing mouse on an hidden window works usually, it's some edge case on Windows with MFC.
|
||||
@@ -45,6 +49,7 @@ static Draggable* bestDraggable(Draggable *draggable)
|
||||
WindowBeingDragged::WindowBeingDragged(FloatingWindow *fw, Draggable *draggable)
|
||||
: m_floatingWindow(fw)
|
||||
, m_draggable(bestDraggable(draggable)->asWidget())
|
||||
, m_affinities(fw->affinities())
|
||||
{
|
||||
init();
|
||||
|
||||
@@ -53,6 +58,17 @@ WindowBeingDragged::WindowBeingDragged(FloatingWindow *fw, Draggable *draggable)
|
||||
if (!qIsNaN(opacity) && !qFuzzyCompare(1.0, opacity))
|
||||
fw->setWindowOpacity(opacity);
|
||||
}
|
||||
#if DOCKS_DEVELOPER_MODE
|
||||
|
||||
// Just used by tests
|
||||
WindowBeingDragged::WindowBeingDragged(FloatingWindow *fw)
|
||||
: m_floatingWindow(fw)
|
||||
, m_draggable(nullptr)
|
||||
, m_affinities(fw->affinities())
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
WindowBeingDragged::~WindowBeingDragged()
|
||||
{
|
||||
@@ -82,3 +98,36 @@ void WindowBeingDragged::grabMouse(bool grab)
|
||||
else
|
||||
DragController::instance()->releaseMouse(m_draggable);
|
||||
}
|
||||
|
||||
QStringList WindowBeingDragged::affinities() const
|
||||
{
|
||||
return m_affinities;
|
||||
}
|
||||
|
||||
QSize WindowBeingDragged::size() const
|
||||
{
|
||||
if (m_floatingWindow)
|
||||
return m_floatingWindow->size();
|
||||
|
||||
return QSize();
|
||||
}
|
||||
|
||||
QSize WindowBeingDragged::minSize() const
|
||||
{
|
||||
if (m_floatingWindow) {
|
||||
Layouting::ItemContainer *root = m_floatingWindow->dropArea()->rootItem();
|
||||
return root->minSize();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
QSize WindowBeingDragged::maxSize() const
|
||||
{
|
||||
if (m_floatingWindow) {
|
||||
Layouting::ItemContainer *root = m_floatingWindow->dropArea()->rootItem();
|
||||
return root->maxSizeHint();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -26,6 +26,11 @@ struct DOCKS_EXPORT_FOR_UNIT_TESTS WindowBeingDragged
|
||||
{
|
||||
public:
|
||||
explicit WindowBeingDragged(FloatingWindow *fw, Draggable *draggable);
|
||||
#if DOCKS_DEVELOPER_MODE
|
||||
// For tests.
|
||||
explicit WindowBeingDragged(FloatingWindow *fw);
|
||||
#endif
|
||||
|
||||
~WindowBeingDragged();
|
||||
void init();
|
||||
|
||||
@@ -34,10 +39,23 @@ public:
|
||||
///@brief grabs or releases the mouse
|
||||
void grabMouse(bool grab);
|
||||
|
||||
///@brief returns the affinities of the window being dragged
|
||||
QStringList affinities() const;
|
||||
|
||||
///@brief size of the window being dragged contents
|
||||
QSize size() const;
|
||||
|
||||
/// @brief returns the min-size of the window being dragged contents
|
||||
QSize minSize() const;
|
||||
|
||||
/// @brief returns the max-size of the window being dragged contents
|
||||
QSize maxSize() const;
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(WindowBeingDragged)
|
||||
QPointer<FloatingWindow> m_floatingWindow;
|
||||
QPointer<QWidgetOrQuick> m_draggable;
|
||||
const QStringList m_affinities;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -92,15 +92,17 @@ void ClassicIndicators::updateIndicatorsVisibility(bool visible)
|
||||
|
||||
m_innerIndicatorsVisible = visible && m_hoveredFrame;
|
||||
|
||||
WindowBeingDragged *windowBeingDragged = DragController::instance()->windowBeingDragged();
|
||||
|
||||
// If there's only 1 frame in the layout, the outter indicators are redundant, as they do the same thing as the internal ones.
|
||||
// But there might be another window obscuring our target, so it's useful to show the outter indicators in this case
|
||||
m_outterIndicatorsVisible = visible && (!isTheOnlyFrame ||
|
||||
DockRegistry::self()->isProbablyObscured(m_hoveredFrame->window()->windowHandle(), DragController::instance()->windowBeingDragged()));
|
||||
DockRegistry::self()->isProbablyObscured(m_hoveredFrame->window()->windowHandle(), windowBeingDragged));
|
||||
|
||||
|
||||
// Only allow to dock to center if the affinities match
|
||||
m_tabIndicatorVisible = m_innerIndicatorsVisible && m_windowBeingDragged &&
|
||||
DockRegistry::self()->affinitiesMatch(m_hoveredFrame->affinities(), m_windowBeingDragged->affinities());
|
||||
m_tabIndicatorVisible = m_innerIndicatorsVisible && windowBeingDragged &&
|
||||
DockRegistry::self()->affinitiesMatch(m_hoveredFrame->affinities(), windowBeingDragged->affinities());
|
||||
|
||||
Q_EMIT innerIndicatorsVisibleChanged();
|
||||
Q_EMIT outterIndicatorsVisibleChanged();
|
||||
@@ -161,7 +163,7 @@ void ClassicIndicators::setDropLocation(ClassicIndicators::DropLocation location
|
||||
case DropLocation_Bottom:
|
||||
if (!m_hoveredFrame) {
|
||||
qWarning() << "ClassicIndicators::setCurrentDropLocation: frame is null. location=" << location
|
||||
<< "; windowBeingDragged=" << m_windowBeingDragged
|
||||
<< "; isHovered=" << isHovered()
|
||||
<< "; dropArea->widgets=" << m_dropArea->items();
|
||||
Q_ASSERT(false);
|
||||
return;
|
||||
@@ -177,7 +179,9 @@ void ClassicIndicators::setDropLocation(ClassicIndicators::DropLocation location
|
||||
break;
|
||||
}
|
||||
|
||||
QRect rect = m_dropArea->rectForDrop(m_windowBeingDragged, multisplitterLocation,
|
||||
auto windowBeingDragged = DragController::instance()->windowBeingDragged();
|
||||
|
||||
QRect rect = m_dropArea->rectForDrop(windowBeingDragged, multisplitterLocation,
|
||||
m_dropArea->itemForFrame(relativeToFrame));
|
||||
|
||||
m_rubberBand->setGeometry(rect);
|
||||
|
||||
@@ -279,7 +279,12 @@ QObject *Item::host() const
|
||||
|
||||
void Item::restore(Widget *guest)
|
||||
{
|
||||
Q_ASSERT(!isVisible() && !guestAsQObject());
|
||||
if (isVisible() || guestAsQObject()) {
|
||||
qWarning() << Q_FUNC_INFO << "Hitting assert. visible="
|
||||
<< isVisible() << "; guest=" << guestAsQObject();
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
|
||||
if (isContainer()) {
|
||||
qWarning() << Q_FUNC_INFO << "Containers can't be restored";
|
||||
} else {
|
||||
@@ -634,9 +639,14 @@ bool Item::checkSanity()
|
||||
|
||||
if (m_guest) {
|
||||
if (m_guest->parent() != hostWidget()->asQObject()) {
|
||||
qWarning() << Q_FUNC_INFO << "Unexpected parent for our guest"
|
||||
<< m_guest->parent() << "; host=" << hostWidget()
|
||||
<< m_guest->asQObject() << this;
|
||||
if (root())
|
||||
root()->dumpLayout();
|
||||
qWarning() << Q_FUNC_INFO << "Unexpected parent for our guest. guest.parent="
|
||||
<< m_guest->parent() << "; host=" << hostWidget()->asQObject()
|
||||
<< "; guest.asObj=" << m_guest->asQObject()
|
||||
<< "; this=" << this
|
||||
<< "; item.parentContainer=" << parentContainer()
|
||||
<< "; item.root.parent=" << (root() ? root()->parent() : nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,10 @@ public:
|
||||
virtual void setLayoutItem(Item *) = 0;
|
||||
|
||||
// Not strickly necessary, but it's nice conveniance for kddw which is widget based.
|
||||
virtual QWidget *asQWidget() const { return nullptr; }
|
||||
virtual QWidget *asQWidget() const {
|
||||
Q_ASSERT(false); // Only wanted for QtWidgets. All other should not call this.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual QSize sizeHint() const { return {}; }
|
||||
virtual QSize minSize() const = 0;
|
||||
|
||||
@@ -45,8 +45,8 @@ void Widget_quick::setParent(Widget *parent)
|
||||
}
|
||||
|
||||
if (auto qquickitem = qobject_cast<QQuickItem*>(parent->asQObject())) {
|
||||
m_thisWidget->setParentItem(qquickitem);
|
||||
m_thisWidget->setParent(qquickitem);
|
||||
m_thisWidget->setParentItem(qquickitem);
|
||||
} else {
|
||||
qWarning() << Q_FUNC_INFO << "parent is not a widget, you have a bug" << parent->asQObject();
|
||||
Q_ASSERT(false);
|
||||
|
||||
@@ -82,7 +82,7 @@ bool DockWidgetQuick::event(QEvent *e)
|
||||
} else if (e->type() == QEvent::Hide) {
|
||||
onHidden(e->spontaneous());
|
||||
} else if (e->type() == QEvent::Close) {
|
||||
onClosed(static_cast<QCloseEvent*>(e));
|
||||
onCloseEvent(static_cast<QCloseEvent*>(e));
|
||||
}
|
||||
|
||||
return DockWidgetBase::event(e);
|
||||
|
||||
@@ -64,7 +64,7 @@ FloatingWindowQuick::~FloatingWindowQuick()
|
||||
|
||||
void FloatingWindowQuick::setGeometry(QRect geo)
|
||||
{
|
||||
FloatingWindow::setGeometry(geo);
|
||||
parentItem()->setSize(geo.size());
|
||||
m_quickWindow->setGeometry(geo);
|
||||
}
|
||||
|
||||
@@ -85,13 +85,17 @@ void FloatingWindowQuick::init()
|
||||
}
|
||||
});
|
||||
|
||||
m_quickWindow->setResizeMode(QQuickView::SizeRootObjectToView);
|
||||
const QSize minSize(100, 100);
|
||||
m_quickWindow->resize(minSize);
|
||||
m_quickWindow->contentItem()->setSize(minSize);
|
||||
|
||||
|
||||
m_quickWindow->setTransientParent(candidateParentWindow());
|
||||
|
||||
QWidgetAdapter::setParent(m_quickWindow->contentItem());
|
||||
QWidgetAdapter::makeItemFillParent(this);
|
||||
|
||||
m_quickWindow->setResizeMode(QQuickView::SizeViewToRootObject);
|
||||
|
||||
QQuickItem *visualItem = createItem(Config::self().qmlEngine(), QStringLiteral("qrc:/kddockwidgets/private/quick/qml/FloatingWindow.qml"));
|
||||
Q_ASSERT(visualItem);
|
||||
visualItem->setParent(this);
|
||||
@@ -99,5 +103,4 @@ void FloatingWindowQuick::init()
|
||||
|
||||
m_quickWindow->setFlags(windowFlags());
|
||||
m_quickWindow->show();
|
||||
m_quickWindow->setGeometry(200, 200, 800, 800); // TODO: remove
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ QVariant DockWidgetModel::data(const QModelIndex &index, int role) const
|
||||
DockWidgetBase *DockWidgetModel::dockWidgetAt(int index) const
|
||||
{
|
||||
if (index < 0 || index >= m_dockWidgets.size()) {
|
||||
qWarning() << Q_FUNC_INFO << "Shouldn't happen" << index << m_dockWidgets.size();
|
||||
// Can happen. Benign.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,12 +26,12 @@ MainWindowQuick::MainWindowQuick(const QString &uniqueName, MainWindowOptions op
|
||||
|
||||
SideBar *MainWindowQuick::sideBar(SideBarLocation) const
|
||||
{
|
||||
qWarning() << Q_FUNC_INFO << "SideBar hasn't been implemented yet";
|
||||
qDebug() << Q_FUNC_INFO << "SideBar hasn't been implemented yet";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QMargins MainWindowQuick::centerWidgetMargins() const
|
||||
{
|
||||
qWarning() << Q_FUNC_INFO << "SideBar hasn't been implemented yet";
|
||||
qDebug() << Q_FUNC_INFO << "SideBar hasn't been implemented yet";
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ void QWidgetAdapter::itemChange(QQuickItem::ItemChange change, const QQuickItem:
|
||||
switch (change) {
|
||||
case QQuickItem::ItemParentHasChanged: {
|
||||
QEvent ev(QEvent::ParentChange);
|
||||
event(&ev);
|
||||
qApp->sendEvent(this, &ev); // Not calling event() directly, otherwise it would skip event filters
|
||||
Q_EMIT parentChanged();
|
||||
break;
|
||||
}
|
||||
@@ -93,6 +93,24 @@ void QWidgetAdapter::itemChange(QQuickItem::ItemChange change, const QQuickItem:
|
||||
}
|
||||
}
|
||||
|
||||
void QWidgetAdapter::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
|
||||
{
|
||||
// Send a few events manually, since QQuickItem doesn't do it for us.
|
||||
QQuickItem::geometryChanged(newGeometry, oldGeometry);
|
||||
|
||||
// Not calling event() directly, otherwise it would skip event filters
|
||||
|
||||
if (newGeometry.size() != oldGeometry.size()) {
|
||||
QEvent ev(QEvent::Resize);
|
||||
qApp->sendEvent(this, &ev);
|
||||
}
|
||||
|
||||
if (newGeometry.topLeft() != oldGeometry.topLeft()) {
|
||||
QEvent ev(QEvent::Move);
|
||||
qApp->sendEvent(this, &ev);
|
||||
}
|
||||
}
|
||||
|
||||
void QWidgetAdapter::raise()
|
||||
{
|
||||
if (QWindow *w = windowHandle())
|
||||
@@ -141,8 +159,7 @@ void QWidgetAdapter::setGeometry(QRect rect)
|
||||
{
|
||||
setWidth(rect.width());
|
||||
setHeight(rect.height());
|
||||
setX(rect.x());
|
||||
setY(rect.y());
|
||||
move(rect.topLeft());
|
||||
}
|
||||
|
||||
void QWidgetAdapter::grabMouse()
|
||||
@@ -254,6 +271,19 @@ QPoint QWidgetAdapter::mapTo(const QQuickItem *parent, const QPoint &pos) const
|
||||
return parent->mapFromGlobal(QQuickItem::mapToGlobal(pos)).toPoint();
|
||||
}
|
||||
|
||||
bool QWidgetAdapter::testAttribute(Qt::WidgetAttribute attr) const
|
||||
{
|
||||
return m_widgetAttributes & attr;
|
||||
}
|
||||
|
||||
void QWidgetAdapter::setAttribute(Qt::WidgetAttribute attr, bool enable)
|
||||
{
|
||||
if (enable)
|
||||
m_widgetAttributes |= attr;
|
||||
else
|
||||
m_widgetAttributes &= ~attr;
|
||||
}
|
||||
|
||||
void QWidgetAdapter::setWindowTitle(const QString &title)
|
||||
{
|
||||
if (QWindow *window = windowHandle())
|
||||
@@ -281,10 +311,16 @@ QQuickItem *QWidgetAdapter::childAt(QPoint p) const
|
||||
return QQuickItem::childAt(p.x(), p.y());
|
||||
}
|
||||
|
||||
void QWidgetAdapter::move(QPoint pt)
|
||||
{
|
||||
move(pt.x(), pt.y());
|
||||
}
|
||||
|
||||
void QWidgetAdapter::move(int x, int y)
|
||||
{
|
||||
setX(x);
|
||||
setY(y);
|
||||
setAttribute(Qt::WA_Moved);
|
||||
}
|
||||
|
||||
void QWidgetAdapter::setParent(QQuickItem *p)
|
||||
|
||||
@@ -124,13 +124,15 @@ public:
|
||||
QPoint mapToGlobal(QPoint pt) const;
|
||||
QPoint mapFromGlobal(QPoint) const;
|
||||
QPoint mapTo(const QQuickItem *parent, const QPoint &pos) const;
|
||||
bool testAttribute(Qt::WidgetAttribute) { return false; }
|
||||
bool testAttribute(Qt::WidgetAttribute) const;
|
||||
void setAttribute(Qt::WidgetAttribute, bool enabled = true);
|
||||
|
||||
void setWindowTitle(const QString &);
|
||||
void setWindowIcon(const QIcon &);
|
||||
void close();
|
||||
QQuickItem *childAt(QPoint) const;
|
||||
void move(int x, int y);
|
||||
void move(QPoint);
|
||||
|
||||
void setParent(QQuickItem*);
|
||||
void activateWindow();
|
||||
@@ -149,6 +151,7 @@ public:
|
||||
Q_SIGNALS:
|
||||
void parentChanged();
|
||||
protected:
|
||||
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
|
||||
void raiseAndActivate();
|
||||
virtual bool onResize(QSize newSize);
|
||||
virtual void onLayoutRequest();
|
||||
@@ -163,6 +166,7 @@ private:
|
||||
QSize m_minimumSize = {KDDOCKWIDGETS_MIN_WIDTH, KDDOCKWIDGETS_MIN_HEIGHT};
|
||||
QSize m_maximumSize = {KDDOCKWIDGETS_MAX_WIDTH, KDDOCKWIDGETS_MAX_HEIGHT};
|
||||
Qt::WindowFlags m_windowFlags;
|
||||
int m_widgetAttributes = 0; // Qt::WidgetAttribute
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
void KDDockWidgets::registerQmlTypes()
|
||||
{
|
||||
qDebug() << "Registering types";
|
||||
qmlRegisterType<DropAreaWithCentralFrame>("com.kdab.dockwidgets", 1, 0, "DropAreaWithCentralFrame");
|
||||
qmlRegisterType<MainWindowWrapper>("com.kdab.dockwidgets", 1, 0, "MainWindow");
|
||||
|
||||
|
||||
@@ -68,5 +68,5 @@ bool DockWidget::event(QEvent *e)
|
||||
|
||||
void DockWidget::closeEvent(QCloseEvent *e)
|
||||
{
|
||||
onClosed(e);
|
||||
onCloseEvent(e);
|
||||
}
|
||||
|
||||
@@ -64,8 +64,8 @@ static bool shouldBlacklistWarning(const QString &msg, const QString &category)
|
||||
msg.contains(QLatin1String("Testing::")) ||
|
||||
msg.contains(QLatin1String("outside any known screen, using primary screen"))
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
// TODO: Debug why this happens
|
||||
|| msg.contains(QLatin1String("Layouting::ItemContainer::setSize_recursive"))
|
||||
// TODO: Fix later, not important right now
|
||||
|| msg.contains(QLatin1String("Binding loop detected for property"))
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
@@ -137,6 +137,22 @@ namespace Testing {
|
||||
QSize m_minSz;
|
||||
};
|
||||
}
|
||||
|
||||
struct SetExpectedWarning
|
||||
{
|
||||
explicit SetExpectedWarning(const QString &s)
|
||||
{
|
||||
if (!s.isEmpty())
|
||||
Testing::setExpectedWarning(s);
|
||||
}
|
||||
|
||||
~SetExpectedWarning()
|
||||
{
|
||||
Testing::setExpectedWarning({});
|
||||
}
|
||||
Q_DISABLE_COPY(SetExpectedWarning)
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -107,7 +107,7 @@ void Fuzzer::runTest(const Test &test)
|
||||
for (MainWindowBase *mw : DockRegistry::self()->mainwindows())
|
||||
delete mw;
|
||||
|
||||
for (FloatingWindow *fw : DockRegistry::self()->nestedwindows())
|
||||
for (FloatingWindow *fw : DockRegistry::self()->floatingWindows())
|
||||
delete fw;
|
||||
|
||||
for (DockWidgetBase *dw : DockRegistry::self()->dockwidgets())
|
||||
|
||||
@@ -19,14 +19,21 @@
|
||||
#include "private/MultiSplitter_p.h"
|
||||
#include "TitleBar_p.h"
|
||||
#include "Position_p.h"
|
||||
#include "DropAreaWithCentralFrame_p.h"
|
||||
#include "WindowBeingDragged_p.h"
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
#include <QObject>
|
||||
#include <QApplication>
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
# include "quick/DockWidgetQuick.h"
|
||||
|
||||
# include <QQmlEngine>
|
||||
# include <QQuickStyle>
|
||||
# else
|
||||
# include "DockWidget.h"
|
||||
# include <QPushButton>
|
||||
#endif
|
||||
|
||||
using namespace KDDockWidgets;
|
||||
@@ -61,12 +68,38 @@ public Q_SLOTS:
|
||||
|
||||
private Q_SLOTS:
|
||||
void tst_simple1();
|
||||
void tst_simple2();
|
||||
void tst_doesntHaveNativeTitleBar();
|
||||
void tst_resizeWindow2();
|
||||
void tst_hasLastDockedLocation();
|
||||
void tst_ghostSeparator();
|
||||
void tst_detachFromMainWindow();
|
||||
void tst_detachPos();
|
||||
void tst_floatingWindowSize();
|
||||
void tst_sizeAfterRedock();
|
||||
void tst_tabbingWithAffinities();
|
||||
void tst_honourUserGeometry();
|
||||
void tst_floatingWindowTitleBug();
|
||||
void tst_setFloatingSimple();
|
||||
|
||||
void tst_resizeWindow_data();
|
||||
void tst_resizeWindow();
|
||||
void tst_restoreEmpty();
|
||||
void tst_restoreCentralFrame();
|
||||
void tst_shutdown();
|
||||
void tst_doubleClose();
|
||||
void tst_dockInternal();
|
||||
void tst_maximizeAndRestore();
|
||||
void tst_propagateResize2();
|
||||
void tst_28NestedWidgets();
|
||||
void tst_28NestedWidgets_data();
|
||||
void tst_negativeAnchorPosition2();
|
||||
void tst_negativeAnchorPosition3();
|
||||
void tst_negativeAnchorPosition4();
|
||||
void tst_negativeAnchorPosition5();
|
||||
void tst_startHidden();
|
||||
void tst_closeReparentsToNull();
|
||||
void tst_invalidAnchorGroup();
|
||||
};
|
||||
|
||||
void TestCommon::tst_simple1()
|
||||
@@ -77,6 +110,19 @@ void TestCommon::tst_simple1()
|
||||
m->multiSplitter()->checkSanity();
|
||||
}
|
||||
|
||||
void TestCommon::tst_simple2()
|
||||
{
|
||||
// Simply create a MainWindow, and dock something on top
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow();
|
||||
auto dw = createDockWidget("dw", new MyWidget("dw", Qt::blue));
|
||||
auto fw = dw->floatingWindow();
|
||||
m->addDockWidget(dw, KDDockWidgets::Location_OnTop);
|
||||
m->multiSplitter()->checkSanity();
|
||||
delete fw;
|
||||
}
|
||||
|
||||
|
||||
void TestCommon::tst_doesntHaveNativeTitleBar()
|
||||
{
|
||||
// Tests that a floating window doesn't have a native title bar
|
||||
@@ -130,6 +176,10 @@ void TestCommon::tst_hasLastDockedLocation()
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow(QSize(501, 500), MainWindowOption_None);
|
||||
auto dock1 = createDockWidget("1");
|
||||
m->multiSplitter()->checkSanity();
|
||||
m->multiSplitter()->setObjectName("mainWindow-dropArea");
|
||||
dock1->floatingWindow()->multiSplitter()->setObjectName("first-dropArea1");
|
||||
dock1->floatingWindow()->multiSplitter()->checkSanity();
|
||||
auto window1 = dock1->window();
|
||||
QVERIFY(dock1->isFloating());
|
||||
QVERIFY(!dock1->hasPreviousDockedLocation());
|
||||
@@ -139,12 +189,20 @@ void TestCommon::tst_hasLastDockedLocation()
|
||||
QVERIFY(!dock1->hasPreviousDockedLocation());
|
||||
|
||||
m->addDockWidget(dock1, Location_OnBottom);
|
||||
m->multiSplitter()->checkSanity();
|
||||
|
||||
QVERIFY(!dock1->isFloating());
|
||||
QVERIFY(dock1->setFloating(true));
|
||||
|
||||
auto ms1 = dock1->floatingWindow()->multiSplitter();
|
||||
ms1->setObjectName("dropArea1");
|
||||
ms1->checkSanity();
|
||||
QVERIFY(dock1->hasPreviousDockedLocation());
|
||||
auto window11 = dock1->window();
|
||||
QVERIFY(dock1->setFloating(false));
|
||||
|
||||
delete window1;
|
||||
delete window11;
|
||||
}
|
||||
|
||||
void TestCommon::tst_ghostSeparator()
|
||||
@@ -221,6 +279,252 @@ void TestCommon::tst_detachPos()
|
||||
delete dock1->window();
|
||||
}
|
||||
|
||||
void TestCommon::tst_floatingWindowSize()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow(QSize(501, 500), MainWindowOption_None);
|
||||
auto dock1 = createDockWidget("1");
|
||||
auto fw1 = dock1->window();
|
||||
|
||||
|
||||
QTest::qWait(2000);
|
||||
|
||||
QVERIFY(!fw1->geometry().isNull());
|
||||
QCOMPARE(fw1->size(), fw1->windowHandle()->size());
|
||||
|
||||
delete fw1;
|
||||
}
|
||||
|
||||
void TestCommon::tst_tabbingWithAffinities()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
// Tests that dock widgets with different affinities should not tab together
|
||||
|
||||
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None);
|
||||
m1->setAffinities({ "af1", "af2" });
|
||||
|
||||
auto dw1 = new DockWidgetType("1");
|
||||
dw1->setAffinities({ "af1" });
|
||||
dw1->show();
|
||||
|
||||
auto dw2 = new DockWidgetType("2");
|
||||
dw2->setAffinities({ "af2" });
|
||||
dw2->show();
|
||||
|
||||
FloatingWindow *fw1 = dw1->floatingWindow();
|
||||
FloatingWindow *fw2 = dw2->floatingWindow();
|
||||
|
||||
{
|
||||
SetExpectedWarning ignoreWarning("Refusing to dock widget with incompatible affinity");
|
||||
dw1->addDockWidgetAsTab(dw2);
|
||||
QVERIFY(dw1->window() != dw2->window());
|
||||
}
|
||||
|
||||
m1->addDockWidget(dw1, Location_OnBottom);
|
||||
QVERIFY(!dw1->isFloating());
|
||||
|
||||
{
|
||||
SetExpectedWarning ignoreWarning("Refusing to dock widget with incompatible affinity");
|
||||
auto dropArea = m1->dropArea();
|
||||
QVERIFY(!dropArea->drop(fw2, dw1->frame(), DropIndicatorOverlayInterface::DropLocation_Center));
|
||||
QVERIFY(dw1->window() != dw2->window());
|
||||
}
|
||||
|
||||
delete fw1;
|
||||
delete fw2;
|
||||
}
|
||||
|
||||
void TestCommon::tst_sizeAfterRedock()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto dw1 = new DockWidgetType(QStringLiteral("1"));
|
||||
auto dw2 = new DockWidgetType(QStringLiteral("2"));
|
||||
dw2->setWidget(new MyWidget("2", Qt::red));
|
||||
|
||||
dw1->addDockWidgetToContainingWindow(dw2, Location_OnBottom);
|
||||
const int height2 = dw2->frame()->height();
|
||||
|
||||
dw2->setFloating(true);
|
||||
QCOMPARE(height2, dw2->window()->height());
|
||||
auto oldFw2 = dw2->floatingWindow();
|
||||
|
||||
// Redock
|
||||
FloatingWindow *fw1 = dw1->floatingWindow();
|
||||
DropArea *dropArea = fw1->dropArea();
|
||||
|
||||
MultiSplitter *ms1 = fw1->multiSplitter();
|
||||
{
|
||||
WindowBeingDragged wbd2(oldFw2);
|
||||
const QRect suggestedDropRect = ms1->rectForDrop(&wbd2, Location_OnBottom, nullptr);
|
||||
QCOMPARE(suggestedDropRect.height(), height2);
|
||||
}
|
||||
|
||||
dropArea->drop(dw2->floatingWindow(), Location_OnBottom, nullptr);
|
||||
|
||||
QCOMPARE(dw2->frame()->height(), height2);
|
||||
|
||||
delete dw1->window();
|
||||
delete oldFw2;
|
||||
}
|
||||
|
||||
void TestCommon::tst_honourUserGeometry()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None);
|
||||
auto dw1 = new DockWidgetType(QStringLiteral("1"));
|
||||
|
||||
const QPoint pt(10, 10);
|
||||
dw1->move(pt);
|
||||
dw1->show();
|
||||
FloatingWindow *fw1 = dw1->floatingWindow();
|
||||
QCOMPARE(fw1->windowHandle()->geometry().topLeft(), pt);
|
||||
|
||||
delete dw1->window();
|
||||
}
|
||||
|
||||
void TestCommon::tst_floatingWindowTitleBug()
|
||||
{
|
||||
// Test for #74
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto dw1 = new DockWidgetType(QStringLiteral("1"));
|
||||
auto dw2 = new DockWidgetType(QStringLiteral("2"));
|
||||
auto dw3 = new DockWidgetType(QStringLiteral("3"));
|
||||
|
||||
dw1->setObjectName(QStringLiteral("1"));
|
||||
dw2->setObjectName(QStringLiteral("2"));
|
||||
dw3->setObjectName(QStringLiteral("3"));
|
||||
|
||||
dw1->show();
|
||||
dw1->addDockWidgetAsTab(dw2);
|
||||
dw1->addDockWidgetToContainingWindow(dw3, Location_OnBottom);
|
||||
|
||||
dw1->titleBar()->onFloatClicked();
|
||||
|
||||
QCOMPARE(dw3->titleBar()->title(), QLatin1String("3"));
|
||||
|
||||
delete dw1->window();
|
||||
delete dw3->window();
|
||||
}
|
||||
|
||||
void TestCommon::tst_resizeWindow_data()
|
||||
{
|
||||
QTest::addColumn<bool>("doASaveRestore");
|
||||
QTest::newRow("false") << false;
|
||||
QTest::newRow("true") << true;
|
||||
}
|
||||
|
||||
void TestCommon::tst_resizeWindow()
|
||||
{
|
||||
QFETCH(bool, doASaveRestore);
|
||||
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow(QSize(501, 500), MainWindowOption_None);
|
||||
auto dock1 = createDockWidget("1", new MyWidget("1", Qt::red));
|
||||
auto dock2 = createDockWidget("2", new MyWidget("2", Qt::blue));
|
||||
QPointer<FloatingWindow> fw1 = dock1->floatingWindow();
|
||||
QPointer<FloatingWindow> fw2 = dock2->floatingWindow();
|
||||
m->addDockWidget(dock1, Location_OnLeft);
|
||||
m->addDockWidget(dock2, Location_OnRight);
|
||||
|
||||
auto layout = m->multiSplitter();
|
||||
|
||||
layout->checkSanity();
|
||||
|
||||
const int oldWidth1 = dock1->width();
|
||||
const int oldWidth2 = dock2->width();
|
||||
|
||||
QVERIFY(oldWidth2 - oldWidth1 <= 1); // They're not equal if separator thickness if even
|
||||
|
||||
if (doASaveRestore) {
|
||||
LayoutSaver saver;
|
||||
saver.restoreLayout(saver.serializeLayout());
|
||||
}
|
||||
|
||||
m->showMaximized();
|
||||
Testing::waitForResize(m.get());
|
||||
|
||||
const int maximizedWidth1 = dock1->width();
|
||||
const int maximizedWidth2 = dock2->width();
|
||||
|
||||
const double relativeDifference = qAbs((maximizedWidth1 - maximizedWidth2) / (1.0 * layout->width()));
|
||||
|
||||
qDebug() << oldWidth1 << oldWidth2 << maximizedWidth1 << maximizedWidth2 << relativeDifference;
|
||||
QVERIFY(relativeDifference <= 0.01);
|
||||
|
||||
m->showNormal();
|
||||
Testing::waitForResize(m.get());
|
||||
|
||||
const int newWidth1 = dock1->width();
|
||||
const int newWidth2 = dock2->width();
|
||||
|
||||
QCOMPARE(oldWidth1, newWidth1);
|
||||
QCOMPARE(oldWidth2, newWidth2);
|
||||
layout->checkSanity();
|
||||
|
||||
delete fw1;
|
||||
delete fw2;
|
||||
}
|
||||
|
||||
void TestCommon::tst_restoreEmpty()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
|
||||
// Create an empty main window, save it to disk.
|
||||
auto m = createMainWindow(QSize(800, 500), MainWindowOption_None);
|
||||
auto layout = m->multiSplitter();
|
||||
LayoutSaver saver;
|
||||
const QSize oldSize = m->size();
|
||||
QVERIFY(saver.saveToFile(QStringLiteral("layout_tst_restoreEmpty.json")));
|
||||
saver.restoreFromFile(QStringLiteral("layout_tst_restoreEmpty.json"));
|
||||
QVERIFY(m->multiSplitter()->checkSanity());
|
||||
QCOMPARE(layout->separators().size(), 0);
|
||||
QCOMPARE(layout->count(), 0);
|
||||
QCOMPARE(m->size(), oldSize);
|
||||
QVERIFY(layout->checkSanity());
|
||||
}
|
||||
|
||||
void TestCommon::tst_restoreCentralFrame()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow(QSize(800, 500));
|
||||
auto layout = m->multiSplitter();
|
||||
|
||||
QCOMPARE(layout->count(), 1);
|
||||
Item *item = m->dropArea()->centralFrame();
|
||||
QVERIFY(item);
|
||||
auto frame = static_cast<Frame *>(item->guestAsQObject());
|
||||
QCOMPARE(frame->options(), FrameOption_IsCentralFrame | FrameOption_AlwaysShowsTabs);
|
||||
QVERIFY(!frame->titleBar()->isVisible());
|
||||
|
||||
LayoutSaver saver;
|
||||
QVERIFY(saver.saveToFile(QStringLiteral("layout_tst_restoreCentralFrame.json")));
|
||||
QVERIFY(saver.restoreFromFile(QStringLiteral("layout_tst_restoreCentralFrame.json")));
|
||||
|
||||
QCOMPARE(layout->count(), 1);
|
||||
item = m->dropArea()->centralFrame();
|
||||
QVERIFY(item);
|
||||
frame = static_cast<Frame *>(item->guestAsQObject());
|
||||
QCOMPARE(frame->options(), FrameOption_IsCentralFrame | FrameOption_AlwaysShowsTabs);
|
||||
QVERIFY(!frame->titleBar()->isVisible());
|
||||
}
|
||||
|
||||
void TestCommon::tst_setFloatingSimple()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow();
|
||||
auto dock1 = createDockWidget("dock1", new MyWidget("one"));
|
||||
m->addDockWidget(dock1, Location_OnTop);
|
||||
auto l = m->multiSplitter();
|
||||
dock1->setFloating(true);
|
||||
QVERIFY(l->checkSanity());
|
||||
dock1->setFloating(false);
|
||||
QVERIFY(l->checkSanity());
|
||||
dock1->setFloating(true);
|
||||
QVERIFY(l->checkSanity());
|
||||
dock1->setFloating(false);
|
||||
QVERIFY(l->checkSanity());
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (!qpaPassedAsArgument(argc, argv)) {
|
||||
@@ -234,5 +538,562 @@ int main(int argc, char *argv[])
|
||||
return QTest::qExec(&test, argc, argv);
|
||||
}
|
||||
|
||||
void TestCommon::tst_doubleClose()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
{
|
||||
// Via close()
|
||||
auto dock1 = createDockWidget("hello", Qt::green);
|
||||
dock1->close();
|
||||
dock1->close();
|
||||
|
||||
delete dock1->window();
|
||||
}
|
||||
{
|
||||
// Via the button
|
||||
auto dock1 = createDockWidget("hello", Qt::green);
|
||||
auto fw1 = dock1->floatingWindow();
|
||||
|
||||
auto t = dock1->frame()->titleBar();
|
||||
t->onCloseClicked();
|
||||
t->onCloseClicked();
|
||||
|
||||
delete dock1;
|
||||
delete fw1;
|
||||
}
|
||||
}
|
||||
|
||||
void TestCommon::tst_dockInternal()
|
||||
{
|
||||
/**
|
||||
* Here we dock relative to an existing widget, and not to the drop-area.
|
||||
*/
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow();
|
||||
auto dock1 = createDockWidget("dock1", new QPushButton("one"));
|
||||
auto dropArea = m->dropArea();
|
||||
|
||||
auto centralWidget = static_cast<Frame*>(dropArea->items()[0]->guestAsQObject());
|
||||
nestDockWidget(dock1, dropArea, centralWidget, KDDockWidgets::Location_OnRight);
|
||||
|
||||
QVERIFY(dock1->width() < dropArea->width() - centralWidget->width());
|
||||
}
|
||||
|
||||
void TestCommon::tst_maximizeAndRestore()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow();
|
||||
auto dock1 = createDockWidget("dock1", new QPushButton("one"));
|
||||
auto dock2 = createDockWidget("dock2", new QPushButton("two"));
|
||||
|
||||
m->addDockWidget(dock1, KDDockWidgets::Location_OnLeft);
|
||||
m->addDockWidget(dock2, KDDockWidgets::Location_OnRight);
|
||||
|
||||
auto dropArea = m->dropArea();
|
||||
QVERIFY(dropArea->checkSanity());
|
||||
|
||||
m->showMaximized();
|
||||
Testing::waitForResize(m.get());
|
||||
|
||||
QVERIFY(dropArea->checkSanity());
|
||||
qDebug() << "About to show normal";
|
||||
m->showNormal();
|
||||
Testing::waitForResize(m.get());
|
||||
|
||||
QVERIFY(dropArea->checkSanity());
|
||||
}
|
||||
|
||||
void TestCommon::tst_propagateResize2()
|
||||
{
|
||||
// |5|1|2|
|
||||
// | |3|4|
|
||||
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow();
|
||||
auto dock1 = createDockWidget("dock1", new QPushButton("one"));
|
||||
auto dock2 = createDockWidget("dock2", new QPushButton("two"));
|
||||
m->addDockWidget(dock1, KDDockWidgets::Location_OnTop);
|
||||
m->addDockWidget(dock2, KDDockWidgets::Location_OnRight, dock1);
|
||||
|
||||
auto dock3 = createDockWidget("dock3", new QPushButton("three"));
|
||||
auto dock4 = createDockWidget("dock4", new QPushButton("four"));
|
||||
|
||||
m->addDockWidget(dock3, KDDockWidgets::Location_OnBottom);
|
||||
m->addDockWidget(dock4, KDDockWidgets::Location_OnRight, dock3);
|
||||
|
||||
auto dock5 = createDockWidget("dock5", new QPushButton("five"));
|
||||
m->addDockWidget(dock5, KDDockWidgets::Location_OnLeft);
|
||||
|
||||
auto dropArea = m->dropArea();
|
||||
dropArea->checkSanity();
|
||||
}
|
||||
|
||||
void TestCommon::tst_shutdown()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto dock = createDockWidget("doc1", Qt::green);
|
||||
|
||||
auto m = createMainWindow();
|
||||
m->show();
|
||||
QVERIFY(QTest::qWaitForWindowActive(m->windowHandle()));
|
||||
delete dock->window();
|
||||
}
|
||||
|
||||
void TestCommon::tst_28NestedWidgets_data()
|
||||
{
|
||||
QTest::addColumn<QVector<DockDescriptor>>("docksToCreate");
|
||||
QTest::addColumn<QVector<int>>("docksToHide");
|
||||
|
||||
QVector<DockDescriptor> docks = {
|
||||
{Location_OnLeft, -1, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnTop, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnLeft, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None }
|
||||
};
|
||||
|
||||
QTest::newRow("28") << docks << QVector<int>{11, 0};
|
||||
|
||||
docks = {
|
||||
{Location_OnLeft, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnTop, -1, nullptr, AddingOption_None },
|
||||
{Location_OnLeft, -1, nullptr, AddingOption_None },
|
||||
|
||||
};
|
||||
|
||||
QVector<int> docksToHide;
|
||||
for (int i = 0; i < docks.size(); ++i) {
|
||||
docksToHide << i;
|
||||
}
|
||||
|
||||
QTest::newRow("anchor_intersection") << docks << docksToHide;
|
||||
|
||||
docks = {
|
||||
{Location_OnLeft, -1, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_None },
|
||||
{Location_OnTop, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
};
|
||||
|
||||
// 2. Produced valgrind invalid reads while adding
|
||||
QTest::newRow("valgrind") << docks << QVector<int>{};
|
||||
|
||||
docks = {
|
||||
{Location_OnLeft, -1, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_None },
|
||||
{Location_OnTop, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
};
|
||||
QTest::newRow("bug_when_closing") << docks << QVector<int>{}; // Q_ASSERT(!isSquashed())
|
||||
|
||||
docks = {
|
||||
{Location_OnLeft, -1, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_None },
|
||||
};
|
||||
|
||||
QTest::newRow("bug_when_closing2") << docks << QVector<int>{}; // Tests for void KDDockWidgets::Anchor::setPosition(int, KDDockWidgets::Anchor::SetPositionOptions) Negative position -69
|
||||
|
||||
docks = {
|
||||
{Location_OnLeft, -1, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, 0, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnTop, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnLeft, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None }
|
||||
};
|
||||
|
||||
docksToHide.clear();
|
||||
for (int i = 0; i < 28; ++i) {
|
||||
if (i != 16 && i != 17 && i != 18 && i != 27)
|
||||
docksToHide << i;
|
||||
}
|
||||
|
||||
QTest::newRow("bug_with_holes") << docks << docksToHide;
|
||||
|
||||
docks = {
|
||||
{Location_OnLeft, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnTop, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnLeft, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnLeft, 17, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None } };
|
||||
|
||||
docksToHide.clear();
|
||||
QTest::newRow("add_as_placeholder") << docks << docksToHide;
|
||||
|
||||
docks = {
|
||||
{Location_OnLeft, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_StartHidden } };
|
||||
|
||||
QTest::newRow("add_as_placeholder_simple") << docks << docksToHide;
|
||||
|
||||
|
||||
docks = {
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_StartHidden } };
|
||||
|
||||
docksToHide.clear();
|
||||
QTest::newRow("isSquashed_assert") << docks << docksToHide;
|
||||
|
||||
docks = {
|
||||
{Location_OnLeft, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnTop, -1, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_StartHidden } };
|
||||
|
||||
docksToHide.clear();
|
||||
QTest::newRow("negative_pos_warning") << docks << docksToHide;
|
||||
|
||||
docks = {
|
||||
{Location_OnTop, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None } };
|
||||
|
||||
docksToHide.clear();
|
||||
QTest::newRow("bug") << docks << docksToHide;
|
||||
|
||||
docks = {
|
||||
{Location_OnTop, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None } };
|
||||
|
||||
docksToHide.clear();
|
||||
QTest::newRow("bug2") << docks << docksToHide;
|
||||
|
||||
docks = {
|
||||
{Location_OnLeft, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnTop, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnLeft, -1, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None } };
|
||||
|
||||
docksToHide.clear();
|
||||
QTest::newRow("bug3") << docks << docksToHide;
|
||||
}
|
||||
|
||||
void TestCommon::tst_28NestedWidgets()
|
||||
{
|
||||
QFETCH(QVector<DockDescriptor>, docksToCreate);
|
||||
QFETCH(QVector<int>, docksToHide);
|
||||
|
||||
// Tests a case that used to cause negative anchor position when turning into placeholder
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow(QSize(800, 500), MainWindowOption_None);
|
||||
auto dropArea = m->dropArea();
|
||||
MultiSplitter *layout = dropArea;
|
||||
|
||||
int i = 0;
|
||||
for (DockDescriptor &desc : docksToCreate) {
|
||||
desc.createdDock = createDockWidget(QString("%1").arg(i), new QPushButton(QString("%1").arg(i).toLatin1()), {}, false);
|
||||
|
||||
DockWidgetBase *relativeTo = nullptr;
|
||||
if (desc.relativeToIndex != -1)
|
||||
relativeTo = docksToCreate.at(desc.relativeToIndex).createdDock;
|
||||
m->addDockWidget(desc.createdDock, desc.loc, relativeTo, desc.option);
|
||||
QVERIFY(layout->checkSanity());
|
||||
++i;
|
||||
}
|
||||
|
||||
layout->checkSanity();
|
||||
|
||||
// Run the saver in these complex scenarios:
|
||||
LayoutSaver saver;
|
||||
const QByteArray saved = saver.serializeLayout();
|
||||
QVERIFY(!saved.isEmpty());
|
||||
QVERIFY(saver.restoreLayout(saved));
|
||||
|
||||
layout->checkSanity();
|
||||
|
||||
for (int i : docksToHide) {
|
||||
docksToCreate.at(i).createdDock->close();
|
||||
layout->checkSanity();
|
||||
QTest::qWait(200);
|
||||
}
|
||||
|
||||
layout->checkSanity();
|
||||
|
||||
for (int i : docksToHide) {
|
||||
docksToCreate.at(i).createdDock->deleteLater();
|
||||
QVERIFY(Testing::waitForDeleted(docksToCreate.at(i).createdDock));
|
||||
}
|
||||
|
||||
layout->checkSanity();
|
||||
|
||||
// And hide the remaining ones
|
||||
i = 0;
|
||||
for (auto dock : docksToCreate) {
|
||||
if (dock.createdDock && dock.createdDock->isVisible()) {
|
||||
dock.createdDock->close();
|
||||
QTest::qWait(200); // Wait for the docks to be closed. TODO Replace with a global event filter and wait for any resize ?
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
layout->checkSanity();
|
||||
|
||||
// Cleanup
|
||||
for (auto dock : DockRegistry::self()->dockwidgets()) {
|
||||
dock->deleteLater();
|
||||
QVERIFY(Testing::waitForDeleted(dock));
|
||||
}
|
||||
}
|
||||
|
||||
void TestCommon::tst_closeReparentsToNull()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto dock1 = createDockWidget("1", new QPushButton("1"));
|
||||
auto fw1 = dock1->window();
|
||||
QVERIFY(dock1->parent() != nullptr);
|
||||
dock1->close();
|
||||
QVERIFY(dock1->parent() == nullptr);
|
||||
delete fw1;
|
||||
delete dock1;
|
||||
}
|
||||
|
||||
void TestCommon::tst_startHidden()
|
||||
{
|
||||
// A really simple test for AddingOption_StartHidden
|
||||
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow(QSize(800, 500), MainWindowOption_None);
|
||||
auto dock1 = createDockWidget("1", new QPushButton("1"), {}, /*show=*/false);
|
||||
m->addDockWidget(dock1, Location_OnRight, nullptr, AddingOption_StartHidden);
|
||||
delete dock1;
|
||||
}
|
||||
|
||||
void TestCommon::tst_negativeAnchorPosition2()
|
||||
{
|
||||
// Tests that the "Out of bounds position" warning doesn't appear. Test will abort if yes.
|
||||
EnsureTopLevelsDeleted e;
|
||||
auto m = createMainWindow(QSize(800, 500), MainWindowOption_None);
|
||||
auto dropArea = m->dropArea();
|
||||
MultiSplitter *layout = dropArea;
|
||||
|
||||
auto dock1 = createDockWidget("1", new QPushButton("1"), {}, /*show=*/false);
|
||||
auto dock2 = createDockWidget("2", new QPushButton("2"), {}, /*show=*/false);
|
||||
auto dock3 = createDockWidget("3", new QPushButton("3"), {}, /*show=*/false);
|
||||
|
||||
m->addDockWidget(dock1, Location_OnLeft);
|
||||
m->addDockWidget(dock2, Location_OnRight, nullptr, AddingOption_StartHidden);
|
||||
m->addDockWidget(dock3, Location_OnRight);
|
||||
QCOMPARE(layout->placeholderCount(), 1);
|
||||
QCOMPARE(layout->count(), 3);
|
||||
|
||||
dock1->setFloating(true);
|
||||
dock1->setFloating(false);
|
||||
dock2->deleteLater();
|
||||
layout->checkSanity();
|
||||
QVERIFY(Testing::waitForDeleted(dock2));
|
||||
}
|
||||
|
||||
void TestCommon::tst_negativeAnchorPosition3()
|
||||
{
|
||||
// 1. Another case, when floating a dock:
|
||||
EnsureTopLevelsDeleted e;
|
||||
QVector<DockDescriptor> docks = { {Location_OnLeft, -1, nullptr, AddingOption_None },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{Location_OnLeft, -1, nullptr, AddingOption_None },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnRight, -1, nullptr, AddingOption_None } };
|
||||
auto m = createMainWindow(docks);
|
||||
auto dropArea = m->dropArea();
|
||||
MultiSplitter *layout = dropArea;
|
||||
layout->checkSanity();
|
||||
|
||||
auto dock1 = docks.at(1).createdDock;
|
||||
auto dock3 = docks.at(3).createdDock;
|
||||
|
||||
dock1->setFloating(true);
|
||||
delete dock1->window();
|
||||
delete dock3->window();
|
||||
|
||||
layout->checkSanity();
|
||||
}
|
||||
|
||||
void TestCommon::tst_negativeAnchorPosition4()
|
||||
{
|
||||
// 1. Tests that we don't get a warning
|
||||
// Out of bounds position= -5 ; oldPosition= 0 KDDockWidgets::Anchor(0x55e726be9090, name = "left") KDDockWidgets::MainWindow(0x55e726beb8d0)
|
||||
EnsureTopLevelsDeleted e;
|
||||
QVector<DockDescriptor> docks = { { Location_OnLeft, -1, nullptr, AddingOption_StartHidden },
|
||||
{ Location_OnTop, -1, nullptr, AddingOption_None },
|
||||
{ Location_OnRight, -1, nullptr, AddingOption_None },
|
||||
{ Location_OnLeft, -1, nullptr, AddingOption_None },
|
||||
{ Location_OnRight, -1, nullptr, AddingOption_None } };
|
||||
|
||||
auto m = createMainWindow(docks);
|
||||
auto dropArea = m->dropArea();
|
||||
MultiSplitter *layout = dropArea;
|
||||
layout->checkSanity();
|
||||
|
||||
auto dock1 = docks.at(1).createdDock;
|
||||
auto dock2 = docks.at(2).createdDock;
|
||||
dock2->setFloating(true);
|
||||
auto fw2 = dock2->floatingWindow();
|
||||
dropArea->addWidget(fw2->dropArea(), Location_OnLeft, dock1->frame());
|
||||
dock2->setFloating(true);
|
||||
fw2 = dock2->floatingWindow();
|
||||
|
||||
dropArea->addWidget(fw2->dropArea(), Location_OnRight, dock1->frame());
|
||||
|
||||
layout->checkSanity();
|
||||
docks.at(0).createdDock->deleteLater();
|
||||
docks.at(4).createdDock->deleteLater();
|
||||
Testing::waitForDeleted(docks.at(4).createdDock);
|
||||
}
|
||||
|
||||
void TestCommon::tst_negativeAnchorPosition5()
|
||||
{
|
||||
EnsureTopLevelsDeleted e;
|
||||
QVector<DockDescriptor> docks = {
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_StartHidden },
|
||||
{Location_OnBottom, -1, nullptr, AddingOption_StartHidden },
|
||||
};
|
||||
|
||||
auto m = createMainWindow(docks);
|
||||
auto dropArea = m->dropArea();
|
||||
MultiSplitter *layout = dropArea;
|
||||
layout->checkSanity();
|
||||
|
||||
auto dock0 = docks.at(0).createdDock;
|
||||
auto dock1 = docks.at(1).createdDock;
|
||||
|
||||
dock1->show();
|
||||
|
||||
dock0->show();
|
||||
layout->checkSanity();
|
||||
|
||||
// Cleanup
|
||||
for (auto dock : DockRegistry::self()->dockwidgets())
|
||||
dock->deleteLater();
|
||||
|
||||
QVERIFY(Testing::waitForDeleted(dock0));
|
||||
}
|
||||
|
||||
void TestCommon::tst_invalidAnchorGroup()
|
||||
{
|
||||
// Tests a bug I got. Should not warn.
|
||||
EnsureTopLevelsDeleted e;
|
||||
|
||||
{
|
||||
auto dock1 = createDockWidget("dock1", new QPushButton("one"));
|
||||
auto dock2 = createDockWidget("dock2", new QPushButton("two"));
|
||||
|
||||
QPointer<FloatingWindow> fw = dock2->morphIntoFloatingWindow();
|
||||
nestDockWidget(dock1, fw->dropArea(), nullptr, KDDockWidgets::Location_OnTop);
|
||||
|
||||
dock1->close();
|
||||
Testing::waitForResize(dock2);
|
||||
auto layout = fw->dropArea();
|
||||
layout->checkSanity();
|
||||
|
||||
dock2->close();
|
||||
dock1->deleteLater();
|
||||
dock2->deleteLater();
|
||||
Testing::waitForDeleted(dock1);
|
||||
}
|
||||
|
||||
{
|
||||
// Stack 1, 2, 3, close 2, close 1
|
||||
|
||||
auto m = createMainWindow(QSize(800, 500), MainWindowOption_None);
|
||||
auto dock1 = createDockWidget("dock1", new QPushButton("one"));
|
||||
auto dock2 = createDockWidget("dock2", new QPushButton("two"));
|
||||
auto dock3 = createDockWidget("dock3", new QPushButton("three"));
|
||||
|
||||
m->addDockWidget(dock3, Location_OnTop);
|
||||
m->addDockWidget(dock2, Location_OnTop);
|
||||
m->addDockWidget(dock1, Location_OnTop);
|
||||
|
||||
dock2->close();
|
||||
dock1->close();
|
||||
|
||||
dock1->deleteLater();
|
||||
dock2->deleteLater();
|
||||
Testing::waitForDeleted(dock1);
|
||||
}
|
||||
}
|
||||
|
||||
#include "tst_common.moc"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,7 @@
|
||||
#include "Config.h"
|
||||
#include "TitleBar_p.h"
|
||||
#include "FloatingWindow_p.h"
|
||||
#include "FrameworkWidgetFactory.h"
|
||||
|
||||
#include <QCloseEvent>
|
||||
#include <QDebug>
|
||||
@@ -114,7 +115,16 @@ std::unique_ptr<MainWindowBase> KDDockWidgets::Tests::createMainWindow(QVector<D
|
||||
{
|
||||
static int count = 0;
|
||||
count++;
|
||||
auto m = std::unique_ptr<MainWindowType>(new MainWindowType(QStringLiteral("MyMainWindow%1").arg(count), MainWindowOption_None));
|
||||
|
||||
WidgetType *parent = nullptr;
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
auto view = new QQuickView(Config::self().qmlEngine(), nullptr);
|
||||
view->setSource(QUrl("qrc:/main.qml"));
|
||||
view->show();
|
||||
parent = view->rootObject();
|
||||
#endif
|
||||
|
||||
auto m = std::unique_ptr<MainWindowType>(new MainWindowType(QStringLiteral("MyMainWindow%1").arg(count), MainWindowOption_None, parent));
|
||||
auto layout = m->multiSplitter();
|
||||
m->show();
|
||||
m->resize(QSize(700, 700));
|
||||
@@ -226,3 +236,13 @@ void KDDockWidgets::Tests::moveMouseTo(QPoint globalDest, QWidget *receiver)
|
||||
QTest::qWait(2);
|
||||
}
|
||||
}
|
||||
|
||||
void KDDockWidgets::Tests::nestDockWidget(DockWidgetBase *dock, DropArea *dropArea, Frame *relativeTo, Location location)
|
||||
{
|
||||
auto frame = Config::self().frameworkWidgetFactory()->createFrame();
|
||||
frame->addWidget(dock);
|
||||
dock->frame()->setObjectName(dock->objectName());
|
||||
|
||||
dropArea->addWidget(frame, location, relativeTo);
|
||||
QVERIFY(dropArea->checkSanity());
|
||||
}
|
||||
|
||||
@@ -101,6 +101,9 @@ KDDockWidgets::DockWidgetBase *createDockWidget(const QString &name, QWidgetOrQu
|
||||
const QString &affinityName = {});
|
||||
KDDockWidgets::DockWidgetBase *createDockWidget(const QString &name, QColor color = Qt::black);
|
||||
|
||||
void nestDockWidget(DockWidgetBase *dock, DropArea *dropArea, Frame *relativeTo,
|
||||
KDDockWidgets::Location location);
|
||||
|
||||
class NonClosableWidget : public QWidget
|
||||
{
|
||||
public:
|
||||
@@ -116,7 +119,7 @@ protected:
|
||||
class MyWidget : public QWidgetOrQuick
|
||||
{
|
||||
public:
|
||||
explicit MyWidget(const QString &, QColor c);
|
||||
explicit MyWidget(const QString &, QColor c = Qt::black);
|
||||
~MyWidget() override;
|
||||
|
||||
|
||||
@@ -134,6 +137,24 @@ private:
|
||||
};
|
||||
|
||||
|
||||
#ifdef KDDOCKWIDGETS_QTQUICK
|
||||
// Don't want to adapt dozens of locations so it compiles for QtQuick, so just typedef.
|
||||
// the fact it's a button isn't important for the tests anyway
|
||||
|
||||
class QPushButton : public MyWidget
|
||||
{
|
||||
public:
|
||||
// use const char* to silence QtCreator static analizer warnings when using const char * in tst_docks.cpp
|
||||
// We don't have QT_NO_CAST_FROM_ASCII and still it complains, so use an indirection so I can read tst_docks while
|
||||
// porting to QtQuick without noise. Once the port is done feel free to change to QString.
|
||||
explicit QPushButton(const char *name)
|
||||
: MyWidget(QString::fromLatin1(name))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
void doubleClickOn(QPoint globalPos, QWidget *receiver);
|
||||
void pressOn(QPoint globalPos, QWidget *receiver);
|
||||
void releaseOn(QPoint globalPos, QWidget *receiver);
|
||||
|
||||
Reference in New Issue
Block a user