/*
 * Peony-Qt's Library
 *
 * Copyright (C) 2020, KylinSoft Co., Ltd.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this library.  If not, see <https://www.gnu.org/licenses/>.
 *
 * Authors: Yue Lan <lanyue@kylinos.cn>
 *
 */

#include "directory-view-menu.h"
#include "directory-view-plugin-iface2.h"
#include "directory-view-widget.h"

#include "fm-window.h"
#include "directory-view-container.h"
#include "plugin-manager.h"
#include "menu-plugin-manager.h"
#include "file-info-job.h"
#include "file-info.h"
#include "manager-control.h"

#include "directory-view-factory-manager.h"
#include "view-factory-model.h"
#include "view-factory-sort-filter-model.h"

#include "clipboard-utils.h"
#include "file-operation-utils.h"
#include "file-operation-manager.h" //FileOpInfo
#include "audio-play-manager.h"
#include "file-untrash-operation.h"
#include "file-delete-operation.h"
#include "sound-effect.h"
#ifdef KY_SDK_SOUND_EFFECTS
#include "ksoundeffects.h"
#endif

#include "file-utils.h"
#include "bookmark-manager.h"

#include "volume-manager.h"

#include "properties-window.h"
#include "properties-window-factory-plugin-manager.h"
#include "windows/format_dialog.h"
#include "file-launch-manager.h"
#include "file-launch-action.h"
#include "file-lauch-dialog.h"
#include "file-operation-error-dialog.h"
#include "file-enumerator.h"
#include "gerror-wrapper.h"
#include "format-dlg-create-delegate.h"
#include "image-mount-manager.h"
#include "idm-actions-manager.h"

#include "global-settings.h"
#include "sound-effect.h"
#include "directoryviewhelper.h"
#include <QDesktopServices>
#include <QUrl>
#include <QMessageBox>

#include <QFileInfo>
#include <QDir>
#include <QStandardPaths>

#include <QLocale>
#include <QStandardPaths>
#include <recent-vfs-manager.h>

#include <QDebug>

#include <QApplication>
#include <QShortcut>
#include <gio/gdesktopappinfo.h>
using namespace Peony;
#ifdef KY_SDK_SOUND_EFFECTS
using namespace kdk;
#endif

#define DEBUG qDebug() << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "]"

DirectoryViewMenu::DirectoryViewMenu(DirectoryViewWidget *directoryView, QWidget *parent) : QMenu(parent)
{
    m_top_window = nullptr;
    m_view = directoryView;

    m_directory = directoryView->getDirectoryUri();
    m_selections = directoryView->getSelections();

    fillActions();
}

DirectoryViewMenu::DirectoryViewMenu(FMWindowIface *window, QWidget *parent) : QMenu(parent)
{
    m_top_window = window;
    m_view = window->getCurrentPage()->getView();
    //setParent(dynamic_cast<QWidget*>(m_view));

    m_directory = window->getCurrentUri();
    m_selections = window->getCurrentSelections();

    fillActions();
}

void DirectoryViewMenu::setHiddenActionsByObjectName(const QStringList &actionNames)
{
    for (auto action : actions()) {
        if (actionNames.contains(action->objectName())) {
            action->setVisible(false);
        }
    }
}

void DirectoryViewMenu::fillActions()
{
    m_version = qApp->property("version").toString();
    QString actualDir =  m_directory;
    if(actualDir.startsWith("search://")){
        m_is_search = true;
        actualDir = FileUtils::getActualDirFromSearchUri(m_directory);
    }

    QString tmpUri;
    g_autoptr (GFile) tmp_file = g_file_new_for_uri(actualDir.toUtf8().constData());
    g_autofree gchar* tmp_uri = g_file_get_uri(tmp_file);
    tmpUri = tmp_uri;

    if (actualDir == "computer:///") {
        m_is_computer = true;
    }

    if (actualDir == "network:///") {
        m_is_network = true;
    }

    if (actualDir == "trash:///") {
        m_is_trash = true;
    }

    if (actualDir.startsWith("burn://")) {
        m_is_cd = true;
    }

    if (actualDir.startsWith("recent://")) {
        m_is_recent = true;
    }

    if (actualDir.startsWith("favorite://")) {
        m_is_favorite = true;
    }

    if (actualDir.startsWith("kydroid:///") || actualDir.startsWith("kmre:///") || actualDir.startsWith("mult://")) {
        m_is_kydroid = true;
    }

    if (actualDir.startsWith("ftp://")
            || actualDir.startsWith("sftp://") || tmpUri.startsWith("ftp://") || tmpUri.startsWith("sftp://")) {
        m_is_ftp = true;
    }

    if (actualDir.startsWith("filesafe:///")){
        m_is_filebox_file = true;
    }

    if(actualDir == "filesafe:///" || m_directory.startsWith("search:///search_uris=filesafe:///&")) {
        m_is_filesafe = true;
    }

    if(actualDir.startsWith("smb://") || tmpUri.startsWith("smb://")){
        m_is_smb_file = true;
    }

    QString boxpath = "file://"+QStandardPaths::writableLocation(QStandardPaths::HomeLocation)+"/.box";
    if(actualDir == boxpath) {
        m_is_boxpath = true;
    }

    if (actualDir.startsWith("label://") && m_version != "ukui3.0"){
        m_is_label_model = true;
    }

    if (actualDir.startsWith("mtp://") || actualDir.startsWith("gphoto2://")){
        m_is_mtp_ptp = true;
    }

    if (actualDir.startsWith("idm://") && !m_is_search) {
        m_is_idm = true;
    }

    isMobileFile(actualDir);/* 判断是否为移动文件或目录 */
//    auto dev = VolumeManager::getDriveFromUri(actualDir);
//    if(dev != nullptr){
//        bool canEject = g_drive_can_eject(dev.get()->getGDrive());
//        bool canStop = g_drive_can_stop(dev.get()->getGDrive());
//        if(canEject || canStop){
//            m_is_mobile_file = true;
//        }
//        qDebug() << "canEject :" << canEject;
//    }
    //task#147972 【删除回收站】选项需求
    //如果是长城的机器并且带了9215控制器，不再区分移动设备，统一右键删除到回收站
    bool trashSettings = GlobalSettings::getInstance()->getValue(TRASH_MOBILE_FILES).toBool();
    if (trashSettings)
       m_is_mobile_file = false;

    QString homeUri = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
    QString musicUri = QStandardPaths::writableLocation(QStandardPaths::MusicLocation);
    QString desktop = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
    QString videoUri = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation);
    QString docUri = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
    QString pictureUri = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
    QString downloadUri = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);

    for (auto uriIndex = 0; uriIndex < m_selections.count(); ++uriIndex) {
        //qDebug() << desktop;
        if (m_selections.at(uriIndex) == "favorite:///?schema=trash"
                || m_selections.at(uriIndex) == "favorite:///?schema=kmre"
                || m_selections.at(uriIndex) == "favorite:///?schema=recent"
                || m_selections.at(uriIndex) == "favorite:///data/usershare?schema=file"
                || m_selections.at(uriIndex) == "favorite://" + homeUri + "?schema=file"
                || m_selections.at(uriIndex) == "favorite://" + desktop + "?schema=file"
                /*|| m_selections.at(uriIndex) == "favorite://" + musicUri + "?schema=file"
                || m_selections.at(uriIndex) == "favorite://" + videoUri + "?schema=file"
                || m_selections.at(uriIndex) == "favorite://" + docUri + "?schema=file"
                || m_selections.at(uriIndex) == "favorite://" + pictureUri + "?schema=file"
                || m_selections.at(uriIndex) == "favorite://" + downloadUri + "?schema=file"*/) {
            m_can_delete = false;
            break;
        }
    }

    QList<QAction *> l;

    if (m_is_idm) {
        auto actions = IDMActionsManager::getInstance()->constructIDMActions(nullptr, m_top_window, m_view, IDMActionsManager::MenuType::DirectoryView);
        addActions(actions);
        return;
    }

    //add open actions
    auto openActions = constructOpenOpActions();
    if (!openActions.isEmpty()) {
        l<<addSeparator();
        l.last()->setObjectName(OPEN_ACTIONS_SEPARATOR);
    }

    //netwotk items not show operation menu
    if (m_is_network)
        return;

    if (! m_is_kydroid){
        //create template actions
        //add view actions
        auto viewActions = constructViewOpActions();
        if (!viewActions.isEmpty()) {
            l<<addSeparator();
            l.last()->setObjectName(VIEW_ACTIONS_SEPARATOR);
        }

        auto templateActions = constructCreateTemplateActions();
        if (!templateActions.isEmpty()) {
            l<<addSeparator();
            l.last()->setObjectName(CREATE_ACTIONS_SEPARATOR);
        }
    }

    //add multiselect action
    auto multiselectAction = constructMultiSelectActions();
    if(!multiselectAction.isEmpty())
        addSeparator();

    if (! m_is_kydroid){
        auto trashActions = constructTrashActions();
        if (!trashActions.isEmpty()) {
            l<<addSeparator();
            l.last()->setObjectName(TRASH_ACTIONS_SEPARATOR);
        }
    }
    //add operation actions
    auto fileOpActions = constructFileOpActions();
    if (!fileOpActions.isEmpty()) {
        l<<addSeparator();
        l.last()->setObjectName(FILE_OPERATION_ACTIONS_SEPARATOR);
    }

    if (! m_is_kydroid){
        //add plugin actions
        auto pluginActions = constructMenuPluginActions();
        if (!pluginActions.isEmpty()) {
            l<<addSeparator();
            l.last()->setObjectName(PLUGIN_ACTIONS_SEPARATOR);
        }
    }

    //add propertries actions
    auto propertiesAction = constructFilePropertiesActions();
    if (!propertiesAction.isEmpty()) {
        l<<addSeparator();
        l.last()->setObjectName(PROPERTIES_ACTIONS_SEPARATOR);
    }

    if (! m_is_kydroid){
        //add actions in computer:///
        auto computerActions = constructComputerActions();
        if (!computerActions.isEmpty()) {
            l<<addSeparator();
            l.last()->setObjectName(COMPUTER_ACTIONS_SEPARATOR);
        }

//        //add actions in trash:///
//        auto trashActions = constructTrashActions();
//        if (!trashActions.isEmpty()) {
//            l<<addSeparator();
//            l.last()->setObjectName(TRASH_ACTIONS_SEPARATOR);
//        }
    }
}

