/*
 * UKUI Intelligent Data Manager
 *
 * Copyright (C) 2025, KylinSoft Co., Ltd.
 *
 * 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 3 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, see <https://www.gnu.org/licenses/>.
 *
 * Authors: JinQin He <hejinqin@kylinos.cn>
 *
 */
#include "searchresultmodel.h"
#include "QUrl"
#include "searchresultmodel.h"
#include <QDebug>
#include <QtDBus/QDBusMetaType>
#include <QUuid>
#include <QTimer>
#include <QCollator>
#include <PeonyFileInfo>
#include <file-meta-info.h>
#include <file-utils.h>
#include <file-batch-rename-operation.h>
#include "search-view.h"
#include "file-rename-operation.h"
#include "thumbnail/searchthumbnailmanager.h"
#include <QPixmapCache>
#include <QImageReader>
QLocale locale = QLocale(QLocale::system().name());
QCollator comparer = QCollator(locale);
using namespace Peony;
SearchFileItemModel::SearchFileItemModel(QObject *parent)
    : QAbstractItemModel(parent)
{
        qDBusRegisterMetaType<QList<QStringList>>();
        qRegisterMetaType<QList<QStringList>>("QList<QStringList>");
        QDBusConnection connection = QDBusConnection::sessionBus();
        if (!connection.isConnected()) {
            qDebug() << "信号创建失败:" << connection.lastError().message();
            return ;
        }
        // 连接信号
        bool connected = connection.connect("com.peony.idm.service", "/org/peony/idm/space/service", "org.peony.idm.modelcontroller",
                           "searchfileReload", this,SLOT(addFileNameResults(QList<QStringList>,QString)));
        connected = connection.connect("com.peony.idm.service", "/org/peony/idm/space/service", "org.peony.idm.modelcontroller",
                                            "searchfileReloadByBatch", this,SLOT(addFileNameResultsByBatch(QList<QStringList>,QString,bool)));
        connection.connect("com.peony.idm.service", "/org/peony/idm/space/service", "org.peony.idm.modelcontroller",
                           "searchContentReload", this,SLOT(addContentResults(QList<QStringList>,QString)));
        // connection.connect("com.peony.idm.service", "/org/peony/idm/space/service", "org.peony.idm.modelcontroller",
        //                    "searchTextContentReload", this,SLOT(addTextContentResults(QList<QStringList>,QString)));
        auto settings = GlobalSettings::getInstance();
        m_showFileExtension = settings->isExist(SHOW_FILE_EXTENSION)? settings->getValue(SHOW_FILE_EXTENSION).toBool(): true;
        connect(GlobalSettings::getInstance(), &GlobalSettings::valueChanged, this, [=] (const QString& key) {
            if (SHOW_FILE_EXTENSION == key) {
                m_showFileExtension= GlobalSettings::getInstance()->getValue(key).toBool();
                beginResetModel();
                endResetModel();
                Q_EMIT expand(0);
            }
        });
        m_maxConcurrentThumbnails = 100; // 同时最多处理100个缩略图任务
        m_currentThumbnailTasks = 0;
}

SearchFileItemModel::~SearchFileItemModel()
{
    m_fileResults.clear();
    m_contentResults.clear();
    for (auto& pair : m_iconMap) {
        if (!pair.second.isNull()) {
            pair.second.detach();
            pair.second = QIcon();
        }
    }
    m_iconMap.clear();
    QPixmapCache::clear();
    malloc_trim(0);
}

QModelIndex SearchFileItemModel::index(int row, int column, const QModelIndex &parent) const
{
    if (!hasIndex(row, column, parent))
        return QModelIndex();

    if (!parent.isValid()) { // 一级节点（分类节点）
        switch (row) {
        case 0: return createIndex(row, column, FILE_CATEGORY_ID);
        case 1: return createIndex(row, column, CONTENT_CATEGORY_ID);
        //case 2: return createIndex(row, column, TEXT_CONTENT_CATEGORY_ID);
        default: return QModelIndex();
        }
    }

    // 二级节点（结果项）
    quintptr parentId = parent.internalId();
    if (parentId == FILE_CATEGORY_ID) {
        if (row < m_fileResults.size()) {
            return createIndex(row, column, FILE_ITEM_BASE_ID + row);
        }
    }
    else if (parentId == CONTENT_CATEGORY_ID) {
        if (row < m_contentResults.size()) {
            return createIndex(row, column, CONTENT_ITEM_BASE_ID + row);
        }
    }
    // else if (parentId == TEXT_CONTENT_CATEGORY_ID) {
    //     if (row < m_textContentResults.size()) {
    //         return createIndex(row, column, TEXT_CONTENT_ITEM_BASE_ID + row);
    //     }
    // }
    return QModelIndex();
}

QModelIndex SearchFileItemModel::parent(const QModelIndex &index) const
{
    if (!index.isValid())
        return QModelIndex();

    quintptr id = index.internalId();

    // 一级节点没有父节点
    if (id <= CONTENT_CATEGORY_ID)
        return QModelIndex();

    // 文件项的子节点
    if (isFileItem(id)) {
        return createIndex(0, 0, FILE_CATEGORY_ID);
    }
    // 内容项的子节点
    else if (isContentItem(id)) {
        return createIndex(1, 0, CONTENT_CATEGORY_ID);
    }
    // else if(isTextContentItem(id)){
    //     return createIndex(2, 0, TEXT_CONTENT_CATEGORY_ID);
    // }

    return QModelIndex();
}

int SearchFileItemModel::rowCount(const QModelIndex &parent) const
{
    if (!parent.isValid()) { // 根节点
        return 2; // 两个分类节点
    }

    quintptr id = parent.internalId();
    if (isFileCategory(id)) {
        return m_fileResults.size();
    }
    else if (isContentCategory(id)) {
        return m_contentResults.size();
    }/*else if (isTextContentCategory(id)) {
        return m_textContentResults.size();
    }*/

    return 0; // 结果项没有子节点
}

int SearchFileItemModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return 4; // 名称、修改日期、类型、大小
}

