diff --git a/krusader/FileSystem/krquery.cpp b/krusader/FileSystem/krquery.cpp index e3cc4425..fbedf07d 100644 --- a/krusader/FileSystem/krquery.cpp +++ b/krusader/FileSystem/krquery.cpp @@ -1,775 +1,786 @@ /*************************************************************************** krquery.cpp ------------------- copyright : (C) 2001 by Shie Erlich & Rafi Yanai email : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD S o u r c e F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "krquery.h" // QtCore #include #include #include #include #include #include #include #include #include "../Archive/krarchandler.h" #include "fileitem.h" #include "filesystem.h" #include "krpermhandler.h" #define STATUS_SEND_DELAY 250 #define MAX_LINE_LEN 1000 // set the defaults KRQuery::KRQuery() : QObject(), matchesCaseSensitive(true), bNull(true), contain(QString()), containCaseSensetive(true), containWholeWord(false), containRegExp(false), minSize(0), maxSize(0), newerThen(0), olderThen(0), owner(QString()), group(QString()), perm(QString()), type(QString()), inArchive(false), recurse(true), followLinksP(true), receivedBuffer(0), receivedBufferLen(0), processEventsConnected(0), codec(QTextCodec::codecForLocale()) { QChar ch = '\n'; QTextCodec::ConverterState state(QTextCodec::IgnoreHeader); encodedEnterArray = codec->fromUnicode(&ch, 1, &state); encodedEnter = encodedEnterArray.data(); encodedEnterLen = encodedEnterArray.size(); } // set the defaults KRQuery::KRQuery(const QString &name, bool matchCase) : QObject(), bNull(true), contain(QString()), containCaseSensetive(true), containWholeWord(false), containRegExp(false), minSize(0), maxSize(0), newerThen(0), olderThen(0), owner(QString()), group(QString()), perm(QString()), type(QString()), inArchive(false), recurse(true), followLinksP(true), receivedBuffer(0), receivedBufferLen(0), processEventsConnected(0), codec(QTextCodec::codecForLocale()) { QChar ch = '\n'; QTextCodec::ConverterState state(QTextCodec::IgnoreHeader); encodedEnterArray = codec->fromUnicode(&ch, 1, &state); encodedEnter = encodedEnterArray.data(); encodedEnterLen = encodedEnterArray.size(); setNameFilter(name, matchCase); } KRQuery::KRQuery(const KRQuery &that) : QObject(), receivedBuffer(0), receivedBufferLen(0), processEventsConnected(0) { *this = that; } KRQuery::~KRQuery() { if (receivedBuffer) delete[] receivedBuffer; receivedBuffer = 0; } KRQuery &KRQuery::operator=(const KRQuery &old) { matches = old.matches; excludes = old.excludes; includedDirs = old.includedDirs; excludedDirs = old.excludedDirs; matchesCaseSensitive = old.matchesCaseSensitive; bNull = old.bNull; contain = old.contain; containCaseSensetive = old.containCaseSensetive; containWholeWord = old.containWholeWord; containRegExp = old.containRegExp; minSize = old.minSize; maxSize = old.maxSize; newerThen = old.newerThen; olderThen = old.olderThen; owner = old.owner; group = old.group; perm = old.perm; type = old.type; customType = old.customType; inArchive = old.inArchive; recurse = old.recurse; followLinksP = old.followLinksP; whereToSearch = old.whereToSearch; + excludedFolderNames = old.excludedFolderNames; whereNotToSearch = old.whereNotToSearch; origFilter = old.origFilter; codec = old.codec; encodedEnterArray = old.encodedEnterArray; encodedEnter = encodedEnterArray.data(); encodedEnterLen = encodedEnterArray.size(); return *this; } void KRQuery::load(KConfigGroup cfg) { *this = KRQuery(); // reset parameters first if (cfg.readEntry("IsNull", true)) return; #define LOAD(key, var) (var = cfg.readEntry(key, var)) LOAD("Matches", matches); LOAD("Excludes", excludes); LOAD("IncludedDirs", includedDirs); LOAD("ExcludedDirs", excludedDirs); LOAD("MatchesCaseSensitive", matchesCaseSensitive); LOAD("Contain", contain); LOAD("ContainCaseSensetive", containCaseSensetive); LOAD("ContainWholeWord", containWholeWord); LOAD("ContainRegExp", containRegExp); LOAD("MinSize", minSize); LOAD("MaxSize", maxSize); newerThen = QDateTime::fromString( cfg.readEntry("NewerThan", QDateTime::fromTime_t(newerThen).toString())) .toTime_t(); olderThen = QDateTime::fromString( cfg.readEntry("OlderThan", QDateTime::fromTime_t(olderThen).toString())) .toTime_t(); LOAD("Owner", owner); LOAD("Group", group); LOAD("Perm", perm); LOAD("Type", type); LOAD("CustomType", customType); LOAD("InArchive", inArchive); LOAD("Recurse", recurse); LOAD("FollowLinks", followLinksP); // KF5 TODO? // LOAD("WhereToSearch", whereToSearch); // LOAD("WhereNotToSearch", whereNotToSearch); LOAD("OrigFilter", origFilter); codec = QTextCodec::codecForName(cfg.readEntry("Codec", codec->name())); if (!codec) codec = QTextCodec::codecForLocale(); LOAD("EncodedEnterArray", encodedEnterArray); encodedEnter = encodedEnterArray.data(); encodedEnterLen = encodedEnterArray.size(); #undef LOAD bNull = false; } void KRQuery::save(KConfigGroup cfg) { cfg.writeEntry("IsNull", bNull); if (bNull) return; cfg.writeEntry("Matches", matches); cfg.writeEntry("Excludes", excludes); cfg.writeEntry("IncludedDirs", includedDirs); cfg.writeEntry("ExcludedDirs", excludedDirs); cfg.writeEntry("MatchesCaseSensitive", matchesCaseSensitive); cfg.writeEntry("Contain", contain); cfg.writeEntry("ContainCaseSensetive", containCaseSensetive); cfg.writeEntry("ContainWholeWord", containWholeWord); cfg.writeEntry("ContainRegExp", containRegExp); cfg.writeEntry("MinSize", minSize); cfg.writeEntry("MaxSize", maxSize); cfg.writeEntry("NewerThan", QDateTime::fromTime_t(newerThen).toString()); cfg.writeEntry("OlderThan", QDateTime::fromTime_t(olderThen).toString()); cfg.writeEntry("Owner", owner); cfg.writeEntry("Group", group); cfg.writeEntry("Perm", perm); cfg.writeEntry("Type", type); cfg.writeEntry("CustomType", customType); cfg.writeEntry("InArchive", inArchive); cfg.writeEntry("Recurse", recurse); cfg.writeEntry("FollowLinks", followLinksP); // KF5 TODO? // cfg.writeEntry("WhereToSearch", whereToSearch); // cfg.writeEntry("WhereNotToSearch", whereNotToSearch); cfg.writeEntry("OrigFilter", origFilter); cfg.writeEntry("Codec", codec->name()); cfg.writeEntry("EncodedEnterArray", encodedEnterArray); cfg.writeEntry("EncodedEnter", encodedEnter); cfg.writeEntry("EncodedEnterLen", encodedEnterLen); } void KRQuery::connectNotify(const QMetaMethod &signal) { if (signal == QMetaMethod::fromSignal(&KRQuery::processEvents)) processEventsConnected++; } void KRQuery::disconnectNotify(const QMetaMethod &signal) { if (signal == QMetaMethod::fromSignal(&KRQuery::processEvents)) processEventsConnected--; } bool KRQuery::checkPerm(QString filePerm) const { for (int i = 0; i < 9; ++i) if (perm[i] != '?' && perm[i] != filePerm[i + 1]) return false; return true; } bool KRQuery::checkType(QString mime) const { if (type == mime) return true; if (type == i18n("Archives")) return KRarcHandler::arcSupported(mime); if (type == i18n("Folders")) return mime.contains("directory"); if (type == i18n("Image Files")) return mime.contains("image/"); if (type == i18n("Text Files")) return mime.contains("text/"); if (type == i18n("Video Files")) return mime.contains("video/"); if (type == i18n("Audio Files")) return mime.contains("audio/"); if (type == i18n("Custom")) return customType.contains(mime); return false; } bool KRQuery::match(const QString &name) const { return matchCommon(name, matches, excludes); } bool KRQuery::matchDirName(const QString &name) const { return matchCommon(name, includedDirs, excludedDirs); } bool KRQuery::matchCommon(const QString &nameIn, const QStringList &matchList, const QStringList &excludeList) const { if (excludeList.count() == 0 && matchList.count() == 0) /* true if there's no match condition */ return true; QString name(nameIn); int ndx = nameIn.lastIndexOf('/'); // virtual filenames may contain '/' if (ndx != -1) // but the end of the filename is OK name = nameIn.mid(ndx + 1); for (int i = 0; i < excludeList.count(); ++i) { if (QRegExp(excludeList[i], matchesCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard) .exactMatch(name)) return false; } if (matchList.count() == 0) return true; for (int i = 0; i < matchList.count(); ++i) { if (QRegExp(matchList[i], matchesCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard) .exactMatch(name)) return true; } return false; } bool KRQuery::match(FileItem *item) const { if (item->isDir() && !matchDirName(item->getName())) return false; // see if the name matches if (!match(item->getName())) return false; // checking the mime if (!type.isEmpty() && !checkType(item->getMime())) return false; // check that the size fit KIO::filesize_t size = item->getSize(); if (minSize && size < minSize) return false; if (maxSize && size > maxSize) return false; // check the time frame time_t mtime = item->getTime_t(); if (olderThen && mtime > olderThen) return false; if (newerThen && mtime < newerThen) return false; // check owner name if (!owner.isEmpty() && item->getOwner() != owner) return false; // check group name if (!group.isEmpty() && item->getGroup() != group) return false; // check permission if (!perm.isEmpty() && !checkPerm(item->getPerm())) return false; if (!contain.isEmpty()) { if ((totalBytes = item->getSize()) == 0) totalBytes++; // sanity receivedBytes = 0; if (receivedBuffer) delete receivedBuffer; receivedBuffer = 0; receivedBufferLen = 0; fileName = item->getName(); timer.start(); // search locally if (item->getUrl().isLocalFile()) { return containsContent(item->getUrl().path()); } // search remotely if (processEventsConnected == 0) { return false; } return containsContent(item->getUrl()); } return true; } // takes the string and adds BOLD to it, so that when it is displayed, // the grepped text will be bold void fixFoundTextForDisplay(QString &haystack, int start, int length) { QString before = haystack.left(start); QString text = haystack.mid(start, length); QString after = haystack.mid(start + length); before.replace('&', "&"); before.replace('<', "<"); before.replace('>', ">"); text.replace('&', "&"); text.replace('<', "<"); text.replace('>', ">"); after.replace('&', "&"); after.replace('<', "<"); after.replace('>', ">"); haystack = ("" + before + "" + text + "" + after + ""); } bool KRQuery::checkBuffer(const char *data, int len) const { bool result = false; char *mergedBuffer = new char[len + receivedBufferLen]; if (receivedBufferLen) memcpy(mergedBuffer, receivedBuffer, receivedBufferLen); if (len) memcpy(mergedBuffer + receivedBufferLen, data, len); int maxLen = len + receivedBufferLen; int maxBuffer = maxLen - encodedEnterLen; int lastLinePosition = 0; for (int enterIndex = 0; enterIndex < maxBuffer; enterIndex++) { if (memcmp(mergedBuffer + enterIndex, encodedEnter, encodedEnterLen) == 0) { QString str = codec->toUnicode(mergedBuffer + lastLinePosition, enterIndex + encodedEnterLen - lastLinePosition); if (str.endsWith('\n')) { str.chop(1); result = result || checkLine(str); lastLinePosition = enterIndex + encodedEnterLen; enterIndex = lastLinePosition; continue; } } } if (maxLen - lastLinePosition > MAX_LINE_LEN || len == 0) { QString str = codec->toUnicode(mergedBuffer + lastLinePosition, maxLen - lastLinePosition); result = result || checkLine(str); lastLinePosition = maxLen; } delete[] receivedBuffer; receivedBuffer = 0; receivedBufferLen = maxLen - lastLinePosition; if (receivedBufferLen) { receivedBuffer = new char[receivedBufferLen]; memcpy(receivedBuffer, mergedBuffer + lastLinePosition, receivedBufferLen); } delete[] mergedBuffer; return result; } bool KRQuery::checkLine(const QString &line, bool backwards) const { if (containRegExp) { QRegExp rexp(contain, containCaseSensetive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::RegExp); int ndx = backwards ? rexp.lastIndexIn(line) : rexp.indexIn(line); bool result = ndx >= 0; if (result) fixFoundTextForDisplay(lastSuccessfulGrep = line, lastSuccessfulGrepMatchIndex = ndx, lastSuccessfulGrepMatchLength = rexp.matchedLength()); return result; } int ndx = backwards ? -1 : 0; if (line.isNull()) return false; if (containWholeWord) { while ((ndx = (backwards) ? line.lastIndexOf(contain, ndx, containCaseSensetive ? Qt::CaseSensitive : Qt::CaseInsensitive) : line.indexOf(contain, ndx, containCaseSensetive ? Qt::CaseSensitive : Qt::CaseInsensitive)) != -1) { QChar before = '\n'; QChar after = '\n'; if (ndx > 0) before = line.at(ndx - 1); if (ndx + contain.length() < line.length()) after = line.at(ndx + contain.length()); if (!before.isLetterOrNumber() && !after.isLetterOrNumber() && after != '_' && before != '_') { lastSuccessfulGrep = line; fixFoundTextForDisplay(lastSuccessfulGrep, lastSuccessfulGrepMatchIndex = ndx, lastSuccessfulGrepMatchLength = contain.length()); return true; } if (backwards) ndx -= line.length() + 1; else ndx++; } } else if ((ndx = (backwards) ? line.lastIndexOf(contain, -1, containCaseSensetive ? Qt::CaseSensitive : Qt::CaseInsensitive) : line.indexOf(contain, 0, containCaseSensetive ? Qt::CaseSensitive : Qt::CaseInsensitive)) != -1) { lastSuccessfulGrep = line; fixFoundTextForDisplay(lastSuccessfulGrep, lastSuccessfulGrepMatchIndex = ndx, lastSuccessfulGrepMatchLength = contain.length()); return true; } return false; } bool KRQuery::containsContent(QString file) const { QFile qf(file); if (!qf.open(QIODevice::ReadOnly)) return false; char buffer[1440]; // 2k buffer while (!qf.atEnd()) { int bytes = qf.read(buffer, sizeof(buffer)); if (bytes <= 0) break; receivedBytes += bytes; if (checkBuffer(buffer, bytes)) return true; if (checkTimer()) { bool stopped = false; emit((KRQuery *)this)->processEvents(stopped); if (stopped) return false; } } if (checkBuffer(buffer, 0)) return true; lastSuccessfulGrep.clear(); // nothing was found return false; } bool KRQuery::containsContent(QUrl url) const { KIO::TransferJob *contentReader = KIO::get(url, KIO::NoReload, KIO::HideProgressInfo); connect(contentReader, &KIO::TransferJob::data, this, &KRQuery::containsContentData); connect(contentReader, &KIO::Job::result, this, &KRQuery::containsContentFinished); busy = true; containsContentResult = false; bool stopped = false; while (busy && !stopped) { checkTimer(); emit((KRQuery *)this)->processEvents(stopped); } if (busy) { contentReader->kill(KJob::EmitResult); busy = false; } return containsContentResult; } void KRQuery::containsContentData(KIO::Job *job, const QByteArray &array) { receivedBytes += array.size(); if (checkBuffer(array.data(), array.size())) { containsContentResult = true; containsContentFinished(job); job->kill(KJob::EmitResult); return; } checkTimer(); } void KRQuery::containsContentFinished(KJob *) { busy = false; } bool KRQuery::checkTimer() const { if (timer.elapsed() >= STATUS_SEND_DELAY) { int pcnt = (int)(100. * (double)receivedBytes / (double)totalBytes + .5); QString message = i18nc("%1=filename, %2=percentage", "Searching content of '%1' (%2%)", fileName, pcnt); timer.start(); emit((KRQuery *)this)->status(message); return true; } return false; } QStringList KRQuery::split(QString str) { QStringList list; int splitNdx = 0; int startNdx = 0; bool quotation = false; while (splitNdx < str.length()) { if (str[splitNdx] == '"') quotation = !quotation; if (!quotation && str[splitNdx] == ' ') { QString section = str.mid(startNdx, splitNdx - startNdx); startNdx = splitNdx + 1; if (section.startsWith('\"') && section.endsWith('\"') && section.length() >= 2) section = section.mid(1, section.length() - 2); if (!section.isEmpty()) list.append(section); } splitNdx++; } if (startNdx < splitNdx) { QString section = str.mid(startNdx, splitNdx - startNdx); if (section.startsWith('\"') && section.endsWith('\"') && section.length() >= 2) section = section.mid(1, section.length() - 2); if (!section.isEmpty()) list.append(section); } return list; } void KRQuery::setNameFilter(const QString &text, bool cs) { bNull = false; matchesCaseSensitive = cs; origFilter = text; QString matchText = text; QString excludeText; int excludeNdx = 0; bool quotationMark = 0; while (excludeNdx < matchText.length()) { if (matchText[excludeNdx] == '"') quotationMark = !quotationMark; if (!quotationMark) { if (matchText[excludeNdx] == '|') break; } excludeNdx++; } if (excludeNdx < matchText.length()) { excludeText = matchText.mid(excludeNdx + 1).trimmed(); matchText.truncate(excludeNdx); matchText = matchText.trimmed(); if (matchText.isEmpty()) matchText = '*'; } int i; matches = split(matchText); includedDirs.clear(); for (i = 0; i < matches.count();) { if (matches[i].endsWith('/')) { includedDirs.push_back(matches[i].left(matches[i].length() - 1)); matches.removeAll(matches.at(i)); continue; } if (!matches[i].contains("*") && !matches[i].contains("?")) matches[i] = '*' + matches[i] + '*'; i++; } excludes = split(excludeText); excludedDirs.clear(); for (i = 0; i < excludes.count();) { if (excludes[i].endsWith('/')) { excludedDirs.push_back(excludes[i].left(excludes[i].length() - 1)); excludes.removeAll(excludes.at(i)); continue; } if (!excludes[i].contains("*") && !excludes[i].contains("?")) excludes[i] = '*' + excludes[i] + '*'; i++; } } void KRQuery::setContent(const QString &content, bool cs, bool wholeWord, QString encoding, bool regExp) { bNull = false; contain = content; containCaseSensetive = cs; containWholeWord = wholeWord; containRegExp = regExp; if (encoding.isEmpty()) codec = QTextCodec::codecForLocale(); else { codec = QTextCodec::codecForName(encoding.toLatin1()); if (codec == 0) codec = QTextCodec::codecForLocale(); } QChar ch = '\n'; QTextCodec::ConverterState state(QTextCodec::IgnoreHeader); encodedEnterArray = codec->fromUnicode(&ch, 1, &state); encodedEnter = encodedEnterArray.data(); encodedEnterLen = encodedEnterArray.size(); } void KRQuery::setMinimumFileSize(KIO::filesize_t minimumSize) { bNull = false; minSize = minimumSize; } void KRQuery::setMaximumFileSize(KIO::filesize_t maximumSize) { bNull = false; maxSize = maximumSize; } void KRQuery::setNewerThan(time_t time) { bNull = false; newerThen = time; } void KRQuery::setOlderThan(time_t time) { bNull = false; olderThen = time; } void KRQuery::setOwner(const QString &ownerIn) { bNull = false; owner = ownerIn; } void KRQuery::setGroup(const QString &groupIn) { bNull = false; group = groupIn; } void KRQuery::setPermissions(const QString &permIn) { bNull = false; perm = permIn; } void KRQuery::setMimeType(const QString &typeIn, QStringList customList) { bNull = false; type = typeIn; customType = customList; } bool KRQuery::isExcluded(const QUrl &url) { - for (int i = 0; i < whereNotToSearch.count(); ++i) - if (whereNotToSearch[i].isParentOf(url) || - url.matches(whereNotToSearch[i], QUrl::StripTrailingSlash)) + for (QUrl &item : whereNotToSearch) + if (item.isParentOf(url) || url.matches(item, QUrl::StripTrailingSlash)) return true; - if (!matchDirName(url.fileName())) + // Exclude folder names that are configured in settings + QString filename = url.fileName(); + for (QString &item : excludedFolderNames) + if (filename == item) + return true; + + if (!matchDirName(filename)) return true; return false; } void KRQuery::setSearchInDirs(const QList &urls) { whereToSearch.clear(); for (int i = 0; i < urls.count(); ++i) { QString url = urls[i].url(); QUrl completed = QUrl::fromUserInput(KUrlCompletion::replacedPath(url, true, true), QString(), QUrl::AssumeLocalFile); whereToSearch.append(completed); } } void KRQuery::setDontSearchInDirs(const QList &urls) { whereNotToSearch.clear(); for (int i = 0; i < urls.count(); ++i) { QString url = urls[i].url(); QUrl completed = QUrl::fromUserInput(KUrlCompletion::replacedPath(url, true, true), QString(), QUrl::AssumeLocalFile); whereNotToSearch.append(completed); } } +void KRQuery::setExcludeFolderNames(const QStringList &paths) +{ + excludedFolderNames.clear(); + excludedFolderNames.append(paths); +} diff --git a/krusader/FileSystem/krquery.h b/krusader/FileSystem/krquery.h index 393b39e7..eee78b4c 100644 --- a/krusader/FileSystem/krquery.h +++ b/krusader/FileSystem/krquery.h @@ -1,232 +1,237 @@ /*************************************************************************** krquery.h ------------------- copyright : (C) 2001 by Shie Erlich & Rafi Yanai email : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD H e a d e r F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef KRQUERY_H #define KRQUERY_H // QtCore #include #include #include #include #include class QTextCodec; class FileItem; /** * @brief A search query for files * * Can be used for finding or selecting files and folders by multiple limiting search criteria */ class KRQuery : public QObject { Q_OBJECT public: // null query KRQuery(); // query only with name filter explicit KRQuery(const QString &name, bool matchCase = true); // copy constructor KRQuery(const KRQuery &); // let operator KRQuery &operator=(const KRQuery &); // destructor virtual ~KRQuery(); // load parameters from config void load(KConfigGroup cfg); // save parameters to config void save(KConfigGroup cfg); // matching a file with the query bool match(FileItem *file) const; // checks if the given fileItem object matches the conditions // matching a name with the query bool match(const QString &name) const; // matching the filename only // matching the name of the directory bool matchDirName(const QString &name) const; // sets the text for name filtering void setNameFilter(const QString &text, bool cs = true); // returns the current filter mask const QString &nameFilter() const { return origFilter; } // returns whether the filter is case sensitive bool isCaseSensitive() { return matchesCaseSensitive; } // returns if the filter is null (was cancelled) bool isNull() { return bNull; } // sets the content part of the query void setContent(const QString &content, bool cs = true, bool wholeWord = false, QString encoding = QString(), bool regExp = false); const QString content() { return contain; } // sets the minimum file size limit void setMinimumFileSize(KIO::filesize_t); // sets the maximum file size limit void setMaximumFileSize(KIO::filesize_t); // sets the time the file newer than void setNewerThan(time_t time); // sets the time the file older than void setOlderThan(time_t time); // sets the owner void setOwner(const QString &ownerIn); // sets the group void setGroup(const QString &groupIn); // sets the permissions void setPermissions(const QString &permIn); // sets the mimetype for the query // type, must be one of the following: // 1. a valid mime type name // 2. one of: i18n("Archives"), i18n("Folders"), i18n("Image Files") // i18n("Text Files"), i18n("Video Files"), i18n("Audio Files") // 3. i18n("Custom") in which case you must supply a list of valid mime-types // in the member QStringList customType void setMimeType(const QString &typeIn, QStringList customList = QStringList()); // true if setMimeType was called bool hasMimeType() { return type.isEmpty(); } // sets the search in archive flag void setSearchInArchives(bool flag) { inArchive = flag; } // gets the search in archive flag bool searchInArchives() { return inArchive; } // sets the recursive flag void setRecursive(bool flag) { recurse = flag; } // gets the recursive flag bool isRecursive() { return recurse; } // sets whether to follow symbolic links void setFollowLinks(bool flag) { followLinksP = flag; } // gets whether to follow symbolic links bool followLinks() { return followLinksP; } + // sets the folder names which the searcher will exclude from traversing + void setExcludeFolderNames(const QStringList &urls); + // gets the folder names which the searcher excludes + const QStringList excludeFolderNames() { return excludedFolderNames; } // sets the folders where the searcher will search void setSearchInDirs(const QList &urls); // gets the folders where the searcher searches const QList &searchInDirs() { return whereToSearch; } // sets the folders where search is not permitted void setDontSearchInDirs(const QList &urls); // gets the folders where search is not permitted const QList &dontSearchInDirs() { return whereNotToSearch; } // checks if a URL is excluded bool isExcluded(const QUrl &url); // gives whether we search for content bool isContentSearched() const { return !contain.isEmpty(); } bool checkLine(const QString &line, bool backwards = false) const; const QString &foundText() const { return lastSuccessfulGrep; } int matchIndex() const { return lastSuccessfulGrepMatchIndex; } int matchLength() const { return lastSuccessfulGrepMatchLength; } protected: // important to know whether the event processor is connected virtual void connectNotify(const QMetaMethod &signal) Q_DECL_OVERRIDE; // important to know whether the event processor is connected virtual void disconnectNotify(const QMetaMethod &signal) Q_DECL_OVERRIDE; protected: QStringList matches; // what to search QStringList excludes; // what to exclude QStringList includedDirs; // what dirs to include QStringList excludedDirs; // what dirs to exclude bool matchesCaseSensitive; bool bNull; // flag if the query is null QString contain; // file must contain this string bool containCaseSensetive; bool containWholeWord; bool containRegExp; KIO::filesize_t minSize; KIO::filesize_t maxSize; time_t newerThen; time_t olderThen; QString owner; QString group; QString perm; QString type; QStringList customType; bool inArchive; // if true- search in archive. bool recurse; // if true recurse ob sub-dirs... bool followLinksP; + QStringList excludedFolderNames; // substrings of paths where not to search QList whereToSearch; // directories to search QList whereNotToSearch; // directories NOT to search signals: void status(const QString &name); void processEvents(bool &stopped); private: bool matchCommon(const QString &, const QStringList &, const QStringList &) const; bool checkPerm(QString perm) const; bool checkType(QString mime) const; bool containsContent(QString file) const; bool containsContent(QUrl url) const; bool checkBuffer(const char *data, int len) const; bool checkTimer() const; QStringList split(QString); private slots: void containsContentData(KIO::Job *, const QByteArray &); void containsContentFinished(KJob *); private: QString origFilter; mutable bool busy; mutable bool containsContentResult; mutable char *receivedBuffer; mutable int receivedBufferLen; mutable QString lastSuccessfulGrep; mutable int lastSuccessfulGrepMatchIndex; mutable int lastSuccessfulGrepMatchLength; mutable QString fileName; mutable KIO::filesize_t receivedBytes; mutable KIO::filesize_t totalBytes; mutable int processEventsConnected; mutable QTime timer; QTextCodec *codec; const char *encodedEnter; int encodedEnterLen; QByteArray encodedEnterArray; }; #endif diff --git a/krusader/Filter/filtersettings.cpp b/krusader/Filter/filtersettings.cpp index 2761c98c..d481ac1c 100644 --- a/krusader/Filter/filtersettings.cpp +++ b/krusader/Filter/filtersettings.cpp @@ -1,333 +1,337 @@ /*************************************************************************** filtersettings.cpp - description ------------------- copyright : (C) 2003 + by Shie Erlich & Rafi Yanai & Csaba Karai (C) 2011 + by Jan Lepper e-mail : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD S o u r c e F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "filtersettings.h" #include "../krservices.h" #include #include FilterSettings::FileSize& FilterSettings::FileSize::operator=(const FileSize &other) { amount = other.amount; unit = other.unit; return *this; } KIO::filesize_t FilterSettings::FileSize::size() const { switch (unit) { case Byte: return amount; case KiloByte: return amount * 1024; case MegaByte: return amount * 1024 * 1024; case GigaByte: return amount * 1024 * 1024 * 1024; default: qWarning() << "invalid size unit: " << unit; return amount; } } FilterSettings::TimeSpan& FilterSettings::TimeSpan::operator=(const TimeSpan &other) { amount = other.amount; unit = other.unit; return *this; } int FilterSettings::TimeSpan::days() const { switch (unit) { case Day: return amount; case Week: return amount * 7; case Month: return amount * 30; case Year: return amount * 365; default: qWarning() << "invalid time unit: " << unit; return amount; } } FilterSettings::FilterSettings() : valid(false), searchFor("*"), searchForCase(false), searchInArchives(false), recursive(false), followLinks(false), containsTextCase(false), containsWholeWord(false), containsRegExp(false), minSizeEnabled(false), maxSizeEnabled(false), modifiedBetweenEnabled(false), notModifiedAfterEnabled(false), modifiedInTheLastEnabled(false), ownerEnabled(false), groupEnabled(false), permissionsEnabled(false) { } FilterSettings& FilterSettings::operator=(const FilterSettings& other) { #define COPY(var) { var = other.var; } COPY(valid); COPY(searchFor); COPY(searchForCase); COPY(mimeType); COPY(searchInArchives); COPY(recursive); COPY(followLinks); COPY(searchIn); COPY(dontSearchIn); + COPY(excludeFolderNames); COPY(contentEncoding); COPY(containsText); COPY(containsTextCase); COPY(containsWholeWord); COPY(containsRegExp); COPY(minSizeEnabled); COPY(minSize); COPY(maxSizeEnabled); COPY(maxSize); COPY(modifiedBetweenEnabled); COPY(modifiedBetween1); COPY(modifiedBetween2); COPY(notModifiedAfterEnabled); COPY(notModifiedAfter); COPY(modifiedInTheLastEnabled); COPY(modifiedInTheLast); COPY(notModifiedInTheLast); COPY(ownerEnabled); COPY(owner); COPY(groupEnabled); COPY(group); COPY(permissionsEnabled); COPY(permissions); #undef COPY return *this; } void FilterSettings::load(KConfigGroup cfg) { *this = FilterSettings(); #define LOAD(key, var) { var = cfg.readEntry(key, var); } LOAD("IsValid", valid); if(!isValid()) return; LOAD("SearchFor", searchFor); LOAD("MimeType", mimeType); LOAD("SearchInArchives", searchInArchives); LOAD("Recursive", recursive); LOAD("FollowLinks", followLinks); searchIn = KrServices::toUrlList(cfg.readEntry("SearchIn", QStringList())); dontSearchIn = KrServices::toUrlList(cfg.readEntry("DontSearchIn", QStringList())); + excludeFolderNames = QStringList(); LOAD("ContentEncoding", contentEncoding); LOAD("ContainsText", containsText); LOAD("ContainsTextCase", containsTextCase); LOAD("ContainsWholeWord", containsWholeWord); LOAD("ContainsRegExp", containsRegExp); LOAD("MinSizeEnabled", minSizeEnabled); LOAD("MinSizeAmount", minSize.amount); minSize.unit = static_cast(cfg.readEntry("MinSizeUnit", 0)); LOAD("MaxSizeEnabled", maxSizeEnabled); LOAD("MaxSizeAmount", maxSize.amount); maxSize.unit = static_cast(cfg.readEntry("MaxSizeUnit", 0)); LOAD("ModifiedBetweenEnabled", modifiedBetweenEnabled); LOAD("ModifiedBetween1", modifiedBetween1); LOAD("ModifiedBetween2", modifiedBetween2); LOAD("NotModifiedAfterEnabled", notModifiedAfterEnabled); LOAD("NotModifiedAfter", notModifiedAfter); LOAD("ModifiedInTheLastEnabled", modifiedInTheLastEnabled); LOAD("ModifiedInTheLastAmount", modifiedInTheLast.amount); modifiedInTheLast.unit = static_cast(cfg.readEntry("ModifiedInTheLastUnit", 0)); LOAD("NotModifiedInTheLastAmount", notModifiedInTheLast.amount); notModifiedInTheLast.unit = static_cast(cfg.readEntry("NotModifiedInTheLastUnit", 0)); LOAD("OwnerEnabled", ownerEnabled); LOAD("Owner", owner); LOAD("GroupEnabled", groupEnabled); LOAD("Group", group); LOAD("PermissionsEnabled", permissionsEnabled); LOAD("Permissions", permissions); #undef LOAD } void FilterSettings::saveDate(QString key, const QDate &date, KConfigGroup &cfg) { if(date.isValid()) cfg.writeEntry(key, date); else cfg.deleteEntry(key); } void FilterSettings::save(KConfigGroup cfg) const { cfg.writeEntry("IsValid", valid); if(!isValid()) return; cfg.writeEntry("SearchFor", searchFor); cfg.writeEntry("MimeType", mimeType); cfg.writeEntry("SearchInArchives", searchInArchives); cfg.writeEntry("Recursive", recursive); cfg.writeEntry("FollowLinks", followLinks); cfg.writeEntry("SearchIn", KrServices::toStringList(searchIn)); cfg.writeEntry("DontSearchIn", KrServices::toStringList(dontSearchIn)); cfg.writeEntry("ContentEncoding", contentEncoding); cfg.writeEntry("ContainsText", containsText); cfg.writeEntry("ContainsTextCase", containsTextCase); cfg.writeEntry("ContainsWholeWord", containsWholeWord); cfg.writeEntry("ContainsRegExp", containsRegExp); cfg.writeEntry("MinSizeEnabled", minSizeEnabled); cfg.writeEntry("MinSizeAmount", minSize.amount); cfg.writeEntry("MinSizeUnit", static_cast(minSize.unit)); cfg.writeEntry("MaxSizeEnabled", maxSizeEnabled); cfg.writeEntry("MaxSizeAmount", maxSize.amount); cfg.writeEntry("MaxSizeUnit", static_cast(maxSize.unit)); cfg.writeEntry("ModifiedBetweenEnabled", modifiedBetweenEnabled); saveDate("ModifiedBetween1", modifiedBetween1, cfg); saveDate("ModifiedBetween2", modifiedBetween2, cfg); cfg.writeEntry("NotModifiedAfterEnabled", notModifiedAfterEnabled); saveDate("NotModifiedAfter", notModifiedAfter, cfg); cfg.writeEntry("ModifiedInTheLastEnabled", modifiedInTheLastEnabled); cfg.writeEntry("ModifiedInTheLastAmount", modifiedInTheLast.amount); cfg.writeEntry("ModifiedInTheLastUnit", static_cast(modifiedInTheLast.unit)); cfg.writeEntry("NotModifiedInTheLastAmount", notModifiedInTheLast.amount); cfg.writeEntry("NotModifiedInTheLastUnit", static_cast(notModifiedInTheLast.unit)); cfg.writeEntry("OwnerEnabled", ownerEnabled); cfg.writeEntry("Owner", owner); cfg.writeEntry("GroupEnabled", groupEnabled); cfg.writeEntry("Group", group); cfg.writeEntry("PermissionsEnabled", permissionsEnabled); cfg.writeEntry("Permissions", permissions); } // bool start: set it to true if this date is the beginning of the search, // if it's the end, set it to false time_t FilterSettings::qdate2time_t (QDate d, bool start) { struct tm t; t.tm_sec = (start ? 0 : 59); t.tm_min = (start ? 0 : 59); t.tm_hour = (start ? 0 : 23); t.tm_mday = d.day(); t.tm_mon = d.month() - 1; t.tm_year = d.year() - 1900; t.tm_wday = d.dayOfWeek() - 1; // actually ignored by mktime t.tm_yday = d.dayOfYear() - 1; // actually ignored by mktime t.tm_isdst = -1; // daylight saving time information isn't available return mktime(&t); } KRQuery FilterSettings::toQuery() const { if(!isValid()) return KRQuery(); KRQuery query; ////////////// General Options ////////////// query.setNameFilter(searchFor, searchForCase); query.setMimeType(mimeType); QString charset; if (!contentEncoding.isEmpty()) charset = KCharsets::charsets()->encodingForName(contentEncoding); if (!containsText.isEmpty()) { query.setContent(containsText, containsTextCase, containsWholeWord, charset, containsRegExp); } query.setRecursive(recursive); query.setSearchInArchives(searchInArchives); query.setFollowLinks(followLinks); if (!searchIn.isEmpty()) query.setSearchInDirs(searchIn); if (!dontSearchIn.isEmpty()) query.setDontSearchInDirs(dontSearchIn); + query.setExcludeFolderNames(excludeFolderNames); + ////////////// Advanced Options ////////////// if (minSizeEnabled) query.setMinimumFileSize(minSize.size()); if (maxSizeEnabled) query.setMaximumFileSize(maxSize.size()); if (modifiedBetweenEnabled) { if(modifiedBetween1.isValid()) query.setNewerThan(qdate2time_t(modifiedBetween1, true)); if(modifiedBetween2.isValid()) query.setOlderThan(qdate2time_t(modifiedBetween2, false)); } else if (notModifiedAfterEnabled && notModifiedAfter.isValid()) { query.setOlderThan(qdate2time_t(notModifiedAfter, false)); } else if (modifiedInTheLastEnabled) { if (modifiedInTheLast.amount) { QDate d = QDate::currentDate().addDays((-1) * modifiedInTheLast.days()); query.setNewerThan(qdate2time_t(d, true)); } if (notModifiedInTheLast.amount) { QDate d = QDate::currentDate().addDays((-1) * notModifiedInTheLast.days()); query.setOlderThan(qdate2time_t(d, true)); } } if (ownerEnabled && !owner.isEmpty()) query.setOwner(owner); if (groupEnabled && !group.isEmpty()) query.setGroup(group); if (permissionsEnabled && !permissions.isEmpty()) query.setPermissions(permissions); return query; } diff --git a/krusader/Filter/filtersettings.h b/krusader/Filter/filtersettings.h index cd5c3146..e15449a7 100644 --- a/krusader/Filter/filtersettings.h +++ b/krusader/Filter/filtersettings.h @@ -1,126 +1,127 @@ /*************************************************************************** filtersettings.h - description ------------------- copyright : (C) 2011 + by Jan Lepper e-mail : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD H e a d e r F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef FILTERSETTINGS_H #define FILTERSETTINGS_H #include "../FileSystem/krquery.h" #include class FilterSettings { friend class FilterTabs; friend class GeneralFilter; friend class AdvancedFilter; public: FilterSettings(); FilterSettings& operator=(const FilterSettings& other); bool isValid() const { return valid; } void load(KConfigGroup cfg); void save(KConfigGroup cfg) const; KRQuery toQuery() const; private: enum SizeUnit { Byte = 0, KiloByte, MegaByte, GigaByte }; enum TimeUnit { Day = 0, Week, Month, Year }; class FileSize { public: FileSize() : amount(0), unit(Byte) {} FileSize& operator=(const FileSize &other); KIO::filesize_t size() const; KIO::filesize_t amount; SizeUnit unit; }; class TimeSpan { public: TimeSpan() : amount(0), unit(Day) {} TimeSpan& operator=(const TimeSpan &other); int days() const; int amount; TimeUnit unit; }; static void saveDate(QString key, const QDate &date, KConfigGroup &cfg); static time_t qdate2time_t(QDate d, bool start); bool valid; QString searchFor; bool searchForCase; QString mimeType; bool searchInArchives; bool recursive; bool followLinks; QList searchIn; QList dontSearchIn; + QStringList excludeFolderNames; QString contentEncoding; QString containsText; bool containsTextCase; bool containsWholeWord; bool containsRegExp; bool minSizeEnabled; FileSize minSize; bool maxSizeEnabled; FileSize maxSize; bool modifiedBetweenEnabled; QDate modifiedBetween1; QDate modifiedBetween2; bool notModifiedAfterEnabled; QDate notModifiedAfter; bool modifiedInTheLastEnabled; TimeSpan modifiedInTheLast; TimeSpan notModifiedInTheLast; bool ownerEnabled; QString owner; bool groupEnabled; QString group; bool permissionsEnabled; QString permissions; }; #endif //FILTERSETTINGS_H diff --git a/krusader/Filter/generalfilter.cpp b/krusader/Filter/generalfilter.cpp index 4a60f0da..3be35c5d 100644 --- a/krusader/Filter/generalfilter.cpp +++ b/krusader/Filter/generalfilter.cpp @@ -1,599 +1,646 @@ /*************************************************************************** generalfilter.cpp - description ------------------- copyright : (C) 2003 + by Shie Erlich & Rafi Yanai & Csaba Karai e-mail : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD S o u r c e F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "generalfilter.h" #include "filtertabs.h" #include "../krglobal.h" #include "../krservices.h" #include "../FileSystem/filesystem.h" // QtWidgets #include #include #include #include #include #include #include #include #include #include typedef struct { const char *description; const char *regExp; int cursorAdjustment; } term; static const term items[] = { { I18N_NOOP("Any Character"), ".", 0 }, { I18N_NOOP("Start of Line"), "^", 0 }, { I18N_NOOP("End of Line"), "$", 0 }, { I18N_NOOP("Set of Characters"), "[]", -1 }, { I18N_NOOP("Repeats, Zero or More Times"), "*", 0 }, { I18N_NOOP("Repeats, One or More Times"), "+", 0 }, { I18N_NOOP("Optional"), "?", 0 }, { I18N_NOOP("Escape"), "\\", 0 }, { I18N_NOOP("TAB"), "\\t", 0 }, { I18N_NOOP("Newline"), "\\n", 0 }, { I18N_NOOP("Carriage Return"), "\\r", 0 }, { I18N_NOOP("White Space"), "\\s", 0 }, { I18N_NOOP("Digit"), "\\d", 0 }, }; class RegExpAction : public QAction { public: RegExpAction(QObject *parent, const QString &text, const QString ®Exp, int cursor) : QAction(text, parent), mText(text), mRegExp(regExp), mCursor(cursor) { } QString text() const { return mText; } QString regExp() const { return mRegExp; } int cursor() const { return mCursor; } private: QString mText; QString mRegExp; int mCursor; }; GeneralFilter::GeneralFilter(FilterTabs *tabs, int properties, QWidget *parent, QStringList extraOptions) : QWidget(parent), profileManager(0), fltTabs(tabs) { QGridLayout *filterLayout = new QGridLayout(this); filterLayout->setSpacing(6); filterLayout->setContentsMargins(11, 11, 11, 11); this->properties = properties; // Options for name filtering QGroupBox *nameGroup = new QGroupBox(this); nameGroup->setTitle(i18n("File Name")); QGridLayout *nameGroupLayout = new QGridLayout(nameGroup); nameGroupLayout->setAlignment(Qt::AlignTop); nameGroupLayout->setSpacing(6); nameGroupLayout->setContentsMargins(11, 11, 11, 11); searchForCase = new QCheckBox(nameGroup); searchForCase->setText(i18n("&Case sensitive")); searchForCase->setChecked(false); nameGroupLayout->addWidget(searchForCase, 1, 2); QLabel *searchForLabel = new QLabel(nameGroup); searchForLabel->setText(i18n("Search &for:")); nameGroupLayout->addWidget(searchForLabel, 0, 0); searchFor = new KHistoryComboBox(false, nameGroup/*, "searchFor"*/); QSizePolicy searchForPolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); searchForPolicy.setHeightForWidth(searchFor->sizePolicy().hasHeightForWidth()); searchFor->setSizePolicy(searchForPolicy); searchFor->setEditable(true); searchFor->setDuplicatesEnabled(false); searchFor->setMaxCount(25); searchFor->setMinimumContentsLength(10); searchForLabel->setBuddy(searchFor); nameGroupLayout->addWidget(searchFor, 0, 1, 1, 2); QString s = "