const QList<QAction *> DirectoryViewMenu::constructOpenOpActions()
{
    QList<QAction *> l;
    if (m_is_trash)
        return l;

    bool isBackgroundMenu = m_selections.isEmpty();
    if (isBackgroundMenu) {
        if (!qApp->property("tabletMode").toBool()) {
            l<<addAction(QIcon::fromTheme("tab-new-symbolic"), tr("Open in New Tab"));
            l.last()->setObjectName(OPEN_IN_NEW_TAB_ACTION);
            connect(l.last(), &QAction::triggered, this, [=]() {
                if (!m_top_window)
                    return;
                QStringList uris;
                uris<<m_directory;
                m_top_window->addNewTabs(uris);
            });
        }
        l<<addAction(QIcon::fromTheme("window-new-symbolic"), tr("Open in New Window"));
        l.last()->setObjectName(OPEN_IN_NEW_WINDOW_ACTION);
        connect(l.last(), &QAction::triggered, this, [=]() {
            auto windowIface = m_top_window->create(m_directory);
            auto newWindow = dynamic_cast<QWidget *>(windowIface);
            newWindow->setAttribute(Qt::WA_DeleteOnClose);
            //FIXME: show when prepared?
            newWindow->show();
        });
    } else {
        if (m_selections.count() == 1) {
            auto info = FileInfo::fromUri(m_selections.first());
            auto displayName = info->displayName();
            auto mimeType = info->mimeType();
            GAppInfo *m_app_info = nullptr;
            if(info->isDesktopFile()){
                GDesktopAppInfo *appInfo = g_desktop_app_info_new_from_filename(info->filePath().toUtf8().constData());
                m_app_info  = G_APP_INFO(appInfo);
            }else{
                GAppInfo *appinfo = g_app_info_get_default_for_type(mimeType.toUtf8().constData(), false);
                auto app_info = G_APP_INFO(appinfo);
                m_app_info = static_cast<GAppInfo*>(g_object_ref(app_info));
            }
            GIcon *icon = g_app_info_get_icon(m_app_info);
            QIcon  appicon;
            auto iconName = FileUtils::getIconStringFromGIcon(icon);
            if (iconName.startsWith("/")) {
                appicon.addFile(iconName);
            } else {
                appicon = QIcon::fromTheme(iconName);
            }
            appicon = appicon.isNull() ? QIcon::fromTheme("document-open-symbolic") : appicon;
            if (displayName.isEmpty())
                displayName = FileUtils::getFileDisplayName(info->uri());
            //when name is too long, show elideText
            //qDebug() << "charWidth:" <<charWidth;
            if (displayName.length() > ELIDE_TEXT_LENGTH)
            {
                int  charWidth = fontMetrics().averageCharWidth();
                displayName = fontMetrics().elidedText(displayName, Qt::ElideRight, ELIDE_TEXT_LENGTH * charWidth);
            }
            if (info->isDir()) {
                //add to bookmark option
                l<<addAction(appicon, tr("Open"));
                l.last()->setObjectName(OPEN_ACTION);
                l.last()->setShortcut(QKeySequence(Qt::Key_Enter));
                connect(l.last(), &QAction::triggered, this, [=]() {
                    if (!m_top_window)
                        return;
                    if(info->uri().startsWith("file://") && !info->canExecute()){
                        QMessageBox::critical(nullptr, tr("Open failed"), tr("Open directory failed, you have no permission!"));
                        return;
                    }

                    bool check = Peony::GlobalSettings::getInstance()->getValue(SHOW_IN_NEW_WINDOW).toBool();
                    if (check) {
                        auto newWindow = dynamic_cast<QWidget *>(m_top_window->create(m_selections.first()));
                        newWindow->setAttribute(Qt::WA_DeleteOnClose);
                        newWindow->show();
                    } else {
                        m_top_window->goToUri(m_selections.first(), true);
                    }
                });

                auto recommendActions = FileLaunchManager::getRecommendActions(m_selections.first());
                if (recommendActions.count() >1)
                {
                    auto openWithAction = addAction(QIcon::fromTheme("openwith-symbolic"),tr("Open with..."));
                    openWithAction->setObjectName(OPEN_WITH_ACTION);
                    QMenu *openWithMenu = new QMenu(this);
                    // do not highlight application icons.
                    openWithMenu->setProperty("skipHighlightIconEffect", true);
                    for (auto action : recommendActions) {
                        action->setParent(openWithMenu);
                        openWithMenu->addAction(static_cast<QAction*>(action));
                    }
                    auto fallbackActions = FileLaunchManager::getFallbackActions(m_selections.first());
                    for (auto action : fallbackActions) {
                        action->setParent(openWithMenu);
                        openWithMenu->addAction(static_cast<QAction*>(action));
                    }
                    openWithMenu->addSeparator();
                    openWithMenu->addAction(tr("More applications..."), [=]() {
                        FileLauchDialog d(m_selections.first());
                        d.exec();
                    });
                    openWithAction->setMenu(openWithMenu);
                }
                if (!qApp->property("tabletMode").toBool()) {
                    l<<addAction(QIcon::fromTheme("tab-new-symbolic"), tr("Open in New Tab"));
                    l.last()->setObjectName(OPEN_IN_NEW_TAB_ACTION);
                    connect(l.last(), &QAction::triggered, this, [=]() {
                        if (!m_top_window)
                            return;
                        m_top_window->addNewTabs(m_selections);
                    });
                }
                l<<addAction(QIcon::fromTheme("window-new-symbolic"), tr("Open in New Window"));
                l.last()->setObjectName(OPEN_IN_NEW_WINDOW_ACTION);
                connect(l.last(), &QAction::triggered, this, [=]() {
                    auto windowIface = m_top_window->create(m_selections.first());
                    auto newWindow = dynamic_cast<QWidget *>(windowIface);
                    newWindow->setAttribute(Qt::WA_DeleteOnClose);
                    //FIXME: show when prepared?
                    newWindow->show();
                });
                if (!info->isVirtual() &&  !info->uri().startsWith("smb://") && !m_is_kydroid && !m_is_filesafe && !m_is_filebox_file)
                {
                    l<<addAction(QIcon::fromTheme("view-pin-symbolic"), tr("Add to bookmark"));
                    l.last()->setObjectName(ADD_TO_BOOKMARK_ACTION);

                    if(BookMarkManager::getInstance()->existsInBookMarks(info->uri()))
                    {
                        l.last()->setEnabled(false);
                    }
                    else
                    {
                        connect(l.last(), &QAction::triggered, this, [=]() {

                            //qDebug() <<"add to bookmark:" <<info->uri();
                            auto bookmark = BookMarkManager::getInstance();
                            if (bookmark->isLoaded()) {
                                bookmark->addBookMark(info->uri());
                            }
                        });
                    }
                }
            } else if (!info->isVolume()) {
#ifdef MULTI_DISABLE
                bool needDisable = isMultFile(info);
#endif
                l<<addAction(appicon, tr("Open"));
                l.last()->setObjectName(OPEN_ACTION);
                l.last()->setShortcut(QKeySequence(Qt::Key_Enter));
                connect(l.last(), &QAction::triggered, this, [=]() {
                    auto uri = m_selections.first();
                    if (m_is_network)
                        m_top_window->goToUri(uri, true);
                    else if (IMAGE_MOUNT_MANAGER->isImageFile(uri)) {
                        IMAGE_MOUNT_MANAGER->mountImage(uri);
                    }
                    else
                        FileLaunchManager::openAsync(uri, false, false);
                });
#ifdef MULTI_DISABLE
                if (needDisable) {
                    l.last()->setEnabled(false);
                }
#endif
                if (m_is_network)
                    return l;
                bool containsWhitelist = MANAGER_CONTROL->containsWhitelistApp(m_selections);
                bool isDesktopDir = MANAGER_CONTROL->isDesktopDirectory(m_directory);
                // Only restrict "Open with..." menu when in desktop directory with whitelist apps
                if (!(isDesktopDir && containsWhitelist)) {
                    auto openWithAction = addAction(QIcon::fromTheme("openwith-symbolic"),tr("Open with..."));
                    openWithAction->setObjectName(OPEN_WITH_ACTION);
                    QMenu *openWithMenu = new QMenu(this);
                    // do not highlight application icons.
                    openWithMenu->setProperty("skipHighlightIconEffect", true);

                    QString uri = m_selections.first();
                    //fix bug#101386, can not open file in filesafe path
                    //fix bug#125679, can not open file in recent
                    if (uri.startsWith("filesafe:///") || uri.startsWith("recent:///"))
                    {
                       auto targetUri = FileUtils::getTargetUri(uri);
                       uri = targetUri.isEmpty() ? uri : targetUri;
                    }

                    //use origin uri instead of target uri, fix recommand menu not same with desktop issue
                    //link to bug#80207
                    auto recommendActions = FileLaunchManager::getRecommendActions(uri);
                    auto fallbackActions = FileLaunchManager::getFallbackActions(uri);
                    //fix has default open app but no recommend actions issue, link to bug#61365
                    //fix open options has two same app issue, linkto bug#74480
                    if (recommendActions.count() == 0 && fallbackActions.count() == 0)
                    {
                        auto action = FileLaunchManager::getDefaultAction(uri);
                        if (action != NULL && action->getAppInfoDisplayName().length() > 0)
                            recommendActions.append(action);
                    }
                    for (auto action : recommendActions) {
                        action->setParent(openWithMenu);
                        openWithMenu->addAction(static_cast<QAction*>(action));
                    }

                    for (auto action : fallbackActions) {
                        action->setParent(openWithMenu);
                        openWithMenu->addAction(static_cast<QAction*>(action));
                    }
                    openWithMenu->addSeparator();
                    openWithMenu->addAction(tr("More applications..."), this, [=]() {
                        FileLauchDialog d(uri);
                        d.exec();
                    });
                    openWithAction->setMenu(openWithMenu);
#ifdef MULTI_DISABLE
                    if (needDisable) {
                        openWithAction->setEnabled(false);
                    }
#endif
                }
            } else {
                l<<addAction(appicon, tr("Open"));
                l.last()->setObjectName(OPEN_ACTION);
                connect(l.last(), &QAction::triggered, this, [=]() {
                    auto uri = m_selections.first();
                    //FIXME:
                    m_top_window->goToUri(uri, true);
                });
            }
        } else {
            bool containsWhitelist = MANAGER_CONTROL->containsWhitelistApp(m_selections);
            bool isDesktopDir = MANAGER_CONTROL->isDesktopDirectory(m_directory);
            
            // Only restrict batch open operation when in desktop directory with whitelist apps
            if (!(isDesktopDir && containsWhitelist)) {
                l<<addAction(QIcon::fromTheme("document-open-symbolic"), tr("Open %1 selected files").arg(m_selections.count()));
                l.last()->setObjectName(OPEN_SELECTED_FILES_ACTION);
                connect(l.last(), &QAction::triggered, this, [=]() {
                    qDebug()<<"triggered";
                    QStringList dirs;
                    QStringList files;
                    for (auto uri : m_selections) {
                        auto info = FileInfo::fromUri(uri);
                        if (info->isDir() || info->isVolume()) {
                            dirs<<uri;
                        } else {
                            files << uri;
                        }
                    }
                    if (!dirs.isEmpty()) {
                        bool check = Peony::GlobalSettings::getInstance()->getValue(SHOW_IN_NEW_WINDOW).toBool();
                        if (check) {
                            for (QString uri : dirs) {
                                auto newWindow = dynamic_cast<QWidget *>(m_top_window->create(uri));
                                newWindow->setAttribute(Qt::WA_DeleteOnClose);
                                newWindow->show();
                            }
                        } else {
                            m_top_window->addNewTabs(dirs);
                        }
                    }

                    if (!files.isEmpty())
                        FileLaunchManager::openFilesByDefaultApplications(files);
                });
#ifdef MULTI_DISABLE
                auto info = FileInfo::fromUri(m_selections.first());
                if (info) {
                    QString uri = info->uri();
                    if (uri.startsWith("mult:///")) {
                        l.last()->setEnabled(false);
                    }
                }
#endif
            }
        }
        if (! m_is_kydroid){
            auto searchActions = constructSearchActions();
        }
    }

    return l;
}

