[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [falkon] /: Add TabTreeModel
From:       David Rosca <null () kde ! org>
Date:       2018-01-31 20:10:36
Message-ID: E1egyiK-0002Fo-QW () code ! kde ! org
[Download RAW message or body]

Git commit e57fb65c955847e5070919e817486b8b25db2f87 by David Rosca.
Committed on 31/01/2018 at 20:03.
Pushed by drosca into branch 'master'.

Add TabTreeModel

This model orders tabs in "Tree Style Tabs" fashion.

M  +98   -0    autotests/tabmodeltest.cpp
M  +1    -0    autotests/tabmodeltest.h
M  +1    -0    src/lib/CMakeLists.txt
A  +390  -0    src/lib/tabwidget/tabtreemodel.cpp     [License: GPL (v3+)]
A  +67   -0    src/lib/tabwidget/tabtreemodel.h     [License: GPL (v3+)]
M  +9    -4    src/lib/webtab/webtab.cpp

https://commits.kde.org/falkon/e57fb65c955847e5070919e817486b8b25db2f87

diff --git a/autotests/tabmodeltest.cpp b/autotests/tabmodeltest.cpp
index 541f68e0..92123af3 100644
--- a/autotests/tabmodeltest.cpp
+++ b/autotests/tabmodeltest.cpp
@@ -18,6 +18,7 @@
 #include "tabmodeltest.h"
 #include "autotests.h"
 #include "tabmodel.h"
+#include "tabtreemodel.h"
 #include "webtab.h"
 #include "tabwidget.h"
 #include "tabbedwebview.h"
@@ -118,5 +119,102 @@ void TabModelTest::dataTest()
 
     delete w;
 }
