#include "notelistmodel.h"
#include <QDebug>  // 包含调试输出头文件
#include "nodepath.h"  // 包含节点路径头文件
#include <QTimer>  // 包含定时器头文件
#include <QMimeData>  // 包含MIME数据头文件

NoteListModel::NoteListModel(QObject *parent) : QAbstractListModel(parent) { }

NoteListModel::~NoteListModel() { }
// 添加笔记
QModelIndex NoteListModel::addNote(const NodeData &note)
{
    // 如果笔记不是被钉住的
    if (!note.isPinnedNote()) {
        // 获取当前行数
        const int rowCnt = rowCount();
        // 开始插入行
        beginInsertRows(QModelIndex(), rowCnt, rowCnt);
        // 将笔记添加到笔记列表
        m_noteList << note;
        // 结束插入行
        endInsertRows();
        // 发出行插入信号
        emit rowsInsertedC({ createIndex(rowCnt, 0) });
        // 发出行数变化信号
        emit rowCountChanged();
        // 返回新笔记的模型索引
        return createIndex(rowCnt, 0);
    } else {
        // 获取被钉住的笔记列表的大小
        const int rowCnt = m_pinnedList.size();
        // 开始插入行
        beginInsertRows(QModelIndex(), rowCnt, rowCnt);
        // 将笔记添加到被钉住的笔记列表
        m_pinnedList << note;
        // 结束插入行
        endInsertRows();
        // 发出行插入信号
        emit rowsInsertedC({ createIndex(rowCnt, 0) });
        // 发出行数变化信号
        emit rowCountChanged();
        // 返回新笔记的模型索引
        return createIndex(rowCnt, 0);
    }
}
// 在指定行插入笔记
QModelIndex NoteListModel::insertNote(const NodeData &note, int row)
{   // 如果笔记是被钉住的
    if (note.isPinnedNote()) {
        // 如果指定行大于被钉住的笔记列表的大小，则设置为列表的末尾
        if (row > m_pinnedList.size()) {
            row = m_pinnedList.size();
        } else if (row < 0) {// 如果指定行小于0，则设置为列表的开头
            row = 0;
        }
        // 开始在被钉住的笔记列表的指定行插入一行
        beginInsertRows(QModelIndex(), row, row);
        // 将笔记插入到被钉住的笔记列表的指定行
        m_pinnedList.insert(row, note);
        // 结束插入行
        endInsertRows();
        // 发出新笔记插入信号
        emit rowsInsertedC({ createIndex(row, 0) });
        // 发出行数变化信号
        emit rowCountChanged();
        // 返回新笔记的模型索引
        return createIndex(row, 0);
    } else {
        // 如果指定行小于被钉住的笔记列表的大小，则设置为被钉住的笔记列表的末尾
        if (row < m_pinnedList.size()) {
            row = m_pinnedList.size();
        } else if (row > (m_pinnedList.size() + m_noteList.size())) {
            // 如果指定行大于笔记列表的总大小，则设置为笔记列表的末尾
            row = m_pinnedList.size() + m_noteList.size();
        }
        // 开始在笔记列表的指定行插入一行
        beginInsertRows(QModelIndex(), row, row);
        // 将笔记插入到笔记列表的指定行
        m_noteList.insert(row - m_pinnedList.size(), note);
        // 结束插入行
        endInsertRows();
        // 发出新笔记插入信号
        emit rowsInsertedC({ createIndex(row, 0) });
        // 发出行数变化信号
        emit rowCountChanged();
        // 返回新笔记的模型索引
        return createIndex(row, 0);
    }
}
// 获取指定模型索引的笔记数据
const NodeData &NoteListModel::getNote(const QModelIndex &index) const
{
    // 获取模型索引的行号
    auto row = index.row();
    // 如果行号小于被钉住的笔记列表的大小，则从被钉住的笔记列表中获取笔记数据
    if (row < m_pinnedList.size()) {
        return m_pinnedList.at(row);
    } else {// 否则从笔记列表中获取笔记数据
        row = row - m_pinnedList.size();
        return m_noteList.at(row);
    }
}
// 获取指定ID的笔记的模型索引
QModelIndex NoteListModel::getNoteIndex(int id) const
{ // 在被钉住的笔记列表中查找ID匹配的笔记
    for (int i = 0; i < m_pinnedList.size(); ++i) {
        if (m_pinnedList[i].id() == id) {
            return createIndex(i, 0);
        }
    }
    // 在笔记列表中查找ID匹配的笔记
    for (int i = 0; i < m_noteList.size(); ++i) {
        if (m_noteList[i].id() == id) {
            return createIndex(i + m_pinnedList.size(), 0);
        }
    }// 如果未找到匹配的笔记，则返回无效的模型索引
    return QModelIndex{};
}
// 设置笔记列表和列表视图信息
void NoteListModel::setListNote(const QVector<NodeData> &notes, const ListViewInfo &inf)
{
    // 开始重置模型
    beginResetModel();
    // 清空被钉住的笔记列表
    m_pinnedList.clear();
    // 清空笔记列表
    m_noteList.clear();
    // 设置列表视图信息
    m_listViewInfo = inf;
    // 如果不在标签中且不在回收站文件夹中
    if ((!m_listViewInfo.isInTag)
        && (m_listViewInfo.parentFolderId != SpecialNodeID::TrashFolder)) {
        // 遍历笔记列表
        for (const auto &note : qAsConst(notes)) {
            // 如果笔记是被钉住的，则添加到被钉住的笔记列表
            if (note.isPinnedNote()) {
                m_pinnedList.append(note);
            } else {// 否则添加到笔记列表
                m_noteList.append(note);
            }
        }
    } else { // 否则直接将笔记列表赋值给笔记列表
        m_noteList = notes;
    }
    // 按升序排序
    sort(0, Qt::AscendingOrder);
    // 结束重置模型
    endResetModel();
    // 发出行数变化信号
    emit rowCountChanged();
}
// 移除指定模型索引列表的笔记
void NoteListModel::removeNotes(const QModelIndexList &noteIndexes)
{
    emit requestRemoveNotes(noteIndexes);// 发出请求移除笔记信号
}
// 移动行
bool NoteListModel::moveRow(const QModelIndex &sourceParent, int sourceRow,
                            const QModelIndex &destinationParent, int destinationChild)
{// 如果源行号或目标行号超出范围，则返回false
    if (sourceRow < 0 || sourceRow >= rowCount() || destinationChild < 0
        || destinationChild >= rowCount()) {
        return false;
    }// 如果源行号和目标行号都在被钉住的笔记列表范围内
    if (sourceRow < m_pinnedList.size() && destinationChild < m_pinnedList.size()) {
        if (beginMoveRows(sourceParent, sourceRow, sourceRow, destinationParent,
                          destinationChild)) {// 在被钉住的笔记列表中移动笔记
            m_pinnedList.move(sourceRow, destinationChild);
            // 结束移动行
            endMoveRows();
            // 发出行即将被移动信号
            emit rowsAboutToBeMovedC({ createIndex(sourceRow, 0) });
            // 发出行移动后信号
            emit rowsMovedC({ createIndex(destinationChild, 0) });
            // 发出行数变化信号
            return true;
        }
    }
    // 如果源行号和目标行号都在笔记列表范围内
    if (sourceRow >= m_pinnedList.size() && destinationChild >= m_pinnedList.size()) {
        // 调整源行号和目标行号以适应笔记列表的范围
        sourceRow = sourceRow - m_pinnedList.size();
        destinationChild = destinationChild - m_pinnedList.size();
        // 开始移动行
        if (beginMoveRows(sourceParent, sourceRow, sourceRow, destinationParent,
                          destinationChild)) {
            // 在笔记列表中移动笔记
            m_noteList.move(sourceRow, destinationChild);
            // 结束移动行
            // 发出行即将被移动信号
            emit rowsAboutToBeMovedC({ createIndex(sourceRow, 0) });
            // 发出行移动后信号
            emit rowsMovedC({ createIndex(destinationChild + 1, 0) });
            // 发出行数变化信号
            emit rowCountChanged();
            return true;
        }
    }
    // 如果源行号和目标行号不在同一范围内，则返回false
    return false;
}
// 清空笔记列表
void NoteListModel::clearNotes()
{
    // 开始重置模型
    beginResetModel();
    // 清空被钉住的笔记列表
    m_pinnedList.clear();
    // 清空笔记列表
    m_noteList.clear();
    // 结束重置模型
    endResetModel();
    // 发出行数变化信号
    emit rowCountChanged();
}
// 获取指定模型索引的数据的实现
QVariant NoteListModel::data(const QModelIndex &index, int role) const
{
    // 如果模型索引的行号超出范围，则返回空的QVariant
    if (index.row() < 0 || index.row() >= (m_noteList.count() + m_pinnedList.count())) {
        return QVariant();
    }
    // 如果角色超出范围，则返回空的QVariant
    if (role < NoteID || role > NoteIsPinned) {
        return QVariant();
    }
    // 获取指定行的笔记数据
    const NodeData &note = getRef(index.row());
    // 根据角色返回相应的数据
    if (role == NoteID) {
        return note.id();
    } else if (role == NoteFullTitle) {
        auto text = note.fullTitle().trimmed();
        if (text.startsWith("#")) {
            text.remove(0, 1);
            text = text.trimmed();
        }
        return text;
    } else if (role == NoteCreationDateTime) {
        return note.creationDateTime();
    } else if (role == NoteLastModificationDateTime) {
        return note.lastModificationdateTime();
    } else if (role == NoteDeletionDateTime) {
        return note.deletionDateTime();
    } else if (role == NoteContent) {
        return note.content();
    } else if (role == NoteScrollbarPos) {
        return note.scrollBarPosition();
    } else if (role == NoteTagsList) {
        return QVariant::fromValue(note.tagIds());
    } else if (role == NoteIsTemp) {
        return note.isTempNote();
    } else if (role == NoteParentName) {
        return note.parentName();
    } else if (role == NoteTagListScrollbarPos) {
        return note.tagListScrollBarPos();
    } else if (role == NoteIsPinned) {
        return note.isPinnedNote();
    }

    return QVariant();
}
// 设置指定模型索引的数据的实现
bool NoteListModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    // 如果模型索引的行号超出范围，则返回false
    if (index.row() < 0 || index.row() >= (m_noteList.count() + m_pinnedList.count())) {
        return false;
    }
    // 获取指定行的笔记数据的引用
    NodeData &note = getRef(index.row());
    // 根据角色设置相应的数据
    if (role == NoteID) {
        note.setId(value.toInt());
    } else if (role == NoteFullTitle) {
        note.setFullTitle(value.toString());
    } else if (role == NoteCreationDateTime) {
        note.setCreationDateTime(value.toDateTime());
    } else if (role == NoteLastModificationDateTime) {
        note.setLastModificationDateTime(value.toDateTime());
    } else if (role == NoteDeletionDateTime) {
        note.setDeletionDateTime(value.toDateTime());
    } else if (role == NoteContent) {
        note.setContent(value.toString());
    } else if (role == NoteScrollbarPos) {
        note.setScrollBarPosition(value.toInt());
    } else if (role == NoteTagsList) {
        note.setTagIds(value.value<QSet<int>>());
    } else if (role == NoteIsTemp) {
        note.setIsTempNote(value.toBool());
    } else if (role == NoteParentName) {
        note.setParentName(value.toString());
    } else if (role == NoteTagListScrollbarPos) {
        note.setTagListScrollBarPos(value.toInt());
    } else {
        return false;
    }
    // 发出数据变化信号
    emit dataChanged(this->index(index.row()), this->index(index.row()), QVector<int>(1, role));
    return true;
}
// 获取指定模型索引的项标志
Qt::ItemFlags NoteListModel::flags(const QModelIndex &index) const
{
    // 如果模型索引无效，则返回启用和可放置的项标志
    if (!index.isValid()) {
        return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled;
    }
    // 返回基类的项标志，并添加可编辑、可拖拽和可放置的项标志
    return QAbstractListModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled
            | Qt::ItemIsDropEnabled;
}
// 获取行数
int NoteListModel::rowCount(const QModelIndex &parent) const
{
    // 忽略parent参数
    Q_UNUSED(parent)
    // 返回笔记列表和被钉住的笔记列表的总大小
    return m_noteList.size() + m_pinnedList.size();
}

