qtquick: Move DockWidgetModel to TabBar_qtquick

It's where it's used
This commit is contained in:
Sergio Martins
2022-09-10 15:26:46 +01:00
parent 0157d7d914
commit 96990be5bb
7 changed files with 229 additions and 236 deletions

View File

@@ -51,7 +51,7 @@ KDDW.TabBarBase {
/// ##HERE## The list of tabs is stored in a C++ model. This repeater populates our tab bar
Repeater {
model: root.groupCpp ? root.groupCpp.tabWidget.dockWidgetModel : 0
model: root.groupCpp ? root.groupCpp.tabBar.dockWidgetModel : 0
Rectangle {
id: tab
height: parent.height

View File

@@ -15,27 +15,20 @@
#include "kddockwidgets/controllers/Stack.h"
#include "kddockwidgets/controllers/Group.h"
#include "kddockwidgets/controllers/DockWidget_p.h"
#include "kddockwidgets/controllers/TabBar.h"
#include <QDebug>
#include <QScopedValueRollback>
using namespace KDDockWidgets;
using namespace KDDockWidgets::Views;
Stack_qtquick::Stack_qtquick(Controllers::Stack *controller, QQuickItem *parent)
: View_qtquick(controller, Type::Stack, parent)
, StackViewInterface(controller)
, m_dockWidgetModel(new DockWidgetModel(this))
{
connect(m_dockWidgetModel, &DockWidgetModel::countChanged, this,
[this] { Q_EMIT m_stack->tabBar()->countChanged(); });
}
void Stack_qtquick::init()
{
m_dockWidgetModel->m_tabBar = m_stack->tabBar();
m_tabBarAutoHideChanged =
m_stack->tabBarAutoHideChanged.connect([this] { Q_EMIT tabBarAutoHideChanged(); });
@@ -52,176 +45,7 @@ QObject *Stack_qtquick::tabBarViewObj() const
return View_qt::asQObject(m_stack->tabBar()->view());
}
Controllers::DockWidget *Stack_qtquick::currentDockWidget() const
{
return m_dockWidgetModel->currentDockWidget();
}
bool Stack_qtquick::tabBarAutoHide() const
{
return m_stack->tabBarAutoHide();
}
DockWidgetModel *Stack_qtquick::dockWidgetModel() const
{
return m_dockWidgetModel;
}
DockWidgetModel::DockWidgetModel(QObject *parent)
: QAbstractListModel(parent)
{
}
int DockWidgetModel::count() const
{
return m_dockWidgets.size();
}
int DockWidgetModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_dockWidgets.size();
}
QVariant DockWidgetModel::data(const QModelIndex &index, int role) const
{
const int row = index.row();
if (row < 0 || row >= m_dockWidgets.size())
return {};
Controllers::DockWidget *dw = m_dockWidgets.at(row);
switch (role) {
case Role_Title:
return dw->title();
}
return {};
}
Controllers::DockWidget *DockWidgetModel::dockWidgetAt(int index) const
{
if (index < 0 || index >= m_dockWidgets.size()) {
// Can happen. Benign.
return nullptr;
}
return m_dockWidgets[index];
}
bool DockWidgetModel::contains(Controllers::DockWidget *dw) const
{
return m_dockWidgets.contains(dw);
}
Controllers::DockWidget *DockWidgetModel::currentDockWidget() const
{
return m_currentDockWidget;
}
void DockWidgetModel::setCurrentDockWidget(Controllers::DockWidget *dw)
{
if (m_currentDockWidget)
m_currentDockWidget->setVisible(false);
m_currentDockWidget = dw;
setCurrentIndex(indexOf(dw));
if (m_currentDockWidget) {
QScopedValueRollback<bool> guard(m_currentDockWidget->d->m_isSettingCurrent, true);
m_currentDockWidget->setVisible(true);
}
}
QHash<int, QByteArray> DockWidgetModel::roleNames() const
{
return { { Role_Title, "title" } };
}
void DockWidgetModel::emitDataChangedFor(Controllers::DockWidget *dw)
{
const int row = indexOf(dw);
if (row == -1) {
qWarning() << Q_FUNC_INFO << "Couldn't find" << dw;
} else {
QModelIndex index = this->index(row, 0);
Q_EMIT dataChanged(index, index);
}
}
void DockWidgetModel::remove(Controllers::DockWidget *dw)
{
QScopedValueRollback<bool> guard(m_removeGuard, true);
const int row = indexOf(dw);
if (row == -1) {
if (!m_removeGuard) {
// can happen if there's reentrancy. Some user code reacting
// to the signals and call remove for whatever reason.
qWarning() << Q_FUNC_INFO << "Nothing to remove"
<< static_cast<void *>(dw); // Print address only, as it might be deleted
// already
}
} else {
const auto connections = m_connections.take(dw);
for (const QMetaObject::Connection &conn : connections)
disconnect(conn);
beginRemoveRows(QModelIndex(), row, row);
m_dockWidgets.removeOne(dw);
endRemoveRows();
Q_EMIT countChanged();
Q_EMIT dockWidgetRemoved();
}
}
int DockWidgetModel::indexOf(const Controllers::DockWidget *dw)
{
return m_dockWidgets.indexOf(const_cast<Controllers::DockWidget *>(dw));
}
int DockWidgetModel::currentIndex() const
{
if (!m_currentDockWidget)
return -1;
const int index = m_dockWidgets.indexOf(m_currentDockWidget);
if (index == -1)
qWarning() << Q_FUNC_INFO << "Unexpected null index for" << m_currentDockWidget << this
<< "; count=" << count();
return index;
}
void DockWidgetModel::setCurrentIndex(int index)
{
Controllers::DockWidget *dw = dockWidgetAt(index);
if (m_currentDockWidget != dw) {
setCurrentDockWidget(dw);
m_tabBar->setCurrentIndex(index);
}
}
bool DockWidgetModel::insert(Controllers::DockWidget *dw, int index)
{
if (m_dockWidgets.contains(dw)) {
qWarning() << Q_FUNC_INFO << "Shouldn't happen";
return false;
}
QMetaObject::Connection conn = connect(dw, &Controllers::DockWidget::titleChanged, this,
[dw, this] { emitDataChangedFor(dw); });
QMetaObject::Connection conn2 =
connect(dw, &QObject::destroyed, this, [dw, this] { remove(dw); });
m_connections[dw] = { conn, conn2 };
beginInsertRows(QModelIndex(), index, index);
m_dockWidgets.insert(index, dw);
endInsertRows();
Q_EMIT countChanged();
return true;
}

View File

@@ -23,7 +23,6 @@
#include "View_qtquick.h"
#include "views/StackViewInterface.h"
#include <QAbstractListModel>
#include <QVector>
#include "kdbindings/signal.h"
@@ -37,20 +36,13 @@ class TabBar;
namespace Views {
class DockWidgetModel;
class DOCKS_EXPORT Stack_qtquick : public View_qtquick, public StackViewInterface
{
Q_OBJECT
Q_PROPERTY(DockWidgetModel *dockWidgetModel READ dockWidgetModel CONSTANT)
Q_PROPERTY(QObject *tabBar READ tabBarViewObj NOTIFY tabBarChanged)
public:
explicit Stack_qtquick(Controllers::Stack *controller, QQuickItem *parent = nullptr);
DockWidgetModel *dockWidgetModel() const;
Controllers::DockWidget *currentDockWidget() const;
/// @brief Returns the tab bar as a QObject for QML.
/// As the base class is not a QObject.
QObject *tabBarViewObj() const;
@@ -71,52 +63,9 @@ protected:
private:
Q_DISABLE_COPY(Stack_qtquick)
DockWidgetModel *const m_dockWidgetModel;
KDBindings::ScopedConnection m_tabBarAutoHideChanged;
};
class DockWidgetModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
public:
enum Role {
Role_Title = Qt::UserRole
};
explicit DockWidgetModel(QObject *parent);
int count() const;
int rowCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
Controllers::DockWidget *dockWidgetAt(int index) const;
Controllers::DockWidget *currentDockWidget() const;
void setCurrentDockWidget(Controllers::DockWidget *);
void remove(Controllers::DockWidget *);
int indexOf(const Controllers::DockWidget *);
bool insert(Controllers::DockWidget *dw, int index);
bool contains(Controllers::DockWidget *dw) const;
int currentIndex() const;
void setCurrentIndex(int index);
// TODOm4: Move to private and make *const
Controllers::TabBar *m_tabBar = nullptr;
protected:
QHash<int, QByteArray> roleNames() const override;
Q_SIGNALS:
void countChanged();
void dockWidgetRemoved();
private:
void emitDataChangedFor(Controllers::DockWidget *);
QVector<Controllers::DockWidget *> m_dockWidgets;
QHash<Controllers::DockWidget *, QVector<QMetaObject::Connection>>
m_connections; // To make it easy to disconnect from lambdas
bool m_removeGuard = false;
Controllers::DockWidget *m_currentDockWidget = nullptr;
};
}
}

