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 "tabmodel.h" 0019 #include "webtab.h" 0020 #include "tabwidget.h" 0021 #include "browserwindow.h" 0022 0023 // TabModelMimeData 0024 TabModelMimeData::TabModelMimeData() 0025 : QMimeData() 0026 { 0027 } 0028 0029 WebTab *TabModelMimeData::tab() const 0030 { 0031 return m_tab; 0032 } 0033 0034 void TabModelMimeData::setTab(WebTab *tab) 0035 { 0036 m_tab = tab; 0037 } 0038 0039 bool TabModelMimeData::hasFormat(const QString &format) const 0040 { 0041 return mimeType() == format; 0042 } 0043 0044 QStringList TabModelMimeData::formats() const 0045 { 0046 return {mimeType()}; 0047 } 0048 0049 // static 0050 QString TabModelMimeData::mimeType() 0051 { 0052 return QSL("application/falkon.tabmodel.tab"); 0053 } 0054 0055 // TabModel 0056 TabModel::TabModel(BrowserWindow *window, QObject *parent) 0057 : QAbstractListModel(parent) 0058 , m_window(window) 0059 { 0060 init(); 0061 } 0062 0063 QModelIndex TabModel::tabIndex(WebTab *tab) const 0064 { 0065 const int idx = m_tabs.indexOf(tab); 0066 if (idx < 0) { 0067 return {}; 0068 } 0069 return index(idx); 0070 } 0071 0072 WebTab *TabModel::tab(const QModelIndex &index) const 0073 { 0074 return m_tabs.value(index.row()); 0075 } 0076 0077 int TabModel::rowCount(const QModelIndex &parent) const 0078 { 0079 if (parent.isValid()) { 0080 return 0; 0081 } 0082 return m_tabs.count(); 0083 } 0084 0085 Qt::ItemFlags TabModel::flags(const QModelIndex &index) const 0086 { 0087 if (!index.isValid()) { 0088 return Qt::ItemIsDropEnabled; 0089 } 0090 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled; 0091 } 0092 0093 QVariant TabModel::data(const QModelIndex &index, int role) const 0094 { 0095 if (index.row() < 0 || index.row() > m_tabs.count()) { 0096 return {}; 0097 } 0098 0099 WebTab *t = tab(index); 0100 if (!t) { 0101 return {}; 0102 } 0103 0104 switch (role) { 0105 case WebTabRole: 0106 return QVariant::fromValue(t); 0107 0108 case TitleRole: 0109 case Qt::DisplayRole: 0110 return t->title(); 0111 0112 case IconRole: 0113 case Qt::DecorationRole: 0114 return t->icon(); 0115 0116 case PinnedRole: 0117 return t->isPinned(); 0118 0119 case RestoredRole: 0120 return t->isRestored(); 0121 0122 case CurrentTabRole: 0123 return t->isCurrentTab(); 0124 0125 case LoadingRole: 0126 return t->isLoading(); 0127 0128 case AudioPlayingRole: 0129 return t->isPlaying(); 0130 0131 case AudioMutedRole: 0132 return t->isMuted(); 0133 0134 case BackgroundActivityRole: 0135 return t->backgroundActivity(); 0136 0137 default: 0138 return {}; 0139 } 0140 } 0141 0142 Qt::DropActions TabModel::supportedDropActions() const 0143 { 0144 return Qt::MoveAction; 0145 } 0146 0147 QStringList TabModel::mimeTypes() const 0148 { 0149 return {TabModelMimeData::mimeType()}; 0150 } 0151 0152 QMimeData *TabModel::mimeData(const QModelIndexList &indexes) const 0153 { 0154 if (indexes.isEmpty()) { 0155 return nullptr; 0156 } 0157 auto *tab = indexes.at(0).data(WebTabRole).value<WebTab*>(); 0158 if (!tab) { 0159 return nullptr; 0160 } 0161 auto *mimeData = new TabModelMimeData; 0162 mimeData->setTab(tab); 0163 return mimeData; 0164 } 0165 0166 bool TabModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const 0167 { 0168 Q_UNUSED(row) 0169 if (action != Qt::MoveAction || parent.isValid() || column > 0 || !m_window) { 0170 return false; 0171 } 0172 const auto *mimeData = qobject_cast<const TabModelMimeData*>(data); 0173 if (!mimeData) { 0174 return false; 0175 } 0176 return mimeData->tab(); 0177 } 0178 0179 bool TabModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) 0180 { 0181 if (!canDropMimeData(data, action, row, column, parent)) { 0182 return false; 0183 } 0184 0185 const auto *mimeData = static_cast<const TabModelMimeData*>(data); 0186 WebTab *tab = mimeData->tab(); 0187 0188 if (tab->browserWindow() == m_window) { 0189 if (row < 0) { 0190 row = tab->isPinned() ? m_window->tabWidget()->pinnedTabsCount() : m_window->tabWidget()->count(); 0191 } 0192 tab->moveTab(row > mimeData->tab()->tabIndex() ? row - 1 : row); 0193 } else { 0194 if (row < 0) { 0195 row = m_window->tabCount(); 0196 } 0197 if (tab->browserWindow()) { 0198 tab->browserWindow()->tabWidget()->detachTab(tab); 0199 } 0200 tab->setPinned(row < m_window->tabWidget()->pinnedTabsCount()); 0201 m_window->tabWidget()->insertView(row, tab, Qz::NT_SelectedTab); 0202 } 0203 0204 return true; 0205 } 0206 0207 void TabModel::init() 0208 { 0209 for (int i = 0; i < m_window->tabCount(); ++i) { 0210 tabInserted(i); 0211 } 0212 0213 connect(m_window->tabWidget(), &TabWidget::tabInserted, this, &TabModel::tabInserted); 0214 connect(m_window->tabWidget(), &TabWidget::tabRemoved, this, &TabModel::tabRemoved); 0215 connect(m_window->tabWidget(), &TabWidget::tabMoved, this, &TabModel::tabMoved); 0216 0217 connect(m_window, &QObject::destroyed, this, [this]() { 0218 beginResetModel(); 0219 m_window = nullptr; 0220 m_tabs.clear(); 0221 endResetModel(); 0222 }); 0223 } 0224 0225 void TabModel::tabInserted(int index) 0226 { 0227 WebTab *tab = m_window->tabWidget()->webTab(index); 0228 0229 beginInsertRows(QModelIndex(), index, index); 0230 m_tabs.insert(index, tab); 0231 endInsertRows(); 0232 0233 auto emitDataChanged = [this](WebTab *tab, int role) { 0234 const QModelIndex idx = tabIndex(tab); 0235 Q_EMIT dataChanged(idx, idx, {role}); 0236 }; 0237 0238 connect(tab, &WebTab::titleChanged, this, std::bind(emitDataChanged, tab, Qt::DisplayRole)); 0239 connect(tab, &WebTab::titleChanged, this, std::bind(emitDataChanged, tab, TitleRole)); 0240 connect(tab, &WebTab::iconChanged, this, std::bind(emitDataChanged, tab, Qt::DecorationRole)); 0241 connect(tab, &WebTab::iconChanged, this, std::bind(emitDataChanged, tab, IconRole)); 0242 connect(tab, &WebTab::pinnedChanged, this, std::bind(emitDataChanged, tab, PinnedRole)); 0243 connect(tab, &WebTab::restoredChanged, this, std::bind(emitDataChanged, tab, RestoredRole)); 0244 connect(tab, &WebTab::currentTabChanged, this, std::bind(emitDataChanged, tab, CurrentTabRole)); 0245 connect(tab, &WebTab::loadingChanged, this, std::bind(emitDataChanged, tab, LoadingRole)); 0246 connect(tab, &WebTab::playingChanged, this, std::bind(emitDataChanged, tab, AudioPlayingRole)); 0247 connect(tab, &WebTab::mutedChanged, this, std::bind(emitDataChanged, tab, AudioMutedRole)); 0248 connect(tab, &WebTab::backgroundActivityChanged, this, std::bind(emitDataChanged, tab, BackgroundActivityRole)); 0249 } 0250 0251 void TabModel::tabRemoved(int index) 0252 { 0253 beginRemoveRows(QModelIndex(), index, index); 0254 m_tabs.remove(index); 0255 endRemoveRows(); 0256 } 0257 0258 void TabModel::tabMoved(int from, int to) 0259 { 0260 if (!beginMoveRows(QModelIndex(), from, from, QModelIndex(), to > from ? to + 1 : to)) { 0261 qWarning() << "Invalid beginMoveRows" << from << (to > from ? to + 1 : to); 0262 return; 0263 } 0264 m_tabs.insert(to, m_tabs.takeAt(from)); 0265 endMoveRows(); 0266 }