Repair project structure.

This commit is contained in:
zhangpengfei 2020-12-30 15:31:36 +08:00
parent 03ac37afe2
commit d8ff48bef1
80 changed files with 88721 additions and 2 deletions

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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 \

View File

@ -0,0 +1,6 @@
#include "blockdirs.h"
BlockDirs::BlockDirs(QObject *parent) : QObject(parent)
{
}

View File

@ -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

View File

@ -0,0 +1,8 @@
#include "chinesecharacterstopinyin.h"
chineseCharactersToPinyin::chineseCharactersToPinyin(QObject *parent) : QObject(parent)
{
map = loadHanziTable("://index/pinyinWithoutTone.txt");
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

32
libsearch/index/index.pri Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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

167
libsearch/index/inotify.cpp Normal file
View File

@ -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;
}
}
}

36
libsearch/index/inotify.h Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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("", "lv")
.replace("", "lv")
.replace("", "lv")
.replace("", "lv")
.replace("", "lv")
.replace("", "nv")
.replace("", "nv")
.replace("", "nv")
.replace("", "nv")
.replace("", "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-----------------*/
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

5
libsearch/libsearch.cpp Normal file
View File

@ -0,0 +1,5 @@
#include "libsearch.h"
Libsearch::Libsearch()
{
}

6
libsearch/resource1.qrc Normal file
View File

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/">
<file>index/pinyinWithTone.txt</file>
<file>index/pinyinWithoutTone.txt</file>
</qresource>
</RCC>

View File

@ -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;
}

View File

@ -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

View File

@ -0,0 +1,7 @@
INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/setting-match.h \
SOURCES += \
$$PWD/setting-match.cpp \

0
src/control/README.md Normal file
View File

View File

@ -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();
}

35
src/control/config-file.h Normal file
View File

@ -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

15
src/control/control.pri Normal file
View File

@ -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 \

View File

@ -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);
}

View File

@ -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

185
src/control/option-view.cpp Normal file
View File

@ -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);
}

50
src/control/option-view.h Normal file
View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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)

View File

@ -31,7 +31,6 @@
#include "libsearch.h"
#include "kwindowsystem.h"
#include "file-utils.h"
//#include "inotify-manager.h"
#include "settings-widget.h"

0
src/model/README.md Normal file
View File

9
src/model/model.pri Normal file
View File

@ -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 \

View File

@ -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;
}

View File

@ -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

82
src/model/search-item.cpp Normal file
View File

@ -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;
}

43
src/model/search-item.h Normal file
View File

@ -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

1
src/res/icons/close.svg Normal file
View File

@ -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

View File

@ -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

BIN
src/res/icons/desktop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 998 B

View File

@ -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

567
src/res/search.xml Normal file
View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

12
src/resource.qrc Normal file
View File

@ -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>

View File

@ -0,0 +1 @@
#include "qtlockedfile.h"

View File

@ -0,0 +1 @@
#include "qt-single-application.h"

View File

@ -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)
}

View File

@ -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

View File

@ -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
*/

View File

@ -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

View File

@ -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

View File

@ -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.
*/

View File

@ -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

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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()
*/

View File

@ -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

View File

@ -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)
}