const QList<QAction *> DirectoryViewMenu::constructCreateTemplateActions()
{
    QList<QAction *> l;
    if (!m_is_search && !m_is_favorite && m_selections.isEmpty() && !m_is_filesafe && !m_is_trash && !m_is_label_model) {
        auto createAction = new QAction(QIcon::fromTheme("new-symbolic"),tr("New"), this);
        createAction->setObjectName(CREATE_ACTION);
        if (m_is_cd) {
            createAction->setEnabled(false);
        }
        if (m_is_boxpath) {
            createAction->setEnabled(false);
        }
        //related bug#191108, huawei/android phone can paste file success,also can create
//        if (m_is_mtp_ptp) {
//            createAction->setEnabled(false);
//        }
        //fix create folder fail issue in special path
        auto info = FileInfo::fromUri(m_directory);
        if (info.get()->isEmptyInfo()) {
            //FIXME: replace BLOCKING api in ui thread.
            FileInfoJob job(info);
            job.querySync();
        }

        if (!info->canWrite() && !m_is_ftp) {
            createAction->setEnabled(false);
        }

        if(m_top_window->getFilterWorking())
        {
            createAction->setEnabled(false);
        }
        l<<createAction;
        QMenu *subMenu = new QMenu(this);
        createAction->setMenu(subMenu);
        addAction(createAction);

        //enumerate template dir
        QDir templateDir(g_get_user_special_dir(G_USER_DIRECTORY_TEMPLATES));
        QString templatePath = templateDir.path();
        qWarning()<<"tempalte Path is"<<templatePath;
        QStringList fileNames;
        if(!templatePath.isEmpty())
        {
            QDir templateDir(templatePath);
            auto templates = templateDir.entryList(QDir::AllEntries|QDir::NoDotAndDotDot);
            if (!templates.isEmpty()) {
                for (auto t : templates) {
                    QFileInfo qinfo(templateDir, t);
                    qWarning()<<"template entry is"<<qinfo.filePath();
                    GFile *gtk_file = g_file_new_for_path(qinfo.filePath().toUtf8().constData());
                    char *uri_str = g_file_get_uri(gtk_file);
                    std::shared_ptr<FileInfo> info = FileInfo::fromUri(uri_str);
                    QIcon tmpIcon;
                    if (info->uri().endsWith(".desktop")) {
                        QUrl url = info->uri();
                        auto path = url.path();
                        auto key_file = g_key_file_new();
                        if (g_key_file_load_from_file(key_file, path.toUtf8().constData(), G_KEY_FILE_NONE, 0)) {
                            g_autofree gchar* icon_name = g_key_file_get_value(key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, 0);
                            if (icon_name) {
                                QString iconName = icon_name;
                                tmpIcon = QIcon::fromTheme(iconName);
                            }
                            g_key_file_free(key_file);
                        }
                    } else {
                        QString iconName = FileUtils::updateFileIconName(info->uri(), true);
                        tmpIcon = QIcon::fromTheme(iconName);
                    }


//                    QString mimeType = info->mimeType();
//                    if (mimeType.isEmpty()) {
//                        FileInfoJob job(info);
//                        job.querySync();
//                        mimeType = info->mimeType();
//                    }

//                    QIcon tmpIcon;
//                    GList *app_infos = g_app_info_get_recommended_for_type(mimeType.toUtf8().constData());
//                    GList *l = app_infos;
//                    QList<FileLaunchAction *> actions;
//                    bool isOnlyUnref = false;
//                    while (l) {
//                        auto app_info = static_cast<GAppInfo*>(l->data);
//                        if (!isOnlyUnref) {
//                            GIcon *icon = g_app_info_get_icon(app_info);
//                            QString iconName = FileUtils::getIconStringFromGIcon(icon);
//                            if (iconName.startsWith("/")) {
//                                tmpIcon.addFile(iconName);
//                            } else {
//                                tmpIcon = QIcon::fromTheme(iconName);
//                            }
//                            if(!tmpIcon.isNull())
//                                isOnlyUnref = true;
//                        }
//                        l = l->next;
//                    }
//                    g_list_free_full(app_infos, g_object_unref);

                    QAction *action = new QAction(tmpIcon, qinfo.baseName(), this);
                    connect(action, &QAction::triggered, this, [=]() {
                        // automatically check for conficts
                        CreateTemplateOperation op(m_directory, CreateTemplateOperation::Template, t);
                        Peony::FileOperationErrorDialogWarning dlg;
                        connect(&op, &Peony::FileOperation::errored, &dlg, &Peony::FileOperationErrorDialogWarning::handle);
                        op.run();
                        auto target = op.target();
                        m_uris_to_edit<<target;
                    });
                    subMenu->addAction(action);
                    fileNames.append(qinfo.fileName());
                    g_free(uri_str);
                    g_object_unref(gtk_file);
                }
                //subMenu->addSeparator();
            } else {
                qWarning()<<"template entries is empty";
            }
        } else {
            qWarning()<<"template path is empty";
        }

        templatePath = "/opt/kingsoft/wps-office/templates/";
        if(!templatePath.isEmpty())
        {
            QDir templateDir(templatePath);
            auto templates = templateDir.entryList(QDir::AllEntries|QDir::NoDotAndDotDot);
            if (!templates.isEmpty()) {
                for (auto t : templates) {
                    QFileInfo qinfo(templateDir, t);
                    auto abspath = qinfo.absoluteFilePath();
                    if (fileNames.contains(qinfo.fileName())) {
                        continue;
                    }

                    qWarning()<<"template entry is"<<qinfo.filePath();
                    GFile *gtk_file = g_file_new_for_path(qinfo.filePath().toUtf8().constData());
                    char *uri_str = g_file_get_uri(gtk_file);
                    std::shared_ptr<FileInfo> info = FileInfo::fromUri(uri_str);

                    QString mimeType = info->mimeType();
                    if (mimeType.isEmpty()) {
                        FileInfoJob job(info);
                        job.querySync();
                        mimeType = info->mimeType();
                    }

                    QIcon tmpIcon;
                    GList *app_infos = g_app_info_get_recommended_for_type(mimeType.toUtf8().constData());
                    GList *l = app_infos;
                    QList<FileLaunchAction *> actions;
                    bool isOnlyUnref = false;
                    while (l) {
                        auto app_info = static_cast<GAppInfo*>(l->data);
                        if (!isOnlyUnref) {
                            GThemedIcon *icon = G_THEMED_ICON(g_app_info_get_icon(app_info));
                            const char * const * icon_names = g_themed_icon_get_names(icon);
                            if (icon_names)
                                tmpIcon = QIcon::fromTheme(*icon_names);
                            if(!tmpIcon.isNull())
                                isOnlyUnref = true;
                        }
                        l = l->next;
                    }
                    g_list_free_full(app_infos, g_object_unref);

                    QAction *action = new QAction(tmpIcon, qinfo.baseName(), this);
                    connect(action, &QAction::triggered, [=]() {
                        // automatically check for conficts
                        CreateTemplateOperation op(m_directory, CreateTemplateOperation::Template, abspath);
                        Peony::FileOperationErrorDialogWarning dlg;
                        connect(&op, &Peony::FileOperation::errored, &dlg, &Peony::FileOperationErrorDialogWarning::handle);
                        op.run();
                        auto target = op.target();
                        m_uris_to_edit<<target;
                    });
                    subMenu->addAction(action);
                    g_free(uri_str);
                    g_object_unref(gtk_file);
                }
                subMenu->addSeparator();
            } else {
                qWarning()<<"template entries is empty";
            }
        } else {
            qWarning()<<"template path is empty";
        }

        QList<QAction *> actions;
        auto createEmptyFileAction = new QAction(QIcon::fromTheme("document-new-symbolic"), tr("Empty File"), this);
        actions<<createEmptyFileAction;
        connect(actions.last(), &QAction::triggered, this, [=]() {
            //FileOperationUtils::create(m_directory);
            CreateTemplateOperation op(m_directory);
            Peony::FileOperationErrorDialogWarning dlg;
            connect(&op, &Peony::FileOperation::errored, &dlg, &Peony::FileOperationErrorDialogWarning::handle);
            op.run();
            auto targetUri = op.target();
            qDebug()<<"target:"<<targetUri;
            m_uris_to_edit<<targetUri;
        });
        auto createFolderActions = new QAction(QIcon::fromTheme("folder-new-symbolic"), tr("Folder"), this);
        actions<<createFolderActions;
        connect(actions.last(), &QAction::triggered, this, [=]() {
            //FileOperationUtils::create(m_directory, nullptr, CreateTemplateOperation::EmptyFolder);
            CreateTemplateOperation op(m_directory, CreateTemplateOperation::EmptyFolder, tr("New Folder"));
            Peony::FileOperationErrorDialogWarning dlg;
            connect(&op, &Peony::FileOperation::errored, &dlg, &Peony::FileOperationErrorDialogWarning::handle);
            op.run();
            auto targetUri = op.target();
            qDebug()<<"target:"<<targetUri;
            m_uris_to_edit<<targetUri;
        });
        subMenu->addActions(actions);
    }

    return l;
}

