File indexing completed on 2024-05-12 04:58:24

0001 /* ============================================================
0002 * Falkon - Qt web browser
0003 * Copyright (C) 2018 David Rosca <nowrep@gmail.com>
0004 *
0005 * This program is free software: you can redistribute it and/or modify
0006 * it under the terms of the GNU General Public License as published by
0007 * the Free Software Foundation, either version 3 of the License, or
0008 * (at your option) any later version.
0009 *
0010 * This program is distributed in the hope that it will be useful,
0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013 * GNU General Public License for more details.
0014 *
0015 * You should have received a copy of the GNU General Public License
0016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0017 * ============================================================ */
0018 #include "tabmrumodel.h"
0019 #include "tabmodel.h"
0020 #include "webtab.h"
0021 #include "tabwidget.h"
0022 #include "browserwindow.h"
0023 
0024 class TabMruModelItem
0025 {
0026 public:
0027     explicit TabMruModelItem(WebTab *tab = nullptr, const QModelIndex &index = QModelIndex());
0028     ~TabMruModelItem();
0029 
0030     WebTab *tab = nullptr;
0031     QVector<TabMruModelItem*> children;
0032     QPersistentModelIndex sourceIndex;
0033 };
0034 
0035 TabMruModelItem::TabMruModelItem(WebTab *tab, const QModelIndex &index)
0036     : tab(tab)
0037     , sourceIndex(index)
0038 {
0039 }
0040 
0041 TabMruModelItem::~TabMruModelItem()
0042 {
0043     qDeleteAll(children);
0044 }
0045 
0046 TabMruModel::TabMruModel(BrowserWindow *window, QObject *parent)
0047     : QAbstractProxyModel(parent)
0048     , m_window(window)
0049 {
0050     connect(this, &QAbstractProxyModel::sourceModelChanged, this, &TabMruModel::init);
0051 }
0052 
0053 TabMruModel::~TabMruModel()
0054 {
0055     delete m_root;
0056 }
0057 
0058 QModelIndex TabMruModel::tabIndex(WebTab *tab) const
0059 {
0060     TabMruModelItem *item = m_items.value(tab);
0061     return item ? createIndex(m_root->children.indexOf(item), 0, item) : QModelIndex();
0062 }
0063 
0064 WebTab *TabMruModel::tab(const QModelIndex &index) const
0065 {
0066     TabMruModelItem *it = item(index);
0067     return it ? it->tab : nullptr;
0068 }
0069 
0070 Qt::ItemFlags TabMruModel::flags(const QModelIndex &index) const
0071 {
0072     if (!index.isValid()) {
0073         return Qt::NoItemFlags;
0074     }
0075     return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
0076 }
0077 
0078 int TabMruModel::rowCount(const QModelIndex &parent) const
0079 {
0080     if (parent.isValid()) {
0081         return 0;
0082     }
0083     return m_items.count();
0084 }
0085 
0086 int TabMruModel::columnCount(const QModelIndex &parent) const
0087 {
0088     if (parent.column() > 0) {
0089         return 0;
0090     }
0091     return 1;
0092 }
0093 
0094 QModelIndex TabMruModel::parent(const QModelIndex &index) const
0095 {
0096     Q_UNUSED(index)
0097     return {};
0098 }
0099 
0100 QModelIndex TabMruModel::index(int row, int column, const QModelIndex &parent) const
0101 {
0102     if (!hasIndex(row, column, parent)) {
0103         return {};
0104     }
0105     return createIndex(row, column, m_root->children.at(row));
0106 }
0107 
0108 QModelIndex TabMruModel::mapFromSource(const QModelIndex &sourceIndex) const
0109 {
0110     return tabIndex(sourceIndex.data(TabModel::WebTabRole).value<WebTab*>());
0111 }
0112 
0113 QModelIndex TabMruModel::mapToSource(const QModelIndex &proxyIndex) const
0114 {
0115     TabMruModelItem *it = item(proxyIndex);
0116     if (!it) {
0117         return {};
0118     }
0119     return it->sourceIndex;
0120 }
0121 
0122 void TabMruModel::init()
0123 {
0124     delete m_root;
0125     m_items.clear();
0126 
0127     m_root = new TabMruModelItem;
0128     sourceRowsInserted(QModelIndex(), 0, sourceModel()->rowCount());
0129     currentTabChanged(m_window->tabWidget()->currentIndex());
0130 
0131     connect(m_window->tabWidget(), &TabWidget::currentChanged, this, &TabMruModel::currentTabChanged, Qt::UniqueConnection);
0132     connect(sourceModel(), &QAbstractItemModel::dataChanged, this, &TabMruModel::sourceDataChanged, Qt::UniqueConnection);
0133     connect(sourceModel(), &QAbstractItemModel::rowsInserted, this, &TabMruModel::sourceRowsInserted, Qt::UniqueConnection);
0134     connect(sourceModel(), &QAbstractItemModel::rowsAboutToBeRemoved, this, &TabMruModel::sourceRowsAboutToBeRemoved, Qt::UniqueConnection);
0135     connect(sourceModel(), &QAbstractItemModel::modelReset, this, &TabMruModel::sourceReset, Qt::UniqueConnection);
0136 }
0137 
0138 QModelIndex TabMruModel::index(TabMruModelItem *item) const
0139 {
0140     if (!item || item == m_root) {
0141         return {};
0142     }
0143     return createIndex(m_root->children.indexOf(item), 0, item);
0144 }
0145 
0146 TabMruModelItem *TabMruModel::item(const QModelIndex &index) const
0147 {
0148     return static_cast<TabMruModelItem*>(index.internalPointer());
0149 }
0150 
0151 void TabMruModel::currentTabChanged(int index)
0152 {
0153     TabMruModelItem *it = item(mapFromSource(sourceModel()->index(index, 0)));
0154     if (!it) {
0155         return;
0156     }
0157     const int from = m_root->children.indexOf(it);
0158     if (from == 0) {
0159         return;
0160     }
0161     if (!beginMoveRows(QModelIndex(), from, from, QModelIndex(), 0)) {
0162         qWarning() << "Invalid beginMoveRows" << from;
0163         return;
0164     }
0165     m_root->children.removeAt(from);
0166     m_root->children.insert(0, it);
0167     endMoveRows();
0168 }
0169 
0170 void TabMruModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
0171 {
0172     Q_EMIT dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight), roles);
0173 }
0174 
0175 void TabMruModel::sourceRowsInserted(const QModelIndex &parent, int start, int end)
0176 {
0177     for (int i = start; i <= end; ++i) {
0178         const QModelIndex index = sourceModel()->index(i, 0, parent);
0179         auto *tab = index.data(TabModel::WebTabRole).value<WebTab*>();
0180         if (tab) {
0181             beginInsertRows(QModelIndex(), m_items.count(), m_items.count());
0182             auto *item = new TabMruModelItem(tab, index);
0183             m_items[tab] = item;
0184             m_root->children.append(item);
0185             endInsertRows();
0186         }
0187     }
0188 }
0189 
0190 void TabMruModel::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
0191 {
0192     for (int i = start; i <= end; ++i) {
0193         const QModelIndex index = sourceModel()->index(i, 0, parent);
0194         TabMruModelItem *it = item(mapFromSource(index));
0195         if (it) {
0196             const int idx = m_root->children.indexOf(it);
0197             beginRemoveRows(QModelIndex(), idx, idx);
0198             m_items.remove(it->tab);
0199             m_root->children.removeAt(idx);
0200             delete it;
0201             endRemoveRows();
0202         }
0203     }
0204 }
0205 
0206 void TabMruModel::sourceReset()
0207 {
0208     beginResetModel();
0209     init();
0210     endResetModel();
0211 }