Begin 'shared' project to share code between cli and gui
此提交包含在:
		
							
								
								
									
										21
									
								
								cli/cli.pro
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								cli/cli.pro
									
									
									
									
									
								
							| @@ -32,7 +32,8 @@ SOURCES += \ | ||||
|     filesaver.cpp \ | ||||
|     databasefactory.cpp \ | ||||
|     sqlitedbservice.cpp \ | ||||
|     logger.cpp | ||||
|     logger.cpp \ | ||||
|     commandsearch.cpp | ||||
|  | ||||
| HEADERS += \ | ||||
|     encodingdetector.h \ | ||||
| @@ -54,5 +55,21 @@ HEADERS += \ | ||||
|     filedata.h \ | ||||
|     databasefactory.h \ | ||||
|     sqlitedbservice.h \ | ||||
|     logger.h | ||||
|     logger.h \ | ||||
|     commandsearch.h | ||||
| INCLUDEPATH += /usr/include/poppler/qt5/ /usr/include/quazip5 | ||||
|  | ||||
|  | ||||
|  | ||||
| win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../shared/release/ -lshared | ||||
| else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../shared/debug/ -lshared | ||||
| else:unix: LIBS += -L$$OUT_PWD/../shared/ -lshared | ||||
|  | ||||
| INCLUDEPATH += $$PWD/../shared | ||||
| DEPENDPATH += $$PWD/../shared | ||||
|  | ||||
| win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../shared/release/libshared.a | ||||
| else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../shared/debug/libshared.a | ||||
| else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../shared/release/shared.lib | ||||
| else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../shared/debug/shared.lib | ||||
| else:unix: PRE_TARGETDEPS += $$OUT_PWD/../shared/libshared.a | ||||
|   | ||||
							
								
								
									
										1
									
								
								cli/commandsearch.cpp
									
									
									
									
									
										一般檔案
									
								
							
							
						
						
									
										1
									
								
								cli/commandsearch.cpp
									
									
									
									
									
										一般檔案
									
								
							| @@ -0,0 +1 @@ | ||||
| #include "commandsearch.h" | ||||
							
								
								
									
										20
									
								
								cli/commandsearch.h
									
									
									
									
									
										一般檔案
									
								
							
							
						
						
									
										20
									
								
								cli/commandsearch.h
									
									
									
									
									
										一般檔案
									
								
							| @@ -0,0 +1,20 @@ | ||||
