Add option to ignore files and folders

master
Jonas Letzbor 2022-10-04 00:25:39 +02:00
parent c88a867238
commit 6f54ccd44c
16 changed files with 687 additions and 13 deletions

View File

@ -52,6 +52,7 @@ set(SOURCES ${CMAKE_SOURCE_DIR}/src/main.cpp
${CMAKE_SOURCE_DIR}/src/handler/contextMenu.cpp
${CMAKE_SOURCE_DIR}/src/handler/eventHandler.cpp
${CMAKE_SOURCE_DIR}/src/handler/mainMenu.cpp
${CMAKE_SOURCE_DIR}/src/handler/fileHandler.cpp
${CMAKE_SOURCE_DIR}/src/ui/listView.cpp
${CMAKE_SOURCE_DIR}/src/ui/listViewEntry.cpp
${CMAKE_SOURCE_DIR}/src/ui/webDAVView/webDAVView.cpp
@ -59,6 +60,7 @@ set(SOURCES ${CMAKE_SOURCE_DIR}/src/main.cpp
${CMAKE_SOURCE_DIR}/src/ui/loginView/loginView.cpp
${CMAKE_SOURCE_DIR}/src/ui/fileView/fileView.cpp
${CMAKE_SOURCE_DIR}/src/ui/fileView/fileViewEntry.cpp
${CMAKE_SOURCE_DIR}/src/ui/excludeFileView/excludeFileView.cpp
${CMAKE_SOURCE_DIR}/src/util/util.cpp
${CMAKE_SOURCE_DIR}/src/util/log.cpp
${CMAKE_SOURCE_DIR}/src/api/webDAV.cpp
@ -78,6 +80,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/ui/webDAVView/
${CMAKE_SOURCE_DIR}/src/ui/fileView/
${CMAKE_SOURCE_DIR}/src/ui/loginView/
${CMAKE_SOURCE_DIR}/src/ui/excludeFileView/
${CMAKE_SOURCE_DIR}/src/api/
)

View File

@ -9,6 +9,8 @@
#include "fileBrowser.h"
#include "inkview.h"
#include "fileHandler.h"
#include "log.h"
#include <string>
#include <experimental/filesystem>
@ -18,6 +20,7 @@ using std::vector;
namespace fs = std::experimental::filesystem;
std::shared_ptr<FileHandler> FileBrowser::_fileHandler = std::shared_ptr<FileHandler>(new FileHandler());
std::vector<FileItem> FileBrowser::getFileStructure(const std::string &path, const bool includeFiles, const bool includeHeader)
{
string localPath = path;
@ -38,6 +41,7 @@ std::vector<FileItem> FileBrowser::getFileStructure(const std::string &path, con
items.push_back(temp);
}
const int storageLocationLength = _fileHandler->getStorageLocation().length();
if (iv_access(localPath.c_str(), R_OK) == 0)
{
for (const auto &entry : fs::directory_iterator(localPath))
@ -46,20 +50,27 @@ std::vector<FileItem> FileBrowser::getFileStructure(const std::string &path, con
auto time = std::chrono::system_clock::to_time_t(fs::last_write_time(entry));
temp.lastEditDate = *gmtime(&time);
string directoryPath = temp.path;
if (directoryPath.length() > storageLocationLength + 1) {
directoryPath = directoryPath.substr(storageLocationLength + 1);
}
if(is_directory(entry))
{
temp.path = entry.path();
temp.name = temp.path.substr(temp.path.find_last_of('/') + 1, temp.path.length());
temp.type = Type::FFOLDER;
items.push_back(temp);
if (!_fileHandler->excludeFolder(directoryPath + "/")) {
items.push_back(temp);
}
}
else if (includeFiles)
{
temp.path = entry.path();
temp.name = temp.path.substr(temp.path.find_last_of('/') + 1, temp.path.length());
temp.type = Type::FFILE;
items.push_back(temp);
if (!_fileHandler->excludeFolder(directoryPath.substr(0, directoryPath.length())) || !_fileHandler->excludeFile(temp.name)) {
items.push_back(temp);
}
}
}
}

View File

@ -11,9 +11,11 @@
#define FILEBROWSER
#include "fileModel.h"
#include "fileHandler.h"
#include <string>
#include <vector>
#include <memory>
class FileBrowser
{
@ -23,5 +25,7 @@ class FileBrowser
private:
FileBrowser(){};
static std::shared_ptr<FileHandler> _fileHandler;
};
#endif

View File

@ -11,6 +11,8 @@
#include "sqlite3.h"
#include "log.h"
#include "util.h"
#include "fileHandler.h"
#include "webDAV.h"
#include <string>
#include <vector>
@ -18,11 +20,13 @@ using std::string;
SqliteConnector::SqliteConnector(const string &DBpath) : _dbpath(DBpath)
{
_fileHandler = std::shared_ptr<FileHandler>(new FileHandler());
}
SqliteConnector::~SqliteConnector()
{
sqlite3_close(_db);
_fileHandler.reset();
Log::writeInfoLog("closed DB");
}
@ -119,11 +123,13 @@ std::vector<WebDAVItem> SqliteConnector::getItemsChildren(const string &parentPa
int rs;
sqlite3_stmt *stmt = 0;
std::vector<WebDAVItem> items;
std::vector<WebDAVItem> itemsToRemove;
rs = sqlite3_prepare_v2(_db, "SELECT title, localPath, path, size, etag, fileType, lastEditDate, type, state FROM 'metadata' WHERE path=? OR parentPath=? ORDER BY parentPath;", -1, &stmt, 0);
rs = sqlite3_bind_text(stmt, 1, parentPath.c_str(), parentPath.length(), NULL);
rs = sqlite3_bind_text(stmt, 2, parentPath.c_str(), parentPath.length(), NULL);
const int storageLocationLength = (NEXTCLOUD_ROOT_PATH + _fileHandler->getStorageUsername() + "/").length();
while (sqlite3_step(stmt) == SQLITE_ROW)
{
WebDAVItem temp;
@ -144,14 +150,55 @@ std::vector<WebDAVItem> SqliteConnector::getItemsChildren(const string &parentPa
temp.state = FileState::ICLOUD;
}
items.push_back(temp);
string direcotryPath = temp.path;
if (direcotryPath.length() >= storageLocationLength) {
direcotryPath = direcotryPath.substr(storageLocationLength);
}
if (temp.type == Itemtype::IFILE && ( _fileHandler->excludeFolder(direcotryPath) || _fileHandler->excludeFile(temp.title))) {
//The file was previously cached and should be excluded from now on
//TODO Maybe an SQL statement with REGEX match should be executed directly after changing the conifg
itemsToRemove.push_back(temp);
} else if (temp.type == Itemtype::IFOLDER && _fileHandler->excludeFolder(direcotryPath)) {
itemsToRemove.push_back(temp);
}
else {
items.push_back(temp);
}
}
sqlite3_finalize(stmt);
sqlite3_close(_db);
for (WebDAVItem itemD : itemsToRemove) {
if (itemD.type == Itemtype::IFOLDER) {
deleteChildren(itemD.path);
} else {
deleteChild(itemD.path, itemD.title);
}
}
return items;
}
void SqliteConnector::deleteChild(const string &path, const string &title)
{
open();
int rs;
sqlite3_stmt *stmt = 0;
rs = sqlite3_prepare_v2(_db, "DELETE FROM 'metadata' WHERE path = ? AND title = ?", -1, &stmt, 0);
rs = sqlite3_bind_text(stmt, 1, path.c_str(), path.length(), NULL);
rs = sqlite3_bind_text(stmt, 1, title.c_str(), title.length(), NULL);
rs = sqlite3_step(stmt);
if (rs != SQLITE_DONE)
{
Log::writeErrorLog(std::string("An error ocurred trying to delete the item ") + sqlite3_errmsg(_db) + std::string(" (Error Code: ") + std::to_string(rs) + ")");
}
rs = sqlite3_clear_bindings(stmt);
rs = sqlite3_reset(stmt);
}
void SqliteConnector::deleteChildren(const string &parentPath)
{
//TODO missing the onces where parentPath is one folder deeper and also destroyed

View File

@ -12,10 +12,13 @@
#include "webDAVModel.h"
#include "sqlite3.h"
#include "fileHandler.h"
#include <string>
#include <vector>
#include <memory>
class SqliteConnector
{
public:
@ -38,11 +41,15 @@ public:
void deleteChildren(const std::string &parentPath);
void deleteChild(const std::string &path, const std::string &title);
bool saveItemsChildren(const std::vector<WebDAVItem> &children);
private:
std::string _dbpath;
sqlite3 *_db;
std::shared_ptr<FileHandler> _fileHandler;
};
#endif

View File

@ -11,6 +11,7 @@
#include "util.h"
#include "log.h"
#include "eventHandler.h"
#include "fileHandler.h"
#include <string>
#include <experimental/filesystem>
@ -37,9 +38,15 @@ WebDAV::WebDAV()
_password = Util::accessConfig<string>(Action::IReadSecret,"password",{});
_url = Util::accessConfig<string>(Action::IReadString, "url",{});
_ignoreCert = Util::accessConfig<int>(Action::IReadInt, "ignoreCert",{});
_fileHandler = std::shared_ptr<FileHandler>(new FileHandler());
}
}
WebDAV::~WebDAV()
{
_fileHandler.reset();
}
std::vector<WebDAVItem> WebDAV::login(const string &Url, const string &Username, const string &Pass, bool ignoreCert)
{
@ -176,7 +183,20 @@ vector<WebDAVItem> WebDAV::getDataStructure(const string &pathUrl)
tempItem.title = tempItem.title.substr(tempItem.title.find_last_of("/") + 1, tempItem.title.length());
Util::decodeUrl(tempItem.title);
tempItems.push_back(tempItem);
string folderPath = tempItem.path;
string prefix = NEXTCLOUD_ROOT_PATH + _username + "/";
if (tempItem.path.find(prefix) != string::npos) {
folderPath = tempItem.path.substr(prefix.length());
if (tempItem.type == Itemtype::IFILE && folderPath.length() >= tempItem.title.length()) {
folderPath = folderPath.substr(0, folderPath.length() - tempItem.title.length());
}
}
if (tempItem.type == Itemtype::IFILE && ( !_fileHandler->excludeFolder(folderPath) && !_fileHandler->excludeFile(tempItem.title) ))
tempItems.push_back(tempItem);
else if (tempItem.type == Itemtype::IFOLDER && !_fileHandler->excludeFolder(folderPath))
tempItems.push_back(tempItem);
xmlItem = xmlItem.substr(end + endItem.length());
begin = xmlItem.find(beginItem);
}

View File

@ -11,11 +11,14 @@
#define WEBDAV
#include "webDAVModel.h"
#include "fileHandler.h"
#include <string>
#include <vector>
const std::string NEXTCLOUD_ROOT_PATH = "/remote.php/dav/files/";
#include <memory>
const static std::string NEXTCLOUD_ROOT_PATH = "/remote.php/dav/files/";
const std::string NEXTCLOUD_START_PATH = "/remote.php/";
const std::string NEXTCLOUD_PATH = "/mnt/ext1/system/config/nextcloud";
@ -27,6 +30,7 @@ class WebDAV
*
*/
WebDAV();
~WebDAV();
std::vector<WebDAVItem> login(const std::string &Url, const std::string &Username, const std::string &Pass, bool ignoreCert = false);
@ -52,5 +56,7 @@ class WebDAV
std::string _url;
bool _ignoreCert;
std::shared_ptr<FileHandler> _fileHandler;
};
#endif