// 排序
void NoteListModel::sort(int column, Qt::SortOrder order)
{
    // 忽略column和order参数
    Q_UNUSED(column)
    Q_UNUSED(order)
    // 如果在回收站文件夹中
    if (m_listViewInfo.parentFolderId == SpecialNodeID::TrashFolder) {
        // 按删除日期时间降序排序笔记列表
        std::stable_sort(m_noteList.begin(), m_noteList.end(),
                         [](const NodeData &lhs, const NodeData &rhs) {
                             return lhs.deletionDateTime() > rhs.deletionDateTime();
                         });
    } else {// 否则按相对位置升序排序被钉住的笔记列表
        std::stable_sort(m_pinnedList.begin(), m_pinnedList.end(),
                         [this](const NodeData &lhs, const NodeData &rhs) {
                             if (isInAllNote()) {
                                 return lhs.relativePosAN() < rhs.relativePosAN();
                             } else {
                                 return lhs.relativePosition() < rhs.relativePosition();
                             }
                         });
        // 按最后修改日期时间降序排序笔记列表
        std::stable_sort(m_noteList.begin(), m_noteList.end(),
                         [](const NodeData &lhs, const NodeData &rhs) {
                             return lhs.lastModificationdateTime() > rhs.lastModificationdateTime();
                         });
    }
    // 发出数据变化信号
    emit dataChanged(index(0), index(rowCount() - 1));
}

