Add DockWidget::Option_NonDockable

A dock widget with this option will always be floating and not be
able to dock into anything. Other widgets can't dock into it either.
This commit is contained in:
Sergio Martins
2020-04-13 12:45:35 +01:00
parent 899ca6af6a
commit ab0fc1e328
11 changed files with 104 additions and 13 deletions

View File

@@ -49,10 +49,11 @@ static MyWidget *newMyWidget()
}
MyMainWindow::MyMainWindow(const QString &uniqueName, KDDockWidgets::MainWindowOptions options,
bool dockWidget0IsNonClosable, bool restoreIsRelative,
bool dockWidget0IsNonClosable, bool nonDockableDockWidget9, bool restoreIsRelative,
const QString &affinityName, QWidget *parent)
: MainWindow(uniqueName, options, parent)
, m_dockWidget0IsNonClosable(dockWidget0IsNonClosable)
, m_dockWidget9IsNonDockable(nonDockableDockWidget9)
, m_restoreIsRelative(restoreIsRelative)
{
// qApp->installEventFilter(this);
@@ -112,8 +113,11 @@ void MyMainWindow::createDockWidgets()
{
Q_ASSERT(m_dockwidgets.isEmpty());
const int numDockWidgets = m_dockWidget9IsNonDockable ? 10 : 9;
// Create 9 KDDockWidget::DockWidget and the respective widgets they're hosting (MyWidget instances)
for (int i = 0; i < 9; i++)
for (int i = 0; i < numDockWidgets; i++)
m_dockwidgets << newDockWidget();
@@ -150,6 +154,9 @@ KDDockWidgets::DockWidgetBase *MyMainWindow::newDockWidget()
if (count == 0 && m_dockWidget0IsNonClosable)
options |= KDDockWidgets::DockWidget::Option_NotClosable;
if (count == 9 && m_dockWidget9IsNonDockable)
options |= KDDockWidgets::DockWidget::Option_NotDockable;
auto dock = new KDDockWidgets::DockWidget(QStringLiteral("DockWidget #%1").arg(count), options);
dock->setAffinityName(affinityName()); // optional, just to show the feature. Pass -mi to the example to see incompatible dock widgets
@@ -157,7 +164,14 @@ KDDockWidgets::DockWidgetBase *MyMainWindow::newDockWidget()
dock->setIcon(QIcon::fromTheme(QStringLiteral("mail-message")));
auto myWidget = newMyWidget();
dock->setWidget(myWidget);
dock->setTitle(QStringLiteral("DockWidget #%1").arg(count));
if (dock->options() & KDDockWidgets::DockWidget::Option_NotDockable) {
dock->setTitle(QStringLiteral("DockWidget #%1 (%2)").arg(count).arg("non dockable"));
} else {
dock->setTitle(QStringLiteral("DockWidget #%1").arg(count));
}
dock->resize(600, 600);
dock->show();
m_toggleMenu->addAction(dock->toggleAction());

View File

@@ -28,7 +28,7 @@ class MyMainWindow : public KDDockWidgets::MainWindow
Q_OBJECT
public:
explicit MyMainWindow(const QString &uniqueName, KDDockWidgets::MainWindowOptions options,
bool dockWidget0IsNonClosable, bool restoreIsRelative,
bool dockWidget0IsNonClosable, bool nonDockableDockWidget9, bool restoreIsRelative,
const QString &affinityName = {}, // Usually not needed. Just here to show the feature.
QWidget *parent = nullptr);
@@ -37,6 +37,7 @@ private:
KDDockWidgets::DockWidgetBase* newDockWidget();
QMenu *m_toggleMenu = nullptr;
const bool m_dockWidget0IsNonClosable;
const bool m_dockWidget9IsNonDockable;
const bool m_restoreIsRelative;
KDDockWidgets::DockWidget::List m_dockwidgets;
};

View File

@@ -76,6 +76,9 @@ int main(int argc, char **argv)
QCommandLineOption doubleClickMaximize("x", QCoreApplication::translate("main", "Double clicking a title bar will maximize a floating window"));
parser.addOption(doubleClickMaximize);
QCommandLineOption nonDockable("d", QCoreApplication::translate("main", "DockWidget #9 will be non-dockable"));
parser.addOption(nonDockable);
#if defined(DOCKS_DEVELOPER_MODE)
QCommandLineOption noCentralFrame("c", QCoreApplication::translate("main", "No central frame"));
parser.addOption(noCentralFrame);
@@ -122,8 +125,9 @@ int main(int argc, char **argv)
const bool nonClosableDockWidget0 = parser.isSet(nonClosableDockWidget);
const bool restoreIsRelative = parser.isSet(relativeRestore);
const bool nonDockableDockWidget9 = parser.isSet(nonDockable);
MyMainWindow mainWindow(QStringLiteral("MyMainWindow"), options, nonClosableDockWidget0, restoreIsRelative);
MyMainWindow mainWindow(QStringLiteral("MyMainWindow"), options, nonClosableDockWidget0, nonDockableDockWidget9, restoreIsRelative);
mainWindow.setWindowTitle("Main Window 1");
mainWindow.resize(1200, 1200);
mainWindow.show();
@@ -135,7 +139,7 @@ int main(int argc, char **argv)
: QString();
auto mainWindow2 = new MyMainWindow(QStringLiteral("MyMainWindow-2"), options,
nonClosableDockWidget0, restoreIsRelative, affinity);
nonClosableDockWidget0, nonDockableDockWidget9, restoreIsRelative, affinity);
if (affinity.isEmpty())
mainWindow2->setWindowTitle("Main Window 2");
else