+void TabModelTest::treeModelTest()
+{
+    BrowserWindow *w = mApp->createWindow(Qz::BW_NewWindow);
+
+    TabModel sourceModel(w);
+    TabTreeModel model;
+    model.setSourceModel(&sourceModel);
+    ModelTest modelTest(&model);
+
+    w->tabWidget()->addView(QUrl());
+    w->tabWidget()->addView(QUrl());
+    w->tabWidget()->addView(QUrl());
+    w->tabWidget()->addView(QUrl());
+    w->tabWidget()->addView(QUrl());
+
+    QTRY_COMPARE(model.rowCount(QModelIndex()), 6);
+
+    WebTab *tab1 = w->weView(0)->webTab();
+    WebTab *tab2 = w->weView(1)->webTab();
+    WebTab *tab3 = w->weView(2)->webTab();
+    WebTab *tab4 = w->weView(3)->webTab();
+    WebTab *tab5 = w->weView(4)->webTab();
+    WebTab *tab6 = w->weView(5)->webTab();
+
+    QCOMPARE(model.index(0, 0).data(TabModel::WebTabRole).value<WebTab*>(), tab1);
+    QCOMPARE(model.index(1, 0).data(TabModel::WebTabRole).value<WebTab*>(), tab2);
+    QCOMPARE(model.index(2, 0).data(TabModel::WebTabRole).value<WebTab*>(), tab3);
+    QCOMPARE(model.index(3, 0).data(TabModel::WebTabRole).value<WebTab*>(), tab4);
+    QCOMPARE(model.index(4, 0).data(TabModel::WebTabRole).value<WebTab*>(), tab5);
+    QCOMPARE(model.index(5, 0).data(TabModel::WebTabRole).value<WebTab*>(), tab6);
+
+    QPersistentModelIndex tab1index = model.index(0, 0);
+    QPersistentModelIndex tab2index = model.index(1, 0);
+    QPersistentModelIndex tab3index = model.index(2, 0);
+    QPersistentModelIndex tab4index = model.index(3, 0);
+    QPersistentModelIndex tab5index = model.index(4, 0);
+    QPersistentModelIndex tab6index = model.index(5, 0);
+
+    QCOMPARE(model.rowCount(tab1index), 0);
+    tab1->addChildTab(tab2);
+
+    QCOMPARE(model.rowCount(tab1index), 1);
+    QCOMPARE(model.index(0, 0, \
tab1index).data(TabModel::WebTabRole).value<WebTab*>(), tab2); +
+    tab1->addChildTab(tab3);
+    QCOMPARE(model.rowCount(tab1index), 2);
+    QCOMPARE(model.index(0, 0, \
tab1index).data(TabModel::WebTabRole).value<WebTab*>(), tab2); +    \
QCOMPARE(model.index(1, 0, tab1index).data(TabModel::WebTabRole).value<WebTab*>(), \
tab3); +
+    tab1->addChildTab(tab4, 1);
+    QCOMPARE(model.rowCount(tab1index), 3);
+    QCOMPARE(model.index(0, 0, \
tab1index).data(TabModel::WebTabRole).value<WebTab*>(), tab2); +    \
QCOMPARE(model.index(1, 0, tab1index).data(TabModel::WebTabRole).value<WebTab*>(), \
tab4); +    QCOMPARE(model.index(2, 0, \
tab1index).data(TabModel::WebTabRole).value<WebTab*>(), tab3); +
+    tab4->addChildTab(tab5);
+    tab4->addChildTab(tab6);
+
+    QCOMPARE(model.rowCount(tab4index), 2);
+    QCOMPARE(model.index(0, 0, \
tab4index).data(TabModel::WebTabRole).value<WebTab*>(), tab5); +    \
QCOMPARE(model.index(1, 0, tab4index).data(TabModel::WebTabRole).value<WebTab*>(), \
tab6); +
+    w->tabWidget()->closeTab(tab4->tabIndex());
+
+    QCOMPARE(model.rowCount(tab1index), 4);
+    QCOMPARE(model.index(0, 0, \
tab1index).data(TabModel::WebTabRole).value<WebTab*>(), tab2); +    \
QCOMPARE(model.index(1, 0, tab1index).data(TabModel::WebTabRole).value<WebTab*>(), \
tab5); +    QCOMPARE(model.index(2, 0, \
tab1index).data(TabModel::WebTabRole).value<WebTab*>(), tab6); +    \
QCOMPARE(model.index(3, 0, tab1index).data(TabModel::WebTabRole).value<WebTab*>(), \
tab3); +
+    tab1->addChildTab(tab3, 0);
+
+    QCOMPARE(model.rowCount(tab1index), 4);
+    QCOMPARE(model.index(0, 0, \
tab1index).data(TabModel::WebTabRole).value<WebTab*>(), tab3); +    \
QCOMPARE(model.index(1, 0, tab1index).data(TabModel::WebTabRole).value<WebTab*>(), \
tab2); +    QCOMPARE(model.index(2, 0, \
tab1index).data(TabModel::WebTabRole).value<WebTab*>(), tab5); +    \
QCOMPARE(model.index(3, 0, tab1index).data(TabModel::WebTabRole).value<WebTab*>(), \
tab6); +
+    tab2->setParentTab(nullptr);
+
+    QCOMPARE(model.rowCount(tab1index), 3);
+    QCOMPARE(model.index(0, 0).data(TabModel::WebTabRole).value<WebTab*>(), tab2);
+    QCOMPARE(model.index(0, 0, \
tab1index).data(TabModel::WebTabRole).value<WebTab*>(), tab3); +    \
QCOMPARE(model.index(1, 0, tab1index).data(TabModel::WebTabRole).value<WebTab*>(), \
tab5); +    QCOMPARE(model.index(2, 0, \
tab1index).data(TabModel::WebTabRole).value<WebTab*>(), tab6); +
+    w->tabWidget()->closeTab(tab1->tabIndex());
+
+    QCOMPARE(model.rowCount(QModelIndex()), 4);
+    QCOMPARE(model.index(0, 0).data(TabModel::WebTabRole).value<WebTab*>(), tab2);
+    QCOMPARE(model.index(1, 0).data(TabModel::WebTabRole).value<WebTab*>(), tab3);
+    QCOMPARE(model.index(2, 0).data(TabModel::WebTabRole).value<WebTab*>(), tab5);
+    QCOMPARE(model.index(3, 0).data(TabModel::WebTabRole).value<WebTab*>(), tab6);
+
+    QTest::qWait(1);
+    delete w;
+}
 
 FALKONTEST_MAIN(TabModelTest)
diff --git a/autotests/tabmodeltest.h b/autotests/tabmodeltest.h
index 56429984..384d5430 100644
--- a/autotests/tabmodeltest.h
+++ b/autotests/tabmodeltest.h
@@ -29,4 +29,5 @@ private slots:
 
     void basicTest();
     void dataTest();