QVariant SearchFileItemModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    quintptr id = index.internalId();
    int column = index.column();
    int row;
    QStringList item;
    int size =0;
    // 分类节点数据
    if (isFileCategory(id)) {
        if (column == 0 && role == Qt::DisplayRole) {
            return tr("File Name Match");
        }
        return QVariant();
    }
    else if (isContentCategory(id)) {
        if (column == 0 && role == Qt::DisplayRole) {
#ifdef ARCH_AVAILABLE_AI
          return tr("Intelligent Content Recognition Match");
#else
          return tr("Text Content");
#endif
        }
        return QVariant();
    }/*else if(isTextContentCategory(id)){
        if (column == 0 && role == Qt::DisplayRole) {
            return tr("Text Content");
        }
    }*/
    else if (isFileItem(id)) {
        row = id - FILE_ITEM_BASE_ID;
        item = m_fileResults[row];
        size = m_fileResults.size();
    }
    else if(isContentItem(id)){
        row = id - CONTENT_ITEM_BASE_ID;
        item = m_contentResults[row];
        size = m_contentResults.size();
    }
    // else if(isTextContentItem(id)){
    //     row = id - TEXT_CONTENT_ITEM_BASE_ID;
    //     item = m_textContentResults[row];
    //     size = m_textContentResults.size();
    // }
    if (row >= 0 && row < size) {
        switch (role) {
        case Qt::DisplayRole:
            switch (column) {
            case 0: {
                if(!m_showFileExtension){
                    auto info = Peony::FileInfo::fromUri(item.value(0));
                    if (info->isDir()||(!item.value(4).contains("."))) {
                        return QVariant(item.value(4));
                    }
                    return QVariant(FileUtils::getBaseNameOfFile(item.value(4)));
                }else
                    return QVariant(item.value(4));
            }
            case 1: return item.value(1);//modifytime format
            case 2: return item.value(2);//filetype
            case 3: return item.value(3);//sizeformat
            }
            break;
    //    case Qt::BackgroundRole:
    //        if (item->type() == SearchFileItem::ContentItem)
    //            return QColor(240, 245, 255);
    //        break;
        case Qt::UserRole:
                return item.value(0);//uri
                break;
        case Qt::UserRole+1:
                return item.value(5);//filepath
                break;
        case Qt::UserRole+2:
                return item.value(7);//fileminetyle
                break;
        case Qt::UserRole+3:
                return item.value(8);//int  size
                break;
        case Qt::UserRole+4:
                return item.value(9);//modifytime int
                break;
        case Qt::UserRole+5:
                return item.value(6);//iconname
                break;
        case Qt::DecorationRole:
            if (index.column() == 0) {
                if(!m_isAiavailable && isContentItem(id) && item.value(6)=="")
                    return "";
               QIcon icon = QIcon::fromTheme(item.value(6),QIcon::fromTheme("unknown"));
               auto it = m_iconMap.find(item.value(5));
               if (it != m_iconMap.end()) {
                    QIcon thumbnailIcon = it->second; // 获取原始指针但不转移所有权
                    return thumbnailIcon.isNull()?icon:thumbnailIcon;
               }
               return icon;
            }
            break;
        }
    }
    return QVariant();
}

QVariant SearchFileItemModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
        switch (section) {
        case 0: return tr("Name");
        case 1: return tr("Modified Date");
        case 2: return tr("File Type");
        case 3: return tr("File Size");
        }
    }
    return QVariant();
}

Qt::ItemFlags SearchFileItemModel::flags(const QModelIndex &index) const
{
    if (index.isValid()) {
        Qt::ItemFlags flags = QAbstractItemModel::flags(index);
        if (index.column() == 0) {
            flags |= Qt::ItemIsDragEnabled;
            flags |= Qt::ItemIsEditable;
        }
        return flags;
    }
}

QMimeData* SearchFileItemModel::mimeData(const QModelIndexList &indexes) const
{
    QMimeData *mimeData = new QMimeData();
    QStringList uris;
    QStringList encodedUris;
    for (const QModelIndex &index : indexes) {
        if (index.isValid() && index.column() == 0) {
            QString uri = data(index, Qt::UserRole).toString(); // 假设 URI 存储在 UserRole 中
            uris << uri;
            encodedUris << uri;
        }
    }

    QList<QUrl> urlList;
    for (const QString &uri : uris) {
        urlList << QUrl(uri);
    }

    mimeData->setUrls(urlList);
    auto encodedString = encodedUris.join(" ");
    mimeData->setData("peony-qt/encoded-uris", encodedString.toUtf8());
    auto string = uris.join(" ");
    mimeData->setText(string);
    return mimeData;
}

void SearchFileItemModel::addFileNameResults(QList<QStringList> fileResults,QString clientid)
{
    // QTimer::singleShot(500, this, [this, fileResults, clientid]() {//防止频繁更新导致UI界面显示空白异常
    //     if (!m_fileResults.isEmpty()) {
    //         beginRemoveRows(index(0, 0), 0, m_fileResults.size() - 1);
    //         m_fileResults.clear();
    //         endRemoveRows();
    //     }
    //     if (fileResults.isEmpty() || (clientid!=m_clientId)){
    //         if(searchContentfinish /*&& searchTextContentFinish*/){
    //             Q_EMIT searchFinished();
    //         }
    //         searchFilefinish = true;
    //         return;
    //     }
    //     beginInsertRows(index(0, 0), 0, fileResults.size() - 1);
    //     m_fileResults = fileResults;
    //     searchFilefinish = true;
    //     endInsertRows();
    //     if(searchContentfinish /*&& searchTextContentFinish*/){
    //         Q_EMIT searchFinished();
    //     }
    //     Q_EMIT resizeColFitContent();
    // });
}

void SearchFileItemModel::addContentResults(QList<QStringList> contentResults,QString clientid)
{
        if (!m_contentResults.isEmpty()) {
            beginRemoveRows(index(1, 0), 0, m_contentResults.size() - 1);
            m_contentResults.clear();
            endRemoveRows();
        }
        if (contentResults.isEmpty() || (clientid!=m_clientId)){
            if(searchFilefinish /*&& searchTextContentFinish*/){
                Q_EMIT searchFinished();
            }
            searchContentfinish = true;
            QTimer::singleShot(100, this, [this]() {
                if (!m_isAiavailable) {
                    addDefaultContent();
                }
            });
            return;
        }
        beginInsertRows(index(1, 0), 0, contentResults.size() - 1);
        m_contentResults = contentResults;
        searchContentfinish = true;
        endInsertRows();
        if(searchFilefinish /*&& searchTextContentFinish*/){
            Q_EMIT searchFinished();
        }
        loadContentIcon();
        Q_EMIT resizeColFitContent();
}

void SearchFileItemModel::clearResult()
{
    beginRemoveRows(index(0, 0), 0, m_fileResults.size() - 1);
    m_fileResults.clear();
    endRemoveRows();

    beginRemoveRows(index(1, 0), 0, m_contentResults.size() - 1);
    m_contentResults.clear();
    endRemoveRows();
}

void SearchFileItemModel::clearAll()
{
    Q_EMIT layoutAboutToBeChanged();
    m_fileResults.clear();
    if(m_isAiavailable)
        m_contentResults.clear();
    m_iconMap.clear();
    Q_EMIT layoutChanged();
}

void SearchFileItemModel::keywordchange(QString keyword){
    m_keyword = keyword;
    clearAll();
}

void SearchFileItemModel::loadContentIcon(){
    QModelIndex sourceRoot = QModelIndex();  // 根节点索引
    // 获取根节点的行数（子项数量）
    int Count = rowCount(sourceRoot);
    int i = int(CONTENT_CATEGORY_ID) -1;
    QModelIndex catIndex = index(i, 0, sourceRoot);
    int count  = rowCount(catIndex);
    QModelIndex topLeft = index(0, 0, catIndex);
    QModelIndex bottomRight = index(count - 1,columnCount(catIndex) -1, catIndex);
    for (int j = 0; j < count; ++j) {
      QModelIndex childIndex = index(j, 0, catIndex);
      QString path = data(childIndex, Qt::UserRole+1).toString();
      QString fileType = data(childIndex, Qt::UserRole+2).toString();
      if(fileType.startsWith("text")){
          continue;
      }
      searchThumbnailManager *manager = new searchThumbnailManager(nullptr);
      manager->setStrictedMode(true);
      manager->startPreview(path);
      connect(manager, &searchThumbnailManager::thumbnailFinished, this, [=](const QString &path, const QImage &image, const QString &errorMessage){
          QMutexLocker locker(&m_dataMutex);
          QPixmap pixmap = QPixmap::fromImage(image);
          QIcon icon;
          icon.addPixmap(QPixmap::fromImage(image));
          m_iconMap[path] = icon;
          Q_EMIT dataChanged(topLeft, bottomRight);
          manager->deleteLater();
      });

    }
}