const QList<QAction *> DirectoryViewMenu::constructViewOpActions()
{
    QList<QAction *> l;

    if (m_selections.isEmpty()) {
        ViewFactorySortFilterModel2 model;
        model.setDirectoryUri(m_directory);
        auto viewNames = model.supportViewIds();
        auto viewFactorysManager = DirectoryViewFactoryManager2::getInstance();

        if (!viewNames.isEmpty()) {
            //view type;
            auto viewTypeAction = addAction(QIcon::fromTheme("view-grid-symbolic"),tr("View Type"));
            viewTypeAction->setObjectName(VIEW_TYPE_ACTION);
            l<<viewTypeAction;
            QMenu *viewTypeSubMenu = new QMenu(this);
            for (auto viewId : viewNames) {
                auto viewType = viewTypeSubMenu->addAction(viewFactorysManager->getFactory(viewId)->viewIcon(), viewFactorysManager->getFactory(viewId)->viewName());
                viewType->setData(viewId);
                if (m_view->viewId() == viewId) {
                    viewType->setCheckable(true);
                    viewType->setChecked(true);
                } else {
                    connect(viewType, &QAction::triggered, this, [=]() {
                        m_top_window->beginSwitchView(viewType->data().toString());
                    });
                }
            }
            viewTypeAction->setMenu(viewTypeSubMenu);
        }

        //sort type
        auto sortTypeAction = addAction(QIcon::fromTheme("ukui-view-sort-letter-symbolic"),tr("Sort By"));
        sortTypeAction->setObjectName(SORT_TYPE_ACTION);
        l<<sortTypeAction;
        QMenu *sortTypeMenu = new QMenu(this);

        QList<QAction *> tmp;
        QPixmap emptyPixmap(0, 0);
        tmp<<sortTypeMenu->addAction(QIcon(emptyPixmap),tr("Name"));
        tmp<<sortTypeMenu->addAction(QIcon(emptyPixmap),tr("Time Modified"));
        tmp<<sortTypeMenu->addAction(tr("File Type"));
        tmp<<sortTypeMenu->addAction(tr("File Size"));
        tmp<<sortTypeMenu->addAction(tr("Original Path"));
        sortTypeMenu->setStyle(new MenuStyle(sortTypeMenu->style()));
        if (m_top_window->getCurrentUri() != "trash:///") {
            tmp.last()->setVisible(false);
        }
        if(m_top_window->getCurrentUri().startsWith("search:///")){
            tmp<<sortTypeMenu->addAction(tr("Path"));
        }

        int sortType = m_view->getSortType();
        if (sortType >= 0 && sortType < tmp.count()) {
            tmp.at(sortType)->setCheckable(true);
            tmp.at(sortType)->setChecked(true);
        } else {
            tmp.at(0)->setCheckable(true);
            tmp.at(0)->setChecked(true);
        }

        for (int i = 0; i < tmp.count(); i++) {
            connect(tmp.at(i), &QAction::triggered, this, [=]() {
                m_top_window->setCurrentSortColumn(i);
            });
        }
        sortTypeAction->setMenu(sortTypeMenu);

        //fix bug#82685
        if(m_is_computer){
            sortTypeAction->setEnabled(false);
        }

//        //sort order
//        auto sortOrderAction = addAction(tr("Sort Order"));
//        sortOrderAction->setObjectName(SORT_ORDER_ACTION);
//        l<<sortOrderAction;
        //QMenu *sortOrderMenu = new QMenu(this);
        QList<QAction *> sortTypeTmp;
        //fix bug#97408,change indicator meanings
        //箭头向上为升序，向下为降序，与通常的理解对应
        QStringList sortNames;
        sortNames.append(tr("Descending Order"));
        sortNames.append(tr("Ascending Order"));
        if (sortType == 1) {
            sortNames.clear();
            sortNames.append(tr("Newest to oldest"));
            sortNames.append(tr("Oldest to newest"));
        } else if (sortType == 3) {
            sortNames.clear();
            sortNames.append(tr("Files from large to small"));
            sortNames.append(tr("Files from small to large"));
        }
        sortTypeMenu->addSeparator();
        sortTypeTmp<<sortTypeMenu->addAction(QIcon::fromTheme("view-sort-descending-symbolic"),sortNames.at(0));
        sortTypeTmp<<sortTypeMenu->addAction(QIcon::fromTheme("view-sort-ascending-symbolic"),sortNames.at(1));
        int sortOrder = m_view->getSortOrder();
        sortTypeTmp.at(sortOrder)->setCheckable(true);
        sortTypeTmp.at(sortOrder)->setChecked(true);
        for (int i = 0; i < sortTypeTmp.count(); i++) {
            connect(sortTypeTmp.at(i), &QAction::triggered, this, [=]() {
                m_top_window->setCurrentSortOrder(Qt::SortOrder(i));
            });
        }

        //sortOrderAction->setMenu(sortOrderMenu);

        auto sortPreferencesAction = addAction(QIcon::fromTheme("ukui-view-sort-favorite-symbolic"),tr("Sort Preferences"));
        sortPreferencesAction->setObjectName(SORT_PREFERENCES_ACTION);
        l<<sortPreferencesAction;

        auto sortPreferencesMenu = new QMenu(this);
        auto folderFirst = sortPreferencesMenu->addAction(tr("Folder First"));
        folderFirst->setCheckable(true);
        folderFirst->setChecked(m_top_window->getWindowSortFolderFirst());
        connect(folderFirst, &QAction::triggered, this, [=](bool checked) {
            m_top_window->setSortFolderFirst(checked);
            //folderFirst->setChecked(checked);
        });

        if (QLocale::system().name().contains("zh")) {
            auto useDefaultNameSortOrder = sortPreferencesMenu->addAction(tr("Chinese First"));
            useDefaultNameSortOrder->setCheckable(true);
            useDefaultNameSortOrder->setChecked(m_top_window->getWindowUseDefaultNameSortOrder());
            connect(useDefaultNameSortOrder, &QAction::triggered, this, [=](bool checked) {
                m_top_window->setUseDefaultNameSortOrder(checked);
                //useDefaultNameSortOrder->setChecked(checked);
            });
        }

        auto showHidden = sortPreferencesMenu->addAction(tr("Show Hidden"));
        showHidden->setCheckable(true);
        showHidden->setChecked(m_top_window->getWindowShowHidden());
        connect(showHidden, &QAction::triggered, this, [=](bool checked) {
            m_top_window->setShowHidden(checked);
            //showHidden->setChecked(m_top_window->getWindowShowHidden());
        });

        sortPreferencesAction->setMenu(sortPreferencesMenu);
    }
    if(!m_is_trash){
        l<<addAction(QIcon::fromTheme("view-refresh-symbolic"), tr("Refresh"));
        l.last()->setObjectName(REFRESH_ACTION);
        l.last()->setShortcut(QKeySequence::Refresh);
        connect(l.last(), &QAction::triggered, this, [=]() {
            m_top_window->refresh();
        });
    }
    return l;
}

const QList<QAction *> DirectoryViewMenu::constructFileOpActions()
{
    QList<QAction *> l;

#if 0
    addAction("test set properties", this, [=]{
        QDialog d;
        QVBoxLayout *layout = new QVBoxLayout;
        auto hiddenBox = new QCheckBox("hidden");
        auto readonlyBox = new QCheckBox("readonly");
        auto recursiveBox = new QCheckBox("recusive");
        layout->addWidget(hiddenBox);
        layout->addWidget(readonlyBox);
        layout->addWidget(recursiveBox);
        auto button = new QPushButton("ok");
        layout->addWidget(button);
        connect(button, &QPushButton::clicked, &d, &QDialog::accept);
        d.setLayout(layout);
        if (d.exec()) {
            bool hidden = hiddenBox->isChecked();
            bool readonly = readonlyBox->isChecked();
            bool recursive = recursiveBox->isChecked();
            FileOperationUtils::setReadOnlyAndHidden(m_selections, readonly, hidden, recursive);
        }
    });
#endif

    if (!m_is_trash && !m_is_computer) {
        QString homeUri = "file://" +  QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
        bool hasStandardPath = FileUtils::containsStandardPath(m_selections);
        //qDebug() << "constructFileOpActions hasStandardPath:" <<hasStandardPath;
        if (!m_selections.isEmpty() && !m_selections.contains(homeUri) && !m_is_recent && !m_is_filesafe) {
            if (!hasStandardPath && !m_is_recent && !m_is_favorite && !m_is_filesafe && !m_is_label_model && !m_is_kydroid)
            {
                /* 经过讨论，对于搜索路径，如果当前操作目录可写时保留现有逻辑，不可写时和删除共用逻辑（即判断选中的第一个文件或文件夹的权限），这样改动影响比较小 */
                bool canCut = true;
                QString actualDir =  m_directory;
                if(actualDir.startsWith("search://")){
                    actualDir =  FileUtils::getActualDirFromSearchUri(m_directory);
                }
                auto info = FileInfo::fromUri(actualDir);
                if (!info->canWrite()) {
                    canCut = false;
                }
                if(m_is_search && !m_selections.isEmpty()){/* hotfix bug#222786 */
                    auto selectInfo = FileInfo::fromUri(m_selections.first());
                    canCut = FileUtils::isSearchFilesParentWriteable(m_selections, m_is_search);
                }
                if (canCut) {
                    l<<addAction(QIcon::fromTheme("edit-cut-symbolic"), tr("Cut"));
                    l.last()->setObjectName(CUT_ACTION);
                    l.last()->setShortcut(QKeySequence::Cut);
                    connect(l.last(), &QAction::triggered, this, [=]() {
                        ClipboardUtils::setClipboardFiles(m_selections, true, m_is_search);
                        m_view->repaintView();
                    });
                }
            }

            if (!m_is_favorite) {
                //code from lixiang for kydroid menu
                if (m_is_kydroid) {
                    bool hasDir = false;
                    for (auto uri : m_selections) {
                        auto info = FileInfo::fromUri(uri);
                        if (info->isDir()) {
                            hasDir = true;
                            break;
                        }
                    }
                    if (!hasDir) {
                        l<<addAction(QIcon::fromTheme("edit-copy-symbolic"), tr("Copy"));
                        l.last()->setObjectName(COPY_ACTION);
                        l.last()->setShortcut(QKeySequence::Copy);
                        connect(l.last(), &QAction::triggered, this, [=]() {
                            ClipboardUtils::setClipboardFiles(m_selections, false);
                        });
                    }
                }
                else {
                    l<<addAction(QIcon::fromTheme("edit-copy-symbolic"), tr("Copy"));
                    l.last()->setObjectName(COPY_ACTION);
                    // 设置 Ctrl+X 快捷键
                    l.last()->setShortcut(QKeySequence::Copy);
                    connect(l.last(), &QAction::triggered, this, [=]() {
                        ClipboardUtils::setClipboardFiles(m_selections, false);
                    });
                }
            }

            //kydroid has no cut,delete,rename option
            if (m_is_kydroid)
                return l;

            if (m_selections.count() > 0 && ! hasStandardPath && !m_is_recent && !m_is_favorite && !m_is_filesafe && !m_is_label_model) {
                l<<addAction(QIcon::fromTheme("rename-symbolic"), tr("Rename"));
                l.last()->setObjectName(RENAME_ACTION);
                l.last()->setShortcut(QKeySequence(Qt::Key_F2));
                if(m_is_search && m_selections.count() > 1){/* 搜索页面暂时不支持批量重命名,菜单置灰 */
                    l.last()->setEnabled(false);
                }
                connect(l.last(), &QAction::triggered, this, [=]() {
                    if (m_selections.count() == 1) {
                        m_view->editUri(m_selections.first());
                    } else if (m_selections.count() > 1) {
                        m_view->editUris(m_selections);
                    }
                });
            }

            bool hasDeleteForever = false;
            if (!m_is_recent && !m_is_favorite && !hasStandardPath && !m_is_filesafe && !m_is_label_model) {
                bool canTrash = true;
                bool canDelete = true;
                bool containsWhitelist = MANAGER_CONTROL->containsWhitelistApp(m_selections);

                /* 同一目录下文件夹和文件的info->cantrash()和info->canDelete()通常一样，采用m_selections.first()判断 */
                auto info = FileInfo::fromUri(m_selections.first());
                if (! info->canTrash())
                    canTrash = false;
                if (! info->canDelete() && (!m_selections.first().startsWith("ftp://")))/* 由于gio info 的can_delete=false,hotfix bug#98208【用例 100365】匿名访问ftp服务器，右键没有删除选项 */
                    canDelete = false;
                if(FileUtils::isLongNameFileOfNotDel2Trash(m_selections.first())){/* 在家目录/下载/扩展目录下存放的长文件名文件使用永久删除，link bug#188864 */
                    canTrash = false;
                }//end
                bool isDesktopDir = MANAGER_CONTROL->isDesktopDirectory(m_directory);
                //fix unencrypted box file can delete to trash issue, link to bug#72948
                // Only restrict delete operation when in desktop directory with whitelist apps
                if (canTrash && ! m_is_filebox_file && !m_is_mobile_file && !(isDesktopDir && containsWhitelist))
                {
                    l<<addAction(QIcon::fromTheme("user-trash-symbolic"), tr("Delete to trash"));
                    l.last()->setObjectName(TRASH_ACTION);
                    l.last()->setShortcut(QKeySequence::Delete);
                    connect(l.last(), &QAction::triggered, this, [=]() {
                        FileOperationUtils::trash(m_selections, true, m_is_search);
                    });
                }
                else if(m_can_delete && canDelete && !(isDesktopDir && containsWhitelist))
                {
                    hasDeleteForever = true;

                    //fix the bug 77131;
                    if(m_is_filebox_file){
                        l<<addAction(QIcon::fromTheme("edit-clear-symbolic"), tr("Delete"));
                        l.last()->setShortcut(QKeySequence::Delete);
                        l.last()->setObjectName(DELETE_ACTION);
                    }else if(!m_is_filebox_file || m_is_mobile_file){
                        l<<addAction(QIcon::fromTheme("edit-clear-symbolic"), tr("Delete forever"));
                        l.last()->setShortcut(QKeySequence::Delete);
                        l.last()->setObjectName(DELETE_ACTION);
                    }

                    connect(l.last(), &QAction::triggered, this, [=]() {
                        FileOperationUtils::executeRemoveActionWithDialog(m_selections);
                    });
                }
            }

            if ((m_is_favorite || m_is_label_model) && m_can_delete && !m_is_filesafe && !hasDeleteForever ) {
                l<<addAction(QIcon::fromTheme("edit-clear-symbolic"), tr("Delete forever"));
                l.last()->setShortcut(QKeySequence::Delete);
                l.last()->setObjectName(DELETE_ACTION);
                connect(l.last(), &QAction::triggered, this, [=]() {
                    FileOperationUtils::executeRemoveActionWithDialog(m_selections);
                });
            }

            if (m_is_smb_file && m_can_delete && !hasDeleteForever) {
                l<<addAction(QIcon::fromTheme("edit-clear-symbolic"), tr("Delete forever"));
                l.last()->setShortcut(QKeySequence::Delete);
                l.last()->setObjectName(DELETE_ACTION);
                connect(l.last(), &QAction::triggered, this, [=]() {
                    FileOperationUtils::executeRemoveActionWithDialog(m_selections);
                });
            }

            //fix ftp, sftp file can not delete issue, task#188197
            if (m_is_ftp && m_can_delete && !hasDeleteForever) {
                l<<addAction(QIcon::fromTheme("edit-clear-symbolic"), tr("Delete forever"));
                l.last()->setShortcut(QKeySequence::Delete);
                connect(l.last(), &QAction::triggered, [=]() {
                    FileOperationUtils::executeRemoveActionWithDialog(m_selections);
                });
            }
        } else {
            if (!m_is_search && !m_is_recent && !m_is_favorite && !m_is_kydroid && !m_is_filesafe && !m_is_cd && !m_is_label_model)
            {
                auto pasteAction = addAction(QIcon::fromTheme("edit-paste-symbolic"), tr("Paste"));
                l<<pasteAction;
                l.last()->setObjectName(PASTE_ACTION);
                l.last()->setShortcut(QKeySequence::Paste);
                //fix bug#183268, not allow paste in mtp, gphoto2 path or can not write path
                auto info = FileInfo::fromUri(m_directory);
                bool isDirectoryCanWrite = true;
                if (!info->isEmptyInfo()) {
                    isDirectoryCanWrite = info->canWrite();
                    if (!isDirectoryCanWrite) {
                        QString fileSystem = info.get()->fileSystemType();
                        if (fileSystem.isEmpty()) {
                            fileSystem = FileUtils::getFsTypeFromFile(info.get()->uri());
                            qDebug() << "file system :" << fileSystem;
                        }
                        if (fileSystem.contains("udf")) {
                            qDebug() << "file system contains:" << fileSystem;
                            isDirectoryCanWrite = true;
                        }
                    }
                }
                //comment to fix bug#191108, huawei phone can paste file success
//                if (m_directory.startsWith("mtp://") || m_directory.startsWith("gphoto2://")){
//                    isDirectoryCanWrite = false;
//                }

                pasteAction->setEnabled(ClipboardUtils::isClipboardHasFiles() && isDirectoryCanWrite);
                connect(l.last(), &QAction::triggered, this, [=]() {
                    auto op = ClipboardUtils::pasteClipboardFiles(m_directory);
                    if (op) {
                        auto window = dynamic_cast<QWidget *>(m_top_window);
                        auto iface = m_top_window;
                        connect(op, &Peony::FileOperation::operationFinished, window, [=](){
                            auto opInfo = op->getOperationInfo();
                            auto targetUirs = opInfo->dests();
                            //fix bug#196528, selection files icon not update issue
                            QTimer::singleShot(300, window, [=](){
                                iface->setCurrentSelectionUris(targetUirs);
                            });
                        }, Qt::BlockingQueuedConnection);
                    }
                    else{
                        //fix paste file in old path not update issue, link to bug#71627
                        m_top_window->getCurrentPage()->getView()->repaintView();
                    }
                });
            }
            else if (m_is_recent && m_selections.count() >0)
            {
                //fix recent files can not be deleted issue        
                l<<addAction(QIcon::fromTheme("edit-copy-symbolic"), tr("Copy"));
                l.last()->setObjectName(COPY_ACTION);
                l.last()->setShortcut(QKeySequence::Copy);
                connect(l.last(), &QAction::triggered, this, [=]() {
                    QStringList selections;
                    for(auto uri:m_selections)
                    {
                        uri = FileUtils::getTargetUri(uri);
                        selections << uri;
                    }
                    ClipboardUtils::setClipboardFiles(selections, false);
                });

                l<<addAction(QIcon::fromTheme("user-trash-symbolic"), tr("Delete"));
                l.last()->setShortcut(QKeySequence::Delete);
                l.last()->setObjectName(DELETE_ACTION);
                connect(l.last(), &QAction::triggered, this, [=]() {
                    FileOperationUtils::remove(m_selections);
                });

            }          
        }
    }

    //select all and reverse select
    if (m_selections.isEmpty() && !m_is_trash &&!m_is_recent)
    {
        l<<addAction(QIcon::fromTheme("edit-select-all-symbolic"),tr("Select All"));
        l.last()->setObjectName(SELECT_ALL_ACTION);
        l.last()->setShortcut(QKeySequence("Ctrl+A"));
        connect(l.last(), &QAction::triggered, this, [=]() {
            //qDebug() << "select all";
            m_view->invertSelections();
        });
    }
    else if(! m_is_kydroid && !m_is_trash&&!m_is_recent)
    {
        l<<addAction(QIcon::fromTheme("edit-select-invert-symbolic"),tr("Reverse Select"));
        l.last()->setObjectName(REVERSE_SELECT_ACTION);
        connect(l.last(), &QAction::triggered, this, [=]() {
            //qDebug() << "Reverse select";
            m_view->invertSelections();
        });
    }

    if (m_selections.isEmpty())
        addActions(FileOperationManager::getInstance()->getUndoRedoActions());

    return l;
}

