File indexing completed on 2024-04-28 16:54:24

0001 /*
0002     SPDX-FileCopyrightText: 2004 Esben Mose Hansen <kde@mosehansen.dk>
0003     SPDX-FileCopyrightText: Andrew Stanley-Jones <asj@cban.com>
0004     SPDX-FileCopyrightText: 2000 Carsten Pfeiffer <pfeiffer@kde.org>
0005     SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "history.h"
0010 
0011 #include <QAction>
0012 
0013 #include "historyitem.h"
0014 #include "historymodel.h"
0015 #include "historystringitem.h"
0016 
0017 class CycleBlocker
0018 {
0019 public:
0020     CycleBlocker();
0021     ~CycleBlocker();
0022 
0023     static bool isBlocked();
0024 
0025 private:
0026     static int s_blocker;
0027 };
0028 
0029 int CycleBlocker::s_blocker = 0;
0030 CycleBlocker::CycleBlocker()
0031 {
0032     s_blocker++;
0033 }
0034 
0035 CycleBlocker::~CycleBlocker()
0036 {
0037     s_blocker--;
0038 }
0039 
0040 bool CycleBlocker::isBlocked()
0041 {
0042     return s_blocker;
0043 }
0044 
0045 History::History(QObject *parent)
0046     : QObject(parent)
0047     , m_topIsUserSelected(false)
0048     , m_model(new HistoryModel(this))
0049 {
0050     connect(m_model, &HistoryModel::rowsInserted, this, [this](const QModelIndex &parent, int start) {
0051         Q_UNUSED(parent)
0052         if (start == 0) {
0053             Q_EMIT topChanged();
0054         }
0055         Q_EMIT changed();
0056     });
0057     connect(m_model,
0058             &HistoryModel::rowsMoved,
0059             this,
0060             [this](const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow) {
0061                 Q_UNUSED(sourceParent)
0062                 Q_UNUSED(sourceEnd)
0063                 Q_UNUSED(destinationParent)
0064                 if (sourceStart == 0 || destinationRow == 0) {
0065                     Q_EMIT topChanged();
0066                 }
0067                 Q_EMIT changed();
0068             });
0069     connect(m_model, &HistoryModel::rowsRemoved, this, [this](const QModelIndex &parent, int start) {
0070         Q_UNUSED(parent)
0071         if (start == 0) {
0072             Q_EMIT topChanged();
0073         }
0074         Q_EMIT changed();
0075     });
0076     connect(m_model, &HistoryModel::modelReset, this, &History::changed);
0077     connect(m_model, &HistoryModel::modelReset, this, &History::topChanged);
0078     connect(this, &History::topChanged, [this]() {
0079         m_topIsUserSelected = false;
0080         if (!CycleBlocker::isBlocked()) {
0081             m_cycleStartUuid = QByteArray();
0082         }
0083     });
0084 }
0085 
0086 History::~History()
0087 {
0088 }
0089 
0090 void History::insert(HistoryItemPtr item)
0091 {
0092     if (!item)
0093         return;
0094 
0095     m_model->insert(item);
0096 }
0097 
0098 void History::clearAndBatchInsert(const QVector<HistoryItemPtr> &items)
0099 {
0100     m_model->clearAndBatchInsert(items);
0101 }
0102 
0103 void History::remove(const HistoryItemConstPtr &newItem)
0104 {
0105     if (!newItem)
0106         return;
0107 
0108     m_model->remove(newItem->uuid());
0109 }
0110 
0111 void History::slotClear()
0112 {
0113     m_model->clear();
0114 }
0115 
0116 void History::slotMoveToTop(QAction *action)
0117 {
0118     QByteArray uuid = action->data().toByteArray();
0119     if (uuid.isNull()) // not an action from popupproxy
0120         return;
0121 
0122     slotMoveToTop(uuid);
0123 }
0124 
0125 void History::slotMoveToTop(const QByteArray &uuid)
0126 {
0127     const QModelIndex item = m_model->indexOf(uuid);
0128     if (item.isValid() && item.row() == 0) {
0129         // The item is already at the top, but it still may be not be set as the actual clipboard
0130         // contents, normally this happens if the item is only in the X11 mouse selection but
0131         // not in the Ctrl+V clipboard.
0132         Q_EMIT topChanged();
0133         m_topIsUserSelected = true;
0134         Q_EMIT topIsUserSelectedSet();
0135         return;
0136     }
0137     m_model->moveToTop(uuid);
0138     m_topIsUserSelected = true;
0139     Q_EMIT topIsUserSelectedSet();
0140 }
0141 
0142 void History::setMaxSize(unsigned max_size)
0143 {
0144     m_model->setMaxSize(max_size);
0145 }
0146 
0147 void History::cycleNext()
0148 {
0149     if (m_model->rowCount() < 2) {
0150         return;
0151     }
0152 
0153     if (m_cycleStartUuid.isEmpty()) {
0154         m_cycleStartUuid = m_model->index(0).data(HistoryModel::UuidRole).toByteArray();
0155     } else if (m_cycleStartUuid == m_model->index(1).data(HistoryModel::UuidRole).toByteArray()) {
0156         // end of cycle
0157         return;
0158     }
0159     CycleBlocker blocker;
0160     m_model->moveTopToBack();
0161 }
0162 
0163 void History::cyclePrev()
0164 {
0165     if (m_cycleStartUuid.isEmpty()) {
0166         return;
0167     }
0168     CycleBlocker blocker;
0169     m_model->moveBackToTop();
0170     if (m_cycleStartUuid == m_model->index(0).data(HistoryModel::UuidRole).toByteArray()) {
0171         m_cycleStartUuid = QByteArray();
0172     }
0173 }
0174 
0175 HistoryItemConstPtr History::nextInCycle() const
0176 {
0177     if (m_model->hasIndex(1, 0)) {
0178         if (!m_cycleStartUuid.isEmpty()) {
0179             // check whether we are not at the end
0180             if (m_cycleStartUuid == m_model->index(1).data(HistoryModel::UuidRole).toByteArray()) {
0181                 return HistoryItemConstPtr();
0182             }
0183         }
0184         return m_model->index(1).data(HistoryModel::HistoryItemConstPtrRole).value<HistoryItemConstPtr>();
0185     }
0186     return HistoryItemConstPtr();
0187 }
0188 
0189 HistoryItemConstPtr History::prevInCycle() const
0190 {
0191     if (m_cycleStartUuid.isEmpty()) {
0192         return HistoryItemConstPtr();
0193     }
0194     return m_model->index(m_model->rowCount() - 1).data(HistoryModel::HistoryItemConstPtrRole).value<HistoryItemConstPtr>();
0195 }
0196 
0197 HistoryItemConstPtr History::find(const QByteArray &uuid) const
0198 {
0199     const QModelIndex index = m_model->indexOf(uuid);
0200     if (!index.isValid()) {
0201         return HistoryItemConstPtr();
0202     }
0203     return index.data(HistoryModel::HistoryItemConstPtrRole).value<HistoryItemConstPtr>();
0204 }
0205 
0206 bool History::empty() const
0207 {
0208     return m_model->rowCount() == 0;
0209 }
0210 
0211 unsigned int History::maxSize() const
0212 {
0213     return m_model->maxSize();
0214 }
0215 
0216 HistoryItemConstPtr History::first() const
0217 {
0218     const QModelIndex index = m_model->index(0);
0219     if (!index.isValid()) {
0220         return HistoryItemConstPtr();
0221     }
0222     return index.data(HistoryModel::HistoryItemConstPtrRole).value<HistoryItemConstPtr>();
0223 }