+    void treeModelTest();
 };
diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt
index 9f91a6ca..097dd759 100644
--- a/src/lib/CMakeLists.txt
+++ b/src/lib/CMakeLists.txt
@@ -180,6 +180,7 @@ set(SRCS ${SRCS}
     tabwidget/tabbar.cpp
     tabwidget/tabicon.cpp
     tabwidget/tabmodel.cpp
+    tabwidget/tabtreemodel.cpp
     tabwidget/tabstackedwidget.cpp
     tabwidget/tabwidget.cpp
     tabwidget/tabcontextmenu.cpp
diff --git a/src/lib/tabwidget/tabtreemodel.cpp b/src/lib/tabwidget/tabtreemodel.cpp
new file mode 100644
index 00000000..02692eb5
--- /dev/null
+++ b/src/lib/tabwidget/tabtreemodel.cpp
@@ -0,0 +1,390 @@
+/* ============================================================
+* Falkon - Qt web browser
+* Copyright (C) 2018 David Rosca <nowrep@gmail.com>
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program.  If not, see <http://www.gnu.org/licenses/>.
+* ============================================================ */
+#include "tabtreemodel.h"
+#include "tabmodel.h"
+#include "webtab.h"
+
+#include <QMimeData>
+
+class TabTreeModelItem
+{
+public:
+    explicit TabTreeModelItem(WebTab *tab = nullptr, const QModelIndex &index = \
QModelIndex()); +    ~TabTreeModelItem();
+
+    bool isRoot() const;
+    void setParent(TabTreeModelItem *item);
+    void addChild(TabTreeModelItem *item, int index = -1);
+
+    WebTab *tab = nullptr;
+    TabTreeModelItem *parent = nullptr;
+    QVector<TabTreeModelItem*> children;
+    QPersistentModelIndex sourceIndex;
+};
+
+TabTreeModelItem::TabTreeModelItem(WebTab *tab, const QModelIndex &index)
+    : tab(tab)
+    , sourceIndex(index)
+{
+}
+
+TabTreeModelItem::~TabTreeModelItem()
+{
+    for (TabTreeModelItem *child : qAsConst(children)) {
+        delete child;
+    }
+}
+
+bool TabTreeModelItem::isRoot() const
+{
+    return !tab;
+}
+
+void TabTreeModelItem::setParent(TabTreeModelItem *item)
+{
+    if (parent == item) {
+        return;
+    }
+    if (parent) {
+        parent->children.removeOne(this);
+    }
+    parent = item;
+    if (parent) {
+        parent->children.append(this);
+    }
+}
+
+void TabTreeModelItem::addChild(TabTreeModelItem *item, int index)
+{
+    item->setParent(nullptr);
+    item->parent = this;
+    if (index < 0 || index > children.size()) {
+        children.append(item);
+    } else {
+        children.insert(index, item);
+    }
+}
+
+TabTreeModel::TabTreeModel(QObject *parent)
+    : QAbstractProxyModel(parent)
+{
+    connect(this, &QAbstractProxyModel::sourceModelChanged, this, \
&TabTreeModel::init); +}
+
+TabTreeModel::~TabTreeModel()
+{
+    delete m_root;
+}
+
+QModelIndex TabTreeModel::tabIndex(WebTab *tab) const
+{
+    TabTreeModelItem *item = m_items.value(tab);
+    if (!item) {
+        return QModelIndex();
+    }
+    return createIndex(item->parent->children.indexOf(item), 0, item);
+}
+
+WebTab *TabTreeModel::tab(const QModelIndex &index) const
+{
+    TabTreeModelItem *it = item(index);
+    return it ? it->tab : nullptr;
+}
+
+Qt::ItemFlags TabTreeModel::flags(const QModelIndex &index) const
+{
+    if (!index.isValid()) {
+        return Qt::ItemIsDropEnabled;
+    }
+    return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | \
Qt::ItemIsDropEnabled; +}
+
+QVariant TabTreeModel::data(const QModelIndex &index, int role) const
+{
+    return sourceModel()->data(mapToSource(index), role);
+}
+
+int TabTreeModel::rowCount(const QModelIndex &parent) const
+{
+    TabTreeModelItem *it = item(parent);
+    if (!it) {
+        return 0;
+    }
+    return it->children.count();
+}
+
+int TabTreeModel::columnCount(const QModelIndex &parent) const
+{
+    if (parent.column() > 0) {
+        return 0;
+    }
+    return 1;
+}
+
+bool TabTreeModel::hasChildren(const QModelIndex &parent) const
+{
+    TabTreeModelItem *it = item(parent);
+    if (!it) {
+        return false;
+    }
+    return !it->children.isEmpty();
+}
+
+QModelIndex TabTreeModel::parent(const QModelIndex &child) const
+{
+    TabTreeModelItem *it = item(child);
+    if (!it) {
+        return QModelIndex();
+    }
+    return index(it->parent);
+}
+
+QModelIndex TabTreeModel::index(int row, int column, const QModelIndex &parent) \
const +{
+    if (!hasIndex(row, column, parent)) {
+        return QModelIndex();
+    }
+    TabTreeModelItem *parentItem = item(parent);
+    return createIndex(row, column, parentItem->children.at(row));
+}
+
+QModelIndex TabTreeModel::mapFromSource(const QModelIndex &sourceIndex) const
+{
+    return tabIndex(sourceIndex.data(TabModel::WebTabRole).value<WebTab*>());
+}
+
+QModelIndex TabTreeModel::mapToSource(const QModelIndex &proxyIndex) const
+{
+    TabTreeModelItem *it = item(proxyIndex);
+    if (!it) {
+        return QModelIndex();
+    }
+    return it->sourceIndex;
+}
+
+bool TabTreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int \
row, int column, const QModelIndex &parent) +{
+    if (action == Qt::IgnoreAction) {
+        return true;
+    }
+
+    const QString mimeType = mimeTypes().at(0);
+
+    if (!data->hasFormat(mimeType) || column > 0) {
+        return false;
+    }
+
+    QByteArray encodedData = data->data(mimeType);
+    QDataStream stream(&encodedData, QIODevice::ReadOnly);
+
+    QVector<WebTab*> tabs;
+    while (!stream.atEnd()) {
+        int index;
+        stream >> index;
+        WebTab *tab = sourceModel()->index(index, \
0).data(TabModel::WebTabRole).value<WebTab*>(); +        if (tab) {
+            tabs.append(tab);
+        }
+    }
+
+    if (tabs.isEmpty()) {
+        return false;
+    }
+
+    // Only support moving one tab
+    WebTab *tab = tabs.at(0);
+
+    TabTreeModelItem *it = m_items.value(tab);
+    TabTreeModelItem *parentItem = item(parent);
+    if (!it || !parentItem) {
+        return false;
+    }
+
+    if (!parentItem->tab) {
+        tab->setParentTab(nullptr);
+        if (row < 0) {
+            row = m_root->children.count();
+        }
+        const QModelIndex fromIdx = index(it);
+        const int childPos = row > fromIdx.row() ? row - 1 : row;
+        if (!beginMoveRows(fromIdx.parent(), fromIdx.row(), fromIdx.row(), \
QModelIndex(), row)) { +            qWarning() << "Invalid beginMoveRows" << \
fromIdx.parent() << fromIdx.row() << "root" << row; +            return true;
+        }
+        m_root->addChild(it, childPos);
+        endMoveRows();
+    } else {
+        parentItem->tab->addChildTab(tab, row);
+    }
+
+    return true;
+}
+
+void TabTreeModel::init()
+{
+    delete m_root;
+    m_items.clear();
+
+    m_root = new TabTreeModelItem;
+
+    for (int i = 0; i < sourceModel()->rowCount(); ++i) {
+        const QModelIndex index = sourceModel()->index(i, 0);
+        WebTab *tab = index.data(TabModel::WebTabRole).value<WebTab*>();
+        if (tab && !tab->parentTab()) {
+            TabTreeModelItem *item = new TabTreeModelItem(tab, index);
+            m_items[tab] = item;
+            m_root->addChild(createItems(item));
+        }
+    }
+
+    for (TabTreeModelItem *item : qAsConst(m_items)) {
+        connectTab(item->tab);
+    }
+
+    connect(sourceModel(), &QAbstractItemModel::dataChanged, this, \
&TabTreeModel::sourceDataChanged); +    connect(sourceModel(), \
&QAbstractItemModel::rowsInserted, this, &TabTreeModel::sourceRowsInserted); +    \
connect(sourceModel(), &QAbstractItemModel::rowsAboutToBeRemoved, this, \
&TabTreeModel::sourceRowsAboutToBeRemoved); +}
+
+QModelIndex TabTreeModel::index(TabTreeModelItem *item) const
+{
+    if (!item || item == m_root) {
+        return QModelIndex();
+    }
+    return createIndex(item->parent->children.indexOf(item), 0, item);
+}
+
+TabTreeModelItem *TabTreeModel::item(const QModelIndex &index) const
+{
+    TabTreeModelItem *it = static_cast<TabTreeModelItem*>(index.internalPointer());
+    return it ? it : m_root;
+}
+
+TabTreeModelItem *TabTreeModel::createItems(TabTreeModelItem *root)
+{
+    const auto children = root->tab->childTabs();
+    for (WebTab *child : children) {
+        const QModelIndex index = sourceModel()->index(child->tabIndex(), 0);
+        TabTreeModelItem *item = new TabTreeModelItem(child, index);
+        m_items[child] = item;
+        root->addChild(createItems(item));
+    }
+    return root;
+}
+
+void TabTreeModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex \
&bottomRight, const QVector<int> &roles) +{
+    emit dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight), roles);
+}
+
+void TabTreeModel::sourceRowsInserted(const QModelIndex &parent, int start, int end)
+{
+    for (int i = start; i <= end; ++i) {
+        insertIndex(sourceModel()->index(i, 0, parent));
+    }
+}
+
+void TabTreeModel::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, \
int end) +{
+    for (int i = start; i <= end; ++i) {
+        removeIndex(sourceModel()->index(i, 0, parent));
+    }
+}
+
+void TabTreeModel::insertIndex(const QModelIndex &sourceIndex)
+{
+    WebTab *tab = sourceIndex.data(TabModel::WebTabRole).value<WebTab*>();
+    if (!tab) {
+        return;
+    }
+    TabTreeModelItem *parent = m_items.value(tab->parentTab());
+    if (!parent) {
+        parent = m_root;
+    }
+    TabTreeModelItem *item = new TabTreeModelItem(tab, sourceIndex);
+
+    const int idx = parent->children.count();
+    beginInsertRows(tabIndex(tab->parentTab()), idx, idx);
+    m_items[tab] = item;
+    parent->addChild(item);
+    endInsertRows();
+
+    connectTab(tab);
+}
+
+void TabTreeModel::removeIndex(const QModelIndex &sourceIndex)
+{
+    WebTab *tab = sourceIndex.data(TabModel::WebTabRole).value<WebTab*>();
+    if (!tab) {
+        return;
+    }
+    TabTreeModelItem *item = m_items.value(tab);
+    if (!item) {
+        return;
+    }
+
+    const QModelIndex index = mapFromSource(sourceIndex);
+    beginRemoveRows(index.parent(), index.row(), index.row());
+    item->setParent(nullptr);
+    Q_ASSERT(item->children.isEmpty());
+    delete item;
+    endRemoveRows();
+
+    tab->disconnect(this);
+}
+
+void TabTreeModel::connectTab(WebTab *tab)
+{
+    TabTreeModelItem *item = m_items.value(tab);
+    Q_ASSERT(item);
+
+    connect(tab, &WebTab::parentTabChanged, this, [=](WebTab *parent) {
+        // Handle only move to root, everything else is done in childTabAdded
+        if (item->parent == m_root || parent) {
+            return;
+        }
+        int pos = m_root->children.count();
+        // Move it to the same spot as old parent
+        if (item->parent->parent == m_root) {
+            pos = m_root->children.indexOf(item->parent);
+        }
+        const QModelIndex fromIdx = index(item);
+        if (!beginMoveRows(fromIdx.parent(), fromIdx.row(), fromIdx.row(), \
QModelIndex(), pos)) { +            qWarning() << "Invalid beginMoveRows" << \
fromIdx.parent() << fromIdx.row() << "root" << pos; +            return;
+        }
+        m_root->addChild(item, pos);
+        endMoveRows();
+    });
+
+    connect(tab, &WebTab::childTabAdded, this, [=](WebTab *child, int pos) {
+        TabTreeModelItem *from = m_items.value(child);
+        if (!from) {
+            return;
+        }
+        const QModelIndex fromIdx = index(from);
+        const QModelIndex toIdx = index(item);
+        const int childPos = fromIdx.parent() == toIdx && pos > fromIdx.row() ? pos \
- 1 : pos; +        if (!beginMoveRows(fromIdx.parent(), fromIdx.row(), \
fromIdx.row(), toIdx, pos)) { +            qWarning() << "Invalid beginMoveRows" << \
fromIdx.parent() << fromIdx.row() << toIdx << pos; +            return;
+        }
+        item->addChild(from, childPos);
+        endMoveRows();
+    });
+}
diff --git a/src/lib/tabwidget/tabtreemodel.h b/src/lib/tabwidget/tabtreemodel.h
new file mode 100644
index 00000000..3e1e86ed
--- /dev/null
+++ b/src/lib/tabwidget/tabtreemodel.h
@@ -0,0 +1,67 @@
+/* ============================================================
+* Falkon - Qt web browser
+* Copyright (C) 2018 David Rosca <nowrep@gmail.com>
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program.  If not, see <http://www.gnu.org/licenses/>.
+* ============================================================ */
+#pragma once
+
+#include <QAbstractProxyModel>
+
+#include "qzcommon.h"
+
+class WebTab;
+class TabTreeModelItem;
+
+class FALKON_EXPORT TabTreeModel : public QAbstractProxyModel
+{
+    Q_OBJECT
+
+public:
+    explicit TabTreeModel(QObject *parent = nullptr);
+    ~TabTreeModel();
+
+    QModelIndex tabIndex(WebTab *tab) const;
+    WebTab *tab(const QModelIndex &index) const;
+
+    Qt::ItemFlags flags(const QModelIndex &index) const override;
+    QVariant data(const QModelIndex &index, int role) const override;
+    int rowCount(const QModelIndex &parent) const override;
+    int columnCount(const QModelIndex &parent) const override;
+    bool hasChildren(const QModelIndex &parent) const override;
+    QModelIndex parent(const QModelIndex &child) const override;
+    QModelIndex index(int row, int column, const QModelIndex &parent = \
QModelIndex()) const override; +
+    QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override;
+    QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;
+
+    bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int \
column, const QModelIndex &parent) override; +
+private:
+    void init();
+    QModelIndex index(TabTreeModelItem *item) const;
+    TabTreeModelItem *item(const QModelIndex &index) const;
+    TabTreeModelItem *createItems(TabTreeModelItem *root);
+
+    void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex \
&bottomRight, const QVector<int> &roles); +    void sourceRowsInserted(const \
QModelIndex &parent, int start, int end); +    void sourceRowsAboutToBeRemoved(const \
QModelIndex &parent, int start, int end); +
+    void insertIndex(const QModelIndex &sourceIndex);
+    void removeIndex(const QModelIndex &sourceIndex);
+    void connectTab(WebTab *tab);
+
+    TabTreeModelItem *m_root = nullptr;
+    QHash<WebTab*, TabTreeModelItem*> m_items;
+};
diff --git a/src/lib/webtab/webtab.cpp b/src/lib/webtab/webtab.cpp
index e746eee8..0883ab8e 100644
--- a/src/lib/webtab/webtab.cpp
+++ b/src/lib/webtab/webtab.cpp
@@ -444,12 +444,17 @@ void WebTab::setParentTab(WebTab *tab)
 
 void WebTab::addChildTab(WebTab *tab, int index)
 {
-    if (tab->parentTab()) {
-        tab->setParentTab(nullptr);
-    }
-
     tab->m_parentTab = this;
 
+    WebTab *tabParent = tab->m_parentTab;
+    if (tabParent) {
+        const int index = tabParent->m_childTabs.indexOf(tab);
+        if (index >= 0) {
+            tabParent->m_childTabs.removeAt(index);
+            emit tabParent->childTabRemoved(tab, index);
+        }
+    }
+
     if (index < 0 || index > m_childTabs.size()) {
         m_childTabs.append(tab);
         emit childTabAdded(tab, m_childTabs.size() - 1);


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic