File indexing completed on 2024-12-22 05:15:21
0001 /* 0002 SPDX-FileCopyrightText: 2015 Eike Hein <hein@kde.org> 0003 SPDX-FileCopyrightText: 2017 Ivan Cukic <ivan.cukic@kde.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "placeholdermodel.h" 0009 #include "actionlist.h" 0010 #include "debug.h" 0011 #include <chrono> 0012 0013 using namespace std::chrono_literals; 0014 0015 PlaceholderModel::PlaceholderModel(QObject *parent) 0016 : AbstractModel(parent) 0017 , m_dropPlaceholderIndex(-1) 0018 , m_isTriggerInhibited(false) 0019 { 0020 connect(&m_triggerInhibitor, &QTimer::timeout, this, [&] { 0021 qCDebug(KICKER_DEBUG) << "%%% Inhibit stopped"; 0022 m_isTriggerInhibited = false; 0023 }); 0024 0025 m_triggerInhibitor.setInterval(500ms); 0026 m_triggerInhibitor.setSingleShot(true); 0027 } 0028 0029 void PlaceholderModel::inhibitTriggering() 0030 { 0031 qCDebug(KICKER_DEBUG) << "%%% Inhibit started"; 0032 m_isTriggerInhibited = true; 0033 m_triggerInhibitor.start(); 0034 } 0035 0036 PlaceholderModel::~PlaceholderModel() 0037 { 0038 } 0039 0040 QString PlaceholderModel::description() const 0041 { 0042 if (auto abstractModel = qobject_cast<AbstractModel *>(m_sourceModel)) { 0043 return abstractModel->description(); 0044 0045 } else { 0046 return QString(); 0047 } 0048 } 0049 0050 QAbstractItemModel *PlaceholderModel::sourceModel() const 0051 { 0052 return m_sourceModel; 0053 } 0054 0055 void PlaceholderModel::setSourceModel(QAbstractItemModel *sourceModel) 0056 { 0057 disconnectSignals(); 0058 0059 beginResetModel(); 0060 0061 m_sourceModel = sourceModel; 0062 0063 connectSignals(); 0064 0065 endResetModel(); 0066 0067 Q_EMIT countChanged(); 0068 Q_EMIT sourceModelChanged(); 0069 Q_EMIT descriptionChanged(); 0070 } 0071 0072 bool PlaceholderModel::canFetchMore(const QModelIndex &parent) const 0073 { 0074 return m_sourceModel && m_sourceModel->canFetchMore(indexToSourceIndex(parent)); 0075 } 0076 0077 void PlaceholderModel::fetchMore(const QModelIndex &parent) 0078 { 0079 if (m_sourceModel) { 0080 m_sourceModel->fetchMore(indexToSourceIndex(parent)); 0081 } 0082 } 0083 0084 QModelIndex PlaceholderModel::index(int row, int column, const QModelIndex &parent) const 0085 { 0086 Q_UNUSED(parent) 0087 0088 return m_sourceModel ? createIndex(row, column) : QModelIndex(); 0089 } 0090 0091 QModelIndex PlaceholderModel::parent(const QModelIndex &index) const 0092 { 0093 Q_UNUSED(index) 0094 0095 return QModelIndex(); 0096 } 0097 0098 QVariant PlaceholderModel::data(const QModelIndex &index, int role) const 0099 { 0100 const auto row = index.row(); 0101 0102 if (m_dropPlaceholderIndex == row) { 0103 switch (role) { 0104 case Kicker::IsDropPlaceholderRole: 0105 return true; 0106 0107 // TODO: Maybe it would be nice to show something here? 0108 // case Qt::DisplayRole: 0109 // return "placeholder"; 0110 // 0111 // case Qt::DecorationRole: 0112 // return "select"; 0113 0114 default: 0115 return QVariant(); 0116 } 0117 } 0118 0119 return m_sourceModel ? m_sourceModel->data(indexToSourceIndex(index), role) : QVariant(); 0120 } 0121 0122 int PlaceholderModel::rowCount(const QModelIndex &parent) const 0123 { 0124 if (!m_sourceModel || parent.isValid()) { 0125 return 0; 0126 } 0127 0128 return m_sourceModel->rowCount() + (m_dropPlaceholderIndex != -1 ? 1 : 0); 0129 } 0130 0131 QModelIndex PlaceholderModel::indexToSourceIndex(const QModelIndex &index) const 0132 { 0133 if (!m_sourceModel || !index.isValid()) { 0134 return QModelIndex(); 0135 } 0136 0137 const auto row = index.row(); 0138 const auto column = index.column(); 0139 0140 return index.parent().isValid() ? 0141 // We do not support tree models 0142 QModelIndex() 0143 : 0144 0145 // If we are on top-level, lets add a placeholder 0146 m_sourceModel->index(row - (m_dropPlaceholderIndex != -1 && row > m_dropPlaceholderIndex ? 1 : 0), column, QModelIndex()); 0147 } 0148 0149 int PlaceholderModel::sourceRowToRow(int sourceRow) const 0150 { 0151 return sourceRow + (m_dropPlaceholderIndex != -1 && sourceRow >= m_dropPlaceholderIndex ? 1 : 0); 0152 } 0153 0154 int PlaceholderModel::rowToSourceRow(int row) const 0155 { 0156 return row == m_dropPlaceholderIndex ? -1 : row - (m_dropPlaceholderIndex != -1 && row > m_dropPlaceholderIndex ? 1 : 0); 0157 } 0158 0159 QModelIndex PlaceholderModel::sourceIndexToIndex(const QModelIndex &sourceIndex) const 0160 { 0161 if (!m_sourceModel || !sourceIndex.isValid()) { 0162 return QModelIndex(); 0163 } 0164 0165 const auto sourceRow = sourceIndex.row(); 0166 const auto sourceColumn = sourceIndex.column(); 0167 0168 return sourceIndex.parent().isValid() ? 0169 // We do not support tree-models 0170 QModelIndex() 0171 : 0172 0173 // If we are on top-level, lets add a placeholder 0174 index(sourceRowToRow(sourceRow), sourceColumn, QModelIndex()); 0175 } 0176 0177 bool PlaceholderModel::trigger(int row, const QString &actionId, const QVariant &argument) 0178 { 0179 if (m_isTriggerInhibited) 0180 return false; 0181 0182 if (auto abstractModel = qobject_cast<AbstractModel *>(m_sourceModel)) { 0183 return abstractModel->trigger(rowToSourceRow(row), actionId, argument); 0184 0185 } else { 0186 return false; 0187 } 0188 } 0189 0190 QString PlaceholderModel::labelForRow(int row) 0191 { 0192 if (auto abstractModel = qobject_cast<AbstractModel *>(m_sourceModel)) { 0193 return abstractModel->labelForRow(rowToSourceRow(row)); 0194 0195 } else { 0196 return QString(); 0197 } 0198 } 0199 0200 AbstractModel *PlaceholderModel::modelForRow(int row) 0201 { 0202 if (auto abstractModel = qobject_cast<AbstractModel *>(m_sourceModel)) { 0203 return abstractModel->modelForRow(rowToSourceRow(row)); 0204 0205 } else { 0206 return nullptr; 0207 } 0208 } 0209 0210 AbstractModel *PlaceholderModel::favoritesModel() 0211 { 0212 if (auto abstractModel = qobject_cast<AbstractModel *>(m_sourceModel)) { 0213 return abstractModel->favoritesModel(); 0214 0215 } else { 0216 return AbstractModel::favoritesModel(); 0217 } 0218 } 0219 0220 int PlaceholderModel::separatorCount() const 0221 { 0222 if (auto abstractModel = qobject_cast<AbstractModel *>(m_sourceModel)) { 0223 return abstractModel->separatorCount(); 0224 0225 } else { 0226 return 0; 0227 } 0228 } 0229 0230 void PlaceholderModel::reset() 0231 { 0232 beginResetModel(); 0233 endResetModel(); 0234 Q_EMIT countChanged(); 0235 Q_EMIT separatorCountChanged(); 0236 } 0237 0238 void PlaceholderModel::connectSignals() 0239 { 0240 if (!m_sourceModel) { 0241 return; 0242 } 0243 0244 const auto sourceModelPtr = m_sourceModel.data(); 0245 0246 connect(sourceModelPtr, SIGNAL(destroyed()), this, SLOT(reset())); 0247 0248 connect(sourceModelPtr, &QAbstractItemModel::dataChanged, this, [this](const QModelIndex &from, const QModelIndex &to, const QList<int> &roles) { 0249 Q_EMIT dataChanged(sourceIndexToIndex(from), sourceIndexToIndex(to), roles); 0250 }); 0251 0252 connect(sourceModelPtr, &QAbstractItemModel::rowsAboutToBeInserted, this, [this](const QModelIndex &parent, int from, int to) { 0253 if (parent.isValid()) { 0254 qCWarning(KICKER_DEBUG) << "We do not support tree models"; 0255 0256 } else { 0257 beginInsertRows(QModelIndex(), sourceRowToRow(from), sourceRowToRow(to)); 0258 } 0259 }); 0260 0261 connect(sourceModelPtr, &QAbstractItemModel::rowsInserted, this, [this] { 0262 endInsertRows(); 0263 Q_EMIT countChanged(); 0264 }); 0265 0266 connect(sourceModelPtr, 0267 &QAbstractItemModel::rowsAboutToBeMoved, 0268 this, 0269 [this](const QModelIndex &source, int from, int to, const QModelIndex &dest, int destRow) { 0270 if (source.isValid() || dest.isValid()) { 0271 qCWarning(KICKER_DEBUG) << "We do not support tree models"; 0272 0273 } else { 0274 beginMoveRows(QModelIndex(), sourceRowToRow(from), sourceRowToRow(to), QModelIndex(), sourceRowToRow(destRow)); 0275 } 0276 }); 0277 0278 connect(sourceModelPtr, &QAbstractItemModel::rowsMoved, this, [this] { 0279 endMoveRows(); 0280 }); 0281 0282 connect(sourceModelPtr, &QAbstractItemModel::rowsAboutToBeRemoved, this, [this](const QModelIndex &parent, int from, int to) { 0283 if (parent.isValid()) { 0284 qCWarning(KICKER_DEBUG) << "We do not support tree models"; 0285 0286 } else { 0287 beginRemoveRows(QModelIndex(), sourceRowToRow(from), sourceRowToRow(to)); 0288 } 0289 }); 0290 0291 connect(sourceModelPtr, &QAbstractItemModel::rowsRemoved, this, [this] { 0292 endRemoveRows(); 0293 Q_EMIT countChanged(); 0294 }); 0295 0296 connect(sourceModelPtr, &QAbstractItemModel::modelAboutToBeReset, this, [this] { 0297 beginResetModel(); 0298 }); 0299 0300 connect(sourceModelPtr, &QAbstractItemModel::modelReset, this, [this] { 0301 endResetModel(); 0302 Q_EMIT countChanged(); 0303 }); 0304 0305 // We do not have persistant indices 0306 // connect(sourceModelPtr, &QAbstractItemModel::layoutAboutToBeChanged), 0307 // this, &PlaceholderModel::layoutAboutToBeChanged); 0308 // connect(sourceModelPtr, &QAbstractItemModel::layoutChanged), 0309 // this, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), 0310 // Qt::UniqueConnection); 0311 } 0312 0313 void PlaceholderModel::disconnectSignals() 0314 { 0315 if (!m_sourceModel) { 0316 return; 0317 } 0318 0319 disconnect(m_sourceModel, nullptr, this, nullptr); 0320 } 0321 0322 int PlaceholderModel::dropPlaceholderIndex() const 0323 { 0324 return m_dropPlaceholderIndex; 0325 } 0326 0327 void PlaceholderModel::setDropPlaceholderIndex(int index) 0328 { 0329 if (index == m_dropPlaceholderIndex) 0330 return; 0331 0332 inhibitTriggering(); 0333 0334 if (index == -1 && m_dropPlaceholderIndex != -1) { 0335 // Removing the placeholder 0336 beginRemoveRows(QModelIndex(), m_dropPlaceholderIndex, m_dropPlaceholderIndex); 0337 m_dropPlaceholderIndex = index; 0338 endRemoveRows(); 0339 0340 Q_EMIT countChanged(); 0341 0342 } else if (index != -1 && m_dropPlaceholderIndex == -1) { 0343 // Creating the placeholder 0344 beginInsertRows(QModelIndex(), index, index); 0345 m_dropPlaceholderIndex = index; 0346 endInsertRows(); 0347 0348 Q_EMIT countChanged(); 0349 0350 } else if (m_dropPlaceholderIndex != index) { 0351 // Moving the placeholder 0352 int modelTo = index + (index > m_dropPlaceholderIndex ? 1 : 0); 0353 0354 if (beginMoveRows(QModelIndex(), m_dropPlaceholderIndex, m_dropPlaceholderIndex, QModelIndex(), modelTo)) { 0355 m_dropPlaceholderIndex = index; 0356 endMoveRows(); 0357 } 0358 } 0359 0360 Q_EMIT dropPlaceholderIndexChanged(); 0361 }