// 设置指定模型索引的笔记数据
void NoteListModel::setNoteData(const QModelIndex &index, const NodeData &note)
{
    // 如果模型索引无效，则返回
    if (!index.isValid()) {
        return;
    }
    auto row = index.row();// 获取模型索引的行号
    // 如果行号小于被钉住的笔记列表的大小，则在被钉住的笔记列表中设置笔记数据
    if (row < m_pinnedList.size()) {
        m_pinnedList[row] = note;
    } else { // 否则在笔记列表中设置笔记数据
        row = row - m_pinnedList.size();
        m_noteList[row] = note;
    }
    // 发出数据变化信号
    emit dataChanged(this->index(index.row()), this->index(index.row()));
}

// 更新被钉住的笔记的相对位置的实现
void NoteListModel::updatePinnedRelativePosition()
{
    // 遍历被钉住的笔记列表
    for (int i = 0; i < m_pinnedList.size(); ++i) {
        // 如果不在所有笔记中
        if (!isInAllNote()) {
            // 发出请求更新笔记的相对位置信号
            emit requestUpdatePinnedRelPos(m_pinnedList[i].id(), i);
        } else { // 否则发出请求更新笔记的相对位置（在所有笔记中）信号
            emit requestUpdatePinnedRelPosAN(m_pinnedList[i].id(), i);
        }
    }
}
// 检查是否在所有笔记中
bool NoteListModel::isInAllNote() const
{
    return (!m_listViewInfo.isInTag)// 如果不在标签中且在根文件夹中，则返回true
            && (m_listViewInfo.parentFolderId == SpecialNodeID::RootFolder);
}

