You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

406 lines
12 KiB

/***************************************************************************
* Copyright (C) 2015 by Eike Hein <hein@kde.org> *
* Copyright (C) 2017 by Ivan Cukic <ivan.cukic@kde.org> *
* *
* 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 2 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, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
***************************************************************************/
#include "placeholdermodel.h"
#include "actionlist.h"
#include "debug.h"
PlaceholderModel::PlaceholderModel(QObject *parent)
: AbstractModel(parent)
, m_dropPlaceholderIndex(-1)
, m_isTriggerInhibited(false)
{
connect(&m_triggerInhibitor, &QTimer::timeout,
this, [&] {
qCDebug(KICKER_DEBUG) << "%%% Inhibit stopped";
m_isTriggerInhibited = false;
});
m_triggerInhibitor.setInterval(500);
m_triggerInhibitor.setSingleShot(true);
}
void PlaceholderModel::inhibitTriggering()
{
qCDebug(KICKER_DEBUG) << "%%% Inhibit started";
m_isTriggerInhibited = true;
m_triggerInhibitor.start();
}
PlaceholderModel::~PlaceholderModel()
{
}
QString PlaceholderModel::description() const
{
if (auto abstractModel = qobject_cast<AbstractModel *>(m_sourceModel)) {
return abstractModel->description();
} else {
return QString();
}
}
QAbstractItemModel *PlaceholderModel::sourceModel() const
{
return m_sourceModel;
}
void PlaceholderModel::setSourceModel(QAbstractItemModel *sourceModel)
{
disconnectSignals();
beginResetModel();
m_sourceModel = sourceModel;
connectSignals();
endResetModel();
emit countChanged();
emit sourceModelChanged();
emit descriptionChanged();
}
bool PlaceholderModel::canFetchMore(const QModelIndex &parent) const
{
return m_sourceModel && m_sourceModel->canFetchMore(indexToSourceIndex(parent));
}
void PlaceholderModel::fetchMore(const QModelIndex &parent)
{
if (m_sourceModel) {
m_sourceModel->fetchMore(indexToSourceIndex(parent));
}
}
QModelIndex PlaceholderModel::index(int row, int column, const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_sourceModel ? createIndex(row, column)
: QModelIndex();
}
QModelIndex PlaceholderModel::parent(const QModelIndex &index) const
{
Q_UNUSED(index)
return QModelIndex();
}
QVariant PlaceholderModel::data(const QModelIndex &index, int role) const
{
const auto row = index.row();
if (m_dropPlaceholderIndex == row) {
switch (role) {
case Kicker::IsDropPlaceholderRole:
return true;
// TODO: Maybe it would be nice to show something here?
// case Qt::DisplayRole:
// return "placeholder";
//
// case Qt::DecorationRole:
// return "select";
default:
return QVariant();
}
}
return m_sourceModel ? m_sourceModel->data(indexToSourceIndex(index), role)
: QVariant();
}
int PlaceholderModel::rowCount(const QModelIndex &parent) const
{
if (!m_sourceModel || parent.isValid()) {
return 0;
}
return m_sourceModel->rowCount()
+ (m_dropPlaceholderIndex != -1 ? 1 : 0);
}
QModelIndex PlaceholderModel::indexToSourceIndex(const QModelIndex& index) const
{
if (!m_sourceModel || !index.isValid()) {
return QModelIndex();
}
const auto row = index.row();
const auto column = index.column();
return index.parent().isValid() ?
// We do not support tree models
QModelIndex() :
// If we are on top-level, lets add a placeholder
m_sourceModel->index(
row - (m_dropPlaceholderIndex != -1 && row > m_dropPlaceholderIndex ? 1 : 0),
column,
QModelIndex()
);
}
int PlaceholderModel::sourceRowToRow(int sourceRow) const
{
return sourceRow +
(m_dropPlaceholderIndex != -1 && sourceRow >= m_dropPlaceholderIndex ? 1 : 0);
}
int PlaceholderModel::rowToSourceRow(int row) const
{
return row == m_dropPlaceholderIndex ? -1 :
row - (m_dropPlaceholderIndex != -1 && row > m_dropPlaceholderIndex ? 1 : 0);
}
QModelIndex PlaceholderModel::sourceIndexToIndex(const QModelIndex& sourceIndex) const
{
if (!m_sourceModel || !sourceIndex.isValid()) {
return QModelIndex();
}
const auto sourceRow = sourceIndex.row();
const auto sourceColumn = sourceIndex.column();
return sourceIndex.parent().isValid() ?
// We do not support tree-models
QModelIndex() :
// If we are on top-level, lets add a placeholder
index(
sourceRowToRow(sourceRow),
sourceColumn,
QModelIndex()
);
}
bool PlaceholderModel::trigger(int row, const QString &actionId, const QVariant &argument)
{
if (m_isTriggerInhibited) return false;
if (auto abstractModel = qobject_cast<AbstractModel *>(m_sourceModel)) {
return abstractModel->trigger(rowToSourceRow(row), actionId, argument);
} else {
return false;
}
}
QString PlaceholderModel::labelForRow(int row)
{
if (auto abstractModel = qobject_cast<AbstractModel *>(m_sourceModel)) {
return abstractModel->labelForRow(rowToSourceRow(row));
} else {
return QString();
}
}
AbstractModel* PlaceholderModel::modelForRow(int row)
{
if (auto abstractModel = qobject_cast<AbstractModel *>(m_sourceModel)) {
return abstractModel->modelForRow(rowToSourceRow(row));
} else {
return nullptr;
}
}
AbstractModel* PlaceholderModel::favoritesModel()
{
if (auto abstractModel = qobject_cast<AbstractModel *>(m_sourceModel)) {
return abstractModel->favoritesModel();
} else {
return AbstractModel::favoritesModel();
}
}
int PlaceholderModel::separatorCount() const
{
if (auto abstractModel = qobject_cast<AbstractModel *>(m_sourceModel)) {
return abstractModel->separatorCount();
} else {
return 0;
}
}
void PlaceholderModel::reset()
{
beginResetModel();
endResetModel();
emit countChanged();
emit separatorCountChanged();
}
void PlaceholderModel::connectSignals()
{
if (!m_sourceModel) {
return;
}
const auto sourceModelPtr = m_sourceModel.data();
connect(sourceModelPtr, SIGNAL(destroyed()), this, SLOT(reset()));
connect(sourceModelPtr, &QAbstractItemModel::dataChanged,
this, [this] (const QModelIndex &from, const QModelIndex &to, const QVector<int> &roles) {
emit dataChanged(sourceIndexToIndex(from),
sourceIndexToIndex(to),
roles);
});
connect(sourceModelPtr, &QAbstractItemModel::rowsAboutToBeInserted,
this, [this] (const QModelIndex &parent, int from, int to) {
if (parent.isValid()) {
qWarning() << "We do not support tree models";
} else {
beginInsertRows(QModelIndex(),
sourceRowToRow(from),
sourceRowToRow(to));
}
});
connect(sourceModelPtr, &QAbstractItemModel::rowsInserted,
this, [this] {
endInsertRows();
emit countChanged();
});
connect(sourceModelPtr, &QAbstractItemModel::rowsAboutToBeMoved,
this, [this] (const QModelIndex &source, int from, int to, const QModelIndex &dest, int destRow) {
if (source.isValid() || dest.isValid()) {
qWarning() << "We do not support tree models";
} else {
beginMoveRows(QModelIndex(),
sourceRowToRow(from),
sourceRowToRow(to),
QModelIndex(),
sourceRowToRow(destRow));
}
});
connect(sourceModelPtr, &QAbstractItemModel::rowsMoved,
this, [this] {
endMoveRows();
});
connect(sourceModelPtr, &QAbstractItemModel::rowsAboutToBeRemoved,
this, [this] (const QModelIndex &parent, int from, int to) {
if (parent.isValid()) {
qWarning() << "We do not support tree models";
} else {
beginRemoveRows(QModelIndex(),
sourceRowToRow(from),
sourceRowToRow(to));
}
});
connect(sourceModelPtr, &QAbstractItemModel::rowsRemoved,
this, [this] {
endRemoveRows();
emit countChanged();
});
connect(sourceModelPtr, &QAbstractItemModel::modelAboutToBeReset,
this, [this] {
beginResetModel();
});
connect(sourceModelPtr, &QAbstractItemModel::modelReset,
this, [this] {
endResetModel();
emit countChanged();
});
// We do not have persistant indices
// connect(sourceModelPtr, &QAbstractItemModel::layoutAboutToBeChanged),
// this, &PlaceholderModel::layoutAboutToBeChanged);
// connect(sourceModelPtr, &QAbstractItemModel::layoutChanged),
// this, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
// Qt::UniqueConnection);
}
void PlaceholderModel::disconnectSignals()
{
if (!m_sourceModel) {
return;
}
disconnect(m_sourceModel, nullptr, this, nullptr);
}
int PlaceholderModel::dropPlaceholderIndex() const
{
return m_dropPlaceholderIndex;
}
void PlaceholderModel::setDropPlaceholderIndex(int index)
{
if (index == m_dropPlaceholderIndex) return;
inhibitTriggering();
if (index == -1 && m_dropPlaceholderIndex != -1) {
// Removing the placeholder
beginRemoveRows(QModelIndex(), m_dropPlaceholderIndex, m_dropPlaceholderIndex);
m_dropPlaceholderIndex = index;
endRemoveRows();
emit countChanged();
} else if (index != -1 && m_dropPlaceholderIndex == -1) {
// Creating the placeholder
beginInsertRows(QModelIndex(), index, index);
m_dropPlaceholderIndex = index;
endInsertRows();
emit countChanged();
} else if (m_dropPlaceholderIndex != index) {
// Moving the placeholder
int modelTo = index + (index > m_dropPlaceholderIndex ? 1 : 0);
if (beginMoveRows(
QModelIndex(), m_dropPlaceholderIndex, m_dropPlaceholderIndex,
QModelIndex(), modelTo)) {
m_dropPlaceholderIndex = index;
endMoveRows();
}
}
emit dropPlaceholderIndexChanged();
}