Repair project structure.
This commit is contained in:
parent
03ac37afe2
commit
d8ff48bef1
|
@ -0,0 +1,35 @@
|
||||||
|
QT -= gui
|
||||||
|
|
||||||
|
TARGET = chinese-segmentation
|
||||||
|
TEMPLATE = lib
|
||||||
|
DEFINES += LIBCHINESESEGMENTATION_LIBRARY
|
||||||
|
|
||||||
|
CONFIG += c++11
|
||||||
|
|
||||||
|
# The following define makes your compiler emit warnings if you use
|
||||||
|
# any Qt feature that has been marked deprecated (the exact warnings
|
||||||
|
# depend on your compiler). Please consult the documentation of the
|
||||||
|
# deprecated API in order to know how to port your code away from it.
|
||||||
|
DEFINES += QT_DEPRECATED_WARNINGS
|
||||||
|
|
||||||
|
# You can also make your code fail to compile if it uses deprecated APIs.
|
||||||
|
# In order to do so, uncomment the following line.
|
||||||
|
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||||
|
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||||
|
#include(jieba/jieba.pri)
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
chinese-segmentation.cpp \
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
chinese-segmentation.h \
|
||||||
|
libchinese-segmentation_global.h
|
||||||
|
|
||||||
|
# Default rules for deployment.
|
||||||
|
unix {
|
||||||
|
target.path = /usr/lib
|
||||||
|
}
|
||||||
|
!isEmpty(target.path): INSTALLS += target
|
||||||
|
|
||||||
|
#DISTFILES += \
|
||||||
|
# jiaba/jieba.pri
|
|
@ -0,0 +1,200 @@
|
||||||
|
#include "app-match.h"
|
||||||
|
#include <glib.h>
|
||||||
|
#include "chinesecharacterstopinyin.h"
|
||||||
|
AppMatch::AppMatch(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
this->getDesktopFilePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList AppMatch::startMatchApp(QString input){
|
||||||
|
input.replace(" ","");
|
||||||
|
m_soureText=input;
|
||||||
|
m_returnResult.clear();
|
||||||
|
if(input.isEmpty()){
|
||||||
|
return m_returnResult;
|
||||||
|
}
|
||||||
|
this->getAppName();
|
||||||
|
m_returnResult=m_midResult;
|
||||||
|
m_midResult.clear();
|
||||||
|
return m_returnResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppMatch::getAllDesktopFilePath(QString path){
|
||||||
|
|
||||||
|
GKeyFileFlags flags=G_KEY_FILE_NONE;
|
||||||
|
GKeyFile* keyfile=g_key_file_new ();
|
||||||
|
|
||||||
|
QDir dir(path);
|
||||||
|
if (!dir.exists()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dir.setFilter(QDir::Dirs|QDir::Files|QDir::NoDotAndDotDot);
|
||||||
|
dir.setSorting(QDir::DirsFirst);
|
||||||
|
QFileInfoList list = dir.entryInfoList();
|
||||||
|
list.removeAll(QFileInfo("/usr/share/applications/screensavers"));
|
||||||
|
if(list.size()< 1 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int i=0;
|
||||||
|
|
||||||
|
//递归算法的核心部分
|
||||||
|
do{
|
||||||
|
QFileInfo fileInfo = list.at(i);
|
||||||
|
//如果是文件夹,递归
|
||||||
|
bool isDir = fileInfo.isDir();
|
||||||
|
if(isDir) {
|
||||||
|
getAllDesktopFilePath(fileInfo.filePath());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
//过滤LXQt、KDE
|
||||||
|
QString filePathStr=fileInfo.filePath();
|
||||||
|
if(filePathStr.contains("KDE",Qt::CaseInsensitive)||
|
||||||
|
filePathStr.contains("mate",Qt::CaseInsensitive)||
|
||||||
|
filePathStr.contains("LX",Qt::CaseInsensitive) ){
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//过滤后缀不是.desktop的文件
|
||||||
|
if(!filePathStr.endsWith(".desktop"))
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
QByteArray fpbyte=filePathStr.toLocal8Bit();
|
||||||
|
char* filepath=fpbyte.data();
|
||||||
|
g_key_file_load_from_file(keyfile,filepath,flags,nullptr);
|
||||||
|
char* ret_1=g_key_file_get_locale_string(keyfile,"Desktop Entry","NoDisplay", nullptr, nullptr);
|
||||||
|
if(ret_1!=nullptr)
|
||||||
|
{
|
||||||
|
QString str=QString::fromLocal8Bit(ret_1);
|
||||||
|
if(str.contains("true"))
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char* ret_2=g_key_file_get_locale_string(keyfile,"Desktop Entry","NotShowIn", nullptr, nullptr);
|
||||||
|
if(ret_2!=nullptr)
|
||||||
|
{
|
||||||
|
QString str=QString::fromLocal8Bit(ret_2);
|
||||||
|
if(str.contains("UKUI"))
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//过滤中英文名为空的情况
|
||||||
|
QLocale cn;
|
||||||
|
QString language=cn.languageToString(cn.language());
|
||||||
|
if(QString::compare(language,"Chinese")==0)
|
||||||
|
{
|
||||||
|
char* nameCh=g_key_file_get_string(keyfile,"Desktop Entry","Name[zh_CN]", nullptr);
|
||||||
|
char* nameEn=g_key_file_get_string(keyfile,"Desktop Entry","Name", nullptr);
|
||||||
|
if(QString::fromLocal8Bit(nameCh).isEmpty() && QString::fromLocal8Bit(nameEn).isEmpty())
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char* name=g_key_file_get_string(keyfile,"Desktop Entry","Name", nullptr);
|
||||||
|
if(QString::fromLocal8Bit(name).isEmpty())
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_filePathList.append(filePathStr);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
|
||||||
|
} while(i < list.size());
|
||||||
|
|
||||||
|
g_key_file_free(keyfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppMatch::getDesktopFilePath()
|
||||||
|
{
|
||||||
|
m_filePathList.clear();
|
||||||
|
getAllDesktopFilePath("/usr/share/applications/");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/software-properties-livepatch.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/mate-color-select.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/blueman-adapters.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/blueman-manager.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/mate-user-guide.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/nm-connection-editor.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/debian-uxterm.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/debian-xterm.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/im-config.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/fcitx.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/fcitx-configtool.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/onboard-settings.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/info.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/ukui-power-preferences.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/ukui-power-statistics.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/software-properties-drivers.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/software-properties-gtk.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/gnome-session-properties.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/org.gnome.font-viewer.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/xdiagnose.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/gnome-language-selector.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/mate-notification-properties.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/transmission-gtk.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/mpv.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/system-config-printer.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/org.gnome.DejaDup.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/yelp.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/peony-computer.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/peony-home.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/peony-trash.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/peony.desktop");
|
||||||
|
|
||||||
|
//v10
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/mate-about.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/time.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/network.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/shares.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/mate-power-statistics.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/display-im6.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/display-im6.q16.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/openjdk-8-policytool.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/kylin-io-monitor.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/wps-office-uninstall.desktop");
|
||||||
|
m_filePathList.removeAll("/usr/share/applications/wps-office-misc.desktop");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppMatch::getAppName()
|
||||||
|
{
|
||||||
|
GKeyFileFlags flags=G_KEY_FILE_NONE;
|
||||||
|
GKeyFile* keyfile=g_key_file_new ();
|
||||||
|
|
||||||
|
QByteArray fpbyte;
|
||||||
|
QString str;
|
||||||
|
char* filepath;
|
||||||
|
char* name;
|
||||||
|
QString namestr;
|
||||||
|
for(int i=0;i<m_filePathList.size();i++){
|
||||||
|
str=m_filePathList.at(i);
|
||||||
|
fpbyte=str.toLocal8Bit();
|
||||||
|
filepath=fpbyte.data();
|
||||||
|
g_key_file_load_from_file(keyfile,filepath,flags,nullptr);
|
||||||
|
name=g_key_file_get_locale_string(keyfile,"Desktop Entry","Name", nullptr, nullptr);
|
||||||
|
namestr=QString::fromLocal8Bit(name);
|
||||||
|
appNameMatch(namestr,str);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_key_file_load_from_file(keyfile,filepath,flags,nullptr);
|
||||||
|
g_key_file_free(keyfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppMatch::appNameMatch(QString appname,QString desktoppath){
|
||||||
|
if(appname.contains(m_soureText)){
|
||||||
|
m_midResult.append(desktoppath);
|
||||||
|
}
|
||||||
|
QString pinyin=chineseCharactersToPinyin::find(appname).toLower(); // 中文转拼音
|
||||||
|
if(pinyin.contains(m_soureText,Qt::CaseInsensitive)){
|
||||||
|
m_midResult.append(desktoppath);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef APPMATCH_H
|
||||||
|
#define APPMATCH_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QLocale>
|
||||||
|
#include <QDebug>
|
||||||
|
class AppMatch : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit AppMatch(QObject *parent = nullptr);
|
||||||
|
QStringList startMatchApp(QString input);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void getAllDesktopFilePath(QString path);
|
||||||
|
void getDesktopFilePath();
|
||||||
|
void getAppName();
|
||||||
|
void appNameMatch(QString appname,QString desktoppath);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_soureText;
|
||||||
|
QStringList m_filePathList;
|
||||||
|
QStringList m_returnResult;
|
||||||
|
QStringList m_midResult;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // APPMATCH_H
|
|
@ -0,0 +1,11 @@
|
||||||
|
INCLUDEPATH += $$PWD
|
||||||
|
|
||||||
|
include(index/index.pri)
|
||||||
|
include(appsearch/appsearch.pri)
|
||||||
|
include(settingsearch/settingsearch.pri)
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
$$PWD/app-match.h \
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
$$PWD/app-match.cpp \
|
|
@ -0,0 +1,6 @@
|
||||||
|
#include "blockdirs.h"
|
||||||
|
|
||||||
|
BlockDirs::BlockDirs(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef BLOCKDIRS_H
|
||||||
|
#define BLOCKDIRS_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class BlockDirs : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit BlockDirs(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BLOCKDIRS_H
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include "chinesecharacterstopinyin.h"
|
||||||
|
|
||||||
|
chineseCharactersToPinyin::chineseCharactersToPinyin(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
map = loadHanziTable("://index/pinyinWithoutTone.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
#ifndef CHINESECHARACTERSTOPINYIN_H
|
||||||
|
#define CHINESECHARACTERSTOPINYIN_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
class chineseCharactersToPinyin : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit chineseCharactersToPinyin(QObject *parent = nullptr);
|
||||||
|
static QString find(const QString &hanzi)
|
||||||
|
{
|
||||||
|
static QMap<QString, QStringList> map = loadHanziTable("://index/pinyinWithoutTone.txt");
|
||||||
|
// static QMap<QString, QStringList> map;
|
||||||
|
QString output;
|
||||||
|
QStringList stringList = hanzi.split("");
|
||||||
|
|
||||||
|
/* 遍历查找汉字-拼音对照表的内容并将汉字替换为拼音 */
|
||||||
|
for (const QString &str : stringList) {
|
||||||
|
if (map.contains(str))
|
||||||
|
output += map[str].first();
|
||||||
|
else
|
||||||
|
output += str;
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
private:
|
||||||
|
static QMap<QString, QStringList> map;
|
||||||
|
/* 加载汉字对照表 */
|
||||||
|
static QMap<QString, QStringList> loadHanziTable(const QString &fileName)
|
||||||
|
{
|
||||||
|
QMap<QString, QStringList> map;
|
||||||
|
QFile file(fileName);
|
||||||
|
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
||||||
|
qDebug("File: '%s' open failed!", file.fileName().toStdString().c_str());
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 读取汉字对照表文件并转换为QMap存储 */
|
||||||
|
while(!file.atEnd()) {
|
||||||
|
QString content = QString::fromUtf8(file.readLine());
|
||||||
|
map[content.split(" ").last().trimmed()] = content.split(" ").first().split(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CHINESECHARACTERSTOPINYIN_H
|
|
@ -0,0 +1,67 @@
|
||||||
|
#include "document.h"
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
Document::Document()
|
||||||
|
{
|
||||||
|
m_document = new Xapian::Document;
|
||||||
|
}
|
||||||
|
|
||||||
|
Document::~Document()
|
||||||
|
{
|
||||||
|
// if(m_document)
|
||||||
|
// delete m_document;
|
||||||
|
// if(m_index_text)
|
||||||
|
// delete m_index_text;
|
||||||
|
// if(m_unique_term)
|
||||||
|
// delete m_unique_term;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Document::setData(QString data)
|
||||||
|
{
|
||||||
|
if(data.isEmpty())
|
||||||
|
return;
|
||||||
|
m_document->set_data(data.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Document::addterm(QString term)
|
||||||
|
{
|
||||||
|
if(term.isEmpty())
|
||||||
|
return;
|
||||||
|
m_document->add_term(term.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Document::addValue(QString value)
|
||||||
|
{
|
||||||
|
m_document->add_value(1,value.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Document::setUniqueTerm(QString term)
|
||||||
|
{
|
||||||
|
if(term.isEmpty())
|
||||||
|
return;
|
||||||
|
// m_document->add_term(term.toStdString());
|
||||||
|
|
||||||
|
m_unique_term = new QString(term);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Document::getUniqueTerm()
|
||||||
|
{
|
||||||
|
// qDebug()<<"m_unique_term!"<<*m_unique_term;
|
||||||
|
return m_unique_term->toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Document::setIndexText(QStringList indexText)
|
||||||
|
{
|
||||||
|
// QStringList indexTextList = indexText;
|
||||||
|
m_index_text = new QStringList(indexText);
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList Document::getIndexText()
|
||||||
|
{
|
||||||
|
return *m_index_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
Xapian::Document Document::getXapianDocument()
|
||||||
|
{
|
||||||
|
return *m_document;
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef DOCUMENT_H
|
||||||
|
#define DOCUMENT_H
|
||||||
|
|
||||||
|
#include <xapian.h>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
class Document
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Document();
|
||||||
|
~Document();
|
||||||
|
void setData(QString data);
|
||||||
|
void addterm(QString term);
|
||||||
|
void addValue(QString value);
|
||||||
|
void setUniqueTerm(QString term);
|
||||||
|
std::string getUniqueTerm();
|
||||||
|
void setIndexText(QStringList indexText);
|
||||||
|
QStringList getIndexText();
|
||||||
|
Xapian::Document getXapianDocument();
|
||||||
|
private:
|
||||||
|
Xapian::Document *m_document;
|
||||||
|
QStringList *m_index_text;
|
||||||
|
QString *m_unique_term;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DOCUMENT_H
|
|
@ -0,0 +1,20 @@
|
||||||
|
#include "file-reader.h"
|
||||||
|
#include "file-utils.h"
|
||||||
|
|
||||||
|
FileReader::FileReader(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QString *FileReader::getTextContent(QString path)
|
||||||
|
{
|
||||||
|
//获取所有文件内容
|
||||||
|
//先分类
|
||||||
|
QString type =FileUtils::getMimetype(path);
|
||||||
|
if(type == "application/zip")
|
||||||
|
return FileUtils::getDocxTextContent(path);
|
||||||
|
else if(type == "text/plain")
|
||||||
|
return FileUtils::getTxtContent(path);
|
||||||
|
|
||||||
|
return new QString();
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef FILEREADER_H
|
||||||
|
#define FILEREADER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class FileReader : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit FileReader(QObject *parent = nullptr);
|
||||||
|
static QString* getTextContent(QString path);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FILEREADER_H
|
|
@ -0,0 +1,108 @@
|
||||||
|
#include "file-searcher.h"
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
FileSearcher::FileSearcher(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSearcher::onKeywordSearch(QString keyword, int begin, int num)
|
||||||
|
{
|
||||||
|
QVector<QStringList> searchResult;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
qDebug()<<"--search start--";
|
||||||
|
|
||||||
|
Xapian::Database db(INDEX_PATH);
|
||||||
|
Xapian::Enquire enquire(db);
|
||||||
|
Xapian::QueryParser qp;
|
||||||
|
qp.set_default_op(Xapian::Query::OP_PHRASE);
|
||||||
|
qp.set_database(db);
|
||||||
|
auto userInput = keyword;
|
||||||
|
|
||||||
|
std::string queryStr = keyword.replace(""," ").toStdString();
|
||||||
|
// std::string s =db.get_spelling_suggestion(queryStr,10);
|
||||||
|
// qDebug()<<"spelling_suggestion!"<<QString::fromStdString(s);
|
||||||
|
|
||||||
|
qDebug()<<"queryStr!"<<QString::fromStdString(queryStr);
|
||||||
|
//Creat a query
|
||||||
|
Xapian::Query queryPhrase = qp.parse_query(queryStr,Xapian::QueryParser::FLAG_PHRASE);
|
||||||
|
std::vector<Xapian::Query> v;
|
||||||
|
for(int i=0;i<userInput.size();i++)
|
||||||
|
{
|
||||||
|
v.push_back(Xapian::Query(QString(userInput.at(i)).toStdString()));
|
||||||
|
qDebug()<<userInput.at(i);
|
||||||
|
qDebug()<<QString::fromStdString(Xapian::Query(QString(userInput.at(i)).toStdString()).get_description());
|
||||||
|
}
|
||||||
|
Xapian::Query queryNear =Xapian::Query(Xapian::Query::OP_NEAR, v.begin(), v.end());
|
||||||
|
Xapian::Query query = Xapian::Query(Xapian::Query::OP_AND,queryNear,queryPhrase);
|
||||||
|
|
||||||
|
//1- dir 2-file
|
||||||
|
unsigned slot = 1;
|
||||||
|
std::string value = "1";
|
||||||
|
Xapian::Query queryValue1 = Xapian::Query(Xapian::Query::OP_VALUE_GE,slot,value);
|
||||||
|
value = "0";
|
||||||
|
Xapian::Query queryValue0 = Xapian::Query(Xapian::Query::OP_VALUE_LE,1,value);
|
||||||
|
Xapian::Query queryDir = Xapian::Query(Xapian::Query::OP_AND,query,queryValue1);
|
||||||
|
Xapian::Query queryFile = Xapian::Query(Xapian::Query::OP_AND,query,queryValue0);
|
||||||
|
|
||||||
|
qDebug()<<QString::fromStdString(query.get_description());
|
||||||
|
|
||||||
|
enquire.set_query(queryDir);
|
||||||
|
//dir result
|
||||||
|
Xapian::MSet result = enquire.get_mset(begin, begin+num);
|
||||||
|
qDebug()<< "find dir results count=" <<static_cast<int>(result.get_matches_estimated());
|
||||||
|
searchResult.append(getResult(result));
|
||||||
|
|
||||||
|
enquire.set_query(queryFile);
|
||||||
|
//file result
|
||||||
|
result = enquire.get_mset(begin, begin+num);
|
||||||
|
qDebug()<< "find file results count=" <<static_cast<int>(result.get_matches_estimated());
|
||||||
|
searchResult.append(getResult(result));
|
||||||
|
|
||||||
|
qDebug()<< "--search finish--";
|
||||||
|
}
|
||||||
|
catch(const Xapian::Error &e)
|
||||||
|
{
|
||||||
|
qDebug() <<QString::fromStdString(e.get_description());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Q_EMIT this->result(searchResult);
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList FileSearcher::getResult(Xapian::MSet &result)
|
||||||
|
{
|
||||||
|
//QStringList *pathTobeDelete = new QStringList;
|
||||||
|
//Delete those path doc which is not already exist.
|
||||||
|
|
||||||
|
QStringList searchResult = QStringList();
|
||||||
|
if(result.size() == 0)
|
||||||
|
return searchResult;
|
||||||
|
for (auto it = result.begin(); it != result.end(); ++it)
|
||||||
|
{
|
||||||
|
Xapian::Document doc = it.get_document();
|
||||||
|
qDebug()<<"value!!!!"<<QString::fromStdString(doc.get_value(1));
|
||||||
|
std::string data = doc.get_data();
|
||||||
|
Xapian::weight docScoreWeight = it.get_weight();
|
||||||
|
Xapian::percent docScorePercent = it.get_percent();
|
||||||
|
QFileInfo *info = new QFileInfo(QString::fromStdString(data));
|
||||||
|
|
||||||
|
if(!info->exists())
|
||||||
|
{
|
||||||
|
// pathTobeDelete->append(QString::fromStdString(data));
|
||||||
|
qDebug()<<QString::fromStdString(data)<<"is not exist!!";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
searchResult.append(QString::fromStdString(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug()<< "doc="<< QString::fromStdString(data) << ",weight=" <<docScoreWeight << ",percent=" << docScorePercent;
|
||||||
|
}
|
||||||
|
// if(!pathTobeDelete->isEmpty())
|
||||||
|
// deleteAllIndex(pathTobeDelete)
|
||||||
|
return searchResult;
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef FILESEARCHER_H
|
||||||
|
#define FILESEARCHER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <xapian.h>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QVector>
|
||||||
|
#define INDEX_PATH (QStandardPaths::writableLocation(QStandardPaths::HomeLocation)+"/.config/org.ukui/index_data").toStdString()
|
||||||
|
|
||||||
|
|
||||||
|
class FileSearcher : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit FileSearcher(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void onKeywordSearch(QString keyword, int begin, int num);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void result(QVector<QStringList> resultV);
|
||||||
|
private:
|
||||||
|
QStringList getResult(Xapian::MSet &result);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FILESEARCHER_H
|
|
@ -0,0 +1,33 @@
|
||||||
|
#include <QDebug>
|
||||||
|
#include "filetypefilter.h"
|
||||||
|
|
||||||
|
FileTypeFilter::FileTypeFilter(const QString& path) : Traverse_BFS(path)
|
||||||
|
{
|
||||||
|
this->result = new QVector<QString>();
|
||||||
|
this->Traverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileTypeFilter::~FileTypeFilter()
|
||||||
|
{
|
||||||
|
delete this->result;
|
||||||
|
this->result = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileTypeFilter::DoSomething(const QFileInfo& fileInfo){
|
||||||
|
// QMimeDatabase qmd;
|
||||||
|
// QMimeType qmt;
|
||||||
|
// qmt = qmd.mimeTypeForFile(fileInfo.fileName());
|
||||||
|
// qDebug() << qmt.preferredSuffix();
|
||||||
|
for (auto i : this->targetFileTypeVec){
|
||||||
|
if (fileInfo.fileName().endsWith(i)){
|
||||||
|
// qDebug() << fileInfo.fileName();
|
||||||
|
this->result->append(fileInfo.absoluteFilePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<QString>* FileTypeFilter::getTargetFileAbsolutePath(){
|
||||||
|
return this->result;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef FILETYPEFILTER_H
|
||||||
|
#define FILETYPEFILTER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QMimeDatabase>
|
||||||
|
#include <QMimeType>
|
||||||
|
#include <QVector>
|
||||||
|
#include "traverse_bfs.h"
|
||||||
|
|
||||||
|
class FileTypeFilter : public QObject, public Traverse_BFS
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit FileTypeFilter(const QString&);
|
||||||
|
~FileTypeFilter();
|
||||||
|
virtual void DoSomething(const QFileInfo&) final;
|
||||||
|
QVector<QString>* getTargetFileAbsolutePath();
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
private:
|
||||||
|
const QVector<QString> targetFileTypeVec ={ QString(".doc"),
|
||||||
|
QString(".docx"),
|
||||||
|
QString(".ppt"),
|
||||||
|
QString(".pptx"),
|
||||||
|
QString(".xls"),
|
||||||
|
QString(".xlsx"),
|
||||||
|
QString(".txt")};
|
||||||
|
QVector<QString>* result;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FILETYPEFILTER_H
|
|
@ -0,0 +1,302 @@
|
||||||
|
#include <QFile>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDebug>
|
||||||
|
#include "file-utils.h"
|
||||||
|
#include "index-generator.h"
|
||||||
|
#include "chinesecharacterstopinyin.h"
|
||||||
|
#include <QtConcurrent>
|
||||||
|
#include <QFuture>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define INDEX_PATH (QStandardPaths::writableLocation(QStandardPaths::HomeLocation)+"/.config/org.ukui/index_data").toStdString()
|
||||||
|
#define CONTENT_INDEX_PATH (QStandardPaths::writableLocation(QStandardPaths::HomeLocation)+"/.config/org.ukui/content_index_data").toStdString()
|
||||||
|
|
||||||
|
static IndexGenerator *global_instance = nullptr;
|
||||||
|
|
||||||
|
IndexGenerator *IndexGenerator::getInstance()
|
||||||
|
{
|
||||||
|
if (!global_instance) {
|
||||||
|
global_instance = new IndexGenerator;
|
||||||
|
}
|
||||||
|
return global_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IndexGenerator::setIndexdataPath()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IndexGenerator::creatAllIndex(QList<QVector<QString> > *messageList)
|
||||||
|
{
|
||||||
|
HandlePathList(messageList);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_indexer = new Xapian::TermGenerator();
|
||||||
|
m_indexer->set_database(*m_datebase_path);
|
||||||
|
//可以实现拼写纠正
|
||||||
|
// m_indexer->set_flags(Xapian::TermGenerator::FLAG_SPELLING);
|
||||||
|
m_indexer->set_stemming_strategy(Xapian::TermGenerator::STEM_SOME);
|
||||||
|
|
||||||
|
int count =0;
|
||||||
|
for(int i = 0;i < m_doc_list_path->size(); i++)
|
||||||
|
{
|
||||||
|
insertIntoDatabase(m_doc_list_path->at(i));
|
||||||
|
|
||||||
|
if(++count == 9999)
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
m_datebase_path->commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_datebase_path->commit();
|
||||||
|
}
|
||||||
|
catch(const Xapian::Error &e)
|
||||||
|
{
|
||||||
|
qDebug()<<"creatAllIndex fail!"<<QString::fromStdString(e.get_description());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_doc_list_path->clear();
|
||||||
|
Q_EMIT this->transactionFinished();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IndexGenerator::creatAllIndex(QVector<QString> *messageList)
|
||||||
|
{
|
||||||
|
HandlePathList(messageList);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexGenerator::IndexGenerator(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
m_datebase_path = new Xapian::WritableDatabase(INDEX_PATH, Xapian::DB_CREATE_OR_OPEN);
|
||||||
|
m_database_content = new Xapian::WritableDatabase(CONTENT_INDEX_PATH, Xapian::DB_CREATE_OR_OPEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexGenerator::~IndexGenerator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void IndexGenerator::insertIntoDatabase(Document doc)
|
||||||
|
{
|
||||||
|
// qDebug()<< "--index start--";
|
||||||
|
Xapian::Document document = doc.getXapianDocument();
|
||||||
|
m_indexer->set_document(document);
|
||||||
|
// qDebug()<<doc.getIndexText();
|
||||||
|
|
||||||
|
for(auto i : doc.getIndexText()){
|
||||||
|
m_indexer->index_text(i.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
Xapian::docid innerId= m_datebase_path->replace_document(doc.getUniqueTerm(),document);
|
||||||
|
// qDebug()<<"replace doc docid="<<static_cast<int>(innerId);
|
||||||
|
// qDebug()<< "--index finish--";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IndexGenerator::HandlePathList(QList<QVector<QString>> *messageList)
|
||||||
|
{
|
||||||
|
qDebug()<<"Begin HandlePathList!";
|
||||||
|
qDebug()<<messageList->size();
|
||||||
|
// qDebug()<<QString::number(quintptr(QThread::currentThreadId()));
|
||||||
|
QFuture<Document> future = QtConcurrent::mapped(*messageList,&IndexGenerator::GenerateDocument);
|
||||||
|
|
||||||
|
future.waitForFinished();
|
||||||
|
|
||||||
|
QList<Document> docList = future.results();
|
||||||
|
m_doc_list_path = new QList<Document>(docList);
|
||||||
|
qDebug()<<m_doc_list_path->size();
|
||||||
|
|
||||||
|
qDebug()<<"Finish HandlePathList!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IndexGenerator::HandlePathList(QVector<QString> *messageList)
|
||||||
|
{
|
||||||
|
qDebug()<<"Begin HandlePathList for content index!";
|
||||||
|
qDebug()<<messageList->size();
|
||||||
|
// qDebug()<<QString::number(quintptr(QThread::currentThreadId()));
|
||||||
|
QFuture<Document> future = QtConcurrent::mapped(*messageList,&IndexGenerator::GenerateContentDocument);
|
||||||
|
|
||||||
|
future.waitForFinished();
|
||||||
|
|
||||||
|
QList<Document> docList = future.results();
|
||||||
|
m_doc_list_content = new QList<Document>(docList);
|
||||||
|
qDebug()<<m_doc_list_content->size();
|
||||||
|
|
||||||
|
qDebug()<<"Finish HandlePathList for content index!";
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Document IndexGenerator::GenerateDocument(const QVector<QString> &list)
|
||||||
|
{
|
||||||
|
// qDebug()<<QString::number(quintptr(QThread::currentThreadId()));
|
||||||
|
//0-filename 1-filepathname 2-file or dir
|
||||||
|
QString index_text = list.at(0);
|
||||||
|
QString sourcePath = list.at(1);
|
||||||
|
index_text = index_text.replace(".","").replace(""," ");
|
||||||
|
index_text = index_text.simplified();
|
||||||
|
//这个应该是写错了
|
||||||
|
// QString pinyin_text = FileUtils::find(index_text.replace(".", "")).replace("", " ");
|
||||||
|
|
||||||
|
//不带多音字版
|
||||||
|
// QString pinyin_text = FileUtils::find(QString(list.at(0)).replace(".","")).replace("", " ").simplified();
|
||||||
|
|
||||||
|
//多音字版
|
||||||
|
//现加入首字母
|
||||||
|
QStringList pinyin_text_list = FileUtils::findMultiToneWords(QString(list.at(0)).replace(".",""));
|
||||||
|
for (QString& i : pinyin_text_list){
|
||||||
|
i.replace("", " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString uniqueterm = QString::fromStdString(FileUtils::makeDocUterm(sourcePath));
|
||||||
|
// QString uniqueterm1 = QString::fromStdString(QCryptographicHash::hash(sourcePath.toUtf8(),QCryptographicHash::Md5).toStdString());
|
||||||
|
/*--------------------------------------------------------------------*/
|
||||||
|
//QByteArray 和 QString 之间会进行隐式转换,造成字符串被截断等意想不到的后果!!!!!!! zpf
|
||||||
|
// if(uniqueterm1!=uniqueterm){
|
||||||
|
// qDebug()<<"-----------------------------------------start";
|
||||||
|
// qDebug()<<uniqueterm1;
|
||||||
|
// qDebug()<<uniqueterm;
|
||||||
|
// qDebug()<<"------------------------------------------finish";
|
||||||
|
// }
|
||||||
|
/*--------------------------------------------------------------------*/
|
||||||
|
Document doc;
|
||||||
|
doc.setData(sourcePath);
|
||||||
|
doc.setUniqueTerm(uniqueterm);
|
||||||
|
doc.addValue(list.at(2));
|
||||||
|
if(list.at(2) == QString("1"))
|
||||||
|
qDebug()<<"value!!!"<<list.at(2);
|
||||||
|
QStringList temp;
|
||||||
|
temp.append(index_text);
|
||||||
|
temp.append(pinyin_text_list);
|
||||||
|
doc.setIndexText(temp);
|
||||||
|
// doc.setIndexText(QStringList()<<index_text<<pinyin_text);
|
||||||
|
// doc.setIndexText(QStringList()<<index_text);
|
||||||
|
return doc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Document IndexGenerator::GenerateContentDocument(const QString &path)
|
||||||
|
{
|
||||||
|
//构造文本索引的document
|
||||||
|
FileReader::getTextContent(path);
|
||||||
|
QString uniqueterm = QString::fromStdString(FileUtils::makeDocUterm(path));
|
||||||
|
Document doc;
|
||||||
|
doc.setData(path);
|
||||||
|
doc.setUniqueTerm(uniqueterm);
|
||||||
|
return doc;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IndexGenerator::isIndexdataExist()
|
||||||
|
{
|
||||||
|
|
||||||
|
// Xapian::Database db(m_index_data_path->toStdString());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList IndexGenerator::IndexSearch(QString indexText)
|
||||||
|
{
|
||||||
|
QStringList searchResult;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
qDebug()<<"--search start--";
|
||||||
|
|
||||||
|
Xapian::Database db(INDEX_PATH);
|
||||||
|
Xapian::Enquire enquire(db);
|
||||||
|
Xapian::QueryParser qp;
|
||||||
|
qp.set_default_op(Xapian::Query::OP_PHRASE);
|
||||||
|
qp.set_database(db);
|
||||||
|
auto userInput = indexText;
|
||||||
|
|
||||||
|
std::string queryStr = indexText.replace(""," ").toStdString();
|
||||||
|
// std::string s =db.get_spelling_suggestion(queryStr,10);
|
||||||
|
// qDebug()<<"spelling_suggestion!"<<QString::fromStdString(s);
|
||||||
|
|
||||||
|
qDebug()<<"queryStr!"<<QString::fromStdString(queryStr);
|
||||||
|
//Creat a query
|
||||||
|
Xapian::Query queryPhrase = qp.parse_query(queryStr,Xapian::QueryParser::FLAG_PHRASE);
|
||||||
|
std::vector<Xapian::Query> v;
|
||||||
|
for(int i=0;i<userInput.size();i++)
|
||||||
|
{
|
||||||
|
v.push_back(Xapian::Query(QString(userInput.at(i)).toStdString()));
|
||||||
|
qDebug()<<userInput.at(i);
|
||||||
|
qDebug()<<QString::fromStdString(Xapian::Query(QString(userInput.at(i)).toStdString()).get_description());
|
||||||
|
}
|
||||||
|
Xapian::Query queryNear =Xapian::Query(Xapian::Query::OP_NEAR, v.begin(), v.end());
|
||||||
|
Xapian::Query query = Xapian::Query(Xapian::Query::OP_AND,queryNear,queryPhrase);
|
||||||
|
|
||||||
|
qDebug()<<QString::fromStdString(query.get_description());
|
||||||
|
enquire.set_query(query);
|
||||||
|
|
||||||
|
Xapian::MSet result = enquire.get_mset(0, 9999);
|
||||||
|
qDebug()<< "find results count=" <<static_cast<int>(result.get_matches_estimated());
|
||||||
|
|
||||||
|
// QStringList *pathTobeDelete = new QStringList;
|
||||||
|
|
||||||
|
//get search result
|
||||||
|
for (auto it = result.begin(); it != result.end(); ++it) {
|
||||||
|
Xapian::Document doc = it.get_document();
|
||||||
|
std::string data = doc.get_data();
|
||||||
|
Xapian::weight docScoreWeight = it.get_weight();
|
||||||
|
Xapian::percent docScorePercent = it.get_percent();
|
||||||
|
QFileInfo *info = new QFileInfo(QString::fromStdString(data));
|
||||||
|
|
||||||
|
if(!info->exists())
|
||||||
|
{
|
||||||
|
// pathTobeDelete->append(QString::fromStdString(data));
|
||||||
|
qDebug()<<QString::fromStdString(data)<<"is not exist!!";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
searchResult.append(QString::fromStdString(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug()<< "doc="<< QString::fromStdString(data) << ",weight=" <<docScoreWeight << ",percent=" << docScorePercent;
|
||||||
|
}
|
||||||
|
// //Delete those path doc which is not already exist.
|
||||||
|
// if(!pathTobeDelete->isEmpty())
|
||||||
|
// deleteAllIndex(pathTobeDelete);
|
||||||
|
|
||||||
|
qDebug()<< "--search finish--";
|
||||||
|
}
|
||||||
|
catch(const Xapian::Error &e)
|
||||||
|
{
|
||||||
|
qDebug() <<QString::fromStdString(e.get_description());
|
||||||
|
}
|
||||||
|
return searchResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IndexGenerator::deleteAllIndex(QStringList *pathlist)
|
||||||
|
{
|
||||||
|
QStringList *list = pathlist;
|
||||||
|
if(list->isEmpty())
|
||||||
|
return true;
|
||||||
|
for(int i = 0;i<list->size();i++)
|
||||||
|
{
|
||||||
|
QString doc = list->at(i);
|
||||||
|
std::string uniqueterm = FileUtils::makeDocUterm(doc);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
qDebug()<<"--delete start--";
|
||||||
|
m_datebase_path->delete_document(uniqueterm);
|
||||||
|
qDebug()<<"delete md5"<<QString::fromStdString(uniqueterm);
|
||||||
|
m_datebase_path->commit();
|
||||||
|
qDebug()<< "--delete finish--";
|
||||||
|
}
|
||||||
|
catch(const Xapian::Error &e)
|
||||||
|
{
|
||||||
|
qDebug() <<QString::fromStdString(e.get_description());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Q_EMIT this->transactionFinished();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
#ifndef INDEXGENERATOR_H
|
||||||
|
#define INDEXGENERATOR_H
|
||||||
|
|
||||||
|
#include <xapian.h>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
#include "document.h"
|
||||||
|
#include "file-reader.h"
|
||||||
|
|
||||||
|
class IndexGenerator : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
static IndexGenerator *getInstance();
|
||||||
|
bool setIndexdataPath();
|
||||||
|
bool isIndexdataExist();
|
||||||
|
static QStringList IndexSearch(QString indexText);
|
||||||
|
Q_SIGNALS:
|
||||||
|
void transactionFinished();
|
||||||
|
void searchFinish();
|
||||||
|
public Q_SLOTS:
|
||||||
|
bool creatAllIndex(QList<QVector<QString>> *messageList);
|
||||||
|
bool creatAllIndex(QVector<QString> *messageList);
|
||||||
|
bool deleteAllIndex(QStringList *pathlist);
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit IndexGenerator(QObject *parent = nullptr);
|
||||||
|
//For file name index
|
||||||
|
void HandlePathList(QList<QVector<QString>> *messageList);
|
||||||
|
//For file content index
|
||||||
|
void HandlePathList(QVector<QString> *messageList);
|
||||||
|
static Document GenerateDocument(const QVector<QString> &list);
|
||||||
|
static Document GenerateContentDocument(const QString &list);
|
||||||
|
//add one data in database
|
||||||
|
void insertIntoDatabase(Document doc);
|
||||||
|
~IndexGenerator();
|
||||||
|
|
||||||
|
QMap<QString,QStringList> *m_index_map;
|
||||||
|
QList<Document> *m_doc_list_path; //for path index
|
||||||
|
QList<Document> *m_doc_list_content; // for text content index
|
||||||
|
QString *m_index_data_path;
|
||||||
|
Xapian::WritableDatabase *m_datebase_path;
|
||||||
|
Xapian::WritableDatabase *m_database_content;
|
||||||
|
std::string m_docstr;
|
||||||
|
std::string m_index_text_str;
|
||||||
|
Xapian::TermGenerator *m_indexer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INDEXGENERATOR_H
|
|
@ -0,0 +1,32 @@
|
||||||
|
INCLUDEPATH += $$PWD
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
# $$PWD/chinesecharacterstopinyin.h \
|
||||||
|
$$PWD/blockdirs.h \
|
||||||
|
$$PWD/document.h \
|
||||||
|
$$PWD/filetypefilter.h \
|
||||||
|
$$PWD/file-reader.h \
|
||||||
|
$$PWD/index-generator.h \
|
||||||
|
# $$PWD/inotify-manager.h \
|
||||||
|
$$PWD/inotify.h \
|
||||||
|
$$PWD/messagelist-manager.h \
|
||||||
|
$$PWD/traverse_bfs.h \
|
||||||
|
$$PWD/messagelist-manager.h \
|
||||||
|
$$PWD/text-content-indexer.h \
|
||||||
|
$$PWD/file-searcher.h
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
# $$PWD/chinesecharacterstopinyin.cpp \
|
||||||
|
$$PWD/blockdirs.cpp \
|
||||||
|
$$PWD/document.cpp \
|
||||||
|
$$PWD/filetypefilter.cpp \
|
||||||
|
$$PWD/file-reader.cpp \
|
||||||
|
$$PWD/index-generator.cpp \
|
||||||
|
# $$PWD/inotify-manager.cpp \
|
||||||
|
$$PWD/inotify.cpp \
|
||||||
|
$$PWD/messagelist-manager.cpp \
|
||||||
|
$$PWD/test-Inotify-Manager.cpp \
|
||||||
|
$$PWD/traverse_bfs.cpp \
|
||||||
|
$$PWD/text-content-indexer.cpp \
|
||||||
|
$$PWD/file-searcher.cpp
|
||||||
|
|
|
@ -0,0 +1,226 @@
|
||||||
|
#include "inotify-manager.h"
|
||||||
|
#include "index-generator.h"
|
||||||
|
#include "messagelist-manager.h"
|
||||||
|
|
||||||
|
bool InotifyManager::Traverse_BFS(const QString& path, int autoSendMessageLength){
|
||||||
|
qDebug() << "BFS start-----------------------------";
|
||||||
|
this->mlm->SetAutoSendMessageLength(autoSendMessageLength);
|
||||||
|
QQueue<QString> bfs;
|
||||||
|
bfs.enqueue(path);
|
||||||
|
QFileInfoList list;
|
||||||
|
QDir dir;
|
||||||
|
dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
|
||||||
|
dir.setSorting(QDir::DirsFirst);
|
||||||
|
while (!bfs.empty()) {
|
||||||
|
dir.setPath(bfs.dequeue());
|
||||||
|
list = dir.entryInfoList();
|
||||||
|
for (auto i : list){
|
||||||
|
// qDebug() << i.absoluteFilePath();
|
||||||
|
if (i.isDir()){
|
||||||
|
AddWatch(i.absoluteFilePath());
|
||||||
|
bfs.enqueue(i.absoluteFilePath());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
this->mlm->AddMessage(i.absoluteFilePath());
|
||||||
|
//continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->mlm->SendMessage();
|
||||||
|
qDebug() << "BFS end-----------------------------";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//the DFS method is aborted
|
||||||
|
bool InotifyManager::Traverse_DFS(const QString& path, const bool& CREATORDELETE){
|
||||||
|
|
||||||
|
QDir dir(path);
|
||||||
|
if (!dir.exists()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
|
||||||
|
dir.setSorting(QDir::DirsFirst);
|
||||||
|
QFileInfoList list = dir.entryInfoList();
|
||||||
|
int i = 0;
|
||||||
|
do {
|
||||||
|
if(list.size()==0){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
QFileInfo fileInfo = list.at(i);
|
||||||
|
bool bisDir = fileInfo.isDir();
|
||||||
|
if (fileInfo.fileName().at(0) != '.'){
|
||||||
|
if (bisDir) {
|
||||||
|
// qDebug() << QString("Path: %0/%1")
|
||||||
|
// .arg(fileInfo.path())
|
||||||
|
// .arg(fileInfo.fileName());
|
||||||
|
qDebug() << "inotify-manager traverse: " << fileInfo.filePath();
|
||||||
|
if (CREATORDELETE){
|
||||||
|
AddWatch(fileInfo.filePath());
|
||||||
|
}
|
||||||
|
Traverse_DFS(fileInfo.filePath(), CREATORDELETE);
|
||||||
|
if (!CREATORDELETE){
|
||||||
|
RemoveWatch(fileInfo.filePath());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// qDebug() << QString("File: %0/%1")
|
||||||
|
// .arg(fileInfo.path())
|
||||||
|
// .arg(fileInfo.fileName());
|
||||||
|
//IndexGenerator::getInstance()->creatAllIndex(new QStringList(fileInfo.filePath()));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
} while (i < list.size());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InotifyManager::AddWatch(const QString &path){
|
||||||
|
//m_fd = inotify_init();
|
||||||
|
// qDebug() << "m_fd: " <<m_fd;
|
||||||
|
//int ret = inotify_add_watch(m_fd, path.toStdString().c_str(), IN_ALL_EVENTS);
|
||||||
|
int ret = inotify_add_watch(m_fd, path.toStdString().c_str(), (IN_MOVED_FROM | IN_MOVED_TO | IN_CREATE | IN_DELETE));
|
||||||
|
Q_ASSERT(ret!=-1);
|
||||||
|
if (ret == -1) {
|
||||||
|
qDebug() << "AddWatch error:" << path;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
currentPath[ret] = path;
|
||||||
|
qDebug() << "ret: " <<ret;
|
||||||
|
qDebug() << "Watch:" << path;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//暂时没用
|
||||||
|
bool InotifyManager::AddWatchList(const QStringList &paths){
|
||||||
|
m_fd = inotify_init();
|
||||||
|
qDebug() << "m_fd----------->" <<m_fd;
|
||||||
|
for (const QString& p:paths) {
|
||||||
|
int ret = inotify_add_watch(m_fd, p.toStdString().c_str(), IN_ALL_EVENTS);
|
||||||
|
if (ret == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InotifyManager::RemoveWatch(const QString &path){
|
||||||
|
int ret = inotify_rm_watch(m_fd, currentPath.key(path));
|
||||||
|
if (ret){
|
||||||
|
qDebug() << "remove path error";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// qDebug() << "remove path: " << path;
|
||||||
|
|
||||||
|
for (QMap<int, QString>::Iterator i = currentPath.begin(); i != currentPath.end();){
|
||||||
|
if (i.value().length() > path.length()){
|
||||||
|
if (i.value().mid(0, path.length()) == path){
|
||||||
|
qDebug() << i.value();
|
||||||
|
/*--------------------------------*/
|
||||||
|
//在此调用删除索引
|
||||||
|
IndexGenerator::getInstance()->deleteAllIndex(new QStringList(path));
|
||||||
|
/*--------------------------------*/
|
||||||
|
currentPath.erase(i++);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qDebug() << path;
|
||||||
|
//这个貌似不用删,先mark一下
|
||||||
|
//currentPath.remove(currentPath.key(path));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InotifyManager::run(){
|
||||||
|
|
||||||
|
char * p;
|
||||||
|
char buf[BUF_LEN] __attribute__((aligned(8)));
|
||||||
|
|
||||||
|
ssize_t numRead;
|
||||||
|
|
||||||
|
for (;;) { /* Read events forever */
|
||||||
|
numRead = read(m_fd, buf, BUF_LEN);
|
||||||
|
if (numRead == 0) {
|
||||||
|
qDebug() << "read() from inotify fd returned 0!";
|
||||||
|
}
|
||||||
|
if (numRead == -1) {
|
||||||
|
qDebug() << "read";
|
||||||
|
}
|
||||||
|
qDebug() << "Read " << numRead << " bytes from inotify fd";
|
||||||
|
|
||||||
|
/* Process all of the events in buffer returned by read() */
|
||||||
|
|
||||||
|
for (p = buf; p < buf + numRead;) {
|
||||||
|
struct inotify_event * event = reinterpret_cast<inotify_event *>(p);
|
||||||
|
if(event->name[0] != '.'){
|
||||||
|
// if(true){
|
||||||
|
//这个位运算不要在意,只是懒得把文件夹、文件和事件排列组合了,只是看一下事件的类型
|
||||||
|
qDebug() << "Read Event: " << num2string[(event->mask & 0x0000ffff)] << currentPath[event->wd] << QString(event->name) << event->cookie << event->wd;
|
||||||
|
//num2string[event->mask & 0x0000ffff]
|
||||||
|
IndexGenerator::getInstance()->creatAllIndex(new QStringList(currentPath[event->wd] + event->name));
|
||||||
|
|
||||||
|
/*--------------------------------*/
|
||||||
|
|
||||||
|
//传创建或移动过来的文件路径
|
||||||
|
if((event->mask & IN_CREATE) | (event->mask & IN_MOVED_TO)){
|
||||||
|
//添加监视要先序遍历,先添加top节点
|
||||||
|
if (event->mask & IN_ISDIR){
|
||||||
|
AddWatch(currentPath[event->wd] + '/' + event->name);
|
||||||
|
Traverse_BFS(currentPath[event->wd] + '/' + event->name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//IndexGenerator::getInstance()->creatAllIndex(new QStringList(currentPath[event->wd] + '/' + event->name));
|
||||||
|
this->mlm->AddMessage(currentPath[event->wd] + '/' + event->name);
|
||||||
|
this->mlm->SendMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if((event->mask & IN_DELETE) | (event->mask & IN_MOVED_FROM)){
|
||||||
|
if (event->mask & IN_ISDIR){
|
||||||
|
RemoveWatch(currentPath[event->wd] + '/' + event->name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//这里调用删除索引
|
||||||
|
this->mlm->AddMessage(currentPath[event->wd] + '/' + event->name);
|
||||||
|
this->mlm->SendDeleteMessage();
|
||||||
|
// IndexGenerator::getInstance()->deleteAllIndex(new QStringList(currentPath[event->wd] + '/' + event->name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*--------------------------------*/
|
||||||
|
}
|
||||||
|
p += sizeof(struct inotify_event) + event->len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
InotifyManager::InotifyManager()
|
||||||
|
{
|
||||||
|
|
||||||
|
m_fd = inotify_init();
|
||||||
|
qDebug() << "m_fd----------->" <<m_fd;
|
||||||
|
num2string.insert(IN_ACCESS, "IN_ACCESS");
|
||||||
|
num2string.insert(IN_MODIFY, "IN_MODIFY");
|
||||||
|
num2string.insert(IN_ATTRIB, "IN_ATTRIB");
|
||||||
|
num2string.insert(IN_CLOSE_WRITE, "IN_CLOSE_WRITE");
|
||||||
|
num2string.insert(IN_CLOSE_NOWRITE, "IN_CLOSE_NOWRITE");
|
||||||
|
num2string.insert(IN_CLOSE, "IN_CLOSE");
|
||||||
|
num2string.insert(IN_OPEN, "IN_OPEN");
|
||||||
|
num2string.insert(IN_MOVED_FROM, "IN_MOVED_FROM");
|
||||||
|
num2string.insert(IN_MOVED_TO, "IN_MOVED_TO");
|
||||||
|
num2string.insert(IN_MOVE, "IN_MOVE");
|
||||||
|
num2string.insert(IN_CREATE, "IN_CREATE");
|
||||||
|
num2string.insert(IN_DELETE, "IN_DELETE");
|
||||||
|
num2string.insert(IN_DELETE_SELF, "IN_DELETE_SELF");
|
||||||
|
num2string.insert(IN_MOVE_SELF, "IN_MOVE_SELF");
|
||||||
|
num2string.insert(IN_UNMOUNT, "IN_UNMOUNT");
|
||||||
|
num2string.insert(IN_Q_OVERFLOW, "IN_Q_OVERFLOW");
|
||||||
|
num2string.insert(IN_IGNORED, "IN_IGNORED");
|
||||||
|
this->mlm = new MessageListManager();
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
#ifndef INOTIFYMANAGER_H
|
||||||
|
#define INOTIFYMANAGER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QThread>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/inotify.h>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QQueue>
|
||||||
|
#include "messagelist-manager.h"
|
||||||
|
//#define EVENT_NUM 12
|
||||||
|
#define BUF_LEN 1024
|
||||||
|
|
||||||
|
|
||||||
|
class InotifyManager : public QThread
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit InotifyManager();
|
||||||
|
//the DFS method is aborted
|
||||||
|
bool Traverse_DFS(const QString&, const bool&);//true->create, false->delete
|
||||||
|
bool Traverse_BFS(const QString&, int autoSendMessageLength = 80000);
|
||||||
|
//typedef bool (*AddWatch)(const QString&);
|
||||||
|
//AddWatch cmp;
|
||||||
|
|
||||||
|
bool AddWatch(const QString&);
|
||||||
|
bool AddWatchList(const QStringList&);
|
||||||
|
bool RemoveWatch(const QString&);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void run() override;
|
||||||
|
private:
|
||||||
|
QString *m_watch_path;
|
||||||
|
int m_fd;
|
||||||
|
QMap<int, QString> currentPath;
|
||||||
|
QMap<int, QString> num2string;
|
||||||
|
MessageListManager* mlm;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
void testTraverse(void);
|
||||||
|
|
||||||
|
#endif // INOTIFYMANAGER_H
|
|
@ -0,0 +1,167 @@
|
||||||
|
#include "inotify.h"
|
||||||
|
|
||||||
|
InotifyManagerRefact::InotifyManagerRefact(const QString& path) : Traverse_BFS(path)
|
||||||
|
{
|
||||||
|
// dirPath = new QMap<QString, QStringList>();
|
||||||
|
m_fd = inotify_init();
|
||||||
|
qDebug() << "m_fd----------->" <<m_fd;
|
||||||
|
num2string.insert(IN_ACCESS, "IN_ACCESS");
|
||||||
|
num2string.insert(IN_MODIFY, "IN_MODIFY");
|
||||||
|
num2string.insert(IN_ATTRIB, "IN_ATTRIB");
|
||||||
|
num2string.insert(IN_CLOSE_WRITE, "IN_CLOSE_WRITE");
|
||||||
|
num2string.insert(IN_CLOSE_NOWRITE, "IN_CLOSE_NOWRITE");
|
||||||
|
num2string.insert(IN_CLOSE, "IN_CLOSE");
|
||||||
|
num2string.insert(IN_OPEN, "IN_OPEN");
|
||||||
|
num2string.insert(IN_MOVED_FROM, "IN_MOVED_FROM");
|
||||||
|
num2string.insert(IN_MOVED_TO, "IN_MOVED_TO");
|
||||||
|
num2string.insert(IN_MOVE, "IN_MOVE");
|
||||||
|
num2string.insert(IN_CREATE, "IN_CREATE");
|
||||||
|
num2string.insert(IN_DELETE, "IN_DELETE");
|
||||||
|
num2string.insert(IN_DELETE_SELF, "IN_DELETE_SELF");
|
||||||
|
num2string.insert(IN_MOVE_SELF, "IN_MOVE_SELF");
|
||||||
|
num2string.insert(IN_UNMOUNT, "IN_UNMOUNT");
|
||||||
|
num2string.insert(IN_Q_OVERFLOW, "IN_Q_OVERFLOW");
|
||||||
|
num2string.insert(IN_IGNORED, "IN_IGNORED");
|
||||||
|
this->mlm = new MessageListManager();
|
||||||
|
|
||||||
|
this->AddWatch("/home");
|
||||||
|
this->Traverse();
|
||||||
|
this->SendRestMessage();
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
InotifyManagerRefact::~InotifyManagerRefact(){
|
||||||
|
delete this->mlm;
|
||||||
|
this->mlm = nullptr;
|
||||||
|
// delete dirPath;
|
||||||
|
// dirPath = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InotifyManagerRefact::DoSomething(const QFileInfo& fileInfo){
|
||||||
|
this->mlm->AddMessage(QVector<QString>() << fileInfo.fileName() << fileInfo.absoluteFilePath() << QString(fileInfo.isDir()?"1":"0"));
|
||||||
|
// if(QString(bool((fileInfo.isDir()))) == QString("1"))
|
||||||
|
// qDebug()<<"bool((fileInfo.isDir())"<<QString(fileInfo.isDir());
|
||||||
|
// this->mlm->AddMessage(QVector<QString>() << "PLog" << "/home/zpf/baidunetdisk/PLog" << "1");
|
||||||
|
if(fileInfo.isDir()){
|
||||||
|
this->AddWatch(fileInfo.absoluteFilePath());
|
||||||
|
}
|
||||||
|
// else{
|
||||||
|
// this->mlm->AddMessage(QVector<QString>() << fileInfo.fileName() << fileInfo.absoluteFilePath() << QString(bool((fileInfo.isDir()))));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void InotifyManagerRefact::SendRestMessage()
|
||||||
|
{
|
||||||
|
this->mlm->SendMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InotifyManagerRefact::AddWatch(const QString &path){
|
||||||
|
//m_fd = inotify_init();
|
||||||
|
// qDebug() << "m_fd: " <<m_fd;
|
||||||
|
//int ret = inotify_add_watch(m_fd, path.toStdString().c_str(), IN_ALL_EVENTS);
|
||||||
|
int ret = inotify_add_watch(m_fd, path.toStdString().c_str(), (IN_MOVED_FROM | IN_MOVED_TO | IN_CREATE | IN_DELETE));
|
||||||
|
if (ret == -1) {
|
||||||
|
qDebug() << "AddWatch error:" << path;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
currentPath[ret] = path;
|
||||||
|
//qDebug() << "Watch:" << path;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InotifyManagerRefact::RemoveWatch(const QString &path){
|
||||||
|
int ret = inotify_rm_watch(m_fd, currentPath.key(path));
|
||||||
|
if (ret){
|
||||||
|
qDebug() << "remove path error";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// qDebug() << "remove path: " << path;
|
||||||
|
|
||||||
|
for (QMap<int, QString>::Iterator i = currentPath.begin(); i != currentPath.end();){
|
||||||
|
if (i.value().length() > path.length()){
|
||||||
|
if (i.value().mid(0, path.length()) == path){
|
||||||
|
qDebug() << i.value();
|
||||||
|
/*--------------------------------*/
|
||||||
|
//在此调用删除索引
|
||||||
|
IndexGenerator::getInstance()->deleteAllIndex(new QStringList(path));
|
||||||
|
/*--------------------------------*/
|
||||||
|
currentPath.erase(i++);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qDebug() << path;
|
||||||
|
//这个貌似不用删,先mark一下
|
||||||
|
//currentPath.remove(currentPath.key(path));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InotifyManagerRefact::run(){
|
||||||
|
|
||||||
|
char * p;
|
||||||
|
char buf[BUF_LEN] __attribute__((aligned(8)));
|
||||||
|
|
||||||
|
ssize_t numRead;
|
||||||
|
|
||||||
|
for (;;) { /* Read events forever */
|
||||||
|
numRead = read(m_fd, buf, BUF_LEN);
|
||||||
|
if (numRead == 0) {
|
||||||
|
qDebug() << "read() from inotify fd returned 0!";
|
||||||
|
}
|
||||||
|
if (numRead == -1) {
|
||||||
|
qDebug() << "read";
|
||||||
|
}
|
||||||
|
qDebug() << "Read " << numRead << " bytes from inotify fd";
|
||||||
|
|
||||||
|
/* Process all of the events in buffer returned by read() */
|
||||||
|
|
||||||
|
for (p = buf; p < buf + numRead;) {
|
||||||
|
struct inotify_event * event = reinterpret_cast<inotify_event *>(p);
|
||||||
|
if(event->name[0] != '.'){
|
||||||
|
// if(true){
|
||||||
|
//这个位运算不要在意,只是懒得把文件夹、文件和事件排列组合了,只是看一下事件的类型
|
||||||
|
qDebug() << "Read Event: " << num2string[(event->mask & 0x0000ffff)] << currentPath[event->wd] << QString(event->name) << event->cookie << event->wd;
|
||||||
|
//num2string[event->mask & 0x0000ffff]
|
||||||
|
// IndexGenerator::getInstance()->creatAllIndex(new QStringList(currentPath[event->wd] + event->name));
|
||||||
|
|
||||||
|
/*--------------------------------*/
|
||||||
|
|
||||||
|
//传创建或移动过来的文件路径
|
||||||
|
if((event->mask & IN_CREATE) | (event->mask & IN_MOVED_TO)){
|
||||||
|
//添加监视要先序遍历,先添加top节点
|
||||||
|
if (event->mask & IN_ISDIR){
|
||||||
|
AddWatch(currentPath[event->wd] + '/' + event->name);
|
||||||
|
this->setPath(currentPath[event->wd] + '/' + event->name);
|
||||||
|
Traverse();
|
||||||
|
}
|
||||||
|
// else {
|
||||||
|
|
||||||
|
//IndexGenerator::getInstance()->creatAllIndex(new QStringList(currentPath[event->wd] + '/' + event->name));
|
||||||
|
this->mlm->AddMessage(QVector<QString>() << event->name << (currentPath[event->wd] + '/' + event->name) << QString(bool((event->mask & IN_ISDIR))));
|
||||||
|
this->mlm->SendMessage();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
else if((event->mask & IN_DELETE) | (event->mask & IN_MOVED_FROM)){
|
||||||
|
if (event->mask & IN_ISDIR){
|
||||||
|
RemoveWatch(currentPath[event->wd] + '/' + event->name);
|
||||||
|
}
|
||||||
|
// else {
|
||||||
|
//这里调用删除索引
|
||||||
|
// this->mlm->AddMessage(QVector<QString>() << event->name << (currentPath[event->wd] + '/' + event->name) << QString(bool((event->mask & IN_ISDIR))));
|
||||||
|
// this->mlm->SendDeleteMessage();
|
||||||
|
IndexGenerator::getInstance()->deleteAllIndex(new QStringList(currentPath[event->wd] + '/' + event->name));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
/*--------------------------------*/
|
||||||
|
}
|
||||||
|
p += sizeof(struct inotify_event) + event->len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
#ifndef INOTIFY_H
|
||||||
|
#define INOTIFY_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QThread>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/inotify.h>
|
||||||
|
#include "traverse_bfs.h"
|
||||||
|
#include "messagelist-manager.h"
|
||||||
|
#define BUF_LEN 1024
|
||||||
|
|
||||||
|
class InotifyManagerRefact : public QThread, public Traverse_BFS
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit InotifyManagerRefact(const QString&);
|
||||||
|
~InotifyManagerRefact();
|
||||||
|
|
||||||
|
bool AddWatch(const QString&);
|
||||||
|
bool RemoveWatch(const QString&);
|
||||||
|
virtual void DoSomething(const QFileInfo &) final;
|
||||||
|
void SendRestMessage();
|
||||||
|
Q_SIGNALS:
|
||||||
|
protected:
|
||||||
|
void run() override;
|
||||||
|
private:
|
||||||
|
QString *m_watch_path;
|
||||||
|
int m_fd;
|
||||||
|
QMap<int, QString> currentPath;
|
||||||
|
QMap<int, QString> num2string;
|
||||||
|
MessageListManager* mlm;
|
||||||
|
|
||||||
|
QMap<QString, QStringList>* dirPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INOTIFY_H
|
|
@ -0,0 +1,64 @@
|
||||||
|
#include "messagelist-manager.h"
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QTimer>
|
||||||
|
//#include <unistd.h>
|
||||||
|
|
||||||
|
MessageListManager::MessageListManager(){
|
||||||
|
this->messageList = new QList<QVector<QString>>();
|
||||||
|
this->ig = IndexGenerator::getInstance();
|
||||||
|
// indexGeneratorThread = new QThread();
|
||||||
|
// this->ig->moveToThread(indexGeneratorThread);
|
||||||
|
// connect(this,&MessageListManager::Send, this->ig, &IndexGenerator::creatAllIndex/*, Qt::QueuedConnection*/);
|
||||||
|
// connect(this,&MessageListManager::Send1, this->ig, [=](QStringList *l){
|
||||||
|
// qDebug()<<"send"<<*l;
|
||||||
|
// });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageListManager::~MessageListManager(){
|
||||||
|
delete this->messageList;
|
||||||
|
delete this->indexGeneratorThread;
|
||||||
|
//delete this->ig;
|
||||||
|
|
||||||
|
this->messageList = nullptr;
|
||||||
|
this->ig = nullptr;
|
||||||
|
this->indexGeneratorThread = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageListManager::AddMessage(const QVector<QString>& pathVec){
|
||||||
|
this->messageList->append(pathVec);
|
||||||
|
if (static_cast<size_t>(this->messageList->length()) >= this->length){
|
||||||
|
this->SendMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MessageListManager::SendMessage(){
|
||||||
|
//Q_EMIT Send(this->messageList);
|
||||||
|
if (this->messageList->empty()){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Q_EMIT Send(this->messageList);
|
||||||
|
// qDebug() << "emit";
|
||||||
|
this->ig->creatAllIndex(this->messageList);
|
||||||
|
|
||||||
|
//sleep(1);
|
||||||
|
this->messageList->clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MessageListManager::SendDeleteMessage(){
|
||||||
|
if (this->messageList->empty()){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this->ig->deleteAllIndex(this->messageList);
|
||||||
|
this->messageList->clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageListManager::SetAutoSendMessageLength(const size_t& length){
|
||||||
|
this->length = length;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef MESSAGELISTMANAGER_H
|
||||||
|
#define MESSAGELISTMANAGER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include "index-generator.h"
|
||||||
|
|
||||||
|
class MessageListManager : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit MessageListManager();
|
||||||
|
~MessageListManager();
|
||||||
|
|
||||||
|
void AddMessage(const QVector<QString>&);
|
||||||
|
bool SendMessage();
|
||||||
|
bool SendDeleteMessage();
|
||||||
|
void SetAutoSendMessageLength(const size_t&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// QStringList* messageList;
|
||||||
|
QList<QVector<QString>>* messageList;
|
||||||
|
|
||||||
|
size_t length = 80000;
|
||||||
|
IndexGenerator* ig;
|
||||||
|
QThread* indexGeneratorThread;
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
bool Send(QStringList*);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MESSAGELISTMANAGER_H
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,131 @@
|
||||||
|
#include <QTime>
|
||||||
|
#include <QDebug>
|
||||||
|
#include "inotify-manager.h"
|
||||||
|
#include "chinesecharacterstopinyin.h"
|
||||||
|
#include "inotify.h"
|
||||||
|
|
||||||
|
void testTraverse(void){
|
||||||
|
/*-------------Inotify Test Start---------------*/
|
||||||
|
// QTime t1 = QTime::currentTime();
|
||||||
|
// InotifyManager* im = new InotifyManager();
|
||||||
|
// im->AddWatch("/home");
|
||||||
|
// im->Traverse_BFS("/home", true);
|
||||||
|
// QTime t2 = QTime::currentTime();
|
||||||
|
// qDebug() << t1;
|
||||||
|
// qDebug() << t2;
|
||||||
|
// im->start();
|
||||||
|
/*-------------Inotify Test End-----------------*/
|
||||||
|
|
||||||
|
/*-------------PinyinSearch Test Start---------------*/
|
||||||
|
// QTime t1 = QTime::currentTime();
|
||||||
|
// QString test("test");
|
||||||
|
// qDebug() << IndexGenerator::IndexSearch(test);
|
||||||
|
// QTime t2 = QTime::currentTime();
|
||||||
|
// qDebug() << t1;
|
||||||
|
// qDebug() << t2;
|
||||||
|
/*-------------PinyinSearch Test End-----------------*/
|
||||||
|
|
||||||
|
/*-------------InotyifyRefact Test Start---------------*/
|
||||||
|
// QTime t1 = QTime::currentTime();
|
||||||
|
// InotifyManagerRefact* imr = new InotifyManagerRefact("/home");
|
||||||
|
// imr->AddWatch("/home");
|
||||||
|
// imr->setPath("/home");
|
||||||
|
// imr->Traverse();
|
||||||
|
// QTime t2 = QTime::currentTime();
|
||||||
|
// qDebug() << t1;
|
||||||
|
// qDebug() << t2;
|
||||||
|
/*-------------InotyifyRefact Test End-----------------*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeTone(){
|
||||||
|
/*-------------Remove Tone Start---------------*/
|
||||||
|
qDebug() << chineseCharactersToPinyin::find("z测试策士xl123123");
|
||||||
|
|
||||||
|
QFile file("://index/pinyinWithTone.txt");
|
||||||
|
QFile fileOut("/home/zhangzihao/ukui/ns/ukui-search/index/pinyinWithoutTone.txt");
|
||||||
|
fileOut.open(QIODevice::WriteOnly/* | QIODevice::Text*/);
|
||||||
|
|
||||||
|
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
||||||
|
qDebug("File: '%s' open failed!", file.fileName().toStdString().c_str());
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
while(!file.atEnd()) {
|
||||||
|
QString content = QString::fromUtf8(file.readLine());
|
||||||
|
content.replace("ā", "a")
|
||||||
|
.replace("á", "a")
|
||||||
|
.replace("ǎ", "a")
|
||||||
|
.replace("à", "a")
|
||||||
|
.replace("ō", "o")
|
||||||
|
.replace("ó", "o")
|
||||||
|
.replace("ǒ", "o")
|
||||||
|
.replace("ò", "o")
|
||||||
|
.replace("ê", "e")
|
||||||
|
.replace("ē", "e")
|
||||||
|
.replace("é", "e")
|
||||||
|
.replace("ě", "e")
|
||||||
|
.replace("è", "e")
|
||||||
|
.replace("ī", "i")
|
||||||
|
.replace("í", "i")
|
||||||
|
.replace("ǐ", "i")
|
||||||
|
.replace("ì", "i")
|
||||||
|
.replace("ū", "u")
|
||||||
|
.replace("ú", "u")
|
||||||
|
.replace("ǔ", "u")
|
||||||
|
.replace("ù", "u")
|
||||||
|
//l和n后面的ü写作v
|
||||||
|
.replace("lǖ", "lv")
|
||||||
|
.replace("lǘ", "lv")
|
||||||
|
.replace("lǚ", "lv")
|
||||||
|
.replace("lǜ", "lv")
|
||||||
|
.replace("lü", "lv")
|
||||||
|
.replace("nǖ", "nv")
|
||||||
|
.replace("nǘ", "nv")
|
||||||
|
.replace("nǚ", "nv")
|
||||||
|
.replace("nǜ", "nv")
|
||||||
|
.replace("nü", "nv")
|
||||||
|
//l和n后面的ü替换之后,其他的ü替换为u
|
||||||
|
.replace("ǖ", "u")
|
||||||
|
.replace("ǘ", "u")
|
||||||
|
.replace("ǚ", "u")
|
||||||
|
.replace("ǜ", "u")
|
||||||
|
.replace("ü", "u")
|
||||||
|
.replace("ê", "e")
|
||||||
|
.replace("ɑ", "a")
|
||||||
|
.replace("", "m")
|
||||||
|
.replace("ń", "n")
|
||||||
|
.replace("", "n")
|
||||||
|
.replace("ɡ", "g");
|
||||||
|
//去除同音不同调
|
||||||
|
//QString content = QString::fromUtf8(file.readLine());
|
||||||
|
|
||||||
|
QStringList temp = content.split(" ").first().split(",").toSet().toList();
|
||||||
|
QString outContent;
|
||||||
|
for (auto i : temp){
|
||||||
|
outContent += i;
|
||||||
|
outContent += ",";
|
||||||
|
}
|
||||||
|
outContent = outContent.left(outContent.size() - 1);
|
||||||
|
outContent += " ";
|
||||||
|
outContent += content.split(" ").last().trimmed();
|
||||||
|
outContent += "\n";
|
||||||
|
fileOut.write(outContent.toUtf8());
|
||||||
|
// temp.toSet().toList();
|
||||||
|
//content.split(" ").first().split(",")
|
||||||
|
|
||||||
|
//map[content.split(" ").last().trimmed()] = content.split(" ").first().split(",");
|
||||||
|
|
||||||
|
|
||||||
|
// ā á ǎ à ō ó ǒ ò ê ē é ě è ī í ǐ ì ū ú ǔ ù ǖ ǘ ǚ ǜ ü ê ɑ ń ň ɡ
|
||||||
|
// fileOut.write(content.toUtf8());
|
||||||
|
qDebug() << content;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
fileOut.close();
|
||||||
|
/*-------------Remove Tone End-----------------*/
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
#include "text-content-indexer.h"
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
TextContentIndexer::TextContentIndexer(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextContentIndexer::creatContentdata()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextContentIndexer::setFileList(QStringList *filelist)
|
||||||
|
{
|
||||||
|
m_file_list = filelist;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextContentIndexer::begin()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TextContentIndexer::getPlaintextFileContent(QString path)
|
||||||
|
{
|
||||||
|
QFile file(path);
|
||||||
|
if(!file.open(QIODevice::ReadOnly))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QTextStream *stream = new QTextStream(&file);
|
||||||
|
QString content = stream->readAll();
|
||||||
|
qDebug()<<content;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef TEXTCONTENTINDEXER_H
|
||||||
|
#define TEXTCONTENTINDEXER_H
|
||||||
|
|
||||||
|
#include "document.h"
|
||||||
|
#include <QObject>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class TextContentIndexer : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit TextContentIndexer(QObject *parent = nullptr);
|
||||||
|
void setFileList(QStringList *filelist);
|
||||||
|
void begin();
|
||||||
|
bool getPlaintextFileContent(QString path);
|
||||||
|
Q_SIGNALS:
|
||||||
|
bool finish();
|
||||||
|
private:
|
||||||
|
void creatContentdata();
|
||||||
|
QStringList *m_file_list;
|
||||||
|
Document *m_current_document;
|
||||||
|
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TEXTCONTENTINDEXER_H
|
|
@ -0,0 +1,29 @@
|
||||||
|
#include "traverse_bfs.h"
|
||||||
|
|
||||||
|
Traverse_BFS::Traverse_BFS(const QString& path)
|
||||||
|
{
|
||||||
|
this->path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Traverse_BFS::Traverse(){
|
||||||
|
QQueue<QString> bfs;
|
||||||
|
bfs.enqueue(this->path);
|
||||||
|
QFileInfoList list;
|
||||||
|
QDir dir;
|
||||||
|
dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
|
||||||
|
dir.setSorting(QDir::DirsFirst);
|
||||||
|
while (!bfs.empty()) {
|
||||||
|
dir.setPath(bfs.dequeue());
|
||||||
|
list = dir.entryInfoList();
|
||||||
|
for (auto i : list){
|
||||||
|
if (i.isDir()){
|
||||||
|
bfs.enqueue(i.absoluteFilePath());
|
||||||
|
}
|
||||||
|
DoSomething(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Traverse_BFS::setPath(const QString& path){
|
||||||
|
this->path = path;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef TRAVERSE_BFS_H
|
||||||
|
#define TRAVERSE_BFS_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QQueue>
|
||||||
|
|
||||||
|
class Traverse_BFS
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Traverse_BFS(const QString&);
|
||||||
|
void Traverse();
|
||||||
|
virtual void DoSomething(const QFileInfo&) = 0;
|
||||||
|
void setPath(const QString&);
|
||||||
|
private:
|
||||||
|
QString path = "/home";
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TRAVERSE_BFS_H
|
|
@ -0,0 +1,5 @@
|
||||||
|
#include "libsearch.h"
|
||||||
|
|
||||||
|
Libsearch::Libsearch()
|
||||||
|
{
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>index/pinyinWithTone.txt</file>
|
||||||
|
<file>index/pinyinWithoutTone.txt</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
|
@ -0,0 +1,86 @@
|
||||||
|
#include "setting-match.h"
|
||||||
|
|
||||||
|
SettingsMatch::SettingsMatch(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
xmlElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList SettingsMatch::startMatchApp(const QString &source){
|
||||||
|
m_sourceText=source;
|
||||||
|
// qDebug()<<m_sourceText;
|
||||||
|
QStringList settingList=matching();
|
||||||
|
return settingList;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsMatch::xmlElement(){
|
||||||
|
QString pinyinIndex;
|
||||||
|
QString ChineseIndex;
|
||||||
|
|
||||||
|
QFile file(QString::fromLocal8Bit(":/res/search.xml"));
|
||||||
|
if (!file.open(QIODevice::ReadOnly)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QDomDocument doc;
|
||||||
|
doc.setContent(&file);
|
||||||
|
QDomElement root=doc.documentElement();
|
||||||
|
QDomNode node = root.previousSibling();
|
||||||
|
node=root.firstChild();
|
||||||
|
|
||||||
|
while(!node.isNull()){
|
||||||
|
QDomElement element=node.toElement();
|
||||||
|
QString key=element.attribute("name");;
|
||||||
|
m_chine_searchResult=m_chine_searchList.value(key);
|
||||||
|
m_pinyin_searchResult=m_pinyin_searchList.value(key);
|
||||||
|
QDomNodeList list=element.childNodes();
|
||||||
|
for(int i=0;i<list.count();++i){
|
||||||
|
QDomNode n=list.at(i);
|
||||||
|
|
||||||
|
if(n.nodeName()==QString::fromLocal8Bit("pinyinPlugin")){
|
||||||
|
pinyinIndex=n.toElement().text();
|
||||||
|
}
|
||||||
|
if(n.nodeName()==QString::fromLocal8Bit("pinyinfunc")){
|
||||||
|
pinyinIndex+=QString::fromLocal8Bit(":")+n.toElement().text();
|
||||||
|
m_pinyin_searchResult.append(pinyinIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(n.nodeName()==QString::fromLocal8Bit("ChinesePlugin")){
|
||||||
|
ChineseIndex=n.toElement().text();
|
||||||
|
}
|
||||||
|
if(n.nodeName()==QString::fromLocal8Bit("ChineseFunc")){
|
||||||
|
ChineseIndex+=QString::fromLocal8Bit("/")+n.toElement().text();
|
||||||
|
|
||||||
|
m_chine_searchResult.append(ChineseIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_pinyin_searchList.insert(key,m_pinyin_searchResult);
|
||||||
|
m_chine_searchList.insert(key,m_chine_searchResult);
|
||||||
|
|
||||||
|
node=node.nextSibling();
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
// qDebug()<<pinyin_searchlist;
|
||||||
|
// qDebug()<<chine_searchlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList SettingsMatch::matching(){
|
||||||
|
QStringList returnresult;
|
||||||
|
QStringList regmatch;
|
||||||
|
QString key;
|
||||||
|
QMap<QString, QStringList>::const_iterator i;
|
||||||
|
for(i=m_chine_searchList.constBegin();i!=m_chine_searchList.constEnd();++i){
|
||||||
|
regmatch=*i;
|
||||||
|
key=i.key();
|
||||||
|
// qDebug()<<key;
|
||||||
|
for(int t=0; t<regmatch.size();t++)
|
||||||
|
{
|
||||||
|
QString str =regmatch.at(t);
|
||||||
|
if(str.contains(m_sourceText))
|
||||||
|
{
|
||||||
|
str=key+"/"+str;
|
||||||
|
returnresult.append(str);//中文名
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// qDebug()<<returnresult;
|
||||||
|
return returnresult;
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef SETTINGSEARCH_H
|
||||||
|
#define SETTINGSEARCH_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QDomElement>
|
||||||
|
#include <QDomDocument>
|
||||||
|
#include <QDomNode>
|
||||||
|
#include <QDomNodeList>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QDebug>
|
||||||
|
class SettingsMatch : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit SettingsMatch(QObject *parent = nullptr);
|
||||||
|
QStringList startMatchApp(const QString &source);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void xmlElement();
|
||||||
|
QStringList matching();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMap<QString,QStringList> m_pinyin_searchList;
|
||||||
|
QMap<QString,QStringList> m_chine_searchList;
|
||||||
|
QStringList m_pinyin_searchResult;
|
||||||
|
QStringList m_chine_searchResult;
|
||||||
|
QString m_sourceText;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SETTINGSEARCH_H
|
|
@ -0,0 +1,7 @@
|
||||||
|
INCLUDEPATH += $$PWD
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
$$PWD/setting-match.h \
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
$$PWD/setting-match.cpp \
|
|
@ -0,0 +1,90 @@
|
||||||
|
#include "config-file.h"
|
||||||
|
|
||||||
|
ConfigFile::ConfigFile(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
QFile file(QDir::homePath()+"/.config/org.ukui/ukui-search/ukui-search.conf");
|
||||||
|
if(!file.exists()){
|
||||||
|
file.open( QIODevice::ReadWrite | QIODevice::Text );
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
m_qSettings=new QSettings(QDir::homePath()+"/.config/org.ukui/ukui-search/ukui-search.conf",QSettings::IniFormat);
|
||||||
|
receiveMessage("ukui-panel");//测试使用
|
||||||
|
receiveMessage("ukui-panel.desktop");//测试使用
|
||||||
|
readConfig();//页面调用
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigFile::writeCommonly(QString message){
|
||||||
|
QStringList messagelist=message.split("/");
|
||||||
|
QString appname=messagelist.last();
|
||||||
|
if(!appname.contains("desktop"))
|
||||||
|
return;
|
||||||
|
m_qSettings->beginGroup("Commonly");
|
||||||
|
QStringList quickly=m_qSettings->allKeys();
|
||||||
|
if(quickly.contains(message)){
|
||||||
|
m_qSettings->setValue(message,m_qSettings->value(message).toInt()+1);
|
||||||
|
}else{
|
||||||
|
m_qSettings->setValue(message,1);
|
||||||
|
}
|
||||||
|
m_qSettings->endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList ConfigFile::readCommonly(){
|
||||||
|
QStringList returnlist;
|
||||||
|
QMap<QString,int> quicklycount;
|
||||||
|
m_qSettings->beginGroup("Commonly");
|
||||||
|
QStringList Commonly=m_qSettings->allKeys();
|
||||||
|
for(int i=0;i<Commonly.size();i++){
|
||||||
|
quicklycount.insert(Commonly.at(i),m_qSettings->value(Commonly.at(i)).toInt());
|
||||||
|
}
|
||||||
|
m_qSettings->endGroup();
|
||||||
|
QMap<QString, int>::iterator iter =quicklycount.begin();
|
||||||
|
QVector<QPair<QString, int>> vec;
|
||||||
|
QString iconamePah;
|
||||||
|
while(iter !=quicklycount.end()) {
|
||||||
|
vec.push_back(qMakePair(iter.key(), iter.value()));
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
qSort(vec.begin(), vec.end(), [](const QPair<QString, int> &l, const QPair<QString, int> &r) {
|
||||||
|
return (l.second > r.second);
|
||||||
|
});
|
||||||
|
for(int j=0;j<vec.size();j++){
|
||||||
|
returnlist.append(vec.at(j).first);
|
||||||
|
}
|
||||||
|
// qDebug()<<returnlist;
|
||||||
|
return returnlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigFile::writeRecently(QString message){
|
||||||
|
m_qSettings->beginGroup("Recently");
|
||||||
|
QStringList recently=m_qSettings->value("Recently").toStringList();
|
||||||
|
m_qSettings->endGroup();
|
||||||
|
recently.insert(0,message);
|
||||||
|
m_qSettings->beginGroup("Recently");
|
||||||
|
m_qSettings->setValue("Recently",recently);
|
||||||
|
m_qSettings->endGroup();
|
||||||
|
}
|
||||||
|
QStringList ConfigFile::readRecently(){
|
||||||
|
m_qSettings->beginGroup("Recently");
|
||||||
|
QStringList recently=m_qSettings->value("Recently").toStringList();
|
||||||
|
m_qSettings->endGroup();
|
||||||
|
// qDebug()<<recently;
|
||||||
|
return recently;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigFile::writeConfig(){
|
||||||
|
writeCommonly(m_message);
|
||||||
|
writeRecently(m_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
QMap<QString,QStringList> ConfigFile::readConfig(){
|
||||||
|
QMap<QString,QStringList> returnresult;
|
||||||
|
returnresult.insert("Commonly",readCommonly());
|
||||||
|
returnresult.insert("Recently",readRecently());
|
||||||
|
// qDebug()<<returnresult;
|
||||||
|
return returnresult;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigFile::receiveMessage(QString message){
|
||||||
|
m_message=message;
|
||||||
|
writeConfig();
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
#ifndef CONFIGFILE_H
|
||||||
|
#define CONFIGFILE_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDir>
|
||||||
|
class ConfigFile : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ConfigFile(QObject *parent = nullptr);
|
||||||
|
void writeConfig();
|
||||||
|
QMap<QString,QStringList> readConfig();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSettings *m_qSettings;
|
||||||
|
QString m_message;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void writeCommonly(QString message);
|
||||||
|
QStringList readCommonly();
|
||||||
|
void writeRecently(QString message);
|
||||||
|
QStringList readRecently();
|
||||||
|
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void receiveMessage(QString message);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CONFIGFILE_H
|
|
@ -0,0 +1,15 @@
|
||||||
|
INCLUDEPATH += $$PWD
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
$$PWD/config-file.h \
|
||||||
|
$$PWD/search-list-view.h \
|
||||||
|
$$PWD/search-detail-view.h \
|
||||||
|
$$PWD/option-view.h \
|
||||||
|
$$PWD/home-page-item.h \
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
$$PWD/config-file.cpp \
|
||||||
|
$$PWD/search-list-view.cpp \
|
||||||
|
$$PWD/search-detail-view.cpp \
|
||||||
|
$$PWD/option-view.cpp \
|
||||||
|
$$PWD/home-page-item.cpp \
|
|
@ -0,0 +1,129 @@
|
||||||
|
#include "home-page-item.h"
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <gio/gdesktopappinfo.h>
|
||||||
|
|
||||||
|
HomePageItem::HomePageItem(QWidget *parent, const int& type, const QString& path) : QWidget(parent)
|
||||||
|
{
|
||||||
|
setupUi(type, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
HomePageItem::~HomePageItem()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief HomePageItem::setupUi 根据不同的分栏创建item
|
||||||
|
* @param type 所属分栏
|
||||||
|
* @param path 路径
|
||||||
|
*/
|
||||||
|
void HomePageItem::setupUi(const int& type, const QString& path) {
|
||||||
|
m_widget = new QWidget(this);
|
||||||
|
m_widget->setObjectName("MainWidget");
|
||||||
|
m_widget->setStyleSheet("QWidget#MainWidget{background: rgba(0, 0, 0, 0.05); border-radius: 4px;}");
|
||||||
|
m_widget->installEventFilter(this);
|
||||||
|
connect(this, &HomePageItem::onItemClicked, this, [ = ]() {
|
||||||
|
switch (SearchListView::getResType(path)) {
|
||||||
|
case SearchListView::ResType::App: {
|
||||||
|
GDesktopAppInfo * desktopAppInfo = g_desktop_app_info_new_from_filename(path.toLocal8Bit().data());
|
||||||
|
g_app_info_launch(G_APP_INFO(desktopAppInfo),nullptr, nullptr, nullptr);
|
||||||
|
g_object_unref(desktopAppInfo);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SearchListView::ResType::Dir:
|
||||||
|
case SearchListView::ResType::File: {
|
||||||
|
QProcess * process = new QProcess;
|
||||||
|
process->start(QString("xdg-open %1").arg(path));
|
||||||
|
connect(process, static_cast<void(QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished), this, [ = ]() {
|
||||||
|
process->deleteLater();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SearchListView::ResType::Setting: {
|
||||||
|
//打开控制面板对应页面
|
||||||
|
QProcess * process = new QProcess;
|
||||||
|
process->start(QString("ukui-control-center --%1").arg(path.left(path.indexOf("/")).toLower()));
|
||||||
|
connect(process, static_cast<void(QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished), this, [ = ]() {
|
||||||
|
process->deleteLater();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
m_iconlabel = new QLabel(m_widget);
|
||||||
|
m_namelabel = new QLabel(m_widget);
|
||||||
|
m_namelabel->setStyleSheet("QLabel{color: palette(text);}");
|
||||||
|
if (type == ItemType::Recent) {
|
||||||
|
m_widget->setFixedSize(265, 48);
|
||||||
|
QIcon icon;
|
||||||
|
switch (SearchListView::getResType(path)) { //可能出现文件应用等,需要根据路径判断类型
|
||||||
|
case SearchListView::ResType::App : {
|
||||||
|
icon = FileUtils::getAppIcon(path);
|
||||||
|
m_namelabel->setText(FileUtils::getAppName(path));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SearchListView::ResType::File : {
|
||||||
|
icon = FileUtils::getFileIcon(QString("file://%1").arg(path));
|
||||||
|
m_namelabel->setText(FileUtils::getFileName(path));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SearchListView::ResType::Setting : {
|
||||||
|
icon = FileUtils::getSettingIcon(path, true);
|
||||||
|
m_namelabel->setText(FileUtils::getSettingName(path));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SearchListView::ResType::Dir : {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default :
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_iconlabel->setPixmap(icon.pixmap(icon.actualSize(QSize(24, 24))));
|
||||||
|
m_hlayout = new QHBoxLayout(m_widget);
|
||||||
|
m_iconlabel->setAlignment(Qt::AlignCenter);
|
||||||
|
m_namelabel->setAlignment(Qt::AlignCenter);
|
||||||
|
m_hlayout->addWidget(m_iconlabel);
|
||||||
|
m_hlayout->addWidget(m_namelabel);
|
||||||
|
m_hlayout->addStretch();
|
||||||
|
return;
|
||||||
|
} else if (type == ItemType::Quick) {
|
||||||
|
if (SearchListView::getResType(path) == SearchListView::ResType::Setting) {
|
||||||
|
QIcon icon = FileUtils::getSettingIcon(path, true);
|
||||||
|
m_iconlabel->setPixmap(icon.pixmap(icon.actualSize(QSize(48, 48))));
|
||||||
|
m_namelabel->setText(FileUtils::getSettingName(path));
|
||||||
|
} else {
|
||||||
|
QIcon icon = FileUtils::getAppIcon(path);
|
||||||
|
m_iconlabel->setPixmap(icon.pixmap(icon.actualSize(QSize(48, 48))));
|
||||||
|
m_namelabel->setText(FileUtils::getAppName(path));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QIcon icon = FileUtils::getAppIcon(path);
|
||||||
|
m_iconlabel->setPixmap(icon.pixmap(icon.actualSize(QSize(48, 48))));
|
||||||
|
m_namelabel->setText(FileUtils::getAppName(path));
|
||||||
|
}
|
||||||
|
m_widget->setFixedSize(120, 120);
|
||||||
|
m_vlayout = new QVBoxLayout(m_widget);
|
||||||
|
m_vlayout->setContentsMargins(0,16,0,12);
|
||||||
|
m_iconlabel->setAlignment(Qt::AlignCenter);
|
||||||
|
m_namelabel->setAlignment(Qt::AlignCenter);
|
||||||
|
m_vlayout->addWidget(m_iconlabel);
|
||||||
|
m_vlayout->addWidget(m_namelabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HomePageItem::eventFilter(QObject *watched, QEvent *event){
|
||||||
|
if (watched == m_widget){
|
||||||
|
if (event->type() == QEvent::MouseButtonPress) {
|
||||||
|
Q_EMIT this->onItemClicked();
|
||||||
|
m_widget->setStyleSheet("QWidget#MainWidget{background: rgba(0, 0, 0, 0.1); border-radius: 4px;}");
|
||||||
|
return true;
|
||||||
|
} else if (event->type() == QEvent::MouseButtonRelease) {
|
||||||
|
m_widget->setStyleSheet("QWidget#MainWidget{background: rgba(0, 0, 0, 0.05); border-radius: 4px;}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QObject::eventFilter(watched, event);
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
#ifndef HOMEPAGEITEM_H
|
||||||
|
#define HOMEPAGEITEM_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include "file-utils.h"
|
||||||
|
#include "search-list-view.h"
|
||||||
|
|
||||||
|
class HomePageItem : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit HomePageItem(QWidget *, const int&, const QString&);
|
||||||
|
~HomePageItem();
|
||||||
|
|
||||||
|
enum ItemType { //homepage中item的类型,包括常用应用、最近打开、快捷打开
|
||||||
|
Common,
|
||||||
|
Recent,
|
||||||
|
Quick
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject *, QEvent *);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupUi(const int&, const QString&);
|
||||||
|
|
||||||
|
QWidget * m_widget = nullptr;
|
||||||
|
QHBoxLayout * m_hlayout = nullptr;
|
||||||
|
QVBoxLayout * m_vlayout = nullptr;
|
||||||
|
QLabel * m_iconlabel = nullptr;
|
||||||
|
QLabel * m_namelabel = nullptr;
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void onItemClicked();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HOMEPAGEITEM_H
|
|
@ -0,0 +1,185 @@
|
||||||
|
#include "option-view.h"
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QEvent>
|
||||||
|
|
||||||
|
OptionView::OptionView(QWidget *parent, const int& type) : QWidget(parent)
|
||||||
|
{
|
||||||
|
m_mainLyt = new QVBoxLayout(this);
|
||||||
|
this->setLayout(m_mainLyt);
|
||||||
|
m_mainLyt->setContentsMargins(0,8,0,0);
|
||||||
|
m_mainLyt->setSpacing(8);
|
||||||
|
initComponent(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
OptionView::~OptionView()
|
||||||
|
{
|
||||||
|
if (m_openLabel) {
|
||||||
|
delete m_openLabel;
|
||||||
|
m_openLabel = NULL;
|
||||||
|
}
|
||||||
|
if (m_shortcutLabel) {
|
||||||
|
delete m_shortcutLabel;
|
||||||
|
m_shortcutLabel = NULL;
|
||||||
|
}
|
||||||
|
if (m_panelLabel) {
|
||||||
|
delete m_panelLabel;
|
||||||
|
m_panelLabel = NULL;
|
||||||
|
}
|
||||||
|
if (m_openPathLabel) {
|
||||||
|
delete m_openPathLabel;
|
||||||
|
m_openPathLabel = NULL;
|
||||||
|
}
|
||||||
|
if (m_copyPathLabel) {
|
||||||
|
delete m_copyPathLabel;
|
||||||
|
m_copyPathLabel = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OptionView::initComponent 构建可用选项表
|
||||||
|
* @param type 详情页类型
|
||||||
|
*/
|
||||||
|
void OptionView::initComponent(const int& type) {
|
||||||
|
switch (type) {
|
||||||
|
case SearchListView::ResType::App : {
|
||||||
|
setupAppOptions();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SearchListView::ResType::File : {
|
||||||
|
setupFileOptions();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SearchListView::ResType::Setting : {
|
||||||
|
setupSettingOptions();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SearchListView::ResType::Dir : {
|
||||||
|
setupDirOptions();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief setupOptionLabel 创建每一个单独的选项
|
||||||
|
* @param opt 选项类型
|
||||||
|
*/
|
||||||
|
void OptionView::setupOptionLabel(const int& opt) {
|
||||||
|
QFrame * optionFrame = new QFrame(this);
|
||||||
|
QHBoxLayout * optionLyt = new QHBoxLayout(optionFrame);
|
||||||
|
optionLyt->setContentsMargins(8, 0, 0, 0);
|
||||||
|
switch (opt) {
|
||||||
|
case Options::Open: {
|
||||||
|
m_openLabel = new QLabel(optionFrame);
|
||||||
|
m_openLabel->setText(tr("Open")); //打开
|
||||||
|
m_openLabel->setStyleSheet("QLabel{font-size: 14px; color: #3D6BE5}");
|
||||||
|
m_openLabel->setCursor(QCursor(Qt::PointingHandCursor));
|
||||||
|
m_openLabel->installEventFilter(this);
|
||||||
|
optionLyt->addWidget(m_openLabel);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Options::Shortcut: {
|
||||||
|
m_shortcutLabel = new QLabel(optionFrame);
|
||||||
|
m_shortcutLabel->setText(tr("Add Shortcut to Desktop")); //添加到桌面快捷方式
|
||||||
|
m_shortcutLabel->setStyleSheet("QLabel{font-size: 14px; color: #3D6BE5}");
|
||||||
|
m_shortcutLabel->setCursor(QCursor(Qt::PointingHandCursor));
|
||||||
|
m_shortcutLabel->installEventFilter(this);
|
||||||
|
optionLyt->addWidget(m_shortcutLabel);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Options::Panel: {
|
||||||
|
m_panelLabel = new QLabel(optionFrame);
|
||||||
|
m_panelLabel->setText(tr("Add Shortcut to Panel")); //添加到任务栏快捷方式
|
||||||
|
m_panelLabel->setStyleSheet("QLabel{font-size: 14px; color: #3D6BE5}");
|
||||||
|
m_panelLabel->setCursor(QCursor(Qt::PointingHandCursor));
|
||||||
|
m_panelLabel->installEventFilter(this);
|
||||||
|
optionLyt->addWidget(m_panelLabel);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Options::OpenPath: {
|
||||||
|
m_openPathLabel = new QLabel(optionFrame);
|
||||||
|
m_openPathLabel->setText(tr("Open path")); //打开所在路径
|
||||||
|
m_openPathLabel->setStyleSheet("QLabel{font-size: 14px; color: #3D6BE5}");
|
||||||
|
m_openPathLabel->setCursor(QCursor(Qt::PointingHandCursor));
|
||||||
|
m_openPathLabel->installEventFilter(this);
|
||||||
|
optionLyt->addWidget(m_openPathLabel);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Options::CopyPath: {
|
||||||
|
m_copyPathLabel = new QLabel(optionFrame);
|
||||||
|
m_copyPathLabel->setText(tr("Copy path")); //复制所在路径
|
||||||
|
m_copyPathLabel->setStyleSheet("QLabel{font-size: 14px; color: #3D6BE5}");
|
||||||
|
m_copyPathLabel->setCursor(QCursor(Qt::PointingHandCursor));
|
||||||
|
m_copyPathLabel->installEventFilter(this);
|
||||||
|
optionLyt->addWidget(m_copyPathLabel);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
optionLyt->addStretch();
|
||||||
|
optionFrame->setLayout(optionLyt);
|
||||||
|
m_mainLyt->addWidget(optionFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OptionView::setupAppOptions 为应用类型的详情页构建选项表
|
||||||
|
*/
|
||||||
|
void OptionView::setupAppOptions() {
|
||||||
|
setupOptionLabel(Options::Open);
|
||||||
|
setupOptionLabel(Options::Shortcut);
|
||||||
|
setupOptionLabel(Options::Panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OptionView::setupFileOptions 为文件类型的详情页构建选项表
|
||||||
|
*/
|
||||||
|
void OptionView::setupFileOptions() {
|
||||||
|
setupOptionLabel(Options::Open);
|
||||||
|
setupOptionLabel(Options::OpenPath);
|
||||||
|
setupOptionLabel(Options::CopyPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OptionView::setupDirOptions 为文件夹类型的详情页构建选项表
|
||||||
|
*/
|
||||||
|
void OptionView::setupDirOptions() {
|
||||||
|
setupOptionLabel(Options::Open);
|
||||||
|
setupOptionLabel(Options::OpenPath);
|
||||||
|
setupOptionLabel(Options::CopyPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OptionView::setupSettingOptions 为设置类型的详情页构建选项表
|
||||||
|
*/
|
||||||
|
void OptionView::setupSettingOptions() {
|
||||||
|
setupOptionLabel(Options::Open);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief OptionView::eventFilter 相应鼠标点击事件并发出信号供detailview处理
|
||||||
|
* @param watched
|
||||||
|
* @param event
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool OptionView::eventFilter(QObject *watched, QEvent *event){
|
||||||
|
if (m_openLabel && watched == m_openLabel && event->type() == QEvent::MouseButtonPress){
|
||||||
|
Q_EMIT onOptionClicked(Options::Open);
|
||||||
|
return true;
|
||||||
|
} else if (m_shortcutLabel && watched == m_shortcutLabel && event->type() == QEvent::MouseButtonPress) {
|
||||||
|
Q_EMIT onOptionClicked(Options::Shortcut);
|
||||||
|
return true;
|
||||||
|
} else if (m_panelLabel && watched == m_panelLabel && event->type() == QEvent::MouseButtonPress) {
|
||||||
|
Q_EMIT onOptionClicked(Options::Panel);
|
||||||
|
return true;
|
||||||
|
} else if (m_openPathLabel && watched == m_openPathLabel && event->type() == QEvent::MouseButtonPress) {
|
||||||
|
Q_EMIT onOptionClicked(Options::OpenPath);
|
||||||
|
return true;
|
||||||
|
} else if (m_copyPathLabel && watched == m_copyPathLabel && event->type() == QEvent::MouseButtonPress) {
|
||||||
|
Q_EMIT onOptionClicked(Options::CopyPath);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return QObject::eventFilter(watched, event);
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
#ifndef OPTIONVIEW_H
|
||||||
|
#define OPTIONVIEW_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QFrame>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include "search-list-view.h"
|
||||||
|
|
||||||
|
class OptionView : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit OptionView(QWidget *, const int&);
|
||||||
|
~OptionView();
|
||||||
|
|
||||||
|
enum Options {
|
||||||
|
Open,
|
||||||
|
Shortcut,
|
||||||
|
Panel,
|
||||||
|
OpenPath,
|
||||||
|
CopyPath
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject *, QEvent *);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void initComponent(const int&);
|
||||||
|
void setupAppOptions();
|
||||||
|
void setupFileOptions();
|
||||||
|
void setupDirOptions();
|
||||||
|
void setupSettingOptions();
|
||||||
|
void setupOptionLabel(const int&);
|
||||||
|
|
||||||
|
int m_type;
|
||||||
|
|
||||||
|
QVBoxLayout * m_mainLyt = nullptr;
|
||||||
|
QLabel * m_openLabel = nullptr;
|
||||||
|
QLabel * m_shortcutLabel = nullptr;
|
||||||
|
QLabel * m_panelLabel = nullptr;
|
||||||
|
QLabel * m_openPathLabel = nullptr;
|
||||||
|
QLabel * m_copyPathLabel = nullptr;
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void onOptionClicked(const int&);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // OPTIONVIEW_H
|
|
@ -0,0 +1,296 @@
|
||||||
|
#include "search-detail-view.h"
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QStyleOption>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <gio/gdesktopappinfo.h>
|
||||||
|
#include <QDBusInterface>
|
||||||
|
#include <QDBusReply>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QClipboard>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
SearchDetailView::SearchDetailView(QWidget *parent) : QWidget(parent)
|
||||||
|
{
|
||||||
|
m_layout = new QVBoxLayout(this);
|
||||||
|
this->setLayout(m_layout);
|
||||||
|
m_layout->setContentsMargins(16, 60, 16, 24);
|
||||||
|
this->setObjectName("detailView");
|
||||||
|
this->setStyleSheet("QWidget#detailView{background:transparent;}");
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchDetailView::~SearchDetailView()
|
||||||
|
{
|
||||||
|
if (m_layout) {
|
||||||
|
clearLayout();
|
||||||
|
delete m_layout;
|
||||||
|
m_layout = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SearchDetailView::clearLayout 清空布局
|
||||||
|
*/
|
||||||
|
void SearchDetailView::clearLayout() {
|
||||||
|
QLayoutItem * child;
|
||||||
|
while ((child = m_layout->takeAt(0)) != 0) {
|
||||||
|
if(child->widget())
|
||||||
|
{
|
||||||
|
child->widget()->setParent(NULL); //防止删除后窗口看上去没有消失
|
||||||
|
}
|
||||||
|
delete child;
|
||||||
|
}
|
||||||
|
child = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SearchDetailView::setupWidget 构建右侧搜索结果详情区域
|
||||||
|
* @param type 搜索类型
|
||||||
|
* @param path 结果路径
|
||||||
|
*/
|
||||||
|
void SearchDetailView::setupWidget(const int& type, const QString& path) {
|
||||||
|
clearLayout();
|
||||||
|
|
||||||
|
//图标和名称、分割线区域
|
||||||
|
QLabel * iconLabel = new QLabel(this);
|
||||||
|
iconLabel->setAlignment(Qt::AlignCenter);
|
||||||
|
iconLabel->setFixedHeight(120);
|
||||||
|
|
||||||
|
QFrame * nameFrame = new QFrame(this);
|
||||||
|
QHBoxLayout * nameLayout = new QHBoxLayout(nameFrame);
|
||||||
|
QLabel * nameLabel = new QLabel(nameFrame);
|
||||||
|
QLabel * typeLabel = new QLabel(nameFrame);
|
||||||
|
nameLabel->setStyleSheet("QLabel{font-size: 18px;}");
|
||||||
|
// typeLabel->setStyleSheet("QLabel{font-size: 14px; color: rgba(0, 0, 0, 0.43);}");
|
||||||
|
typeLabel->setStyleSheet("QLabel{font-size: 14px; color: palette(mid);}");
|
||||||
|
nameFrame->setFixedHeight(48);
|
||||||
|
nameLabel->setMaximumWidth(240);
|
||||||
|
nameLayout->addWidget(nameLabel);
|
||||||
|
nameLayout->addStretch();
|
||||||
|
nameLayout->addWidget(typeLabel);
|
||||||
|
nameFrame->setLayout(nameLayout);
|
||||||
|
|
||||||
|
QFrame * hLine = new QFrame(this);
|
||||||
|
hLine->setLineWidth(0);
|
||||||
|
hLine->setFixedHeight(1);
|
||||||
|
hLine->setStyleSheet("QFrame{background: rgba(0,0,0,0.2);}");
|
||||||
|
|
||||||
|
m_layout->addWidget(iconLabel);
|
||||||
|
m_layout->addWidget(nameFrame);
|
||||||
|
m_layout->addWidget(hLine);
|
||||||
|
|
||||||
|
//文件和文件夹有一个额外的详情区域
|
||||||
|
if (type == SearchListView::ResType::Dir || type == SearchListView::ResType::File) {
|
||||||
|
QFrame * detailFrame = new QFrame(this);
|
||||||
|
QVBoxLayout * detailLyt = new QVBoxLayout(detailFrame);
|
||||||
|
detailLyt->setContentsMargins(0,0,0,0);
|
||||||
|
QFrame * pathFrame = new QFrame(detailFrame);
|
||||||
|
QFrame * timeFrame = new QFrame(detailFrame);
|
||||||
|
QHBoxLayout * pathLyt = new QHBoxLayout(pathFrame);
|
||||||
|
QHBoxLayout * timeLyt = new QHBoxLayout(timeFrame);
|
||||||
|
QLabel * pathLabel_1 = new QLabel(pathFrame);
|
||||||
|
QLabel * pathLabel_2 = new QLabel(pathFrame);
|
||||||
|
pathLabel_1->setText(tr("Path"));
|
||||||
|
pathLabel_2->setText(path);
|
||||||
|
pathLabel_2->setMaximumWidth(500);
|
||||||
|
pathLabel_2->setWordWrap(true);
|
||||||
|
pathLyt->addWidget(pathLabel_1);
|
||||||
|
pathLyt->addStretch();
|
||||||
|
pathLyt->addWidget(pathLabel_2);
|
||||||
|
QLabel * timeLabel_1 = new QLabel(timeFrame);
|
||||||
|
QLabel * timeLabel_2 = new QLabel(timeFrame);
|
||||||
|
timeLabel_1->setText(tr("Last time modified"));
|
||||||
|
QFileInfo fileInfo(path);
|
||||||
|
timeLabel_2->setText(fileInfo.lastModified().toString("yyyy-MM-dd hh:mm:ss"));
|
||||||
|
timeLyt->addWidget(timeLabel_1);
|
||||||
|
timeLyt->addStretch();
|
||||||
|
timeLyt->addWidget(timeLabel_2);
|
||||||
|
detailLyt->addWidget(pathFrame);
|
||||||
|
detailLyt->addWidget(timeFrame);
|
||||||
|
|
||||||
|
QFrame * hLine_2 = new QFrame(this);
|
||||||
|
hLine_2->setLineWidth(0);
|
||||||
|
hLine_2->setFixedHeight(1);
|
||||||
|
hLine_2->setStyleSheet("QFrame{background: rgba(0,0,0,0.2);}");
|
||||||
|
|
||||||
|
m_layout->addWidget(detailFrame);
|
||||||
|
m_layout->addWidget(hLine_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
//可执行操作区域
|
||||||
|
OptionView * optionView = new OptionView(this, type);
|
||||||
|
connect(optionView, &OptionView::onOptionClicked, this, [ = ](const int& option) {
|
||||||
|
execActions(type, option, path);
|
||||||
|
});
|
||||||
|
|
||||||
|
m_layout->addWidget(optionView);
|
||||||
|
m_layout->addStretch();
|
||||||
|
|
||||||
|
//根据不同类型的搜索结果切换加载图片和名称的方式
|
||||||
|
switch (type) {
|
||||||
|
case SearchListView::ResType::App : {
|
||||||
|
QIcon icon = FileUtils::getAppIcon(path);
|
||||||
|
iconLabel->setPixmap(icon.pixmap(icon.actualSize(QSize(96, 96))));
|
||||||
|
nameLabel->setText(FileUtils::getAppName(path));
|
||||||
|
typeLabel->setText(tr("Application"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SearchListView::ResType::Dir :
|
||||||
|
case SearchListView::ResType::File : {
|
||||||
|
QIcon icon = FileUtils::getFileIcon(QString("file://%1").arg(path));
|
||||||
|
iconLabel->setPixmap(icon.pixmap(icon.actualSize(QSize(96, 96))));
|
||||||
|
nameLabel->setText(FileUtils::getFileName(path));
|
||||||
|
typeLabel->setText(tr("Document"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SearchListView::ResType::Setting : {
|
||||||
|
QIcon icon = FileUtils::getSettingIcon(path, true);
|
||||||
|
iconLabel->setPixmap(icon.pixmap(icon.actualSize(QSize(96, 96))));
|
||||||
|
QString settingType = path.mid(path.indexOf("/") + 1, path.lastIndexOf("/") - path.indexOf("/") - 1); //配置项所属控制面板插件名
|
||||||
|
nameLabel->setText(settingType);
|
||||||
|
typeLabel->setText(FileUtils::getSettingName(path));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SearchDetailView::execActions 根据点击的选项执行指定动作
|
||||||
|
* @param type 选中的类型
|
||||||
|
*/
|
||||||
|
void SearchDetailView::execActions(const int& type, const int& option, const QString& path) {
|
||||||
|
switch (option) {
|
||||||
|
case OptionView::Options::Open: {
|
||||||
|
openAction(type, path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OptionView::Options::Shortcut: {
|
||||||
|
addDesktopShortcut(path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OptionView::Options::Panel: {
|
||||||
|
addPanelShortcut(path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OptionView::Options::OpenPath: {
|
||||||
|
openPathAction(path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OptionView::Options::CopyPath: {
|
||||||
|
copyPathAction(path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SearchDetailView::openAction 执行“打开”动作
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool SearchDetailView::openAction(const int& type, const QString& path) {
|
||||||
|
switch (type) {
|
||||||
|
case SearchListView::ResType::App: {
|
||||||
|
GDesktopAppInfo * desktopAppInfo = g_desktop_app_info_new_from_filename(path.toLocal8Bit().data());
|
||||||
|
g_app_info_launch(G_APP_INFO(desktopAppInfo),nullptr, nullptr, nullptr);
|
||||||
|
g_object_unref(desktopAppInfo);
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SearchListView::ResType::Dir:
|
||||||
|
case SearchListView::ResType::File: {
|
||||||
|
QProcess * process = new QProcess;
|
||||||
|
process->start(QString("xdg-open %1").arg(path));
|
||||||
|
connect(process, static_cast<void(QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished), this, [ = ]() {
|
||||||
|
process->deleteLater();
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SearchListView::ResType::Setting: {
|
||||||
|
//打开控制面板对应页面
|
||||||
|
QProcess * process = new QProcess;
|
||||||
|
process->start(QString("ukui-control-center --%1").arg(path.left(path.indexOf("/")).toLower()));
|
||||||
|
connect(process, static_cast<void(QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished), this, [ = ]() {
|
||||||
|
process->deleteLater();
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SearchDetailView::addDesktopShortcut 添加到桌面快捷方式
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool SearchDetailView::addDesktopShortcut(const QString& path) {
|
||||||
|
QString dirpath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||||
|
QFileInfo fileInfo(path);
|
||||||
|
QString desktopfn = fileInfo.fileName();
|
||||||
|
QFile file(path);
|
||||||
|
QString newName = QString(dirpath+"/"+desktopfn);
|
||||||
|
bool ret = file.copy(QString(dirpath+"/"+desktopfn));
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
QProcess * process = new QProcess;
|
||||||
|
process->start(QString("chmod a+x %1").arg(newName));
|
||||||
|
connect(process, static_cast<void(QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished), this, [ = ]() {
|
||||||
|
process->deleteLater();
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SearchDetailView::addPanelShortcut 添加到任务栏
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool SearchDetailView::addPanelShortcut(const QString& path) {
|
||||||
|
QDBusInterface iface("com.ukui.panel.desktop",
|
||||||
|
"/",
|
||||||
|
"com.ukui.panel.desktop",
|
||||||
|
QDBusConnection::sessionBus());
|
||||||
|
if (iface.isValid()) {
|
||||||
|
QDBusReply<bool> isExist = iface.call("CheckIfExist",path);
|
||||||
|
if (isExist) {
|
||||||
|
qDebug()<<"qDebug: Add shortcut to panel failed, because it is already existed!";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QDBusReply<QVariant> ret = iface.call("AddToTaskbar",path);
|
||||||
|
qDebug()<<"qDebug: Add shortcut to panel successed!";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SearchDetailView::openPathAction 打开文件所在路径
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool SearchDetailView::openPathAction(const QString& path) {
|
||||||
|
QProcess * process = new QProcess;
|
||||||
|
process->start(QString("xdg-open %1").arg(path.left(path.lastIndexOf("/"))));
|
||||||
|
connect(process, static_cast<void(QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished), this, [ = ]() {
|
||||||
|
process->deleteLater();
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SearchDetailView::copyPathAction 复制文件所在路径
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool SearchDetailView::copyPathAction(const QString& path) {
|
||||||
|
QClipboard * clipboard = QApplication::clipboard(); //获取系统剪贴板指针
|
||||||
|
clipboard->setText(path);
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef SEARCHDETAILVIEW_H
|
||||||
|
#define SEARCHDETAILVIEW_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include "option-view.h"
|
||||||
|
|
||||||
|
class SearchDetailView : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit SearchDetailView(QWidget *parent = nullptr);
|
||||||
|
~SearchDetailView();
|
||||||
|
|
||||||
|
void setupWidget(const int&, const QString&);
|
||||||
|
void clearLayout();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QVBoxLayout * m_layout = nullptr;
|
||||||
|
|
||||||
|
bool openAction(const int&, const QString&);
|
||||||
|
bool addDesktopShortcut(const QString&);
|
||||||
|
bool addPanelShortcut(const QString&);
|
||||||
|
bool openPathAction(const QString&);
|
||||||
|
bool copyPathAction(const QString&);
|
||||||
|
Q_SIGNALS:
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void execActions(const int&, const int&, const QString&);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SEARCHDETAILVIEW_H
|
|
@ -0,0 +1,88 @@
|
||||||
|
#include "search-list-view.h"
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
SearchListView::SearchListView(QWidget * parent, const QStringList& list, const int& type) : QTreeView(parent)
|
||||||
|
{
|
||||||
|
setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
|
setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
|
m_model = new SearchItemModel;
|
||||||
|
m_item = new SearchItem;
|
||||||
|
m_item->setSearchList(type, list);
|
||||||
|
m_model->setItem(m_item);
|
||||||
|
this->setModel(m_model);
|
||||||
|
this->setHeaderHidden(true);
|
||||||
|
this->setColumnWidth(0, 20);
|
||||||
|
this->setColumnWidth(1, 80);
|
||||||
|
int rowHeight = this->rowHeight(this->model()->index(0,1, QModelIndex())) + 1;
|
||||||
|
this->setFixedHeight(list.count() * rowHeight + 2);
|
||||||
|
this->setAttribute(Qt::WA_TranslucentBackground, true);
|
||||||
|
this->setAutoFillBackground(false);
|
||||||
|
this->setStyleSheet("QWidget{background:transparent;}");
|
||||||
|
|
||||||
|
m_type = type;
|
||||||
|
connect(this->selectionModel(), &QItemSelectionModel::selectionChanged, this, [ = ]() {
|
||||||
|
Q_EMIT this->currentRowChanged(getCurrentType(), m_item->m_pathlist.at(this->currentIndex().row()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchListView::~SearchListView()
|
||||||
|
{
|
||||||
|
if (m_model) {
|
||||||
|
delete m_model;
|
||||||
|
m_model = NULL;
|
||||||
|
}
|
||||||
|
if (m_item) {
|
||||||
|
delete m_item;
|
||||||
|
m_item = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取当前选项所属搜索类型
|
||||||
|
int SearchListView::getCurrentType() {
|
||||||
|
switch (m_type) {
|
||||||
|
case SearchItem::SearchType::Apps :
|
||||||
|
// qDebug()<<"qDebug: One row selected, its type is application.";
|
||||||
|
return ResType::App;
|
||||||
|
case SearchItem::SearchType::Files:
|
||||||
|
// qDebug()<<"qDebug: One row selected, its type is file.";
|
||||||
|
return ResType::File;
|
||||||
|
case SearchItem::SearchType::Settings:
|
||||||
|
// qDebug()<<"qDebug: One row selected, its type is setting.";
|
||||||
|
return ResType::Setting;
|
||||||
|
case SearchItem::SearchType::Dirs:
|
||||||
|
// qDebug()<<"qDebug: One row selected, its type is dir.";
|
||||||
|
return ResType::Dir;
|
||||||
|
default: //All或者Best的情况,需要自己判断文件类型
|
||||||
|
return getResType(m_item->m_pathlist.at(this->currentIndex().row()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SearchListView::getResType 根据路径返回文件类型
|
||||||
|
* @param path 路径
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
int SearchListView::getResType(const QString& path) {
|
||||||
|
if (path.endsWith(".desktop")) {
|
||||||
|
// qDebug()<<"qDebug: One row selected, its path is "<<path<<". Its type is application.";
|
||||||
|
return SearchListView::ResType::App;
|
||||||
|
} else if (QFileInfo(path).isFile()) {
|
||||||
|
// qDebug()<<"qDebug: One row selected, its path is "<<path<<". Its type is file.";
|
||||||
|
return SearchListView::ResType::File;
|
||||||
|
} else if (QFileInfo(path).isDir()) {
|
||||||
|
// qDebug()<<"qDebug: One row selected, its path is "<<path<<". Its type is dir.";
|
||||||
|
return SearchListView::ResType::Dir;
|
||||||
|
} else {
|
||||||
|
// qDebug()<<"qDebug: One row selected, its path is "<<path<<". Its type is setting.";
|
||||||
|
return SearchListView::ResType::Setting;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SearchListView::clearSelection 取消当前选项的选中
|
||||||
|
*/
|
||||||
|
void SearchListView::clearSelection() {
|
||||||
|
this->selectionModel()->clearSelection();
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef SEARCHLISTVIEW_H
|
||||||
|
#define SEARCHLISTVIEW_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTreeView>
|
||||||
|
#include "model/search-item-model.h"
|
||||||
|
#include "model/search-item.h"
|
||||||
|
|
||||||
|
class SearchListView : public QTreeView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit SearchListView(QWidget *, const QStringList&, const int&);
|
||||||
|
~SearchListView();
|
||||||
|
|
||||||
|
enum ResType { //搜索结果可能出现的类型:应用、文件、设置、文件夹
|
||||||
|
App,
|
||||||
|
File,
|
||||||
|
Setting,
|
||||||
|
Dir
|
||||||
|
};
|
||||||
|
|
||||||
|
int getCurrentType();
|
||||||
|
static int getResType(const QString&);
|
||||||
|
|
||||||
|
bool is_current_list = false;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SearchItemModel * m_model = nullptr;
|
||||||
|
SearchItem * m_item = nullptr;
|
||||||
|
|
||||||
|
int m_type;
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void currentRowChanged(const int&, const QString&);
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void clearSelection();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SEARCHLISTVIEW_H
|
|
@ -29,7 +29,7 @@
|
||||||
#include "qt-single-application.h"
|
#include "qt-single-application.h"
|
||||||
#include "qt-local-peer.h"
|
#include "qt-local-peer.h"
|
||||||
//#include "inotify-manager.h"
|
//#include "inotify-manager.h"
|
||||||
#include "../libsearch/index/inotify.h"
|
#include "libsearch.h"
|
||||||
|
|
||||||
void centerToScreen(QWidget* widget) {
|
void centerToScreen(QWidget* widget) {
|
||||||
if (!widget)
|
if (!widget)
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
#include "libsearch.h"
|
#include "libsearch.h"
|
||||||
#include "kwindowsystem.h"
|
#include "kwindowsystem.h"
|
||||||
|
|
||||||
#include "file-utils.h"
|
|
||||||
//#include "inotify-manager.h"
|
//#include "inotify-manager.h"
|
||||||
#include "settings-widget.h"
|
#include "settings-widget.h"
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
INCLUDEPATH += $$PWD
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
$$PWD/search-item-model.h \
|
||||||
|
$$PWD/search-item.h \
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
$$PWD/search-item-model.cpp \
|
||||||
|
$$PWD/search-item.cpp \
|
|
@ -0,0 +1,109 @@
|
||||||
|
#include "search-item-model.h"
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
SearchItemModel::SearchItemModel()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
SearchItemModel::~SearchItemModel(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FileItemModel::index
|
||||||
|
* @param rowa
|
||||||
|
* @param column
|
||||||
|
* @param parent
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
QModelIndex SearchItemModel::index(int row, int column, const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
if (row < 0 || row > m_item->m_pathlist.count()-1)
|
||||||
|
return QModelIndex();
|
||||||
|
return createIndex(row, column, m_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FileItemModel::parent
|
||||||
|
* @param child
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
QModelIndex SearchItemModel::parent(const QModelIndex &child) const
|
||||||
|
{
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SearchItemModel::rowCount 重写的model行数函数
|
||||||
|
* @param index 条目的索引
|
||||||
|
* @return model显示的行数
|
||||||
|
*/
|
||||||
|
int SearchItemModel::rowCount(const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
return index.isValid() ? 0 : m_item->m_pathlist.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SearchItemModel::columnCount 重写的model列数函数
|
||||||
|
* @param index 条目的索引
|
||||||
|
* @return model显示的列数
|
||||||
|
*/
|
||||||
|
int SearchItemModel::columnCount(const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
return index.isValid() ? 0 : 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SearchItemModel::headerData filemodel::columnCount 重写的model标头函数
|
||||||
|
* @param section 列
|
||||||
|
* @param orientation 显示方式
|
||||||
|
* @param role 显示内容类型
|
||||||
|
* @return 标头数据
|
||||||
|
*/
|
||||||
|
//QVariant SearchItemModel::headerData(int section,Qt::Orientation orientation ,int role) const {
|
||||||
|
// return tr("");
|
||||||
|
//// return QAbstractItemModel::headerData(section, orientation, role);
|
||||||
|
//}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SearchItemModel::data model每条条目的数据,有显示内容,图片
|
||||||
|
* @param index 条目索引
|
||||||
|
* @param role 显示内容的类型
|
||||||
|
* @return 显示内容数据
|
||||||
|
*/
|
||||||
|
QVariant SearchItemModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if(!index.isValid())
|
||||||
|
return QVariant();
|
||||||
|
switch (index.column()) {
|
||||||
|
case Icon: {
|
||||||
|
switch (role) {
|
||||||
|
case Qt::DecorationRole: {
|
||||||
|
return m_item->getIcon(index.row());
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case Name: {
|
||||||
|
switch (role) {
|
||||||
|
case Qt::DisplayRole: {
|
||||||
|
return QVariant(m_item->getName(index.row()));
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SearchItemModel::setItem 传入存储数据的item
|
||||||
|
* @param item
|
||||||
|
*/
|
||||||
|
void SearchItemModel::setItem(SearchItem * item) {
|
||||||
|
m_item = item;
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef SEARCHITEMMODEL_H
|
||||||
|
#define SEARCHITEMMODEL_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include "search-item.h"
|
||||||
|
|
||||||
|
class SearchItem;
|
||||||
|
|
||||||
|
class SearchItemModel : public QAbstractItemModel
|
||||||
|
{
|
||||||
|
friend class SearchItem;
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit SearchItemModel();
|
||||||
|
~SearchItemModel();
|
||||||
|
|
||||||
|
enum SearchInfo {
|
||||||
|
Icon,
|
||||||
|
Name
|
||||||
|
};
|
||||||
|
|
||||||
|
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
|
||||||
|
QModelIndex parent(const QModelIndex &child) const override;
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent) const override;
|
||||||
|
int columnCount(const QModelIndex &parent) const override;
|
||||||
|
|
||||||
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
|
// QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||||
|
|
||||||
|
void setItem(SearchItem *);
|
||||||
|
|
||||||
|
private :
|
||||||
|
SearchItem * m_item = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SEARCHITEMMODEL_H
|
|
@ -0,0 +1,82 @@
|
||||||
|
#include "search-item.h"
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
SearchItem::SearchItem(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchItem::~SearchItem()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SearchItem::getIcon 获取一个搜索项的图标
|
||||||
|
* @param index 条目索引
|
||||||
|
* @return 图标
|
||||||
|
*/
|
||||||
|
QIcon SearchItem::getIcon(int index) {
|
||||||
|
if (index < 0 || index >= m_pathlist.count())
|
||||||
|
return QIcon("");
|
||||||
|
switch (m_searchtype) {
|
||||||
|
case Settings : //设置项,返回控制面板对应插件的图标
|
||||||
|
return FileUtils::getSettingIcon(m_pathlist.at(index), false);
|
||||||
|
case Dirs :
|
||||||
|
case Files : //文件,返回文件图标
|
||||||
|
return FileUtils::getFileIcon(QString("file://%1").arg(m_pathlist.at(index)));
|
||||||
|
case Apps : //应用,返回应用图标
|
||||||
|
return FileUtils::getAppIcon(m_pathlist.at(index));
|
||||||
|
case Best : {//最佳匹配,含全部类型,需要自己判断,返回不同类型的图标
|
||||||
|
// return QIcon(":/res/icons/edit-find-symbolic.svg");
|
||||||
|
if (m_pathlist.at(index).endsWith(".desktop")) {
|
||||||
|
return FileUtils::getAppIcon(m_pathlist.at(index));
|
||||||
|
} else if (QFileInfo(m_pathlist.at(index)).isFile() || QFileInfo(m_pathlist.at(index)).isDir()) {
|
||||||
|
return FileUtils::getFileIcon(QString("file://%1").arg(m_pathlist.at(index)));
|
||||||
|
} else {
|
||||||
|
return FileUtils::getSettingIcon(m_pathlist.at(index), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return QIcon(":/res/icons/edit-find-symbolic.svg");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SearchItem::getIcon 获取一个搜索项的名称
|
||||||
|
* @param index 条目索引
|
||||||
|
* @return 名字
|
||||||
|
*/
|
||||||
|
QString SearchItem::getName(int index) {
|
||||||
|
if (index < 0 || index >= m_pathlist.count())
|
||||||
|
return 0;
|
||||||
|
switch (m_searchtype) {
|
||||||
|
case Settings : //设置项,返回功能点名
|
||||||
|
return FileUtils::getSettingName(m_pathlist.at(index));
|
||||||
|
case Dirs :
|
||||||
|
case Files : //文件,返回文件名
|
||||||
|
return FileUtils::getFileName(m_pathlist.at(index));
|
||||||
|
case Apps : //应用,返回应用名
|
||||||
|
return FileUtils::getAppName(m_pathlist.at(index));
|
||||||
|
case Best : //最佳匹配,含全部类型,需要自己判断,返回不同类型的名称
|
||||||
|
// return m_pathlist.at(index);
|
||||||
|
if (m_pathlist.at(index).endsWith(".desktop")) {
|
||||||
|
return FileUtils::getAppName(m_pathlist.at(index));
|
||||||
|
} else if (QFileInfo(m_pathlist.at(index)).isFile() || QFileInfo(m_pathlist.at(index)).isDir()) {
|
||||||
|
return FileUtils::getFileName(m_pathlist.at(index));
|
||||||
|
} else {
|
||||||
|
return FileUtils::getSettingName(m_pathlist.at(index));
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return m_pathlist.at(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SearchItem::setSearchList 存入搜索结果列表
|
||||||
|
* @param type 搜索类型
|
||||||
|
* @param searchResult 搜索结果
|
||||||
|
*/
|
||||||
|
void SearchItem::setSearchList(const int& type, const QStringList& searchResult) {
|
||||||
|
m_searchtype = type;
|
||||||
|
m_pathlist = searchResult;
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef SEARCHITEM_H
|
||||||
|
#define SEARCHITEM_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include "search-item-model.h"
|
||||||
|
#include "file-utils.h"
|
||||||
|
|
||||||
|
class SearchItem : public QObject
|
||||||
|
{
|
||||||
|
friend class SearchItemModel;
|
||||||
|
friend class SearchListView;
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit SearchItem(QObject *parent = nullptr);
|
||||||
|
~SearchItem();
|
||||||
|
|
||||||
|
enum SearchType {
|
||||||
|
All,
|
||||||
|
Apps,
|
||||||
|
Settings,
|
||||||
|
Files,
|
||||||
|
Dirs,
|
||||||
|
Best
|
||||||
|
};
|
||||||
|
|
||||||
|
void setSearchList(const int&, const QStringList&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// SearchItem * m_parent = nullptr;
|
||||||
|
// QVector<SearchItem*> * m_children = nullptr;
|
||||||
|
|
||||||
|
int m_searchtype = 0;
|
||||||
|
QStringList m_pathlist;
|
||||||
|
|
||||||
|
QIcon getIcon(int);
|
||||||
|
QString getName(int);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SEARCHITEM_H
|
|
@ -0,0 +1 @@
|
||||||
|
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{opacity:0.85;}</style></defs><title>close</title><path class="cls-1" d="M8.71,8l5.14-5.15a.49.49,0,0,0-.7-.7L8,7.29,2.85,2.15a.49.49,0,0,0-.7.7L7.29,8,2.15,13.15a.48.48,0,0,0,0,.7.48.48,0,0,0,.7,0L8,8.71l5.15,5.14a.48.48,0,0,0,.7,0,.48.48,0,0,0,0-.7Z"/></svg>
|
After Width: | Height: | Size: 374 B |
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="最近文件" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
|
||||||
|
y="0px" viewBox="0 0 19 19" style="enable-background:new 0 0 19 19;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<path class="st0" d="M7,2c0.6,0,1,0.4,1,1v4c0,0.6-0.4,1-1,1H3C2.4,8,2,7.6,2,7V3c0-0.6,0.4-1,1-1H7 M7,1H3C1.9,1,1,1.9,1,3v4
|
||||||
|
c0,1.1,0.9,2,2,2h4c1.1,0,2-0.9,2-2V3C9,1.9,8.1,1,7,1L7,1z"/>
|
||||||
|
<path class="st0" d="M16,2c0.6,0,1,0.4,1,1v4c0,0.6-0.4,1-1,1h-4c-0.6,0-1-0.4-1-1V3c0-0.6,0.4-1,1-1H16 M16,1h-4c-1.1,0-2,0.9-2,2
|
||||||
|
v4c0,1.1,0.9,2,2,2h4c1.1,0,2-0.9,2-2V3C18,1.9,17.1,1,16,1L16,1z"/>
|
||||||
|
<path class="st0" d="M7,11c0.6,0,1,0.4,1,1v4c0,0.6-0.4,1-1,1H3c-0.6,0-1-0.4-1-1v-4c0-0.6,0.4-1,1-1H7 M7,10H3c-1.1,0-2,0.9-2,2v4
|
||||||
|
c0,1.1,0.9,2,2,2h4c1.1,0,2-0.9,2-2v-4C9,10.9,8.1,10,7,10L7,10z"/>
|
||||||
|
<path class="st0" d="M16,11c0.6,0,1,0.4,1,1v4c0,0.6-0.4,1-1,1h-4c-0.6,0-1-0.4-1-1v-4c0-0.6,0.4-1,1-1H16 M16,10h-4
|
||||||
|
c-1.1,0-2,0.9-2,2v4c0,1.1,0.9,2,2,2h4c1.1,0,2-0.9,2-2v-4C18,10.9,17.1,10,16,10L16,10z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 998 B |
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<title>edit-find-symbolic</title>
|
||||||
|
<g id="Icon" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="Icon-Sets" transform="translate(-68.000000, -2529.000000)" fill-rule="nonzero">
|
||||||
|
<g id="编组-9" transform="translate(0.000000, 2399.000000)">
|
||||||
|
<g id="编组" transform="translate(68.000000, 130.000000)">
|
||||||
|
<polygon id="矩形备份" fill="#000000" opacity="0" points="0 0 16 0 16 16 0 16"/>
|
||||||
|
<path d="M6.86630772,1 C8.48762671,1 9.95614366,1.64816049 11.0189488,2.69780957 C12.0771269,3.74288891 12.7327736,5.18634211 12.7327736,6.78146875 C12.7327736,8.28192337 12.1523076,9.64806734 11.2023613,10.6749557 L11.2023613,10.6749557 L14.9869478,14.4127374 L10.6532367,11.3057557 C9.58274699,12.0665702 8.28388099,12.5629531 6.86630772,12.5629531 C5.2449219,12.5629531 3.77647181,11.9148388 2.71373977,10.8652353 C1.65557494,9.82014255 1,8.37664384 1,6.78146875 C1,5.18630217 1.65557811,3.74280894 2.71374274,2.69771882 C3.77647668,1.64811584 5.24492743,1 6.86630772,1 Z" id="路径" stroke="#2FB3E8" stroke-width="2"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -0,0 +1,567 @@
|
||||||
|
|
||||||
|
<plugins>
|
||||||
|
<plugin name="About">
|
||||||
|
<pinyinPlugin>guanyu</pinyinPlugin>
|
||||||
|
<pinyinfunc>banben</pinyinfunc>
|
||||||
|
<ChinesePlugin>关于</ChinesePlugin>
|
||||||
|
<ChineseFunc>版本</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="About">
|
||||||
|
<pinyinPlugin>guanyu</pinyinPlugin>
|
||||||
|
<pinyinfunc>neihe</pinyinfunc>
|
||||||
|
<ChinesePlugin>关于</ChinesePlugin>
|
||||||
|
<ChineseFunc>内核</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="About">
|
||||||
|
<ChinesePlugin>关于</ChinesePlugin>
|
||||||
|
<ChineseFunc>CPU</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="About">
|
||||||
|
<pinyinPlugin>guanyu</pinyinPlugin>
|
||||||
|
<pinyinfunc>neicun</pinyinfunc>
|
||||||
|
<ChinesePlugin>关于</ChinesePlugin>
|
||||||
|
<ChineseFunc>内存</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="About">
|
||||||
|
<pinyinPlugin>guanyu</pinyinPlugin>
|
||||||
|
<pinyinfunc>yingpan</pinyinfunc>
|
||||||
|
<ChinesePlugin>关于</ChinesePlugin>
|
||||||
|
<ChineseFunc>硬盘</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Area">
|
||||||
|
<pinyinPlugin>yuyanhediqu</pinyinPlugin>
|
||||||
|
<pinyinfunc>dangqianquyu</pinyinfunc>
|
||||||
|
<ChinesePlugin>语言和地区</ChinesePlugin>
|
||||||
|
<ChineseFunc>当前区域</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Area">
|
||||||
|
<pinyinPlugin>yuyanhediqu</pinyinPlugin>
|
||||||
|
<pinyinfunc>quyugeshishuju</pinyinfunc>
|
||||||
|
<ChinesePlugin>语言和地区</ChinesePlugin>
|
||||||
|
<ChineseFunc>区域格式数据</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Area">
|
||||||
|
<pinyinPlugin>yuyanhediqu</pinyinPlugin>
|
||||||
|
<pinyinfunc>shouxuanyuyan</pinyinfunc>
|
||||||
|
<ChinesePlugin>语言和地区</ChinesePlugin>
|
||||||
|
<ChineseFunc>首选语言</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Autoboot">
|
||||||
|
<pinyinPlugin>kaijiqidong</pinyinPlugin>
|
||||||
|
<pinyinfunc>morenchengxu</pinyinfunc>
|
||||||
|
<ChinesePlugin>开机启动</ChinesePlugin>
|
||||||
|
<ChineseFunc>默认程序</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Backup">
|
||||||
|
<pinyinPlugin>huifuchuchangshezhi</pinyinPlugin>
|
||||||
|
<pinyinfunc>huanyuan</pinyinfunc>
|
||||||
|
<ChinesePlugin>恢复出厂设置</ChinesePlugin>
|
||||||
|
<ChineseFunc>还原</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Datetime">
|
||||||
|
<pinyinPlugin>shijianheriqi</pinyinPlugin>
|
||||||
|
<pinyinfunc>tongbuxitongshijian</pinyinfunc>
|
||||||
|
<ChinesePlugin>时间和日期</ChinesePlugin>
|
||||||
|
<ChineseFunc>同步系统时间</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Datetime">
|
||||||
|
<pinyinPlugin>shijianheriqi</pinyinPlugin>
|
||||||
|
<pinyinfunc>shoudonggenggaishijian</pinyinfunc>
|
||||||
|
<ChinesePlugin>时间和日期</ChinesePlugin>
|
||||||
|
<ChineseFunc>手动更改时间</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Datetime">
|
||||||
|
<pinyinPlugin>shijianheriqi</pinyinPlugin>
|
||||||
|
<pinyinfunc>genggaishiqu</pinyinfunc>
|
||||||
|
<ChinesePlugin>时间和日期</ChinesePlugin>
|
||||||
|
<ChineseFunc>更改时区</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Datetime">
|
||||||
|
<pinyinPlugin>shijianheriqi</pinyinPlugin>
|
||||||
|
<pinyinfunc>xiaoshizhi</pinyinfunc>
|
||||||
|
<ChinesePlugin>时间和日期</ChinesePlugin>
|
||||||
|
<ChineseFunc>24小时制</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Defaultapp">
|
||||||
|
<pinyinPlugin>morenyingyong</pinyinPlugin>
|
||||||
|
<pinyinfunc>liulanqi</pinyinfunc>
|
||||||
|
<ChinesePlugin>默认应用</ChinesePlugin>
|
||||||
|
<ChineseFunc>浏览器</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Defaultapp">
|
||||||
|
<pinyinPlugin>morenyingyong</pinyinPlugin>
|
||||||
|
<pinyinfunc>dianziyoujian</pinyinfunc>
|
||||||
|
<ChinesePlugin>默认应用</ChinesePlugin>
|
||||||
|
<ChineseFunc>电子邮件</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Defaultapp">
|
||||||
|
<pinyinPlugin>morenyingyong</pinyinPlugin>
|
||||||
|
<pinyinfunc>tuxiangchakanqi</pinyinfunc>
|
||||||
|
<ChinesePlugin>默认应用</ChinesePlugin>
|
||||||
|
<ChineseFunc>图像查看器</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Defaultapp">
|
||||||
|
<pinyinPlugin>morenyingyong</pinyinPlugin>
|
||||||
|
<pinyinfunc>yinpinbofangqi</pinyinfunc>
|
||||||
|
<ChinesePlugin>默认应用</ChinesePlugin>
|
||||||
|
<ChineseFunc>音频播放器</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Defaultapp">
|
||||||
|
<pinyinPlugin>morenyingyong</pinyinPlugin>
|
||||||
|
<pinyinfunc>shipinbofangqi</pinyinfunc>
|
||||||
|
<ChinesePlugin>默认应用</ChinesePlugin>
|
||||||
|
<ChineseFunc>视频播放器</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Defaultapp">
|
||||||
|
<pinyinPlugin>morenyingyong</pinyinPlugin>
|
||||||
|
<pinyinfunc>wendangbianjiqi</pinyinfunc>
|
||||||
|
<ChinesePlugin>默认应用</ChinesePlugin>
|
||||||
|
<ChineseFunc>文档编辑器</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Desktop">
|
||||||
|
<pinyinPlugin>zhuomian</pinyinPlugin>
|
||||||
|
<pinyinfunc>xianshizaizhuomiandetubiao</pinyinfunc>
|
||||||
|
<ChinesePlugin>桌面</ChinesePlugin>
|
||||||
|
<ChineseFunc>显示在桌面的图标</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Desktop">
|
||||||
|
<pinyinPlugin>zhuomian</pinyinPlugin>
|
||||||
|
<pinyinfunc>xianshizaituopanshangdetubiao</pinyinfunc>
|
||||||
|
<ChinesePlugin>桌面</ChinesePlugin>
|
||||||
|
<ChineseFunc>显示在托盘上的图标</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Fonts">
|
||||||
|
<pinyinPlugin>ziti</pinyinPlugin>
|
||||||
|
<pinyinfunc>zitidaxiao</pinyinfunc>
|
||||||
|
<ChinesePlugin>字体</ChinesePlugin>
|
||||||
|
<ChineseFunc>字体大小</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Keyboard">
|
||||||
|
<pinyinPlugin>jianpan</pinyinPlugin>
|
||||||
|
<pinyinfunc>qiyonganjianzhongfushezhi</pinyinfunc>
|
||||||
|
<ChinesePlugin>键盘</ChinesePlugin>
|
||||||
|
<ChineseFunc>启用按键重复设置</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Keyboard">
|
||||||
|
<pinyinPlugin>jianpan</pinyinPlugin>
|
||||||
|
<pinyinfunc>yanchi</pinyinfunc>
|
||||||
|
<ChinesePlugin>键盘</ChinesePlugin>
|
||||||
|
<ChineseFunc>延迟</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Keyboard">
|
||||||
|
<pinyinPlugin>jianpan</pinyinPlugin>
|
||||||
|
<pinyinfunc>sudu</pinyinfunc>
|
||||||
|
<ChinesePlugin>键盘</ChinesePlugin>
|
||||||
|
<ChineseFunc>速度</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Keyboard">
|
||||||
|
<pinyinPlugin>jianpan</pinyinPlugin>
|
||||||
|
<pinyinfunc>shuruzifuceshizhongfuxiaoguoï¼</pinyinfunc>
|
||||||
|
<ChinesePlugin>键盘</ChinesePlugin>
|
||||||
|
<ChineseFunc>输入字符测试重复效果:</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Keyboard">
|
||||||
|
<pinyinPlugin>jianpan</pinyinPlugin>
|
||||||
|
<pinyinfunc>daxiesuodingtishi</pinyinfunc>
|
||||||
|
<ChinesePlugin>键盘</ChinesePlugin>
|
||||||
|
<ChineseFunc>大写锁定提示</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Keyboard">
|
||||||
|
<pinyinPlugin>jianpan</pinyinPlugin>
|
||||||
|
<pinyinfunc>huifumorenbuju</pinyinfunc>
|
||||||
|
<ChinesePlugin>键盘</ChinesePlugin>
|
||||||
|
<ChineseFunc>恢复默认布局</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Keyboard">
|
||||||
|
<pinyinPlugin>jianpan</pinyinPlugin>
|
||||||
|
<pinyinfunc>jianpanbuju</pinyinfunc>
|
||||||
|
<ChinesePlugin>键盘</ChinesePlugin>
|
||||||
|
<ChineseFunc>键盘布局</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Mouse">
|
||||||
|
<pinyinPlugin>shubiao</pinyinPlugin>
|
||||||
|
<pinyinfunc>guanyongshou</pinyinfunc>
|
||||||
|
<ChinesePlugin>鼠标</ChinesePlugin>
|
||||||
|
<ChineseFunc>惯用手</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Mouse">
|
||||||
|
<pinyinPlugin>shubiao</pinyinPlugin>
|
||||||
|
<pinyinfunc>sudu</pinyinfunc>
|
||||||
|
<ChinesePlugin>鼠标</ChinesePlugin>
|
||||||
|
<ChineseFunc>速度</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Mouse">
|
||||||
|
<pinyinPlugin>shubiao</pinyinPlugin>
|
||||||
|
<pinyinfunc>shubiaoshuangjijiangeshichang</pinyinfunc>
|
||||||
|
<ChinesePlugin>鼠标</ChinesePlugin>
|
||||||
|
<ChineseFunc>鼠标双击间隔时长</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Mouse">
|
||||||
|
<pinyinPlugin>shubiao</pinyinPlugin>
|
||||||
|
<pinyinfunc>mingandu</pinyinfunc>
|
||||||
|
<ChinesePlugin>鼠标</ChinesePlugin>
|
||||||
|
<ChineseFunc>敏感度</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Mouse">
|
||||||
|
<pinyinPlugin>shubiao</pinyinPlugin>
|
||||||
|
<pinyinfunc>kejianxing</pinyinfunc>
|
||||||
|
<ChinesePlugin>鼠标</ChinesePlugin>
|
||||||
|
<ChineseFunc>可见性</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Mouse">
|
||||||
|
<pinyinPlugin>shubiao</pinyinPlugin>
|
||||||
|
<pinyinfunc>zhizhendaxiao</pinyinfunc>
|
||||||
|
<ChinesePlugin>鼠标</ChinesePlugin>
|
||||||
|
<ChineseFunc>指针大小</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Mouse">
|
||||||
|
<pinyinPlugin>shubiao</pinyinPlugin>
|
||||||
|
<pinyinfunc>guangbiaosudu</pinyinfunc>
|
||||||
|
<ChinesePlugin>鼠标</ChinesePlugin>
|
||||||
|
<ChineseFunc>光标速度</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Mouse">
|
||||||
|
<pinyinPlugin>shubiao</pinyinPlugin>
|
||||||
|
<pinyinfunc>qiyongwenbenquyudeguangbiaoshanshuo</pinyinfunc>
|
||||||
|
<ChinesePlugin>鼠标</ChinesePlugin>
|
||||||
|
<ChineseFunc>启用文本区域的光标闪烁</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Netconnect">
|
||||||
|
<pinyinPlugin>wangluolianjie</pinyinPlugin>
|
||||||
|
<pinyinfunc>wangluozhuangtai</pinyinfunc>
|
||||||
|
<ChinesePlugin>网络连接</ChinesePlugin>
|
||||||
|
<ChineseFunc>网络状态</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Netconnect">
|
||||||
|
<ChinesePlugin>网络连接</ChinesePlugin>
|
||||||
|
<ChineseFunc>打开wifi</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Notice">
|
||||||
|
<pinyinPlugin>tongzhi</pinyinPlugin>
|
||||||
|
<pinyinfunc>shezhizaitongzhizhongxinxianshidetongzhixinxi</pinyinfunc>
|
||||||
|
<ChinesePlugin>通知</ChinesePlugin>
|
||||||
|
<ChineseFunc>设置在通知中心显示的通知信息</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Notice">
|
||||||
|
<pinyinPlugin>tongzhi</pinyinPlugin>
|
||||||
|
<pinyinfunc>shezhitongzhilaiyuan</pinyinfunc>
|
||||||
|
<ChinesePlugin>通知</ChinesePlugin>
|
||||||
|
<ChineseFunc>设置通知来源</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Display">
|
||||||
|
<pinyinPlugin>xianshiqi</pinyinPlugin>
|
||||||
|
<pinyinfunc>fenbianlv</pinyinfunc>
|
||||||
|
<ChinesePlugin>显示器</ChinesePlugin>
|
||||||
|
<ChineseFunc>分辨率</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Display">
|
||||||
|
<pinyinPlugin>xianshiqi</pinyinPlugin>
|
||||||
|
<pinyinfunc>suofangpingmu</pinyinfunc>
|
||||||
|
<ChinesePlugin>显示器</ChinesePlugin>
|
||||||
|
<ChineseFunc>缩放屏幕</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Power">
|
||||||
|
<pinyinPlugin>dianyuan</pinyinPlugin>
|
||||||
|
<pinyinfunc>pinghengï¼tuijianï¼</pinyinfunc>
|
||||||
|
<ChinesePlugin>电源</ChinesePlugin>
|
||||||
|
<ChineseFunc>平衡(推荐)</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Power">
|
||||||
|
<pinyinPlugin>dianyuan</pinyinPlugin>
|
||||||
|
<pinyinfunc>jieneng</pinyinfunc>
|
||||||
|
<ChinesePlugin>电源</ChinesePlugin>
|
||||||
|
<ChineseFunc>节能</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Power">
|
||||||
|
<pinyinPlugin>dianyuan</pinyinPlugin>
|
||||||
|
<pinyinfunc>zidingyi</pinyinfunc>
|
||||||
|
<ChinesePlugin>电源</ChinesePlugin>
|
||||||
|
<ChineseFunc>自定义</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Printer">
|
||||||
|
<pinyinPlugin>dayinji</pinyinPlugin>
|
||||||
|
<pinyinfunc>tianjiadayinjihesaomiaoyi</pinyinfunc>
|
||||||
|
<ChinesePlugin>打印机</ChinesePlugin>
|
||||||
|
<ChineseFunc>添加打印机和扫描仪</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Printer">
|
||||||
|
<pinyinPlugin>dayinji</pinyinPlugin>
|
||||||
|
<pinyinfunc>tianjiadayinjihesaomiaoyi</pinyinfunc>
|
||||||
|
<ChinesePlugin>打印机</ChinesePlugin>
|
||||||
|
<ChineseFunc>添加打印机和扫描仪</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Proxy">
|
||||||
|
<pinyinPlugin>daili</pinyinPlugin>
|
||||||
|
<pinyinfunc>kaiqizidongdaili</pinyinfunc>
|
||||||
|
<ChinesePlugin>代理</ChinesePlugin>
|
||||||
|
<ChineseFunc>开启自动代理</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Proxy">
|
||||||
|
<pinyinPlugin>daili</pinyinPlugin>
|
||||||
|
<pinyinfunc>kaiqishoudongdaili</pinyinfunc>
|
||||||
|
<ChinesePlugin>代理</ChinesePlugin>
|
||||||
|
<ChineseFunc>开启手动代理</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Screenlock">
|
||||||
|
<pinyinPlugin>suoping</pinyinPlugin>
|
||||||
|
<pinyinfunc>suopingshixianshiweiduxiaoxishu</pinyinfunc>
|
||||||
|
<ChinesePlugin>锁屏</ChinesePlugin>
|
||||||
|
<ChineseFunc>锁屏时显示未读消息数</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Screenlock">
|
||||||
|
<pinyinPlugin>suoping</pinyinPlugin>
|
||||||
|
<pinyinfunc>jihuopingbaoshisuodingpingmu</pinyinfunc>
|
||||||
|
<ChinesePlugin>锁屏</ChinesePlugin>
|
||||||
|
<ChineseFunc>激活屏保时锁定屏幕</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Screenlock">
|
||||||
|
<pinyinPlugin>suoping</pinyinPlugin>
|
||||||
|
<pinyinfunc>xianshisuopingbizhizaidengluyemian</pinyinfunc>
|
||||||
|
<ChinesePlugin>锁屏</ChinesePlugin>
|
||||||
|
<ChineseFunc>显示锁屏壁纸在登录页面</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Screensaver">
|
||||||
|
<pinyinPlugin>pingbao</pinyinPlugin>
|
||||||
|
<pinyinfunc>kaiqipingbao</pinyinfunc>
|
||||||
|
<ChinesePlugin>屏保</ChinesePlugin>
|
||||||
|
<ChineseFunc>开启屏保</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Screensaver">
|
||||||
|
<pinyinPlugin>pingbao</pinyinPlugin>
|
||||||
|
<pinyinfunc>pingmubaohuchengxu</pinyinfunc>
|
||||||
|
<ChinesePlugin>屏保</ChinesePlugin>
|
||||||
|
<ChineseFunc>屏幕保护程序</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Screensaver">
|
||||||
|
<pinyinPlugin>pingbao</pinyinPlugin>
|
||||||
|
<pinyinfunc>dengdaishijian</pinyinfunc>
|
||||||
|
<ChinesePlugin>屏保</ChinesePlugin>
|
||||||
|
<ChineseFunc>等待时间</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Shortcut">
|
||||||
|
<pinyinPlugin>kuaijiejian</pinyinPlugin>
|
||||||
|
<pinyinfunc>xitongkuaijiejian</pinyinfunc>
|
||||||
|
<ChinesePlugin>快捷键</ChinesePlugin>
|
||||||
|
<ChineseFunc>系统快捷键</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Shortcut">
|
||||||
|
<pinyinPlugin>kuaijiejian</pinyinPlugin>
|
||||||
|
<pinyinfunc>zidingyikuaijiejian</pinyinfunc>
|
||||||
|
<ChinesePlugin>快捷键</ChinesePlugin>
|
||||||
|
<ChineseFunc>自定义快捷键</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Shortcut">
|
||||||
|
<pinyinPlugin>kuaijiejian</pinyinPlugin>
|
||||||
|
<pinyinfunc>tianjiazidingyikuaijiejian</pinyinfunc>
|
||||||
|
<ChinesePlugin>快捷键</ChinesePlugin>
|
||||||
|
<ChineseFunc>添加自定义快捷键</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Theme">
|
||||||
|
<pinyinPlugin>zhuti</pinyinPlugin>
|
||||||
|
<pinyinfunc>zhutimoshi</pinyinfunc>
|
||||||
|
<ChinesePlugin>主题</ChinesePlugin>
|
||||||
|
<ChineseFunc>主题模式</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Theme">
|
||||||
|
<pinyinPlugin>zhuti</pinyinPlugin>
|
||||||
|
<pinyinfunc>xitong</pinyinfunc>
|
||||||
|
<ChinesePlugin>主题</ChinesePlugin>
|
||||||
|
<ChineseFunc>系统</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Theme">
|
||||||
|
<pinyinPlugin>zhuti</pinyinPlugin>
|
||||||
|
<pinyinfunc>qianse</pinyinfunc>
|
||||||
|
<ChinesePlugin>主题</ChinesePlugin>
|
||||||
|
<ChineseFunc>浅色</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Theme">
|
||||||
|
<pinyinPlugin>zhuti</pinyinPlugin>
|
||||||
|
<pinyinfunc>toumingxiaoguo</pinyinfunc>
|
||||||
|
<ChinesePlugin>主题</ChinesePlugin>
|
||||||
|
<ChineseFunc>透明效果</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Theme">
|
||||||
|
<pinyinPlugin>zhuti</pinyinPlugin>
|
||||||
|
<pinyinfunc>shense</pinyinfunc>
|
||||||
|
<ChinesePlugin>主题</ChinesePlugin>
|
||||||
|
<ChineseFunc>深色</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Theme">
|
||||||
|
<pinyinPlugin>zhuti</pinyinPlugin>
|
||||||
|
<pinyinfunc>tubiaozhuti</pinyinfunc>
|
||||||
|
<ChinesePlugin>主题</ChinesePlugin>
|
||||||
|
<ChineseFunc>图标主题</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Theme">
|
||||||
|
<pinyinPlugin>zhuti</pinyinPlugin>
|
||||||
|
<pinyinfunc>guangbiaozhuti</pinyinfunc>
|
||||||
|
<ChinesePlugin>主题</ChinesePlugin>
|
||||||
|
<ChineseFunc>光标主题</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Theme">
|
||||||
|
<pinyinPlugin>zhuti</pinyinPlugin>
|
||||||
|
<pinyinfunc>toumingdu</pinyinfunc>
|
||||||
|
<ChinesePlugin>主题</ChinesePlugin>
|
||||||
|
<ChineseFunc>透明度</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Theme">
|
||||||
|
<pinyinPlugin>zhuti</pinyinPlugin>
|
||||||
|
<pinyinfunc>di</pinyinfunc>
|
||||||
|
<ChinesePlugin>主题</ChinesePlugin>
|
||||||
|
<ChineseFunc>低</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Theme">
|
||||||
|
<pinyinPlugin>zhuti</pinyinPlugin>
|
||||||
|
<pinyinfunc>gao</pinyinfunc>
|
||||||
|
<ChinesePlugin>主题</ChinesePlugin>
|
||||||
|
<ChineseFunc>高</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Touchpad">
|
||||||
|
<pinyinPlugin>chumoban</pinyinPlugin>
|
||||||
|
<pinyinfunc>chumobanshezhi</pinyinfunc>
|
||||||
|
<ChinesePlugin>触摸板</ChinesePlugin>
|
||||||
|
<ChineseFunc>触摸板设置</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Audio">
|
||||||
|
<pinyinPlugin>shengyin</pinyinPlugin>
|
||||||
|
<pinyinfunc>xuanzeshurushebei</pinyinfunc>
|
||||||
|
<ChinesePlugin>声音</ChinesePlugin>
|
||||||
|
<ChineseFunc>选择输入设备</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Audio">
|
||||||
|
<pinyinPlugin>shengyin</pinyinPlugin>
|
||||||
|
<pinyinfunc>yinliangdaxiao</pinyinfunc>
|
||||||
|
<ChinesePlugin>声音</ChinesePlugin>
|
||||||
|
<ChineseFunc>音量大小</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Audio">
|
||||||
|
<pinyinPlugin>shengyin</pinyinPlugin>
|
||||||
|
<pinyinfunc>shurudengji</pinyinfunc>
|
||||||
|
<ChinesePlugin>声音</ChinesePlugin>
|
||||||
|
<ChineseFunc>输入等级</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Audio">
|
||||||
|
<pinyinPlugin>shengyin</pinyinPlugin>
|
||||||
|
<pinyinfunc>xuanzeshuchushebei</pinyinfunc>
|
||||||
|
<ChinesePlugin>声音</ChinesePlugin>
|
||||||
|
<ChineseFunc>选择输出设备</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Audio">
|
||||||
|
<pinyinPlugin>shengyin</pinyinPlugin>
|
||||||
|
<pinyinfunc>zhuyinliangdaxiao</pinyinfunc>
|
||||||
|
<ChinesePlugin>声音</ChinesePlugin>
|
||||||
|
<ChineseFunc>主音量大小</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Audio">
|
||||||
|
<pinyinPlugin>shengyin</pinyinPlugin>
|
||||||
|
<pinyinfunc>shengdaopingheng</pinyinfunc>
|
||||||
|
<ChinesePlugin>声音</ChinesePlugin>
|
||||||
|
<ChineseFunc>声道平衡</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Audio">
|
||||||
|
<pinyinPlugin>shengyin</pinyinPlugin>
|
||||||
|
<pinyinfunc>peizhi</pinyinfunc>
|
||||||
|
<ChinesePlugin>声音</ChinesePlugin>
|
||||||
|
<ChineseFunc>配置</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Audio">
|
||||||
|
<pinyinPlugin>shengyin</pinyinPlugin>
|
||||||
|
<pinyinfunc>shengqia</pinyinfunc>
|
||||||
|
<ChinesePlugin>声音</ChinesePlugin>
|
||||||
|
<ChineseFunc>声卡</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Audio">
|
||||||
|
<pinyinPlugin>shengyin</pinyinPlugin>
|
||||||
|
<pinyinfunc>xitongyinxiao</pinyinfunc>
|
||||||
|
<ChinesePlugin>声音</ChinesePlugin>
|
||||||
|
<ChineseFunc>系统音效</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Audio">
|
||||||
|
<pinyinPlugin>shengyin</pinyinPlugin>
|
||||||
|
<pinyinfunc>xitongyinxiaozhuti</pinyinfunc>
|
||||||
|
<ChinesePlugin>声音</ChinesePlugin>
|
||||||
|
<ChineseFunc>系统音效主题</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Audio">
|
||||||
|
<pinyinPlugin>shengyin</pinyinPlugin>
|
||||||
|
<pinyinfunc>tishiyin</pinyinfunc>
|
||||||
|
<ChinesePlugin>声音</ChinesePlugin>
|
||||||
|
<ChineseFunc>提示音</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Audio">
|
||||||
|
<pinyinPlugin>shengyin</pinyinPlugin>
|
||||||
|
<pinyinfunc>kaiguanjiyinle</pinyinfunc>
|
||||||
|
<ChinesePlugin>声音</ChinesePlugin>
|
||||||
|
<ChineseFunc>开关机音乐</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Audio">
|
||||||
|
<pinyinPlugin>shengyin</pinyinPlugin>
|
||||||
|
<pinyinfunc>tishiyinliangkaiguan</pinyinfunc>
|
||||||
|
<ChinesePlugin>声音</ChinesePlugin>
|
||||||
|
<ChineseFunc>提示音量开关</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Display">
|
||||||
|
<pinyinPlugin>xianshiqi</pinyinPlugin>
|
||||||
|
<pinyinfunc>suofangpingmu</pinyinfunc>
|
||||||
|
<ChinesePlugin>显示器</ChinesePlugin>
|
||||||
|
<ChineseFunc>缩放屏幕</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Update">
|
||||||
|
<pinyinPlugin>gengxin</pinyinPlugin>
|
||||||
|
<pinyinfunc>xitonggengxin</pinyinfunc>
|
||||||
|
<ChinesePlugin>更新</ChinesePlugin>
|
||||||
|
<ChineseFunc>系统更新</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Userinfo">
|
||||||
|
<pinyinPlugin>zhanghuxinxi</pinyinPlugin>
|
||||||
|
<pinyinfunc>mimashixiao</pinyinfunc>
|
||||||
|
<ChinesePlugin>账户信息</ChinesePlugin>
|
||||||
|
<ChineseFunc>密码时效</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Userinfo">
|
||||||
|
<pinyinPlugin>zhanghuxinxi</pinyinPlugin>
|
||||||
|
<pinyinfunc>mianmidenglu</pinyinfunc>
|
||||||
|
<ChinesePlugin>账户信息</ChinesePlugin>
|
||||||
|
<ChineseFunc>免密登录</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Userinfo">
|
||||||
|
<pinyinPlugin>zhanghuxinxi</pinyinPlugin>
|
||||||
|
<pinyinfunc>zidongdenglu</pinyinfunc>
|
||||||
|
<ChinesePlugin>账户信息</ChinesePlugin>
|
||||||
|
<ChineseFunc>自动登录</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Vpn">
|
||||||
|
<ChinesePlugin>VPN</ChinesePlugin>
|
||||||
|
<ChineseFunc>添加VPN连接</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Wallpaper">
|
||||||
|
<pinyinPlugin>beijing</pinyinPlugin>
|
||||||
|
<pinyinfunc>liulanbendibizhi</pinyinfunc>
|
||||||
|
<ChinesePlugin>背景</ChinesePlugin>
|
||||||
|
<ChineseFunc>浏览本地壁纸</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Wallpaper">
|
||||||
|
<pinyinPlugin>beijing</pinyinPlugin>
|
||||||
|
<pinyinfunc>huifumorenshezhi</pinyinfunc>
|
||||||
|
<ChinesePlugin>背景</ChinesePlugin>
|
||||||
|
<ChineseFunc>恢复默认设置</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Wallpaper">
|
||||||
|
<pinyinPlugin>beijing</pinyinPlugin>
|
||||||
|
<pinyinfunc>liulanxianshangbizhi</pinyinfunc>
|
||||||
|
<ChinesePlugin>背景</ChinesePlugin>
|
||||||
|
<ChineseFunc>浏览线上壁纸</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Display">
|
||||||
|
<pinyinPlugin>xianshiqi</pinyinPlugin>
|
||||||
|
<pinyinfunc>tongyishuchu</pinyinfunc>
|
||||||
|
<ChinesePlugin>显示器</ChinesePlugin>
|
||||||
|
<ChineseFunc>统一输出</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
<plugin name="Display">
|
||||||
|
<pinyinPlugin>xianshiqi</pinyinPlugin>
|
||||||
|
<pinyinfunc>yejianmoshi</pinyinfunc>
|
||||||
|
<ChinesePlugin>显示器</ChinesePlugin>
|
||||||
|
<ChineseFunc>夜间模式</ChineseFunc>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
|
@ -0,0 +1,89 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE TS>
|
||||||
|
<TS version="2.1">
|
||||||
|
<context>
|
||||||
|
<name>ContentWidget</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/content-widget.cpp" line="121"/>
|
||||||
|
<source>Apps</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/content-widget.cpp" line="123"/>
|
||||||
|
<source>Settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/content-widget.cpp" line="125"/>
|
||||||
|
<source>Files</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/content-widget.cpp" line="127"/>
|
||||||
|
<source>Best Matches</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/content-widget.cpp" line="129"/>
|
||||||
|
<source>Unknown</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MainWindow</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/mainwindow.cpp" line="103"/>
|
||||||
|
<source>Search</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>OptionView</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/option-view.cpp" line="76"/>
|
||||||
|
<source>Open</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/option-view.cpp" line="85"/>
|
||||||
|
<source>Add Shortcut to Desktop</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/option-view.cpp" line="94"/>
|
||||||
|
<source>Add Shortcut to Panel</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/option-view.cpp" line="103"/>
|
||||||
|
<source>Open path</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/option-view.cpp" line="112"/>
|
||||||
|
<source>Copy path</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>QObject</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/main.cpp" line="58"/>
|
||||||
|
<source>ukui-search is already running!</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>SearchDetailView</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/search-detail-view.cpp" line="85"/>
|
||||||
|
<source>Application</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/search-detail-view.cpp" line="92"/>
|
||||||
|
<source>Document</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
</TS>
|
|
@ -0,0 +1,89 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE TS>
|
||||||
|
<TS version="2.1">
|
||||||
|
<context>
|
||||||
|
<name>ContentWidget</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/content-widget.cpp" line="121"/>
|
||||||
|
<source>Apps</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/content-widget.cpp" line="123"/>
|
||||||
|
<source>Settings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/content-widget.cpp" line="125"/>
|
||||||
|
<source>Files</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/content-widget.cpp" line="127"/>
|
||||||
|
<source>Best Matches</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/content-widget.cpp" line="129"/>
|
||||||
|
<source>Unknown</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MainWindow</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/mainwindow.cpp" line="103"/>
|
||||||
|
<source>Search</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>OptionView</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/option-view.cpp" line="76"/>
|
||||||
|
<source>Open</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/option-view.cpp" line="85"/>
|
||||||
|
<source>Add Shortcut to Desktop</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/option-view.cpp" line="94"/>
|
||||||
|
<source>Add Shortcut to Panel</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/option-view.cpp" line="103"/>
|
||||||
|
<source>Open path</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/option-view.cpp" line="112"/>
|
||||||
|
<source>Copy path</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>QObject</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/main.cpp" line="58"/>
|
||||||
|
<source>ukui-search is already running!</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>SearchDetailView</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/search-detail-view.cpp" line="85"/>
|
||||||
|
<source>Application</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/search-detail-view.cpp" line="92"/>
|
||||||
|
<source>Document</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
</TS>
|
|
@ -0,0 +1,89 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!DOCTYPE TS>
|
||||||
|
<TS version="2.1" language="zh_CN">
|
||||||
|
<context>
|
||||||
|
<name>ContentWidget</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/content-widget.cpp" line="121"/>
|
||||||
|
<source>Apps</source>
|
||||||
|
<translation type="unfinished">应用</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/content-widget.cpp" line="123"/>
|
||||||
|
<source>Settings</source>
|
||||||
|
<translation type="unfinished">配置项</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/content-widget.cpp" line="125"/>
|
||||||
|
<source>Files</source>
|
||||||
|
<translation type="unfinished">文件</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/content-widget.cpp" line="127"/>
|
||||||
|
<source>Best Matches</source>
|
||||||
|
<translation type="unfinished">最佳匹配</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/content-widget.cpp" line="129"/>
|
||||||
|
<source>Unknown</source>
|
||||||
|
<translation type="unfinished">未知</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MainWindow</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/mainwindow.cpp" line="103"/>
|
||||||
|
<source>Search</source>
|
||||||
|
<translation type="unfinished">搜索</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>OptionView</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/option-view.cpp" line="76"/>
|
||||||
|
<source>Open</source>
|
||||||
|
<translation type="unfinished">打开</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/option-view.cpp" line="85"/>
|
||||||
|
<source>Add Shortcut to Desktop</source>
|
||||||
|
<translation type="unfinished">添加到桌面快捷方式</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/option-view.cpp" line="94"/>
|
||||||
|
<source>Add Shortcut to Panel</source>
|
||||||
|
<translation type="unfinished">添加到任务栏快捷方式</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/option-view.cpp" line="103"/>
|
||||||
|
<source>Open path</source>
|
||||||
|
<translation type="unfinished">打开文件所在路径</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/option-view.cpp" line="112"/>
|
||||||
|
<source>Copy path</source>
|
||||||
|
<translation type="unfinished">复制文件路径</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>QObject</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../../src/main.cpp" line="58"/>
|
||||||
|
<source>ukui-search is already running!</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>SearchDetailView</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/search-detail-view.cpp" line="85"/>
|
||||||
|
<source>Application</source>
|
||||||
|
<translation type="unfinished">应用</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../control/search-detail-view.cpp" line="92"/>
|
||||||
|
<source>Document</source>
|
||||||
|
<translation type="unfinished">文件</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
</TS>
|
|
@ -0,0 +1,12 @@
|
||||||
|
<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>res/icons/commonuse.svg</file>
|
||||||
|
<file>res/icons/edit-find-symbolic.svg</file>
|
||||||
|
<file>res/translations/bo.ts</file>
|
||||||
|
<file>res/translations/tr.ts</file>
|
||||||
|
<file>res/translations/zh_CN.ts</file>
|
||||||
|
<file>res/icons/desktop.png</file>
|
||||||
|
<file>res/search.xml</file>
|
||||||
|
<file>res/icons/close.svg</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
|
@ -0,0 +1 @@
|
||||||
|
#include "qtlockedfile.h"
|
|
@ -0,0 +1 @@
|
||||||
|
#include "qt-single-application.h"
|
|
@ -0,0 +1,213 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "qt-local-peer.h"
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QDataStream>
|
||||||
|
#include <QTime>
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
#include <QLibrary>
|
||||||
|
#include <qt_windows.h>
|
||||||
|
typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
|
||||||
|
static PProcessIdToSessionId pProcessIdToSessionId = 0;
|
||||||
|
#endif
|
||||||
|
#if defined(Q_OS_UNIX)
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace QtLP_Private {
|
||||||
|
#include "qtlockedfile.cpp"
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
#include "qtlockedfile_win.cpp"
|
||||||
|
#else
|
||||||
|
#include "qtlockedfile_unix.cpp"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* QtLocalPeer::ack = "ack";
|
||||||
|
|
||||||
|
QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
|
||||||
|
: QObject(parent), id(appId)
|
||||||
|
{
|
||||||
|
QString prefix = id;
|
||||||
|
if (id.isEmpty()) {
|
||||||
|
id = QCoreApplication::applicationFilePath();
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
id = id.toLower();
|
||||||
|
#endif
|
||||||
|
prefix = id.section(QLatin1Char('/'), -1);
|
||||||
|
}
|
||||||
|
prefix.remove(QRegExp("[^a-zA-Z]"));
|
||||||
|
prefix.truncate(6);
|
||||||
|
|
||||||
|
QByteArray idc = id.toUtf8();
|
||||||
|
quint16 idNum = qChecksum(idc.constData(), idc.size());
|
||||||
|
socketName = QLatin1String("qtsingleapp-") + prefix
|
||||||
|
+ QLatin1Char('-') + QString::number(idNum, 16);
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
if (!pProcessIdToSessionId) {
|
||||||
|
QLibrary lib("kernel32");
|
||||||
|
pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
|
||||||
|
}
|
||||||
|
if (pProcessIdToSessionId) {
|
||||||
|
DWORD sessionId = 0;
|
||||||
|
pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
|
||||||
|
socketName += QLatin1Char('-') + QString::number(sessionId, 16);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
server = new QLocalServer(this);
|
||||||
|
QString lockName = QDir(QDir::tempPath()).absolutePath()
|
||||||
|
+ QLatin1Char('/') + socketName
|
||||||
|
+ QLatin1String("-lockfile");
|
||||||
|
lockFile.setFileName(lockName);
|
||||||
|
lockFile.open(QIODevice::ReadWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool QtLocalPeer::isClient()
|
||||||
|
{
|
||||||
|
if (lockFile.isLocked())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool res = server->listen(socketName);
|
||||||
|
#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))
|
||||||
|
// ### Workaround
|
||||||
|
if (!res && server->serverError() == QAbstractSocket::AddressInUseError) {
|
||||||
|
QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName);
|
||||||
|
res = server->listen(socketName);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!res)
|
||||||
|
qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
|
||||||
|
QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool QtLocalPeer::sendMessage(const QString &message, int timeout)
|
||||||
|
{
|
||||||
|
if (!isClient())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QLocalSocket socket;
|
||||||
|
bool connOk = false;
|
||||||
|
for(int i = 0; i < 2; i++) {
|
||||||
|
// Try twice, in case the other instance is just starting up
|
||||||
|
socket.connectToServer(socketName);
|
||||||
|
connOk = socket.waitForConnected(timeout/2);
|
||||||
|
if (connOk || i)
|
||||||
|
break;
|
||||||
|
int ms = 250;
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
Sleep(DWORD(ms));
|
||||||
|
#else
|
||||||
|
struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
|
||||||
|
nanosleep(&ts, NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (!connOk)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QByteArray uMsg(message.toUtf8());
|
||||||
|
QDataStream ds(&socket);
|
||||||
|
ds.writeBytes(uMsg.constData(), uMsg.size());
|
||||||
|
bool res = socket.waitForBytesWritten(timeout);
|
||||||
|
if (res) {
|
||||||
|
res &= socket.waitForReadyRead(timeout); // wait for ack
|
||||||
|
if (res)
|
||||||
|
res &= (socket.read(qstrlen(ack)) == ack);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void QtLocalPeer::receiveConnection()
|
||||||
|
{
|
||||||
|
QLocalSocket* socket = server->nextPendingConnection();
|
||||||
|
if (!socket)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (socket->state() == QLocalSocket::UnconnectedState) {
|
||||||
|
qWarning("QtLocalPeer: Peer disconnected");
|
||||||
|
delete socket;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (socket->bytesAvailable() >= qint64(sizeof(quint32)))
|
||||||
|
break;
|
||||||
|
socket->waitForReadyRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream ds(socket);
|
||||||
|
QByteArray uMsg;
|
||||||
|
quint32 remaining;
|
||||||
|
ds >> remaining;
|
||||||
|
uMsg.resize(remaining);
|
||||||
|
int got = 0;
|
||||||
|
char* uMsgBuf = uMsg.data();
|
||||||
|
do {
|
||||||
|
got = ds.readRawData(uMsgBuf, remaining);
|
||||||
|
remaining -= got;
|
||||||
|
uMsgBuf += got;
|
||||||
|
} while (remaining && got >= 0 && socket->waitForReadyRead(2000));
|
||||||
|
if (got < 0) {
|
||||||
|
qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData());
|
||||||
|
delete socket;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString message(QString::fromUtf8(uMsg));
|
||||||
|
socket->write(ack, qstrlen(ack));
|
||||||
|
socket->waitForBytesWritten(1000);
|
||||||
|
socket->waitForDisconnected(1000); // make sure client reads ack
|
||||||
|
delete socket;
|
||||||
|
Q_EMIT messageReceived(message); //### (might take a long time to return)
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QTLOCALPEER_H
|
||||||
|
#define QTLOCALPEER_H
|
||||||
|
|
||||||
|
#include <QLocalServer>
|
||||||
|
#include <QLocalSocket>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
#include "qtlockedfile.h"
|
||||||
|
|
||||||
|
class QtLocalPeer : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
QtLocalPeer(QObject *parent = 0, const QString &appId = QString());
|
||||||
|
bool isClient();
|
||||||
|
bool sendMessage(const QString &message, int timeout);
|
||||||
|
QString applicationId() const
|
||||||
|
{ return id; }
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void messageReceived(const QString &message);
|
||||||
|
|
||||||
|
protected Q_SLOTS:
|
||||||
|
void receiveConnection();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QString id;
|
||||||
|
QString socketName;
|
||||||
|
QLocalServer* server;
|
||||||
|
QtLP_Private::QtLockedFile lockFile;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const char* ack;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QTLOCALPEER_H
|
|
@ -0,0 +1,364 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "qt-single-application.h"
|
||||||
|
#include "qt-local-peer.h"
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QDesktopWidget>
|
||||||
|
#include <QDBusConnection>
|
||||||
|
#include <QDBusInterface>
|
||||||
|
#include <QDBusReply>
|
||||||
|
#include "mainwindow.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class QtSingleApplication qtsingleapplication.h
|
||||||
|
\brief The QtSingleApplication class provides an API to detect and
|
||||||
|
communicate with running instances of an application.
|
||||||
|
|
||||||
|
This class allows you to create applications where only one
|
||||||
|
instance should be running at a time. I.e., if the user tries to
|
||||||
|
launch another instance, the already running instance will be
|
||||||
|
activated instead. Another usecase is a client-server system,
|
||||||
|
where the first started instance will assume the role of server,
|
||||||
|
and the later instances will act as clients of that server.
|
||||||
|
|
||||||
|
By default, the full path of the executable file is used to
|
||||||
|
determine whether two processes are instances of the same
|
||||||
|
application. You can also provide an explicit identifier string
|
||||||
|
that will be compared instead.
|
||||||
|
|
||||||
|
The application should create the QtSingleApplication object early
|
||||||
|
in the startup phase, and call isRunning() to find out if another
|
||||||
|
instance of this application is already running. If isRunning()
|
||||||
|
returns false, it means that no other instance is running, and
|
||||||
|
this instance has assumed the role as the running instance. In
|
||||||
|
this case, the application should continue with the initialization
|
||||||
|
of the application user interface before entering the event loop
|
||||||
|
with exec(), as normal.
|
||||||
|
|
||||||
|
The messageReceived() signal will be emitted when the running
|
||||||
|
application receives messages from another instance of the same
|
||||||
|
application. When a message is received it might be helpful to the
|
||||||
|
user to raise the application so that it becomes visible. To
|
||||||
|
facilitate this, QtSingleApplication provides the
|
||||||
|
setActivationWindow() function and the activateWindow() slot.
|
||||||
|
|
||||||
|
If isRunning() returns true, another instance is already
|
||||||
|
running. It may be alerted to the fact that another instance has
|
||||||
|
started by using the sendMessage() function. Also data such as
|
||||||
|
startup parameters (e.g. the name of the file the user wanted this
|
||||||
|
new instance to open) can be passed to the running instance with
|
||||||
|
this function. Then, the application should terminate (or enter
|
||||||
|
client mode).
|
||||||
|
|
||||||
|
If isRunning() returns true, but sendMessage() fails, that is an
|
||||||
|
indication that the running instance is frozen.
|
||||||
|
|
||||||
|
Here's an example that shows how to convert an existing
|
||||||
|
application to use QtSingleApplication. It is very simple and does
|
||||||
|
not make use of all QtSingleApplication's functionality (see the
|
||||||
|
examples for that).
|
||||||
|
|
||||||
|
\code
|
||||||
|
// Original
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
MyMainWidget mmw;
|
||||||
|
mmw.show();
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single instance
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
QtSingleApplication app(argc, argv);
|
||||||
|
|
||||||
|
if (app.isRunning())
|
||||||
|
return !app.sendMessage(someDataString);
|
||||||
|
|
||||||
|
MyMainWidget mmw;
|
||||||
|
app.setActivationWindow(&mmw);
|
||||||
|
mmw.show();
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
Once this QtSingleApplication instance is destroyed (normally when
|
||||||
|
the process exits or crashes), when the user next attempts to run the
|
||||||
|
application this instance will not, of course, be encountered. The
|
||||||
|
next instance to call isRunning() or sendMessage() will assume the
|
||||||
|
role as the new running instance.
|
||||||
|
|
||||||
|
For console (non-GUI) applications, QtSingleCoreApplication may be
|
||||||
|
used instead of this class, to avoid the dependency on the QtGui
|
||||||
|
library.
|
||||||
|
|
||||||
|
\sa QtSingleCoreApplication
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
void QtSingleApplication::sysInit(const QString &appId)
|
||||||
|
{
|
||||||
|
actWin = 0;
|
||||||
|
peer = new QtLocalPeer(this, appId);
|
||||||
|
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Creates a QtSingleApplication object. The application identifier
|
||||||
|
will be QCoreApplication::applicationFilePath(). \a argc, \a
|
||||||
|
argv, and \a GUIenabled are passed on to the QAppliation constructor.
|
||||||
|
|
||||||
|
If you are creating a console application (i.e. setting \a
|
||||||
|
GUIenabled to false), you may consider using
|
||||||
|
QtSingleCoreApplication instead.
|
||||||
|
*/
|
||||||
|
|
||||||
|
QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled)
|
||||||
|
: QApplication(argc, argv, GUIenabled)
|
||||||
|
{
|
||||||
|
sysInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Creates a QtSingleApplication object with the application
|
||||||
|
identifier \a appId. \a argc and \a argv are passed on to the
|
||||||
|
QAppliation constructor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv)
|
||||||
|
: QApplication(argc, argv)
|
||||||
|
{
|
||||||
|
sysInit(appId);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if QT_VERSION < 0x050000
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Creates a QtSingleApplication object. The application identifier
|
||||||
|
will be QCoreApplication::applicationFilePath(). \a argc, \a
|
||||||
|
argv, and \a type are passed on to the QAppliation constructor.
|
||||||
|
*/
|
||||||
|
QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type)
|
||||||
|
: QApplication(argc, argv, type)
|
||||||
|
{
|
||||||
|
sysInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# if defined(Q_WS_X11)
|
||||||
|
/*!
|
||||||
|
Special constructor for X11, ref. the documentation of
|
||||||
|
QApplication's corresponding constructor. The application identifier
|
||||||
|
will be QCoreApplication::applicationFilePath(). \a dpy, \a visual,
|
||||||
|
and \a cmap are passed on to the QApplication constructor.
|
||||||
|
*/
|
||||||
|
QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE cmap)
|
||||||
|
: QApplication(dpy, visual, cmap)
|
||||||
|
{
|
||||||
|
sysInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Special constructor for X11, ref. the documentation of
|
||||||
|
QApplication's corresponding constructor. The application identifier
|
||||||
|
will be QCoreApplication::applicationFilePath(). \a dpy, \a argc, \a
|
||||||
|
argv, \a visual, and \a cmap are passed on to the QApplication
|
||||||
|
constructor.
|
||||||
|
*/
|
||||||
|
QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
|
||||||
|
: QApplication(dpy, argc, argv, visual, cmap)
|
||||||
|
{
|
||||||
|
sysInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Special constructor for X11, ref. the documentation of
|
||||||
|
QApplication's corresponding constructor. The application identifier
|
||||||
|
will be \a appId. \a dpy, \a argc, \a
|
||||||
|
argv, \a visual, and \a cmap are passed on to the QApplication
|
||||||
|
constructor.
|
||||||
|
*/
|
||||||
|
QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
|
||||||
|
: QApplication(dpy, argc, argv, visual, cmap)
|
||||||
|
{
|
||||||
|
sysInit(appId);
|
||||||
|
}
|
||||||
|
# endif // Q_WS_X11
|
||||||
|
#endif // QT_VERSION < 0x050000
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns true if another instance of this application is running;
|
||||||
|
otherwise false.
|
||||||
|
|
||||||
|
This function does not find instances of this application that are
|
||||||
|
being run by a different user (on Windows: that are running in
|
||||||
|
another session).
|
||||||
|
|
||||||
|
\sa sendMessage()
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool QtSingleApplication::isRunning()
|
||||||
|
{
|
||||||
|
return peer->isClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Tries to send the text \a message to the currently running
|
||||||
|
instance. The QtSingleApplication object in the running instance
|
||||||
|
will emit the messageReceived() signal when it receives the
|
||||||
|
message.
|
||||||
|
|
||||||
|
This function returns true if the message has been sent to, and
|
||||||
|
processed by, the current instance. If there is no instance
|
||||||
|
currently running, or if the running instance fails to process the
|
||||||
|
message within \a timeout milliseconds, this function return false.
|
||||||
|
|
||||||
|
\sa isRunning(), messageReceived()
|
||||||
|
*/
|
||||||
|
bool QtSingleApplication::sendMessage(const QString &message, int timeout)
|
||||||
|
{
|
||||||
|
return peer->sendMessage(message, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the application identifier. Two processes with the same
|
||||||
|
identifier will be regarded as instances of the same application.
|
||||||
|
*/
|
||||||
|
QString QtSingleApplication::id() const
|
||||||
|
{
|
||||||
|
return peer->applicationId();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the activation window of this application to \a aw. The
|
||||||
|
activation window is the widget that will be activated by
|
||||||
|
activateWindow(). This is typically the application's main window.
|
||||||
|
|
||||||
|
If \a activateOnMessage is true (the default), the window will be
|
||||||
|
activated automatically every time a message is received, just prior
|
||||||
|
to the messageReceived() signal being emitted.
|
||||||
|
|
||||||
|
\sa activateWindow(), messageReceived()
|
||||||
|
*/
|
||||||
|
|
||||||
|
void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage)
|
||||||
|
{
|
||||||
|
actWin = aw;
|
||||||
|
if (activateOnMessage)
|
||||||
|
connect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow()));
|
||||||
|
else
|
||||||
|
disconnect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the applications activation window if one has been set by
|
||||||
|
calling setActivationWindow(), otherwise returns 0.
|
||||||
|
|
||||||
|
\sa setActivationWindow()
|
||||||
|
*/
|
||||||
|
QWidget* QtSingleApplication::activationWindow() const
|
||||||
|
{
|
||||||
|
return actWin;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
De-minimizes, raises, and activates this application's activation window.
|
||||||
|
This function does nothing if no activation window has been set.
|
||||||
|
|
||||||
|
This is a convenience function to show the user that this
|
||||||
|
application instance has been activated when he has tried to start
|
||||||
|
another instance.
|
||||||
|
|
||||||
|
This function should typically be called in response to the
|
||||||
|
messageReceived() signal. By default, that will happen
|
||||||
|
automatically, if an activation window has been set.
|
||||||
|
|
||||||
|
\sa setActivationWindow(), messageReceived(), initialize()
|
||||||
|
*/
|
||||||
|
void QtSingleApplication::activateWindow()
|
||||||
|
{
|
||||||
|
if (actWin) {
|
||||||
|
if(this->applicationState() & Qt::ApplicationInactive)
|
||||||
|
{
|
||||||
|
MainWindow* w=qobject_cast<MainWindow*>(actWin);
|
||||||
|
// w->loadMainWindow();
|
||||||
|
w->clearSearchResult();
|
||||||
|
actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized);
|
||||||
|
actWin->raise();
|
||||||
|
actWin->showNormal();
|
||||||
|
actWin->activateWindow();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
actWin->setWindowState(actWin->windowState() & Qt::WindowMinimized);
|
||||||
|
actWin->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void QtSingleApplication::messageReceived(const QString& message)
|
||||||
|
|
||||||
|
This signal is emitted when the current instance receives a \a
|
||||||
|
message from another instance of this application.
|
||||||
|
|
||||||
|
\sa sendMessage(), setActivationWindow(), activateWindow()
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void QtSingleApplication::initialize(bool dummy = true)
|
||||||
|
|
||||||
|
\obsolete
|
||||||
|
*/
|
|
@ -0,0 +1,105 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QTSINGLEAPPLICATION_H
|
||||||
|
#define QTSINGLEAPPLICATION_H
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
class QtLocalPeer;
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
# if !defined(QT_QTSINGLEAPPLICATION_EXPORT) && !defined(QT_QTSINGLEAPPLICATION_IMPORT)
|
||||||
|
# define QT_QTSINGLEAPPLICATION_EXPORT
|
||||||
|
# elif defined(QT_QTSINGLEAPPLICATION_IMPORT)
|
||||||
|
# if defined(QT_QTSINGLEAPPLICATION_EXPORT)
|
||||||
|
# undef QT_QTSINGLEAPPLICATION_EXPORT
|
||||||
|
# endif
|
||||||
|
# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllimport)
|
||||||
|
# elif defined(QT_QTSINGLEAPPLICATION_EXPORT)
|
||||||
|
# undef QT_QTSINGLEAPPLICATION_EXPORT
|
||||||
|
# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllexport)
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define QT_QTSINGLEAPPLICATION_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
|
||||||
|
QtSingleApplication(const QString &id, int &argc, char **argv);
|
||||||
|
#if QT_VERSION < 0x050000
|
||||||
|
QtSingleApplication(int &argc, char **argv, Type type);
|
||||||
|
# if defined(Q_WS_X11)
|
||||||
|
QtSingleApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
|
||||||
|
QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0);
|
||||||
|
QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
|
||||||
|
# endif // Q_WS_X11
|
||||||
|
#endif // QT_VERSION < 0x050000
|
||||||
|
|
||||||
|
bool isRunning();
|
||||||
|
QString id() const;
|
||||||
|
|
||||||
|
void setActivationWindow(QWidget* aw, bool activateOnMessage = true);
|
||||||
|
QWidget* activationWindow() const;
|
||||||
|
|
||||||
|
// Obsolete:
|
||||||
|
void initialize(bool dummy = true)
|
||||||
|
{ isRunning(); Q_UNUSED(dummy) }
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
bool sendMessage(const QString &message, int timeout = 5000);
|
||||||
|
void activateWindow();
|
||||||
|
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void messageReceived(const QString &message);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
void sysInit(const QString &appId = QString());
|
||||||
|
QtLocalPeer *peer;
|
||||||
|
QWidget *actWin;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QTSINGLEAPPLICATION_H
|
|
@ -0,0 +1,24 @@
|
||||||
|
INCLUDEPATH += $$PWD
|
||||||
|
DEPENDPATH += $$PWD
|
||||||
|
QT *= network
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4): QT *= widgets
|
||||||
|
|
||||||
|
qtsingleapplication-uselib:!qtsingleapplication-buildlib {
|
||||||
|
LIBS += -L$$QTSINGLEAPPLICATION_LIBDIR -l$$QTSINGLEAPPLICATION_LIBNAME
|
||||||
|
} else {
|
||||||
|
SOURCES +=
|
||||||
|
HEADERS +=
|
||||||
|
}
|
||||||
|
|
||||||
|
win32 {
|
||||||
|
contains(TEMPLATE, lib):contains(CONFIG, shared):DEFINES += QT_QTSINGLEAPPLICATION_EXPORT
|
||||||
|
else:qtsingleapplication-uselib:DEFINES += QT_QTSINGLEAPPLICATION_IMPORT
|
||||||
|
}
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
$$PWD/qt-local-peer.h \
|
||||||
|
$$PWD/qt-single-application.h
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
$$PWD/qt-local-peer.cpp \
|
||||||
|
$$PWD/qt-single-application.cpp
|
|
@ -0,0 +1,193 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "qtlockedfile.h"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class QtLockedFile
|
||||||
|
|
||||||
|
\brief The QtLockedFile class extends QFile with advisory locking
|
||||||
|
functions.
|
||||||
|
|
||||||
|
A file may be locked in read or write mode. Multiple instances of
|
||||||
|
\e QtLockedFile, created in multiple processes running on the same
|
||||||
|
machine, may have a file locked in read mode. Exactly one instance
|
||||||
|
may have it locked in write mode. A read and a write lock cannot
|
||||||
|
exist simultaneously on the same file.
|
||||||
|
|
||||||
|
The file locks are advisory. This means that nothing prevents
|
||||||
|
another process from manipulating a locked file using QFile or
|
||||||
|
file system functions offered by the OS. Serialization is only
|
||||||
|
guaranteed if all processes that access the file use
|
||||||
|
QLockedFile. Also, while holding a lock on a file, a process
|
||||||
|
must not open the same file again (through any API), or locks
|
||||||
|
can be unexpectedly lost.
|
||||||
|
|
||||||
|
The lock provided by an instance of \e QtLockedFile is released
|
||||||
|
whenever the program terminates. This is true even when the
|
||||||
|
program crashes and no destructors are called.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \enum QtLockedFile::LockMode
|
||||||
|
|
||||||
|
This enum describes the available lock modes.
|
||||||
|
|
||||||
|
\value ReadLock A read lock.
|
||||||
|
\value WriteLock A write lock.
|
||||||
|
\value NoLock Neither a read lock nor a write lock.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructs an unlocked \e QtLockedFile object. This constructor
|
||||||
|
behaves in the same way as \e QFile::QFile().
|
||||||
|
|
||||||
|
\sa QFile::QFile()
|
||||||
|
*/
|
||||||
|
QtLockedFile::QtLockedFile()
|
||||||
|
: QFile()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
wmutex = 0;
|
||||||
|
rmutex = 0;
|
||||||
|
#endif
|
||||||
|
m_lock_mode = NoLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Constructs an unlocked QtLockedFile object with file \a name. This
|
||||||
|
constructor behaves in the same way as \e QFile::QFile(const
|
||||||
|
QString&).
|
||||||
|
|
||||||
|
\sa QFile::QFile()
|
||||||
|
*/
|
||||||
|
QtLockedFile::QtLockedFile(const QString &name)
|
||||||
|
: QFile(name)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
wmutex = 0;
|
||||||
|
rmutex = 0;
|
||||||
|
#endif
|
||||||
|
m_lock_mode = NoLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Opens the file in OpenMode \a mode.
|
||||||
|
|
||||||
|
This is identical to QFile::open(), with the one exception that the
|
||||||
|
Truncate mode flag is disallowed. Truncation would conflict with the
|
||||||
|
advisory file locking, since the file would be modified before the
|
||||||
|
write lock is obtained. If truncation is required, use resize(0)
|
||||||
|
after obtaining the write lock.
|
||||||
|
|
||||||
|
Returns true if successful; otherwise false.
|
||||||
|
|
||||||
|
\sa QFile::open(), QFile::resize()
|
||||||
|
*/
|
||||||
|
bool QtLockedFile::open(OpenMode mode)
|
||||||
|
{
|
||||||
|
if (mode & QIODevice::Truncate) {
|
||||||
|
qWarning("QtLockedFile::open(): Truncate mode not allowed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return QFile::open(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns \e true if this object has a in read or write lock;
|
||||||
|
otherwise returns \e false.
|
||||||
|
|
||||||
|
\sa lockMode()
|
||||||
|
*/
|
||||||
|
bool QtLockedFile::isLocked() const
|
||||||
|
{
|
||||||
|
return m_lock_mode != NoLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the type of lock currently held by this object, or \e
|
||||||
|
QtLockedFile::NoLock.
|
||||||
|
|
||||||
|
\sa isLocked()
|
||||||
|
*/
|
||||||
|
QtLockedFile::LockMode QtLockedFile::lockMode() const
|
||||||
|
{
|
||||||
|
return m_lock_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn bool QtLockedFile::lock(LockMode mode, bool block = true)
|
||||||
|
|
||||||
|
Obtains a lock of type \a mode. The file must be opened before it
|
||||||
|
can be locked.
|
||||||
|
|
||||||
|
If \a block is true, this function will block until the lock is
|
||||||
|
aquired. If \a block is false, this function returns \e false
|
||||||
|
immediately if the lock cannot be aquired.
|
||||||
|
|
||||||
|
If this object already has a lock of type \a mode, this function
|
||||||
|
returns \e true immediately. If this object has a lock of a
|
||||||
|
different type than \a mode, the lock is first released and then a
|
||||||
|
new lock is obtained.
|
||||||
|
|
||||||
|
This function returns \e true if, after it executes, the file is
|
||||||
|
locked by this object, and \e false otherwise.
|
||||||
|
|
||||||
|
\sa unlock(), isLocked(), lockMode()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn bool QtLockedFile::unlock()
|
||||||
|
|
||||||
|
Releases a lock.
|
||||||
|
|
||||||
|
If the object has no lock, this function returns immediately.
|
||||||
|
|
||||||
|
This function returns \e true if, after it executes, the file is
|
||||||
|
not locked by this object, and \e false otherwise.
|
||||||
|
|
||||||
|
\sa lock(), isLocked(), lockMode()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn QtLockedFile::~QtLockedFile()
|
||||||
|
|
||||||
|
Destroys the \e QtLockedFile object. If any locks were held, they
|
||||||
|
are released.
|
||||||
|
*/
|
|
@ -0,0 +1,97 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QTLOCKEDFILE_H
|
||||||
|
#define QTLOCKEDFILE_H
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#include <QVector>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT)
|
||||||
|
# define QT_QTLOCKEDFILE_EXPORT
|
||||||
|
# elif defined(QT_QTLOCKEDFILE_IMPORT)
|
||||||
|
# if defined(QT_QTLOCKEDFILE_EXPORT)
|
||||||
|
# undef QT_QTLOCKEDFILE_EXPORT
|
||||||
|
# endif
|
||||||
|
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport)
|
||||||
|
# elif defined(QT_QTLOCKEDFILE_EXPORT)
|
||||||
|
# undef QT_QTLOCKEDFILE_EXPORT
|
||||||
|
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport)
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define QT_QTLOCKEDFILE_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace QtLP_Private {
|
||||||
|
|
||||||
|
class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum LockMode { NoLock = 0, ReadLock, WriteLock };
|
||||||
|
|
||||||
|
QtLockedFile();
|
||||||
|
QtLockedFile(const QString &name);
|
||||||
|
~QtLockedFile();
|
||||||
|
|
||||||
|
bool open(OpenMode mode);
|
||||||
|
|
||||||
|
bool lock(LockMode mode, bool block = true);
|
||||||
|
bool unlock();
|
||||||
|
bool isLocked() const;
|
||||||
|
LockMode lockMode() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
Qt::HANDLE wmutex;
|
||||||
|
Qt::HANDLE rmutex;
|
||||||
|
QVector<Qt::HANDLE> rmutexes;
|
||||||
|
QString mutexname;
|
||||||
|
|
||||||
|
Qt::HANDLE getMutexHandle(int idx, bool doCreate);
|
||||||
|
bool waitMutex(Qt::HANDLE mutex, bool doBlock);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
LockMode m_lock_mode;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,115 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include "qtlockedfile.h"
|
||||||
|
|
||||||
|
bool QtLockedFile::lock(LockMode mode, bool block)
|
||||||
|
{
|
||||||
|
if (!isOpen()) {
|
||||||
|
qWarning("QtLockedFile::lock(): file is not opened");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == NoLock)
|
||||||
|
return unlock();
|
||||||
|
|
||||||
|
if (mode == m_lock_mode)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (m_lock_mode != NoLock)
|
||||||
|
unlock();
|
||||||
|
|
||||||
|
struct flock fl;
|
||||||
|
fl.l_whence = SEEK_SET;
|
||||||
|
fl.l_start = 0;
|
||||||
|
fl.l_len = 0;
|
||||||
|
fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK;
|
||||||
|
int cmd = block ? F_SETLKW : F_SETLK;
|
||||||
|
int ret = fcntl(handle(), cmd, &fl);
|
||||||
|
|
||||||
|
if (ret == -1) {
|
||||||
|
if (errno != EINTR && errno != EAGAIN)
|
||||||
|
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
m_lock_mode = mode;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool QtLockedFile::unlock()
|
||||||
|
{
|
||||||
|
if (!isOpen()) {
|
||||||
|
qWarning("QtLockedFile::unlock(): file is not opened");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLocked())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
struct flock fl;
|
||||||
|
fl.l_whence = SEEK_SET;
|
||||||
|
fl.l_start = 0;
|
||||||
|
fl.l_len = 0;
|
||||||
|
fl.l_type = F_UNLCK;
|
||||||
|
int ret = fcntl(handle(), F_SETLKW, &fl);
|
||||||
|
|
||||||
|
if (ret == -1) {
|
||||||
|
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lock_mode = NoLock;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QtLockedFile::~QtLockedFile()
|
||||||
|
{
|
||||||
|
if (isOpen())
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,211 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "qtlockedfile.h"
|
||||||
|
#include <qt_windows.h>
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
#define MUTEX_PREFIX "QtLockedFile mutex "
|
||||||
|
// Maximum number of concurrent read locks. Must not be greater than MAXIMUM_WAIT_OBJECTS
|
||||||
|
#define MAX_READERS MAXIMUM_WAIT_OBJECTS
|
||||||
|
|
||||||
|
#if QT_VERSION >= 0x050000
|
||||||
|
#define QT_WA(unicode, ansi) unicode
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate)
|
||||||
|
{
|
||||||
|
if (mutexname.isEmpty()) {
|
||||||
|
QFileInfo fi(*this);
|
||||||
|
mutexname = QString::fromLatin1(MUTEX_PREFIX)
|
||||||
|
+ fi.absoluteFilePath().toLower();
|
||||||
|
}
|
||||||
|
QString mname(mutexname);
|
||||||
|
if (idx >= 0)
|
||||||
|
mname += QString::number(idx);
|
||||||
|
|
||||||
|
Qt::HANDLE mutex;
|
||||||
|
if (doCreate) {
|
||||||
|
QT_WA( { mutex = CreateMutexW(NULL, FALSE, (TCHAR*)mname.utf16()); },
|
||||||
|
{ mutex = CreateMutexA(NULL, FALSE, mname.toLocal8Bit().constData()); } );
|
||||||
|
if (!mutex) {
|
||||||
|
qErrnoWarning("QtLockedFile::lock(): CreateMutex failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (TCHAR*)mname.utf16()); },
|
||||||
|
{ mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, mname.toLocal8Bit().constData()); } );
|
||||||
|
if (!mutex) {
|
||||||
|
if (GetLastError() != ERROR_FILE_NOT_FOUND)
|
||||||
|
qErrnoWarning("QtLockedFile::lock(): OpenMutex failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QtLockedFile::waitMutex(Qt::HANDLE mutex, bool doBlock)
|
||||||
|
{
|
||||||
|
Q_ASSERT(mutex);
|
||||||
|
DWORD res = WaitForSingleObject(mutex, doBlock ? INFINITE : 0);
|
||||||
|
switch (res) {
|
||||||
|
case WAIT_OBJECT_0:
|
||||||
|
case WAIT_ABANDONED:
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case WAIT_TIMEOUT:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qErrnoWarning("QtLockedFile::lock(): WaitForSingleObject failed");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool QtLockedFile::lock(LockMode mode, bool block)
|
||||||
|
{
|
||||||
|
if (!isOpen()) {
|
||||||
|
qWarning("QtLockedFile::lock(): file is not opened");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == NoLock)
|
||||||
|
return unlock();
|
||||||
|
|
||||||
|
if (mode == m_lock_mode)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (m_lock_mode != NoLock)
|
||||||
|
unlock();
|
||||||
|
|
||||||
|
if (!wmutex && !(wmutex = getMutexHandle(-1, true)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!waitMutex(wmutex, block))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (mode == ReadLock) {
|
||||||
|
int idx = 0;
|
||||||
|
for (; idx < MAX_READERS; idx++) {
|
||||||
|
rmutex = getMutexHandle(idx, false);
|
||||||
|
if (!rmutex || waitMutex(rmutex, false))
|
||||||
|
break;
|
||||||
|
CloseHandle(rmutex);
|
||||||
|
}
|
||||||
|
bool ok = true;
|
||||||
|
if (idx >= MAX_READERS) {
|
||||||
|
qWarning("QtLockedFile::lock(): too many readers");
|
||||||
|
rmutex = 0;
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
else if (!rmutex) {
|
||||||
|
rmutex = getMutexHandle(idx, true);
|
||||||
|
if (!rmutex || !waitMutex(rmutex, false))
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
if (!ok && rmutex) {
|
||||||
|
CloseHandle(rmutex);
|
||||||
|
rmutex = 0;
|
||||||
|
}
|
||||||
|
ReleaseMutex(wmutex);
|
||||||
|
if (!ok)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Q_ASSERT(rmutexes.isEmpty());
|
||||||
|
for (int i = 0; i < MAX_READERS; i++) {
|
||||||
|
Qt::HANDLE mutex = getMutexHandle(i, false);
|
||||||
|
if (mutex)
|
||||||
|
rmutexes.append(mutex);
|
||||||
|
}
|
||||||
|
if (rmutexes.size()) {
|
||||||
|
DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(),
|
||||||
|
TRUE, block ? INFINITE : 0);
|
||||||
|
if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) {
|
||||||
|
if (res != WAIT_TIMEOUT)
|
||||||
|
qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed");
|
||||||
|
m_lock_mode = WriteLock; // trick unlock() to clean up - semiyucky
|
||||||
|
unlock();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lock_mode = mode;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QtLockedFile::unlock()
|
||||||
|
{
|
||||||
|
if (!isOpen()) {
|
||||||
|
qWarning("QtLockedFile::unlock(): file is not opened");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLocked())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (m_lock_mode == ReadLock) {
|
||||||
|
ReleaseMutex(rmutex);
|
||||||
|
CloseHandle(rmutex);
|
||||||
|
rmutex = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Q_FOREACH(Qt::HANDLE mutex, rmutexes) {
|
||||||
|
ReleaseMutex(mutex);
|
||||||
|
CloseHandle(mutex);
|
||||||
|
}
|
||||||
|
rmutexes.clear();
|
||||||
|
ReleaseMutex(wmutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lock_mode = QtLockedFile::NoLock;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QtLockedFile::~QtLockedFile()
|
||||||
|
{
|
||||||
|
if (isOpen())
|
||||||
|
unlock();
|
||||||
|
if (wmutex)
|
||||||
|
CloseHandle(wmutex);
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "qtsinglecoreapplication.h"
|
||||||
|
#include "qtlocalpeer.h"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class QtSingleCoreApplication qtsinglecoreapplication.h
|
||||||
|
\brief A variant of the QtSingleApplication class for non-GUI applications.
|
||||||
|
|
||||||
|
This class is a variant of QtSingleApplication suited for use in
|
||||||
|
console (non-GUI) applications. It is an extension of
|
||||||
|
QCoreApplication (instead of QApplication). It does not require
|
||||||
|
the QtGui library.
|
||||||
|
|
||||||
|
The API and usage is identical to QtSingleApplication, except that
|
||||||
|
functions relating to the "activation window" are not present, for
|
||||||
|
obvious reasons. Please refer to the QtSingleApplication
|
||||||
|
documentation for explanation of the usage.
|
||||||
|
|
||||||
|
A QtSingleCoreApplication instance can communicate to a
|
||||||
|
QtSingleApplication instance if they share the same application
|
||||||
|
id. Hence, this class can be used to create a light-weight
|
||||||
|
command-line tool that sends commands to a GUI application.
|
||||||
|
|
||||||
|
\sa QtSingleApplication
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Creates a QtSingleCoreApplication object. The application identifier
|
||||||
|
will be QCoreApplication::applicationFilePath(). \a argc and \a
|
||||||
|
argv are passed on to the QCoreAppliation constructor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
|
||||||
|
: QCoreApplication(argc, argv)
|
||||||
|
{
|
||||||
|
peer = new QtLocalPeer(this);
|
||||||
|
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Creates a QtSingleCoreApplication object with the application
|
||||||
|
identifier \a appId. \a argc and \a argv are passed on to the
|
||||||
|
QCoreAppliation constructor.
|
||||||
|
*/
|
||||||
|
QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc, char **argv)
|
||||||
|
: QCoreApplication(argc, argv)
|
||||||
|
{
|
||||||
|
peer = new QtLocalPeer(this, appId);
|
||||||
|
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns true if another instance of this application is running;
|
||||||
|
otherwise false.
|
||||||
|
|
||||||
|
This function does not find instances of this application that are
|
||||||
|
being run by a different user (on Windows: that are running in
|
||||||
|
another session).
|
||||||
|
|
||||||
|
\sa sendMessage()
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool QtSingleCoreApplication::isRunning()
|
||||||
|
{
|
||||||
|
return peer->isClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Tries to send the text \a message to the currently running
|
||||||
|
instance. The QtSingleCoreApplication object in the running instance
|
||||||
|
will emit the messageReceived() signal when it receives the
|
||||||
|
message.
|
||||||
|
|
||||||
|
This function returns true if the message has been sent to, and
|
||||||
|
processed by, the current instance. If there is no instance
|
||||||
|
currently running, or if the running instance fails to process the
|
||||||
|
message within \a timeout milliseconds, this function return false.
|
||||||
|
|
||||||
|
\sa isRunning(), messageReceived()
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout)
|
||||||
|
{
|
||||||
|
return peer->sendMessage(message, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the application identifier. Two processes with the same
|
||||||
|
identifier will be regarded as instances of the same application.
|
||||||
|
*/
|
||||||
|
|
||||||
|
QString QtSingleCoreApplication::id() const
|
||||||
|
{
|
||||||
|
return peer->applicationId();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void QtSingleCoreApplication::messageReceived(const QString& message)
|
||||||
|
|
||||||
|
This signal is emitted when the current instance receives a \a
|
||||||
|
message from another instance of this application.
|
||||||
|
|
||||||
|
\sa sendMessage()
|
||||||
|
*/
|
|
@ -0,0 +1,71 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Solutions component.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** You may use this file under the terms of the BSD license as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
|
||||||
|
** of its contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QTSINGLECOREAPPLICATION_H
|
||||||
|
#define QTSINGLECOREAPPLICATION_H
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
|
||||||
|
class QtLocalPeer;
|
||||||
|
|
||||||
|
class QtSingleCoreApplication : public QCoreApplication
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
QtSingleCoreApplication(int &argc, char **argv);
|
||||||
|
QtSingleCoreApplication(const QString &id, int &argc, char **argv);
|
||||||
|
|
||||||
|
bool isRunning();
|
||||||
|
QString id() const;
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
bool sendMessage(const QString &message, int timeout = 5000);
|
||||||
|
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void messageReceived(const QString &message);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
QtLocalPeer* peer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // QTSINGLECOREAPPLICATION_H
|
|
@ -0,0 +1,10 @@
|
||||||
|
INCLUDEPATH += $$PWD
|
||||||
|
DEPENDPATH += $$PWD
|
||||||
|
HEADERS += $$PWD/qtsinglecoreapplication.h $$PWD/qtlocalpeer.h
|
||||||
|
SOURCES += $$PWD/qtsinglecoreapplication.cpp $$PWD/qtlocalpeer.cpp
|
||||||
|
|
||||||
|
QT *= network
|
||||||
|
|
||||||
|
win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
|
||||||
|
DEFINES += QT_QTSINGLECOREAPPLICATION_EXPORT=__declspec(dllexport)
|
||||||
|
}
|
Loading…
Reference in New Issue