| #ifndef COMMANDSEARCH_H | ||||
| #define COMMANDSEARCH_H | ||||
| #include "command.h" | ||||
| #include "../shared/sqlitesearch.h" | ||||
|  | ||||
| class CommandSearch : public Command | ||||
| { | ||||
|   private: | ||||
| 	SqliteSearch searcher; | ||||
|  | ||||
|   public: | ||||
| 	using Command::Command; | ||||
|  | ||||
| 	int handle(QStringList arguments) override | ||||
| 	{ | ||||
| 		return 23; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| #endif // COMMANDSEARCH_H | ||||
| @@ -20,6 +20,7 @@ | ||||
| #include "commandadd.h" | ||||
| #include "commanddelete.h" | ||||
| #include "commandupdate.h" | ||||
| #include "commandsearch.h" | ||||
| #include "databasefactory.h" | ||||
| #include "logger.h" | ||||
| void printUsage(QString argv0) | ||||
| @@ -43,7 +44,9 @@ Command *commandFromName(QString name, SqliteDbService &dbService) | ||||
| 	} | ||||
| 	if(name == "search") | ||||
| 	{ | ||||
| 		return new CommandSearch(dbService); | ||||
| 	} | ||||
|  | ||||
| 	return nullptr; | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										13
									
								
								gui/gui.pro
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								gui/gui.pro
									
									
									
									
									
								
							| @@ -22,7 +22,6 @@ DEFINES += QT_DEPRECATED_WARNINGS | ||||
| # 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 | ||||
|  | ||||
|  | ||||
| SOURCES += \ | ||||
|         main.cpp \ | ||||
|         mainwindow.cpp \ | ||||
| @@ -47,3 +46,15 @@ INCLUDEPATH += /usr/include/poppler/qt5/ | ||||
| LIBS += -lpoppler-qt5 | ||||
| QT += widgets sql | ||||
|  | ||||
| win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../shared/release/ -lshared | ||||
| else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../shared/debug/ -lshared | ||||
| else:unix: LIBS += -L$$OUT_PWD/../shared/ -lshared | ||||
|  | ||||
| INCLUDEPATH += $$PWD/../shared | ||||
| DEPENDPATH += $$PWD/../shared | ||||
|  | ||||
| win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../shared/release/libshared.a | ||||
| else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../shared/debug/libshared.a | ||||
| else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../shared/release/shared.lib | ||||
| else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../shared/debug/shared.lib | ||||
| else:unix: PRE_TARGETDEPS += $$OUT_PWD/../shared/libshared.a | ||||
|   | ||||
							
								
								
									
										32
									
								
								shared/shared.pro
									
									
									
									
									
										一般檔案
									
								
							
							
						
						
									
										32
									
								
								shared/shared.pro
									
									
									
									
									
										一般檔案
									
								
							| @@ -0,0 +1,32 @@ | ||||
| #------------------------------------------------- | ||||
| # | ||||
| # Project created by QtCreator 2019-04-20T23:00:36 | ||||
| # | ||||
| #------------------------------------------------- | ||||
|  | ||||
| QT       += sql | ||||
|  | ||||
| QT       -= gui | ||||
|  | ||||
| TARGET = shared | ||||
| TEMPLATE = lib | ||||
| CONFIG += staticlib | ||||
|  | ||||
| # The following define makes your compiler emit warnings if you use | ||||
| # any feature of Qt which has been marked as 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 you use 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 | ||||
|  | ||||
| SOURCES += sqlitesearch.cpp | ||||
|  | ||||
| HEADERS += sqlitesearch.h | ||||
| unix { | ||||
|     target.path = /usr/lib | ||||
|     INSTALLS += target | ||||
| } | ||||
							
								
								
									
										158
									
								
								shared/sqlitesearch.cpp
									
									
									
									
									
										一般檔案
									
								
							
							
						
						
									
										158
									
								
								shared/sqlitesearch.cpp
									
									
									
									
									
										一般檔案
									
								
							| @@ -0,0 +1,158 @@ | ||||
| #include <QStack> | ||||
| #include <QRegularExpression> | ||||
|  | ||||
| #include "sqlitesearch.h" | ||||
|  | ||||
| SqliteSearch::SqliteSearch() | ||||
| { | ||||
| } | ||||
|  | ||||
| QVector<SqliteSearch::Token> SqliteSearch::tokenize(QString expression) | ||||
| { | ||||
| 	if(!checkParanthesis(expression)) | ||||
| 	{ | ||||
| 		throw std::invalid_argument("Invalid paranthesis"); | ||||
| 	} | ||||
| 	// TODO: merge lonewords | ||||
| 	QVector<SqliteSearch::Token> result; | ||||
| 	QRegularExpression rx("((?<filtername>(\\.|\\w)+):(?<args>\\((?<innerargs>[^\\)]+)\\)|(\\w)+)|(?<boolean>AND|OR|!)|" | ||||
| 						  "(?<bracket>\\(|\\))|(?<loneword>\\w+))"); | ||||
| 	QRegularExpressionMatchIterator i = rx.globalMatch(expression); | ||||
| 	bool wasbool = true; | ||||
| 	while(i.hasNext()) | ||||
| 	{ | ||||
| 		QRegularExpressionMatch m = i.next(); | ||||
| 		QString boolean = m.captured("boolean"); | ||||
| 		QString filtername = m.captured("filtername"); | ||||
| 		QString bracket = m.captured("bracket"); | ||||
| 		QString loneword = m.captured("loneword"); | ||||
|  | ||||
| 		if(boolean != "") | ||||
| 		{ | ||||
| 			wasbool = true; | ||||
| 			result.append(Token(boolean)); | ||||
| 		} | ||||
|  | ||||
| 		if(bracket != "") | ||||
| 		{ | ||||
| 			if(!wasbool) | ||||
| 			{ | ||||
| 				if(bracket == "(") | ||||
| 				{ | ||||
| 					result.append(Token("AND")); | ||||
| 				} | ||||
| 			} | ||||
| 			result.append(Token(bracket)); | ||||
| 		} | ||||
|  | ||||
| 		if(loneword != "") | ||||
| 		{ | ||||
| 			if(!wasbool) | ||||
| 			{ | ||||
| 				result.append(Token("AND")); | ||||
| 			} | ||||
| 			wasbool = false; | ||||
| 			result.append(Token("path.contains", loneword)); | ||||
| 		} | ||||
|  | ||||
| 		if(filtername != "") | ||||
| 		{ | ||||
| 			if(!wasbool) | ||||
| 			{ | ||||
| 				result.append(Token("AND")); | ||||
| 			} | ||||
| 			wasbool = false; | ||||
| 			QString value = m.captured("innerargs"); | ||||
| 			if(value == "") | ||||
| 			{ | ||||
| 				value = m.captured("args"); | ||||
| 			} | ||||
| 			result.append(Token(filtername, value)); | ||||
| 		} | ||||
| 	} | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| QString SqliteSearch::createSql(const SqliteSearch::Token &token) | ||||
| { | ||||
| 	QString key = token.key; | ||||
| 	QString value = token.value; | ||||
| 	value = value.replace("'", "\\'"); | ||||
| 	if(key == "AND" || key == "OR" || key == "(" || key == ")") | ||||
| 	{ | ||||
| 		return " " + key + " "; | ||||
| 	} | ||||
| 	if(key == "!") | ||||
| 	{ | ||||
| 		return " NOT "; | ||||
| 	} | ||||
| 	if(key == "path.starts") | ||||
| 	{ | ||||
| 		return " file.path LIKE '" + value + "%' "; | ||||
| 	} | ||||
| 	if(key == "path.ends") | ||||
| 	{ | ||||
| 		return " file.path LIKE '%" + value + "' "; | ||||
| 	} | ||||
| 	if(key == "path.contains" || key == "inpath") | ||||
| 	{ | ||||
| 		return " file.path LIKE '%" + value + "%' "; | ||||
| 	} | ||||
| 	if(key == "page") | ||||
| 	{ | ||||
| 		return " content.page = " + value; | ||||
| 	} | ||||
| 	if(key == "contains" || key == "c") | ||||
| 	{ | ||||
| 		return " content.id IN (SELECT content_fts.ROWID FROM content_fts WHERE content_fts.content MATCH '" + value + | ||||
| 			   "' )"; | ||||
| 	} | ||||
|  | ||||
| 	throw std::invalid_argument("Unknown filter: " + key.toStdString()); | ||||
| } | ||||
|  | ||||
| QString SqliteSearch::makeSql(const QVector<SqliteSearch::Token> &tokens) | ||||
| { | ||||
| 	QString result; | ||||
| 	for(const Token &c : tokens) | ||||
| 	{ | ||||
| 		result += createSql(c); | ||||
| 	} | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| void SqliteSearch::search(const QString &query) | ||||
| { | ||||
| } | ||||
|  | ||||
| bool SqliteSearch::checkParanthesis(QString expression) | ||||
| { | ||||
| 	QStack<QChar> open; | ||||
| 	QStack<QChar> close; | ||||
|  | ||||
| 	for(QChar &c : expression) | ||||
| 	{ | ||||
| 		if(c == '(') | ||||
| 		{ | ||||
| 			open.push(c); | ||||
| 		} | ||||
| 		if(c == ')') | ||||
| 		{ | ||||
| 			close.push(c); | ||||
| 		} | ||||
| 	} | ||||
| 	if(open.size() != close.size()) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 	while(!open.empty() && !close.empty()) | ||||
| 	{ | ||||
| 		QChar o = open.pop(); | ||||
| 		QChar c = close.pop(); | ||||
| 		if(o != '(' && c != ')') | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
							
								
								
									
										33
									
								
								shared/sqlitesearch.h
									
									
									
									
									
										一般檔案
									
								
							
							
						
						
									
										33
									
								
								shared/sqlitesearch.h
									
									
									
									
									
										一般檔案
									
								
							| @@ -0,0 +1,33 @@ | ||||
| #ifndef SQLITESEARCH_H | ||||
| #define SQLITESEARCH_H | ||||
| #include <QSqlDatabase> | ||||
|  | ||||
| class SqliteSearch | ||||
| { | ||||
| 	class Token | ||||
| 	{ | ||||
| 	  public: | ||||
| 		QString key; | ||||
| 		QString value; | ||||
|  | ||||
| 		Token(QString key = "", QString value = "") | ||||
| 		{ | ||||
| 			this->key = key; | ||||
| 			this->value = value; | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
|   private: | ||||
| 	QSqlDatabase *db; | ||||
| 	QVector<SqliteSearch::Token> tokenize(QString expression); | ||||
| 	QString createSql(const Token &token); | ||||
| 	QString makeSql(const QVector<Token> &tokens); | ||||
| 	bool checkParanthesis(QString expression); | ||||
|  | ||||
|   public: | ||||
| 	SqliteSearch(); | ||||
| 	SqliteSearch(QSqlDatabase &db); | ||||
| 	void search(const QString &query); | ||||
| }; | ||||
|  | ||||
| #endif // SQLITESEARCH_H | ||||
		新增問題並參考
	
	封鎖使用者