Move lots of methods from MultiSplitter to its base class

This commit is contained in:
Sergio Martins
2021-02-09 15:09:07 +00:00
parent eb67f19e3e
commit 5fbff7211b
5 changed files with 231 additions and 191 deletions

View File

@@ -9,7 +9,13 @@
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#include "Config.h"
#include "DockWidgetBase_p.h"
#include "FloatingWindow_p.h"
#include "FrameworkWidgetFactory.h"
#include "LayoutWidget_p.h"
#include "MainWindowBase.h"
#include "Position_p.h"
using namespace KDDockWidgets;
@@ -22,3 +28,113 @@ LayoutWidget::LayoutWidget(QWidgetOrQuick *parent)
LayoutWidget::~LayoutWidget()
{
}
bool LayoutWidget::isInMainWindow() const
{
return mainWindow() != nullptr;
}
MainWindowBase *LayoutWidget::mainWindow() const
{
if (auto pw = QWidgetAdapter::parentWidget()) {
// Note that if pw is a FloatingWindow then pw->parentWidget() can be a MainWindow too, as
// it's parented
if (pw->objectName() == QLatin1String("MyCentralWidget"))
return qobject_cast<MainWindowBase *>(pw->parentWidget());
if (auto mw = qobject_cast<MainWindowBase *>(pw))
return mw;
}
return nullptr;
}
FloatingWindow *LayoutWidget::floatingWindow() const
{
return qobject_cast<FloatingWindow *>(QWidgetAdapter::parentWidget());
}
void LayoutWidget::setRootItem(Layouting::ItemContainer *root)
{
delete m_rootItem;
m_rootItem = root;
connect(m_rootItem, &Layouting::ItemContainer::numVisibleItemsChanged, this,
&MultiSplitter::visibleWidgetCountChanged);
connect(m_rootItem, &Layouting::ItemContainer::minSizeChanged, this,
[this] { setMinimumSize(layoutMinimumSize()); });
}
QSize LayoutWidget::layoutMinimumSize() const
{
return m_rootItem->minSize();
}
QSize LayoutWidget::layoutMaximumSizeHint() const
{
return m_rootItem->maxSizeHint();
}
void LayoutWidget::setLayoutMinimumSize(QSize sz)
{
if (sz != m_rootItem->minSize()) {
setLayoutSize(size().expandedTo(m_rootItem->minSize())); // Increase size in case we need to
m_rootItem->setMinSize(sz);
}
}
QSize LayoutWidget::size() const
{
return m_rootItem->size();
}
void LayoutWidget::clearLayout()
{
m_rootItem->clear();
}
bool LayoutWidget::checkSanity() const
{
return m_rootItem->checkSanity();
}
void LayoutWidget::dumpLayout() const
{
m_rootItem->dumpLayout();
}
void LayoutWidget::restorePlaceholder(DockWidgetBase *dw, Layouting::Item *item, int tabIndex)
{
if (item->isPlaceholder()) {
Frame *newFrame = Config::self().frameworkWidgetFactory()->createFrame(this);
item->restore(newFrame);
}
auto frame = qobject_cast<Frame *>(item->guestAsQObject());
Q_ASSERT(frame);
if (tabIndex != -1 && frame->dockWidgetCount() >= tabIndex) {
frame->insertWidget(dw, tabIndex);
} else {
frame->addWidget(dw);
}
frame->QWidgetAdapter::setVisible(true);
}
void LayoutWidget::unrefOldPlaceholders(const Frame::List &framesBeingAdded) const
{
for (Frame *frame : framesBeingAdded) {
for (DockWidgetBase *dw : frame->dockWidgets()) {
dw->d->lastPositions().removePlaceholders(this);
}
}
}
void LayoutWidget::setLayoutSize(QSize size)
{
if (size != this->size()) {
m_rootItem->setSize_recursive(size);
if (!m_inResizeEvent && !LayoutSaver::restoreInProgress())
resize(size);
}
}

View File