// 获取指定行的笔记数据的引用
NodeData &NoteListModel::getRef(int row)
{
    // 如果行号小于被钉住的笔记列表的大小，则从被钉住的笔记列表中获取笔记数据的引用
    if (row < m_pinnedList.size())
        return m_pinnedList[row];
    // 否则从笔记列表中获取笔记数据的引用
    return m_noteList[row - m_pinnedList.size()];
}
// 获取指定行的笔记数据的常量引用
const NodeData &NoteListModel::getRef(int row) const
{
    // 如果行号小于被钉住的笔记列表的大小，则从被钉住的笔记列表中获取笔记数据的常量引用
    if (row < m_pinnedList.size())
        return m_pinnedList[row];
    // 否则从笔记列表中获取笔记数据的常量引用
    return m_noteList[row - m_pinnedList.size()];
}
// 移除行
bool NoteListModel::removeRows(int row, int count, const QModelIndex &parent)
{
    if (row < 0 || (row + count) > (m_pinnedList.size() + m_noteList.size())) {// 如果行号或行数超出范围，则返回false
        return false;
    }
    beginRemoveRows(parent, row, row + count - 1);// 开始移除行
    for (int r = row; r < row + count; ++r) {// 遍历要移除的行
        // 如果行号小于被钉住的笔记列表的大小，则从被钉住的笔记列表中移除笔记
        if (r < m_pinnedList.size()) {
            m_pinnedList.takeAt(r);
        } else {// 否则从笔记列表中移除笔记
            auto rr = r - m_pinnedList.size();
            m_noteList.takeAt(rr);
        }
    }// 结束移除行
    endRemoveRows();
    emit rowCountChanged();// 发出行数变化信号
    return true;
}
// 获取支持的拖放操作
Qt::DropActions NoteListModel::supportedDropActions() const
{
    return Qt::MoveAction;// 返回移动操作
}
// 获取支持的拖拽操作
Qt::DropActions NoteListModel::supportedDragActions() const
{
    return Qt::MoveAction;// 返回移动操作
}
// 获取支持的MIME类型
QStringList NoteListModel::mimeTypes() const
{
    return QStringList() << NOTE_MIME;// 返回包含笔记MIME类型的列表
}
// 获取指定模型索引列表的MIME数据
QMimeData *NoteListModel::mimeData(const QModelIndexList &indexes) const
{
    // 如果模型索引列表为空，则返回nullptr
    if (indexes.isEmpty()) {
        return nullptr;
    }
    QStringList d;// 创建一个字符串列表来存储笔记ID
    for (const auto &index : indexes) {// 遍历模型索引列表
        // 获取笔记ID并添加到字符串列表中
        auto id = index.data(NoteListModel::NoteID).toInt();
        d.append(QString::number(id));
    }
    if (d.isEmpty()) {
        return nullptr;// 如果字符串列表为空，则返回nullptr
    }
    QMimeData *mimeData = new QMimeData;// 创建一个新的QMimeData对象
    mimeData->setData(NOTE_MIME, d.join(QStringLiteral(PATH_SEPARATOR)).toUtf8());// 将笔记ID列表设置为MIME数据
    return mimeData;
}
// 处理MIME数据的拖放
bool NoteListModel::dropMimeData(const QMimeData *mime, Qt::DropAction action, int row, int column,
                                 const QModelIndex &parent)
{// 忽略column参数
    Q_UNUSED(column);
    // 如果MIME数据不包含笔记MIME类型或操作不是移动操作，则返回false
    if (!(mime->hasFormat(NOTE_MIME) && action == Qt::MoveAction)) {
        return false;
    }
    // 如果行号为-1，则根据parent的有效性确定行号
    if (row == -1) {
        // 如果parent有效，则行号为parent的行号
        if (parent.isValid()) {
            row = parent.row();
        } else { // 否则行号为模型的行数
            // invalid index: append at bottom, after last toplevel
            row = rowCount(parent);
        }
    }
    // 根据行号确定是否移动到被钉住的笔记列表
    bool toPinned = false;
    if (row >= m_pinnedList.size()) {
        toPinned = false;
    } else {
        toPinned = true;
    }// 获取笔记ID列表
    auto idl = QString::fromUtf8(mime->data(NOTE_MIME)).split(QStringLiteral(PATH_SEPARATOR));
    // 创建一个QSet来存储移动的笔记ID
    QSet<int> movedIds;
    // 创建一个QModelIndexList来存储移动的笔记的模型索引
    QModelIndexList idxe;
    // 遍历笔记ID列表
    for (const auto &id_s : qAsConst(idl)) {
        // 获取笔记ID并添加到模型索引列表中
        auto nodeId = id_s.toInt();
        idxe.append(getNoteIndex(nodeId));
    }
    // 发出行即将被移动信号
    emit rowsAboutToBeMovedC(idxe);
    // 开始重置模型
    beginResetModel();
    // 如果移动到被钉住的笔记列表
    if (toPinned) {
        // 遍历移动的笔记的模型索引列表
        for (const auto &index : qAsConst(idxe)) {
            // 获取笔记数据的引用
            auto &note = getRef(index.row());
            // 如果笔记不是被钉住的，则设置为被钉住的
            if (!note.isPinnedNote()) {
                note.setIsPinnedNote(true);
                // 发出请求更新笔记的钉住状态信号
                emit requestUpdatePinned(note.id(), true);
                // 将笔记从笔记列表移动到被钉住的笔记列表的开头
                m_pinnedList.prepend(m_noteList.takeAt(index.row() - m_pinnedList.size()));
            }
        }
        // 遍历笔记ID列表
        for (const auto &id_s : qAsConst(idl)) {
            // 获取笔记ID
            auto nodeId = id_s.toInt();
            // 遍历被钉住的笔记列表
            for (int i = 0; i < m_pinnedList.size(); ++i) {
                // 如果找到匹配的笔记，则移动到指定行
                if (m_pinnedList[i].id() == nodeId) {
                    m_pinnedList.move(i, row);
                    break;
                }
            }
            movedIds.insert(nodeId);// 将笔记ID添加到移动的笔记ID集合中
        }
    } else { // 否则移动到笔记列表
        // 遍历移动的笔记的模型索引列表
        for (const auto &index : qAsConst(idxe)) {
            // 获取笔记数据的引用
            auto &note = getRef(index.row());
            // 将笔记ID添加到移动的笔记ID集合中
            movedIds.insert(note.id());
            // 如果笔记是被钉住的，则设置为不是被钉住的
            if (!note.isPinnedNote()) {
                continue;
            }
            note.setIsPinnedNote(false);
            // 发出请求更新笔记的钉住状态信号
            emit requestUpdatePinned(note.id(), false);
            // 根据当前视图确定插入位置
            int destinationChild = 0;
            if (m_listViewInfo.parentFolderId == SpecialNodeID::TrashFolder) {
                // 如果在回收站文件夹中，则按删除日期时间排序
                auto lastMod = index.data(NoteDeletionDateTime).toDateTime();
                for (destinationChild = 0; destinationChild < m_noteList.size();
                     ++destinationChild) {
                    if (m_noteList[destinationChild].deletionDateTime() <= lastMod) {
                        break;
                    }
                }
            } else {// 否则按最后修改日期时间排序
                auto lastMod = index.data(NoteLastModificationDateTime).toDateTime();
                for (destinationChild = 0; destinationChild < m_noteList.size();
                     ++destinationChild) {
                    if (m_noteList[destinationChild].deletionDateTime() <= lastMod) {
                        break;
                    }
                }
            }// 将笔记从被钉住的笔记列表移动到笔记列表的指定位置
            m_noteList.insert(destinationChild, m_pinnedList.takeAt(index.row()));
        }
    }

    // 结束重置模型
    endResetModel();
    // 创建一个QModelIndexList来存储移动后的笔记的模型索引
    QModelIndexList destinations;
    // 遍历移动的笔记ID集合
    for (const auto &id : movedIds) {
        // 获取笔记的模型索引并添加到模型索引列表中
        auto index = getNoteIndex(id);
        if (!index.isValid()) {
            continue;
        }
        destinations.append(index);
    }
    // 发出选择笔记信号
    emit selectNotes(destinations);
    // 发出行移动后信号
    emit rowsMovedC(destinations);
    // 更新被钉住的笔记的相对位置
    updatePinnedRelativePosition();
    return true;
}
// 获取第一个未被钉住的笔记的模型索引
QModelIndex NoteListModel::getFirstUnpinnedNote() const
{// 如果笔记列表不为空，则返回第一个未被钉住的笔记的模型索引
    if (!m_noteList.isEmpty()) {
        return createIndex(m_pinnedList.size(), 0);
    } else {// 否则返回无效的模型索引
        return QModelIndex();
    }
}
// 检查是否有被钉住的笔记
bool NoteListModel::hasPinnedNote() const
{
    // 如果不在标签中且不在回收站文件夹中
    if ((!m_listViewInfo.isInTag)
        && (m_listViewInfo.parentFolderId == SpecialNodeID::TrashFolder)) {
        // 回收站文件夹中没有被钉住的笔记，返回false
        // Trash don't have pinned note
        return false;
    }// 如果被钉住的笔记列表不为空，则返回true
    return !m_pinnedList.isEmpty();
}