View File

@ -18,6 +18,7 @@
#include "fileBrowser.h"
#include "fileView.h"
#include "fileModel.h"
#include "fileHandler.h"
#include <experimental/filesystem>
#include <string>
@ -36,6 +37,7 @@ EventHandler::EventHandler()
//create an copy of the eventhandler to handle methods that require static functions
_eventHandlerStatic = std::unique_ptr<EventHandler>(this);
_fileHandler = std::shared_ptr<FileHandler>(new FileHandler());
_menu = std::unique_ptr<MainMenu>(new MainMenu("Nextcloud"));
if (iv_access(CONFIG_PATH.c_str(), W_OK) == 0)
{
@ -203,8 +205,23 @@ void EventHandler::mainMenuHandler(const int index)
Message(ICON_INFORMATION, "Info", "Reload page to see new order method in effect.", 2000);
break;
}
//Select folder
// Exclude and hide files
case 104:
{
if (_fileView != nullptr) {
_currentPath = _fileView->getCurrentEntry().path;
_fileView.reset();
} else {
_currentPath = "";
}
_webDAVView.reset();
FillAreaRect(&_menu->getContentRect(), WHITE);
_excludeFileView = std::unique_ptr<ExcludeFileView>(new ExcludeFileView(_menu->getContentRect()));
break;
}
//Select folder
case 105:
{
_currentPath = _currentPath + ((_currentPath.back() != '/') ? "/nextcloud" : "nextcloud");
@ -232,13 +249,13 @@ void EventHandler::mainMenuHandler(const int index)
break;
}
//Info
case 105:
case 106:
{
Message(ICON_INFORMATION, "Info", "Version 1.02 \n For support please open a ticket at https://github.com/JuanJakobo/Pocketbook-Nextcloud-Client/issues", 1200);
break;
}
//Exit
case 106:
case 107:
CloseApp();
break;
default:
@ -364,6 +381,42 @@ int EventHandler::pointerHandler(const int type, const int par1, const int par2)
return 0;
}
else if (_excludeFileView != nullptr) {
int click = _excludeFileView->excludeClicked(par1, par2);
if (click == 3) {
Util::accessConfig<string>(Action::IWriteString, "ex_extensionList", _excludeFileView->getExtensionList());
Util::accessConfig<string>(Action::IWriteString, "ex_pattern",_excludeFileView->getRegex());
Util::accessConfig<string>(Action::IWriteString, "ex_folderPattern",_excludeFileView->getFolderRegex());
Util::accessConfig<int>(Action::IWriteInt, "ex_invertMatch", _excludeFileView->getInvertMatch());
_excludeFileView.reset();
ShowHourglassForce();
FillAreaRect(&_menu->getContentRect(), WHITE);
if (_currentPath != ""){
vector<FileItem> currentFolder = FileBrowser::getFileStructure(_currentPath,false,true);
_fileView.reset(new FileView(_menu->getContentRect(), currentFolder,1));
} else {
std::vector<WebDAVItem> currentWebDAVItems = _webDAV.getDataStructure(NEXTCLOUD_ROOT_PATH + Util::accessConfig<string>(Action::IReadString,"UUID",{}) + '/');
updateItems(currentWebDAVItems);
drawWebDAVItems(currentWebDAVItems);
}
}
else if (click == -1) {
_excludeFileView.reset();
ShowHourglassForce();
FillAreaRect(&_menu->getContentRect(), WHITE);
if (_currentPath != ""){
vector<FileItem> currentFolder = FileBrowser::getFileStructure(_currentPath,false,true);
_fileView.reset(new FileView(_menu->getContentRect(), currentFolder,1));
} else {
std::vector<WebDAVItem> currentWebDAVItems = _webDAV.getDataStructure(NEXTCLOUD_ROOT_PATH + Util::accessConfig<string>(Action::IReadString,"UUID",{}) + '/');
updateItems(currentWebDAVItems);
drawWebDAVItems(currentWebDAVItems);
}
}
}
//if loginView is shown
else if (_loginView != nullptr)
{
@ -556,6 +609,7 @@ void EventHandler::getLocalFileStructure(std::vector<WebDAVItem> &tempItems)
{
vector<FileItem> currentFolder = FileBrowser::getFileStructure(localPath,true,false);
const int storageLocationLength = _fileHandler->getStorageLocation().length();
for(const FileItem &local : currentFolder)
{
auto p = find_if(tempItems.begin()+1, tempItems.end(), [&] (const WebDAVItem &item) {return item.localPath.compare(local.path) == 0;});
@ -567,16 +621,30 @@ void EventHandler::getLocalFileStructure(std::vector<WebDAVItem> &tempItems)
temp.title = temp.localPath.substr(temp.localPath.find_last_of('/') + 1, temp.localPath.length());
//Log::writeInfoLog(std::to_string(fs::file_size(entry)));
temp.lastEditDate = local.lastEditDate;
string directoryPath = temp.localPath;
if (directoryPath.length() > storageLocationLength) {
directoryPath = directoryPath.substr(storageLocationLength + 1);
}
if(local.type == Type::FFOLDER)
{
if (_fileHandler->excludeFolder(directoryPath + "/")) {
continue;
}
//create new dir in cloud
temp.type = Itemtype::IFOLDER;
}
else
{
//put to cloud
temp.fileType = "File";
temp.type = Itemtype::IFILE;
if (directoryPath.length() > temp.title.length()) {
directoryPath = directoryPath.substr(0, directoryPath.length() - temp.title.length());
}
if (_fileHandler->excludeFolder(directoryPath) || _fileHandler->excludeFile(temp.title))
{
continue;
}
}
tempItems.push_back(temp);
}

View File

@ -15,7 +15,10 @@
#include "webDAVView.h"
#include "loginView.h"
#include "fileView.h"
#include "excludeFileView.h"
#include "sqliteConnector.h"
#include "log.h"
#include "fileHandler.h"
#include <memory>
@ -40,13 +43,17 @@ public:
*/
int eventDistributor(const int type, const int par1, const int par2);
private:
static std::unique_ptr<EventHandler> _eventHandlerStatic;
std::unique_ptr<WebDAVView> _webDAVView;
std::unique_ptr<LoginView> _loginView;
std::unique_ptr<FileView> _fileView;
std::unique_ptr<ExcludeFileView> _excludeFileView;
std::unique_ptr<MainMenu> _menu;
std::shared_ptr<FileHandler> _fileHandler;
ContextMenu _contextMenu = ContextMenu();
WebDAV _webDAV = WebDAV();
SqliteConnector _sqllite = SqliteConnector(DB_PATH);

View File

@ -0,0 +1,138 @@
//------------------------------------------------------------------
// fileHandler.cpp
//
// Author: RPJoshL
// Date: 03.10.2022
//
//-------------------------------------------------------------------
#include "fileHandler.h"
#include "log.h"
#include "util.h"
#include <sstream>
#include <regex>
#include <algorithm>
#include <string>
using std::string;
using std::find;
using std::regex;
std::vector<FileHandler*> FileHandler::_instances;
FileHandler::FileHandler()
{
_instances.push_back(this);
parseConfig(
Util::getConfig<string>("ex_pattern", ""),
Util::getConfig<string>("ex_folderPattern", ""),
Util::getConfig<string>("ex_extensionList", ""),
Util::getConfig<int>("ex_invertMatch", 0)
);
}
void FileHandler::parseConfig(string regex, string folderRegex, string extensions, int invertMatch) {
_extensions.clear();
// split the comma seperated string
if (!extensions.empty()) {
string line;
std::stringstream ss(extensions);
while(getline(ss, line, ',')) {
_extensions.push_back(line);
}
}
// parse the regex only onces
if (!regex.empty()) {
try {
_regex = std::regex(regex);
_useRegex = true;
} catch(std::regex_error err) {
Log::writeErrorLog("Unable to parse regex '" + regex + "' for file: " + err.what());
}
} else {
_useRegex = false;
}
if (!folderRegex.empty()) {
try {
_folderRegex = std::regex(folderRegex);
_useFolderRegex = true;
} catch(std::regex_error err) {
Log::writeErrorLog("Unable to parse regex '" + folderRegex + "' for folder: " + err.what());
}
} else {
_useFolderRegex = false;
}
_invertMatch = invertMatch;
}
FileHandler::~FileHandler()
{
_instances.erase(std::remove(_instances.begin(), _instances.end(), this), _instances.end());
}
bool FileHandler::excludeFile(std::string filename) {
// check for file extensions
if (!_extensions.empty()) {
int indexOfDot = filename.find_last_of(".");
if (indexOfDot != std::string::npos && filename.length() > indexOfDot + 1) {
string extension = filename.substr(filename.find_last_of(".") + 1);
if(std::find(_extensions.begin(),_extensions.end(), extension) != _extensions.end()) {
return !_invertMatch;
}
}
}
if (_useRegex) {
try {
bool t = std::regex_match(filename, _regex) != _invertMatch;
string ta = t ? "true" : "false";
return t;
} catch (std::regex_error err) {
string errM = err.what();
Log::writeErrorLog("Unable to parse regex for file:'" + errM);
}
}
return _invertMatch;
}
bool FileHandler::excludeFolder(std::string folderName) {
folderName = "/" + folderName;
// always display root folder because that can't be matched
if (folderName == "/" || folderName == "//") {
return false;
}
if (_useFolderRegex) {
try {
bool t = std::regex_match(folderName, _folderRegex) != _invertMatch;
return t;
} catch (std::regex_error err) {
string errM = err.what();
Log::writeErrorLog("Unable to parse regex for folder:'" + errM);
}
}
return _invertMatch;
}
void FileHandler::update(string regex, string folderRegex, string extensions, int invertMatch) {
for (FileHandler *handler : _instances) {
handler->parseConfig(regex, folderRegex, extensions, invertMatch);
}
}
string FileHandler::getStorageLocation() {
return Util::accessConfig<string>(Action::IReadString, "storageLocation",{}) + getStorageUsername() + "/";
}
string FileHandler::getStorageUsername() {
return Util::accessConfig<string>(Action::IReadString, "username",{});
}

View File

@ -0,0 +1,43 @@
//------------------------------------------------------------------
// fileHandler.h
//
// Author: RPJoshL
// Date: 03.10.2022
//
//-------------------------------------------------------------------
#ifndef FILEHANDLER
#define FILEHANDLER
#include <regex>
#include <string>
#include <vector>
#include <memory>
class FileHandler
{
public:
FileHandler();
~FileHandler();
bool excludeFile(std::string filename);
bool excludeFolder(std::string foldername);
std::string getStorageLocation();
std::string getStorageUsername();
static void update(std::string regex, std::string folderRegex, std::string extensions, int invertMatch);
private:
std::regex _regex;
std::regex _folderRegex;
// can't use pointers with regex... Why? -> unable to null check
bool _useRegex = false;
bool _useFolderRegex = false;
std::vector<std::string> _extensions;
bool _invertMatch;
void parseConfig(std::string regex, std::string folderRegex, std::string extensions, int invertMatch);
static std::vector<FileHandler *> _instances;
};
#endif

View File

@ -42,6 +42,7 @@ MainMenu::~MainMenu()
free(_menu);
free(_logout);
free(_sortBy);
free(_excludeFiles);
free(_info);
free(_exit);
free(_chooseFolder);
@ -61,14 +62,15 @@ int MainMenu::createMenu(bool filePicker, bool loggedIn, iv_menuhandler handler)
//show logged in
{loggedIn ? (short)ITEM_ACTIVE : (short)ITEM_HIDDEN, 101, _syncFolder, NULL},
{loggedIn ? (short)ITEM_ACTIVE : (short)ITEM_HIDDEN, 103, _sortBy, NULL},
{loggedIn ? (short)ITEM_ACTIVE : (short)ITEM_HIDDEN, 104, _excludeFiles, NULL},
//show if filePicker is shown
{filePicker ? (short)ITEM_ACTIVE : (short)ITEM_HIDDEN, 104, _chooseFolder, NULL},
{filePicker ? (short)ITEM_ACTIVE : (short)ITEM_HIDDEN, 105, _chooseFolder, NULL},
//show always
{ITEM_ACTIVE, 105, _info, NULL},
{ITEM_ACTIVE, 106, _info, NULL},
//show logged in
{loggedIn ? (short)ITEM_ACTIVE : (short)ITEM_HIDDEN, 102, _logout, NULL},
//show always
{ITEM_ACTIVE, 106, _exit, NULL},
{ITEM_ACTIVE, 107, _exit, NULL},
{0, 0, NULL, NULL}};
OpenMenu(mainMenu, 0, _panelMenuBeginX, _panelMenuBeginY, handler);

View File

@ -55,6 +55,7 @@ private:
char *_logout = strdup("Logout");
char *_chooseFolder = strdup("Create here");
char *_sortBy = strdup("Order items by");
char *_excludeFiles = strdup("Exclude and hide files");
char *_info = strdup("Info");
char *_exit = strdup("Close App");

View File

@ -0,0 +1,200 @@
//------------------------------------------------------------------
// excludeFileView.cpp
//
// Author: RPJoshL
// Date: 03.10.2022
//
//-------------------------------------------------------------------
#include "excludeFileView.h"
#include "log.h"
#include "util.h"
#include <regex>
using std::string;
std::shared_ptr<ExcludeFileView> ExcludeFileView::_excludeFileViewStatic;
ExcludeFileView::ExcludeFileView(const irect &contentRect): _contentRect(contentRect)
{
_excludeFileViewStatic.reset(this);
_extensionList = Util::getConfig<string>("ex_extensionList", "");
_regex = Util::getConfig<string>("ex_pattern", "");
_folderRegex = Util::getConfig<string>("ex_folderPattern", "");
_invertMatch = Util::getConfig<int>("ex_invertMatch",0);
int contentHeight = contentRect.h / 2;
int contentWidth = _contentRect.w * 0.9;
int checkBoxWidth = _contentRect.w * 0.1;
int beginY = 0.4 * contentHeight;
int beginX = (_contentRect.w - contentWidth) / 2;
int contents = contentHeight / 7;
_fontHeight = contents / 2;
_font = OpenFont("LiberationMono", _fontHeight, FONT_STD);
SetFont(_font, BLACK);
FillAreaRect(&_contentRect, WHITE);
_extensionListButton = iRect(beginX, beginY, contentWidth, contents, ALIGN_CENTER);
DrawTextRect(_extensionListButton.x, _extensionListButton.y - _fontHeight - _fontHeight/2, _extensionListButton.w, _extensionListButton.h, "Extensions:", ALIGN_LEFT);
DrawString(_extensionListButton.x, _extensionListButton.y, _extensionList.c_str());
DrawRect(_extensionListButton.x - 1, _extensionListButton.y - 1, _extensionListButton.w + 2, _extensionListButton.h + 2, BLACK);
_regexButton = iRect(beginX, beginY + 2 * contents, contentWidth, contents, ALIGN_CENTER);
DrawTextRect(_regexButton.x, _regexButton.y - _fontHeight - _fontHeight/3, _regexButton.w, _regexButton.h, "File-Regex:", ALIGN_LEFT);
DrawString(_regexButton.x, _regexButton.y, _regex.c_str());
DrawRect(_regexButton.x - 1, _regexButton.y - 1, _regexButton.w + 2, _regexButton.h + 2, BLACK);
_folderRegexButton = iRect(beginX, beginY + 4 * contents, contentWidth, contents, ALIGN_CENTER);
DrawTextRect(_folderRegexButton.x, _folderRegexButton.y - _fontHeight - _fontHeight/3, _folderRegexButton.w, _folderRegexButton.h, "Folder-Regex:", ALIGN_LEFT);
DrawString(_folderRegexButton.x, _folderRegexButton.y, _folderRegex.c_str());
DrawRect(_folderRegexButton.x - 1, _folderRegexButton.y - 1, _folderRegexButton.w + 2, _folderRegexButton.h + 2, BLACK);
_invertMatchButton = iRect(_contentRect.w - 2 * checkBoxWidth, beginY + 6 * contents, checkBoxWidth, contents, ALIGN_CENTER);
DrawTextRect(beginX, _invertMatchButton.y, contentWidth, _invertMatchButton.h, "Only include matching:", ALIGN_LEFT);
DrawRect(_invertMatchButton.x - 1, _invertMatchButton.y - 1, _invertMatchButton.w + 2, _invertMatchButton.h + 2, BLACK);
if (_invertMatch) {
FillArea(_invertMatchButton.x - 1, _invertMatchButton.y - 1, _invertMatchButton.w + 2, _invertMatchButton.h + 2, BLACK);
}
_saveButton = iRect(beginX, beginY + 8 * contents, contentWidth / 2 - 20, contents, ALIGN_CENTER);
FillAreaRect(&_saveButton, BLACK);
SetFont(_font, WHITE);
DrawTextRect2(&_saveButton, "Save");
PartialUpdate(_contentRect.x, _contentRect.y, _contentRect.w, _contentRect.h);
_cancelButton = iRect(beginX + contentWidth / 2, beginY + 8 * contents, contentWidth / 2 - 20, contents, ALIGN_CENTER);
FillAreaRect(&_cancelButton, BLACK);
SetFont(_font, WHITE);
DrawTextRect2(&_cancelButton, "Cancel");
PartialUpdate(_contentRect.x, _contentRect.y, _contentRect.w, _contentRect.h);
}
ExcludeFileView::~ExcludeFileView()
{
CloseFont(_font);
}
int ExcludeFileView::excludeClicked(int x, int y)
{
_temp = "";
if (IsInRect(x, y, &_extensionListButton))
{
_target = ExcludeFileKeyboardTarget::IEXTENSIONS;
if (!_extensionList.empty())
_temp = _extensionList;
_temp.resize(EXCLUDE_FILE_KEYBOARD_STRING_LENGHT);
OpenKeyboard("docx,pdf,sdr", &_temp[0], EXCLUDE_FILE_KEYBOARD_STRING_LENGHT - 1, KBD_NORMAL, &keyboardHandlerStatic);
return 1;
}
else if (IsInRect(x, y, &_regexButton))
{
_target = ExcludeFileKeyboardTarget::IREGEX;
if (!_regex.empty())
_temp = _regex;
_temp.resize(EXCLUDE_FILE_KEYBOARD_STRING_LENGHT);
OpenKeyboard("Pre.*Post\\.pdf", &_temp[0], EXCLUDE_FILE_KEYBOARD_STRING_LENGHT, KBD_NORMAL, &keyboardHandlerStatic);
return 1;
}
else if (IsInRect(x, y, &_folderRegexButton))
{
_target = ExcludeFileKeyboardTarget::IFOLDERREGEX;
if (!_folderRegex.empty())
_temp = _folderRegex;
_temp.resize(EXCLUDE_FILE_KEYBOARD_STRING_LENGHT);
OpenKeyboard("/root/.*/test/", &_temp[0], EXCLUDE_FILE_KEYBOARD_STRING_LENGHT, KBD_NORMAL, &keyboardHandlerStatic);
return 1;
}
else if (IsInRect(x, y, &_invertMatchButton))
{
_invertMatch = !_invertMatch;
FillAreaRect(&_invertMatchButton, WHITE);
if(_invertMatch)
FillArea(_invertMatchButton.x - 1, _invertMatchButton.y - 1, _invertMatchButton.w + 2, _invertMatchButton.h + 2, BLACK);
else
DrawRect(_invertMatchButton.x - 1, _invertMatchButton.y - 1, _invertMatchButton.w + 2, _invertMatchButton.h + 2, BLACK);
PartialUpdate(_invertMatchButton.x, _invertMatchButton.y, _invertMatchButton.w, _invertMatchButton.h);
return 1;
}
else if (IsInRect(x, y, &_saveButton))
{
if (!_regex.empty()) {
try {
std::regex regP = std::regex(_regex);
} catch(std::regex_error err) {
Log::writeErrorLog("Unable to parse regex '" + _regex + "': " + err.what());
Message(ICON_ERROR, "Error", "Unable to parse the regex for the files.", 1200);
return 1;
} catch(...) {
Message(ICON_ERROR, "Error", "Unknown error occured while parsing the regex for the files.", 1200);
return 1;
}
}
if (!_folderRegex.empty()) {
try {
std::regex regP = std::regex(_folderRegex);
} catch(std::regex_error err) {
Log::writeErrorLog("Unable to parse regex for folder '" + _folderRegex + "': " + err.what());
Message(ICON_ERROR, "Error", "Unable to parse the regex for the folders.", 1200);
return 1;
} catch(...) {
Message(ICON_ERROR, "Error", "Unknown error occured while parsing the regex for the folders.", 1200);
return 1;
}
}
FileHandler::update(_regex, _folderRegex, _extensionList, _invertMatch);
return 3;
}
else if (IsInRect(x, y, &_cancelButton))
{
return -1;
}
return 0;
}
void ExcludeFileView::keyboardHandlerStatic(char *text)
{
if (_excludeFileViewStatic != nullptr) {
_excludeFileViewStatic->keyboardHandler(text);
}
}
void ExcludeFileView::keyboardHandler(char *text)
{
if (!text)
return;
string s(text);
if (s.empty())
return;
if (_target == ExcludeFileKeyboardTarget::IEXTENSIONS)
{
_extensionList = s.c_str();
FillAreaRect(&_extensionListButton, WHITE);
DrawTextRect2(&_extensionListButton, s.c_str());
}
else if (_target == ExcludeFileKeyboardTarget::IREGEX)
{
_regex = s.c_str();
FillAreaRect(&_regexButton, WHITE);
DrawTextRect2(&_regexButton, s.c_str());
}
else if (_target == ExcludeFileKeyboardTarget::IFOLDERREGEX)
{
_folderRegex = s.c_str();
FillAreaRect(&_folderRegexButton, WHITE);
DrawTextRect2(&_folderRegexButton, s.c_str());
}
}

View File

@ -0,0 +1,88 @@
//------------------------------------------------------------------
// excludeFileView.h
//
// Author: RPJoshL
// Date: 03.10.2022
//
//-------------------------------------------------------------------
#include <string>
#ifndef EXCLUDEFILEVIEW
#define EXCLUDEFILEVIEW
using std::string;
#include "inkview.h"
#include <string>
#include <memory>
enum class ExcludeFileKeyboardTarget
{
IEXTENSIONS,
IREGEX,
IFOLDERREGEX
};
const int EXCLUDE_FILE_KEYBOARD_STRING_LENGHT = 90;
class ExcludeFileView
{
public:
/**
* Draws the excludeFileView including an textfield with Extension list and regex, checkbox for inverting the "excluding" and the
* save and cancel button inside the contentRect
*
* @param contentRect area where the excludeFileView shall be drawn
*/
ExcludeFileView(const irect &contentRect);
~ExcludeFileView();
/**
* Checks which part of the view is shown and reacts accordingly
*
* @param x x-coordinate
* @param y y-coordinate
* @return int if event has been handled. Returns 2 if save has been clicked and all items are set, or -1 when cancel was fired
*/
int excludeClicked(int x, int y);
std::string getExtensionList() { return _extensionList; };
std::string getRegex() { return _regex; };
std::string getFolderRegex() { return _folderRegex; };
int getInvertMatch() { return _invertMatch; };
private:
static std::shared_ptr<ExcludeFileView> _excludeFileViewStatic;
int _fontHeight;
ifont *_font;
const irect _contentRect;
irect _saveButton;
irect _cancelButton;
irect _extensionListButton;
irect _regexButton;
irect _invertMatchButton;
irect _folderRegexButton;
ExcludeFileKeyboardTarget _target;
std::string _extensionList;
std::string _regex;
std::string _folderRegex;
bool _invertMatch = false;
std::string _temp;
/**
* Functions needed to call C function, handles the keyboard
*
* @param text text that has been typed in by the user
*/
static void keyboardHandlerStatic(char *text);
/**
* Called by the static method and saves and writes the input from the user to the screen
*
* @param text text that has been typed in by the user
*/
void keyboardHandler(char *text);
};
#endif

View File

@ -108,6 +108,35 @@ public:
return returnValue;
}
/**
* Reads the value from the config file
* T defines the type of the item (e.g. int, string etc.)
*
* @param name of the requested item
* @param defaultValue value to return when no was found
*
* @return value from config
*/
template <typename T>
static T getConfig(string name, T defaultValue)
{
iconfigedit *temp = nullptr;
iconfig *config = OpenConfig(CONFIG_PATH.c_str(), temp);
T returnValue;
if constexpr(std::is_same<T, std::string>::value)
{
returnValue = ReadString(config, name.c_str(), ((std::string) defaultValue).c_str());
}
else if constexpr(std::is_same<T, int>::value)
{
returnValue = ReadInt(config, name.c_str(), defaultValue);
}
CloseConfig(config);
return returnValue;
}
/**
* Returns an integer representing the download progress
*