@@ -28,8 +28,21 @@
#include "kddockwidgets/KDDockWidgets.h"
#include "kddockwidgets/QWidgetAdapter.h"
#include <QList>
namespace Layouting {
class Item;
class Separator;
class Widget_qwidget;
}
namespace KDDockWidgets {
class MainWindowBase;
class FloatingWindow;
class Frame;
class DockWidgetBase;
/**
* @brief The widget (QWidget or QQuickItem) which holds a layout of dock widgets.
*
@@ -47,6 +60,92 @@ class DOCKS_EXPORT LayoutWidget : public LayoutGuestWidget
public:
explicit LayoutWidget(QWidgetOrQuick *parent = nullptr);
~LayoutWidget() override;
bool isInMainWindow() const;
MainWindowBase *mainWindow() const;
FloatingWindow *floatingWindow() const;
/**
* @brief returns the layout's minimum size
* @ref setLayoutMinimumSize
*/
QSize layoutMinimumSize() const;
/**
* @brief returns the layout's maximum size hint
*/
QSize layoutMaximumSizeHint() const;
/**
* @brief returns the contents width.
* Usually it's the same width as the respective parent MultiSplitter.
*/
int width() const
{
return size().width();
}
/**
* @brief returns the contents height.
* Usually it's the same height as the respective parent MultiSplitter.
*/
int height() const
{
return size().height();
}
/**
* @brief getter for the size
*/
QSize size() const;
/// @brief Runs some sanity checks. Returns true if everything is OK
bool checkSanity() const;
/// @brief clears the layout
void clearLayout();
/// @brief dumps the layout to stderr
void dumpLayout() const;
/**
* @brief setter for the contents size
* The "contents size" is just the size() of this layout. However, since resizing
* QWidgets is async and we need it to be sync. As sometimes adding widgets will increase
* the MultiSplitter size (due to widget's min-size constraints).
*/
void setLayoutSize(QSize);
/// @brief restores the dockwidget @p dw to its previous position
void restorePlaceholder(DockWidgetBase *dw, Layouting::Item *, int tabIndex);
protected:
bool m_inResizeEvent = false;
void setRootItem(Layouting::ItemContainer *root);
/**
* @brief setter for the minimum size
* @ref minimumSize
*/
void setLayoutMinimumSize(QSize);
/**
* @brief Removes unneeded placeholder items when adding new frames.
*
* A floating frame A might have a placeholder in the main window (for example to remember its
* position on the Left), but then the user might attach it to the right, so the left
* placeholder is no longer need. Right before adding the frame to the right we remove the left
* placeholder, otherwise it's unrefed while we're adding causing a segfault. So what this does
* is making the unrefing happen a bit earlier.
*/
void unrefOldPlaceholders(const QList<Frame *> &framesBeingAdded) const;
Q_SIGNALS:
void visibleWidgetCountChanged(int count);
private:
Layouting::ItemContainer *m_rootItem = nullptr;
};
}

View File