bool SearchFileItemModel::isSortingEnabled()
{
    return m_SortingEnabled;
}

void SearchFileItemModel::addFileNameResultsByBatch(QList<QStringList> fileResults, QString clientid, bool finish)
{
    if (fileResults.isEmpty() || clientid != m_clientId) {
        if(finish) {
            searchFilefinish = true;
            if(searchContentfinish) {
                Q_EMIT searchFinished();
            }
            m_SortingEnabled = true;
        }
        return;
    }

    // 批量插入数据
    int startPos = m_fileResults.size();
    int endPos = startPos + fileResults.size() - 1;
    beginInsertRows(index(0, 0), startPos, endPos);
    m_fileResults.append(fileResults);
    endInsertRows();
    m_SortingEnabled = false;
    // 异步生成缩略图
    if(finish) {
        m_SortingEnabled = true;
        if(searchContentfinish) {
            Q_EMIT searchFinished();
        }
        searchFilefinish = true;
    }
    loadNextBatchIcons(fileResults);
}

void SearchFileItemModel::loadNextBatchIcons(QList<QStringList> infolist) {
    int batchCount = infolist.size();

    if (batchCount == 0) return;

    // 将需要加载缩略图的文件路径添加到队列中
    for (int i = 0; i < batchCount; ++i) {
        QString path = infolist[i][5];
        QString fileType = infolist[i][7];

        // 只对非文本文件进行缩略图加载
        if (!fileType.startsWith("text")) {
            m_thumbnailQueue.append(path);
        }
    }

    // 开始处理缩略图队列
    processThumbnailQueue();
}

void SearchFileItemModel::processThumbnailQueue() {
    // 如果队列为空或已达到最大并发数，则返回
    if (m_thumbnailQueue.isEmpty() || m_currentThumbnailTasks >= m_maxConcurrentThumbnails) {
        return;
    }

    // 计算本次可以处理的任务数
    int tasksToStart = qMin(m_maxConcurrentThumbnails - m_currentThumbnailTasks, m_thumbnailQueue.size());

    for (int i = 0; i < tasksToStart; ++i) {
        QString path = m_thumbnailQueue.takeFirst();
        m_currentThumbnailTasks++;
        searchThumbnailManager *manager = new searchThumbnailManager(nullptr);
        manager->setStrictedMode(true);
        manager->startPreview(path);
        connect(manager, &searchThumbnailManager::thumbnailFinished, this,
                [=](const QString &path, const QImage &image, const QString &errorMessage) {
                    if (!image.isNull()) {
                        QMutexLocker locker(&m_dataMutex);
                        QIcon icon;
                        icon.addPixmap(QPixmap::fromImage(image));
                        m_iconMap[path] = icon;
                    }

                    // 减少当前任务计数
                    m_currentThumbnailTasks--;
                    // 删除manager对象
                    manager->deleteLater();
                    // 触发界面更新（可以考虑批量更新）
                    QModelIndex sourceRoot = QModelIndex();
                    QModelIndex catIndex = index(0, 0, sourceRoot);
                    if (catIndex.isValid()) {
                        int rowCountVal = rowCount(catIndex);
                        if (rowCountVal > 0) {
                            QModelIndex topLeft = index(0, 0, catIndex);
                            QModelIndex bottomRight = index(rowCountVal - 1, columnCount(catIndex) - 1, catIndex);
                            Q_EMIT dataChanged(topLeft, bottomRight);
                        }
                    }
        //             // 继续处理队列中的其他任务
                    if (!m_thumbnailQueue.isEmpty()) {
                        QTimer::singleShot(0, this, &SearchFileItemModel::processThumbnailQueue);
                    }
                 });
    }
}

void SearchFileItemModel::updateSearchstatus(bool isFinish){
    searchFilefinish = isFinish;
    searchContentfinish = isFinish;
}

void SearchFileItemModel::setClientId(QString clientid)
{
    m_clientId = clientid;
}

void SearchFileItemModel::addDefaultContent()
{
    if (!m_isAiavailable){
        if(searchFilefinish){
            Q_EMIT searchFinished();
        }
        searchContentfinish = true;
    }
    QString Warning;
#ifdef ARCH_AVAILABLE_AI
    Warning = tr("To Obtain Natural Language Recognition Results, Please in【Settings】->【Global Search】<span style='color:#3790FA;'>Open \"AI Index\"</span> ");
#else
    if(isFileContentOn()){
        return;
    }
    Warning = tr("To Obtain the Matching Results of Text, Pictures, Videos. Please<span style='color:#3790FA;'> Open \"File Content Index\"</span>");
#endif
    QStringList list;
    list<<""<<""<<""<<""<<Warning<<""<<""<<""<<""<<"";
    beginInsertRows(index(1, 0), 0, 0);
    m_contentResults.clear();
    m_contentResults.append(list);
    endInsertRows();
    m_hasDefaultContent = true;
    Q_EMIT resizeColFitContent();
}

void SearchFileItemModel::setAiCondition(bool isavailable)
{
    m_isAiavailable = isavailable;
}

void SearchFileItemModel::childRemove(const QString uri)
{
    QString path =  QUrl(uri).toLocalFile();
    for (int i = 0; i < m_fileResults.size(); ++i) {
        if (m_fileResults[i].value(5) == path) {
            beginRemoveRows(index(0, 0), i, i);
            m_fileResults.removeAt(i);
            endRemoveRows();
            return;
        }
    }

    for (int i = 0; i < m_contentResults.size(); ++i) {
        if (m_contentResults[i].value(5) == path) {
            beginRemoveRows(index(1, 0), i, i);
            m_contentResults.removeAt(i);
            endRemoveRows();
            return;
        }
    }
}

bool SearchFileItemModel::childRename(const QString& oldUri, const QString& newUri)
{
    QString oldPath = QUrl(oldUri).toLocalFile();
    QString newPath = QUrl(newUri).toLocalFile();

    // 在文件结果中查找
    for (int i = 0; i < m_fileResults.size(); ++i) {
        if (m_fileResults[i].value(5) == oldPath) {
            QModelIndex topLeft = index(i, 0, index(0, 0));
            QModelIndex bottomRight = index(i, columnCount() - 1, index(0, 0));
            auto info = Peony::FileInfo::fromUri(newUri);
            auto infoJob = new Peony::FileInfoJob(info);
            infoJob->querySync();
            QString displayName = info->displayName();
            if (info->isDesktopFile()) {
                displayName = FileUtils::handleDesktopFileName(info->uri(), info->displayName());
            }
            m_fileResults[i].replace(4, displayName);
            m_fileResults[i].replace(5, newPath);
            m_fileResults[i].replace(0, newUri);

            Q_EMIT dataChanged(topLeft, bottomRight, {Qt::UserRole+1, Qt::UserRole, Qt::DisplayRole});
            return true;
        }
    }

    // 在内容结果中查找
    for (int i = 0; i < m_contentResults.size(); ++i) {
        if (m_contentResults[i].value(5) == oldPath) {
            QModelIndex topLeft = index(i, 0, index(1, 0));
            QModelIndex bottomRight = index(i, columnCount() - 1, index(1, 0));
            auto info = Peony::FileInfo::fromUri(newUri);
            auto infoJob = new Peony::FileInfoJob(info);
            infoJob->querySync();
            QString displayName = info->displayName();
            if (info->isDesktopFile()) {
                displayName = FileUtils::handleDesktopFileName(info->uri(), info->displayName());
            }
            m_contentResults[i].replace(4, displayName);
            m_contentResults[i].replace(5, newPath);
            m_contentResults[i].replace(0, newUri);

            Q_EMIT dataChanged(topLeft, bottomRight, {Qt::UserRole+1, Qt::UserRole, Qt::DisplayRole});
            return true;
        }
    }

    return false;
}

bool SearchFileItemModel::hasDefaultContent()
{
    return m_hasDefaultContent;
}
//QIcon SearchFileItemModel::getIcon(const QModelIndex &index)
//{
//     quintptr id = index.internalId();
//     int row;
//     QStringList item;
//     if (isFileItem(id)) {
//         row = id - FILE_ITEM_BASE_ID;
//         item = m_fileResults[row];
//     }
//     else if(isContentItem(id)){
//         row = id - CONTENT_ITEM_BASE_ID;
//         item = m_contentResults[row];
//     }
//     QIcon icon = QIcon::fromTheme(item.value(6),QIcon::fromTheme("unknown"));

//     QIcon thumbnailIcon = m_iconMap.value(id);
//     return thumbnailIcon.isNull()?icon:thumbnailIcon;
//}

//QMap<quintptr, QIcon> SearchFileItemModel::getIconMap()
//{
//    return m_iconMap;
//}


SearchFilterProxyModel::SearchFilterProxyModel(QObject* parent)
    : QSortFilterProxyModel(parent) {
    auto settings = Peony::GlobalSettings::getInstance();
    m_settings = settings;
    setDynamicSortFilter(false);
}


bool SearchFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const {
    const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
    // 第一级项目总是显示且保持原始顺序
    if (!sourceParent.isValid()) {
        return true;
    }
//        // 第二级项目应用过滤
    if (!sourceParent.parent().isValid()) {
        auto sourcemodel =  static_cast<SearchFileItemModel*>(sourceModel());
        const QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent);
        const QModelIndex index1 = sourceModel()->index(sourceRow, 1, sourceParent); // 修改日期
        const QModelIndex index2 = sourceModel()->index(sourceRow, 2, sourceParent); // 文件类型
        const QModelIndex index3 = sourceModel()->index(sourceRow, 3, sourceParent); // 文件大小

        QString displayName = sourceModel()->data(index0, Qt::DisplayRole).toString();
        qint64 modifiedDate = sourceModel()->data(index1, Qt::UserRole+4).toLongLong();
        QString fileType = sourceModel()->data(index2, Qt::UserRole+2).toString();
        qint64 fileSize = sourceModel()->data(index3, Qt::UserRole+3).toLongLong();
        if (!checkFileTypeFilter(fileType))
            return false;
        if (! checkFileModifyTimeFilter(modifiedDate))
            return false;
        bool isdir = fileType =="inode/directory";
        if (! checkFileSizeOrTypeFilter(fileSize,isdir) )
            return false;
        if (! checkFileNameFilter(displayName))
            return false;
        quintptr id = index.internalId();
        if(!needFileContent && sourcemodel->isContentItem(id)){
            return false;
        }
    }
    return true;
}

void SearchFilterProxyModel::updateconditions(QString conditionsobj){
    m_keywords.clear();
    m_conditions.clear();
    m_contains.clear();
    needFileContent = true;
    m_keywordsContain = true;
    QJsonDocument doc = QJsonDocument::fromJson(conditionsobj.toUtf8());
    QJsonObject jsonObj = doc.object();
    int count = jsonObj["conditions count"].toInt();
    for (int i = 0; i < count; i++) {
        auto conditionObj = jsonObj[QString::number(i)].toObject();
        int type = conditionObj["condition type"].toInt();
        bool contains = conditionObj["contains"].toBool();
        if(type == int(Type::FileName))
       {
            auto jsonArray = conditionObj["keywords"].toArray();
            QStringList keywords;
            for (auto value : jsonArray) {
                if(!value.toString().isEmpty())
                    keywords << value.toString();
            }
            m_keywords<<keywords;
            m_keywordsContain = contains;
        }
        else if(type == int(Type::ConditionMatchRule)){
             int filtertype =  conditionObj["type"].toInt();
             needFileContent = filtertype == 0?  true:false;
        }
        else{
            int filtertype =  conditionObj["type"].toInt();
            m_conditions.insert(type,filtertype);
            m_contains.insert(type,contains);
        }
    }
    invalidateFilter();
}


QStringList SearchFilterProxyModel::getFiltereUrilist(){
    urilist.clear();
   // 获取源模型根索引
   QModelIndex sourceRoot = mapToSource(QModelIndex());
   // 查找目标分类
   for (int i = 0; i < sourceModel()->rowCount(sourceRoot); ++i) {
       QModelIndex catIndex = sourceModel()->index(i, 0, sourceRoot);
       for (int j = 0; j < sourceModel()->rowCount(catIndex); ++j) {
           QModelIndex childIndex = sourceModel()->index(j, 0, catIndex);
           if (filterAcceptsRow(j, catIndex)) {
               QString uri = sourceModel()->data(childIndex, Qt::UserRole+1).toString();
               if (!uri.isEmpty()) {
                   urilist << uri;
               }
           }
       }
    }
   return urilist;
}

void SearchFilterProxyModel::update()
{
    invalidateFilter();
}

bool SearchFilterProxyModel::checkFileModifyTimeFilter(quint64 modifiedTime) const{
    int ConditionType =  int(Type::DateRange);
    int cur = m_conditions[ConditionType];
    bool contains = m_contains[ConditionType];
    if(!m_conditions.contains(ConditionType))
        return true;
    if(cur==ALL_TYPE){
        return contains;
    }
    auto time = QDateTime::currentMSecsSinceEpoch();
    auto dateTime = QDateTime::fromMSecsSinceEpoch(time);
    //qDebug() << "cur QDateTime:" <<dateTime.toString(Qt::SystemLocaleShortDate);
    QDate date = dateTime.date();
    int year = date.year();
    int month = date.month();
    int day = date.day();
    QDate md_date = QDateTime::fromMSecsSinceEpoch(modifiedTime).date();
    //qDebug() << "modify time:" <<QDateTime::fromMSecsSinceEpoch(modifiedTime *1000).toString(Qt::SystemLocaleShortDate);
    int md_year= md_date.year();
    int md_month = md_date.month();
    int md_day = md_date.day();
    switch(cur)
    {
    case TODAY:
    {
        if (year == md_year && month == md_month && day == md_day)
            return contains;
        break;
    }
    case YESTERDAY:
    {
        QDate yesterday = date.addDays(-1);
        if(yesterday == md_date)/* 判断给定日期是否是昨天 */
            return contains;
        break;
    }
    case THIS_WEEK:
    {
        QDate md_date(md_year, md_month, md_day);
        int week, md_week,week_year, md_week_year;
        week = date.weekNumber(&week_year);
        md_week = md_date.weekNumber(&md_week_year);
        if (week == md_week && week_year == md_week_year)
            return contains;
        break;
    }
    case LAST_WEEK:
    {
        QDate monDate = date.addDays(-date.dayOfWeek() + 1);
        if(monDate.addDays(-7) <= md_date &&  md_date <= monDate.addDays(-1))/* 判断给定日期是否在上周 */
            return contains;
        break;
    }
    case THIS_MONTH:
    {
        if (year == md_year && month == md_month)
            return contains;
        break;
    }
    case LAST_MONTH:
    {
        int lastMonth = (month == 1) ? 12 : month - 1;
        if(md_month == lastMonth){/*  判断给定日期是否在上个月 */
            if((month == 1 && md_year == (year - 1)) || (month !=1 && year == md_year)){
                return contains;
            }
        }
        break;

    }
    case THIS_YEAR:
    {
        if (year == md_year)
            return contains;
        break;
    }
    case LAST_YEAR:
    {
        int lastYear = year - 1;
        if(md_year == lastYear)/* 判断给定日期是否在去年 */
            return contains;
        break;
    }
    case BEFORE_LAST_YEAR:
    {
        int lastYear = year - 1;
        if(md_year < lastYear)/* 判断给定日期是否在去年 */
            return contains;
        break;
    }
    default:
        break;
    }
    return !contains;
}


bool SearchFilterProxyModel::checkFileSizeFilter(quint64 size) const{
    int ConditionType =  int(Type::FileSize);
    int cur = m_conditions[ConditionType];
    bool contains = m_contains[ConditionType];
    if(!m_conditions.contains(ConditionType))
        return true;
    if(cur==ALL_TYPE){
        return contains;
    }
    switch (cur)
    {
    case EMPTY: //[0K]
    {
        if (size == 0)
            return contains;
        break;
    }
    case TINY: //（0-16K]
    {
        if (size > 0 && size <= TINY_BASE)
            return contains;
        break;
    }
    case SMALL:  //（16k-1M]
    {
        if(size > TINY_BASE && size <= SMALL_BASE)
            return contains;
        break;
    }
    case MEDIUM: //(1M-128M]
    {
        if(size > SMALL_BASE && size <= MEDIUM_BASE)
            return contains;
        break;
    }
    case BIG:  //(128M-1G]
    {
        if(size > MEDIUM_BASE && size <= BIG_BASE)
            return contains;
        break;
    }
    case LARGE: //(1-4G]
    {
        if (size > BIG_BASE && size <= LARGE_BASE)
            return contains;
        break;
    }
    case GREAT: //>4G
    {
        if (size > LARGE_BASE)
            return contains;
        break;
    }
    default:
        break;
    }
    return !contains;
}

bool SearchFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
    // 一级节点按原顺序倒序排列
    Qt::SortOrder order = this->sortOrder();
    bool resort = order == Qt::AscendingOrder;
    bool flag = left.row() > right.row();
    if (!left.parent().isValid() && !right.parent().isValid()) {//固定一级节点排序 不让文件名匹配在内容匹配下面
           return resort ? !flag:flag;
    }
    SearchFileItemModel *sourceRootModel = static_cast<SearchFileItemModel*>(sourceModel());
    if(!sourceRootModel->isSortingEnabled()){
        return left.row() < right.row();
    }
    // 获取对应的SearchFileItemModel指针
    if (left.isValid() && right.isValid()) {
        // 获取当前排序的列和顺序
        int sortColumn = this->sortColumn();

        // 获取对应的数据角色
        int role ;
        switch (sortColumn) {
            case 0: // 名称列
                role = Qt::DisplayRole;
                break;
            case 1: // 修改日期列
                role = Qt::UserRole + 4;
                break;
            case 2: // 文件类型列
                role = Qt::UserRole + 2;
                break;
            case 3: // 文件大小列
                role = Qt::UserRole + 3;
                break;
            default:
                return QSortFilterProxyModel::lessThan(left, right);
        }
        QVariant leftData = sourceRootModel->data(left, role);
        QVariant rightData = sourceRootModel->data(right, role);
        // 根据数据类型进行比较
        if (role == Qt::UserRole + 4 || role == Qt::UserRole + 3) {
            // 处理数值类型（qint64）
            qint64 leftValue = leftData.toLongLong();
            qint64 rightValue = rightData.toLongLong();
            if(leftValue == rightValue)
                goto default_sort;
            bool result = (leftValue > rightValue);
            return result;
        } else if (role == Qt::UserRole + 2) {
            // 文件类型使用字符串比较
            QString leftDisplayType = leftData.toString();
            QString rightDisplayType= rightData.toString();

            if (leftDisplayType == rightDisplayType)
            {
                 goto default_sort;
            }
            if (m_use_default_name_sort_order) {
                bool lesser = true;
                if(startWithChinese(leftDisplayType) && ! startWithChinese(rightDisplayType)) {
                    // fix #103343
                    lesser = true;
                    if (sortOrder() == Qt::AscendingOrder)
                        return lesser;
                    return !lesser;
                }
                else if(! startWithChinese(leftDisplayType) && startWithChinese(rightDisplayType)) {
                    lesser = false;
                    if (sortOrder() == Qt::AscendingOrder)
                        return lesser;
                    return !lesser;
                }
                else
                    return comparer.compare(leftDisplayType, rightDisplayType) > 0;
            }
            return comparer.compare(leftDisplayType, rightDisplayType) > 0;

        }else if(role == Qt::DisplayRole){ //文件名
            goto default_sort;
        }/*else {
            // 其他字符串类型比较
            QString leftStr = leftData.toString();
            QString rightStr = rightData.toString();
            return QString::localeAwareCompare(leftStr, rightStr) < 0;
        }*/

default_sort:
            const QModelIndex index0 = sourceModel()->index(left.row(), 0, left.parent());
            const QModelIndex index1 = sourceModel()->index(right.row(), 0, right.parent());

            QString leftDisplayName = sourceRootModel->data(index0, Qt::DisplayRole).toString();
            QString rightDisplayName = sourceRootModel->data(index1, Qt::DisplayRole).toString();

            if (m_use_default_name_sort_order) {
                //fix chinese first sort wrong issue, link to bug#70836
                //fix bug#97408,change indicator meanings
                bool lesser = true;
                if(startWithChinese(leftDisplayName) && ! startWithChinese(rightDisplayName)) {
                    // fix #103343
                    lesser = true;
                    if (sortOrder() == Qt::AscendingOrder)
                        return lesser;
                    return !lesser;
                }
                else if(!startWithChinese(leftDisplayName) && startWithChinese(rightDisplayName)) {
                    lesser = false;
                    if (sortOrder() == Qt::AscendingOrder)
                        return lesser;
                    return !lesser;
                }
                else
                    return comparer.compare(leftDisplayName, rightDisplayName) > 0;
            }
            return comparer.compare(leftDisplayName, rightDisplayName) > 0;
    }
    return QSortFilterProxyModel::lessThan(left, right);
}


void SearchFilterProxyModel::checkSortSettings()
{
    m_use_global_sort = m_settings->getValue(USE_GLOBAL_DEFAULT_SORTING).toBool();
    if (m_use_global_sort) {
        //m_show_hidden = m_settings->isExist(SHOW_HIDDEN_PREFERENCE)? m_settings->getValue(SHOW_HIDDEN_PREFERENCE).toBool(): false;
        m_use_default_name_sort_order = m_settings->isExist(SORT_CHINESE_FIRST)? m_settings->getValue(SORT_CHINESE_FIRST).toBool(): false;
        m_folder_first = m_settings->isExist(SORT_FOLDER_FIRST)? m_settings->getValue(SORT_FOLDER_FIRST).toBool(): true;
    } else {
        auto info = Peony::FileInfo::fromUri(m_uri);
        auto fileMetaInfo = Peony::FileMetaInfo::fromUri(m_uri);
        if (fileMetaInfo) {
            //m_show_hidden = fileMetaInfo->getMetaInfoVariant(SHOW_HIDDEN_PREFERENCE).isValid()? fileMetaInfo->getMetaInfoVariant(SHOW_HIDDEN_PREFERENCE).toBool(): false;
            m_use_default_name_sort_order = fileMetaInfo->getMetaInfoVariant(SORT_CHINESE_FIRST).isValid()? fileMetaInfo->getMetaInfoVariant(SORT_CHINESE_FIRST).toBool(): true;
            m_folder_first = fileMetaInfo->getMetaInfoVariant(SORT_FOLDER_FIRST).isValid()? fileMetaInfo->getMetaInfoVariant(SORT_FOLDER_FIRST).toBool(): true;
        } else {
            m_use_default_name_sort_order = true;
            m_folder_first = true;
        }
    }
}

void SearchFilterProxyModel::setCurrenturi(QString uri)
{
    m_uri = uri;
}

bool SearchFilterProxyModel::startWithChinese(const QString &displayName) const
{
    //NOTE: a newly created file might could not get display name soon.
    if (displayName.isEmpty()) {
        return false;
    }
    auto firstStrUnicode = displayName.at(0).unicode();
    return (firstStrUnicode <=0x9FA5 && firstStrUnicode >= 0x4E00);
}

bool SearchFilterProxyModel::checkFileSizeOrTypeFilter(quint64 size, bool isDir) const{
    int ConditionType =  int(Type::FileSize);
    int cur = m_conditions[ConditionType];
    bool contains = m_contains[ConditionType];
    if(!m_conditions.contains(ConditionType))
        return true;
    if(cur==ALL_TYPE){
        return contains;
    }
    if(isDir)
        return false;
   return checkFileSizeFilter(size);
}

bool SearchFilterProxyModel::checkFileNameFilter(const QString &displayName) const{
    if(m_keywords.isEmpty())
        return true;
    for (auto key:m_keywords) {
        if (displayName.contains(key, Qt::CaseInsensitive))
            return m_keywordsContain;
    }
    return false;
}

bool SearchFilterProxyModel::checkFileContentFilter(const QString &displayName) const{
    if(!needFileContent)
        return false;
    return true;
}


bool SearchFilterProxyModel::checkFileTypeFilter(QString type) const
{
    int ConditionType =  int(Type::FileType);
    int cur = m_conditions[ConditionType];
    bool contains = m_contains[ConditionType];
    if(!m_conditions.contains(ConditionType))
        return true;
    if(cur==ALL_TYPE){
        return contains;
    }
    switch (cur)
    {
    case FILE_FOLDER:
    {
        if (type == Folder_Type)
            return contains;
        break;
    }
    case PICTURE:
    {
        if (type.contains(Image_Type))
            return contains;
        break;
    }
    case VIDEO:
    {
        if (type.contains(Video_Type))
            return contains;
        break;
    }
    case TXT_FILE:
    {
        if (type.contains(Text_Type))
            return contains;
        break;
    }
    case WPS_FILE:
    {
        if (type.contains(Wps_Type))
            return contains;
        break;
    }
    case AUDIO:
    {
        if (type.contains(Audio_Type) || type.contains("application/x-smaf"))
            return contains;
        break;
    }
    case OTHERS:
    {
        //exclude classfied types, show the rest other types
        if (type != Folder_Type && ! type.contains(Image_Type) && ! type.contains(Video_Type)
                && ! type.contains(Text_Type) && !type.contains(Wps_Type) && ! type.contains(Audio_Type) && !type.contains("application/x-smaf"))
            return contains;
        break;
    }
    default:
        break;
    }
    return !contains;
}

bool SearchFilterProxyModel::hasChildren(const QModelIndex& parent) const {
    if (!parent.isValid()) {
        return sourceModel()->hasChildren(mapToSource(parent));
    }
    if (!parent.parent().isValid()) {
        return true; // 第一级项目总是显示为有子项
    }
    return QSortFilterProxyModel::hasChildren(parent);
}

void TreeviewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
    if (!index.isValid()) return;

    auto clipedUris = Peony::ClipboardUtils::getInstance()->getCutFileUris();
    if (!clipedUris.isEmpty()){
        if (clipedUris.contains(index.data(Qt::UserRole).toString())) {
            painter->setOpacity(0.5);
        } else {
            painter->setOpacity(1.0);
        }
    } else {
        painter->setOpacity(1.0);
    }

    // 第一层级或非第0列使用默认绘制
    if (!index.parent().isValid() || index.column() != 0) {
        QStyledItemDelegate::paint(painter, option, index);
        return;
    }

    QStyleOptionViewItem opt = option;
    opt.textElideMode = Qt::ElideRight;
    initStyleOption(&opt, index);

    // 保存原始内容
    QString text = opt.text;
    QIcon icon = opt.icon;

    // 1. 先绘制默认背景和焦点状态（关键修改）
    const QWidget* widget = opt.widget;
    QStyle* style = widget ? widget->style() : QApplication::style();
    style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, widget);

    // 2. 准备绘制参数
    QFont defaultFont = opt.font;
    QFont boldFont = defaultFont;
    boldFont.setBold(true);

    QFontMetrics fmNormal(defaultFont);
    QFontMetrics fmBold(boldFont);

    int xPos = opt.rect.left();
    int yPos = opt.rect.top();
    int availableWidth = opt.rect.width();

    // 3. 绘制图标（如果有）
    if (!icon.isNull()) {
        const int iconLeftMargin = 2;
        const int iconSize = qMin(opt.decorationSize.width(), opt.rect.height() - 4);

        opt.rect.adjust(-18, 0, 0, 0);
        QRect iconRect(opt.rect.left() + iconLeftMargin,
                       opt.rect.top() + (opt.rect.height() - iconSize) / 2,
                       iconSize,
                       iconSize);

        icon.paint(painter, iconRect, Qt::AlignLeft | Qt::AlignVCenter);
        xPos = iconRect.right() + 4;
        availableWidth -= (xPos - opt.rect.left());
    }

    // 获取正确的文本颜色（根据选中状态）
    QColor textColor = opt.state & QStyle::State_Selected
                           ? opt.palette.highlightedText().color()
                           : opt.palette.text().color();

    // 4. 检查是否是HTML内容
    bool isHtml = Qt::mightBeRichText(text);

    // 如果没有关键字且不是HTML，直接绘制文本（带Elide）
    if (m_keyword.isEmpty() && !isHtml) {
        painter->save();
        painter->setPen(textColor);

        QString elidedText = fmNormal.elidedText(text, Qt::ElideRight, availableWidth);
        painter->drawText(QRect(xPos, yPos, availableWidth, opt.rect.height()),
                          Qt::AlignLeft | Qt::AlignVCenter,
                          elidedText);
        painter->restore();
        return;
    }

    // 如果是HTML内容，使用文本文档绘制
    if (isHtml) {
        QTextDocument doc;
        doc.setDefaultFont(defaultFont);
        doc.setHtml(text);
        doc.setDocumentMargin(0);
        doc.setTextWidth(-1);

        if (doc.idealWidth() > availableWidth) {
            QString plainText = doc.toPlainText();
            QString elidedPlain = fmNormal.elidedText(plainText, Qt::ElideRight, availableWidth);
            doc.setPlainText(elidedPlain);
        }

        qreal docHeight = doc.size().height();
        qreal yOffset = (opt.rect.height() - docHeight) / 2;
        yOffset = qMax(0.0, yOffset);

        painter->save();
        painter->translate(xPos-10, yPos + yOffset);
        QRect clip(0, 0, availableWidth, opt.rect.height());
        painter->setClipRect(clip);

        QAbstractTextDocumentLayout::PaintContext ctx;
        ctx.palette = opt.palette;
        // 强制使用正确的文本颜色
        if (opt.state & QStyle::State_Selected) {
            ctx.palette.setColor(QPalette::Text, opt.palette.highlightedText().color());
        }
        doc.documentLayout()->draw(painter, ctx);
        painter->restore();
        return;
    }

    // 5. 有关键字时，分段绘制（高亮 + Elide处理）
    QRegularExpression re("(" + QRegularExpression::escape(m_keyword) + ")",
                          QRegularExpression::CaseInsensitiveOption);
    QRegularExpressionMatchIterator it = re.globalMatch(text);
    int lastPos = 0;
    bool isElided = false;

    while (it.hasNext() && !isElided) {
        QRegularExpressionMatch match = it.next();
        int start = match.capturedStart();
        int length = match.capturedLength();

        // 绘制匹配前的普通文本
        if (start > lastPos) {
            QString before = text.mid(lastPos, start - lastPos);
            int beforeWidth = fmNormal.horizontalAdvance(before);

            if (xPos + beforeWidth > opt.rect.right()) {
                QString remainingText = text.mid(lastPos);
                QString elidedText = fmNormal.elidedText(remainingText, Qt::ElideRight, opt.rect.right() - xPos);
                painter->setFont(defaultFont);
                painter->setPen(textColor);  // 使用正确的文本颜色
                painter->drawText(QRect(xPos, yPos, opt.rect.right() - xPos, opt.rect.height()),
                                  Qt::AlignLeft | Qt::AlignVCenter,
                                  elidedText);
                isElided = true;
                break;
            }

            painter->setFont(defaultFont);
            painter->setPen(textColor);  // 使用正确的文本颜色
            painter->drawText(QRect(xPos, yPos, beforeWidth, opt.rect.height()),
                              Qt::AlignLeft | Qt::AlignVCenter,
                              before);
            xPos += beforeWidth;
        }

        // 绘制高亮关键字
        if (!isElided) {
            QString keyword = match.captured();
            int keywordWidth = fmBold.horizontalAdvance(keyword);

            if (xPos + keywordWidth > opt.rect.right()) {
                QString remainingText = text.mid(lastPos);
                QString elidedText = fmNormal.elidedText(remainingText, Qt::ElideRight, opt.rect.right() - xPos);
                painter->setFont(defaultFont);
                painter->setPen(textColor);  // 使用正确的文本颜色
                painter->drawText(QRect(xPos, yPos, opt.rect.right() - xPos, opt.rect.height()),
                                  Qt::AlignLeft | Qt::AlignVCenter,
                                  elidedText);
                isElided = true;
                break;
            }

            // 绘制高亮背景
            painter->fillRect(QRect(xPos, yPos + 2, keywordWidth, opt.rect.height() - 4),
                              QColor(0, 255, 0));  // 绿色背景

            // 绘制关键字文本
            painter->setFont(defaultFont);
            painter->setPen(textColor);  // 选中时用黑色，否则用默认颜色
            painter->drawText(QRect(xPos, yPos, keywordWidth, opt.rect.height()),
                              Qt::AlignLeft | Qt::AlignVCenter,
                              keyword);
            xPos += keywordWidth;
            lastPos = start + length;
        }
    }

    // 6. 绘制剩余文本（如果未Elide）
    if (!isElided && lastPos < text.length()) {
        QString after = text.mid(lastPos);
        int afterWidth = fmNormal.horizontalAdvance(after);

        if (xPos + afterWidth > opt.rect.right()) {
            after = fmNormal.elidedText(after, Qt::ElideRight, opt.rect.right() - xPos);
        }

        painter->setFont(defaultFont);
        painter->setPen(textColor);  // 使用正确的文本颜色
        painter->drawText(QRect(xPos, yPos, opt.rect.right() - xPos, opt.rect.height()),
                          Qt::AlignLeft | Qt::AlignVCenter,
                          after);
    }
    painter->restore();
}

QSize TreeviewDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {
    QStyleOptionViewItem opt = option;
    initStyleOption(&opt, index);
    QFontMetrics fm(opt.font);
    int height = qMax(40, fm.height());
    int width = fm.horizontalAdvance(opt.text);
    if (index.column() == 0 && !opt.icon.isNull()) {
        width += opt.decorationSize.width() + 8;
    }
    return QSize(width, height);
}

QWidget *TreeviewDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    TextEdit *edit = new TextEdit(parent);
    edit->setAcceptRichText(false);
    //edit->setContextMenuPolicy(Qt::CustomContextMenu);
    edit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    edit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    edit->setWordWrapMode(QTextOption::NoWrap);

    edit->blockSignals(true);
    auto displayString = index.data(Qt::DisplayRole).toString();
    auto displayName = index.data(Qt::UserRole + 1).toString();
    auto uri = index.data(Qt::UserRole).toString();
    auto suffix = displayName.remove(displayString);
    auto fsType = FileUtils::getFsTypeFromFile(uri);
    auto info = FileInfo::fromUri(uri);
    int32_t maxLength = 255;
    if (info->isDesktopFile()) {
        suffix = ".desktop";
    }
    if (FileUtils::isFuseFileSystem(uri)) {
        fsType = "fuse.kyfs";
    }
    if (fsType.contains("ext")) {
        maxLength = 255 - suffix.toLocal8Bit().length();
        edit->setMaxLengthLimit(maxLength);
    } else if (fsType == "ecryptfs") {
        maxLength = 143 - suffix.toLocal8Bit().length();
        edit->setMaxLengthLimit(maxLength);
    } else if (fsType == "udf") {
        maxLength = 254 - suffix.toLocal8Bit().length();
        edit->setMaxLengthLimit(maxLength);
    } else if (fsType.contains("ntfs")) {
        edit->setLimitBytes(false);
        maxLength = 255 - suffix.length();
        edit->setMaxLengthLimit(maxLength);
    } else if (fsType.contains("fuse.kyfs")) {
        edit->setLimitBytes(false);
        QDBusInterface iface ("com.kylin.file.system.fuse","/com/kylin/file/system/fuse","com.kylin.file.system.fuse",QDBusConnection::systemBus());
        QDBusReply<int32_t> reply = iface.call("GetFilenameLength");
        if (reply.isValid()) {
            maxLength = reply.value();
        }
        maxLength = maxLength - suffix.length();
        edit->setMaxLengthLimit(maxLength);
    }
    edit->blockSignals(false);

    //    QTimer::singleShot(1, parent, [=]() {
    //        this->updateEditorGeometry(edit, option, index);
    //    });

    //    connect(edit, &TextEdit::textChanged, this, [=]() {
    //        updateEditorGeometry(edit, option, index);
    //    });

    connect(edit, &TextEdit::textChanged, this, [=]() {
        auto text = edit->toPlainText();
        //fix bug#220283, rename edit position wrong issue
        //short file name no need update to avoid position wrong
        edit->adjustText();
        updateEditorGeometry(edit, option, index);
    });

    connect(edit, &TextEdit::finishEditRequest, this, &TreeviewDelegate::slot_finishEdit);
    connect(edit, &QWidget::destroyed, this, [=]() {
        Q_EMIT isEditing(false);
    });
    // connect(edit, &TextEdit::focusLost, [edit]() {
    //     edit->finishEditRequest();
    // });
    return edit;
}

void TreeviewDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    TextEdit *edit = qobject_cast<TextEdit *>(editor);
    if (!edit)
        return;

    Q_EMIT isEditing(true);
    edit->setText(index.data(Qt::DisplayRole).toString());
    auto cursor = edit->textCursor();
    cursor.setPosition(0, QTextCursor::MoveAnchor);
    cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
    bool isDir = FileUtils::getFileIsFolder(index.data(Qt::UserRole).toString());
    bool isDesktopFile = index.data(Qt::UserRole).toString().endsWith(".desktop");
    bool isSoftLink = FileUtils::getFileIsSymbolicLink(index.data(Qt::UserRole).toString());
    if (!isDesktopFile && !isSoftLink && !isDir && edit->toPlainText().contains(".") && !edit->toPlainText().startsWith(".")) {
        int n = 1;
        if(index.data(Qt::DisplayRole).toString().contains(".tar.")) //ex xxx.tar.gz xxx.tar.bz2
            n = 2;
        while(n){
            cursor.movePosition(QTextCursor::WordLeft, QTextCursor::KeepAnchor, 1);
            cursor.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, 1);
            --n;
        }
    }
    //qDebug()<<cursor.anchor();
    edit->setTextCursor(cursor);
}

void TreeviewDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyledItemDelegate::updateEditorGeometry(editor, option, index);

    TextEdit *edit = qobject_cast<TextEdit*>(editor);
    if (!edit || !edit->m_backgroundEdit)
        return;

    QRect editRect = option.rect;
    auto leftShift = option.decorationSize.width()/2;
    editRect.setLeft(editRect.left() + leftShift);
    editRect.setWidth(editRect.width());
    editor->setGeometry(editRect);
    edit->m_backgroundEdit->setGeometry(1, 2, edit->width() - 2, edit->height() - 4);
    QTimer::singleShot(0, edit, [=]() {
        qreal docHeight = edit->document()->size().height();
        int availableHeight = edit->height();
        int topMargin = (availableHeight - docHeight) / 2;
        topMargin = qMax(2, static_cast<int>(topMargin));
        edit->setMargins(1, topMargin, 1, 2);
    });
}

void TreeviewDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    TextEdit *edit = qobject_cast<TextEdit*>(editor);
    if (!edit)
        return;

    auto text = edit->toPlainText();
    if (text.isEmpty())
        return;
    if (text == index.data(Qt::DisplayRole).toString())
        return;
    //process special name . or .. or only space
    if (text == "." || text == ".." || text.trimmed() == "")
        return;

    if (! index.isValid())
        return;

    auto view = qobject_cast<SearchView *>(parent());
    auto oldName = index.data(Qt::DisplayRole).toString();
    if (text == oldName)
    {
        //create new file, should select the file or folder
        auto flags = QItemSelectionModel::Select|QItemSelectionModel::Rows;
        view->selectionModel()->select(index, flags);
        view->setFocus();
        return;
    }

    if (view->getSelections().count() > 1) {
        auto fileOpMgr = FileOperationManager::getInstance();
        QStringList lists = view->getSelections();
        auto renameOp = new FileBatchRenameOperation(lists, text);

        connect(renameOp, &FileBatchRenameOperation::operationFinished, view, [=](){
                auto info = renameOp->getOperationInfo().get();
                auto uri = info->target();
                QTimer::singleShot(100, view, [=](){
                    view->setSelections(QStringList()<<uri);
                    //after rename will nor sort immediately, comment to fix bug#60482
                    //view->scrollToSelection(uri);
                    view->setFocus();
                });
            }, Qt::BlockingQueuedConnection);

        fileOpMgr->startOperation(renameOp, true);
    } else {
        auto fileOpMgr = FileOperationManager::getInstance();
        QString ddd = index.data(Qt::UserRole).toString();
        auto renameOp = new FileRenameOperation(index.data(Qt::UserRole).toString(), text);

        connect(renameOp, &FileRenameOperation::operationFinished, view, [=](){
                auto info = renameOp->getOperationInfo().get();
                auto uri = info->target();
                QTimer::singleShot(100, view, [=](){
                    view->setSelections(QStringList()<<uri);
                    //after rename will nor sort immediately, comment to fix bug#60482
                    //view->scrollToSelection(uri);
                    view->setFocus();
                });
            }, Qt::BlockingQueuedConnection);

        fileOpMgr->startOperation(renameOp, true);
    }
}

void TreeviewDelegate::slot_finishEdit()
{
    auto edit = qobject_cast<QWidget *>(sender());
    commitData(edit);
    closeEditor(edit, QAbstractItemDelegate::SubmitModelCache);
    if(edit){
        delete edit;
        edit = nullptr;
    }
}

TextEdit::TextEdit(QWidget *parent) : QTextEdit (parent)
{
    // fix #164278, icon view text editor doesn't cover view item.
    // note on ukui platform theme, style panel frame is not visible.
    setFrameShape(QFrame::NoFrame);
    setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
    setViewportMargins(1, 2, 1, 2);
    if (m_backgroundEdit == nullptr) {
        m_backgroundEdit = new QTextEdit(this);
        m_backgroundEdit->setReadOnly(true);
        m_backgroundEdit->setFrameShape(QTextEdit::NoFrame);

        m_backgroundEdit->setGeometry(1, 2, size().width() - 2, size().height() - 4);
        m_backgroundEdit->lower();
    }
}

void TextEdit::adjustText()
{
    if (m_max_length_limit) {
        //fix #154584
        blockSignals(true);
        auto position = textCursor().position();
        while (true) {
            if (m_limit_bytes) {
                auto local8Bit = toPlainText().toLocal8Bit();
                if (local8Bit.length() <= m_max_length_limit) {
                    break;
                }
            } else {
                if (toPlainText().length() <= m_max_length_limit) {
                    break;
                }
            }
            if (position > 0) {
                position--;
                textCursor().beginEditBlock();
                textCursor().setPosition(position);
                textCursor().deletePreviousChar();
                textCursor().endEditBlock();
            } else {
                break;
            }
        }
        blockSignals(false);
    }
}

void TextEdit::setMaxLengthLimit(int length)
{
    m_max_length_limit = length;
}

void TextEdit::setLimitBytes(bool limitBytes)
{
    m_limit_bytes = limitBytes;
}

void TextEdit::keyPressEvent(QKeyEvent *e)
{
    if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
        Q_EMIT finishEditRequest();
        return;
    }
    return QTextEdit::keyPressEvent(e);
}

void TextEdit::focusOutEvent(QFocusEvent *e)
{
    QTextEdit::focusOutEvent(e);
    Q_EMIT focusLost(); // 发出我们自己的信号
}

void TextEdit::setMargins(int left, int top, int right, int bottom)
{
    setViewportMargins(left, top, right, bottom);
}

bool isFileContentOn()
{
    bool flage = false;
    const QByteArray id("org.ukui.search.settings");
    if (QGSettings::isSchemaInstalled(id)) {
        auto settings = new QGSettings(id, QByteArray(), nullptr);
        QStringList keys = settings->keys();
        if (keys.contains("contentIndexEnable")) {
            flage = settings->get("contentIndexEnable").toBool();
        }
        delete settings;
    }
    return flage;
}