const QList<QAction *> DirectoryViewMenu::constructFilePropertiesActions()
{
    QList<QAction *> l;

    //fix select mutiple file in trash path show empty issue
    if (m_selections.count() > 1 && (m_is_trash || m_is_recent))
        return l;

    //favorite is should not show property
    if (m_selections.isEmpty() && m_directory == "favorite:///")
        return l;

    if (! m_is_search) {
        //包含network的情况下，不显示属性选项
        if (m_is_network) {
            return l;
        }

        for (QString uri : m_selections) {
            if (uri.startsWith("network://")) {
                return l;
            }
        }

        l<<addAction(QIcon::fromTheme("properties-symbolic"), tr("Properties"));
        l.last()->setShortcut(QKeySequence("Alt+Enter"));
        l.last()->setObjectName(PROPERTIES_ACTION);
        connect(l.last(), &QAction::triggered, this, [=]() {
            //FIXME:
            if (m_selections.isEmpty()) {
                QStringList uris;
                uris<<m_directory;
                //QMainWindow *p = PropertiesWindowFactoryPluginManager::getInstance()->create(uris);
                //PropertiesWindow *p = new PropertiesWindow(uris);
                //if(this->parentWidget() && this->parentWidget()->isModal()){
                //    p->setParent(this->parentWidget());
                //}
                //p->setAttribute(Qt::WA_DeleteOnClose);
                //PropertiesWindowFactoryPluginManager::getInstance()->show();
                //p->show();
                if(this->parentWidget() && this->parentWidget()->isModal()){
                    QMainWindow *p = PropertiesWindowFactoryPluginManager::getInstance()->create(uris, this->parentWidget());
                    p->setAttribute(Qt::WA_DeleteOnClose);
                } else {
                    QMainWindow *p = PropertiesWindowFactoryPluginManager::getInstance()->create(uris);
                    p->setAttribute(Qt::WA_DeleteOnClose);
                }
                PropertiesWindowFactoryPluginManager::getInstance()->show();
            } else {
                QStringList selectUriList;
                if (m_selections.first().contains("favorite:///")) {
                    for (auto uriIndex = 0; uriIndex < m_selections.count(); ++uriIndex) {
                        if (m_selections.at(uriIndex) == "favorite:///?schema=trash"
                        || m_selections.at(uriIndex) == "favorite:///?schema=recent") {
                            QStringList urisList;
                            urisList << FileUtils::getTargetUri(m_selections.at(uriIndex));
                            //PropertiesWindow *p = new PropertiesWindow(urisList);
                            //QMainWindow *p = PropertiesWindowFactoryPluginManager::getInstance()->create(urisList);
                            //if(this->parentWidget() && this->parentWidget()->isModal()){
                            //    p->setParent(this->parentWidget());
                            //}
                            //p->setAttribute(Qt::WA_DeleteOnClose);
                            //PropertiesWindowFactoryPluginManager::getInstance()->show();
                            //p->show();
                            if(this->parentWidget() && this->parentWidget()->isModal()){
                                QMainWindow *p = PropertiesWindowFactoryPluginManager::getInstance()->create(urisList, this->parentWidget());
                                p->setAttribute(Qt::WA_DeleteOnClose);
                            } else {
                                QMainWindow *p = PropertiesWindowFactoryPluginManager::getInstance()->create(urisList);
                                p->setAttribute(Qt::WA_DeleteOnClose);
                            }
                            PropertiesWindowFactoryPluginManager::getInstance()->show();
                        } else {
                            selectUriList<< m_selections.at(uriIndex);
                        }
                    }
                }else if(m_selections.first().startsWith("label:///") && m_version != "ukui3.0"){
                    for(auto &labelUri : m_selections){/* 标记模式页面为不同目录下的文件（夹），所以每个都需要一个属性对话框 */
                        QStringList urisList;
                        urisList.append(labelUri);
                        //QMainWindow *p = PropertiesWindowFactoryPluginManager::getInstance()->create(urisList);
                        //PropertiesWindow *p = new PropertiesWindow(urisList);
                        //if(this->parentWidget() && this->parentWidget()->isModal()){
                        //    p->setParent(this->parentWidget());
                        //}
                        //p->setAttribute(Qt::WA_DeleteOnClose);
                        //PropertiesWindowFactoryPluginManager::getInstance()->show();
                        //p->show();
                        if(this->parentWidget() && this->parentWidget()->isModal()){
                            QMainWindow *p = PropertiesWindowFactoryPluginManager::getInstance()->create(urisList, this->parentWidget());
                            p->setAttribute(Qt::WA_DeleteOnClose);
                        } else {
                            QMainWindow *p = PropertiesWindowFactoryPluginManager::getInstance()->create(urisList);
                            p->setAttribute(Qt::WA_DeleteOnClose);
                        }
                        PropertiesWindowFactoryPluginManager::getInstance()->show();
                    }
                }else {
                    selectUriList = m_selections;
                }

                if (selectUriList.count() > 0) {
                    //QMainWindow *p = PropertiesWindowFactoryPluginManager::getInstance()->create(selectUriList);
                    //PropertiesWindow *p = new PropertiesWindow(selectUriList);
                    //if(this->parentWidget() && this->parentWidget()->isModal()){
                    //    p->setParent(this->parentWidget());
                    //}
                    //p->setAttribute(Qt::WA_DeleteOnClose);
                    //PropertiesWindowFactoryPluginManager::getInstance()->show();
                    //p->show();
                    if(this->parentWidget() && this->parentWidget()->isModal()){
                        QMainWindow *p = PropertiesWindowFactoryPluginManager::getInstance()->create(selectUriList, this->parentWidget());
                        p->setAttribute(Qt::WA_DeleteOnClose);
                    } else {
                        QMainWindow *p = PropertiesWindowFactoryPluginManager::getInstance()->create(selectUriList);
                        p->setAttribute(Qt::WA_DeleteOnClose);
                    }
                    PropertiesWindowFactoryPluginManager::getInstance()->show();
                }
            }
        });
    } else if (m_selections.count() == 1) {
        l<<addAction(QIcon::fromTheme("properties-symbolic"), tr("Properties"));
        l.last()->setShortcut(QKeySequence("Alt+Return"));
        l.last()->setObjectName(PROPERTIES_ACTION);
        connect(l.last(), &QAction::triggered, this, [=]() {
            //QMainWindow *p = PropertiesWindowFactoryPluginManager::getInstance()->create(m_selections);
            //PropertiesWindow *p = new PropertiesWindow(m_selections);
            //if(this->parentWidget() && this->parentWidget()->isModal()){
            //    p->setParent(this->parentWidget());
            //}
            //p->setAttribute(Qt::WA_DeleteOnClose);
            //PropertiesWindowFactoryPluginManager::getInstance()->show();
            //p->show();
            if(this->parentWidget() && this->parentWidget()->isModal()){
                QMainWindow *p = PropertiesWindowFactoryPluginManager::getInstance()->create(m_selections, this->parentWidget());
                p->setAttribute(Qt::WA_DeleteOnClose);
            } else {
                QMainWindow *p = PropertiesWindowFactoryPluginManager::getInstance()->create(m_selections);
                p->setAttribute(Qt::WA_DeleteOnClose);
            }
            PropertiesWindowFactoryPluginManager::getInstance()->show();
        });
    }

    return l;
}