@@ -78,30 +78,6 @@ bool MultiSplitter::onResize(QSize newSize)
return false; // So QWidget::resizeEvent is called
}
bool MultiSplitter::isInMainWindow() const
{
return mainWindow() != nullptr;
}
MainWindowBase *MultiSplitter::mainWindow() const
{
if (auto pw = QWidgetAdapter::parentWidget()) {
// Note that if pw is a FloatingWindow then pw->parentWidget() can be a MainWindow too, as it's parented
if (pw->objectName() == QLatin1String("MyCentralWidget"))
return qobject_cast<MainWindowBase*>(pw->parentWidget());
if (auto mw = qobject_cast<MainWindowBase*>(pw))
return mw;
}
return nullptr;
}
FloatingWindow *MultiSplitter::floatingWindow() const
{
return qobject_cast<FloatingWindow*>(QWidgetAdapter::parentWidget());
}
bool MultiSplitter::validateInputs(QWidgetOrQuick *widget,
Location location,
const Frame *relativeToFrame, InitialOption option) const
@@ -334,25 +310,6 @@ Frame::List MultiSplitter::frames() const
return result;
}
void MultiSplitter::restorePlaceholder(DockWidgetBase *dw, Layouting::Item *item, int tabIndex)
{
if (item->isPlaceholder()) {
Frame *newFrame = Config::self().frameworkWidgetFactory()->createFrame(this);
item->restore(newFrame);
}
auto frame = qobject_cast<Frame*>(item->guestAsQObject());
Q_ASSERT(frame);
if (tabIndex != -1 && frame->dockWidgetCount() >= tabIndex) {
frame->insertWidget(dw, tabIndex);
} else {
frame->addWidget(dw);
}
frame->QWidgetAdapter::setVisible(true);
}
void MultiSplitter::layoutEqually()
{
layoutEqually(m_rootItem);
@@ -367,70 +324,13 @@ void MultiSplitter::layoutEqually(Layouting::ItemBoxContainer *container)
}
}
void MultiSplitter::clearLayout()
{
m_rootItem->clear();
}
bool MultiSplitter::checkSanity() const
{
return m_rootItem->checkSanity();
}
void MultiSplitter::unrefOldPlaceholders(const Frame::List &framesBeingAdded) const
{
for (Frame *frame : framesBeingAdded) {
for (DockWidgetBase *dw : frame->dockWidgets()) {
dw->d->lastPositions().removePlaceholders(this);
}
}
}
void MultiSplitter::dumpLayout() const
{
m_rootItem->dumpLayout();
}
void MultiSplitter::setLayoutSize(QSize size)
{
if (size != this->size()) {
m_rootItem->setSize_recursive(size);
if (!m_inResizeEvent && !LayoutSaver::restoreInProgress())
resize(size);
}
}
QSize MultiSplitter::layoutMinimumSize() const
{
return m_rootItem->minSize();
}
QSize MultiSplitter::layoutMaximumSizeHint() const
{
return m_rootItem->maxSizeHint();
}
QSize MultiSplitter::size() const { return m_rootItem->size(); }
void MultiSplitter::setLayoutMinimumSize(QSize sz)
{
if (sz != m_rootItem->minSize()) {
setLayoutSize(size().expandedTo(m_rootItem->minSize())); // Increase size in case we need to
m_rootItem->setMinSize(sz);
}
qCDebug(sizing) << Q_FUNC_INFO << "minSize = " << m_rootItem->minSize();
}
void MultiSplitter::setRootItem(Layouting::ItemBoxContainer *root)
{
delete m_rootItem;
LayoutWidget::setRootItem(root);
m_rootItem = root;
connect(m_rootItem, &Layouting::ItemBoxContainer::numVisibleItemsChanged,
this, &MultiSplitter::visibleWidgetCountChanged);
connect(m_rootItem, &Layouting::ItemBoxContainer::minSizeChanged, this, [this] {
setMinimumSize(layoutMinimumSize());
});
connect(m_rootItem, &Layouting::ItemContainer::minSizeChanged, this,
[this] { setMinimumSize(layoutMinimumSize()); });
}
const Layouting::Item::List MultiSplitter::items() const

View File