" + i18n("

The filename filtering criteria is defined here.

You can make use of wildcards. Multiple patterns are separated by space (means logical OR) and patterns are excluded from the search using the pipe symbol.

If the pattern is ended with a slash (*pattern*/), that means that pattern relates to recursive search of folders.

  • pattern - means to search those files/folders that name is pattern, recursive search goes through all subfolders independently of the value of pattern
  • pattern/ - means to search all files/folders, but recursive search goes through/excludes the folders that name is pattern

It is allowed to use quotation marks for names that contain space. Filter \"Program Files\" searches out those files/folders that name is Program Files.

Examples:

  • *.o
  • *.h *.c\?\?
  • *.cpp *.h | *.moc.cpp
  • * | .svn/ .git/

Note: the search term 'text' is equivalent to '*text*'.

"); searchFor->setWhatsThis(s); searchForLabel->setWhatsThis(s); QLabel *searchType = new QLabel(nameGroup); searchType->setText(i18n("&Of type:")); nameGroupLayout->addWidget(searchType, 1, 0); ofType = new KComboBox(false, nameGroup); ofType->setObjectName("ofType"); QSizePolicy ofTypePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); ofTypePolicy.setHeightForWidth(ofType->sizePolicy().hasHeightForWidth()); ofType->setSizePolicy(ofTypePolicy); ofType->setEditable(false); searchType->setBuddy(ofType); ofType->addItem(i18n("All Files")); ofType->addItem(i18n("Archives")); ofType->addItem(i18n("Folders")); ofType->addItem(i18n("Image Files")); ofType->addItem(i18n("Text Files")); ofType->addItem(i18n("Video Files")); ofType->addItem(i18n("Audio Files")); connect(ofType, SIGNAL(currentIndexChanged(int)), this, SLOT(slotDisable())); nameGroupLayout->addWidget(ofType, 1, 1); filterLayout->addWidget(nameGroup, 0, 0); middleLayout = new QHBoxLayout(); middleLayout->setSpacing(6); middleLayout->setContentsMargins(0, 0, 0, 0); QSpacerItem* middleSpacer = new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Fixed); middleLayout->addItem(middleSpacer); if (properties & FilterTabs::HasProfileHandler) { // The profile handler QGroupBox *profileHandler = new QGroupBox(this); profileHandler->setTitle(i18n("&Profile handler")); QGridLayout *profileLayout = new QGridLayout(profileHandler); profileLayout->setAlignment(Qt::AlignTop); profileLayout->setSpacing(6); profileLayout->setContentsMargins(11, 11, 11, 11); profileListBox = new KrListWidget(profileHandler); profileLayout->addWidget(profileListBox, 0, 0, 4, 1); profileAddBtn = new QPushButton(profileHandler); KStandardGuiItem::assign(profileAddBtn, KStandardGuiItem::Add); profileLayout->addWidget(profileAddBtn, 0, 1); profileLoadBtn = new QPushButton(i18n("&Load"), profileHandler); profileLoadBtn->setEnabled(false); profileLayout->addWidget(profileLoadBtn, 1, 1); profileOverwriteBtn = new QPushButton(profileHandler); profileOverwriteBtn->setEnabled(false); KStandardGuiItem::assign(profileOverwriteBtn, KStandardGuiItem::Overwrite); profileLayout->addWidget(profileOverwriteBtn, 2, 1); profileRemoveBtn = new QPushButton(profileHandler); profileRemoveBtn->setEnabled(false); KStandardGuiItem::assign(profileRemoveBtn, KStandardGuiItem::Remove); profileLayout->addWidget(profileRemoveBtn, 3, 1); profileManager = new ProfileManager("SelectionProfile", this); profileManager->hide(); middleLayout->addWidget(profileHandler); refreshProfileListBox(); } if (properties & FilterTabs::HasSearchIn) { // Options for search in QGroupBox *searchInGroup = new QGroupBox(this); searchInGroup->setTitle(i18n("Searc&h in")); QGridLayout *searchInLayout = new QGridLayout(searchInGroup); searchInLayout->setAlignment(Qt::AlignTop); searchInLayout->setSpacing(6); searchInLayout->setContentsMargins(11, 11, 11, 11); searchIn = new KURLListRequester(KURLListRequester::RequestDirs, searchInGroup); searchInLayout->addWidget(searchIn, 0, 0); connect(searchIn, SIGNAL(changed()), this, SLOT(slotDisable())); middleLayout->addWidget(searchInGroup); } if (properties & FilterTabs::HasDontSearchIn) { // Options for don't search in QGroupBox *dontSearchInGroup = new QGroupBox(this); dontSearchInGroup->setTitle(i18n("&Do not search in")); QGridLayout *dontSearchInLayout = new QGridLayout(dontSearchInGroup); dontSearchInLayout->setAlignment(Qt::AlignTop); dontSearchInLayout->setSpacing(6); dontSearchInLayout->setContentsMargins(11, 11, 11, 11); dontSearchIn = new KURLListRequester(KURLListRequester::RequestDirs, dontSearchInGroup); - dontSearchInLayout->addWidget(dontSearchIn, 0, 0); + dontSearchInLayout->addWidget(dontSearchIn, 0, 0, 1, 2); + + if (properties & FilterTabs::HasRecurseOptions) { + KConfigGroup group(krConfig, "Search"); + + useExcludeFolderNames = new QCheckBox(this); + useExcludeFolderNames->setText(i18n("Exclude Folder Names")); + useExcludeFolderNames->setToolTip(i18n("Filters out specified directory names from the results.")); + useExcludeFolderNames->setChecked(static_cast(group.readEntry("ExcludeFolderNamesUse", 0))); + dontSearchInLayout->addWidget(useExcludeFolderNames, 1, 0, 1, 1); + + excludeFolderNames = new KHistoryComboBox(false, dontSearchInGroup); + QSizePolicy excludeFolderNamesPolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + excludeFolderNamesPolicy.setHeightForWidth(excludeFolderNames->sizePolicy().hasHeightForWidth()); + excludeFolderNames->setSizePolicy(excludeFolderNamesPolicy); + excludeFolderNames->setEditable(true); + excludeFolderNames->setDuplicatesEnabled(false); + excludeFolderNames->setMaxCount(25); + excludeFolderNames->setMinimumContentsLength(10); + excludeFolderNames->lineEdit()->setPlaceholderText("Enter colon separated folder names"); + dontSearchInLayout->addWidget(excludeFolderNames, 1, 1, 1, 1); + excludeFolderNames->setHistoryItems(group.readEntry("ExcludeFolderNamesHistory", QStringList())); + excludeFolderNames->setEditText(group.readEntry("ExcludeFolderNames", "")); + if (!useExcludeFolderNames->isChecked()) { + excludeFolderNames->setDisabled(true); + } + + connect(useExcludeFolderNames, &QCheckBox::toggled, excludeFolderNames, &KHistoryComboBox::setEnabled); + } middleLayout->addWidget(dontSearchInGroup); } filterLayout->addLayout(middleLayout, 1, 0); // Options for containing text QGroupBox *containsGroup = new QGroupBox(this); containsGroup->setTitle(i18n("Containing text")); QGridLayout *containsLayout = new QGridLayout(containsGroup); containsLayout->setAlignment(Qt::AlignTop); containsLayout->setSpacing(6); containsLayout->setContentsMargins(11, 11, 11, 11); QHBoxLayout *containsTextLayout = new QHBoxLayout(); containsTextLayout->setSpacing(6); containsTextLayout->setContentsMargins(0, 0, 0, 0); containsLabel = new QLabel(containsGroup); QSizePolicy containsLabelPolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); containsLabelPolicy.setHeightForWidth(containsLabel->sizePolicy().hasHeightForWidth()); containsLabel->setSizePolicy(containsLabelPolicy); containsLabel->setText(i18n("&Text:")); containsTextLayout->addWidget(containsLabel); containsText = new KHistoryComboBox(false, containsGroup/*, "containsText"*/); QSizePolicy containsTextPolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); containsTextPolicy.setHeightForWidth(containsText->sizePolicy().hasHeightForWidth()); containsText->setSizePolicy(containsTextPolicy); containsText->setDuplicatesEnabled(false); containsText->setMaxCount(25); containsText->setMinimumContentsLength(10); containsTextLayout->addWidget(containsText); containsLabel->setBuddy(containsText); containsRegExp = new QToolButton(containsGroup); containsRegExp->setPopupMode(QToolButton::MenuButtonPopup); containsRegExp->setCheckable(true); containsRegExp->setText(i18n("RegExp")); // Populate the popup menu. QMenu *patterns = new QMenu(containsRegExp); for (int i = 0; (unsigned)i < sizeof(items) / sizeof(items[0]); i++) { patterns->addAction(new RegExpAction(patterns, i18n(items[i].description), items[i].regExp, items[i].cursorAdjustment)); } connect(containsRegExp, SIGNAL(toggled(bool)), this, SLOT(slotDisable())); connect(containsRegExp, SIGNAL(triggered(QAction*)), this, SLOT(slotRegExpTriggered(QAction*))); containsRegExp->setMenu(patterns); patterns->setEnabled(false); containsTextLayout->addWidget(containsRegExp); containsLayout->addLayout(containsTextLayout, 0, 0); QHBoxLayout *containsCbsLayout = new QHBoxLayout(); containsCbsLayout->setSpacing(6); containsCbsLayout->setContentsMargins(0, 0, 0, 0); encLabel = new QLabel(i18n("Encoding:"), containsGroup); containsCbsLayout->addWidget(encLabel); contentEncoding = new KComboBox(containsGroup); contentEncoding->setEditable(false); contentEncoding->addItem(i18nc("Default encoding", "Default")); contentEncoding->addItems(KCharsets::charsets()->descriptiveEncodingNames()); containsCbsLayout->addWidget(contentEncoding); QSpacerItem* cbSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); containsCbsLayout->addItem(cbSpacer); containsWholeWord = new QCheckBox(containsGroup); QSizePolicy containsWholeWordPolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); containsWholeWordPolicy.setHeightForWidth(containsWholeWord->sizePolicy().hasHeightForWidth()); containsWholeWord->setSizePolicy(containsWholeWordPolicy); containsWholeWord->setText(i18n("&Match whole word only")); containsWholeWord->setChecked(false); containsCbsLayout->addWidget(containsWholeWord); containsTextCase = new QCheckBox(containsGroup); QSizePolicy containsTextCasePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); containsTextCasePolicy.setHeightForWidth(containsTextCase->sizePolicy().hasHeightForWidth()); containsTextCase->setSizePolicy(containsTextCasePolicy); containsTextCase->setText(i18n("Cas&e sensitive")); containsTextCase->setChecked(true); containsCbsLayout->addWidget(containsTextCase); containsLayout->addLayout(containsCbsLayout, 1, 0); filterLayout->addWidget(containsGroup, 2, 0); QHBoxLayout *recurseLayout = new QHBoxLayout(); recurseLayout->setSpacing(6); recurseLayout->setContentsMargins(0, 0, 0, 0); QSpacerItem* recurseSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); recurseLayout->addItem(recurseSpacer); if (properties & FilterTabs::HasRecurseOptions) { // Options for recursive searching searchInDirs = new QCheckBox(this); searchInDirs->setText(i18n("Search in s&ub folders")); searchInDirs->setChecked(true); recurseLayout->addWidget(searchInDirs); searchInArchives = new QCheckBox(this); searchInArchives->setText(i18n("Search in arch&ives")); recurseLayout->addWidget(searchInArchives); followLinks = new QCheckBox(this); followLinks->setText(i18n("Follow &links")); recurseLayout->addWidget(followLinks); } filterLayout->addLayout(recurseLayout, 3, 0); for(int i = 0; i < extraOptions.length(); i++) { QCheckBox *option = new QCheckBox(this); option->setText(extraOptions[i]); recurseLayout->addWidget(option); this->extraOptions.insert(extraOptions[i], option); } // Connection table if (properties & FilterTabs::HasProfileHandler) { connect(profileAddBtn, SIGNAL(clicked()) , this, SLOT(slotAddBtnClicked())); connect(profileLoadBtn, SIGNAL(clicked()) , this, SLOT(slotLoadBtnClicked())); connect(profileOverwriteBtn, SIGNAL(clicked()) , this, SLOT(slotOverwriteBtnClicked())); connect(profileRemoveBtn, SIGNAL(clicked()) , this, SLOT(slotRemoveBtnClicked())); connect(profileListBox, SIGNAL(itemDoubleClicked(QListWidgetItem*)) , this, SLOT(slotProfileDoubleClicked(QListWidgetItem*))); connect(profileManager, SIGNAL(loadFromProfile(QString)), fltTabs, SLOT(loadFromProfile(QString))); connect(profileManager, SIGNAL(saveToProfile(QString)), fltTabs, SLOT(saveToProfile(QString))); } connect(searchFor, SIGNAL(activated(QString)), searchFor, SLOT(addToHistory(QString))); connect(containsText, SIGNAL(activated(QString)), containsText, SLOT(addToHistory(QString))); // load the completion and history lists // ==> search for KConfigGroup group(krConfig, "Search"); QStringList list = group.readEntry("SearchFor Completion", QStringList()); searchFor->completionObject()->setItems(list); list = group.readEntry("SearchFor History", QStringList()); searchFor->setHistoryItems(list); // ==> grep list = group.readEntry("ContainsText Completion", QStringList()); containsText->completionObject()->setItems(list); list = group.readEntry("ContainsText History", QStringList()); containsText->setHistoryItems(list); setTabOrder(searchFor, containsText); // search for -> content setTabOrder(containsText, searchType); // content -> search type slotDisable(); } GeneralFilter::~GeneralFilter() { // save the history combos // ==> search for QStringList list = searchFor->completionObject()->items(); KConfigGroup group(krConfig, "Search"); group.writeEntry("SearchFor Completion", list); list = searchFor->historyItems(); group.writeEntry("SearchFor History", list); // ==> grep text list = containsText->completionObject()->items(); group.writeEntry("ContainsText Completion", list); list = containsText->historyItems(); group.writeEntry("ContainsText History", list); - + if (properties & FilterTabs::HasDontSearchIn) { + if (properties & FilterTabs::HasRecurseOptions) { + list = excludeFolderNames->historyItems(); + group.writeEntry("ExcludeFolderNamesHistory", list); + group.writeEntry("ExcludeFolderNames", excludeFolderNames->currentText()); + group.writeEntry("ExcludeFolderNamesUse", static_cast(useExcludeFolderNames->checkState())); + } + } krConfig->sync(); } bool GeneralFilter::isExtraOptionChecked(QString name) { QCheckBox *option = extraOptions[name]; return option ? option->isChecked() : false; } void GeneralFilter::checkExtraOption(QString name, bool check) { QCheckBox *option = extraOptions[name]; if(option) option->setChecked(check); } void GeneralFilter::queryAccepted() { searchFor->addToHistory(searchFor->currentText()); containsText->addToHistory(containsText->currentText()); + if (properties & FilterTabs::HasDontSearchIn) { + if (properties & FilterTabs::HasRecurseOptions) { + excludeFolderNames->addToHistory(excludeFolderNames->currentText()); + } + } } void GeneralFilter::refreshProfileListBox() { profileListBox->clear(); profileListBox->addItems(ProfileManager::availableProfiles("SelectionProfile")); if (profileListBox->count() != 0) { profileLoadBtn->setEnabled(true); profileOverwriteBtn->setEnabled(true); profileRemoveBtn->setEnabled(true); } else { profileLoadBtn->setEnabled(false); profileOverwriteBtn->setEnabled(false); profileRemoveBtn->setEnabled(false); } } void GeneralFilter::slotAddBtnClicked() { profileManager->newProfile(searchFor->currentText().simplified()); refreshProfileListBox(); } void GeneralFilter::slotOverwriteBtnClicked() { QListWidgetItem *item = profileListBox->currentItem(); if (item != 0) profileManager->overwriteProfile(item->text()); } void GeneralFilter::slotRemoveBtnClicked() { QListWidgetItem *item = profileListBox->currentItem(); if (item != 0) { profileManager->deleteProfile(item->text()); refreshProfileListBox(); } } void GeneralFilter::slotProfileDoubleClicked(QListWidgetItem *item) { if (item != 0) { QString profileName = item->text(); profileManager->loadProfile(profileName); fltTabs->close(true); } } void GeneralFilter::slotLoadBtnClicked() { QListWidgetItem *item = profileListBox->currentItem(); if (item != 0) profileManager->loadProfile(item->text()); } void GeneralFilter::slotDisable() { bool state = containsRegExp->isChecked(); bool global = ofType->currentText() != i18n("Folders"); bool remoteOnly = false; if (properties & FilterTabs::HasSearchIn) { QList urlList = searchIn->urlList(); remoteOnly = urlList.count() != 0; foreach(const QUrl &url, urlList) if (url.scheme() == "file") remoteOnly = false; } containsWholeWord->setEnabled(!state && global); containsRegExp->menu()->setEnabled(state && global); encLabel->setEnabled(global); contentEncoding->setEnabled(global); containsTextCase->setEnabled(global); containsRegExp->setEnabled(global); if (properties & FilterTabs::HasRecurseOptions) searchInArchives->setEnabled(global && !remoteOnly); containsLabel->setEnabled(global); containsText->setEnabled(global); } void GeneralFilter::slotRegExpTriggered(QAction * act) { if (act == 0) return; RegExpAction *regAct = dynamic_cast(act); if (regAct == 0) return; containsText->lineEdit()->insert(regAct->regExp()); containsText->lineEdit()->setCursorPosition(containsText->lineEdit()->cursorPosition() + regAct->cursor()); containsText->lineEdit()->setFocus(); } bool GeneralFilter::getSettings(FilterSettings &s) { // check that we have (at least) what to search, and where to search in if (searchFor->currentText().simplified().isEmpty()) { KMessageBox::error(this , i18n("No search criteria entered.")); searchFor->setFocus(); return false; } s.searchFor = searchFor->currentText().trimmed(); s.searchForCase = searchForCase->isChecked(); if (ofType->currentText() != i18n("All Files")) s.mimeType = ofType->currentText(); if (containsText->isEnabled()) { s.containsText = containsText->currentText(); s.containsTextCase = containsTextCase->isChecked(); s.containsWholeWord = containsWholeWord->isChecked(); s.containsRegExp = containsRegExp->isChecked(); } if (contentEncoding->currentIndex() != 0) s.contentEncoding = KCharsets::charsets()->encodingForName(contentEncoding->currentText()); if (properties & FilterTabs::HasRecurseOptions) { s.recursive = searchInDirs->isChecked(); s.searchInArchives = searchInArchives->isChecked(); s.followLinks = followLinks->isChecked(); } if (properties & FilterTabs::HasSearchIn) { s.searchIn = searchIn->urlList(); if (s.searchIn.isEmpty()) { // we need a place to search in KMessageBox::error(this , i18n("Please specify a location to search in.")); searchIn->lineEdit()->setFocus(); return false; } } - if (properties & FilterTabs::HasDontSearchIn) + if (properties & FilterTabs::HasDontSearchIn) { s.dontSearchIn = dontSearchIn->urlList(); - + if (properties & FilterTabs::HasRecurseOptions) { + if(useExcludeFolderNames->isChecked()) { + s.excludeFolderNames = excludeFolderNames->currentText().split(':'); + } else { + s.excludeFolderNames = QStringList(); + } + } + } return true; } void GeneralFilter::applySettings(const FilterSettings &s) { searchFor->setEditText(s.searchFor); searchForCase->setChecked(s.searchForCase); setComboBoxValue(ofType, s.mimeType); containsText->setEditText(s.containsText); containsTextCase->setChecked(s.containsTextCase); containsWholeWord->setChecked(s.containsWholeWord); containsRegExp->setChecked(s.containsRegExp); setComboBoxValue(contentEncoding, KCharsets::charsets()->descriptionForEncoding(s.contentEncoding)); if (properties & FilterTabs::HasRecurseOptions) { searchInDirs->setChecked(s.recursive); searchInArchives->setChecked(s.searchInArchives); followLinks->setChecked(s.followLinks); } if (properties & FilterTabs::HasSearchIn) { searchIn->lineEdit()->clear(); searchIn->listBox()->clear(); searchIn->listBox()->addItems(KrServices::toStringList(s.searchIn)); } if (properties & FilterTabs::HasDontSearchIn) { dontSearchIn->lineEdit()->clear(); dontSearchIn->listBox()->clear(); dontSearchIn->listBox()->addItems(KrServices::toStringList(s.dontSearchIn)); } } diff --git a/krusader/Filter/generalfilter.h b/krusader/Filter/generalfilter.h index 838d6cb7..bbb71aa3 100644 --- a/krusader/Filter/generalfilter.h +++ b/krusader/Filter/generalfilter.h @@ -1,123 +1,125 @@ /*************************************************************************** generalfilter.h - description ------------------- copyright : (C) 2003 + by Csaba Karai e-mail : krusader@users.sourceforge.net web site : http://krusader.sourceforge.net --------------------------------------------------------------------------- Description *************************************************************************** A db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b. 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY' 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88. YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD H e a d e r F i l e *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef GENERALFILTER_H #define GENERALFILTER_H // QtWidgets #include #include #include #include #include #include #include #include #include #include "filterbase.h" #include "../Dialogs/kurllistrequester.h" #include "../GUI/profilemanager.h" #include "../GUI/krlistwidget.h" class GeneralFilter : public QWidget, public FilterBase { Q_OBJECT public: GeneralFilter(FilterTabs *tabs, int properties, QWidget *parent = 0, QStringList extraOptions = QStringList()); ~GeneralFilter(); virtual void queryAccepted() Q_DECL_OVERRIDE; virtual QString name() Q_DECL_OVERRIDE { return "GeneralFilter"; } virtual FilterTabs * filterTabs() Q_DECL_OVERRIDE { return fltTabs; } virtual bool getSettings(FilterSettings&) Q_DECL_OVERRIDE; virtual void applySettings(const FilterSettings&) Q_DECL_OVERRIDE; bool isExtraOptionChecked(QString name); void checkExtraOption(QString name, bool check); public slots: void slotAddBtnClicked(); void slotLoadBtnClicked(); void slotOverwriteBtnClicked(); void slotRemoveBtnClicked(); void slotDisable(); void slotRegExpTriggered(QAction * act); void slotProfileDoubleClicked(QListWidgetItem *); void refreshProfileListBox(); public: KComboBox* contentEncoding; QCheckBox* searchForCase; QCheckBox* containsTextCase; QCheckBox* containsWholeWord; + QCheckBox* useExcludeFolderNames; QCheckBox* searchInDirs; QCheckBox* searchInArchives; QCheckBox* followLinks; QHash extraOptions; KURLListRequester *searchIn; KURLListRequester *dontSearchIn; QHBoxLayout *middleLayout; KHistoryComboBox* searchFor; KHistoryComboBox* containsText; + KHistoryComboBox* excludeFolderNames; QToolButton* containsRegExp; KComboBox* ofType; QLabel *encLabel; QLabel *containsLabel; KShellCompletion completion; KrListWidget *profileListBox; QPushButton *profileAddBtn; QPushButton *profileLoadBtn; QPushButton *profileOverwriteBtn; QPushButton *profileRemoveBtn; ProfileManager *profileManager; int properties; FilterTabs *fltTabs; }; #endif /* GENERALFILTER_H */