const QList<QAction *> DirectoryViewMenu::constructComputerActions()
{
    QList<QAction *> l;
    if (m_is_computer && m_selections.count() == 1) {
        QString uri = m_selections.first();

        auto info = FileInfo::fromUri(uri);
        if (info->displayName().isEmpty() || info->targetUri().isEmpty()) {
            FileInfoJob j(info);
            j.querySync();
        }

        //not allow format data block, fix bug#66471，66479
        QString targetUri = FileUtils::getTargetUri(uri);
        if (uri == "file:///data" || targetUri == "file:///data"
            || (uri.startsWith("file:///media") && uri.endsWith("/data"))
            || (targetUri.startsWith("file:///media") && targetUri.endsWith("/data")))
            return l;

        auto mount = VolumeManager::getMountFromUri(info->targetUri());
        //fix bug#52491, CDROM and DVD can format issue
        if (nullptr != mount) {
            QString unixDevice = FileUtils::getUnixDevice(info->uri());
            if (! unixDevice.isNull() && ! unixDevice.contains("/dev/sr")
                && info->isVolume() && info->canUnmount()) {
                l<<addAction(QIcon::fromTheme("format-symbolic"), tr("format"), this, [=] () {
                    // FIXME:// refactory Format_Dialog
                    Format_Dialog* fd  = new Format_Dialog(info->uri(), nullptr, m_view);
                    fd->show();
//                    Format_Dialog *fd = format_dlg_create_delegate::getInstance()->createDlg(info->uri(), nullptr);
//                    fd->show();
                });
                l.last()->setObjectName(FORMAT_ACTION);

                if (!mount) {
                    l.last()->setEnabled(false);
                }
            }
        }
    }

    return l;
}

const QList<QAction *> DirectoryViewMenu::constructTrashActions()
{
    QList<QAction *> l;

    if (m_is_trash) {
        bool isTrashEmpty = m_top_window->getCurrentAllFileUris().isEmpty();

        if (m_selections.isEmpty()) {
            l<<addAction(QIcon::fromTheme("edit-select-all-symbolic"),tr("Select All"));
            l.last()->setObjectName(SELECT_ALL_ACTION);
            l.last()->setShortcut(QKeySequence("Ctrl+A"));
            connect(l.last(), &QAction::triggered, this, [=]() {
                //qDebug() << "select all";
                m_view->invertSelections();
            });
            l<<addSeparator();
            l<<addAction(QIcon::fromTheme("user-trash-symbolic"), tr("&Clean the Trash"));
            l.last()->setObjectName(CLEAN_THE_TRASH_ACTION);
            l.last()->setEnabled(!isTrashEmpty);
            connect(l.last(), &QAction::triggered, this, [=]() {
                auto uris = m_top_window->getCurrentAllFileUris();
//                auto removeop = Peony::FileOperationUtils::clearRecycleBinWithDialog(uris, this->topLevelWidget());
                // fix #161877 【文件管理器】回收站内右键空白处选择情况回收站，确认弹窗不居中
                auto removeop = Peony::FileOperationUtils::clearRecycleBinWithDialog(uris, dynamic_cast<QWidget *>(m_top_window));

                qApp->setProperty("clearTrash",true);
//                    if(removeop){
//                        removeop->connect(removeop,&Peony::FileDeleteOperation::operationFinished, [=](){
//                            Peony::SoundEffect::getInstance()->recycleBinClearMusic();
//                        });
//                    }

//                AudioPlayManager::getInstance()->playWarningAudio();
//                auto result = QMessageBox::question(nullptr, tr("Delete Permanently"), tr("Are you sure that you want to delete these files? "
//                                                                                          "Once you start a deletion, the files deleting will never be "
//                                                                                          "restored again."));
//                if (result == QMessageBox::Yes) {
////                    SoundEffect::getInstance()->recycleBinClearMusic();
//                    auto uris = m_top_window->getCurrentAllFileUris();
//                    FileOperationUtils::remove(uris);
//                }
            });

        } else {
            l<<addAction(QIcon::fromTheme("edit-cut-symbolic"),tr("Cut"));
            l.last()->setShortcut(QKeySequence::Cut);
            l.last()->setObjectName(CUT_ACTION);
            connect(l.last(), &QAction::triggered, this, [=]() {
                ClipboardUtils::setClipboardFiles(m_selections, true, m_is_search);
                m_view->repaintView();
            });
            l<<addAction(QIcon::fromTheme("edit-copy-symbolic"),tr("Copy"));
            l.last()->setObjectName(COPY_ACTION);
            l.last()->setShortcut(QKeySequence::Copy);
            connect(l.last(), &QAction::triggered, this, [=]() {
                ClipboardUtils::setClipboardFiles(m_selections, false);
            });

            l<<addAction(QIcon::fromTheme("user-trash-symbolic"), tr("Delete"));
            l.last()->setShortcut(QKeySequence::Delete);
            l.last()->setObjectName(DELETE_ACTION);
            connect(l.last(), &QAction::triggered, this, [=]() {
                AudioPlayManager::getInstance()->playWarningAudio();
                int result = 0;
                QString message = QObject::tr("Are you sure you want to permanently delete this file?"
                                      " Once deletion begins, "
                                      "the file will not be recoverable.");
                if (m_selections.count() > 1) {
                    message = QObject::tr("Are you sure you want to permanently delete these %1 files?"
                                          " Once deletion begins, "
                                          "these file will not be recoverable.").arg(m_selections.count());
                }


                QMessageBox msgBox;
                msgBox.setText(message);
                msgBox.setIcon(QMessageBox::Question);
                QPushButton *deleteButton = msgBox.addButton(tr("Delete"), QMessageBox::AcceptRole);
                deleteButton->setProperty("isImportant", true);
                msgBox.addButton(tr("Cancel"), QMessageBox::RejectRole);
                deleteButton->setDefault(true);

                result = msgBox.exec();
                if (msgBox.clickedButton() == deleteButton) {
//                    SoundEffect::getInstance()->recycleBinClearMusic();
                    FileOperationUtils::remove(m_selections);
                }
            });

            l<<addAction(QIcon::fromTheme("edit-select-invert-symbolic"),tr("Reverse Select"));
            l.last()->setObjectName(REVERSE_SELECT_ACTION);
            connect(l.last(), &QAction::triggered, this, [=]() {
                //qDebug() << "Reverse select";
                m_view->invertSelections();
            });
            l<<addSeparator();
            l<<addAction(QIcon::fromTheme("document-revert-symbolic"),tr("Restore"));
            l.last()->setObjectName(RESTORE_ACTION);
            connect(l.last(), &QAction::triggered, this, [=]() {
                if (m_selections.count() == 1) {
                    auto untrashop = FileOperationUtils::restore(m_selections.first());
                    if(untrashop){
                        auto window = dynamic_cast<QWidget *>(m_top_window);
                        untrashop->connect(untrashop,&Peony::FileUntrashOperation::operationFinished,window, [=](){
                            //Peony::SoundEffect::getInstance()->copyOrMoveSucceedMusic();
                            //Task#152997, use sdk play sound
#ifdef KY_SDK_SOUND_EFFECTS
                            kdk::KSoundEffects::playSound(SoundType::OPERATION_FILE);
#endif
                        });
                    }
                } else {
                    auto untrashop = FileOperationUtils::restore(m_selections);
                    if(untrashop){
                        auto window = dynamic_cast<QWidget *>(m_top_window);
                        untrashop->connect(untrashop,&Peony::FileUntrashOperation::operationFinished,window, [=](){
                            //Peony::SoundEffect::getInstance()->copyOrMoveSucceedMusic();
                            //Task#152997, use sdk play sound
#ifdef KY_SDK_SOUND_EFFECTS
                            kdk::KSoundEffects::playSound(SoundType::OPERATION_FILE);
#endif
                        });
                    }
                }
//                qApp->setProperty("restoreFile",true);
            });
        }
    } else if (m_is_recent && m_selections.isEmpty()) {        
        l<<addAction(QIcon::fromTheme("edit-select-all-symbolic"),tr("Select All"));
        l.last()->setObjectName(SELECT_ALL_ACTION);
        l.last()->setShortcut(QKeySequence("Ctrl+A"));
        connect(l.last(), &QAction::triggered, this, [=]() {
            //qDebug() << "select all";
            m_view->invertSelections();
        });
        l<<addSeparator();

        l<<addAction(QIcon::fromTheme("user-trash-symbolic"),tr("Clean All"));
        l.last()->setObjectName(CLEAN_THE_RECENT_ACTION);
        connect(l.last(), &QAction::triggered, this, [=]() {
            RecentVFSManager::getInstance()->clearAll();
        });
    }

    return l;
}