View File

@@ -19,12 +19,15 @@
#include "TabBar_qtquick.h"
#include "Stack_qtquick.h"
#include "kddockwidgets/controllers/DockWidget_p.h"
#include "kddockwidgets/controllers/TabBar.h"
#include "kddockwidgets/controllers/Stack.h"
#include "Stack_qtquick.h"
#include <QMetaObject>
#include <QMouseEvent>
#include <QDebug>
#include <QScopedValueRollback>
using namespace KDDockWidgets;
using namespace KDDockWidgets::Views;
@@ -32,7 +35,11 @@ using namespace KDDockWidgets::Views;
TabBar_qtquick::TabBar_qtquick(Controllers::TabBar *controller, QQuickItem *parent)
: View_qtquick(controller, Type::TabBar, parent)
, TabBarViewInterface(controller)
, m_dockWidgetModel(new DockWidgetModel(this))
{
m_dockWidgetModel->m_tabBar = controller;
connect(m_dockWidgetModel, &DockWidgetModel::countChanged, this,
[controller] { Q_EMIT controller->countChanged(); });
}
void TabBar_qtquick::init()
@@ -150,7 +157,7 @@ Stack_qtquick *TabBar_qtquick::stackView() const
void TabBar_qtquick::setCurrentIndex(int index)
{
stackView()->dockWidgetModel()->setCurrentIndex(index);
m_dockWidgetModel->setCurrentIndex(index);
}
void TabBar_qtquick::renameTab(int index, const QString &)
@@ -167,7 +174,7 @@ void TabBar_qtquick::changeTabIcon(int index, const QIcon &)
void TabBar_qtquick::removeDockWidget(Controllers::DockWidget *dw)
{
stackView()->dockWidgetModel()->remove(dw);
m_dockWidgetModel->remove(dw);
}
void TabBar_qtquick::insertDockWidget(int index, Controllers::DockWidget *dw, const QIcon &icon,
@@ -176,5 +183,169 @@ void TabBar_qtquick::insertDockWidget(int index, Controllers::DockWidget *dw, co
Q_UNUSED(title); // TODO
Q_UNUSED(icon); // TODO
stackView()->dockWidgetModel()->insert(dw, index);
m_dockWidgetModel->insert(dw, index);
}
DockWidgetModel *TabBar_qtquick::dockWidgetModel() const
{
return m_dockWidgetModel;
}
DockWidgetModel::DockWidgetModel(QObject *parent)
: QAbstractListModel(parent)
{
}
int DockWidgetModel::count() const
{
return m_dockWidgets.size();
}
int DockWidgetModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_dockWidgets.size();
}
QVariant DockWidgetModel::data(const QModelIndex &index, int role) const
{
const int row = index.row();
if (row < 0 || row >= m_dockWidgets.size())
return {};
Controllers::DockWidget *dw = m_dockWidgets.at(row);
switch (role) {
case Role_Title:
return dw->title();
}
return {};
}
Controllers::DockWidget *DockWidgetModel::dockWidgetAt(int index) const
{
if (index < 0 || index >= m_dockWidgets.size()) {
// Can happen. Benign.
return nullptr;
}
return m_dockWidgets[index];
}
bool DockWidgetModel::contains(Controllers::DockWidget *dw) const
{
return m_dockWidgets.contains(dw);
}
Controllers::DockWidget *DockWidgetModel::currentDockWidget() const
{
return m_currentDockWidget;
}
void DockWidgetModel::setCurrentDockWidget(Controllers::DockWidget *dw)
{
if (m_currentDockWidget)
m_currentDockWidget->setVisible(false);
m_currentDockWidget = dw;
setCurrentIndex(indexOf(dw));
if (m_currentDockWidget) {
QScopedValueRollback<bool> guard(m_currentDockWidget->d->m_isSettingCurrent, true);
m_currentDockWidget->setVisible(true);
}
}
QHash<int, QByteArray> DockWidgetModel::roleNames() const
{
return { { Role_Title, "title" } };
}
void DockWidgetModel::emitDataChangedFor(Controllers::DockWidget *dw)
{
const int row = indexOf(dw);
if (row == -1) {
qWarning() << Q_FUNC_INFO << "Couldn't find" << dw;
} else {
QModelIndex index = this->index(row, 0);
Q_EMIT dataChanged(index, index);
}
}
void DockWidgetModel::remove(Controllers::DockWidget *dw)
{
QScopedValueRollback<bool> guard(m_removeGuard, true);
const int row = indexOf(dw);
if (row == -1) {
if (!m_removeGuard) {
// can happen if there's reentrancy. Some user code reacting
// to the signals and call remove for whatever reason.
qWarning() << Q_FUNC_INFO << "Nothing to remove"
<< static_cast<void *>(dw); // Print address only, as it might be deleted
// already
}
} else {
const auto connections = m_connections.take(dw);
for (const QMetaObject::Connection &conn : connections)
disconnect(conn);
beginRemoveRows(QModelIndex(), row, row);
m_dockWidgets.removeOne(dw);
endRemoveRows();
Q_EMIT countChanged();
Q_EMIT dockWidgetRemoved();
}
}
int DockWidgetModel::indexOf(const Controllers::DockWidget *dw)
{
return m_dockWidgets.indexOf(const_cast<Controllers::DockWidget *>(dw));
}
int DockWidgetModel::currentIndex() const
{
if (!m_currentDockWidget)
return -1;
const int index = m_dockWidgets.indexOf(m_currentDockWidget);
if (index == -1)
qWarning() << Q_FUNC_INFO << "Unexpected null index for" << m_currentDockWidget << this
<< "; count=" << count();
return index;
}
void DockWidgetModel::setCurrentIndex(int index)
{
Controllers::DockWidget *dw = dockWidgetAt(index);
if (m_currentDockWidget != dw) {
setCurrentDockWidget(dw);
m_tabBar->setCurrentIndex(index);
}
}
bool DockWidgetModel::insert(Controllers::DockWidget *dw, int index)
{
if (m_dockWidgets.contains(dw)) {
qWarning() << Q_FUNC_INFO << "Shouldn't happen";
return false;
}
QMetaObject::Connection conn = connect(dw, &Controllers::DockWidget::titleChanged, this,
[dw, this] { emitDataChangedFor(dw); });
QMetaObject::Connection conn2 =
connect(dw, &QObject::destroyed, this, [dw, this] { remove(dw); });
m_connections[dw] = { conn, conn2 };
beginInsertRows(QModelIndex(), index, index);
m_dockWidgets.insert(index, dw);
endInsertRows();
Q_EMIT countChanged();
return true;
}