// 设置指定模型索引列表的笔记的钉住状态的实现
void NoteListModel::setNotesIsPinned(const QModelIndexList &indexes, bool isPinned)
{
    // 发出请求关闭笔记编辑器信号
    emit requestCloseNoteEditor(indexes);
    // 创建一个QSet来存储需要移动的笔记ID
    QSet<int> needMovingIds;
    // 创建一个QModelIndexList来存储需要移动的笔记的模型索引
    QModelIndexList needMovingIndexes;
    // 遍历模型索引列表
    for (const auto &index : indexes) {
        // 如果模型索引有效
        if (index.isValid()) {
            // 获取笔记数据的引用
            NodeData &note = getRef(index.row());
            // 如果笔记的钉住状态需要改变
            if (note.isPinnedNote() != isPinned) {
                // 将笔记ID添加到需要移动的笔记ID集合中
                needMovingIds.insert(note.id());
                // 将模型索引添加到需要移动的笔记的模型索引列表中
                needMovingIndexes.append(index);
                // 设置笔记的钉住状态
                note.setIsPinnedNote(isPinned);
                // 发出请求更新笔记的钉住状态信号
                emit requestUpdatePinned(note.id(), isPinned);
            }
        }
    }

    // 如果设置为被钉住的
    if (isPinned) {
        // 发出行即将被移动信号
        emit rowsAboutToBeMovedC(needMovingIndexes);
        // 开始重置模型
        beginResetModel();
        // 遍历需要移动的笔记ID集合
        for (const auto &id : qAsConst(needMovingIds)) {
            // 获取笔记的模型索引
            auto index = getNoteIndex(id);
            if (!index.isValid()) {
                continue;
            }
            // 获取源行号
            int sourceRow = index.row();
            // 如果源行号超出范围，则继续下一个
            if (sourceRow < 0 || sourceRow >= rowCount()) {
                continue;
            }
            // 将笔记从笔记列表移动到被钉住的笔记列表的开头
            m_pinnedList.prepend(m_noteList.takeAt(sourceRow - m_pinnedList.size()));
        }
        // 结束重置模型
        endResetModel();
        // 创建一个QModelIndexList来存储移动后的笔记的模型索引
        QModelIndexList destinations;
        // 遍历需要移动的笔记ID集合
        for (const auto &id : qAsConst(needMovingIds)) {
            // 获取笔记的模型索引并添加到模型索引列表中
            auto index = getNoteIndex(id);
            if (!index.isValid()) {
                continue;
            }
            destinations.append(index);
        }
        // 发出选择笔记信号
        emit selectNotes(destinations);
        // 发出行移动后信号
        emit rowsMovedC(destinations);
        // 发出行数变化信号
        emit rowCountChanged();
        // 更新被钉住的笔记的相对位置
        updatePinnedRelativePosition();
    } else { // 否则设置为不是被钉住的
        // 发出行即将被移动信号
        emit rowsAboutToBeMovedC(needMovingIndexes);
        // 开始重置模型
        beginResetModel();
        // 遍历需要移动的笔记ID集合
        for (const auto &id : qAsConst(needMovingIds)) {
            // 获取笔记的模型索引
            auto index = getNoteIndex(id);
            if (!index.isValid()) {
                continue;
            }
            int destinationChild = 0;
            if (m_listViewInfo.parentFolderId == SpecialNodeID::TrashFolder) {
                // 如果在回收站文件夹中，则按删除日期时间排序
                auto lastMod = index.data(NoteDeletionDateTime).toDateTime();
                for (destinationChild = 0; destinationChild < m_noteList.size();
                     ++destinationChild) {
                    const auto &note = m_noteList[destinationChild];
                    if (note.deletionDateTime() <= lastMod) {
                        break;
                    }
                }
            } else {// 否则按最后修改日期时间排序
                auto lastMod = index.data(NoteLastModificationDateTime).toDateTime();
                for (destinationChild = 0; destinationChild < m_noteList.size();
                     ++destinationChild) {
                    const auto &note = m_noteList[destinationChild];
                    if (note.lastModificationdateTime() <= lastMod) {
                        break;
                    }
                }
            }// 将笔记从被钉住的笔记列表移动到笔记列表的指定位置
            m_noteList.insert(destinationChild, m_pinnedList.takeAt(index.row()));
        }
        // 结束重置模型
        endResetModel();
        // 创建一个QModelIndexList来存储移动后的笔记的模型索引
        QModelIndexList destinations;
        // 遍历需要移动的笔记ID集合
        for (const auto &id : needMovingIds) {
            // 获取笔记的模型索引并添加到模型索引列表中
            auto index = getNoteIndex(id);
            if (!index.isValid()) {
                continue;
            }
            destinations.append(index);
        }
        // 发出选择笔记信号
        emit selectNotes(destinations);
        // 发出行移动后信号
        emit rowsMovedC(destinations);
        // 发出行数变化信号
        emit rowCountChanged();
        // 更新被钉住的笔记的相对位置
        updatePinnedRelativePosition();
    }
}
// 检查指定模型索引的笔记是否具有标签
bool NoteListModel::noteIsHaveTag(const QModelIndex &index) const
{// 如果模型索引无效，则返回false
    if (index.row() < 0 || index.row() >= (m_noteList.count() + m_pinnedList.count())) {
        return false;
    }
    // 获取模型索引的行号
    auto row = index.row();
    // 创建一个NodeData对象来存储笔记数据
    NodeData note;
    // 如果行号小于被钉住的笔记列表的大小，则从被钉住的笔记列表中获取笔记数据
    if (row < m_pinnedList.size()) {
        note = m_pinnedList[row];
    } else { // 否则从笔记列表中获取笔记数据
        row = row - m_pinnedList.size();
        note = m_noteList[row];
    }
    return !note.tagIds().empty();// 如果笔记的标签列表不为空，则返回true
}

