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-local-peer.h"
|
||||
//#include "inotify-manager.h"
|
||||
#include "../libsearch/index/inotify.h"
|
||||
#include "libsearch.h"
|
||||
|
||||
void centerToScreen(QWidget* widget) {
|
||||
if (!widget)
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include "libsearch.h"
|
||||
#include "kwindowsystem.h"
|
||||
|
||||
#include "file-utils.h"
|
||||
//#include "inotify-manager.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