View File

@@ -150,6 +150,12 @@ void DockWidgetBase::addDockWidgetAsTab(DockWidgetBase *other, AddingOption addi
return;
}
if ((other->options() & DockWidgetBase::Option_NotDockable) ||
(options() & DockWidgetBase::Option_NotDockable)) {
qWarning() << Q_FUNC_INFO << "Refusing to dock non-dockable widget" << other;
return;
}
Frame *frame = this->frame();
if (frame) {
@@ -184,6 +190,12 @@ void DockWidgetBase::addDockWidgetToContainingWindow(DockWidgetBase *other, Loca
return;
}
if ((other->options() & DockWidgetBase::Option_NotDockable) ||
(options() & DockWidgetBase::Option_NotDockable)) {
qWarning() << Q_FUNC_INFO << "Refusing to dock non-dockable widget" << other;
return;
}
if (isWindow())
morphIntoFloatingWindow();
@@ -283,6 +295,11 @@ DockWidgetBase::Options DockWidgetBase::options() const
void DockWidgetBase::setOptions(Options options)
{
if ((d->options & Option_NotDockable) != (options & Option_NotDockable)) {
qWarning() << Q_FUNC_INFO << "Option_NotDockable not allowed to change. Pass via ctor only.";
return;
}
if (options != d->options) {
d->options = options;
Q_EMIT optionsChanged(options);

View File

@@ -69,7 +69,8 @@ public:
///@brief DockWidget options to pass at construction time
enum Option {
Option_None = 0, ///< No option, the default
Option_NotClosable = 1 /// The DockWidget can't be closed on the [x], only programatically
Option_NotClosable = 1, /// The DockWidget can't be closed on the [x], only programatically
Option_NotDockable = 2 ///< The DockWidget can't be docked, it's always floating
};
Q_DECLARE_FLAGS(Options, Option)
@@ -180,7 +181,10 @@ public:
Options options() const;
/**
* @brief Setter for the options
* @brief Setter for the options.
* Only Option_NotClosable is allowed to change after construction. For the other options use
* the constructor only.
*
* @sa options(), optionsChanged()
*/
void setOptions(Options);

View File

@@ -81,6 +81,11 @@ void MainWindowBase::addDockWidgetAsTab(DockWidgetBase *widget)
return;
}
if (widget->options() & DockWidgetBase::Option_NotDockable) {
qWarning() << Q_FUNC_INFO << "Refusing to dock non-dockable widget" << widget;
return;
}
if (d->supportsCentralFrame()) {
dropArea()->m_centralFrame->addWidget(widget);
} else {
@@ -90,6 +95,11 @@ void MainWindowBase::addDockWidgetAsTab(DockWidgetBase *widget)
void MainWindowBase::addDockWidget(DockWidgetBase *dw, Location location, DockWidgetBase *relativeTo, AddingOption option)
{
if (dw->options() & DockWidgetBase::Option_NotDockable) {
qWarning() << Q_FUNC_INFO << "Refusing to dock non-dockable widget" << dw;
return;
}
dropArea()->addDockWidget(dw, location, relativeTo, option);
}

View File

@@ -197,6 +197,12 @@ bool StateDragging::handleMouseButtonRelease(QPoint globalPos)
return true;
}
if (floatingWindow->anyNonDockable()) {
qCDebug(state) << "StateDragging: Ignoring floating window with non dockable widgets";
Q_EMIT q->dragCanceled();
return true;
}
if (q->m_currentDropArea) {
if (q->m_currentDropArea->drop(floatingWindow, globalPos)) {
Q_EMIT q->dropped();
@@ -213,21 +219,36 @@ bool StateDragging::handleMouseButtonRelease(QPoint globalPos)
bool StateDragging::handleMouseMove(QPoint globalPos)
{
if (!q->m_windowBeingDragged->floatingWindow()) {
FloatingWindow *fw = q->m_windowBeingDragged->floatingWindow();
if (!fw) {
qCDebug(state) << "Canceling drag, window was deleted";
Q_EMIT q->dragCanceled();
return true;
}
if (!q->m_nonClientDrag)
q->m_windowBeingDragged->floatingWindow()->windowHandle()->setPosition(globalPos - q->m_offset);
fw->windowHandle()->setPosition(globalPos - q->m_offset);
if (fw->anyNonDockable()) {
qCDebug(state) << "StateDragging: Ignoring non dockable floating window";
return true;
}
DropArea *dropArea = q->dropAreaUnderCursor();
if (q->m_currentDropArea && dropArea != q->m_currentDropArea)
q->m_currentDropArea->removeHover();
if (dropArea)
dropArea->hover(q->m_windowBeingDragged->floatingWindow(), globalPos);
if (dropArea) {
if (FloatingWindow *targetFw = dropArea->floatingWindow()) {
if (targetFw->anyNonDockable()) {
qCDebug(state) << "StateDragging: Ignoring non dockable target floating window";
return false;
}
}
dropArea->hover(fw, globalPos);
}
q->m_currentDropArea = dropArea;

View File

@@ -260,6 +260,15 @@ bool FloatingWindow::anyNonClosable() const
return false;
}
bool FloatingWindow::anyNonDockable() const
{
for (Frame *frame : frames()) {
if (frame->anyNonDockable())
return true;
}
return false;
}
bool FloatingWindow::hasSingleFrame() const
{
return frames().size() == 1;

View File

@@ -63,6 +63,7 @@ public:
TitleBar *titleBar() const { return m_titleBar; }
bool anyNonClosable() const;
bool anyNonDockable() const;
/**
* @brief checks if this FloatingWindow only has one frame.

View File

@@ -333,6 +333,16 @@ bool Frame::anyNonClosable() const
return false;
}
bool Frame::anyNonDockable() const
{
for (auto dw : dockWidgets()) {
if (dw->options() & DockWidgetBase::Option_NotDockable)
return true;
}
return false;
}
void Frame::onDockWidgetShown(DockWidgetBase *w)
{
if (hasSingleDockWidget() && contains(w)) { // We have to call contains because it might be being in process of being reparented

View File

@@ -164,7 +164,7 @@ public:
FrameOptions options() const { return m_options; }
bool anyNonClosable() const;
bool anyNonDockable() const;
///@brief returns whether there's 0 dock widgets. If not persistent then the Frame will delete itself.
bool isEmpty() const { return dockWidgetCount() == 0; }