// 检查指定模型索引的笔记是否为第一个被钉住的笔记
bool NoteListModel::isFirstPinnedNote(const QModelIndex &index) const
{
    // 如果模型索引无效，则返回false
    if (!index.isValid()) {
        return false;
    }
    // 如果模型索引的行号大于0，则返回false
    if (index.row() > 0) {
        return false;
    }
    // 获取指定行的笔记数据的常量引用
    const NodeData &note = getRef(index.row());
    // 如果模型索引的行号为0且笔记是被钉住的，则返回true
    if (index.row() == 0 && note.isPinnedNote()) {
        return true;
    }
    return false;
}
// 检查指定模型索引的笔记是否为第一个未被钉住的笔记
bool NoteListModel::isFirstUnpinnedNote(const QModelIndex &index) const
{// 如果模型索引无效，则返回false
    if (!index.isValid()) {
        return false;
    }
    // 获取指定行的笔记数据的常量引用
    const NodeData &note = getRef(index.row());
    if ((index.row() - m_pinnedList.size()) == 0 && !note.isPinnedNote()) {// 如果模型索引的行号减去被钉住的笔记列表的大小为0且笔记不是被钉住的，则返回true
        return true;
    }
    return false;
}
// 获取第一个被钉住的笔记的模型索引
QModelIndex NoteListModel::getFirstPinnedNote() const
{
    if (m_pinnedList.isEmpty()) {// 如果被钉住的笔记列表不为空，则返回第一个被钉住的笔记的模型索引
        return QModelIndex();
    }// 否则返回无效的模型索引
    return createIndex(0, 0);
}
