7#include <QStandardPaths> 
   12#include <QProcessEnvironment> 
   14#if defined(Q_OS_ANDROID) 
   15#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 
   16#include <QtCore/private/qandroidextras_p.h> 
   20#ifdef HAVE_RABBITCOMMON_GUI 
   22    #include <QMainWindow> 
   23    #include <QMessageBox> 
   24    #include <QPushButton> 
   25    #include <QApplication> 
   26    #include <QDesktopServices> 
   30        #include "Information.h" 
   33    #include <QCoreApplication> 
   36#include "RabbitCommonTools.h" 
   37#include "RabbitCommonDir.h" 
   38#ifdef HAVE_ADMINAUTHORISER 
   39#include "AdminAuthoriser/adminauthoriser.h" 
   41#include "RabbitCommonRegister.h" 
   44#if defined(HAVE_OPENSSL) 
   45    #include "openssl/opensslv.h" 
   46    #include "openssl/crypto.h" 
   47    #include "openssl/ssl.h" 
   63    #include "CoreDump/MiniDumper.h" 
   65#include "CoreDump/StackTrace.h" 
   67#ifdef HAVE_RABBITCOMMON_GUI 
   68    #include "Log/DockDebugLog.h" 
   69    #include "Log/DlgFilter.h" 
   78#include "cmark-gfm-core-extensions.h" 
   81inline void g_RabbitCommon_InitResource()
 
   83    Q_INIT_RESOURCE(ResourceRabbitCommon);
 
   92    Q_INIT_RESOURCE(QUIWidgetQss);
 
   97inline void g_RabbitCommon_CleanResource()
 
   99    Q_CLEANUP_RESOURCE(ResourceRabbitCommon);
 
  100#ifdef BUILD_QUIWidget 
  105#ifdef BUILD_QUIWidget 
  106    Q_CLEANUP_RESOURCE(QUIWidgetQss);
 
  113static Q_LOGGING_CATEGORY(log, 
"RabbitCommon.Tools")
 
  114static Q_LOGGING_CATEGORY(logTranslation, "
RabbitCommon.Tools.Translation")
 
  116static CCallTrace* g_pCallStack = 
nullptr;
 
  118CTools::CTools() : QObject()
 
  119    , m_Initialized(false)
 
  120#if defined(Q_OS_ANDROID) 
  121    , m_bShowMaxWindow(
true)
 
  123    , m_bShowMaxWindow(
false)
 
  127    cmark_gfm_core_extensions_ensure_registered();
 
  135    qDebug(log) << 
"CTools::~CTools()";
 
  136#if HAVE_RABBITCOMMON_GUI 
  138        delete g_pDcokDebugLog;
 
  142CTools* CTools::Instance()
 
  144    static CTools* pTools = 
nullptr;
 
  145    if(
nullptr == pTools)
 
  146        pTools = 
new CTools();
 
  150static QString g_szLanguage;
 
  151int CTools::SetLanguage(
const QString szLanguage)
 
  153    g_szLanguage = szLanguage;
 
  159    QString szLANG = QProcessEnvironment::systemEnvironment().value(
"LANG");
 
  160    if(szLANG.isEmpty()) {
 
  161        if(g_szLanguage.isEmpty())
 
  162            return QLocale::system().name();
 
  165        int underscoreIndex = szLANG.indexOf(
'.');
 
  166        if (underscoreIndex != -1) {
 
  167            szLANG.truncate(underscoreIndex);
 
 
  177    QString szVersion(RabbitCommon_VERSION);
 
  178    QString szRevision(RabbitCommon_REVISION);
 
  179    if(szRevision.isEmpty()) {
 
  180        szReturn = tr(
"Version: ") + szVersion;
 
  182        szReturn = tr(
"Version: ") + szVersion + tr(
" (From revision: "); 
 
  183#if (defined(HAVE_CMARK) || defined(HAVE_CMARK_GFM)) 
  184        szReturn += 
"[" + szRevision + 
"](http://github.com/KangLin/RabbitCommon/tree/" + szRevision + 
")";
 
  186        szReturn += szRevision;
 
 
  196    szInfo = tr(
"- Functions:") + 
"\n";
 
  197    szInfo += tr(
"  - Locale: ") + 
GetLanguage() + 
"\n";
 
  198#if defined(HAVE_RABBITCOMMON_GUI) 
  199    szInfo += tr(
"  - Have GUI") + 
"\n";
 
  200#if defined(HAVE_ABOUT) 
  201    szInfo += tr(
"    - Have About dialog") + 
"\n";
 
  203    szInfo += tr(
"    - Use cmark-gfm") + 
"\n";
 
  205    szInfo += tr(
"      - Use cmark") + 
"\n";
 
  208#if defined(HAVE_UPDATE) 
  209    szInfo += tr(
"    - Have Update") + 
"\n";
 
  211    szInfo += tr(
"    - Custom title bar for QWidget") + 
"\n";
 
  212    szInfo += tr(
"    - Dock Folder browser") + 
"\n";
 
  213    szInfo += tr(
"    - Recent menu") + 
"\n";
 
  214    szInfo += tr(
"    - Style") + 
"\n";
 
  215    szInfo += tr(
"      - Icon theme: ") + QIcon::themeName() + 
"\n";
 
  216    #if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) 
  217    szInfo += tr(
"      - Fall back icon theme: ") + QIcon::fallbackThemeName() + 
"\n";
 
  220    szInfo += tr(
"  - Log") + 
"\n";
 
  221    szInfo += tr(
"    - Core dump") + 
"\n";
 
  222    szInfo += tr(
"    - Log file: ") + CLog::Instance()->GetLogFile() + 
"\n";
 
  223#if defined(HAVE_OPENSSL) 
  224    szInfo += tr(
"  - Have encrypt(OPENSSL)") + 
"\n";
 
  226#if defined(BUILD_QUIWidget) 
  227    szInfo += tr(
"  - Have QUIWidget") + 
"\n";
 
  229    szInfo += tr(
"  - Application paths and files: ") + 
"\n";
 
  230    szInfo += tr(
"    - Installation root path: ") + RabbitCommon::CDir::Instance()->GetDirApplicationInstallRoot() + 
"\n";
 
  231    szInfo += tr(
"    - Application path: ") + RabbitCommon::CDir::Instance()->GetDirApplication() + 
"\n";
 
  232    szInfo += tr(
"    - Configure path: ") + RabbitCommon::CDir::Instance()->GetDirConfig() + 
"\n";
 
  233    szInfo += tr(
"    - Configure file: ") + RabbitCommon::CDir::Instance()->GetFileApplicationConfigure() + 
"\n";
 
  234    szInfo += tr(
"    - Translations path: ") + RabbitCommon::CDir::Instance()->
GetDirTranslations() + 
"\n";
 
  235    szInfo += tr(
"    - Log path: ") + RabbitCommon::CDir::Instance()->GetDirLog() + 
"\n";
 
  236    szInfo += tr(
"    - Data path: ") + RabbitCommon::CDir::Instance()->
GetDirData() + 
"\n";
 
  237    szInfo += tr(
"    - Icons path: ") + RabbitCommon::CDir::Instance()->GetDirIcons() + 
"\n";
 
  238    szInfo += tr(
"    - Database path: ") + RabbitCommon::CDir::Instance()->GetDirDatabase() + 
"\n";
 
  239    szInfo += tr(
"    - Database file: ") + RabbitCommon::CDir::Instance()->GetDirDatabaseFile() + 
"\n";
 
  240    szInfo += tr(
"    - Plugins path: ") + RabbitCommon::CDir::Instance()->GetDirPlugins() + 
"\n";
 
  241    szInfo += tr(
"  - User folders and files: ") + 
"\n";
 
  242    szInfo += tr(
"    - Documents path: ") + RabbitCommon::CDir::Instance()->GetDirUserDocument() + 
"\n";
 
  243    szInfo += tr(
"    - Configure path: ") + RabbitCommon::CDir::Instance()->GetDirUserConfig() + 
"\n";
 
  244    szInfo += tr(
"    - Configure file: ") + RabbitCommon::CDir::Instance()->GetFileUserConfigure() + 
"\n";
 
  245    szInfo += tr(
"    - Data path: ") + RabbitCommon::CDir::Instance()->GetDirUserData() + 
"\n";
 
  246    szInfo += tr(
"    - Image path: ") + RabbitCommon::CDir::Instance()->GetDirUserImage() + 
"\n";
 
  247    szInfo += tr(
"    - Database path: ") + RabbitCommon::CDir::Instance()->GetDirUserDatabase() + 
"\n";
 
  248    szInfo += tr(
"    - Database file: ") + RabbitCommon::CDir::Instance()->GetDirUserDatabaseFile() + 
"\n";
 
  250    szInfo += tr(
"- Dependent libraries:") + 
"\n";
 
  251    szInfo += tr(
"  - OpenSSL:") + 
"\n";
 
  252#if defined(HAVE_OPENSSL) 
  253    szInfo += 
"    - " + tr(
"Build Version: ") + OPENSSL_VERSION_TEXT + 
"\n";
 
  254    szInfo += 
"    - " + tr(
"Runtime Version: ") + OpenSSL_version(OPENSSL_VERSION) + 
"\n";
 
  256    if(QSslSocket::supportsSsl())
 
  258#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 3)) 
  259        szInfo += 
"    - Qt " + tr(
"Build Version: ") + QSslSocket::sslLibraryBuildVersionString() + 
"\n";
 
  261        szInfo += 
"    - Qt " + tr(
"Installed Version: ") + QSslSocket::sslLibraryVersionString() + 
"\n";
 
  263#if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 3)) 
  264        szInfo += 
"    - Qt " + tr(
"Build Version: ") + QSslSocket::sslLibraryBuildVersionString() + 
"\n";
 
  266        szInfo += 
"    - Qt " + tr(
"Don't install OPENSSL dynamic library. Please install it") + 
"\n";
 
  269    szInfo += tr(
"  - StackWalker") + 
"\n";
 
  272    szInfo += tr(
"  - cmark-gfm") + 
"\n";
 
  274    szInfo += tr(
"  - cmark") + 
"\n";
 
 
  279int CTools::AndroidRequestPermission(
const QString &permission)
 
  281#if defined (Q_OS_ANDROID) 
  282    #if QT_VERSION > QT_VERSION_CHECK(6, 0, 0) 
  286    if (QtAndroidPrivate::checkPermission(permission).result()
 
  287        == QtAndroidPrivate::Denied)
 
  289        QtAndroidPrivate::requestPermission(permission).waitForFinished();
 
  291    qInfo(log) << 
"android permission" << permission << 
";status:" 
  292                  << QtAndroidPrivate::checkPermission(permission).result();
 
  299int CTools::AndroidRequestPermission(
const QStringList &permissions)
 
  301    foreach (
auto p, permissions) {
 
  302        AndroidRequestPermission(p);
 
  309    if(1 > argc || !argv) {
 
  310        qCritical(log) << 
"The parameters is error";
 
  316    QFileInfo fi(argv[0]);
 
  317    if(szApplicationName.isEmpty())
 
  318        szName = fi.baseName();
 
  320        szName = szApplicationName;
 
  321    szPath = fi.absolutePath();
 
  322    Init(szName, szPath, szPath + QDir::separator() + 
"..");
 
 
  326                  QString szApplicationDirPath,
 
  327                  QString szApplicationInstallRoot,
 
  328                  const QString szLanguage)
 
  331        qWarning(log) << 
"CTools is already initialized";
 
  335#if defined(HAVE_WebEngineWidgets) 
  337    if(!qEnvironmentVariable(
"SNAP").isEmpty()) {
 
  338        qputenv(
"QTWEBENGINE_DISABLE_SANDBOX", 
"1");
 
  341    if(QCoreApplication::applicationName().isEmpty())
 
  343        QCoreApplication::setApplicationName(szApplicationName);
 
  344        CDir::Instance()->SetDirUserDocument();
 
  346    if(QCoreApplication::applicationDirPath().isEmpty()
 
  347        && CDir::Instance()->GetDirApplication().isEmpty())
 
  348        CDir::Instance()->SetDirApplication(szApplicationDirPath);
 
  349    if(CDir::Instance()->GetDirApplicationInstallRoot().isEmpty())
 
  350        CDir::Instance()->SetDirApplicationInstallRoot(szApplicationInstallRoot);
 
  351    if(QCoreApplication::applicationName().isEmpty()
 
  352        || CDir::Instance()->GetDirApplication().isEmpty()
 
  353        || CDir::Instance()->GetDirApplicationInstallRoot().isEmpty())
 
  356            << 
"CTools::Instance()->Init() is called after QApplication a(argc, argv);" 
  357               "Or call this function with the parameters" 
  358               "szApplicationName, " 
  359               "szApplicationDirPath, " 
  360               "and szApplicationInstallRoot";
 
  365    QStringList permissions;
 
  366    permissions << 
"android.permission.WRITE_EXTERNAL_STORAGE" 
  367                << 
"android.permission.INTERNET" 
  368                << 
"android.permission.ACCESS_NETWORK_STATE" 
  369                << 
"android.permission.CHANGE_WIFI_STATE" 
  370                << 
"android.permission.ACCESS_WIFI_STATE" 
  371                << 
"android.permission.ACCESS_NETWORK_STATE" 
  372                << 
"android.permission.CHANGE_NETWORK_STATE";
 
  373    AndroidRequestPermission(permissions);
 
  375    RabbitCommon::CLog::Instance();
 
  376    SetLanguage(szLanguage);
 
  377    qInfo(logTranslation) << 
"Language:" << szLanguage;
 
  381    QString szQtTranslationPath;
 
  382#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 
  383    szQtTranslationPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
 
  385    szQtTranslationPath = QLibraryInfo::path(QLibraryInfo::TranslationsPath);
 
  387    QStringList qtTranslations;
 
  388    qtTranslations << 
"qt" << 
"qtbase" << 
"qtmultimedia" 
  390#if HAVE_WebEngineWidgets 
  391    qtTranslations << 
"qtwebengine";
 
  393    foreach(
auto f, qtTranslations) {
 
  394        QString szFile = szQtTranslationPath + QDir::separator()
 
  395                 + f + 
"_" + szLanguage + 
".qm";
 
  398            InstallTranslatorFile(szFile);
 
  400            qWarning(logTranslation) << 
"The file doesn't exists: " << szFile;
 
  403#ifdef HAVE_RABBITCOMMON_GUI 
  404    QSettings set(RabbitCommon::CDir::Instance()->GetFileUserConfigure(),
 
  405                  QSettings::IniFormat);
 
  406    m_bShowMaxWindow = set.value(
"Tools/Window/ShowMax", m_bShowMaxWindow).toBool();
 
  408    CStyle::Instance()->LoadStyle();
 
  410    CInformation info(
"RabbitCommon, Qt and System information:", 
"");
 
  413    qDebug(log) << 
"RabbitCommon:" << 
"\n" << 
Information();
 
 
  419    foreach(
auto t, m_Translator) {
 
  420        QCoreApplication::removeTranslator(t.data());
 
  422    m_Translator.clear();
 
  424    delete RabbitCommon::CLog::Instance();
 
 
  427QSharedPointer<QTranslator> CTools::InstallTranslatorFile(
const QString szFile)
 
  429    QSharedPointer<QTranslator> translator
 
  430        = QSharedPointer<QTranslator>(
new QTranslator());
 
  432        qCritical(logTranslation) << 
"new QTranslator fail";
 
  435    bool bRet = translator->load(szFile);
 
  438        bRet = QCoreApplication::installTranslator(translator.data());
 
  441            m_Translator.push_back(translator);
 
  442            qDebug(logTranslation) << 
"Install translator:" << szFile;
 
  446            qCritical(logTranslation) << 
"Install translator fail:" << szFile;
 
  449        qCritical(logTranslation) << 
"Load translator file fail:" << szFile;
 
  450    return QSharedPointer<QTranslator>();
 
  454    const QString szName,
 
  455    TranslationType type,
 
  456    const QString szPluginDir,
 
  457    const QString szLanguage)
 
  459    QString szTranslationName = szName;
 
  463    szSuffix = QDir::separator() + szTranslationName + 
"_" + szLanguage + 
".qm";
 
  465    case TranslationType::Application:
 
  466        szPath = CDir::Instance()->GetDirTranslations();
 
  467        if(szTranslationName.isEmpty()) {
 
  468            szTranslationName = QCoreApplication::applicationName();
 
  469            szSuffix = QDir::separator() + szTranslationName + 
"_" + szLanguage + 
".qm";
 
  472    case TranslationType::Library: {
 
  473        szPath = CDir::Instance()->GetDirTranslations();
 
  474        if(szTranslationName.isEmpty()) {
 
  475            qCritical(logTranslation) << 
"Please set translation name";
 
  478#if defined(Q_OS_LINUX) 
  479        QFile file(szPath + szSuffix);
 
  481            szPath = CDir::Instance()->GetDirTranslations(
"/usr/share");
 
  482            file.setFileName(szPath + szSuffix);
 
  484                szPath = CDir::Instance()->GetDirTranslations(
 
  491    case TranslationType::Plugin:
 
  492        szPath = CDir::Instance()->GetDirPluginsTranslation(szPluginDir);
 
  493        if(szTranslationName.isEmpty()) {
 
  494            qCritical(logTranslation) << 
"Please set translation name";
 
  500    QString szFile = szPath + szSuffix;
 
  504        qCritical(logTranslation) << 
"File isn't exit:" << szFile;
 
  505        return QSharedPointer<QTranslator>();
 
  508    return InstallTranslatorFile(szFile);
 
 
  511int CTools::RemoveTranslator(QSharedPointer<QTranslator> translator)
 
  513    foreach(
auto t, m_Translator) {
 
  514        if(t == translator) {
 
  515            QCoreApplication::removeTranslator(t.data());
 
  516            m_Translator.removeAll(t);
 
  523void CTools::InitResource()
 
  525    g_RabbitCommon_InitResource();
 
  528void CTools::CleanResource()
 
  530    g_RabbitCommon_CleanResource();
 
  533#if defined(Q_OS_UNIX) 
  534void SigHandler(
int sig)
 
  541        qCritical(log) << 
"Receive exception signal:" << sig << 
"\n" 
  542                       << g_pCallStack->GetStack(3).toStdString().c_str();
 
  545        qDebug(log) << 
"Receive signal:" << sig;
 
  559    RabbitCommon::EnableMiniDumper();
 
  562    signal(SIGSEGV, SigHandler);
 
  564    signal(SIGBUS, SigHandler);
 
  566    signal(SIGILL, SigHandler);
 
 
  573#ifdef HAVE_ADMINAUTHORISER 
  574    return CAdminAuthoriser::Instance()->hasAdminRights();
 
 
  580bool CTools::ExecuteWithAdministratorPrivilege(
const QString &program,
 
  581                                               const QStringList &arguments,
 
  584#ifdef HAVE_ADMINAUTHORISER 
  585    CAdminAuthoriser::Instance()->SetDetached(bDetached);
 
  586    return CAdminAuthoriser::Instance()->execute(program, arguments);
 
  594    return ExecuteWithAdministratorPrivilege(program, arguments);
 
 
  601        auto para = QApplication::arguments();
 
  602        QString szApp = QApplication::applicationFilePath();
 
  604#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0) && defined(Q_OS_WIN) 
  605        szAppImage = qEnvironmentVariable(
"APPIMAGE");
 
  607        szAppImage = QString::fromLocal8Bit(qgetenv(
"APPIMAGE"));
 
  609        qDebug(log) << 
"App:" << szApp << szAppImage;
 
  610        if(!szAppImage.isEmpty())
 
  615            bRet = ExecuteWithAdministratorPrivilege(szApp);
 
  617            bRet = ExecuteWithAdministratorPrivilege(szApp, para);
 
  620#ifdef HAVE_RABBITCOMMON_GUI 
  621                auto pMainWindow = GetMainWindow();
 
  624                    QMetaObject::invokeMethod(pMainWindow, 
"close", Qt::QueuedConnection);
 
  629                        QMetaObject::invokeMethod(qApp, 
"quit", Qt::QueuedConnection);
 
  633            qCritical(log) << 
"Start by root fail:" << QCoreApplication::applicationFilePath()
 
 
  646    appPath = QCoreApplication::applicationFilePath();
 
  648    if(!szPath.isEmpty())
 
  650    if(appPath.isEmpty())
 
  652        qCCritical(log) << 
"szPath is empty";
 
  656        return RabbitCommon::CRegister::InstallStartRun();
 
  657    return RabbitCommon::CRegister::InstallStartRunCurrentUser();
 
  664    if(QFile::exists(szLink))
 
  665        if(RemoveStartRun(szName, bAllUser))
 
  667            qCCritical(log) << 
"RemoveStartRun" << szName << 
"fail";
 
  675        qCCritical(log) << 
"The desktop file doesn't exist: " << appPath;
 
  678    bool ret = f.link(szLink);
 
  681        QString szCmd = 
"ln -s " + appPath + 
" " + szLink;
 
  682        if(!ExecuteWithAdministratorPrivilege(szCmd))
 
  683            qCritical(log) << 
"CTools::InstallStartRun: file link" 
  684                              << f.fileName() << 
" to " << szLink << f.error();
 
 
  691int CTools::RemoveStartRun(
const QString &szName, 
bool bAllUser)
 
  694    QString appName = QCoreApplication::applicationName();
 
  695    if(!szName.isEmpty())
 
  698        return RabbitCommon::CRegister::RemoveStartRun();
 
  699    return RabbitCommon::CRegister::RemoveStartRunCurrentUser();
 
  702    if(!QFile::exists(szLink)) 
return 0;
 
  705    if(d.remove(szLink)) 
return 0;
 
  707    QString szCmd = 
"rm " + szLink;
 
  708    if(ExecuteWithAdministratorPrivilege(szCmd)) 
return 0;
 
  709    qCritical(log) << 
"execute" << szCmd << 
"fail";
 
  714bool CTools::IsStartRun(
const QString &szName, 
bool bAllUser)
 
  719        return RabbitCommon::CRegister::IsStartRun();
 
  720    return RabbitCommon::CRegister::IsStartRunCurrentUser();
 
  723    if(QFile::exists(szLink))
 
  729                                const QString &szName)
 
  736    szContent = 
"[Desktop Entry]\n";
 
  737    szContent += 
"Name=" + QCoreApplication::applicationName() + 
"\n";
 
  738    szContent += 
"Comment=" + QCoreApplication::applicationName() + 
"\n";
 
  739#ifdef HAVE_RABBITCOMMON_GUI 
  740    szContent += 
"Name[" + QLocale::system().name() + 
"]=" + QApplication::applicationDisplayName() + 
"\n";
 
  741    szContent += 
"Comment[" + QLocale::system().name() + 
"]=" + QApplication::applicationDisplayName() + 
"\n";
 
  743    szContent += 
"Name[" + QLocale::system().name() + 
"]=" + QCoreApplication::applicationName() + 
"\n";
 
  744    szContent += 
"Comment[" + QLocale::system().name() + 
"]=" + QCoreApplication::applicationName() + 
"\n";
 
  746    szContent += 
"Icon=" + QCoreApplication::applicationName() + 
"\n";
 
  747    szContent += 
"Exec=" + QCoreApplication::applicationFilePath() + 
"\n";
 
  748    szContent += 
"Categories=Application;Development;\n";
 
  749    szContent += 
"Terminal=false\n";
 
  750    szContent += 
"StartupNotify=true\n";
 
  753    if(!f.open(QFile::WriteOnly))
 
  757    f.write(szContent.toStdString().c_str());
 
 
  762QString CTools::GetCurrentUser()
 
  766    pwd = getpwuid(getuid());
 
  769    CHAR szUserName[MAX_PATH] = {0};
 
  770    DWORD dwSize=MAX_PATH;
 
  771    ::GetUserNameA(szUserName, &dwSize);
 
  775    return QDir::home().dirName();
 
  779QString CTools::GetHostName()
 
  782    gethostname(buf, 
sizeof(buf));
 
  786QString CTools::MarkDownToHtml(
const QString &szText)
 
  788    QString szHtml = szText;
 
  789#if defined(HAVE_CMARK_GFM) || defined(HAVE_CMARK) 
  790    char* pHtml = cmark_markdown_to_html(szText.toStdString().c_str(),
 
  791                                         szText.toStdString().length(),
 
  798        qCritical(log) << 
"cmark_markdown_to_html fail";
 
  834#ifdef HAVE_RABBITCOMMON_GUI 
  835QAction* CTools::AddStyleMenu(QMenu *pMenu, QWidget *parent)
 
  837    return pMenu->addAction(QIcon::fromTheme(
"style"),
 
  846void CTools::InsertStyleMenu(QMenu *pMenu, QAction *before, QWidget *parent)
 
  848    QAction* pAction = 
new QAction(QIcon::fromTheme(
"style"),
 
  849                                   tr(
"Style"), parent);
 
  852    pAction->setStatusTip(tr(
"Style"));
 
  853    QObject::connect(pAction, &QAction::triggered, [=](){
 
  858    pMenu->insertAction(before, pAction);
 
  861QMenu* CTools::GetLogMenu(QWidget *parentMainWindow)
 
  863    QMenu* pMenu = 
new QMenu(tr(
"Log"), parentMainWindow);
 
  864    if(!pMenu) 
return pMenu;
 
  865    pMenu->setStatusTip(tr(
"Log"));
 
  866    pMenu->setIcon(QIcon::fromTheme(
"folder-open"));
 
  867    QAction* pAction = pMenu->addAction(QIcon::fromTheme(
"emblem-system"),
 
  871                         QString szInclude, szExclude;
 
  872                         CLog::Instance()->GetFilter(szInclude, szExclude);
 
  873                         dlg.SetFilter(szInclude, szExclude);
 
  874                         if(QDialog::Accepted == RC_SHOW_WINDOW(&dlg))
 
  876                             dlg.GetFilter(szInclude, szExclude);
 
  877                             CLog::Instance()->SetFilter(szInclude, szExclude);
 
  880    pAction->setStatusTip(pAction->text());
 
  881    pAction = pMenu->addAction(QIcon::fromTheme(
"document-open"),
 
  882                     tr(
"Open Log configure file"),
 
  883                     [](){RabbitCommon::OpenLogConfigureFile();});
 
  884    pAction->setStatusTip(pAction->text());
 
  885    pAction = pMenu->addAction(QIcon::fromTheme(
"document-open"),
 
  887                     [](){RabbitCommon::OpenLogFile();});
 
  888    pAction->setStatusTip(pAction->text());
 
  889    pAction = pMenu->addAction(QIcon::fromTheme(
"folder-open"),
 
  890                     tr(
"Open Log folder"),
 
  891                     [](){RabbitCommon::OpenLogFolder();});
 
  892    pAction->setStatusTip(pAction->text());
 
  894    QMainWindow* pMainWindow = qobject_cast<QMainWindow*>(parentMainWindow);
 
  896        pMenu->addSeparator();
 
  899        pMainWindow->addDockWidget(Qt::DockWidgetArea::BottomDockWidgetArea,
 
  902        g_pDcokDebugLog->setObjectName(
"dockDebugLog");
 
  903        QAction* pDock = g_pDcokDebugLog->toggleViewAction();
 
  904        pMenu->addAction(pDock);
 
  905        pDock->setText(tr(
"Log dock"));
 
  906        pDock->setIcon(QIcon::fromTheme(
"floating"));
 
  907        pDock->setStatusTip(tr(
"Log dock"));
 
  909        qWarning(log) << 
"CTools::GetLogMenu: Don't use dock debug log." 
  910                         <<  
"The parent suggest is MainWindow pointer";
 
  913    pMenu->addSeparator();
 
  914    pAction = pMenu->addAction(QIcon::fromTheme(
"edit-copy"),
 
  915                               tr(
"Copy log file path to clipboard"),
 
  916                               [](){RabbitCommon::CopyLogFileToClipboard();});
 
  917    pAction->setStatusTip(pAction->text());
 
  918    pAction = pMenu->addAction(QIcon::fromTheme(
"edit-copy"),
 
  919                               tr(
"Copy log folder to clipboard"),
 
  920                               [](){RabbitCommon::CopyLogFolderToClipboard();});
 
  921    pAction->setStatusTip(pAction->text());
 
  926int CTools::RestoreWidget(QWidget *pWidget)
 
  930    if(!pWidget) 
return -1;
 
  931    QSettings set(RabbitCommon::CDir::Instance()->GetFileUserConfigure(),
 
  932                  QSettings::IniFormat);
 
  934            = set.value(
"MainWindow/Status/Geometry").toByteArray();
 
  935    if(!geometry.isEmpty()) {
 
  936        if(!pWidget->restoreGeometry(geometry))
 
  937            qWarning(log) << 
"Restore geometry fail";
 
  939    QMainWindow* pMainWindow = qobject_cast<QMainWindow*>(pWidget);
 
  941        QByteArray state = set.value(
"MainWindow/Status/State").toByteArray();
 
  942        if(!state.isEmpty()) {
 
  943            if(!pMainWindow->restoreState(state))
 
  944                qWarning(log) << 
"Restore state fail";
 
  950int CTools::SaveWidget(QWidget *pWidget)
 
  954    if(!pWidget) 
return -1;
 
  955    QSettings set(RabbitCommon::CDir::Instance()->GetFileUserConfigure(),
 
  956                  QSettings::IniFormat);
 
  957    set.setValue(
"MainWindow/Status/Geometry", pWidget->saveGeometry());
 
  958    QMainWindow* pMainWindow = qobject_cast<QMainWindow*>(pWidget);
 
  960        set.setValue(
"MainWindow/Status/State", pMainWindow->saveState());
 
  965int CTools::ShowWidget(QWidget *pWin)
 
  968        qCritical(log) << Q_FUNC_INFO << 
"The parameter is nullptr";
 
  973    QDialog* pDlg = qobject_cast<QDialog*>(pWin);
 
  975        if(m_bShowMaxWindow) {
 
  976            pDlg->showMaximized();
 
  980        if(m_bShowMaxWindow) {
 
  981            pWin->showMaximized();
 
  988void CTools::ShowCoreDialog(QString szTitle, QString szContent, QString szDetail, QString szCoreDumpFile)
 
  990    g_pCallStack->ShowCoreDialog(szTitle, szContent, szDetail, szCoreDumpFile);
 
  993#if defined(Q_OS_LINUX) 
  995QString detectDesktopEnvironment() {
 
  996    QString desktop = qgetenv(
"XDG_CURRENT_DESKTOP");
 
  997    if (desktop.isEmpty()) {
 
  998        desktop = qgetenv(
"DESKTOP_SESSION");
 
 1000    return desktop.toLower();
 
 1004bool openFileLocation(
const QString &szFile) {
 
 1006    QFileInfo fileInfo(szFile);
 
 1007    if (!fileInfo.exists()) {
 
 1008        qCritical(log) << 
"File does not exist:" << szFile;
 
 1012    QString desktopEnv = detectDesktopEnvironment();
 
 1013    qDebug(log) << 
"Detected desktop environment:" << desktopEnv;
 
 1014    QStringList lstPara;
 
 1016    lstPara << 
"--select" << fileInfo.absoluteFilePath();
 
 1017    if (desktopEnv.contains(
"gnome") || desktopEnv.contains(
"ubuntu") || desktopEnv.contains(
"unity")) {
 
 1018        szProgram = 
"nautilus";
 
 1019    } 
else if (desktopEnv.contains(
"kde") || desktopEnv.contains(
"plasma")) {
 
 1020        szProgram = 
"dolphin";
 
 1021    } 
else if (desktopEnv.contains(
"xfce")) {
 
 1022        szProgram = 
"thunar";
 
 1023    } 
else if (desktopEnv.contains(
"lxde") || desktopEnv.contains(
"lubuntu")) {
 
 1024        szProgram = 
"pcmanfm";
 
 1025    } 
else if(desktopEnv.contains(
"mate")) {
 
 1028    qDebug(log) << 
"Program:" << szProgram << 
"Para:" << lstPara;
 
 1029    if(!szProgram.isEmpty()) {
 
 1030        bRet = QProcess::startDetached(szProgram, lstPara);
 
 1032        bRet = QDesktopServices::openUrl(QUrl::fromLocalFile(fileInfo.absolutePath()));
 
 1052bool CTools::LocateFileWithExplorer(
const QString szFile)
 
 1056    QString command = 
"explorer";
 
 1057    QStringList args = {
"/select,", QDir::toNativeSeparators(szFile)};
 
 1058    bRet = QProcess::startDetached(command, args);
 
 1059#elif defined(Q_OS_MAC) 
 1061    args << 
"-e" << QString(
"tell application \"Finder\" to reveal POSIX file \"%1\"").arg(szFile);
 
 1062    args << 
"-e" << 
"tell application \"Finder\" to activate";
 
 1063    bRet = QProcess::startDetached(
"osascript", args);
 
 1064#elif defined(Q_OS_LINUX) 
 1065    bRet = openFileLocation(szFile);
 
 1069        QFileInfo fileInfo(szFile);
 
 1070        if (!fileInfo.exists()) {
 
 1071            qCritical(log) << 
"File does not exist:" << szFile;
 
 1074        bRet = QDesktopServices::openUrl(QUrl::fromLocalFile(fileInfo.absolutePath()));
 
 1079QMainWindow* CTools::GetMainWindow()
 
 1081    foreach (QWidget *w, qApp->topLevelWidgets()) {
 
 1082        if (QMainWindow* mainWin = qobject_cast<QMainWindow*>(w)) {
 
Set style and icon theme form.
 
QString GetDirData(bool bReadOnly=false)
Get data directory.
 
QString GetDirTranslations(QString szPrefix=QString())
 
static QString GetDesktopFileLink(const QString &szName=QString(), bool bAllUser=false)
GetDesktopFileLink.
 
static QString GetDesktopFileName(const QString &szPath=QString(), const QString &szName=QString())
Generate the name of desktop file.