@@ -28,19 +28,10 @@
#include "kddockwidgets/QWidgetAdapter.h"
#include "kddockwidgets/docks_export.h"
namespace Layouting {
class Item;
class Separator;
class Widget_qwidget;
}
class TestDocks;
namespace KDDockWidgets {
class MainWindowBase;
class FloatingWindow;
class Frame;
struct WindowBeingDragged;
/**
@@ -60,9 +51,6 @@ class DOCKS_EXPORT MultiSplitter : public LayoutWidget
public:
explicit MultiSplitter(QWidgetOrQuick *parent = nullptr);
~MultiSplitter() override;
bool isInMainWindow() const;
MainWindowBase* mainWindow() const;
FloatingWindow* floatingWindow() const;
/**
* @brief Adds a widget to this MultiSplitter.
@@ -120,7 +108,7 @@ public:
/**
* @brief The list of items in this layout.
*/
const QVector<Layouting::Item*> items() const;
const QVector<Layouting::Item *> items() const;
/**
@@ -143,48 +131,6 @@ public:
*/
void updateSizeConstraints();
/**
* @brief setter for the contents size
* The "contents size" is just the size() of this layout. However, since resizing
* QWidgets is async and we need it to be sync. As sometimes adding widgets will increase
* the MultiSplitter size (due to widget's min-size constraints).
*/
void setLayoutSize(QSize);
/**
* @brief returns the contents width.
* Usually it's the same width as the respective parent MultiSplitter.
*/
int width() const { return size().width(); }
/**
* @brief returns the contents height.
* Usually it's the same height as the respective parent MultiSplitter.
*/
int height() const { return size().height(); }
/**
* @brief returns the layout's minimum size
* @ref setLayoutMinimumSize
*/
QSize layoutMinimumSize() const;
/**
* @brief returns the layout's maximum size hint
*/
QSize layoutMaximumSizeHint() const;
/**
* @brief getter for the size
*/
QSize size() const;
/// @brief Runs some sanity checks. Returns true if everything is OK
bool checkSanity() const;
/// @brief dumps the layout to stderr
void dumpLayout() const;
/**
* @brief returns the Item that holds @p frame in this layout
*/
@@ -198,27 +144,16 @@ public:
/// @brief Returns the list of dock widgets contained in this layout
QVector<DockWidgetBase*> dockWidgets() const;
/// @brief restores the dockwidget @p dw to its previous position
void restorePlaceholder(DockWidgetBase *dw, Layouting::Item *, int tabIndex);
/// @brief See docs for MainWindowBase::layoutEqually()
void layoutEqually();
/// @brief overload that just resizes widgets within a sub-tree
void layoutEqually(Layouting::ItemBoxContainer *);
/// @brief clears the layout
void clearLayout();
Q_SIGNALS:
void visibleWidgetCountChanged(int count);
protected:
void onLayoutRequest() override;
bool onResize(QSize newSize) override;
private:
bool m_inResizeEvent = false;
friend class ::TestDocks;
/**
@@ -234,21 +169,6 @@ private:
bool validateInputs(QWidgetOrQuick *widget, KDDockWidgets::Location location,
const Frame *relativeToFrame, InitialOption option) const;
/**
* @brief Removes unneeded placeholder items when adding new frames.
*
* A floating frame A might have a placeholder in the main window (for example to remember its position on the Left),
* but then the user might attach it to the right, so the left placeholder is no longer need.
* Right before adding the frame to the right we remove the left placeholder, otherwise it's unrefed while we're adding
* causing a segfault. So what this does is making the unrefing happen a bit earlier.
*/
void unrefOldPlaceholders(const QList<Frame*> &framesBeingAdded) const;
/**
* @brief setter for the minimum size
* @ref minimumSize
*/
void setLayoutMinimumSize(QSize);
void setRootItem(Layouting::ItemBoxContainer *);

View File

@@ -294,6 +294,8 @@ public:
QVector<int> pathFromRoot() const;
Q_REQUIRED_RESULT virtual bool checkSanity();
virtual QSize minSize() const;
virtual QSize maxSizeHint() const;
virtual void setSize_recursive(QSize newSize, ChildrenResizeStrategy strategy = ChildrenResizeStrategy::Percentage);
@@ -321,7 +323,6 @@ protected:
explicit Item(bool isContainer, Widget *hostWidget, ItemContainer *parent);
void setParentContainer(ItemContainer *parent);
void connectParent(ItemContainer *parent);
Q_REQUIRED_RESULT virtual bool checkSanity();
void setPos(QPoint);
void setPos(int pos, Qt::Orientation);
const ItemContainer *asContainer() const;
@@ -384,10 +385,18 @@ public:
bool contains_recursive(const Item *item) const;
int visibleCount_recursive() const override;
int count_recursive() const;
virtual void clear() = 0;
protected:
bool hasSingleVisibleItem() const;
Item::List m_children;
Q_SIGNALS:
void itemsChanged();
void numVisibleItemsChanged(int);
void numItemsChanged();
private:
struct Private;
Private *const d;
@@ -427,7 +436,7 @@ public:
QRect suggestedDropRect(const Item *item, const Item *relativeTo, KDDockWidgets::Location) const;
QVariantMap toVariantMap() const override;
void fillFromVariantMap(const QVariantMap &map, const QHash<QString, Widget *> &widgets) override;
void clear();
void clear() override;
Qt::Orientation orientation() const;
bool isVertical() const;
bool isHorizontal() const;
@@ -516,10 +525,6 @@ private:
bool test_suggestedRect();
#endif
Q_SIGNALS:
void itemsChanged();
void numVisibleItemsChanged(int);
void numItemsChanged();
public:
QVector<Layouting::Separator*> separators_recursive() const;
QVector<Layouting::Separator*> separators() const;