3070 lines
108 KiB
C++
3070 lines
108 KiB
C++
/*
|
|
This file is part of KDDockWidgets.
|
|
|
|
SPDX-FileCopyrightText: 2019 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
|
Author: Sérgio Martins <sergio.martins@kdab.com>
|
|
|
|
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
|
|
|
|
Contact KDAB at <info@kdab.com> for commercial licensing options.
|
|
*/
|
|
|
|
/// @file
|
|
/// @brief Here lives the tests that only apply to QtWidgets
|
|
/// either because they haven't been ported to QtQuick yet or because they are really
|
|
/// QtWidgets specific.
|
|
|
|
#define NOMINMAX
|
|
|
|
#include "kddockwidgets/KDDockWidgets.h"
|
|
#include "../utils.h"
|
|
#include "Config.h"
|
|
#include "LayoutSaver.h"
|
|
#include "core/Logging_p.h"
|
|
#include "core/DragController_p.h"
|
|
#include "core/layouting/Item_p.h"
|
|
#include "core/layouting/LayoutingSeparator_p.h"
|
|
#include "core/WindowBeingDragged_p.h"
|
|
|
|
#include "qtwidgets/ViewFactory.h"
|
|
#include "core/LayoutSaver_p.h"
|
|
#include "core/Platform.h"
|
|
#include "core/Action_p.h"
|
|
#include "core/DropArea.h"
|
|
#include "core/Separator.h"
|
|
#include "core/Group.h"
|
|
#include "core/DockWidget.h"
|
|
#include "core/MainWindow.h"
|
|
#include "core/SideBar.h"
|
|
|
|
#include "qtwidgets/views/MDIArea.h"
|
|
#include "qtwidgets/views/Stack.h"
|
|
#include "qtwidgets/views/MainWindow.h"
|
|
#include "qtwidgets/views/ViewWrapper_p.h"
|
|
#include "qtwidgets/views/DockWidget.h"
|
|
#include "qtwidgets/views/TitleBar.h"
|
|
#include "qtcommon/View.h"
|
|
|
|
#include "ui_mainwindow.h"
|
|
|
|
#ifdef KDDW_HAS_SPDLOG
|
|
#include "../fatal_logger.h"
|
|
#endif
|
|
|
|
#include "../src/qtwidgets/DebugWidgetViewer_p.h"
|
|
|
|
#include <QObject>
|
|
#include <QPushButton>
|
|
#include <QMenuBar>
|
|
#include <QTabBar>
|
|
#include <QTabWidget>
|
|
#include <QVBoxLayout>
|
|
#include <QGraphicsView>
|
|
#include <QGraphicsScene>
|
|
#include <QLineEdit>
|
|
#include <QGraphicsProxyWidget>
|
|
#include <QtTest/QTest>
|
|
|
|
using namespace KDDockWidgets;
|
|
using namespace KDDockWidgets::Core;
|
|
using namespace KDDockWidgets::Tests;
|
|
|
|
namespace {
|
|
|
|
// For testing overriding DockWidget::closeEvent()
|
|
// You can override the guest's closeEvent() instead. That's already tested elsewhere.
|
|
class NonClosableDockWidget : public QtWidgets::DockWidget
|
|
{
|
|
public:
|
|
using QtWidgets::DockWidget::DockWidget;
|
|
void closeEvent(QCloseEvent *ev) override
|
|
{
|
|
ev->ignore();
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
inline Core::DockWidget *createDockWidget(const QString &name, QWidget *w,
|
|
DockWidgetOptions options = {},
|
|
LayoutSaverOptions layoutSaverOptions = {},
|
|
bool show = true, const QString &affinityName = {})
|
|
{
|
|
w->setFocusPolicy(Qt::StrongFocus);
|
|
auto dock = newDockWidget(name, options, layoutSaverOptions);
|
|
dock->setAffinityName(affinityName);
|
|
dock->setGuestView(QtWidgets::ViewWrapper::create(w));
|
|
dock->setObjectName(name);
|
|
dock->view()->setGeometry(QRect(0, 0, 400, 400));
|
|
if (show) {
|
|
dock->open();
|
|
dock->dptr()->morphIntoFloatingWindow();
|
|
dock->view()->activateWindow();
|
|
Q_ASSERT(dock->window());
|
|
if (Platform::instance()->tests_waitForWindowActive(dock->view()->window(), 1000)) {
|
|
return dock;
|
|
}
|
|
KDDW_WARN("KDDockWidgets::Tests::createDockWidget: Couldn't activate window");
|
|
return nullptr;
|
|
} else {
|
|
return dock;
|
|
}
|
|
}
|
|
|
|
class EmbeddedWindow : public QWidget
|
|
{
|
|
public:
|
|
explicit EmbeddedWindow(Core::MainWindow *m)
|
|
: mainWindow(m)
|
|
{
|
|
}
|
|
|
|
~EmbeddedWindow() override;
|
|
|
|
Core::MainWindow *const mainWindow;
|
|
};
|
|
EmbeddedWindow::~EmbeddedWindow() = default;
|
|
|
|
|
|
inline EmbeddedWindow *createEmbeddedMainWindow(QSize sz)
|
|
{
|
|
// Tests a MainWindow which isn't a top-level window, but is embedded in another window
|
|
auto mainwindow = createMainWindow(QSize(600, 600), MainWindowOption_HasCentralGroup).release();
|
|
|
|
auto window = new EmbeddedWindow(mainwindow);
|
|
|
|
auto lay = new QVBoxLayout(window);
|
|
lay->setContentsMargins(100, 100, 100, 100);
|
|
lay->addWidget(dynamic_cast<QWidget *>(mainwindow->view()));
|
|
|
|
window->show();
|
|
window->resize(sz);
|
|
return window;
|
|
}
|
|
|
|
class TestQtWidgets : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
public Q_SLOTS:
|
|
void initTestCase();
|
|
void cleanupTestCase();
|
|
|
|
private Q_SLOTS:
|
|
// TODO: Port these to QtQuick
|
|
void tst_mainWindowAlwaysHasCentralWidget();
|
|
void tst_dockableMainWindows();
|
|
void tst_mdi_mixed_with_docking();
|
|
void tst_mdi_mixed_with_docking2();
|
|
void tst_mdi_mixed_with_docking_setMDISize();
|
|
void tst_deleteOnClose();
|
|
void tstCloseNestedMdi();
|
|
void tstCloseNestedMDIPropagates();
|
|
void tstQGraphicsProxyWidget();
|
|
|
|
// But these are fine to be widget only:
|
|
void tst_controllerToView();
|
|
void tst_designerMainWindow();
|
|
void tst_tabsNotClickable();
|
|
void tst_embeddedMainWindow();
|
|
void tst_restoreEmbeddedMainWindow();
|
|
void tst_negativeAnchorPositionWhenEmbedded();
|
|
void tst_negativeAnchorPositionWhenEmbedded_data();
|
|
void tst_closeRemovesFromSideBar();
|
|
void tst_sideBarHidden();
|
|
void tst_restoreSideBar();
|
|
void tst_restoreSideBar2();
|
|
void tst_toggleActionOnSideBar();
|
|
void tst_deleteOnCloseWhenOnSideBar();
|
|
void tst_openWhenOnSideBar();
|
|
void tst_isOpenSideBar();
|
|
void tst_sidebarOverlayShowsAutohide();
|
|
void tst_sidebarOverlayGetsHiddenOnClick();
|
|
void tst_sidebarGrouping();
|
|
void tst_sidebarCrash();
|
|
void tst_sidebarCrash2();
|
|
void tst_sidebarCloseReason();
|
|
void tst_sidebarSide();
|
|
void tst_floatRemovesFromSideBar();
|
|
void tst_overlayedGeometryIsSaved();
|
|
void tst_overlayCrash();
|
|
void tst_setAsCurrentTab();
|
|
void tst_crash326();
|
|
void tst_restoreWithIncompleteFactory();
|
|
void tst_deleteDockWidget();
|
|
void tst_standaloneTitleBar();
|
|
void tst_titleBarTitle();
|
|
void tst_widgetAddQAction();
|
|
void tst_currentTabChanged();
|
|
void tst_moveTab();
|
|
void tst_moveTab_data();
|
|
void tst_nestedMainWindowToggle();
|
|
void tst_nestedMainWindowFloatButton();
|
|
void tst_nestedMainWindowSaveRestore_data();
|
|
void tst_nestedMainWindowSaveRestore();
|
|
void tst_focusBetweenTabs();
|
|
void addDockWidgetToSide();
|
|
void addDockWidgetToSide2();
|
|
void addDockWidgetToSide3();
|
|
void addDockWidgetToSide4();
|
|
void addDockWidgetToSide5();
|
|
void addDockWidgetToSideCrash();
|
|
void userHiddenButton();
|
|
void tst_tabAsCentralWidget();
|
|
void tst_nonClosable();
|
|
void tst_crashDuringRestore();
|
|
void tst_toggleVsShowHidden();
|
|
void tst_indicatorsNotShowing();
|
|
void tst_neighbourSqueezeStrategy();
|
|
void tst_tabBarIcons();
|
|
void tst_debugWidgetViewer();
|
|
void tst_addDockWidgetToContainingWindowNested();
|
|
void tst_restoreInvalidPercentages();
|
|
|
|
// And fix these
|
|
void tst_floatingWindowDeleted();
|
|
void tst_addToSmallMainWindow6();
|
|
void tst_minSizeChanges();
|
|
void tst_maxSizePropagates();
|
|
void tst_maxSizePropagates2();
|
|
void tst_maxSizedFloatingWindow();
|
|
void tst_restoreWithRemapping();
|
|
void tst_restoreResizesLayout();
|
|
void tst_restoreNonRelativeFloatingWindowGeometry();
|
|
void tst_maxSizeHonouredWhenDropped();
|
|
void tst_fixedSizePolicy();
|
|
void tst_maxSizeHonouredWhenAnotherDropped();
|
|
void tst_addToHiddenMainWindow();
|
|
void tst_maximumSizePolicy();
|
|
void tst_complex();
|
|
void tst_restoreFloatingMaximizedState();
|
|
void tst_findAncestor();
|
|
};
|
|
|
|
void TestQtWidgets::tst_designerMainWindow()
|
|
{
|
|
// Tests that a KDDW main window doesn't crash if the user used setupUI() on it.
|
|
// setupUI() triggers a QMainWindow::setCentralWidget() call which overrides KDDW's own central widget
|
|
// solution is for KDDW users to call manualInit() later
|
|
|
|
EnsureTopLevelsDeleted e;
|
|
QtWidgets::MainWindow mw("mw1", MainWindowOptions(MainWindowOption_HasCentralWidget) | MainWindowOption_ManualInit);
|
|
auto dock1 = createDockWidget("dock1", new QWidget());
|
|
mw.show();
|
|
|
|
QVERIFY(!mw.centralWidget());
|
|
|
|
Ui_MainWindow ui; // autogenerated by mainwindow.ui
|
|
ui.setupUi(&mw);
|
|
|
|
QVERIFY(mw.centralWidget()->objectName() != "MyCentralWidget");
|
|
mw.manualInit();
|
|
QCOMPARE(mw.centralWidget()->objectName(), "MyCentralWidget");
|
|
|
|
mw.mainWindow()->addDockWidget(dock1, KDDockWidgets::Location_OnRight);
|
|
QTest::qWait(1);
|
|
QVERIFY(dock1->isVisible());
|
|
}
|
|
|
|
void TestQtWidgets::tst_tabsNotClickable()
|
|
{
|
|
// Well, not a great unit-test, as it's only repro when it's Windows sending the native event
|
|
// Can't repro with fabricated events. Uncomment the WAIT and test different configs manually
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(
|
|
KDDockWidgets::Config::Flag_Default
|
|
| KDDockWidgets::Config::Flag_HideTitleBarWhenTabsVisible);
|
|
|
|
auto dock1 = createDockWidget("dock1", new QWidget());
|
|
auto dock2 = createDockWidget("dock2", new QWidget());
|
|
dock1->addDockWidgetAsTab(dock2);
|
|
|
|
auto group = dock1->dptr()->group();
|
|
QCOMPARE(group->currentIndex(), 1);
|
|
|
|
QTest::qWait(500); // wait for window to get proper geometry
|
|
|
|
const QPoint clickPoint = group->tabBar()->mapToGlobal(group->tabBar()->rectForTab(0).center());
|
|
QCursor::setPos(clickPoint); // Just for visual debug when needed
|
|
|
|
pressOn(clickPoint, group->tabBar()->view());
|
|
releaseOn(clickPoint, group->tabBar()->view());
|
|
|
|
// WAIT // Uncomment for MANUAL test. Also test by adding Flag_AlwaysShowTabs
|
|
|
|
QCOMPARE(group->currentIndex(), 0);
|
|
}
|
|
|
|
void TestQtWidgets::tst_mainWindowAlwaysHasCentralWidget()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
|
|
auto m = createMainWindow();
|
|
|
|
QWidget *central = dynamic_cast<QtWidgets::MainWindow *>(m->view())->centralWidget();
|
|
auto dropArea = m->dropArea();
|
|
QVERIFY(dropArea);
|
|
|
|
ObjectGuard<Core::Group> centralGroup = Group::fromItem(dropArea->centralFrame());
|
|
QVERIFY(central);
|
|
QVERIFY(dropArea);
|
|
QCOMPARE(dropArea->count(), 1);
|
|
QVERIFY(centralGroup);
|
|
QCOMPARE(centralGroup->dockWidgetCount(), 0);
|
|
|
|
// Add a tab
|
|
auto dock = createDockWidget("doc1");
|
|
m->addDockWidgetAsTab(dock);
|
|
QCOMPARE(dropArea->count(), 1);
|
|
QCOMPARE(centralGroup->dockWidgetCount(), 1);
|
|
|
|
// Detach tab
|
|
QPoint globalPressPos = dragPointForWidget(centralGroup.data(), 0);
|
|
auto tabBar = centralGroup->tabBar()->view();
|
|
QVERIFY(tabBar);
|
|
drag(tabBar, globalPressPos, m->geometry().bottomRight() + QPoint(30, 30));
|
|
|
|
QVERIFY(centralGroup);
|
|
QCOMPARE(dropArea->count(), 1);
|
|
QCOMPARE(centralGroup->dockWidgetCount(), 0);
|
|
QVERIFY(dropArea->checkSanity());
|
|
}
|
|
|
|
void TestQtWidgets::tst_dockableMainWindows()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
|
|
auto m1 = createMainWindow();
|
|
auto dock1 = createDockWidget("dock1", new QPushButton("foo"));
|
|
m1->addDockWidget(dock1, Location_OnTop);
|
|
|
|
auto m2 = new KDDockWidgets::QtWidgets::MainWindow("mainwindow-dockable");
|
|
auto m2Container = createDockWidget("mainwindow-dw", ( View * )m2);
|
|
auto menubar = m2->menuBar();
|
|
menubar->addMenu("File");
|
|
menubar->addMenu("View");
|
|
menubar->addMenu("Help");
|
|
m2Container->open();
|
|
|
|
auto dock21 = createDockWidget("dock21", new QPushButton("foo"));
|
|
auto dock22 = createDockWidget("dock22", new QPushButton("foo"));
|
|
m2->mainWindow()->addDockWidget(dock21, Location_OnLeft);
|
|
m2->mainWindow()->addDockWidget(dock22, Location_OnRight);
|
|
|
|
auto fw = m2Container->floatingWindow();
|
|
Core::TitleBar *fwTitleBar = fw->titleBar();
|
|
|
|
QVERIFY(fw->hasSingleGroup());
|
|
QVERIFY(fw->hasSingleDockWidget());
|
|
|
|
// Check that the inner-inner dock widgets have a visible title-bar
|
|
QVERIFY(dock21->titleBar()->isVisible());
|
|
QVERIFY(dock22->titleBar()->isVisible());
|
|
QVERIFY(dock21->titleBar() != fwTitleBar);
|
|
QVERIFY(dock22->titleBar() != fwTitleBar);
|
|
|
|
const QPoint startPoint = fwTitleBar->mapToGlobal(QPoint(5, 5));
|
|
const QPoint destination = startPoint + QPoint(20, 20);
|
|
|
|
// Check that we don't get the "Refusing to itself" warning. not actually dropping anywhere
|
|
drag(fwTitleBar->view(), startPoint, destination);
|
|
|
|
// The FloatingWindow has a single DockWidget, so it shows the title bar, while the Frame
|
|
// doesn't
|
|
QVERIFY(fwTitleBar->isVisible());
|
|
QVERIFY(!m2Container->dptr()->group()->titleBar()->isVisible());
|
|
|
|
fw->dropArea()->addDockWidget(dock1, Location::Location_OnLeft, nullptr);
|
|
// Now the FloatingWindow has two dock widgets, so our main window dock widget also shows the
|
|
// title bar
|
|
QVERIFY(fwTitleBar->isVisible());
|
|
QVERIFY(m2Container->dptr()->group()->titleBar()->isVisible());
|
|
|
|
// Put it how it was, FloatingWindow is single dock again
|
|
auto group1 = dock1->dptr()->group();
|
|
dock1->close();
|
|
Platform::instance()->tests_waitForDeleted(group1);
|
|
QVERIFY(fwTitleBar->isVisible());
|
|
QVERIFY(!m2Container->dptr()->group()->titleBar()->isVisible());
|
|
|
|
// Repeat, but instead of closing dock1, we float it
|
|
fw->dropArea()->addDockWidget(dock1, Location::Location_OnLeft, nullptr);
|
|
QVERIFY(fwTitleBar->isVisible());
|
|
QVERIFY(m2Container->dptr()->group()->titleBar()->isVisible());
|
|
group1 = dock1->dptr()->group();
|
|
group1->titleBar()->onFloatClicked();
|
|
QVERIFY(fwTitleBar->isVisible());
|
|
|
|
QVERIFY(!m2Container->dptr()->group()->titleBar()->isVisible());
|
|
|
|
fw->dropArea()->addDockWidget(dock1, Location::Location_OnLeft, nullptr);
|
|
}
|
|
|
|
void TestQtWidgets::tst_mdi_mixed_with_docking()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
auto m = createMainWindow(QSize(500, 500), MainWindowOption_HasCentralWidget);
|
|
auto dock1 = createDockWidget("1", new QPushButton("1"));
|
|
|
|
m->addDockWidget(dock1, Location_OnBottom);
|
|
|
|
auto mdiArea = new QtWidgets::MDIArea();
|
|
m->setPersistentCentralView(QtWidgets::ViewWrapper::create(mdiArea));
|
|
|
|
auto mdiWidget1 = createDockWidget("mdi1", new QPushButton("mdi1"));
|
|
auto mdiWidget2 = createDockWidget("mdi2", new QPushButton("mdi12"));
|
|
|
|
mdiArea->addDockWidget(mdiWidget1, QPoint(10, 10));
|
|
mdiArea->addDockWidget(mdiWidget2, QPoint(50, 50));
|
|
|
|
|
|
// We don't support LayoutSaver with mdi yet, but it shouldn't crash
|
|
// so test it as well
|
|
LayoutSaver saver;
|
|
saver.serializeLayout();
|
|
|
|
Core::Group *groupMDI1 = mdiWidget1->d->group();
|
|
Core::Group *group1 = dock1->d->group();
|
|
QVERIFY(!group1->isMDI());
|
|
QVERIFY(groupMDI1->isMDI());
|
|
QVERIFY(!group1->mdiLayout());
|
|
QVERIFY(groupMDI1->mdiLayout());
|
|
|
|
QVERIFY(!dock1->titleBar()->isMDI());
|
|
|
|
auto tb1 = mdiWidget1->titleBar();
|
|
QVERIFY(tb1->isMDI());
|
|
QVERIFY(Platform::instance()->tests_waitForEvent(tb1->view(), QEvent::Show));
|
|
QVERIFY(tb1->isVisible());
|
|
|
|
// Press the float button
|
|
tb1->onFloatClicked();
|
|
|
|
QVERIFY(mdiWidget1->d->lastPosition()->lastItem());
|
|
QVERIFY(mdiWidget1->titleBar()->isVisible());
|
|
QVERIFY(mdiWidget1->isFloating());
|
|
|
|
// Dock again, and check it went back
|
|
mdiWidget1->titleBar()->onFloatClicked();
|
|
QVERIFY(!mdiWidget1->isFloating());
|
|
}
|
|
|
|
void TestQtWidgets::tst_mdi_mixed_with_docking2()
|
|
{
|
|
// Here, the MDI dock widgets are themselves main windows which will show drop-indicators.
|
|
// It will be super nested: MainWindow -> MDI -> MainWindow
|
|
|
|
EnsureTopLevelsDeleted e;
|
|
auto m = createMainWindow(QSize(1000, 500), MainWindowOption_HasCentralWidget);
|
|
auto dock1 = createDockWidget("1", new QPushButton("1"));
|
|
|
|
m->addDockWidget(dock1, Location_OnBottom);
|
|
|
|
auto mdiArea = new QtWidgets::MDIArea();
|
|
|
|
m->setPersistentCentralView(QtWidgets::ViewWrapper::create(mdiArea));
|
|
|
|
|
|
auto createSheet = [](int id) -> Core::DockWidget * {
|
|
auto dock =
|
|
newDockWidget(QStringLiteral("dw-sheet-%1").arg(id), DockWidgetOption_MDINestable);
|
|
auto btn = new QPushButton(QStringLiteral("Sheet %1").arg(id));
|
|
dock->setGuestView(QtWidgets::ViewWrapper::create(btn));
|
|
dock->setTitle(QStringLiteral("Sheet %1").arg(id));
|
|
|
|
return dock;
|
|
};
|
|
|
|
auto mdiWidget1 = createSheet(1);
|
|
auto mdiWidget2 = createSheet(2);
|
|
auto mdiWidget3 = createSheet(3);
|
|
/*auto mdiWidget4 = createSheet(4);
|
|
auto mdiWidget5 = createSheet(5);
|
|
auto mdiWidget6 = createSheet(6);*/
|
|
|
|
|
|
mdiArea->addDockWidget(mdiWidget1, QPoint(10, 10));
|
|
mdiArea->addDockWidget(mdiWidget2, QPoint(50, 50));
|
|
|
|
Core::Group *group1 = mdiWidget1->d->group();
|
|
Core::Group *mdiFrame1 = group1->mdiFrame();
|
|
|
|
ObjectGuard<Core::Group> group2 = mdiWidget2->d->group();
|
|
ObjectGuard<Core::Group> mdiFrame2 = group2->mdiFrame();
|
|
ObjectGuard<DropArea> dropArea2 = group2->mdiDropAreaWrapper();
|
|
|
|
ObjectGuard<DropArea> dropArea1 = group1->mdiDropAreaWrapper();
|
|
dropArea1->addDockWidget(mdiWidget3, Location_OnLeft, nullptr);
|
|
|
|
QVERIFY(!group1->isMDI());
|
|
QVERIFY(group1->isMDIWrapper());
|
|
QVERIFY(group1->mdiDockWidgetWrapper());
|
|
QVERIFY(dropArea1->isMDIWrapper());
|
|
QVERIFY(dropArea2->isMDIWrapper());
|
|
QVERIFY(!mdiFrame1->isMDIWrapper());
|
|
QVERIFY(mdiFrame1->isMDI());
|
|
QVERIFY(!mdiWidget1->d->isMDIWrapper());
|
|
|
|
// Test title bars:
|
|
|
|
auto tb1 = mdiWidget1->titleBar();
|
|
auto mdiTb1 = mdiFrame1->titleBar();
|
|
auto mdiTb2 = mdiFrame2->titleBar();
|
|
|
|
Platform::instance()->tests_waitForEvent(mdiTb1, QEvent::Show);
|
|
|
|
QVERIFY(mdiTb1->isVisible());
|
|
QVERIFY(mdiTb2->isVisible());
|
|
QVERIFY(tb1->isVisible());
|
|
QCOMPARE(tb1->title(), QString("Sheet 1"));
|
|
QCOMPARE(mdiTb1->title(), QString("dockwidgets-unit-tests"));
|
|
QCOMPARE(mdiTb2->title(), QString("Sheet 2"));
|
|
|
|
QVERIFY(tb1 != mdiTb1);
|
|
QCOMPARE(mdiWidget2->titleBar(), mdiTb2);
|
|
|
|
// Test that closing will delete the wrappers:
|
|
mdiWidget2->close();
|
|
QVERIFY(!mdiWidget2->isOpen());
|
|
|
|
Platform::instance()->tests_waitForDeleted(dropArea2);
|
|
QVERIFY(dropArea2.isNull());
|
|
QVERIFY(Platform::instance()->tests_waitForDeleted(mdiFrame2));
|
|
QVERIFY(!mdiFrame2);
|
|
|
|
mdiWidget1->close();
|
|
QVERIFY(!mdiWidget1->isOpen());
|
|
QTest::qWait(500); // wait some event loops to make sure there's no delete later. (There isn't,
|
|
// but a bug could introduce them)
|
|
QVERIFY(!dropArea1.isNull()); // Not deleted, as sheet3 is still there
|
|
QCOMPARE(dropArea1->visibleCount(), 1);
|
|
QVERIFY(mdiTb1->isVisible());
|
|
QCOMPARE(mdiWidget3->titleBar(), mdiTb1);
|
|
Core::Group *group3 = mdiWidget3->d->group();
|
|
QVERIFY(!group3->titleBar()->isVisible());
|
|
|
|
mdiWidget3->close();
|
|
QVERIFY(Platform::instance()->tests_waitForDeleted(dropArea1));
|
|
QVERIFY(!mdiWidget3->isOpen());
|
|
QVERIFY(dropArea1.isNull());
|
|
|
|
// Reopen everything again:
|
|
|
|
mdiArea->addDockWidget(mdiWidget1, QPoint(10, 10));
|
|
mdiArea->addDockWidget(mdiWidget2, QPoint(50, 50));
|
|
group1 = mdiWidget1->d->group();
|
|
mdiFrame1 = group1->mdiFrame();
|
|
dropArea1 = group1->mdiDropAreaWrapper();
|
|
dropArea1->addDockWidget(mdiWidget3, Location_OnLeft, nullptr);
|
|
|
|
// Test floating:
|
|
group2 = mdiWidget2->d->group();
|
|
ObjectGuard<Core::DockWidget> dwWrapper2 = group2->mdiDockWidgetWrapper();
|
|
dropArea2 = group2->mdiDropAreaWrapper();
|
|
QVERIFY(mdiWidget2->isVisible());
|
|
QVERIFY(group2->isMDIWrapper());
|
|
QVERIFY(dwWrapper2->d->isMDIWrapper());
|
|
mdiFrame2 = group2->mdiFrame();
|
|
mdiWidget2->setFloating(true);
|
|
QVERIFY(mdiWidget2->isFloating());
|
|
|
|
QVERIFY(!mdiWidget2->d->group()->isMDI());
|
|
QVERIFY(!mdiWidget2->d->group()->isMDIWrapper());
|
|
QVERIFY(Platform::instance()->tests_waitForDeleted(mdiFrame2));
|
|
|
|
QVERIFY(dropArea2.isNull());
|
|
QVERIFY(dwWrapper2.isNull());
|
|
|
|
auto mdiFrames = mdiArea->groups();
|
|
QCOMPARE(mdiFrames.count(), 1);
|
|
mdiFrame1 = mdiFrames.first();
|
|
QVERIFY(mdiFrame1->isMDI());
|
|
QVERIFY(mdiFrame1->hasNestedMDIDockWidgets());
|
|
auto mdiTitleBar1 = mdiFrame1->titleBar();
|
|
QVERIFY(mdiFrame1->titleBar()->isVisible());
|
|
mdiTitleBar1->makeWindow();
|
|
|
|
QVERIFY(Platform::instance()->tests_waitForDeleted(mdiFrame1));
|
|
QCOMPARE(mdiArea->groups().size(), 0);
|
|
|
|
// Dock again:
|
|
mdiArea->addDockWidget(mdiWidget1, QPoint(10, 10));
|
|
mdiArea->addDockWidget(mdiWidget2, QPoint(50, 50));
|
|
|
|
group1 = mdiWidget1->d->group();
|
|
dropArea1 = group1->mdiDropAreaWrapper();
|
|
dropArea1->addDockWidget(mdiWidget3, Location_OnLeft, nullptr);
|
|
|
|
// Detach an internal dock widget by dragging
|
|
const QPoint globalSrc = mdiWidget1->mapToGlobal(QPoint(5, 5));
|
|
const QPoint globalDest = globalSrc + QPoint(100, 100);
|
|
|
|
drag(mdiWidget1->view(), globalDest);
|
|
|
|
QCOMPARE(mdiArea->groups().count(), 2);
|
|
auto mdiTitleBar = mdiArea->groups().first()->titleBar();
|
|
QVERIFY(mdiTitleBar->isVisible());
|
|
|
|
QVERIFY(!mdiWidget3->isFloating());
|
|
QVERIFY(mdiWidget3->d->lastPosition()->lastItem());
|
|
mdiTitleBar->onFloatClicked();
|
|
QVERIFY(mdiWidget3->isFloating());
|
|
|
|
QVERIFY(Platform::instance()->tests_waitForDeleted(mdiArea->groups().constFirst()));
|
|
QCOMPARE(mdiArea->groups().size(), 1);
|
|
|
|
QVERIFY(!mdiWidget2->isFloating());
|
|
Core::Group *lastMdiFrame = mdiArea->groups().constFirst();
|
|
QVERIFY(lastMdiFrame->titleBar()->isVisible());
|
|
QVERIFY(!lastMdiFrame->titleBar()->isFloating());
|
|
lastMdiFrame->titleBar()->onFloatClicked();
|
|
QVERIFY(mdiWidget2->isFloating());
|
|
|
|
// put it in the MDI area again
|
|
mdiWidget2->titleBar()->onFloatClicked();
|
|
QVERIFY(!mdiWidget2->isFloating());
|
|
}
|
|
|
|
void TestQtWidgets::tst_mdi_mixed_with_docking_setMDISize()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
auto m = createMainWindow(QSize(1000, 500), MainWindowOption_HasCentralWidget);
|
|
auto dock1 = createDockWidget("1", new QPushButton("1"));
|
|
|
|
m->addDockWidget(dock1, Location_OnBottom);
|
|
|
|
auto mdiArea = new QtWidgets::MDIArea();
|
|
m->setPersistentCentralView(QtWidgets::ViewWrapper::create(mdiArea));
|
|
|
|
auto createSheet = [](int id) -> Core::DockWidget * {
|
|
auto dock =
|
|
newDockWidget(QStringLiteral("dw-sheet-%1").arg(id), DockWidgetOption_MDINestable);
|
|
dock->setGuestView(QtWidgets::ViewWrapper::create(
|
|
new QPushButton(QStringLiteral("Sheet %1").arg(id))));
|
|
dock->setTitle(QStringLiteral("Sheet %1").arg(id));
|
|
|
|
return dock;
|
|
};
|
|
|
|
auto mdiWidget1 = createSheet(1);
|
|
auto mdiWidget2 = createSheet(2);
|
|
|
|
mdiArea->addDockWidget(mdiWidget1, QPoint(10, 10));
|
|
mdiArea->addDockWidget(mdiWidget2, QPoint(50, 50));
|
|
|
|
Core::Group *group1 = mdiArea->groups().at(0);
|
|
|
|
const QSize sz1 = group1->view()->size();
|
|
const QSize increment(200, 200);
|
|
|
|
QVERIFY(mdiWidget1->d->mdiLayout());
|
|
mdiWidget1->setMDISize(sz1 + increment);
|
|
|
|
QCOMPARE(group1->size(), sz1 + increment);
|
|
}
|
|
|
|
// No need to port to QtQuick
|
|
void TestQtWidgets::tst_floatingWindowDeleted()
|
|
{
|
|
// Tests a case where the empty floating dock widget wouldn't be deleted
|
|
// Doesn't repro QTBUG-83030 unfortunately, as we already have an event loop running
|
|
// but let's leave this here nonetheless
|
|
class MyMainWindow : public KDDockWidgets::QtWidgets::MainWindow
|
|
{
|
|
public:
|
|
MyMainWindow()
|
|
: KDDockWidgets::QtWidgets::MainWindow("tst_floatingWindowDeleted",
|
|
MainWindowOption_None)
|
|
{
|
|
auto dock1 = newDockWidget(QStringLiteral("DockWidget #1"));
|
|
auto myWidget = new QWidget();
|
|
dock1->setGuestView(QtWidgets::ViewWrapper::create((myWidget)));
|
|
dock1->view()->resize(QSize(600, 600));
|
|
dock1->open();
|
|
|
|
auto dock2 = newDockWidget(QStringLiteral("DockWidget #2"));
|
|
myWidget = new QWidget();
|
|
dock2->setGuestView(QtWidgets::ViewWrapper::create(myWidget));
|
|
dock2->view()->resize(QSize(600, 600));
|
|
dock2->open();
|
|
|
|
dock1->addDockWidgetAsTab(dock2);
|
|
}
|
|
};
|
|
|
|
MyMainWindow m;
|
|
}
|
|
|
|
void TestQtWidgets::tst_addToSmallMainWindow6()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
// Test test shouldn't spit any warnings
|
|
|
|
QWidget container;
|
|
auto lay = new QVBoxLayout(&container);
|
|
auto m = Platform::instance()->createMainWindow("MyMainWindow_tst_addToSmallMainWindow8", {},
|
|
MainWindowOption_None);
|
|
auto qmainwindow = dynamic_cast<QtWidgets::MainWindow *>(m->view());
|
|
lay->addWidget(qmainwindow);
|
|
container.resize(100, 100);
|
|
Platform::instance()->tests_waitForEvent(&container, QEvent::Resize);
|
|
container.show();
|
|
Platform::instance()->tests_waitForResize(m);
|
|
auto dock1 = createDockWidget(
|
|
"dock1", Platform::instance()->tests_createView({ true, {}, QSize(50, 240) }));
|
|
auto dock2 = createDockWidget(
|
|
"dock2", Platform::instance()->tests_createView({ true, {}, QSize(50, 240) }));
|
|
m->addDockWidget(dock1, KDDockWidgets::Location_OnBottom);
|
|
m->addDockWidget(dock2, KDDockWidgets::Location_OnBottom);
|
|
Platform::instance()->tests_waitForResize(m);
|
|
QVERIFY(m->dropArea()->checkSanity());
|
|
delete m;
|
|
}
|
|
|
|
void TestQtWidgets::tst_sideBarHidden()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None);
|
|
auto dw1 = newDockWidget(QStringLiteral("1"));
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
|
|
auto sb = m1->sideBar(SideBarLocation::South);
|
|
QVERIFY(sb);
|
|
QVERIFY(sb->isEmpty());
|
|
QVERIFY(!sb->isVisible());
|
|
|
|
m1->moveToSideBar(dw1);
|
|
QVERIFY(!sb->isEmpty());
|
|
QVERIFY(sb->isVisible());
|
|
}
|
|
|
|
void TestQtWidgets::tst_closeRemovesFromSideBar()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None);
|
|
auto dw1 = newDockWidget(QStringLiteral("1"));
|
|
auto fw1 = dw1->window();
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
m1->moveToSideBar(dw1);
|
|
|
|
QVERIFY(!dw1->isOverlayed());
|
|
QVERIFY(!dw1->isVisible());
|
|
QVERIFY(dw1->isInSideBar());
|
|
|
|
Core::SideBar *sb = m1->sideBarForDockWidget(dw1);
|
|
QVERIFY(sb);
|
|
|
|
// Overlay it:
|
|
sb->toggleOverlay(dw1);
|
|
QVERIFY(dw1->isOverlayed());
|
|
QVERIFY(dw1->isVisible());
|
|
QCOMPARE(dw1->sideBarLocation(), sb->location());
|
|
QVERIFY(dw1->isInMainWindow());
|
|
QVERIFY(!dw1->isFloating());
|
|
|
|
// Close it while it's overlayed:
|
|
dw1->close();
|
|
QVERIFY(!dw1->isInMainWindow());
|
|
QVERIFY(!dw1->isOverlayed());
|
|
QVERIFY(!dw1->isVisible());
|
|
QCOMPARE(dw1->sideBarLocation(), SideBarLocation::None);
|
|
}
|
|
|
|
void TestQtWidgets::tst_restoreSideBar()
|
|
{
|
|
SideBarLocation loc;
|
|
QByteArray serialized; // serialization after having 1 sidebar visible
|
|
QByteArray beforeSideBarSerialized; // serialization without any sidebar visible
|
|
|
|
{
|
|
LayoutSaver saver;
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = newDockWidget(QStringLiteral("1"));
|
|
auto fw1 = dw1->window();
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
beforeSideBarSerialized = saver.serializeLayout();
|
|
QVERIFY(!m1->anySideBarIsVisible());
|
|
m1->moveToSideBar(dw1);
|
|
QVERIFY(m1->anySideBarIsVisible());
|
|
|
|
QVERIFY(!dw1->isOverlayed());
|
|
QVERIFY(!dw1->isVisible());
|
|
loc = dw1->sideBarLocation();
|
|
QVERIFY(loc != SideBarLocation::None);
|
|
|
|
serialized = saver.serializeLayout();
|
|
|
|
m1.reset();
|
|
}
|
|
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = newDockWidget(QStringLiteral("1"));
|
|
auto fw1 = dw1->window();
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
QVERIFY(!m1->anySideBarIsVisible());
|
|
QVERIFY(!dw1->isOverlayed());
|
|
QVERIFY(dw1->isVisible());
|
|
QVERIFY(!dw1->isFloating());
|
|
QVERIFY(dw1->isInMainWindow());
|
|
|
|
LayoutSaver restorer;
|
|
restorer.restoreLayout(serialized);
|
|
|
|
QVERIFY(!dw1->isOverlayed());
|
|
QVERIFY(!dw1->isVisible());
|
|
QVERIFY(!dw1->isInMainWindow());
|
|
QVERIFY(m1->anySideBarIsVisible());
|
|
|
|
QCOMPARE(loc, dw1->sideBarLocation());
|
|
|
|
restorer.restoreLayout(beforeSideBarSerialized);
|
|
QVERIFY(!dw1->isOverlayed());
|
|
QVERIFY(dw1->isVisible());
|
|
QVERIFY(!dw1->isFloating());
|
|
QVERIFY(dw1->isInMainWindow());
|
|
QVERIFY(!m1->anySideBarIsVisible());
|
|
|
|
QCOMPARE(LayoutSaver::sideBarDockWidgetsInLayout(serialized), { "1" });
|
|
}
|
|
|
|
void TestQtWidgets::tst_restoreSideBar2()
|
|
{
|
|
// Tests a case where the layout size would be bigger than the parent DropArea
|
|
EnsureTopLevelsDeleted e;
|
|
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
KDDockWidgets::QtWidgets::MainWindow m1("MyMainWindow");
|
|
m1.resize(QSize(1197, 1197));
|
|
|
|
auto dw1 = new KDDockWidgets::QtWidgets::DockWidget(
|
|
QStringLiteral("DockWidget #0"));
|
|
auto dw2 = new KDDockWidgets::QtWidgets::DockWidget(
|
|
QStringLiteral("DockWidget #1"));
|
|
auto dw3 = new KDDockWidgets::QtWidgets::DockWidget(
|
|
QStringLiteral("DockWidget #2"));
|
|
m1.addDockWidget(dw1, KDDockWidgets::Location_OnTop);
|
|
m1.addDockWidget(dw2, KDDockWidgets::Location_OnRight, dw1);
|
|
m1.addDockWidget(dw3, KDDockWidgets::Location_OnLeft);
|
|
m1.show();
|
|
auto layout = m1.mainWindow()->layout();
|
|
QCOMPARE(layout->size().width(), layout->layoutSize().width());
|
|
QCOMPARE(layout->size().height(), layout->layoutSize().height());
|
|
|
|
LayoutSaver saver;
|
|
saver.restoreFromFile(":/layouts/sidebar_restore.json");
|
|
|
|
QVERIFY(dw1->isOpen());
|
|
QVERIFY(!dw2->isOpen());
|
|
QVERIFY(dw3->dockWidget()->isInSideBar());
|
|
QVERIFY(layout->checkSanity());
|
|
|
|
QCOMPARE(layout->size(), layout->layoutSize());
|
|
}
|
|
|
|
void TestQtWidgets::tst_openWhenOnSideBar()
|
|
{
|
|
// Calling DW::open() when on sidebar should open it in its previous docked position
|
|
// and remove it from overlay
|
|
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = newDockWidget("1");
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
dw1->moveToSideBar();
|
|
QTest::qWait(100);
|
|
|
|
QVERIFY(!m1->overlayedDockWidget());
|
|
QVERIFY(m1->anySideBarIsVisible());
|
|
|
|
QVERIFY(!dw1->dptr()->m_lastPositions->wasFloating());
|
|
dw1->open();
|
|
|
|
QVERIFY(!m1->overlayedDockWidget());
|
|
QVERIFY(!m1->anySideBarIsVisible());
|
|
QVERIFY(dw1->isInMainWindow());
|
|
}
|
|
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = newDockWidget("1");
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
dw1->moveToSideBar();
|
|
QTest::qWait(100);
|
|
|
|
QVERIFY(!m1->overlayedDockWidget());
|
|
QVERIFY(m1->anySideBarIsVisible());
|
|
|
|
// overlay and deoverlay
|
|
m1->toggleOverlayOnSideBar(dw1);
|
|
m1->toggleOverlayOnSideBar(dw1);
|
|
|
|
// open should go to docked position, not floating
|
|
dw1->open();
|
|
|
|
QVERIFY(!m1->overlayedDockWidget());
|
|
QVERIFY(!m1->anySideBarIsVisible());
|
|
|
|
QVERIFY(dw1->isInMainWindow());
|
|
}
|
|
}
|
|
|
|
void TestQtWidgets::tst_isOpenSideBar()
|
|
{
|
|
// Tests that DockWidget::isOpen() toggles when we toggle the overlay
|
|
EnsureTopLevelsDeleted e;
|
|
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = newDockWidget("1");
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
dw1->moveToSideBar();
|
|
|
|
QVERIFY(!m1->overlayedDockWidget());
|
|
QVERIFY(m1->anySideBarIsVisible());
|
|
QVERIFY(!dw1->isOpen());
|
|
|
|
// overlay it:
|
|
m1->toggleOverlayOnSideBar(dw1);
|
|
QVERIFY(m1->overlayedDockWidget());
|
|
QVERIFY(m1->anySideBarIsVisible());
|
|
QVERIFY(dw1->isOpen());
|
|
|
|
// close overlay:
|
|
m1->toggleOverlayOnSideBar(dw1);
|
|
QVERIFY(!m1->overlayedDockWidget());
|
|
QVERIFY(m1->anySideBarIsVisible());
|
|
|
|
QVERIFY(!dw1->isOpen());
|
|
}
|
|
|
|
void TestQtWidgets::tst_toggleActionOnSideBar()
|
|
{
|
|
// When a dock widget is in the sidebar and we use DockWidget::toggleAction() then it should
|
|
// toggle visibility without removing it from the sidebar
|
|
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = newDockWidget("1");
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
dw1->moveToSideBar();
|
|
|
|
QVERIFY(!dw1->isVisible());
|
|
QVERIFY(!dw1->isOverlayed());
|
|
QVERIFY(dw1->isInSideBar());
|
|
QVERIFY(!dw1->isInMainWindow());
|
|
|
|
auto action = dw1->toggleAction();
|
|
action->trigger();
|
|
|
|
QVERIFY(dw1->isVisible());
|
|
QVERIFY(dw1->isOverlayed());
|
|
QVERIFY(dw1->isInMainWindow());
|
|
|
|
QVERIFY(dw1->isInSideBar());
|
|
action->trigger();
|
|
|
|
QVERIFY(!dw1->isOverlayed());
|
|
QVERIFY(!dw1->isInMainWindow());
|
|
|
|
QVERIFY(dw1->isInSideBar());
|
|
QVERIFY(!dw1->isInMainWindow());
|
|
|
|
|
|
// Count how many times toggleActions triggers:
|
|
int openCount = 0;
|
|
int closeCount = 0;
|
|
KDBindings::ScopedConnection conn = action->d->toggled.connect([&](bool t) {
|
|
if (t)
|
|
openCount++;
|
|
else
|
|
closeCount++;
|
|
});
|
|
|
|
// Make it visible on sidebar:
|
|
m1->toggleOverlayOnSideBar(dw1);
|
|
QCOMPARE(openCount, 1);
|
|
QCOMPARE(closeCount, 0);
|
|
|
|
// close it on sidebar
|
|
m1->toggleOverlayOnSideBar(dw1);
|
|
QCOMPARE(openCount, 1);
|
|
QCOMPARE(closeCount, 1);
|
|
|
|
// Make visible on sidebar again
|
|
m1->toggleOverlayOnSideBar(dw1);
|
|
QCOMPARE(openCount, 2);
|
|
QCOMPARE(closeCount, 1);
|
|
|
|
// Click the unpin button, docks in main window, no toggling should happen
|
|
dw1->titleBar()->onAutoHideClicked();
|
|
QCOMPARE(openCount, 2);
|
|
QCOMPARE(closeCount, 1);
|
|
}
|
|
|
|
void TestQtWidgets::tst_deleteOnCloseWhenOnSideBar()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
auto m = createMainWindow(QSize(800, 500), MainWindowOption_None);
|
|
ObjectGuard<Core::DockWidget> dock1 = createDockWidget(
|
|
"dock1", Platform::instance()->tests_createView({ true, {}, QSize(400, 400) }),
|
|
DockWidgetOption_DeleteOnClose);
|
|
m->addDockWidget(dock1, Location_OnLeft);
|
|
|
|
dock1->moveToSideBar();
|
|
QVERIFY(dock1);
|
|
QVERIFY(dock1->isInSideBar());
|
|
|
|
QTest::qWait(500);
|
|
QVERIFY(dock1);
|
|
}
|
|
|
|
void TestQtWidgets::tst_sidebarOverlayShowsAutohide()
|
|
{
|
|
// Tests that overlayed widgets show the "Disable auto-hide" button
|
|
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = newDockWidget(QStringLiteral("1"));
|
|
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
QVERIFY(dw1->titleBar()->supportsAutoHideButton());
|
|
|
|
m1->moveToSideBar(dw1);
|
|
m1->overlayOnSideBar(dw1);
|
|
|
|
QVERIFY(dw1->isOverlayed());
|
|
|
|
auto titleBar = dw1->titleBar();
|
|
QVERIFY(titleBar->isVisible());
|
|
QVERIFY(titleBar->supportsAutoHideButton());
|
|
|
|
delete dw1;
|
|
}
|
|
|
|
void TestQtWidgets::tst_sidebarOverlayGetsHiddenOnClick()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
|
|
{
|
|
// Case #1 click on another dockwidget should hide the overlay
|
|
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = newDockWidget(QStringLiteral("1"));
|
|
auto dw2 = newDockWidget(QStringLiteral("2"));
|
|
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
m1->addDockWidget(dw2, Location_OnBottom);
|
|
|
|
m1->moveToSideBar(dw1);
|
|
m1->overlayOnSideBar(dw1);
|
|
|
|
QVERIFY(dw1->isOverlayed());
|
|
|
|
Tests::clickOn(dw2->mapToGlobal(dw2->rect().bottomLeft() + QPoint(5, -5)), dw2->view());
|
|
QVERIFY(!dw1->isOverlayed());
|
|
QVERIFY(dw1->isInSideBar());
|
|
|
|
auto widget2 = Platform::instance()->tests_createView({ true });
|
|
dw2->setGuestView(widget2->asWrapper());
|
|
m1->overlayOnSideBar(dw1);
|
|
QVERIFY(dw1->isOverlayed());
|
|
Tests::clickOn(widget2->mapToGlobal(widget2->rect().bottomLeft() + QPoint(5, -5)), widget2);
|
|
QVERIFY(!dw1->isOverlayed());
|
|
|
|
m1.reset();
|
|
delete dw1;
|
|
}
|
|
|
|
{
|
|
// Case #1 click on empty main window space, should hide the overlay
|
|
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = newDockWidget(QStringLiteral("1"));
|
|
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
|
|
m1->moveToSideBar(dw1);
|
|
m1->overlayOnSideBar(dw1);
|
|
|
|
QVERIFY(dw1->isOverlayed());
|
|
|
|
const QPoint localPt(100, 250);
|
|
Tests::clickOn(m1->mapToGlobal(m1->rect().topLeft() + localPt),
|
|
m1->view()->childViewAt(localPt).get());
|
|
QVERIFY(!dw1->isOverlayed());
|
|
}
|
|
}
|
|
|
|
void TestQtWidgets::tst_sidebarGrouping()
|
|
{
|
|
// Tests Flag_AutoHideAsTabGroups
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport | KDDockWidgets::Config::Flag_AutoHideAsTabGroups);
|
|
|
|
{
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = newDockWidget(QStringLiteral("1"));
|
|
auto dw2 = newDockWidget(QStringLiteral("2"));
|
|
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
dw1->addDockWidgetAsTab(dw2);
|
|
|
|
dw1->titleBar()->onAutoHideClicked();
|
|
QVERIFY(dw1->isInSideBar());
|
|
QVERIFY(dw2->isInSideBar());
|
|
QVERIFY(!dw1->isOverlayed());
|
|
QVERIFY(!dw2->isOverlayed());
|
|
|
|
m1->overlayOnSideBar(dw1);
|
|
QVERIFY(dw1->isOverlayed());
|
|
QVERIFY(!dw2->isOverlayed());
|
|
|
|
dw1->titleBar()->onAutoHideClicked();
|
|
QVERIFY(!dw1->isInSideBar());
|
|
QVERIFY(!dw2->isInSideBar());
|
|
QVERIFY(!dw1->isOverlayed());
|
|
QVERIFY(!dw2->isOverlayed());
|
|
}
|
|
}
|
|
|
|
void TestQtWidgets::tst_sidebarCrash()
|
|
{
|
|
// Tests a crash that happened when toggling overlay a few times
|
|
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = newDockWidget(QStringLiteral("1"));
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
|
|
dw1->titleBar()->onAutoHideClicked();
|
|
QVERIFY(dw1->isInSideBar());
|
|
|
|
m1->overlayOnSideBar(dw1);
|
|
|
|
dw1->titleBar()->onAutoHideClicked();
|
|
QVERIFY(!dw1->isInSideBar());
|
|
QVERIFY(!dw1->isOverlayed());
|
|
|
|
dw1->titleBar()->onAutoHideClicked();
|
|
QVERIFY(dw1->isInSideBar());
|
|
|
|
QTest::qWait(1000);
|
|
|
|
m1->toggleOverlayOnSideBar(dw1);
|
|
}
|
|
|
|
void TestQtWidgets::tst_sidebarCrash2()
|
|
{
|
|
// Tests a crash, only reproduceable with an ASAN build of Qt
|
|
// While unpinning, the QToolButton would be deleted while still on the stack
|
|
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = newDockWidget(QStringLiteral("1"));
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
m1->moveToSideBar(dw1);
|
|
m1->overlayOnSideBar(dw1);
|
|
|
|
auto titleBarWidget = qobject_cast<QtWidgets::TitleBar *>(QtCommon::View_qt::asQWidget(dw1->titleBar()->view()));
|
|
QVERIFY(titleBarWidget && titleBarWidget->isVisible());
|
|
|
|
auto button = titleBarWidget->m_autoHideButton;
|
|
QVERIFY(button && button->isVisible());
|
|
|
|
auto globalPos = button->mapToGlobal(QPoint(5, 5));
|
|
|
|
auto b = QtWidgets::ViewWrapper::create(button);
|
|
Tests::clickOn(globalPos, b.get());
|
|
}
|
|
|
|
void TestQtWidgets::tst_sidebarCloseReason()
|
|
{
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = newDockWidget(QStringLiteral("1"));
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
|
|
CloseReason expectedLastReason = CloseReason::Unspecified;
|
|
KDBindings::ScopedConnection conn = dw1->toggleAction()->d->toggled.connect([&expectedLastReason, dw1](bool open) {
|
|
// We also check that the value is actually set *before* the QAction firing
|
|
// as users connect to the action
|
|
if (!open)
|
|
Q_ASSERT(dw1->lastCloseReason() == expectedLastReason);
|
|
});
|
|
|
|
expectedLastReason = CloseReason::MovedToSideBar;
|
|
dw1->titleBar()->onAutoHideClicked();
|
|
QVERIFY(dw1->isInSideBar());
|
|
QVERIFY(!dw1->isOpen());
|
|
|
|
QCOMPARE(dw1->lastCloseReason(), expectedLastReason);
|
|
|
|
m1->overlayOnSideBar(dw1);
|
|
QVERIFY(dw1->isInSideBar());
|
|
QVERIFY(dw1->isOpen());
|
|
|
|
expectedLastReason = CloseReason::OverlayCollapse;
|
|
m1->clearSideBarOverlay();
|
|
QCOMPARE(dw1->lastCloseReason(), expectedLastReason);
|
|
|
|
m1->overlayOnSideBar(dw1);
|
|
QVERIFY(dw1->isInSideBar());
|
|
QVERIFY(dw1->isOpen());
|
|
expectedLastReason = CloseReason::TitleBarCloseButton;
|
|
dw1->titleBar()->onCloseClicked();
|
|
QCOMPARE(dw1->lastCloseReason(), expectedLastReason);
|
|
|
|
expectedLastReason = CloseReason::MovedToSideBar;
|
|
dw1->open();
|
|
m1->moveToSideBar(dw1);
|
|
QCOMPARE(dw1->lastCloseReason(), expectedLastReason);
|
|
}
|
|
}
|
|
|
|
void TestQtWidgets::tst_sidebarSide()
|
|
{
|
|
// Tests which sidebar is chosen
|
|
|
|
{
|
|
// Tests that if a dock widget is touching top and bottom border, it will go to
|
|
// left sidebar if it's closer to it.
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = newDockWidget(QStringLiteral("1"));
|
|
auto dw2 = newDockWidget(QStringLiteral("2"));
|
|
auto dw3 = newDockWidget(QStringLiteral("3"));
|
|
auto dw4 = newDockWidget(QStringLiteral("4"));
|
|
m1->addDockWidget(dw1, Location_OnRight);
|
|
m1->addDockWidget(dw2, Location_OnRight);
|
|
m1->addDockWidget(dw3, Location_OnRight);
|
|
m1->addDockWidget(dw4, Location_OnRight);
|
|
m1->layoutEqually();
|
|
|
|
dw2->titleBar()->onAutoHideClicked();
|
|
|
|
auto sb = m1->sideBarForDockWidget(dw2);
|
|
QVERIFY(sb);
|
|
QCOMPARE(sb->location(), SideBarLocation::West);
|
|
}
|
|
}
|
|
|
|
void TestQtWidgets::tst_floatRemovesFromSideBar()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = newDockWidget(QStringLiteral("1"));
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
|
|
m1->moveToSideBar(dw1);
|
|
m1->overlayOnSideBar(dw1);
|
|
|
|
QVERIFY(dw1->isOverlayed());
|
|
QVERIFY(!dw1->isFloating());
|
|
QVERIFY(dw1->isInMainWindow());
|
|
|
|
dw1->setFloating(true);
|
|
QVERIFY(!dw1->isOverlayed());
|
|
QVERIFY(dw1->isFloating());
|
|
QVERIFY(!dw1->isInMainWindow());
|
|
|
|
QCOMPARE(dw1->sideBarLocation(), SideBarLocation::None);
|
|
|
|
// Also test a crash I got
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
|
|
auto tb = dw1->titleBar();
|
|
QVERIFY(tb->isVisible());
|
|
|
|
tb->onFloatClicked();
|
|
}
|
|
|
|
void TestQtWidgets::tst_overlayedGeometryIsSaved()
|
|
{
|
|
// Tests that after resizing an overlayed widget, and then hide+show, its size is preserved
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = newDockWidget(QStringLiteral("1"));
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
|
|
m1->moveToSideBar(dw1, SideBarLocation::North);
|
|
m1->overlayOnSideBar(dw1);
|
|
|
|
Core::Group *group = dw1->dptr()->group();
|
|
QVERIFY(group->isOverlayed());
|
|
QCOMPARE(dw1->sideBarLocation(), SideBarLocation::North);
|
|
QVERIFY(group->height() > 0);
|
|
|
|
const int newHeight = group->height() + 300;
|
|
group->view()->setHeight(newHeight);
|
|
|
|
m1->toggleOverlayOnSideBar(dw1);
|
|
m1->toggleOverlayOnSideBar(dw1);
|
|
|
|
group = dw1->dptr()->group();
|
|
QCOMPARE(group->height(), newHeight);
|
|
}
|
|
|
|
void TestQtWidgets::tst_overlayCrash()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = newDockWidget(QStringLiteral("1"));
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
|
|
auto dw2 = newDockWidget(QStringLiteral("2"));
|
|
m1->addDockWidget(dw2, Location_OnBottom);
|
|
|
|
m1->moveToSideBar(dw1);
|
|
m1->toggleOverlayOnSideBar(dw1);
|
|
|
|
dw1->close();
|
|
|
|
auto tb = dw2->titleBar();
|
|
QVERIFY(tb->isVisible());
|
|
|
|
pressOn(tb->mapToGlobal(QPoint(5, 5)), tb->view());
|
|
}
|
|
|
|
void TestQtWidgets::tst_embeddedMainWindow()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
// Tests a MainWindow which isn't a top-level window, but is embedded in another window
|
|
EmbeddedWindow *window = createEmbeddedMainWindow(QSize(800, 800));
|
|
|
|
auto dock1 = createDockWidget("1", new QPushButton("1"));
|
|
window->mainWindow->addDockWidget(dock1, Location_OnTop);
|
|
dock1->setFloating(true);
|
|
auto dropArea = window->mainWindow->dropArea();
|
|
auto fw = dock1->floatingWindow();
|
|
|
|
dragFloatingWindowTo(fw, dropArea, DropLocation_Left);
|
|
|
|
auto layout = dropArea;
|
|
QVERIFY(Platform::instance()->tests_waitForDeleted(fw));
|
|
QCOMPARE(layout->count(), 2); // 2, as it has the central group
|
|
QCOMPARE(layout->visibleCount(), 2);
|
|
layout->checkSanity();
|
|
|
|
delete window;
|
|
}
|
|
|
|
void TestQtWidgets::tst_restoreEmbeddedMainWindow()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
// Tests a MainWindow which isn't a top-level window, but is embedded in another window
|
|
EmbeddedWindow *window = createEmbeddedMainWindow(QSize(800, 800));
|
|
|
|
auto dock1 = createDockWidget("1", new QPushButton("1"));
|
|
window->mainWindow->addDockWidget(dock1, Location_OnTop);
|
|
|
|
const QPoint originalPos(250, 250);
|
|
const QSize originalSize = window->size();
|
|
window->move(originalPos);
|
|
|
|
LayoutSaver saver;
|
|
QByteArray saved = saver.serializeLayout();
|
|
QVERIFY(!saved.isEmpty());
|
|
|
|
window->resize(555, 555);
|
|
const QPoint newPos(500, 500);
|
|
window->move(newPos);
|
|
QVERIFY(saver.restoreLayout(saved));
|
|
|
|
QCOMPARE(window->pos(), originalPos);
|
|
QCOMPARE(window->size(), originalSize);
|
|
window->mainWindow->layout()->checkSanity();
|
|
|
|
delete window;
|
|
}
|
|
|
|
void TestQtWidgets::tst_negativeAnchorPositionWhenEmbedded_data()
|
|
{
|
|
QTest::addColumn<bool>("embedded");
|
|
|
|
QTest::newRow("false") << false;
|
|
QTest::newRow("true") << true;
|
|
}
|
|
|
|
void TestQtWidgets::tst_negativeAnchorPositionWhenEmbedded()
|
|
{
|
|
QFETCH(bool, embedded);
|
|
EnsureTopLevelsDeleted e;
|
|
|
|
MainWindow *m = nullptr;
|
|
if (embedded) {
|
|
auto em = createEmbeddedMainWindow(QSize(500, 500));
|
|
m = em->mainWindow;
|
|
} else {
|
|
m = createMainWindow(QSize(500, 500), MainWindowOption_HasCentralGroup).release();
|
|
m->view()->resize(QSize(500, 500));
|
|
m->show();
|
|
}
|
|
auto layout = m->multiSplitter();
|
|
|
|
auto w1 = Platform::instance()->tests_createView({ true, {}, QSize(400, 400) });
|
|
auto w2 = Platform::instance()->tests_createView({ true, {}, QSize(400, 400) });
|
|
auto d1 = createDockWidget("1", w1);
|
|
auto d2 = createDockWidget("2", w2);
|
|
auto d3 = createDockWidget("3", w2);
|
|
|
|
m->addDockWidget(d1, Location_OnLeft);
|
|
m->addDockWidget(d2, Location_OnLeft);
|
|
m->addDockWidget(d3, Location_OnLeft);
|
|
|
|
layout->checkSanity();
|
|
|
|
delete static_cast<QtWidgets::ViewWrapper *>(m->window().get())->widget();
|
|
}
|
|
|
|
// For #443
|
|
void TestQtWidgets::tst_restoreWithRemapping()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
QByteArray savedState;
|
|
|
|
// 1. Create a saved state and immediately delete the main window and dock widgets
|
|
auto m = createMainWindow(QSize(500, 500), MainWindowOption_None, "mainWindow1");
|
|
auto dock1 = createDockWidget("1", new QPushButton("1"));
|
|
m->addDockWidget(dock1, Location_OnLeft);
|
|
auto dock2 = createDockWidget("2", new QPushButton("2"));
|
|
m->addDockWidget(dock2, Location_OnRight);
|
|
|
|
LayoutSaver saver;
|
|
savedState = saver.serializeLayout();
|
|
|
|
dock1->setUniqueName("2");
|
|
dock2->setUniqueName("1");
|
|
|
|
// 2. Restore the dock widgets via factory
|
|
LayoutSaver restorer;
|
|
restorer.restoreLayout(savedState);
|
|
|
|
// dock 1 is now on the right of dock 2
|
|
QVERIFY(dock1->dptr()->group()->view()->x() > dock2->dptr()->group()->view()->x());
|
|
}
|
|
|
|
void TestQtWidgets::tst_restoreResizesLayout()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
auto m = createMainWindow(QSize(500, 500), MainWindowOption_None);
|
|
auto dock1 = createDockWidget("1", new QPushButton("1"));
|
|
m->addDockWidget(dock1, Location_OnLeft);
|
|
|
|
LayoutSaver saver;
|
|
QVERIFY(saver.saveToFile("layout_tst_restoreResizesLayout.json"));
|
|
|
|
// Now resize the window, and then restore. The layout should have the new size
|
|
|
|
auto layout = m->multiSplitter();
|
|
m->view()->resize(QSize(1050, 1050));
|
|
QCOMPARE(m->size(), QSize(1050, 1050));
|
|
|
|
LayoutSaver restorer(RestoreOption_RelativeToMainWindow);
|
|
QVERIFY(restorer.restoreFromFile("layout_tst_restoreResizesLayout.json"));
|
|
QVERIFY(layout->checkSanity());
|
|
|
|
QCOMPARE(m->dropArea()->size(), layout->layoutSize());
|
|
QVERIFY(layout->checkSanity());
|
|
}
|
|
|
|
void TestQtWidgets::tst_restoreNonRelativeFloatingWindowGeometry()
|
|
{
|
|
// Tests that disabling RelativeFloatingWindowGeometry works
|
|
|
|
EnsureTopLevelsDeleted e;
|
|
auto m = createMainWindow(QSize(500, 500), MainWindowOption_None);
|
|
auto dock1 = createDockWidget("1", new QPushButton("1"));
|
|
|
|
// Also test that invisible dock doesn't change size
|
|
auto dock2 = createDockWidget("2", new QPushButton("2"), {}, {}, /*show=*/false);
|
|
|
|
LayoutSaver saver(RestoreOption_RelativeToMainWindow);
|
|
saver.dptr()->m_restoreOptions.setFlag(InternalRestoreOption::RelativeFloatingWindowGeometry,
|
|
false);
|
|
|
|
const QByteArray saved = saver.serializeLayout();
|
|
|
|
const QSize floatingWindowSize = dock1->window()->size();
|
|
const QSize floatingWindowSize2 = dock2->window()->size();
|
|
|
|
m->view()->resize(QSize(m->width() * 2, m->height()));
|
|
saver.restoreLayout(saved);
|
|
|
|
QVERIFY(dock2->isFloating());
|
|
QVERIFY(!dock2->isOpen());
|
|
|
|
QCOMPARE(dock1->window()->size(), floatingWindowSize);
|
|
QCOMPARE(dock2->window()->size(), floatingWindowSize2);
|
|
}
|
|
|
|
void TestQtWidgets::tst_maximumSizePolicy()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
|
|
const int maxHeight = 250;
|
|
auto widget =
|
|
Platform::instance()->tests_createView({ true, QSize(250, maxHeight), QSize(200, 200) });
|
|
QtCommon::View_qt::asQWidget(widget)->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
|
|
|
|
auto dock1 = createDockWidget("dock1", widget);
|
|
dock1->open();
|
|
dock1->window()->resize(QSize(500, 500));
|
|
auto window1 = dock1->window();
|
|
dock1->close();
|
|
dock1->open();
|
|
auto oldFw2 = dock1->window();
|
|
|
|
const int tolerance = 50;
|
|
QVERIFY(dock1->window()->height() <= maxHeight + tolerance); // +tolerance as the floating
|
|
// window is a bit bigger, due to
|
|
// margins etc.
|
|
QVERIFY(dock1->height() <= maxHeight);
|
|
|
|
auto m1 = createMainWindow();
|
|
auto dock2 = createDockWidget("dock2", new QPushButton("foo"));
|
|
m1->addDockWidget(dock2, Location_OnTop);
|
|
m1->view()->resize(QSize(2000, 3000));
|
|
|
|
// Make the floating window big, and see if the suggested highlight is still small
|
|
dock1->window()->resize(QSize(dock1->width(), 800));
|
|
|
|
{
|
|
WindowBeingDragged wbd1(dock1->floatingWindow());
|
|
const QRect highlightRect =
|
|
m1->multiSplitter()->rectForDrop(&wbd1, Location_OnBottom, nullptr);
|
|
QVERIFY(highlightRect.height() <= maxHeight + tolerance);
|
|
}
|
|
|
|
// Now drop it, and check too
|
|
m1->addDockWidget(dock1, Location_OnBottom);
|
|
QVERIFY(dock1->height() <= maxHeight);
|
|
}
|
|
|
|
void TestQtWidgets::tst_minSizeChanges()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
auto m = createMainWindow(QSize(600, 600), MainWindowOption_None);
|
|
m->show();
|
|
auto w1 = Platform::instance()->tests_createView({ true, {}, QSize(400, 400) });
|
|
auto w2 = Platform::instance()->tests_createView({ true, {}, QSize(400, 400) });
|
|
|
|
auto d1 = newDockWidget("1");
|
|
d1->setGuestView(w1->asWrapper());
|
|
auto d2 = newDockWidget("2");
|
|
d2->setGuestView(w2->asWrapper());
|
|
|
|
m->addDockWidget(d1, Location_OnTop);
|
|
m->addDockWidget(d2, Location_OnTop, nullptr, InitialVisibilityOption::StartHidden);
|
|
auto layout = m->multiSplitter();
|
|
|
|
// 1. d2 is a placeholder, let's change its min size before showing it
|
|
w2->setMinimumSize(QSize(800, 800));
|
|
d2->open();
|
|
|
|
Item *item2 = layout->itemForGroup(d2->dptr()->group());
|
|
|
|
QVERIFY(layout->checkSanity());
|
|
|
|
Platform::instance()->tests_waitForResize(m->view());
|
|
|
|
QVERIFY(item2->width() >= 800);
|
|
QVERIFY(item2->height() >= 800);
|
|
QVERIFY(m->height() >= 1200);
|
|
|
|
// 2. d1 is visible, let's change its min size
|
|
w1->setMinimumSize(QSize(800, 800));
|
|
|
|
Platform::instance()->tests_waitForResize(m->view());
|
|
layout->checkSanity();
|
|
|
|
QVERIFY(m->height() >= 1600);
|
|
|
|
// add a small one to the middle
|
|
auto w3 = Platform::instance()->tests_createView({ true, {}, QSize(100, 100) });
|
|
auto d3 = newDockWidget("3");
|
|
d3->setGuestView(w3->asWrapper());
|
|
m->addDockWidget(d3, Location_OnTop, d1);
|
|
}
|
|
|
|
void TestQtWidgets::tst_maxSizePropagates()
|
|
{
|
|
// Tests that the DockWidget gets the min and max size of its guest widget
|
|
EnsureTopLevelsDeleted e;
|
|
auto dock1 = newDockWidget("dock1");
|
|
|
|
auto w = Platform::instance()->tests_createView({ true, {}, QSize(200, 200) });
|
|
w->setMinimumSize(QSize(120, 120));
|
|
w->setMaximumSize(QSize(500, 500));
|
|
dock1->setGuestView(w->asWrapper());
|
|
dock1->open();
|
|
|
|
|
|
QCOMPARE(dock1->view()->minSize(), w->minSize());
|
|
QCOMPARE(dock1->view()->maxSizeHint(), w->maxSizeHint());
|
|
|
|
w->setMinimumSize(QSize(121, 121));
|
|
w->setMaximumSize(QSize(501, 501));
|
|
|
|
Platform::instance()->tests_waitForEvent(w, QEvent::LayoutRequest);
|
|
|
|
QCOMPARE(dock1->view()->minSize(), w->minSize());
|
|
QCOMPARE(dock1->view()->maxSizeHint(), w->maxSizeHint());
|
|
|
|
// Now let's see if our Frame also has proper size-constraints
|
|
Core::Group *group = dock1->dptr()->group();
|
|
QCOMPARE(group->view()->maxSizeHint().expandedTo(w->maxSizeHint()),
|
|
group->view()->maxSizeHint());
|
|
}
|
|
|
|
void TestQtWidgets::tst_maxSizedFloatingWindow()
|
|
{
|
|
// Tests that FloatingWindows get a proper max-size, if its dock widget has one
|
|
EnsureTopLevelsDeleted e;
|
|
auto dock1 = newDockWidget("dock1");
|
|
auto dock2 = newDockWidget("dock2");
|
|
auto w = Platform::instance()->tests_createView({ true });
|
|
w->setMinimumSize(QSize(120, 100));
|
|
w->setMaximumSize(QSize(300, 300));
|
|
dock1->setGuestView(w->asWrapper());
|
|
|
|
dock1->open();
|
|
dock2->open();
|
|
|
|
auto window1 = dock1->window();
|
|
auto window2 = dock2->window();
|
|
Platform::instance()->tests_waitForEvent(window1.get(), QEvent::LayoutRequest);
|
|
|
|
QVERIFY(window1->maxSizeHint().width() < 500);
|
|
QVERIFY(window1->maxSizeHint().height() < 500);
|
|
QVERIFY(window2->maxSizeHint().width() > 500);
|
|
QVERIFY(window2->maxSizeHint().height() > 500);
|
|
|
|
auto hasMax = [&window1] {
|
|
const QSize max = window1->maxSizeHint();
|
|
return max.width() < 500 && max.height() < 500;
|
|
};
|
|
|
|
// Adding side-by-side, we don't honour max size (yet)
|
|
dock1->addDockWidgetToContainingWindow(dock2, Location_OnBottom);
|
|
Platform::instance()->tests_waitForEvent(window1.get(), QEvent::LayoutRequest);
|
|
QVERIFY(window1->maxSizeHint().width() > 500);
|
|
QVERIFY(window1->maxSizeHint().height() > 500);
|
|
|
|
// Close dw2, we have a single dock widget again, we honour max-size
|
|
dock2->close();
|
|
Platform::instance()->tests_waitForEvent(window1.get(), QEvent::LayoutRequest);
|
|
QVERIFY(hasMax());
|
|
|
|
dock1->addDockWidgetAsTab(dock2);
|
|
Platform::instance()->tests_waitForEvent(window1.get(), QEvent::LayoutRequest);
|
|
QVERIFY(!hasMax());
|
|
|
|
dock2->close();
|
|
Platform::instance()->tests_waitForEvent(window1.get(), QEvent::LayoutRequest);
|
|
QVERIFY(hasMax());
|
|
}
|
|
|
|
void TestQtWidgets::tst_maxSizeHonouredWhenAnotherDropped()
|
|
{
|
|
// dock1 is docked, and has small max-height.
|
|
// When dropping dock2, which is small too, dock2 should occupy all the height except dock1's
|
|
// max-height i.e. dock2 should expand and eat all available space
|
|
|
|
EnsureTopLevelsDeleted e;
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None);
|
|
auto dock1 = newDockWidget("dock1");
|
|
|
|
auto w = Platform::instance()->tests_createView({ true, {}, QSize(400, 400) });
|
|
w->setMinimumSize(QSize(120, 100));
|
|
w->setMaximumSize(QSize(300, 150));
|
|
dock1->setGuestView(w->asWrapper());
|
|
m1->addDockWidget(dock1, Location_OnLeft);
|
|
|
|
auto dock2 = newDockWidget("dock2");
|
|
m1->addDockWidget(dock2, Location_OnBottom);
|
|
|
|
auto root = m1->multiSplitter()->rootItem();
|
|
auto separator = root->separators().constFirst();
|
|
const int min1 = root->minPosForSeparator_global(separator);
|
|
const int max2 = root->maxPosForSeparator_global(separator);
|
|
|
|
QVERIFY(separator->position() >= min1);
|
|
QVERIFY(separator->position() <= max2);
|
|
const int item1MaxHeight = dock1->dptr()->group()->view()->maxSizeHint().height();
|
|
QVERIFY(dock1->dptr()->group()->view()->height() <= item1MaxHeight);
|
|
root->dumpLayout();
|
|
QCOMPARE(dock2->dptr()->group()->view()->height(),
|
|
root->height() - item1MaxHeight - Item::layoutSpacing);
|
|
}
|
|
|
|
void TestQtWidgets::tst_addToHiddenMainWindow()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
auto m = createMainWindow(QSize(1000, 1000), MainWindowOption_HasCentralGroup, {}, false);
|
|
auto w1 = Platform::instance()->tests_createView({ true, {}, QSize(400, 400) });
|
|
auto w2 = Platform::instance()->tests_createView({ true, {}, QSize(400, 400) });
|
|
auto d1 = createDockWidget("1", w1);
|
|
auto d2 = createDockWidget("2", w2);
|
|
|
|
m->addDockWidget(d1, Location_OnTop);
|
|
m->addDockWidget(d2, Location_OnTop);
|
|
|
|
QVERIFY(!m->isVisible());
|
|
d1->setFloating(true);
|
|
d2->setFloating(false);
|
|
m->layout()->checkSanity();
|
|
}
|
|
|
|
void TestQtWidgets::tst_maxSizePropagates2()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None);
|
|
auto dock1 = newDockWidget("dock1");
|
|
|
|
auto w = Platform::instance()->tests_createView({ true, {}, QSize(200, 200) });
|
|
w->setMinimumSize(QSize(120, 120));
|
|
w->setMaximumSize(QSize(300, 500));
|
|
dock1->setGuestView(w->asWrapper());
|
|
dock1->open();
|
|
|
|
auto dock2 = newDockWidget("dock2");
|
|
auto dock3 = newDockWidget("dock3");
|
|
auto dock4 = newDockWidget("dock4");
|
|
m1->addDockWidget(dock2, Location_OnLeft);
|
|
m1->addDockWidget(dock3, Location_OnRight);
|
|
m1->addDockWidget(dock4, Location_OnBottom, dock3);
|
|
m1->addDockWidget(dock1, Location_OnLeft, dock4);
|
|
|
|
Core::Group *group1 = dock1->dptr()->group();
|
|
|
|
Core::ItemBoxContainer *root = m1->multiSplitter()->rootItem();
|
|
Item *item1 = root->itemForView(group1->asLayoutingGuest());
|
|
auto vertSep1 = root->separators().constFirst();
|
|
const int min1 = root->minPosForSeparator_global(vertSep1);
|
|
|
|
ItemBoxContainer *container1 = item1->parentBoxContainer();
|
|
auto innerVertSep1 = container1->separators().constFirst();
|
|
const int minInnerSep = container1->minPosForSeparator_global(innerVertSep1);
|
|
const int maxInnerSep = container1->maxPosForSeparator_global(innerVertSep1);
|
|
|
|
root->requestSeparatorMove(vertSep1, -(vertSep1->position() - min1));
|
|
QVERIFY(group1->width() <= group1->view()->maxSizeHint().width());
|
|
|
|
container1->requestSeparatorMove(innerVertSep1, -(innerVertSep1->position() - minInnerSep));
|
|
QVERIFY(group1->width() <= group1->view()->maxSizeHint().width());
|
|
|
|
container1->requestSeparatorMove(innerVertSep1, maxInnerSep - innerVertSep1->position());
|
|
QVERIFY(group1->width() <= group1->view()->maxSizeHint().width());
|
|
}
|
|
|
|
void TestQtWidgets::tst_maxSizeHonouredWhenDropped()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
auto m1 = createMainWindow();
|
|
auto dock1 = newDockWidget("dock1");
|
|
auto dock2 = newDockWidget("dock2");
|
|
m1->addDockWidget(dock1, Location_OnTop);
|
|
m1->view()->resize(QSize(2000, 2000));
|
|
|
|
auto w2 = Platform::instance()->tests_createView({ true, {}, { 0, 0 } });
|
|
dock2->setGuestView(w2->asWrapper());
|
|
const int maxWidth = 200;
|
|
w2->setMaximumSize(QSize(maxWidth, 200));
|
|
m1->addDockWidget(dock2, Location_OnLeft);
|
|
const int droppedWidth = dock2->dptr()->group()->width();
|
|
QVERIFY(droppedWidth < maxWidth + 50); // +50 to cover any margins and waste by QTabWidget
|
|
|
|
// Try again, but now dropping a multisplitter
|
|
dock2->setFloating(true);
|
|
auto fw = dock2->floatingWindow();
|
|
|
|
m1->dropArea()->drop(fw->view(), Location_OnLeft, nullptr);
|
|
QCOMPARE(dock2->dptr()->group()->width(), droppedWidth);
|
|
}
|
|
|
|
void TestQtWidgets::tst_fixedSizePolicy()
|
|
{
|
|
// tests that KDDW also takes into account QSizePolicy::Fixed for calculating the max size hint.
|
|
// Since QPushButton for example doesn't set QWidget::maximumSize(), but instead uses sizeHint()
|
|
// + QSizePolicy::Fixed.
|
|
EnsureTopLevelsDeleted e;
|
|
auto button = new QPushButton("one");
|
|
auto dock1 = createDockWidget("dock1", button);
|
|
Core::Group *group = dock1->dptr()->group();
|
|
|
|
// Just a precondition from the test. If QPushButton ever changes, replace with a QWidget and
|
|
// set fixed size policy
|
|
QCOMPARE(button->sizePolicy().verticalPolicy(), QSizePolicy::Fixed);
|
|
|
|
const int buttonMaxHeight = button->sizeHint().height();
|
|
|
|
QWidget *dockWidget1 = QtCommon::View_qt::asQWidget(dock1->view());
|
|
QCOMPARE(dockWidget1->sizePolicy().verticalPolicy(),
|
|
button->sizePolicy().verticalPolicy());
|
|
QCOMPARE(dockWidget1->sizePolicy().horizontalPolicy(),
|
|
button->sizePolicy().horizontalPolicy());
|
|
|
|
QCOMPARE(group->view()->maxSizeHint().height(),
|
|
qMax(buttonMaxHeight, Core::Item::hardcodedMinimumSize.height()));
|
|
}
|
|
|
|
void TestQtWidgets::tst_restoreFloatingMaximizedState()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_TitleBarHasMaximizeButton);
|
|
auto dock1 = createDockWidget("dock1", Platform::instance()->tests_createView({ true }));
|
|
const QRect originalNormalGeometry = dock1->floatingWindow()->view()->normalGeometry();
|
|
dock1->floatingWindow()->view()->showMaximized();
|
|
|
|
QCOMPARE(dock1->floatingWindow()->view()->window()->windowState(), WindowState::Maximized);
|
|
|
|
LayoutSaver saver;
|
|
const QByteArray saved = saver.serializeLayout();
|
|
|
|
saver.restoreLayout(saved);
|
|
QCOMPARE(dock1->floatingWindow()->view()->window()->windowState(), WindowState::Maximized);
|
|
|
|
QCOMPARE(dock1->floatingWindow()->view()->normalGeometry(), originalNormalGeometry);
|
|
|
|
dock1->floatingWindow()->view()->showNormal();
|
|
QCOMPARE(dock1->floatingWindow()->view()->normalGeometry(), originalNormalGeometry);
|
|
}
|
|
|
|
void TestQtWidgets::tst_complex()
|
|
{
|
|
// Tests some anchors out of bounds I got
|
|
|
|
EnsureTopLevelsDeleted e;
|
|
auto m = createMainWindow(QSize(600, 500), MainWindowOption_None);
|
|
auto layout = m->multiSplitter();
|
|
m->view()->resize(QSize(3266, 2239));
|
|
m->show();
|
|
|
|
Core::DockWidget::List docks;
|
|
|
|
QVector<KDDockWidgets::Location> locations = {
|
|
Location_OnLeft, Location_OnLeft, Location_OnLeft, Location_OnRight,
|
|
Location_OnRight, Location_OnRight, Location_OnRight, Location_OnBottom,
|
|
Location_OnBottom, Location_OnBottom, Location_OnBottom, Location_OnBottom,
|
|
Location_OnBottom, Location_OnBottom, Location_OnBottom, Location_OnBottom,
|
|
Location_OnBottom, Location_OnBottom, Location_OnBottom, Location_OnBottom,
|
|
Location_OnBottom
|
|
};
|
|
|
|
QVector<KDDockWidgets::InitialVisibilityOption> options = {
|
|
InitialVisibilityOption::StartVisible, InitialVisibilityOption::StartVisible,
|
|
InitialVisibilityOption::StartHidden, InitialVisibilityOption::StartHidden,
|
|
InitialVisibilityOption::StartVisible, InitialVisibilityOption::StartHidden,
|
|
InitialVisibilityOption::StartHidden, InitialVisibilityOption::StartHidden,
|
|
InitialVisibilityOption::StartHidden, InitialVisibilityOption::StartHidden,
|
|
InitialVisibilityOption::StartHidden, InitialVisibilityOption::StartVisible,
|
|
InitialVisibilityOption::StartVisible, InitialVisibilityOption::StartHidden,
|
|
InitialVisibilityOption::StartHidden, InitialVisibilityOption::StartHidden,
|
|
InitialVisibilityOption::StartHidden, InitialVisibilityOption::StartHidden,
|
|
InitialVisibilityOption::StartHidden, InitialVisibilityOption::StartHidden,
|
|
InitialVisibilityOption::StartHidden
|
|
};
|
|
|
|
QVector<bool> floatings = { true, false, true, false, false, false, false,
|
|
false, false, false, false, false, true, false,
|
|
false, true, true, true, true, true, false };
|
|
|
|
QVector<QSize> minSizes = { QSize(316, 219), QSize(355, 237), QSize(293, 66), QSize(158, 72),
|
|
QSize(30, 141), QSize(104, 143), QSize(104, 105), QSize(84, 341),
|
|
QSize(130, 130), QSize(404, 205), QSize(296, 177), QSize(914, 474),
|
|
QSize(355, 237), QSize(104, 104), QSize(104, 138), QSize(1061, 272),
|
|
QSize(165, 196), QSize(296, 177), QSize(104, 104), QSize(355, 237),
|
|
QSize(104, 138) };
|
|
|
|
const int num = 21;
|
|
for (int i = 0; i < num; ++i) {
|
|
auto widget = Platform::instance()->tests_createView({ true, {}, minSizes.at(i) });
|
|
auto dw = newDockWidget(QString::number(i));
|
|
dw->setGuestView(widget->asWrapper());
|
|
docks << dw;
|
|
}
|
|
|
|
for (int i = 0; i < num; ++i) {
|
|
m->addDockWidget(docks[i], locations[i], nullptr, options[i]);
|
|
layout->checkSanity();
|
|
docks[i]->setFloating(floatings[i]);
|
|
layout->checkSanity();
|
|
}
|
|
|
|
m->show();
|
|
|
|
// Cleanup
|
|
qDeleteAll(docks);
|
|
qDeleteAll(DockRegistry::self()->groups());
|
|
}
|
|
|
|
|
|
void TestQtWidgets::tst_deleteOnClose()
|
|
{
|
|
// QtQuick doesn't support autohide/pin/sidebar yet.
|
|
// Tests that restoring the side-bar-overlay will call the users dock widget factory in case
|
|
// the dock widget was deleted already
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_AutoHideSupport);
|
|
KDDockWidgets::Config::self().setDockWidgetFactoryFunc([](const QString &name) {
|
|
return createDockWidget(
|
|
name, Platform::instance()->tests_createView({ true, {}, QSize(400, 400) }),
|
|
DockWidgetOption_DeleteOnClose);
|
|
});
|
|
|
|
auto m = createMainWindow(QSize(800, 500), MainWindowOption_None);
|
|
ObjectGuard<Core::DockWidget> dock1 =
|
|
createDockWidget("1", Platform::instance()->tests_createView({ true, {}, QSize(400, 400) }),
|
|
DockWidgetOption_DeleteOnClose);
|
|
m->addDockWidget(dock1, Location_OnLeft);
|
|
m->moveToSideBar(dock1);
|
|
m->overlayOnSideBar(dock1);
|
|
LayoutSaver saver;
|
|
const QByteArray saved = saver.serializeLayout();
|
|
|
|
QVERIFY(dock1->isVisible());
|
|
dock1->close();
|
|
QVERIFY(Platform::instance()->tests_waitForDeleted(dock1));
|
|
QVERIFY(!dock1.data());
|
|
|
|
saver.restoreLayout(saved);
|
|
}
|
|
|
|
void TestQtWidgets::tstCloseNestedMdi()
|
|
{
|
|
// Tests a bug where closing a mdi dock widget would close its main window too
|
|
EnsureTopLevelsDeleted e;
|
|
|
|
auto m = createMainWindow(QSize(1000, 500), MainWindowOption_HasCentralWidget);
|
|
ObjectGuard<Core::MainWindow> p = m.get();
|
|
|
|
auto mdi = new QtWidgets::MDIArea();
|
|
m->setPersistentCentralView(mdi->asWrapper());
|
|
|
|
auto dock1 = new QtWidgets::DockWidget(QStringLiteral("MyDock1"));
|
|
dock1->setWidget(new QPushButton("1"));
|
|
|
|
mdi->addDockWidget(dock1, {});
|
|
|
|
dock1->dockWidget()->titleBar()->onCloseClicked();
|
|
QVERIFY(p);
|
|
QVERIFY(m->isVisible());
|
|
}
|
|
|
|
void TestQtWidgets::tstCloseNestedMDIPropagates()
|
|
{
|
|
auto m = createMainWindow(QSize(1000, 500), MainWindowOption_HasCentralWidget);
|
|
ObjectGuard<Core::MainWindow> p = m.get();
|
|
|
|
auto mdi = new QtWidgets::MDIArea();
|
|
m->setPersistentCentralView(mdi->asWrapper());
|
|
|
|
auto dock1 = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("MyDock1"));
|
|
auto nonClosableWidget = Platform::instance()->tests_createNonClosableView();
|
|
dock1->dockWidget()->setGuestView(nonClosableWidget->asWrapper());
|
|
mdi->addDockWidget(dock1, {});
|
|
|
|
auto dock2 = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("MyDock2"));
|
|
auto nonClosableWidget2 = Platform::instance()->tests_createNonClosableView();
|
|
dock2->dockWidget()->setGuestView(nonClosableWidget2->asWrapper());
|
|
dock2->open();
|
|
|
|
Platform::instance()->tests_waitForEvent(dock1->controller(), QEvent::Show);
|
|
QVERIFY(dock1->isVisible());
|
|
QVERIFY(dock2->isVisible());
|
|
|
|
m->close();
|
|
|
|
QVERIFY(dock2->isVisible());
|
|
QVERIFY(dock1->isVisible());
|
|
}
|
|
|
|
void TestQtWidgets::tst_setAsCurrentTab()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
|
|
// For issue #312, which is QtWidget only. The controller has the correct current index but
|
|
// not the QTabBar.
|
|
auto dw = Config::self().viewFactory()->createDockWidget("dw1")->asDockWidgetController();
|
|
auto dw2 = Config::self().viewFactory()->createDockWidget("dw2")->asDockWidgetController();
|
|
auto dw3 = Config::self().viewFactory()->createDockWidget("dw3")->asDockWidgetController();
|
|
|
|
dw->view()->show();
|
|
dw->addDockWidgetAsTab(dw2);
|
|
dw->addDockWidgetAsTab(dw3);
|
|
|
|
Core::Group *group = dw->d->group();
|
|
auto tabBar = group->tabBar();
|
|
QTabBar *tabBarWidget = qobject_cast<QTabBar *>(QtCommon::View_qt::asQWidget(tabBar->view()));
|
|
|
|
QVERIFY(!dw->isCurrentTab());
|
|
QVERIFY(!dw2->isCurrentTab());
|
|
QVERIFY(dw3->isCurrentTab());
|
|
QCOMPARE(tabBarWidget->currentIndex(), 2);
|
|
|
|
dw->setAsCurrentTab();
|
|
|
|
QVERIFY(dw->isCurrentTab());
|
|
QVERIFY(!dw2->isCurrentTab());
|
|
QVERIFY(!dw3->isCurrentTab());
|
|
|
|
QCOMPARE(group->currentIndex(), 0);
|
|
QCOMPARE(group->currentDockWidget(), dw);
|
|
|
|
QCOMPARE(tabBar->currentIndex(), 0);
|
|
|
|
QCOMPARE(tabBarWidget->currentIndex(), 0);
|
|
}
|
|
|
|
void TestQtWidgets::initTestCase()
|
|
{
|
|
KDDockWidgets::Core::Platform::instance()->installMessageHandler();
|
|
}
|
|
|
|
void TestQtWidgets::cleanupTestCase()
|
|
{
|
|
KDDockWidgets::Core::Platform::instance()->uninstallMessageHandler();
|
|
}
|
|
|
|
void TestQtWidgets::tst_crash326()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
auto m = createMainWindow(QSize(500, 500), MainWindowOption_HasCentralWidget);
|
|
auto dock1 = createDockWidget("1", new QPushButton("1"), {}, {}, false);
|
|
m->addDockWidget(dock1, KDDockWidgets::Location_OnBottom);
|
|
ObjectGuard<Group> originalGroup = dock1->d->group();
|
|
dock1->close();
|
|
QVERIFY(dock1->parent() == nullptr);
|
|
QVERIFY(originalGroup != dock1->d->group());
|
|
QVERIFY(originalGroup->beingDeletedLater());
|
|
|
|
dock1->show();
|
|
QVERIFY(originalGroup != dock1->d->group());
|
|
}
|
|
|
|
void TestQtWidgets::tst_restoreWithIncompleteFactory()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
SetExpectedWarning ignoreWarning("Couldn't find dock widget");
|
|
KDDockWidgets::Config::self().setDockWidgetFactoryFunc([](const QString &name) -> KDDockWidgets::Core::DockWidget * {
|
|
if (name.contains(QStringLiteral("centralDockWidget")))
|
|
return nullptr;
|
|
|
|
auto w = new KDDockWidgets::QtWidgets::DockWidget(name);
|
|
w->setWidget(new QWidget());
|
|
return w->asDockWidgetController();
|
|
});
|
|
|
|
auto m = createMainWindow(QSize(500, 500), MainWindowOption_None, "MainWindow1");
|
|
|
|
LayoutSaver saver;
|
|
saver.restoreFromFile(":/layouts/restoreWithIncompleteFactory.json");
|
|
|
|
auto layout = m->multiSplitter();
|
|
QCOMPARE(layout->separators().size(), 0);
|
|
}
|
|
|
|
void TestQtWidgets::tst_deleteDockWidget()
|
|
{
|
|
// Tests deleting the dock widget directly
|
|
// The layout should readjust
|
|
|
|
EnsureTopLevelsDeleted e;
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = Config::self().viewFactory()->createDockWidget("dw1")->asDockWidgetController();
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
auto dw3 = Config::self().viewFactory()->createDockWidget("dw3")->asDockWidgetController();
|
|
m1->addDockWidget(dw3, Location_OnTop);
|
|
|
|
auto dw2 = Config::self().viewFactory()->createDockWidget("dw2")->asDockWidgetController();
|
|
|
|
m1->addDockWidget(dw2, KDDockWidgets::Location_OnLeft, dw1);
|
|
dw2->setFloating(true);
|
|
|
|
// There's one separator, separating dock 1 from dock 3
|
|
QCOMPARE(m1->multiSplitter()->separators().size(), 1);
|
|
|
|
delete dw1;
|
|
|
|
// Frame is deleted delayed
|
|
QTest::qWait(1000);
|
|
|
|
// Dock3 now occupies everything, separator was deleted
|
|
QVERIFY(m1->multiSplitter()->separators().isEmpty());
|
|
}
|
|
|
|
void TestQtWidgets::tst_findAncestor()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
QVERIFY(KDDockWidgets::findAncestor<QWidget>(nullptr) == nullptr);
|
|
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dw1 = Config::self().viewFactory()->createDockWidget("dw1")->asDockWidgetController();
|
|
m1->addDockWidget(dw1, Location_OnBottom);
|
|
|
|
auto mainWindow = QtCommon::View_qt::asQWidget(m1->view());
|
|
auto dockWidget = QtCommon::View_qt::asQWidget(dw1->view());
|
|
|
|
QCOMPARE(mainWindow, KDDockWidgets::findAncestor<QMainWindow>(mainWindow));
|
|
QCOMPARE(mainWindow, KDDockWidgets::findAncestor<QMainWindow>(dockWidget));
|
|
}
|
|
|
|
void TestQtWidgets::tst_standaloneTitleBar()
|
|
{
|
|
QWidget window;
|
|
|
|
QtWidgets::TitleBar titleBar(&window);
|
|
titleBar.asTitleBarController()->setTitle("some title");
|
|
|
|
auto lay = new QVBoxLayout(&window);
|
|
lay->addWidget(&titleBar);
|
|
lay->addStretch();
|
|
|
|
window.show();
|
|
|
|
QVERIFY(window.isVisible());
|
|
titleBar.asTitleBarController()->onCloseClicked();
|
|
QVERIFY(!window.isVisible());
|
|
}
|
|
|
|
void TestQtWidgets::tst_titleBarTitle()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dock1 = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("MyDock1"));
|
|
m1->addDockWidget(dock1->asDockWidgetController(), Location_OnBottom);
|
|
|
|
auto tb = dock1->actualTitleBar();
|
|
QCOMPARE(dock1->asDockWidgetController()->title(), "MyDock1");
|
|
QCOMPARE(tb->title(), "MyDock1");
|
|
|
|
dock1->setTitle("Other");
|
|
QCOMPARE(tb->title(), "Other");
|
|
}
|
|
|
|
void TestQtWidgets::tst_widgetAddQAction()
|
|
{
|
|
auto dock1 = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("MyDock1"));
|
|
|
|
QWidget w;
|
|
w.addAction(dock1->toggleAction());
|
|
|
|
delete dock1;
|
|
}
|
|
|
|
void TestQtWidgets::tst_currentTabChanged()
|
|
{
|
|
// Tests that QtWidgets::DockWidget::isCurrentTabConnection is emitted
|
|
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dock1 = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("MyDock1"));
|
|
auto dock2 = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("MyDock2"));
|
|
|
|
int count1 = 0;
|
|
int count2 = 0;
|
|
connect(dock1, &QtWidgets::DockWidget::isCurrentTabChanged, [&count1](bool isCurrent) {
|
|
if (isCurrent)
|
|
count1++;
|
|
else
|
|
count1--;
|
|
});
|
|
|
|
connect(dock2, &QtWidgets::DockWidget::isCurrentTabChanged, [&count2](bool isCurrent) {
|
|
if (isCurrent)
|
|
count2++;
|
|
else
|
|
count2--;
|
|
});
|
|
|
|
m1->addDockWidget(dock1->asDockWidgetController(), Location_OnBottom);
|
|
QCOMPARE(count1, 1);
|
|
QCOMPARE(count2, 0);
|
|
|
|
dock1->addDockWidgetAsTab(dock2);
|
|
QCOMPARE(count1, 0);
|
|
QCOMPARE(count2, 1);
|
|
|
|
// already current
|
|
dock2->dockWidget()->setAsCurrentTab();
|
|
QCOMPARE(count1, 0);
|
|
QCOMPARE(count2, 1);
|
|
|
|
dock1->dockWidget()->setAsCurrentTab();
|
|
QCOMPARE(count1, 1);
|
|
QCOMPARE(count2, 0);
|
|
|
|
dock2->dockWidget()->setAsCurrentTab();
|
|
QCOMPARE(count1, 0);
|
|
QCOMPARE(count2, 1);
|
|
}
|
|
|
|
void TestQtWidgets::tst_moveTab_data()
|
|
{
|
|
QTest::addColumn<bool>("moveViaController");
|
|
|
|
QTest::newRow("true") << true;
|
|
QTest::newRow("false") << false;
|
|
}
|
|
|
|
void TestQtWidgets::tst_moveTab()
|
|
{
|
|
QFETCH(bool, moveViaController);
|
|
|
|
EnsureTopLevelsDeleted e;
|
|
Config::self().setFlags(Config::Flag_AllowReorderTabs);
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dockA = Config::self().viewFactory()->createDockWidget("dwA")->asDockWidgetController();
|
|
auto dockB = Config::self().viewFactory()->createDockWidget("dwB")->asDockWidgetController();
|
|
|
|
auto qwidgetA = QtCommon::View_qt::asQWidget(dockA->view());
|
|
auto qwidgetB = QtCommon::View_qt::asQWidget(dockB->view());
|
|
|
|
m1->addDockWidget(dockA, Location_OnBottom);
|
|
dockA->addDockWidgetAsTab(dockB);
|
|
|
|
Core::TabBar *tb = dockA->d->group()->tabBar();
|
|
QVERIFY(tb);
|
|
tb->setCurrentIndex(0);
|
|
QCOMPARE(tb->currentDockWidget(), dockA);
|
|
auto qtabbar = qobject_cast<QTabBar *>(QtCommon::View_qt::asQWidget(tb->view()));
|
|
auto qtabwidget = qobject_cast<QTabWidget *>(QtCommon::View_qt::asQWidget(tb->stack()->view()));
|
|
QVERIFY(qtabbar);
|
|
QVERIFY(qtabwidget);
|
|
QCOMPARE(qtabbar->currentIndex(), 0);
|
|
QCOMPARE(qtabwidget->currentIndex(), 0);
|
|
QCOMPARE(qtabwidget->widget(0), qwidgetA);
|
|
QCOMPARE(qtabwidget->widget(1), qwidgetB);
|
|
|
|
if (moveViaController) {
|
|
tb->moveTabTo(0, 1);
|
|
} else {
|
|
qtabbar->moveTab(0, 1);
|
|
}
|
|
|
|
QCOMPARE(qtabbar->currentIndex(), 1);
|
|
QCOMPARE(qtabwidget->widget(0), qwidgetB);
|
|
QCOMPARE(qtabwidget->widget(1), qwidgetA);
|
|
|
|
QCOMPARE(tb->currentIndex(), 1);
|
|
QCOMPARE(tb->currentDockWidget(), dockA);
|
|
}
|
|
|
|
void TestQtWidgets::tst_nestedMainWindowSaveRestore_data()
|
|
{
|
|
QTest::addColumn<bool>("nestFurther");
|
|
|
|
QTest::newRow("true") << true; // parented to DockWidget
|
|
QTest::newRow("false") << false; // parented to intermediate container
|
|
}
|
|
|
|
void TestQtWidgets::tst_nestedMainWindowSaveRestore()
|
|
{
|
|
// This is for #508 . Do not change this configuration.
|
|
// tests that a save/restore of tabbed nested main windows does not
|
|
// hide the main window
|
|
|
|
|
|
QFETCH(bool, nestFurther);
|
|
EnsureTopLevelsDeleted e;
|
|
|
|
auto mainWindow = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto nestedMainWindow1 = createMainWindow(QSize(500, 500), MainWindowOption_None, "MW1.1");
|
|
nestedMainWindow1->setAffinities({ "foo1" });
|
|
auto nestedMainWindow2 = createMainWindow(QSize(500, 500), MainWindowOption_None, "MW1.2");
|
|
nestedMainWindow2->setAffinities({ "foo2" });
|
|
|
|
auto containerDock1 = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("Nested MainWindow Dock container1"));
|
|
auto containerDock2 = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("Nested MainWindow Dock container2"));
|
|
auto nestedMainWindowQWidget1 = static_cast<QMainWindow *>(QtCommon::View_qt::asQWidget(nestedMainWindow1->view()));
|
|
auto nestedMainWindowQWidget2 = static_cast<QMainWindow *>(QtCommon::View_qt::asQWidget(nestedMainWindow2->view()));
|
|
|
|
|
|
if (nestFurther) {
|
|
auto container1 = new QWidget();
|
|
auto container2 = new QWidget();
|
|
auto lay1 = new QVBoxLayout(container1);
|
|
auto lay2 = new QVBoxLayout(container2);
|
|
lay1->addWidget(nestedMainWindowQWidget1);
|
|
lay2->addWidget(nestedMainWindowQWidget2);
|
|
|
|
containerDock1->setWidget(container1);
|
|
containerDock2->setWidget(container2);
|
|
} else {
|
|
containerDock1->setWidget(nestedMainWindowQWidget1);
|
|
containerDock2->setWidget(nestedMainWindowQWidget2);
|
|
}
|
|
|
|
mainWindow->addDockWidget(containerDock1->asDockWidgetController(), KDDockWidgets::Location_OnRight);
|
|
mainWindow->addDockWidget(containerDock2->asDockWidgetController(), KDDockWidgets::Location_OnRight);
|
|
|
|
containerDock1->addDockWidgetAsTab(containerDock2);
|
|
containerDock1->setAsCurrentTab();
|
|
|
|
LayoutSaver saver;
|
|
QVERIFY(saver.restoreLayout(saver.serializeLayout()));
|
|
QVERIFY(mainWindow->isVisible());
|
|
}
|
|
|
|
void TestQtWidgets::tst_nestedMainWindowFloatButton()
|
|
{
|
|
// Bug 1 reported in #464:
|
|
// Dockwidget, inside MainWindow inside MainWindow.
|
|
// Float inner main window
|
|
// DockWidget's float button stops working
|
|
EnsureTopLevelsDeleted e;
|
|
auto mainWindow = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto nestedMainWindow = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW2");
|
|
mainWindow->setObjectName("root main window");
|
|
|
|
auto containerDock = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("Nested MainWindow Dock container"));
|
|
auto nestedMainWindowQWidget = static_cast<QMainWindow *>(QtCommon::View_qt::asQWidget(nestedMainWindow->view()));
|
|
containerDock->setWidget(nestedMainWindowQWidget);
|
|
mainWindow->addDockWidget(containerDock->asDockWidgetController(), Location_OnBottom);
|
|
|
|
auto nestedDock = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("Nested Dock"));
|
|
nestedMainWindow->addDockWidget(nestedDock->asDockWidgetController(), Location_OnBottom);
|
|
nestedMainWindowQWidget->menuBar()->addMenu("Inner menu");
|
|
nestedMainWindowQWidget->setObjectName("nested main window");
|
|
|
|
QVERIFY(!containerDock->isFloating());
|
|
QVERIFY(!nestedDock->isFloating());
|
|
QVERIFY(containerDock->dockWidget()->isInMainWindow());
|
|
QVERIFY(nestedDock->dockWidget()->isInMainWindow());
|
|
|
|
containerDock->setFloating(true);
|
|
|
|
QVERIFY(containerDock->isFloating());
|
|
QVERIFY(!nestedDock->isFloating());
|
|
QVERIFY(!containerDock->dockWidget()->isInMainWindow());
|
|
QVERIFY(nestedDock->dockWidget()->isInMainWindow());
|
|
}
|
|
|
|
void TestQtWidgets::tst_nestedMainWindowToggle()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
auto mainWindow = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto nestedMainWindow = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW2");
|
|
mainWindow->setObjectName("root main window");
|
|
|
|
auto dock1 = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("Nested MainWindow Dock container"));
|
|
auto nestedMainWindowQWidget = static_cast<QMainWindow *>(QtCommon::View_qt::asQWidget(nestedMainWindow->view()));
|
|
dock1->setWidget(nestedMainWindowQWidget);
|
|
mainWindow->addDockWidget(dock1->asDockWidgetController(), Location_OnBottom);
|
|
|
|
auto nestedDock = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("Nested Dock"));
|
|
nestedMainWindow->addDockWidget(nestedDock->asDockWidgetController(), Location_OnBottom);
|
|
nestedMainWindowQWidget->menuBar()->addMenu("Just a visual cue, to notice the nesting");
|
|
nestedMainWindowQWidget->setObjectName("nested main window");
|
|
QPointer<QObject> guard = nestedMainWindowQWidget;
|
|
|
|
// Close dock1:
|
|
QVERIFY(dock1->isOpen());
|
|
QVERIFY(nestedDock->isOpen());
|
|
|
|
dock1->close();
|
|
QVERIFY(guard); // For some reason nested main window was being deleted
|
|
QVERIFY(!dock1->isOpen());
|
|
QVERIFY(!nestedDock->isOpen());
|
|
|
|
// Reopen dock1, the nested dockwidgets should also reopen
|
|
|
|
dock1->open();
|
|
|
|
QVERIFY(guard);
|
|
QVERIFY(dock1->isOpen());
|
|
QVERIFY(dock1->isVisible());
|
|
QVERIFY(nestedMainWindowQWidget->isVisible());
|
|
|
|
QEXPECT_FAIL("", "Bug #360, to be fixed", Continue);
|
|
QVERIFY(nestedDock->isOpen());
|
|
}
|
|
|
|
void TestQtWidgets::tstQGraphicsProxyWidget()
|
|
{
|
|
// Tests that using a QGraphicsProxyWidget doesn't crash
|
|
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "MW1");
|
|
auto dock1 = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("MyDock1"));
|
|
m1->addDockWidget(dock1->asDockWidgetController(), Location_OnBottom);
|
|
|
|
auto qgv = new QGraphicsView();
|
|
dock1->setWidget(qgv);
|
|
qgv->setVisible(true);
|
|
|
|
auto scene = new QGraphicsScene();
|
|
qgv->setScene(scene);
|
|
|
|
auto lineEdit = new QLineEdit();
|
|
auto proxyWidget = new QGraphicsProxyWidget();
|
|
proxyWidget->setWidget(lineEdit);
|
|
lineEdit->setText("Test");
|
|
|
|
QVERIFY(lineEdit->graphicsProxyWidget());
|
|
QVERIFY(lineEdit->isWindow());
|
|
|
|
scene->addItem(proxyWidget);
|
|
}
|
|
|
|
void TestQtWidgets::tst_focusBetweenTabs()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_TitleBarIsFocusable);
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_None, "mw1");
|
|
|
|
auto floatingDock = new QtWidgets::DockWidget(QStringLiteral("floatingDock"));
|
|
auto leFloating = new QLineEdit("floating");
|
|
floatingDock->setWidget(leFloating);
|
|
floatingDock->show();
|
|
|
|
auto dock1 = new QtWidgets::DockWidget(QStringLiteral("MyDock1"));
|
|
auto le1 = new QLineEdit("text1");
|
|
dock1->setWidget(le1);
|
|
|
|
auto dock2 = new QtWidgets::DockWidget(QStringLiteral("MyDock2"));
|
|
auto le2 = new QLineEdit("text2");
|
|
dock2->setWidget(le2);
|
|
|
|
auto dock3 = new QtWidgets::DockWidget(QStringLiteral("MyDock3"));
|
|
auto le3 = new QLineEdit("text3");
|
|
dock3->setWidget(le3);
|
|
|
|
m1->addDockWidget(dock1->asDockWidgetController(), Location_OnLeft);
|
|
m1->addDockWidget(dock2->asDockWidgetController(), Location_OnRight);
|
|
dock2->addDockWidgetAsTab(dock3);
|
|
|
|
// 1. Setup: Give focus to le2 and le3, just so our focus scope remembers they were focused.
|
|
le1->setFocus();
|
|
leFloating->setFocus();
|
|
QVERIFY(dock3->dockWidget()->isCurrentTab());
|
|
m1->view()->activateWindow();
|
|
EVENT_LOOP(1);
|
|
le3->setFocus();
|
|
|
|
QVERIFY(le3->hasFocus());
|
|
dock2->setAsCurrentTab();
|
|
QVERIFY(dock2->dockWidget()->isCurrentTab());
|
|
le2->setFocus();
|
|
EVENT_LOOP(1);
|
|
QVERIFY(le2->hasFocus());
|
|
|
|
// 2. Now, cycling tabs should toggle focus between le2 and le3
|
|
dock3->setAsCurrentTab();
|
|
QVERIFY(le3->hasFocus());
|
|
QVERIFY(!le2->hasFocus());
|
|
|
|
dock2->setAsCurrentTab();
|
|
QVERIFY(le2->hasFocus());
|
|
QVERIFY(!le3->hasFocus());
|
|
|
|
// 3. Check that focusing titlebar focuses the previous focused line edit as well
|
|
auto titlebar1 = dock1->actualTitleBar()->view();
|
|
titlebar1->setFocus(Qt::MouseFocusReason);
|
|
QVERIFY(le1->hasFocus());
|
|
QVERIFY(!le2->hasFocus());
|
|
QVERIFY(!le3->hasFocus());
|
|
|
|
// 4. Test with a floating window as well
|
|
floatingDock->rootView()->activateWindow();
|
|
QVERIFY(Platform::instance()->tests_waitForWindowActive(floatingDock->window(), 1000));
|
|
QVERIFY(floatingDock->window()->isActive());
|
|
auto titlebarFloating = floatingDock->actualTitleBar()->view();
|
|
QVERIFY(titlebarFloating->isVisible());
|
|
titlebarFloating->setFocus(Qt::MouseFocusReason);
|
|
EVENT_LOOP(1000);
|
|
|
|
QVERIFY(leFloating->hasFocus());
|
|
QVERIFY(!le1->hasFocus());
|
|
QVERIFY(!le2->hasFocus());
|
|
QVERIFY(!le3->hasFocus());
|
|
}
|
|
|
|
void TestQtWidgets::addDockWidgetToSide()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
KDDockWidgets::Config::self().setFlags(KDDockWidgets::Config::Flag_TitleBarIsFocusable);
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_HasCentralGroup, "mw1");
|
|
|
|
auto d1 = new QtWidgets::DockWidget("d1");
|
|
auto d2 = new QtWidgets::DockWidget("d2");
|
|
auto d3 = new QtWidgets::DockWidget("d3");
|
|
auto d4 = new QtWidgets::DockWidget("d4");
|
|
auto dTop = new QtWidgets::DockWidget("dTop");
|
|
auto dTop2 = new QtWidgets::DockWidget("dTop2");
|
|
QVERIFY(!d1->isOpen());
|
|
QVERIFY(!d1->toggleAction()->isChecked());
|
|
m1->addDockWidgetToSide(d1->asDockWidgetController(), KDDockWidgets::Location_OnLeft);
|
|
QVERIFY(d1->isOpen());
|
|
QVERIFY(d1->toggleAction()->isChecked());
|
|
m1->addDockWidgetToSide(d2->asDockWidgetController(), KDDockWidgets::Location_OnLeft);
|
|
m1->addDockWidgetToSide(d3->asDockWidgetController(), KDDockWidgets::Location_OnRight);
|
|
m1->addDockWidgetToSide(dTop->asDockWidgetController(), KDDockWidgets::Location_OnTop);
|
|
m1->addDockWidgetToSide(dTop2->asDockWidgetController(), KDDockWidgets::Location_OnTop);
|
|
m1->addDockWidgetToSide(d4->asDockWidgetController(), KDDockWidgets::Location_OnRight);
|
|
|
|
auto root = m1->layout()->rootItem()->asBoxContainer();
|
|
QVERIFY(root->isVertical());
|
|
|
|
auto topContainer = root->childItems()[0]->asBoxContainer();
|
|
QVERIFY(!topContainer->isVertical());
|
|
QCOMPARE(topContainer->numChildren(), 2);
|
|
|
|
QCOMPARE(Group::fromItem(topContainer->childItems()[0])->objectName(), "dTop");
|
|
QCOMPARE(Group::fromItem(topContainer->childItems()[1])->objectName(), "dTop2");
|
|
|
|
auto bottomContainer = root->childItems()[1]->asBoxContainer();
|
|
QVERIFY(!bottomContainer->isVertical());
|
|
QCOMPARE(bottomContainer->numChildren(), 3);
|
|
|
|
auto leftContainer = bottomContainer->childItems()[0]->asBoxContainer();
|
|
auto rightContainer = bottomContainer->childItems()[2]->asBoxContainer();
|
|
QVERIFY(leftContainer->isVertical());
|
|
QVERIFY(rightContainer->isVertical());
|
|
QCOMPARE(leftContainer->numChildren(), 2);
|
|
QCOMPARE(rightContainer->numChildren(), 2);
|
|
|
|
QCOMPARE(Group::fromItem(leftContainer->childItems()[0])->objectName(), "d1");
|
|
QCOMPARE(Group::fromItem(leftContainer->childItems()[1])->objectName(), "d2");
|
|
QCOMPARE(Group::fromItem(rightContainer->childItems()[0])->objectName(), "d3");
|
|
QCOMPARE(Group::fromItem(rightContainer->childItems()[1])->objectName(), "d4");
|
|
}
|
|
|
|
void TestQtWidgets::addDockWidgetToSide2()
|
|
{
|
|
// Tests adding relative to a StartHidden
|
|
|
|
EnsureTopLevelsDeleted e;
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_HasCentralGroup, "mw1");
|
|
|
|
auto d1 = new QtWidgets::DockWidget("d1");
|
|
auto d2 = new QtWidgets::DockWidget("d2");
|
|
|
|
QVERIFY(!d1->isOpen());
|
|
QVERIFY(!d1->toggleAction()->isChecked());
|
|
m1->addDockWidgetToSide(d1->asDockWidgetController(), KDDockWidgets::Location_OnRight, InitialVisibilityOption::StartHidden);
|
|
QVERIFY(!d1->isOpen());
|
|
QVERIFY(!d1->toggleAction()->isChecked());
|
|
|
|
m1->addDockWidgetToSide(d2->asDockWidgetController(), KDDockWidgets::Location_OnRight);
|
|
|
|
d1->show();
|
|
|
|
auto root = m1->layout()->rootItem()->asBoxContainer();
|
|
QVERIFY(root->isHorizontal());
|
|
QCOMPARE(root->numChildren(), 2);
|
|
}
|
|
|
|
void TestQtWidgets::addDockWidgetToSide3()
|
|
{
|
|
// Tests adding relative to a StartHidden but the new one is also hidden
|
|
EnsureTopLevelsDeleted e;
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_HasCentralGroup, "mw1");
|
|
|
|
auto d1 = new QtWidgets::DockWidget("d1");
|
|
auto d2 = new QtWidgets::DockWidget("d2");
|
|
m1->addDockWidgetToSide(d1->asDockWidgetController(), KDDockWidgets::Location_OnRight, InitialVisibilityOption::StartHidden);
|
|
m1->addDockWidgetToSide(d2->asDockWidgetController(), KDDockWidgets::Location_OnRight, InitialVisibilityOption::StartHidden);
|
|
|
|
auto root = m1->layout()->rootItem()->asBoxContainer();
|
|
QVERIFY(root->isHorizontal());
|
|
QCOMPARE(root->numChildren(), 2);
|
|
|
|
d1->show();
|
|
d2->show();
|
|
|
|
auto inner = root->childItems()[1]->asBoxContainer();
|
|
QVERIFY(inner);
|
|
QVERIFY(inner->isVertical());
|
|
QCOMPARE(inner->numChildren(), 2);
|
|
QCOMPARE(inner->numVisibleChildren(), 2);
|
|
}
|
|
|
|
void TestQtWidgets::addDockWidgetToSide4()
|
|
{
|
|
// Tests a case where generated layout would be off by a few pixels
|
|
EnsureTopLevelsDeleted e;
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_HasCentralGroup, "mw1");
|
|
|
|
auto dummy1 = new QtWidgets::DockWidget("dummy1");
|
|
auto dummy2 = new QtWidgets::DockWidget("dummy2");
|
|
m1->addDockWidget(dummy1->asDockWidgetController(), KDDockWidgets::Location_OnRight, nullptr, InitialVisibilityOption::StartHidden);
|
|
m1->addDockWidget(dummy2->asDockWidgetController(), KDDockWidgets::Location_OnLeft, nullptr, InitialVisibilityOption::StartHidden);
|
|
|
|
auto leftVisible = new QtWidgets::DockWidget("leftVisible");
|
|
auto leftHidden = new QtWidgets::DockWidget("leftHidden");
|
|
auto bottomHidden = new QtWidgets::DockWidget("bottomHidden");
|
|
auto rightVisible = new QtWidgets::DockWidget("rightVisible");
|
|
auto leftVisible2 = new QtWidgets::DockWidget("leftVisible2");
|
|
auto bottomHidden2 = new QtWidgets::DockWidget("bottomHidden2");
|
|
auto rightHidden = new QtWidgets::DockWidget("rightHidden");
|
|
auto rightHidden2 = new QtWidgets::DockWidget("rightHidden2");
|
|
|
|
m1->addDockWidgetToSide(leftVisible->asDockWidgetController(), KDDockWidgets::Location_OnLeft);
|
|
m1->addDockWidgetToSide(leftHidden->asDockWidgetController(), KDDockWidgets::Location_OnLeft, InitialVisibilityOption::StartHidden);
|
|
m1->addDockWidgetToSide(bottomHidden->asDockWidgetController(), KDDockWidgets::Location_OnBottom, InitialVisibilityOption::StartHidden);
|
|
|
|
m1->addDockWidgetToSide(leftVisible2->asDockWidgetController(), KDDockWidgets::Location_OnLeft);
|
|
|
|
m1->addDockWidgetToSide(bottomHidden2->asDockWidgetController(), KDDockWidgets::Location_OnBottom, InitialVisibilityOption::StartHidden);
|
|
m1->addDockWidgetToSide(rightHidden->asDockWidgetController(), KDDockWidgets::Location_OnRight, InitialVisibilityOption::StartHidden);
|
|
m1->addDockWidgetToSide(rightHidden2->asDockWidgetController(), KDDockWidgets::Location_OnRight, InitialVisibilityOption::StartHidden);
|
|
|
|
leftVisible->open();
|
|
|
|
QVERIFY(m1->layout()->checkSanity());
|
|
m1->addDockWidgetToSide(rightVisible->asDockWidgetController(), KDDockWidgets::Location_OnRight);
|
|
QVERIFY(m1->layout()->checkSanity());
|
|
}
|
|
|
|
void TestQtWidgets::addDockWidgetToSide5()
|
|
{
|
|
// Tests a case where generated layout would be off by a few pixels
|
|
EnsureTopLevelsDeleted e;
|
|
auto m1 = createMainWindow(QSize(1002, 1002), MainWindowOption_HasCentralGroup, "mw1");
|
|
|
|
auto rightVisible = new QtWidgets::DockWidget("rightVisible");
|
|
auto rightHidden = new QtWidgets::DockWidget("rightHidden");
|
|
auto rightHidden2 = new QtWidgets::DockWidget("rightHidden2");
|
|
|
|
m1->addDockWidgetToSide(rightHidden->asDockWidgetController(), KDDockWidgets::Location_OnRight, InitialVisibilityOption::StartHidden);
|
|
m1->addDockWidgetToSide(rightHidden2->asDockWidgetController(), KDDockWidgets::Location_OnRight, InitialVisibilityOption::StartHidden);
|
|
|
|
QVERIFY(m1->layout()->checkSanity());
|
|
m1->addDockWidgetToSide(rightVisible->asDockWidgetController(), KDDockWidgets::Location_OnRight);
|
|
QVERIFY(m1->layout()->checkSanity());
|
|
}
|
|
|
|
void TestQtWidgets::addDockWidgetToSideCrash()
|
|
{
|
|
// There used to be a crash when adding this layout setup.
|
|
// This test just ensures it doesn't regress
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_HasCentralGroup, "mw1");
|
|
|
|
auto bottom1 = new QtWidgets::DockWidget("bottom1");
|
|
auto left1 = new QtWidgets::DockWidget("left1");
|
|
auto bottom2 = new QtWidgets::DockWidget("bottom2");
|
|
auto right1 = new QtWidgets::DockWidget("right1");
|
|
|
|
m1->addDockWidgetToSide(bottom1->asDockWidgetController(), KDDockWidgets::Location_OnBottom, InitialVisibilityOption::StartHidden);
|
|
m1->addDockWidgetToSide(left1->asDockWidgetController(), KDDockWidgets::Location_OnLeft);
|
|
m1->addDockWidgetToSide(bottom2->asDockWidgetController(), KDDockWidgets::Location_OnBottom, InitialVisibilityOption::StartHidden);
|
|
|
|
QVERIFY(m1->layout()->checkSanity());
|
|
bottom1->open();
|
|
bottom2->open();
|
|
QVERIFY(m1->layout()->checkSanity());
|
|
|
|
auto centralGroup = m1->dropArea()->centralGroup();
|
|
auto centralItem = centralGroup->layoutItem();
|
|
Core::Item *neighbor = centralItem->outermostNeighbor(KDDockWidgets::Location_OnRight, /*visibleOnly=*/false);
|
|
QVERIFY(!neighbor);
|
|
|
|
m1->addDockWidgetToSide(right1->asDockWidgetController(), KDDockWidgets::Location_OnRight);
|
|
}
|
|
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_HasCentralGroup, "mw1");
|
|
|
|
auto dummy1 = new QtWidgets::DockWidget("dummy1");
|
|
auto dummy2 = new QtWidgets::DockWidget("dummy2");
|
|
|
|
auto left1 = new QtWidgets::DockWidget("left1");
|
|
auto bottom1 = new QtWidgets::DockWidget("bottom1");
|
|
auto left2 = new QtWidgets::DockWidget("left2");
|
|
|
|
m1->addDockWidgetToSide(dummy1->asDockWidgetController(), KDDockWidgets::Location_OnLeft, InitialVisibilityOption::StartHidden);
|
|
m1->addDockWidgetToSide(dummy2->asDockWidgetController(), KDDockWidgets::Location_OnRight, InitialVisibilityOption::StartHidden);
|
|
m1->addDockWidgetToSide(left1->asDockWidgetController(), KDDockWidgets::Location_OnLeft, InitialVisibilityOption::StartHidden);
|
|
m1->addDockWidgetToSide(bottom1->asDockWidgetController(), KDDockWidgets::Location_OnBottom, InitialVisibilityOption::StartHidden);
|
|
m1->addDockWidgetToSide(left2->asDockWidgetController(), KDDockWidgets::Location_OnLeft, InitialVisibilityOption::StartVisible);
|
|
}
|
|
}
|
|
|
|
void TestQtWidgets::userHiddenButton()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
auto d1 = new QtWidgets::DockWidget("d1");
|
|
d1->show();
|
|
auto tb = d1->actualTitleBar();
|
|
auto tbWidget = QtCommon::View_qt::asQWidget(tb->view());
|
|
auto buttons = tbWidget->findChildren<QAbstractButton *>();
|
|
QCOMPARE(buttons.size(), 5);
|
|
|
|
const auto numVisible = std::count_if(buttons.cbegin(), buttons.cend(), [](auto button) {
|
|
return button->isVisible();
|
|
});
|
|
|
|
QCOMPARE(numVisible, 2);
|
|
|
|
// Hide float and close:
|
|
tb->setUserHiddenButtons(TitleBarButtonTypes(TitleBarButtonType::Close) | TitleBarButtonType::Float);
|
|
|
|
// 0 visible buttons now:
|
|
QCOMPARE(std::count_if(buttons.cbegin(), buttons.cend(), [](auto button) {
|
|
return button->isVisible();
|
|
}),
|
|
0);
|
|
}
|
|
|
|
void TestQtWidgets::tst_tabAsCentralWidget()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
auto m = createMainWindow(QSize(600, 600), MainWindowOption_HasCentralWidget);
|
|
auto tabWidget = new QTabWidget();
|
|
auto tab1 = new QWidget();
|
|
auto tab2 = new QWidget();
|
|
tabWidget->addTab(tab1, "tab1");
|
|
tabWidget->addTab(tab2, "tab2");
|
|
|
|
m->setPersistentCentralView(QtWidgets::ViewWrapper::create(tabWidget));
|
|
|
|
auto d1 = new QtWidgets::DockWidget("d1");
|
|
auto d2 = new QtWidgets::DockWidget("d2");
|
|
auto d3 = new QtWidgets::DockWidget("d3");
|
|
m->addDockWidget(d1->dockWidget(), KDDockWidgets::Location_OnRight);
|
|
m->addDockWidget(d2->dockWidget(), KDDockWidgets::Location_OnRight);
|
|
m->addDockWidget(d3->dockWidget(), KDDockWidgets::Location_OnRight);
|
|
}
|
|
|
|
void TestQtWidgets::tst_nonClosable()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
auto d1 = NonClosableDockWidget("d1");
|
|
d1.open();
|
|
QVERIFY(d1.isOpen());
|
|
d1.close();
|
|
QVERIFY(d1.isOpen());
|
|
d1.forceClose();
|
|
QVERIFY(!d1.isOpen());
|
|
}
|
|
|
|
void TestQtWidgets::tst_crashDuringRestore()
|
|
{
|
|
// Contrived case where if dockWidget->open() was called during restore it would crash
|
|
|
|
EnsureTopLevelsDeleted e;
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_HasCentralGroup, "mw1");
|
|
auto d1 = new QtWidgets::DockWidget("d1");
|
|
auto d3 = new QtWidgets::DockWidget("d3");
|
|
m1->addDockWidget(d1->asDockWidgetController(), Location_OnRight);
|
|
d1->addDockWidgetAsTab(d3);
|
|
|
|
connect(d3->toggleAction(), &QAction::toggled, this, [d3](bool) {
|
|
d3->open();
|
|
});
|
|
|
|
LayoutSaver saver;
|
|
const QByteArray saved = saver.serializeLayout();
|
|
|
|
saver.restoreLayout(saved);
|
|
}
|
|
|
|
void TestQtWidgets::tst_toggleVsShowHidden()
|
|
{
|
|
// Tests that the QAction doesn't fire when adding as hidden
|
|
EnsureTopLevelsDeleted e;
|
|
auto m1 = createMainWindow(QSize(1000, 1000), MainWindowOption_HasCentralGroup, "mw1");
|
|
auto d1 = new QtWidgets::DockWidget("d1");
|
|
QVERIFY(!d1->toggleAction()->isChecked());
|
|
QVERIFY(!d1->isOpen());
|
|
int count = 0;
|
|
connect(d1->toggleAction(), &QAction::toggled, this, [&count](bool) {
|
|
count++;
|
|
});
|
|
|
|
m1->addDockWidget(d1->asDockWidgetController(), Location_OnRight, nullptr, KDDockWidgets::InitialVisibilityOption::StartHidden);
|
|
QVERIFY(!d1->toggleAction()->isChecked());
|
|
QVERIFY(!d1->isOpen());
|
|
|
|
QCOMPARE(count, 0);
|
|
}
|
|
|
|
void TestQtWidgets::tst_neighbourSqueezeStrategy()
|
|
{
|
|
// Tests NeighbourSqueezeStrategy::ImmediateNeighboursFirst
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
InitialOption::s_defaultNeighbourSqueezeStrategy = NeighbourSqueezeStrategy::ImmediateNeighboursFirst;
|
|
auto m1 = createMainWindow(QSize(1000, 500), {}, "mw1");
|
|
|
|
auto d1 = new QtWidgets::DockWidget("d1");
|
|
auto d2 = new QtWidgets::DockWidget("d2");
|
|
auto d3 = new QtWidgets::DockWidget("d3");
|
|
auto d4 = new QtWidgets::DockWidget("d4");
|
|
|
|
m1->addDockWidget(d1->dockWidget(), KDDockWidgets::Location_OnRight);
|
|
m1->addDockWidget(d2->dockWidget(), KDDockWidgets::Location_OnRight);
|
|
m1->addDockWidget(d3->dockWidget(), KDDockWidgets::Location_OnBottom);
|
|
InitialOption opt = QSize(100, 0);
|
|
opt.visibility = InitialVisibilityOption::StartHidden;
|
|
m1->addDockWidget(d4->dockWidget(), KDDockWidgets::Location_OnRight, d2->dockWidget(), opt);
|
|
m1->layoutEqually();
|
|
|
|
auto group1 = d1->dockWidget()->dptr()->group();
|
|
const auto sz1 = group1->size();
|
|
d4->open();
|
|
QCOMPARE(sz1, group1->size());
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
|
|
class Stack464 : public QtWidgets::Stack
|
|
{
|
|
public:
|
|
using QtWidgets::Stack::Stack;
|
|
void init() override
|
|
{
|
|
m_stack->setHideDisabledButtons(TitleBarButtonType::Close);
|
|
|
|
QtWidgets::Stack::init(); // important
|
|
}
|
|
};
|
|
|
|
class ViewFactory464 : public QtWidgets::ViewFactory
|
|
{
|
|
public:
|
|
Core::View *createStack(Core::Stack *controller, Core::View *parent) const override
|
|
{
|
|
return new Stack464(controller, QtCommon::View_qt::asQWidget(parent));
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
void TestQtWidgets::tst_debugWidgetViewer()
|
|
{
|
|
// Tests that DebugWidgetViewer builds and can be created destroyed
|
|
// not worth doing fancy tests as it's a debugging aid
|
|
DebugWidgetViewer viewer;
|
|
}
|
|
|
|
void TestQtWidgets::tst_addDockWidgetToContainingWindowNested()
|
|
{
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
|
|
auto m1 = createMainWindow(QSize(1000, 500), {}, "mw1");
|
|
auto d1 = new QtWidgets::DockWidget("d1");
|
|
auto d2 = new QtWidgets::DockWidget("d2");
|
|
|
|
m1->addDockWidget(d1->dockWidget(), Location_OnRight);
|
|
d1->dockWidget()->addDockWidgetToContainingWindow(d2->dockWidget(), KDDockWidgets::Location_OnLeft);
|
|
|
|
QVERIFY(d1->dockWidget()->isInMainWindow());
|
|
QVERIFY(d2->dockWidget()->isInMainWindow());
|
|
}
|
|
|
|
{
|
|
// Tests using addDockWidgetToContainingWindow when dock is nested
|
|
EnsureTopLevelsDeleted e;
|
|
|
|
auto m1 = createMainWindow(QSize(1000, 500), {}, "mw1");
|
|
auto nestedMainWindow = createMainWindow(QSize(1000, 500), {}, "mw2");
|
|
|
|
auto d1 = new KDDockWidgets::QtWidgets::DockWidget(QStringLiteral("Nested MainWindow Dock container"));
|
|
auto nestedMainWindowQWidget = static_cast<QMainWindow *>(QtCommon::View_qt::asQWidget(nestedMainWindow->view()));
|
|
d1->setWidget(nestedMainWindowQWidget);
|
|
m1->addDockWidget(d1->asDockWidgetController(), Location_OnBottom);
|
|
|
|
auto d2 = new QtWidgets::DockWidget("d2");
|
|
nestedMainWindow->addDockWidget(d2->dockWidget(), Location_OnRight);
|
|
|
|
auto d3 = new QtWidgets::DockWidget("d3");
|
|
d2->dockWidget()->addDockWidgetToContainingWindow(d3->dockWidget(), Location_OnRight);
|
|
|
|
QVERIFY(d1->dockWidget()->isInMainWindow());
|
|
QVERIFY(d2->dockWidget()->isInMainWindow());
|
|
QVERIFY(d3->dockWidget()->isInMainWindow());
|
|
|
|
QCOMPARE(d1->dockWidget()->mainWindow(), m1.get());
|
|
QCOMPARE(d2->dockWidget()->mainWindow(), nestedMainWindow.get());
|
|
QCOMPARE(d3->dockWidget()->mainWindow(), nestedMainWindow.get());
|
|
}
|
|
}
|
|
|
|
void TestQtWidgets::tst_tabBarIcons()
|
|
{
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
auto &config = Config::self();
|
|
config.setFlags(config.flags()
|
|
| KDDockWidgets::Config::Flag_HideTitleBarWhenTabsVisible
|
|
| KDDockWidgets::Config::Flag_TabsHaveCloseButton
|
|
| KDDockWidgets::Config::Flag_CloseOnlyCurrentTab
|
|
| KDDockWidgets::Config::Flag_ShowButtonsOnTabBarIfTitleBarHidden);
|
|
|
|
auto d1 = new QtWidgets::DockWidget("d1", KDDockWidgets::DockWidgetOption_NotClosable);
|
|
auto d2 = new QtWidgets::DockWidget("d2", KDDockWidgets::DockWidgetOption_NotClosable);
|
|
|
|
d1->addDockWidgetAsTab(d2);
|
|
|
|
auto stack = d1->dockWidget()->dptr()->group()->stack();
|
|
auto tabWidget = qobject_cast<QtWidgets::Stack *>(QtCommon::View_qt::asQWidget(stack->view()));
|
|
QVERIFY(tabWidget);
|
|
|
|
auto closeButton = tabWidget->button(TitleBarButtonType::Close);
|
|
QVERIFY(closeButton);
|
|
QVERIFY(closeButton->isVisible());
|
|
QVERIFY(!closeButton->isEnabled());
|
|
}
|
|
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
auto &config = Config::self();
|
|
config.setFlags(config.flags()
|
|
| KDDockWidgets::Config::Flag_HideTitleBarWhenTabsVisible
|
|
| KDDockWidgets::Config::Flag_TabsHaveCloseButton
|
|
| KDDockWidgets::Config::Flag_CloseOnlyCurrentTab
|
|
| KDDockWidgets::Config::Flag_ShowButtonsOnTabBarIfTitleBarHidden);
|
|
config.setViewFactory(new ViewFactory464());
|
|
|
|
auto d1 = new QtWidgets::DockWidget("d1", KDDockWidgets::DockWidgetOption_NotClosable);
|
|
auto d2 = new QtWidgets::DockWidget("d2", KDDockWidgets::DockWidgetOption_NotClosable);
|
|
|
|
d1->addDockWidgetAsTab(d2);
|
|
|
|
auto stack = d1->dockWidget()->dptr()->group()->stack();
|
|
auto tabWidget = qobject_cast<QtWidgets::Stack *>(QtCommon::View_qt::asQWidget(stack->view()));
|
|
QVERIFY(tabWidget);
|
|
|
|
auto closeButton = tabWidget->button(TitleBarButtonType::Close);
|
|
QVERIFY(closeButton);
|
|
QVERIFY(!closeButton->isVisible());
|
|
QVERIFY(!closeButton->isEnabled());
|
|
}
|
|
}
|
|
|
|
void TestQtWidgets::tst_indicatorsNotShowing()
|
|
{
|
|
// Tests bug #474, where wrong top level window is detected under cursor
|
|
EnsureTopLevelsDeleted e;
|
|
const Point globalPos = { 600, 300 };
|
|
QCursor::setPos(globalPos);
|
|
|
|
auto m1 = createMainWindow(QSize(1000, 500), {}, "mw1");
|
|
auto m2 = createMainWindow(QSize(1000, 500), {}, "mw2");
|
|
// m2->setAffinities({ "m2" });
|
|
auto d2 = new QtWidgets::DockWidget("d2");
|
|
// d2->setAffinities({ "m2" });
|
|
d2->show();
|
|
QTest::qWait(200);
|
|
m2->view()->move(0, 0);
|
|
m1->view()->move(500, 250);
|
|
m1->view()->raiseAndActivate();
|
|
m1->view()->setWindowTitle("m1");
|
|
|
|
auto mainWindow1 = dynamic_cast<QtWidgets::MainWindow *>(m1->view());
|
|
QVERIFY(QTest::qWaitForWindowActive(mainWindow1));
|
|
|
|
auto dc = DragController::instance();
|
|
|
|
dc->programmaticStartDrag(d2->dockWidget()->titleBar(), globalPos, { 10, 5 });
|
|
|
|
auto tlw = dc->qtTopLevelUnderCursor();
|
|
QVERIFY(tlw);
|
|
|
|
/// Fixed on windows and Linux. Other platforms don't have the required API
|
|
/// to get correct z-order of windows under cursor
|
|
const bool supportsZOrderedWindowSearch = KDDockWidgets::isWindows() || (KDDockWidgets::isXCB() && KDDockWidgets::linksToXLib());
|
|
if (!supportsZOrderedWindowSearch)
|
|
QEXPECT_FAIL("", "Not supported on this platform", Continue);
|
|
|
|
QCOMPARE(tlw->controller(), m1.get());
|
|
|
|
dc->programmaticStopDrag();
|
|
}
|
|
|
|
void TestQtWidgets::tst_restoreInvalidPercentages()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
|
|
auto m = createMainWindow(Size(500, 500), MainWindowOption_HasCentralWidget, "mainWindowId1");
|
|
|
|
createDockWidget("_kddw_internal_dummy", Platform::instance()->tests_createView({ true }));
|
|
createDockWidget("_kddw_internal_dummy2", Platform::instance()->tests_createView({ true }));
|
|
for (int i = 0; i <= 8; ++i) {
|
|
new QtWidgets::DockWidget(QStringLiteral("dockwidget_tests_%1").arg(i));
|
|
}
|
|
|
|
bool ok = false;
|
|
LayoutSaver restorer;
|
|
const QByteArray data = Platform::instance()->readFile(":/layouts/invalidPercentages.json", /*by-ref*/ ok);
|
|
QVERIFY(ok);
|
|
QVERIFY(restorer.restoreLayout(data));
|
|
|
|
LayoutSaver saver;
|
|
QVERIFY(!saver.serializeLayout().isEmpty());
|
|
}
|
|
|
|
|
|
void TestQtWidgets::tst_controllerToView()
|
|
{
|
|
EnsureTopLevelsDeleted e;
|
|
auto dw = createDockWidget("dw1", Platform::instance()->tests_createView({ true }));
|
|
auto dwView = KDDockWidgets::controllerToView<QtWidgets::DockWidget>(dw);
|
|
|
|
std::vector<Core::DockWidget *> dws = { dw };
|
|
auto dwViews = KDDockWidgets::controllersToViews<QtWidgets::DockWidget>(dws);
|
|
|
|
QCOMPARE(dw->view(), dwView);
|
|
QCOMPARE(dws[0]->view(), dwView);
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
#ifdef KDDW_HAS_SPDLOG
|
|
FatalLogger::create();
|
|
#endif
|
|
|
|
// Might be disabled by env var
|
|
const auto frontends = Platform::frontendTypes();
|
|
if (std::find(frontends.cbegin(), frontends.cend(), FrontendType::QtWidgets)
|
|
== frontends.cend())
|
|
return 0;
|
|
|
|
Platform::tests_initPlatform(argc, argv, FrontendType::QtWidgets);
|
|
|
|
TestQtWidgets test;
|
|
const int exitCode = QTest::qExec(&test, argc, argv);
|
|
Platform::tests_deinitPlatform();
|
|
|
|
return exitCode;
|
|
}
|
|
|
|
#include "tst_qtwidgets.moc"
|