const QList<QAction *> DirectoryViewMenu::constructSearchActions()
{
    QList<QAction *> l;
    if (m_is_search || m_is_recent) {
        if (m_selections.isEmpty())
            return l;

        l<<addAction(QIcon::fromTheme("window-new-symbolic"), tr("Open Parent Folder in New Window"));
        l.last()->setObjectName(OPEN_IN_NEW_WINDOW_ACTION);
        connect(l.last(), &QAction::triggered, this, [=]() {
            for (auto uri : m_selections) {
                if (m_is_recent)
                    uri = FileUtils::getTargetUri(uri);
                auto parentUri = FileUtils::getParentUri(uri);
                //bool exist = FileUtils::isFileExsit(uri);
                bool exist = true;
                if (exist && ! parentUri.isNull()) {
                    auto *windowIface = m_top_window->create(parentUri);
                    auto newWindow = dynamic_cast<QWidget *>(windowIface);
                    auto selection = m_selections;
#if QT_VERSION > QT_VERSION_CHECK(5, 12, 0)
                    QTimer::singleShot(1000, newWindow, [=]() {
                        if (newWindow)
                            windowIface->setCurrentSelectionUris(selection);
                    });
#else
                    QTimer::singleShot(1000, newWindow, [=]() {
                        if (newWindow)
                            windowIface->setCurrentSelectionUris(selection);
                    });
#endif
                    newWindow->show();
                 }
                else
                {
                    QMessageBox::warning(nullptr,
                                         tr("Error"),
                                         tr("File:\"%1\" is not exist, did you moved or deleted it?").arg(QUrl(uri).path()));
                }
            }
        });
    }
    return l;
}

const QList<QAction *> DirectoryViewMenu::constructIsoMountActions()
{
    QList<QAction *> l;

    if (m_selections.count() == 1) {
        QString uri = m_selections.first();
        if (!IMAGE_MOUNT_MANAGER->isImageFile(uri)) {
            return l;
        }

        auto mountAction = addAction(QIcon::fromTheme("drive-multidisk-symbolic"), tr("Mount"));
        l << mountAction;
        connect(mountAction, &QAction::triggered, this, [=]() {
            IMAGE_MOUNT_MANAGER->mountImage(uri);
        });
    }

    return l;
}

bool DirectoryViewMenu::isMultFile(std::shared_ptr<FileInfo> info)
{
    if (!info) {
        qDebug() << "file info not valid";
        return false;
    }

    QString uri = info->uri();
    if (uri.startsWith("mult:///") && (!info->isDir())) {
        return true;
    }

    return false;
}

void DirectoryViewMenu::isMobileFile(const QString &uri)
{
    if(uri.startsWith("file:///media/")){
        QString unixDevice = FileInfo::fromUri(uri).get()->unixDeviceFile();
        bool canEject = false;
        bool canStop = false;
        FileEnumerator e;
        e.setEnumerateDirectory("computer:///");
        e.enumerateSync();
        for (auto fileInfo : e.getChildren()) {
            QString uriStr = fileInfo.get()->uri();
            GFile* gFile = g_file_new_for_uri(uriStr.toUtf8().constData());
            GError *err = nullptr;
            QString device;
            bool can_eject = false;
            bool can_stop = false;
            QString target_uri;
            GFileInfo* gFileInfo = g_file_query_info(gFile,
                                           "standard::*," "time::*," "access::*," "mountable::*," "metadata::*," "trash::*," G_FILE_ATTRIBUTE_ID_FILE,
                                           G_FILE_QUERY_INFO_NONE,
                                           g_cancellable_new(),
                                           &err);
            if (err) {
                DEBUG<<err->code<<err->message;
                g_error_free(err);
                g_object_unref(gFile);
                g_object_unref(gFileInfo);
                continue;
            }else{
                if(g_file_info_has_attribute(gFileInfo,G_FILE_ATTRIBUTE_MOUNTABLE_UNIX_DEVICE_FILE)){
                    device = g_file_info_get_attribute_string(gFileInfo,G_FILE_ATTRIBUTE_MOUNTABLE_UNIX_DEVICE_FILE);
                }
                target_uri = g_file_info_get_attribute_string(gFileInfo, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI);
                can_eject = g_file_info_get_attribute_boolean(gFileInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT);
                can_stop = g_file_info_get_attribute_boolean(gFileInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_STOP);
            }
            g_object_unref(gFile);
            g_object_unref(gFileInfo);
            if((device == unixDevice) || (!target_uri.isEmpty() && uri.startsWith(target_uri))){
                canEject = can_eject;
                canStop = can_stop;
                break;
            }
        }

        if(canEject || canStop){
            m_is_mobile_file = true;
        }
        DEBUG<<"unixDevice:"<<unixDevice<<"canEject:"<<canEject<<"canStop"<<canStop<<"m_is_mobile_file"<<m_is_mobile_file;
    }else{
        auto dev = VolumeManager::getDriveFromUri(uri);
        if(dev != nullptr){
            bool canEject = g_drive_can_eject(dev.get()->getGDrive());
            bool canStop = g_drive_can_stop(dev.get()->getGDrive());
            if(canEject || canStop){
                m_is_mobile_file = true;
            }
            qDebug() << "canEject :" << canEject;
        }
    }
}

const QList<QAction *> DirectoryViewMenu::constructMenuPluginActions()
{
    QList<QAction *> l;
    if (!m_is_favorite && !m_is_label_model) {
        auto pluginIds = MenuPluginManager::getInstance()->getPluginIds();
        //sort plugiins by name, so the menu option orders is relatively fixed
        std::sort(pluginIds.begin(), pluginIds.end());
        QString shareMenuFileName = QString("libpeony-share-menu-plugin.so");
        auto sharePlugin = PluginManager::getInstance()->getPluginByFileName(shareMenuFileName);
        auto sharePluginId = PluginManager::getInstance()->getPluginId(sharePlugin);
        
        for (auto id : pluginIds) {
            if (!MANAGER_CONTROL->checkSmbSharePermission() && sharePluginId == id) {
                qDebug() << "SMB share plugin disabled, skipping:" << id;
                continue;
            }
            
            auto plugin = MenuPluginManager::getInstance()->getPlugin(id);
            auto tPlugin = MenuPluginManager::getInstance()->getFileSafePlugin(id);
            auto pluginObj = dynamic_cast<QObject *>(plugin);
            if(m_is_filesafe||m_is_filebox_file) {
                if((plugin && tPlugin && plugin == tPlugin)
                        || pluginObj->property("IsFileSafeShow").toBool()) {
                    auto actions = plugin->menuActions(MenuPluginInterface::DirectoryView, m_directory, m_selections);
                    l<<actions;
                    for (auto action : actions) {
                        action->setParent(this);
                        action->setObjectName(plugin->name());
                        addAction(action);
                        if(action->icon().isNull()){
                            auto pluginicon = plugin->icon();
                            if(!pluginicon.isNull()){
                                action->setIcon(pluginicon);
                            }
                        }
                    }
                    if(id == "Peony File Labels Menu Extension" && m_version != "ukui3.0"){
                        l<<addSeparator();
                    }
                }
            } else {
                if(plugin != tPlugin) {
                    auto a = Peony::FileOperationManager::getInstance()->isFsynchronizing();
                    if(m_is_mobile_file && Peony::FileOperationManager::getInstance()->isFsynchronizing()){
                        /* 往移动设备中进行文件拷贝fysnc时导致io阻塞，插件暂先屏蔽,待后续改进 */
                        //todo
                        DEBUG<<"mobile file is synchronizing";
                    }else{
                        auto actions = plugin->menuActions(MenuPluginInterface::DirectoryView, m_directory, m_selections);
                        l<<actions;
                        for (auto action : actions) {
                            action->setParent(this);
                            action->setObjectName(plugin->name());
                            addAction(action);
                            if(action->icon().isNull()){
                                auto pluginicon = plugin->icon();
                                if(!pluginicon.isNull()){
                                    action->setIcon(pluginicon);
                                }
                            }
                        }
                        if(id == "Peony File Labels Menu Extension" && m_version != "ukui3.0"){
                            l<<addSeparator();
                        }
                    }
                }
            }
        }
    }

    auto isoActions = constructIsoMountActions();
    if (!isoActions.isEmpty()) {
        if (l.length() > 0) {
            l.last()->setObjectName(ISO_MOUNT_ACTIONS);
        }
        l << isoActions;
    }
    return l;
}

const QList<QAction *> DirectoryViewMenu::constructMultiSelectActions()
{
    QList<QAction *> l;
    if (m_version == "ukui3.0" || !GlobalSettings::getInstance()->getValue(SHOW_MULTISELECT_CHECKBOX).toBool()) {
        return l;
    }

    auto MultiSelectAction = addAction(tr("MultiSelect"));
    l<<MultiSelectAction;
    connect(l.last(), &QAction::triggered, [=]() {
        Peony::DirectoryViewHelper::globalInstance()->getViewIface2ByDirectoryViewWidget(m_view)->doMultiSelect(true);
    });
    return l;

}

void DirectoryViewMenu::keyPressEvent(QKeyEvent *e)
{
    QMenu::keyPressEvent(e);
    if(e->key() == Qt::Key_F10 && e->modifiers() == Qt::ShiftModifier) {
        close();
    }
}
