File indexing completed on 2024-05-19 13:37:45
0001 /* 0002 SPDX-FileCopyrightText: 2001 Shie Erlich <krusader@users.sourceforge.net> 0003 SPDX-FileCopyrightText: 2001 Rafi Yanai <krusader@users.sourceforge.net> 0004 SPDX-FileCopyrightText: 2004-2022 Krusader Krew <https://krusader.org> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "krquery.h" 0010 0011 // QtCore 0012 #include <QFile> 0013 #include <QMetaMethod> 0014 #include <QRegExp> 0015 #include <QTextCodec> 0016 0017 #include <KCoreAddons/KFormat> 0018 #include <KI18n/KLocalizedString> 0019 #include <KIO/Job> 0020 #include <KIOCore/KFileItem> 0021 #include <KIOWidgets/KUrlCompletion> 0022 #include <utility> 0023 0024 #include "../Archive/krarchandler.h" 0025 #include "fileitem.h" 0026 #include "filesystem.h" 0027 #include "krpermhandler.h" 0028 0029 #define STATUS_SEND_DELAY 250 0030 #define MAX_LINE_LEN 1000 0031 0032 // set the defaults 0033 KrQuery::KrQuery() 0034 : matchesCaseSensitive(true) 0035 , bNull(true) 0036 , contain(QString()) 0037 , containCaseSensetive(true) 0038 , containWholeWord(false) 0039 , containRegExp(false) 0040 , minSize(0) 0041 , maxSize(0) 0042 , newerThen(0) 0043 , olderThen(0) 0044 , owner(QString()) 0045 , group(QString()) 0046 , perm(QString()) 0047 , type(QString()) 0048 , inArchive(false) 0049 , recurse(true) 0050 , followLinksP(true) 0051 , receivedBuffer(nullptr) 0052 , receivedBufferLen(0) 0053 , processEventsConnected(0) 0054 , codec(QTextCodec::codecForLocale()) 0055 { 0056 QChar ch = '\n'; 0057 QTextCodec::ConverterState state(QTextCodec::IgnoreHeader); 0058 encodedEnterArray = codec->fromUnicode(&ch, 1, &state); 0059 encodedEnter = encodedEnterArray.data(); 0060 encodedEnterLen = encodedEnterArray.size(); 0061 } 0062 0063 // set the defaults 0064 KrQuery::KrQuery(const QString &name, bool matchCase) 0065 : bNull(true) 0066 , contain(QString()) 0067 , containCaseSensetive(true) 0068 , containWholeWord(false) 0069 , containRegExp(false) 0070 , minSize(0) 0071 , maxSize(0) 0072 , newerThen(0) 0073 , olderThen(0) 0074 , owner(QString()) 0075 , group(QString()) 0076 , perm(QString()) 0077 , type(QString()) 0078 , inArchive(false) 0079 , recurse(true) 0080 , followLinksP(true) 0081 , receivedBuffer(nullptr) 0082 , receivedBufferLen(0) 0083 , processEventsConnected(0) 0084 , codec(QTextCodec::codecForLocale()) 0085 { 0086 QChar ch = '\n'; 0087 QTextCodec::ConverterState state(QTextCodec::IgnoreHeader); 0088 encodedEnterArray = codec->fromUnicode(&ch, 1, &state); 0089 encodedEnter = encodedEnterArray.data(); 0090 encodedEnterLen = encodedEnterArray.size(); 0091 0092 setNameFilter(name, matchCase); 0093 } 0094 0095 KrQuery::KrQuery(const KrQuery &that) 0096 : QObject() 0097 , receivedBuffer(nullptr) 0098 , receivedBufferLen(0) 0099 , processEventsConnected(0) 0100 { 0101 *this = that; 0102 } 0103 0104 KrQuery::~KrQuery() 0105 { 0106 if (receivedBuffer) 0107 delete[] receivedBuffer; 0108 receivedBuffer = nullptr; 0109 } 0110 0111 KrQuery &KrQuery::operator=(const KrQuery &old) 0112 { 0113 matches = old.matches; 0114 excludes = old.excludes; 0115 includedDirs = old.includedDirs; 0116 excludedDirs = old.excludedDirs; 0117 matchesCaseSensitive = old.matchesCaseSensitive; 0118 bNull = old.bNull; 0119 contain = old.contain; 0120 containCaseSensetive = old.containCaseSensetive; 0121 containWholeWord = old.containWholeWord; 0122 containRegExp = old.containRegExp; 0123 minSize = old.minSize; 0124 maxSize = old.maxSize; 0125 newerThen = old.newerThen; 0126 olderThen = old.olderThen; 0127 owner = old.owner; 0128 group = old.group; 0129 perm = old.perm; 0130 type = old.type; 0131 customType = old.customType; 0132 inArchive = old.inArchive; 0133 recurse = old.recurse; 0134 followLinksP = old.followLinksP; 0135 whereToSearch = old.whereToSearch; 0136 excludedFolderNames = old.excludedFolderNames; 0137 whereNotToSearch = old.whereNotToSearch; 0138 origFilter = old.origFilter; 0139 0140 codec = old.codec; 0141 0142 encodedEnterArray = old.encodedEnterArray; 0143 encodedEnter = encodedEnterArray.data(); 0144 encodedEnterLen = encodedEnterArray.size(); 0145 0146 return *this; 0147 } 0148 0149 void KrQuery::load(const KConfigGroup &cfg) 0150 { 0151 *this = KrQuery(); // reset parameters first 0152 0153 if (cfg.readEntry("IsNull", true)) 0154 return; 0155 0156 #define LOAD(key, var) (var = cfg.readEntry(key, var)) 0157 LOAD("Matches", matches); 0158 LOAD("Excludes", excludes); 0159 LOAD("IncludedDirs", includedDirs); 0160 LOAD("ExcludedDirs", excludedDirs); 0161 LOAD("MatchesCaseSensitive", matchesCaseSensitive); 0162 LOAD("Contain", contain); 0163 LOAD("ContainCaseSensetive", containCaseSensetive); 0164 LOAD("ContainWholeWord", containWholeWord); 0165 LOAD("ContainRegExp", containRegExp); 0166 LOAD("MinSize", minSize); 0167 LOAD("MaxSize", maxSize); 0168 newerThen = QDateTime::fromString(cfg.readEntry("NewerThan", QDateTime::fromTime_t(static_cast<uint>(newerThen)).toString())).toTime_t(); 0169 olderThen = QDateTime::fromString(cfg.readEntry("OlderThan", QDateTime::fromTime_t(static_cast<uint>(olderThen)).toString())).toTime_t(); 0170 LOAD("Owner", owner); 0171 LOAD("Group", group); 0172 LOAD("Perm", perm); 0173 LOAD("Type", type); 0174 LOAD("CustomType", customType); 0175 LOAD("InArchive", inArchive); 0176 LOAD("Recurse", recurse); 0177 LOAD("FollowLinks", followLinksP); 0178 // KF5 TODO? 0179 // LOAD("WhereToSearch", whereToSearch); 0180 // LOAD("WhereNotToSearch", whereNotToSearch); 0181 LOAD("OrigFilter", origFilter); 0182 0183 codec = QTextCodec::codecForName(cfg.readEntry("Codec", codec->name())); 0184 if (!codec) 0185 codec = QTextCodec::codecForLocale(); 0186 0187 LOAD("EncodedEnterArray", encodedEnterArray); 0188 encodedEnter = encodedEnterArray.data(); 0189 encodedEnterLen = encodedEnterArray.size(); 0190 #undef LOAD 0191 0192 bNull = false; 0193 } 0194 0195 void KrQuery::save(KConfigGroup cfg) 0196 { 0197 cfg.writeEntry("IsNull", bNull); 0198 0199 if (bNull) 0200 return; 0201 0202 cfg.writeEntry("Matches", matches); 0203 cfg.writeEntry("Excludes", excludes); 0204 cfg.writeEntry("IncludedDirs", includedDirs); 0205 cfg.writeEntry("ExcludedDirs", excludedDirs); 0206 cfg.writeEntry("MatchesCaseSensitive", matchesCaseSensitive); 0207 cfg.writeEntry("Contain", contain); 0208 cfg.writeEntry("ContainCaseSensetive", containCaseSensetive); 0209 cfg.writeEntry("ContainWholeWord", containWholeWord); 0210 cfg.writeEntry("ContainRegExp", containRegExp); 0211 cfg.writeEntry("MinSize", minSize); 0212 cfg.writeEntry("MaxSize", maxSize); 0213 cfg.writeEntry("NewerThan", QDateTime::fromTime_t(static_cast<uint>(newerThen)).toString()); 0214 cfg.writeEntry("OlderThan", QDateTime::fromTime_t(static_cast<uint>(olderThen)).toString()); 0215 cfg.writeEntry("Owner", owner); 0216 cfg.writeEntry("Group", group); 0217 cfg.writeEntry("Perm", perm); 0218 cfg.writeEntry("Type", type); 0219 cfg.writeEntry("CustomType", customType); 0220 cfg.writeEntry("InArchive", inArchive); 0221 cfg.writeEntry("Recurse", recurse); 0222 cfg.writeEntry("FollowLinks", followLinksP); 0223 // KF5 TODO? 0224 // cfg.writeEntry("WhereToSearch", whereToSearch); 0225 // cfg.writeEntry("WhereNotToSearch", whereNotToSearch); 0226 cfg.writeEntry("OrigFilter", origFilter); 0227 0228 cfg.writeEntry("Codec", codec->name()); 0229 cfg.writeEntry("EncodedEnterArray", encodedEnterArray); 0230 cfg.writeEntry("EncodedEnter", encodedEnter); 0231 cfg.writeEntry("EncodedEnterLen", encodedEnterLen); 0232 } 0233 0234 void KrQuery::connectNotify(const QMetaMethod &signal) 0235 { 0236 if (signal == QMetaMethod::fromSignal(&KrQuery::processEvents)) 0237 processEventsConnected++; 0238 } 0239 0240 void KrQuery::disconnectNotify(const QMetaMethod &signal) 0241 { 0242 if (signal == QMetaMethod::fromSignal(&KrQuery::processEvents)) 0243 processEventsConnected--; 0244 } 0245 0246 bool KrQuery::checkPerm(QString filePerm) const 0247 { 0248 for (int i = 0; i < 9; ++i) 0249 if (perm[i] != '?' && perm[i] != filePerm[i + 1]) 0250 return false; 0251 return true; 0252 } 0253 0254 bool KrQuery::checkType(const QString &mime) const 0255 { 0256 if (type == mime) 0257 return true; 0258 if (type == i18n("Archives")) 0259 return KrArcHandler::arcSupported(mime); 0260 if (type == i18n("Folders")) 0261 return mime.contains("directory"); 0262 if (type == i18n("Image Files")) 0263 return mime.contains("image/"); 0264 if (type == i18n("Text Files")) 0265 return mime.contains("text/"); 0266 if (type == i18n("Video Files")) 0267 return mime.contains("video/"); 0268 if (type == i18n("Audio Files")) 0269 return mime.contains("audio/"); 0270 if (type == i18n("Custom")) 0271 return customType.contains(mime); 0272 return false; 0273 } 0274 0275 bool KrQuery::match(const QString &name) const 0276 { 0277 return matchCommon(name, matches, excludes); 0278 } 0279 0280 bool KrQuery::matchDirName(const QString &name) const 0281 { 0282 return matchCommon(name, includedDirs, excludedDirs); 0283 } 0284 0285 bool KrQuery::matchCommon(const QString &nameIn, const QStringList &matchList, const QStringList &excludeList) const 0286 { 0287 if (excludeList.count() == 0 && matchList.count() == 0) /* true if there's no match condition */ 0288 return true; 0289 0290 QString name(nameIn); 0291 int ndx = nameIn.lastIndexOf('/'); // virtual filenames may contain '/' 0292 if (ndx != -1) // but the end of the filename is OK 0293 name = nameIn.mid(ndx + 1); 0294 0295 for (int i = 0; i < excludeList.count(); ++i) { 0296 if (QRegExp(excludeList[i], matchesCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard).exactMatch(name)) 0297 return false; 0298 } 0299 0300 if (matchList.count() == 0) 0301 return true; 0302 0303 for (int i = 0; i < matchList.count(); ++i) { 0304 if (QRegExp(matchList[i], matchesCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::Wildcard).exactMatch(name)) 0305 return true; 0306 } 0307 return false; 0308 } 0309 0310 bool KrQuery::match(FileItem *item) const 0311 { 0312 if (item->isDir() && !matchDirName(item->getName())) 0313 return false; 0314 // see if the name matches 0315 if (!match(item->getName())) 0316 return false; 0317 // checking the mime 0318 if (!type.isEmpty() && !checkType(item->getMime())) 0319 return false; 0320 // check that the size fit 0321 KIO::filesize_t size = item->getSize(); 0322 if (minSize && size < minSize) 0323 return false; 0324 if (maxSize && size > maxSize) 0325 return false; 0326 // check the time frame 0327 time_t mtime = item->getModificationTime(); 0328 if (olderThen && mtime > olderThen) 0329 return false; 0330 if (newerThen && mtime < newerThen) 0331 return false; 0332 // check owner name 0333 if (!owner.isEmpty() && item->getOwner() != owner) 0334 return false; 0335 // check group name 0336 if (!group.isEmpty() && item->getGroup() != group) 0337 return false; 0338 // check permission 0339 if (!perm.isEmpty() && !checkPerm(item->getPerm())) 0340 return false; 0341 0342 if (!contain.isEmpty()) { 0343 totalBytes = item->getSize(); 0344 receivedBytes = 0; 0345 if (receivedBuffer) 0346 delete receivedBuffer; 0347 receivedBuffer = nullptr; 0348 receivedBufferLen = 0; 0349 fileName = item->getName(); 0350 timer.start(); 0351 0352 // search locally 0353 if (item->getUrl().isLocalFile()) { 0354 return containsContent(item->getUrl().path()); 0355 } 0356 0357 // search remotely 0358 if (processEventsConnected == 0) { 0359 return false; 0360 } 0361 return containsContent(item->getUrl()); 0362 } 0363 0364 return true; 0365 } 0366 0367 // takes the string and adds BOLD to it, so that when it is displayed, 0368 // the grepped text will be bold 0369 void fixFoundTextForDisplay(QString &haystack, int start, int length) 0370 { 0371 QString before = haystack.left(start); 0372 QString text = haystack.mid(start, length); 0373 QString after = haystack.mid(start + length); 0374 0375 before.replace('&', "&"); 0376 before.replace('<', "<"); 0377 before.replace('>', ">"); 0378 0379 text.replace('&', "&"); 0380 text.replace('<', "<"); 0381 text.replace('>', ">"); 0382 0383 after.replace('&', "&"); 0384 after.replace('<', "<"); 0385 after.replace('>', ">"); 0386 0387 haystack = ("<qt>" + before + "<b>" + text + "</b>" + after + "</qt>"); 0388 } 0389 0390 bool KrQuery::checkBuffer(const char *data, int len) const 0391 { 0392 bool result = false; 0393 0394 auto *mergedBuffer = new char[len + receivedBufferLen]; 0395 if (receivedBufferLen) 0396 memcpy(mergedBuffer, receivedBuffer, receivedBufferLen); 0397 if (len) 0398 memcpy(mergedBuffer + receivedBufferLen, data, len); 0399 0400 int maxLen = len + receivedBufferLen; 0401 int maxBuffer = maxLen - encodedEnterLen; 0402 int lastLinePosition = 0; 0403 0404 for (int enterIndex = 0; enterIndex < maxBuffer; enterIndex++) { 0405 if (memcmp(mergedBuffer + enterIndex, encodedEnter, encodedEnterLen) == 0) { 0406 QString str = codec->toUnicode(mergedBuffer + lastLinePosition, enterIndex + encodedEnterLen - lastLinePosition); 0407 if (str.endsWith('\n')) { 0408 str.chop(1); 0409 result = result || checkLine(str); 0410 lastLinePosition = enterIndex + encodedEnterLen; 0411 enterIndex = lastLinePosition; 0412 continue; 0413 } 0414 } 0415 } 0416 0417 if (maxLen - lastLinePosition > MAX_LINE_LEN || len == 0) { 0418 QString str = codec->toUnicode(mergedBuffer + lastLinePosition, maxLen - lastLinePosition); 0419 result = result || checkLine(str); 0420 lastLinePosition = maxLen; 0421 } 0422 0423 delete[] receivedBuffer; 0424 receivedBuffer = nullptr; 0425 receivedBufferLen = maxLen - lastLinePosition; 0426 0427 if (receivedBufferLen) { 0428 receivedBuffer = new char[receivedBufferLen]; 0429 memcpy(receivedBuffer, mergedBuffer + lastLinePosition, receivedBufferLen); 0430 } 0431 0432 delete[] mergedBuffer; 0433 return result; 0434 } 0435 0436 bool KrQuery::checkLine(const QString &line, bool backwards) const 0437 { 0438 if (containRegExp) { 0439 QRegExp rexp(contain, containCaseSensetive ? Qt::CaseSensitive : Qt::CaseInsensitive, QRegExp::RegExp); 0440 int ndx = backwards ? rexp.lastIndexIn(line) : rexp.indexIn(line); 0441 bool result = ndx >= 0; 0442 if (result) 0443 fixFoundTextForDisplay(lastSuccessfulGrep = line, lastSuccessfulGrepMatchIndex = ndx, lastSuccessfulGrepMatchLength = rexp.matchedLength()); 0444 return result; 0445 } 0446 0447 int ndx = backwards ? -1 : 0; 0448 0449 if (line.isNull()) 0450 return false; 0451 if (containWholeWord) { 0452 while ((ndx = (backwards) ? line.lastIndexOf(contain, ndx, containCaseSensetive ? Qt::CaseSensitive : Qt::CaseInsensitive) 0453 : line.indexOf(contain, ndx, containCaseSensetive ? Qt::CaseSensitive : Qt::CaseInsensitive)) 0454 != -1) { 0455 QChar before = '\n'; 0456 QChar after = '\n'; 0457 0458 if (ndx > 0) 0459 before = line.at(ndx - 1); 0460 if (ndx + contain.length() < line.length()) 0461 after = line.at(ndx + contain.length()); 0462 0463 if (!before.isLetterOrNumber() && !after.isLetterOrNumber() && after != '_' && before != '_') { 0464 lastSuccessfulGrep = line; 0465 fixFoundTextForDisplay(lastSuccessfulGrep, lastSuccessfulGrepMatchIndex = ndx, lastSuccessfulGrepMatchLength = contain.length()); 0466 return true; 0467 } 0468 0469 if (backwards) 0470 ndx -= line.length() + 1; 0471 else 0472 ndx++; 0473 } 0474 } else if ((ndx = (backwards) ? line.lastIndexOf(contain, -1, containCaseSensetive ? Qt::CaseSensitive : Qt::CaseInsensitive) 0475 : line.indexOf(contain, 0, containCaseSensetive ? Qt::CaseSensitive : Qt::CaseInsensitive)) 0476 != -1) { 0477 lastSuccessfulGrep = line; 0478 fixFoundTextForDisplay(lastSuccessfulGrep, lastSuccessfulGrepMatchIndex = ndx, lastSuccessfulGrepMatchLength = contain.length()); 0479 return true; 0480 } 0481 return false; 0482 } 0483 0484 bool KrQuery::containsContent(const QString &file) const 0485 { 0486 QFile qf(file); 0487 if (!qf.open(QIODevice::ReadOnly)) 0488 return false; 0489 0490 char buffer[1440]; // 2k buffer 0491 0492 while (!qf.atEnd()) { 0493 // Note: As it's stated in the documentation, "`qint64 QIODevice::read(char *data, 0494 // qint64 maxSize)` Reads at most `maxSize` bytes" 0495 int bytes = static_cast<int>(qf.read(buffer, sizeof(buffer))); 0496 0497 if (bytes <= 0) 0498 break; 0499 0500 receivedBytes += bytes; 0501 0502 if (checkBuffer(buffer, bytes)) 0503 return true; 0504 0505 if (checkTimer()) { 0506 bool stopped = false; 0507 emit(const_cast<KrQuery *>(this))->processEvents(stopped); 0508 if (stopped) 0509 return false; 0510 } 0511 } 0512 if (checkBuffer(buffer, 0)) 0513 return true; 0514 0515 lastSuccessfulGrep.clear(); // nothing was found 0516 return false; 0517 } 0518 0519 bool KrQuery::containsContent(const QUrl &url) const 0520 { 0521 KIO::TransferJob *contentReader = KIO::get(url, KIO::NoReload, KIO::HideProgressInfo); 0522 connect(contentReader, &KIO::TransferJob::data, this, &KrQuery::containsContentData); 0523 connect(contentReader, &KIO::Job::result, this, &KrQuery::containsContentFinished); 0524 0525 busy = true; 0526 containsContentResult = false; 0527 bool stopped = false; 0528 0529 while (busy && !stopped) { 0530 checkTimer(); 0531 emit(const_cast<KrQuery *>(this))->processEvents(stopped); 0532 } 0533 0534 if (busy) { 0535 contentReader->kill(KJob::EmitResult); 0536 busy = false; 0537 } 0538 0539 return containsContentResult; 0540 } 0541 0542 void KrQuery::containsContentData(KIO::Job *job, const QByteArray &array) 0543 { 0544 receivedBytes += array.size(); 0545 if (checkBuffer(array.data(), array.size())) { 0546 containsContentResult = true; 0547 containsContentFinished(job); 0548 job->kill(KJob::EmitResult); 0549 return; 0550 } 0551 checkTimer(); 0552 } 0553 0554 void KrQuery::containsContentFinished(KJob *) 0555 { 0556 busy = false; 0557 } 0558 0559 bool KrQuery::checkTimer() const 0560 { 0561 if (timer.elapsed() >= STATUS_SEND_DELAY) { 0562 static KFormat format; 0563 // clang-format off 0564 QString message = 0565 i18nc("%1=filename, %2=percentage", "Searching content of '%1' (%2)", fileName, 0566 (totalBytes > 0 && totalBytes >= receivedBytes) ? 0567 // The normal case: A percentage is shown. 0568 // Note: Instead of rounding, a truncation is performed because each percentage is seen 0569 // only briefly —therefore, here speed is more important than precision 0570 i18nc("%1=percentage", "%1%", (receivedBytes*100)/totalBytes) : 0571 // An unusual case: There are problems when calculating that percentage. Sometimes it's 0572 // because the contents of a big symlinked file are read, then the variable `totalBytes` 0573 // is very small (it's the size of a symlink) but much more bytes are read 0574 format.formatByteSize(static_cast<double>(receivedBytes), 0, KFormat::IECBinaryDialect, KFormat::UnitMegaByte) 0575 ); 0576 // clang-format on 0577 0578 timer.start(); 0579 emit(const_cast<KrQuery *>(this))->status(message); 0580 return true; 0581 } 0582 return false; 0583 } 0584 0585 QStringList KrQuery::split(QString str) 0586 { 0587 QStringList list; 0588 int splitNdx = 0; 0589 int startNdx = 0; 0590 bool quotation = false; 0591 0592 while (splitNdx < str.length()) { 0593 if (str[splitNdx] == '"') 0594 quotation = !quotation; 0595 0596 if (!quotation && str[splitNdx] == ' ') { 0597 QString section = str.mid(startNdx, splitNdx - startNdx); 0598 startNdx = splitNdx + 1; 0599 if (section.startsWith('\"') && section.endsWith('\"') && section.length() >= 2) 0600 section = section.mid(1, section.length() - 2); 0601 if (!section.isEmpty()) 0602 list.append(section); 0603 } 0604 splitNdx++; 0605 } 0606 0607 if (startNdx < splitNdx) { 0608 QString section = str.mid(startNdx, splitNdx - startNdx); 0609 if (section.startsWith('\"') && section.endsWith('\"') && section.length() >= 2) 0610 section = section.mid(1, section.length() - 2); 0611 if (!section.isEmpty()) 0612 list.append(section); 0613 } 0614 0615 return list; 0616 } 0617 0618 void KrQuery::setNameFilter(const QString &text, bool cs) 0619 { 0620 bNull = false; 0621 matchesCaseSensitive = cs; 0622 origFilter = text; 0623 0624 QString matchText = text; 0625 QString excludeText; 0626 0627 int excludeNdx = 0; 0628 bool quotationMark = 0; 0629 while (excludeNdx < matchText.length()) { 0630 if (matchText[excludeNdx] == '"') 0631 quotationMark = !quotationMark; 0632 if (!quotationMark) { 0633 if (matchText[excludeNdx] == '|') 0634 break; 0635 } 0636 excludeNdx++; 0637 } 0638 0639 if (excludeNdx < matchText.length()) { 0640 excludeText = matchText.mid(excludeNdx + 1).trimmed(); 0641 matchText.truncate(excludeNdx); 0642 matchText = matchText.trimmed(); 0643 if (matchText.isEmpty()) 0644 matchText = '*'; 0645 } 0646 0647 int i; 0648 0649 matches = split(matchText); 0650 includedDirs.clear(); 0651 0652 for (i = 0; i < matches.count();) { 0653 if (matches[i].endsWith('/')) { 0654 includedDirs.push_back(matches[i].left(matches[i].length() - 1)); 0655 matches.removeAll(matches.at(i)); 0656 continue; 0657 } 0658 0659 if (!matches[i].contains("*") && !matches[i].contains("?")) 0660 matches[i] = '*' + matches[i] + '*'; 0661 0662 i++; 0663 } 0664 0665 excludes = split(excludeText); 0666 excludedDirs.clear(); 0667 0668 for (i = 0; i < excludes.count();) { 0669 if (excludes[i].endsWith('/')) { 0670 excludedDirs.push_back(excludes[i].left(excludes[i].length() - 1)); 0671 excludes.removeAll(excludes.at(i)); 0672 continue; 0673 } 0674 0675 if (!excludes[i].contains("*") && !excludes[i].contains("?")) 0676 excludes[i] = '*' + excludes[i] + '*'; 0677 0678 i++; 0679 } 0680 } 0681 0682 void KrQuery::setContent(const QString &content, bool cs, bool wholeWord, const QString &encoding, bool regExp) 0683 { 0684 bNull = false; 0685 contain = content; 0686 containCaseSensetive = cs; 0687 containWholeWord = wholeWord; 0688 containRegExp = regExp; 0689 0690 if (encoding.isEmpty()) 0691 codec = QTextCodec::codecForLocale(); 0692 else { 0693 codec = QTextCodec::codecForName(encoding.toLatin1()); 0694 if (codec == nullptr) 0695 codec = QTextCodec::codecForLocale(); 0696 } 0697 0698 QChar ch = '\n'; 0699 QTextCodec::ConverterState state(QTextCodec::IgnoreHeader); 0700 encodedEnterArray = codec->fromUnicode(&ch, 1, &state); 0701 encodedEnter = encodedEnterArray.data(); 0702 encodedEnterLen = encodedEnterArray.size(); 0703 } 0704 0705 void KrQuery::setMinimumFileSize(KIO::filesize_t minimumSize) 0706 { 0707 bNull = false; 0708 minSize = minimumSize; 0709 } 0710 0711 void KrQuery::setMaximumFileSize(KIO::filesize_t maximumSize) 0712 { 0713 bNull = false; 0714 maxSize = maximumSize; 0715 } 0716 0717 void KrQuery::setNewerThan(time_t time) 0718 { 0719 bNull = false; 0720 newerThen = time; 0721 } 0722 0723 void KrQuery::setOlderThan(time_t time) 0724 { 0725 bNull = false; 0726 olderThen = time; 0727 } 0728 0729 void KrQuery::setOwner(const QString &ownerIn) 0730 { 0731 bNull = false; 0732 owner = ownerIn; 0733 } 0734 0735 void KrQuery::setGroup(const QString &groupIn) 0736 { 0737 bNull = false; 0738 group = groupIn; 0739 } 0740 0741 void KrQuery::setPermissions(const QString &permIn) 0742 { 0743 bNull = false; 0744 perm = permIn; 0745 } 0746 0747 void KrQuery::setMimeType(const QString &typeIn, QStringList customList) 0748 { 0749 bNull = false; 0750 type = typeIn; 0751 customType = std::move(customList); 0752 } 0753 0754 bool KrQuery::isExcluded(const QUrl &url) 0755 { 0756 for (QUrl &item : whereNotToSearch) 0757 if (item.isParentOf(url) || url.matches(item, QUrl::StripTrailingSlash)) 0758 return true; 0759 0760 // Exclude folder names that are configured in settings 0761 QString filename = url.fileName(); 0762 for (QString &item : excludedFolderNames) 0763 if (filename == item) 0764 return true; 0765 0766 if (!matchDirName(filename)) 0767 return true; 0768 0769 return false; 0770 } 0771 0772 void KrQuery::setSearchInDirs(const QList<QUrl> &urls) 0773 { 0774 whereToSearch.clear(); 0775 for (int i = 0; i < urls.count(); ++i) { 0776 QString url = urls[i].url(); 0777 QUrl completed = QUrl::fromUserInput(KUrlCompletion::replacedPath(url, true, true), QString(), QUrl::AssumeLocalFile); 0778 whereToSearch.append(completed); 0779 } 0780 } 0781 0782 void KrQuery::setDontSearchInDirs(const QList<QUrl> &urls) 0783 { 0784 whereNotToSearch.clear(); 0785 for (int i = 0; i < urls.count(); ++i) { 0786 QString url = urls[i].url(); 0787 QUrl completed = QUrl::fromUserInput(KUrlCompletion::replacedPath(url, true, true), QString(), QUrl::AssumeLocalFile); 0788 whereNotToSearch.append(completed); 0789 } 0790 } 0791 0792 void KrQuery::setExcludeFolderNames(const QStringList &paths) 0793 { 0794 excludedFolderNames.clear(); 0795 excludedFolderNames.append(paths); 0796 }