View File

@@ -24,6 +24,7 @@
#include "View_qtquick.h"
#include "views/TabBarViewInterface.h"
#include <QAbstractListModel>
#include <QPointer>
#include <QHash>
@@ -36,6 +37,7 @@ class TabBar;
namespace KDDockWidgets::Views {
class DockWidget;
class DockWidgetModel;
class TabWidget;
class Stack_qtquick;
@@ -45,10 +47,13 @@ class DOCKS_EXPORT TabBar_qtquick : public View_qtquick, public TabBarViewInterf
Q_PROPERTY(QQuickItem *tabBarQmlItem READ tabBarQmlItem WRITE setTabBarQmlItem NOTIFY
tabBarQmlItemChanged)
Q_PROPERTY(bool tabBarAutoHide READ tabBarAutoHide NOTIFY tabBarAutoHideChanged)
Q_PROPERTY(DockWidgetModel *dockWidgetModel READ dockWidgetModel CONSTANT)
public:
explicit TabBar_qtquick(Controllers::TabBar *controller, QQuickItem *parent = nullptr);
int tabAt(QPoint localPos) const override;
DockWidgetModel *dockWidgetModel() const;
int tabAt(QPoint localPos) const override;
QQuickItem *tabBarQmlItem() const;
void setTabBarQmlItem(QQuickItem *);
@@ -78,9 +83,53 @@ protected:
private:
QQuickItem *tabAt(int index) const;
DockWidgetModel *const m_dockWidgetModel;
QPointer<QQuickItem> m_tabBarQmlItem;
KDBindings::ScopedConnection m_tabBarAutoHideChanged;
};
class DockWidgetModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
public:
enum Role {
Role_Title = Qt::UserRole
};
explicit DockWidgetModel(QObject *parent);
int count() const;
int rowCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
Controllers::DockWidget *dockWidgetAt(int index) const;
Controllers::DockWidget *currentDockWidget() const;
void setCurrentDockWidget(Controllers::DockWidget *);
void remove(Controllers::DockWidget *);
int indexOf(const Controllers::DockWidget *);
bool insert(Controllers::DockWidget *dw, int index);
bool contains(Controllers::DockWidget *dw) const;
int currentIndex() const;
void setCurrentIndex(int index);
// TODOm4: Move to private and make *const
Controllers::TabBar *m_tabBar = nullptr;
protected:
QHash<int, QByteArray> roleNames() const override;
Q_SIGNALS:
void countChanged();
void dockWidgetRemoved();
private:
void emitDataChangedFor(Controllers::DockWidget *);
QVector<Controllers::DockWidget *> m_dockWidgets;
QHash<Controllers::DockWidget *, QVector<QMetaObject::Connection>>
m_connections; // To make it easy to disconnect from lambdas
bool m_removeGuard = false;
Controllers::DockWidget *m_currentDockWidget = nullptr;
};
}
#endif

View File

@@ -99,7 +99,7 @@ TabBarBase {
Repeater {
/// The list of tabs is stored in a C++ model. This repeater populates our TabBar.
model: root.groupCpp ? root.groupCpp.tabWidget.dockWidgetModel : 0
model: root.groupCpp ? root.groupCpp.tabBar.dockWidgetModel : 0
TabButton {
readonly property int tabIndex: index
text: title

View File

@@ -21,10 +21,10 @@ Item {
readonly property QtObject groupCpp: parent.groupCpp
/// This is our C++ TabBar_qtquick.cpp
readonly property QtObject tabBarCpp: groupCpp ? groupCpp.tabWidget.tabBar : null
readonly property QtObject tabBarCpp: groupCpp ? groupCpp.tabBar : null
/// The number of tabs
readonly property int count: groupCpp ? groupCpp.tabWidget.dockWidgetModel.count : 0
readonly property int count: tabBarCpp ? tabBarCpp.dockWidgetModel.count : 0
property int currentTabIndex: -1