Warning, file /utilities/kfind/src/kftabdlg.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 kftabdlg.cpp 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 0006 */ 0007 0008 #include "kftabdlg.h" 0009 0010 #include <QApplication> 0011 #include <QButtonGroup> 0012 #include <QCheckBox> 0013 #include <QFileDialog> 0014 #include <QLabel> 0015 #include <QMimeDatabase> 0016 #include <QPushButton> 0017 #include <QRadioButton> 0018 #include <QScreen> 0019 #include <QSpinBox> 0020 #include <QStandardPaths> 0021 #include <QWhatsThis> 0022 #include <QtConcurrent/QtConcurrentRun> 0023 #include <QFutureWatcher> 0024 #include <QGridLayout> 0025 0026 #include <KComboBox> 0027 #include <KConfigGroup> 0028 #include <KDateComboBox> 0029 #include <KLineEdit> 0030 #include <KLocalizedString> 0031 #include <KMessageBox> 0032 #include <KSharedConfig> 0033 #include <KShell> 0034 #include <KUrlComboBox> 0035 #include <KUrlCompletion> 0036 0037 #include <algorithm> 0038 0039 #include "kquery.h" 0040 #include <kwidgetsaddons_version.h> 0041 0042 // Static utility functions 0043 static void save_pattern(KComboBox *, const QString &, const QString &); 0044 0045 static const int specialMimeTypeCount = 10; 0046 0047 struct MimeTypes 0048 { 0049 QVector<QMimeType> all; 0050 QStringList image; 0051 QStringList video; 0052 QStringList audio; 0053 }; 0054 0055 KfindTabWidget::KfindTabWidget(QWidget *parent) 0056 : QTabWidget(parent) 0057 { 0058 // ************ Page One ************ 0059 0060 pages[0] = new QWidget; 0061 pages[0]->setObjectName(QStringLiteral("page1")); 0062 0063 nameBox = new KComboBox(pages[0]); 0064 nameBox->setEditable(true); 0065 nameBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); // allow smaller than widest entry 0066 QLabel *namedL = new QLabel(i18nc("this is the label for the name textfield", "&Named:"), pages[0]); 0067 namedL->setBuddy(nameBox); 0068 namedL->setObjectName(QStringLiteral("named")); 0069 namedL->setToolTip(i18n("You can use wildcard matching and \";\" for separating multiple names")); 0070 dirBox = new KUrlComboBox(KUrlComboBox::Directories, pages[0]); 0071 dirBox->setEditable(true); 0072 dirBox->setCompletionObject(new KUrlCompletion(KUrlCompletion::DirCompletion)); 0073 dirBox->setAutoDeleteCompletionObject(true); 0074 dirBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); // allow smaller than widest entry 0075 QLabel *lookinL = new QLabel(i18n("Look &in:"), pages[0]); 0076 lookinL->setBuddy(dirBox); 0077 lookinL->setObjectName(QStringLiteral("lookin")); 0078 subdirsCb = new QCheckBox(i18n("Include &subfolders"), pages[0]); 0079 caseSensCb = new QCheckBox(i18n("Case s&ensitive search"), pages[0]); 0080 browseB = new QPushButton(i18n("&Browse..."), pages[0]); 0081 useLocateCb = new QCheckBox(i18n("&Use files index"), pages[0]); 0082 hiddenFilesCb = new QCheckBox(i18n("Show &hidden files"), pages[0]); 0083 // Setup 0084 0085 subdirsCb->setChecked(true); 0086 caseSensCb->setChecked(false); 0087 useLocateCb->setChecked(false); 0088 hiddenFilesCb->setChecked(false); 0089 if (QStandardPaths::findExecutable(QStringLiteral("locate")).isEmpty()) { 0090 useLocateCb->setEnabled(false); 0091 } 0092 0093 nameBox->setDuplicatesEnabled(false); 0094 nameBox->setFocus(); 0095 dirBox->setDuplicatesEnabled(false); 0096 0097 nameBox->setInsertPolicy(QComboBox::InsertAtTop); 0098 dirBox->setInsertPolicy(QComboBox::InsertAtTop); 0099 0100 const QString nameWhatsThis 0101 = i18n("<qt>Enter the filename you are looking for. <br />" 0102 "Alternatives may be separated by a semicolon \";\".<br />" 0103 "<br />" 0104 "The filename may contain the following special characters:" 0105 "<ul>" 0106 "<li><b>?</b> matches any single character</li>" 0107 "<li><b>*</b> matches zero or more of any characters</li>" 0108 "<li><b>[...]</b> matches any of the characters between the braces</li>" 0109 "</ul>" 0110 "<br />" 0111 "Example searches:" 0112 "<ul>" 0113 "<li><b>*.kwd;*.txt</b> finds all files ending with .kwd or .txt</li>" 0114 "<li><b>go[dt]</b> finds god and got</li>" 0115 "<li><b>Hel?o</b> finds all files that start with \"Hel\" and end with \"o\", " 0116 "having one character in between</li>" 0117 "<li><b>My Document.kwd</b> finds a file of exactly that name</li>" 0118 "</ul></qt>"); 0119 nameBox->setWhatsThis(nameWhatsThis); 0120 namedL->setWhatsThis(nameWhatsThis); 0121 const QString whatsfileindex 0122 = i18n("<qt>This lets you use the files' index created by the <i>slocate</i> " 0123 "package to speed-up the search; remember to update the index from time to time " 0124 "(using <i>updatedb</i>)." 0125 "</qt>"); 0126 useLocateCb->setWhatsThis(whatsfileindex); 0127 0128 // Layout 0129 0130 QGridLayout *grid = new QGridLayout(pages[0]); 0131 QVBoxLayout *subgrid = new QVBoxLayout(); 0132 grid->addWidget(namedL, 0, 0); 0133 grid->addWidget(nameBox, 0, 1, 1, 3); 0134 grid->addWidget(lookinL, 1, 0); 0135 grid->addWidget(dirBox, 1, 1); 0136 grid->addWidget(browseB, 1, 2); 0137 grid->setColumnStretch(1, 1); 0138 grid->addLayout(subgrid, 2, 1, 1, 2); 0139 0140 QHBoxLayout *layoutOne = new QHBoxLayout(); 0141 layoutOne->addWidget(subdirsCb); 0142 layoutOne->addWidget(hiddenFilesCb); 0143 0144 QHBoxLayout *layoutTwo = new QHBoxLayout(); 0145 layoutTwo->addWidget(caseSensCb); 0146 layoutTwo->addWidget(useLocateCb); 0147 0148 subgrid->addLayout(layoutOne); 0149 subgrid->addLayout(layoutTwo); 0150 0151 subgrid->addStretch(1); 0152 0153 // Signals 0154 0155 connect(browseB, &QPushButton::clicked, this, &KfindTabWidget::getDirectory); 0156 0157 connect(nameBox, QOverload<const QString &>::of(&KComboBox::returnPressed), this, &KfindTabWidget::startSearch); 0158 0159 connect(dirBox, QOverload<const QString &>::of(&KUrlComboBox::returnPressed), this, &KfindTabWidget::startSearch); 0160 0161 // ************ Page Two 0162 0163 pages[1] = new QWidget; 0164 pages[1]->setObjectName(QStringLiteral("page2")); 0165 0166 findCreated = new QCheckBox(i18n("Find all files created or &modified:"), pages[1]); 0167 bg = new QButtonGroup(); 0168 rb[0] = new QRadioButton(i18n("&between"), pages[1]); 0169 rb[1] = new QRadioButton(pages[1]); // text set in updateDateLabels 0170 andL = new QLabel(i18n("and"), pages[1]); 0171 andL->setObjectName(QStringLiteral("and")); 0172 betweenType = new KComboBox(pages[1]); 0173 betweenType->setObjectName(QStringLiteral("comboBetweenType")); 0174 betweenType->addItems(QVector<QString>(5).toList()); // texts set in updateDateLabels 0175 betweenType->setCurrentIndex(1); 0176 updateDateLabels(1, 1); 0177 0178 const QDate dt = QDate::currentDate().addYears(-1); 0179 0180 fromDate = new KDateComboBox(pages[1]); 0181 fromDate->setObjectName(QStringLiteral("fromDate")); 0182 fromDate->setDate(dt); 0183 toDate = new KDateComboBox(pages[1]); 0184 toDate->setObjectName(QStringLiteral("toDate")); 0185 timeBox = new QSpinBox(pages[1]); 0186 timeBox->setRange(1, 60); 0187 timeBox->setSingleStep(1); 0188 timeBox->setObjectName(QStringLiteral("timeBox")); 0189 0190 sizeBox = new KComboBox(pages[1]); 0191 sizeBox->setObjectName(QStringLiteral("sizeBox")); 0192 QLabel *sizeL = new QLabel(i18n("File &size is:"), pages[1]); 0193 sizeL->setBuddy(sizeBox); 0194 sizeEdit = new QSpinBox(pages[1]); 0195 sizeEdit->setRange(0, INT_MAX); 0196 sizeEdit->setSingleStep(1); 0197 sizeEdit->setObjectName(QStringLiteral("sizeEdit")); 0198 sizeEdit->setValue(1); 0199 sizeUnitBox = new KComboBox(pages[1]); 0200 sizeUnitBox->setObjectName(QStringLiteral("sizeUnitBox")); 0201 0202 m_usernameBox = new KComboBox(pages[1]); 0203 m_usernameBox->setEditable(true); 0204 m_usernameBox->setObjectName(QStringLiteral("m_combo1")); 0205 QLabel *usernameLabel = new QLabel(i18n("Files owned by &user:"), pages[1]); 0206 usernameLabel->setBuddy(m_usernameBox); 0207 m_groupBox = new KComboBox(pages[1]); 0208 m_groupBox->setEditable(true); 0209 m_groupBox->setObjectName(QStringLiteral("m_combo2")); 0210 QLabel *groupLabel = new QLabel(i18n("Owned by &group:"), pages[1]); 0211 groupLabel->setBuddy(m_groupBox); 0212 0213 sizeBox->addItem(i18nc("file size isn't considered in the search", "(none)")); 0214 sizeBox->addItem(i18n("At Least")); 0215 sizeBox->addItem(i18n("At Most")); 0216 sizeBox->addItem(i18n("Equal To")); 0217 0218 sizeUnitBox->addItem(i18np("Byte", "Bytes", 1)); 0219 sizeUnitBox->addItem(i18n("KiB")); 0220 sizeUnitBox->addItem(i18n("MiB")); 0221 sizeUnitBox->addItem(i18n("GiB")); 0222 sizeUnitBox->setCurrentIndex(1); 0223 0224 int tmp = sizeEdit->fontMetrics().boundingRect(QStringLiteral(" 000000000 ")).width(); 0225 sizeEdit->setMinimumSize(tmp, sizeEdit->sizeHint().height()); 0226 0227 m_usernameBox->setDuplicatesEnabled(false); 0228 m_groupBox->setDuplicatesEnabled(false); 0229 m_usernameBox->setInsertPolicy(QComboBox::InsertAtTop); 0230 m_groupBox->setInsertPolicy(QComboBox::InsertAtTop); 0231 0232 // Setup 0233 rb[0]->setChecked(true); 0234 bg->addButton(rb[0]); 0235 bg->addButton(rb[1]); 0236 0237 // Layout 0238 0239 QGridLayout *grid1 = new QGridLayout(pages[1]); 0240 0241 grid1->addWidget(findCreated, 0, 0, 1, 3); 0242 0243 grid1->addWidget(rb[0], 1, 1); 0244 grid1->addWidget(fromDate, 1, 2); 0245 grid1->addWidget(andL, 1, 3, Qt::AlignHCenter); 0246 grid1->addWidget(toDate, 1, 4); 0247 0248 grid1->addWidget(rb[1], 2, 1); 0249 grid1->addWidget(timeBox, 2, 2, 1, 2); 0250 grid1->addWidget(betweenType, 2, 4); 0251 0252 grid1->addWidget(sizeL, 3, 0, 1, 2); 0253 grid1->addWidget(sizeBox, 3, 2); 0254 grid1->addWidget(sizeEdit, 3, 3); 0255 grid1->addWidget(sizeUnitBox, 3, 4); 0256 0257 grid1->addWidget(usernameLabel, 4, 0, 1, 2); 0258 grid1->addWidget(m_usernameBox, 4, 2); 0259 grid1->addWidget(groupLabel, 4, 3); 0260 grid1->addWidget(m_groupBox, 4, 4); 0261 0262 for (int c = 1; c <= 4; c++) { 0263 grid1->setColumnStretch(c, 1); 0264 } 0265 0266 grid1->setRowStretch(6, 1); 0267 0268 // Connect 0269 connect(findCreated, &QCheckBox::toggled, this, &KfindTabWidget::fixLayout); 0270 connect(bg, static_cast<void (QButtonGroup::*)(QAbstractButton *)>(&QButtonGroup::buttonClicked), this, &KfindTabWidget::fixLayout); 0271 connect(sizeBox, static_cast<void (KComboBox::*)(int)>(&KComboBox::activated), this, &KfindTabWidget::slotSizeBoxChanged); 0272 connect(timeBox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &KfindTabWidget::slotUpdateDateLabelsForNumber); 0273 connect(betweenType, static_cast<void (KComboBox::*)(int)>(&KComboBox::currentIndexChanged), this, &KfindTabWidget::slotUpdateDateLabelsForType); 0274 connect(sizeEdit, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &KfindTabWidget::slotUpdateByteComboBox); 0275 0276 // ************ Page Three 0277 0278 pages[2] = new QWidget; 0279 pages[2]->setObjectName(QStringLiteral("page3")); 0280 0281 typeBox = new KComboBox(pages[2]); 0282 typeBox->setObjectName(QStringLiteral("typeBox")); 0283 typeBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); // allow smaller than widest entry 0284 QLabel *typeL = new QLabel(i18nc("label for the file type combobox", "File &type:"), pages[2]); 0285 typeL->setBuddy(typeBox); 0286 textEdit = new KLineEdit(pages[2]); 0287 textEdit->setClearButtonEnabled(true); 0288 textEdit->setObjectName(QStringLiteral("textEdit")); 0289 QLabel *textL = new QLabel(i18n("C&ontaining text:"), pages[2]); 0290 textL->setBuddy(textEdit); 0291 0292 connect(textEdit, &QLineEdit::returnPressed, this, &KfindTabWidget::startSearch); 0293 0294 const QString containingtext 0295 = i18n("<qt>If specified, only files that contain this text" 0296 " are found. Note that not all file types from the list" 0297 " above are supported. Please refer to the documentation" 0298 " for a list of supported file types." 0299 "</qt>"); 0300 textEdit->setToolTip(containingtext); 0301 textL->setWhatsThis(containingtext); 0302 0303 caseContextCb = new QCheckBox(i18n("Case s&ensitive"), pages[2]); 0304 binaryContextCb = new QCheckBox(i18n("Include &binary files"), pages[2]); 0305 0306 const QString binaryTooltip 0307 = i18n("<qt>This lets you search in any type of file, " 0308 "even those that usually do not contain text (for example " 0309 "program files and images).</qt>"); 0310 binaryContextCb->setToolTip(binaryTooltip); 0311 0312 metainfokeyEdit = new KLineEdit(pages[2]); 0313 metainfoEdit = new KLineEdit(pages[2]); 0314 QLabel *textMetaInfo = new QLabel(i18nc("as in search for", "fo&r:"), pages[2]); 0315 textMetaInfo->setBuddy(metainfoEdit); 0316 QLabel *textMetaKey = new QLabel(i18n("Search &metainfo sections:"), pages[2]); 0317 textMetaKey->setBuddy(metainfokeyEdit); 0318 0319 // Setup 0320 typeBox->addItem(i18n("All Files & Folders")); 0321 typeBox->addItem(i18n("Files")); 0322 typeBox->addItem(i18n("Folders")); 0323 typeBox->addItem(i18n("Symbolic Links")); 0324 typeBox->addItem(i18n("Special Files (Sockets, Device Files, ...)")); 0325 typeBox->addItem(i18n("Executable Files")); 0326 typeBox->addItem(i18n("SUID Executable Files")); 0327 typeBox->addItem(i18n("All Images")); 0328 typeBox->addItem(i18n("All Video")); 0329 typeBox->addItem(i18n("All Sounds")); 0330 typeBox->insertSeparator(typeBox->count()); // append separator 0331 0332 auto mimeTypeFuture = QtConcurrent::run([] { 0333 MimeTypes mimeTypes; 0334 0335 const auto types = QMimeDatabase().allMimeTypes(); 0336 for (const QMimeType &type : types) { 0337 if (!type.comment().isEmpty()) { 0338 mimeTypes.all.append(type); 0339 0340 if (type.name().startsWith(QLatin1String("image/"))) { 0341 mimeTypes.image.append(type.name()); 0342 } else if (type.name().startsWith(QLatin1String("video/"))) { 0343 mimeTypes.video.append(type.name()); 0344 } else if (type.name().startsWith(QLatin1String("audio/"))) { 0345 mimeTypes.audio.append(type.name()); 0346 } 0347 } 0348 } 0349 0350 std::sort(mimeTypes.all.begin(), mimeTypes.all.end(), [](const QMimeType &lhs, const QMimeType &rhs) { 0351 return lhs.comment() < rhs.comment(); 0352 }); 0353 0354 return mimeTypes; 0355 }); 0356 0357 auto *watcher = new QFutureWatcher<MimeTypes>(this); 0358 watcher->setFuture(mimeTypeFuture); 0359 connect(watcher, &QFutureWatcher<MimeTypes>::finished, this, [this, watcher] { 0360 const MimeTypes &mimeTypes = watcher->result(); 0361 0362 for (const auto &mime : std::as_const(mimeTypes.all)) { 0363 typeBox->addItem(mime.comment()); 0364 } 0365 0366 m_types = mimeTypes.all; 0367 0368 m_ImageTypes = mimeTypes.image; 0369 m_VideoTypes = mimeTypes.video; 0370 m_AudioTypes = mimeTypes.audio; 0371 0372 watcher->deleteLater(); 0373 }); 0374 0375 // Layout 0376 tmp = sizeEdit->fontMetrics().boundingRect(QStringLiteral(" 00000 ")).width(); 0377 sizeEdit->setMinimumSize(tmp, sizeEdit->sizeHint().height()); 0378 0379 QGridLayout *grid2 = new QGridLayout(pages[2]); 0380 grid2->addWidget(typeL, 0, 0); 0381 grid2->addWidget(textL, 1, 0); 0382 grid2->addWidget(typeBox, 0, 1, 1, 3); 0383 grid2->addWidget(textEdit, 1, 1, 1, 3); 0384 grid2->addWidget(caseContextCb, 2, 1); 0385 grid2->addWidget(binaryContextCb, 3, 1); 0386 0387 grid2->addWidget(textMetaKey, 4, 0); 0388 grid2->addWidget(metainfokeyEdit, 4, 1); 0389 grid2->addWidget(textMetaInfo, 4, 2, Qt::AlignHCenter); 0390 grid2->addWidget(metainfoEdit, 4, 3); 0391 0392 metainfokeyEdit->setText(QStringLiteral("*")); 0393 0394 addTab(pages[0], i18n("Name/&Location")); 0395 addTab(pages[2], i18nc("tab name: search by contents", "C&ontents")); 0396 addTab(pages[1], i18n("&Properties")); 0397 0398 // Setup 0399 const QString whatsmetainfo 0400 = i18n("<qt>Search within files' specific comments/metainfo<br />" 0401 "These are some examples:<br />" 0402 "<ul>" 0403 "<li><b>Audio files (mp3...)</b> Search in id3 tag for a title, an album</li>" 0404 "<li><b>Images (png...)</b> Search images with a special resolution, comment...</li>" 0405 "</ul>" 0406 "</qt>"); 0407 const QString whatsmetainfokey 0408 = i18n("<qt>If specified, search only in this field<br />" 0409 "<ul>" 0410 "<li><b>Audio files (mp3...)</b> This can be Title, Album...</li>" 0411 "<li><b>Images (png...)</b> Search only in Resolution, Bitdepth...</li>" 0412 "</ul>" 0413 "</qt>"); 0414 textMetaInfo->setWhatsThis(whatsmetainfo); 0415 metainfoEdit->setToolTip(whatsmetainfo); 0416 textMetaKey->setWhatsThis(whatsmetainfokey); 0417 metainfokeyEdit->setToolTip(whatsmetainfokey); 0418 0419 fixLayout(); 0420 loadHistory(); 0421 } 0422 0423 KfindTabWidget::~KfindTabWidget() 0424 { 0425 delete pages[0]; 0426 delete pages[1]; 0427 delete pages[2]; 0428 delete bg; 0429 } 0430 0431 void KfindTabWidget::setURL(const QUrl &url) 0432 { 0433 KConfigGroup conf(KSharedConfig::openConfig(), "History"); 0434 m_url = url; 0435 QStringList sl = conf.readPathEntry("Directories", QStringList()); 0436 dirBox->clear(); // make sure there is no old Stuff in there 0437 0438 if (!sl.isEmpty()) { 0439 dirBox->addItems(sl); 0440 // If the _searchPath already exists in the list we do not 0441 // want to add it again 0442 int indx = sl.indexOf(m_url.toDisplayString()); 0443 if (indx == -1) { 0444 dirBox->insertItem(0, m_url.toDisplayString()); // make it the first one 0445 dirBox->setCurrentIndex(0); 0446 } else { 0447 dirBox->setCurrentIndex(indx); 0448 } 0449 } else { 0450 fillDirBox(); 0451 } 0452 } 0453 0454 void KfindTabWidget::fillDirBox() 0455 { 0456 QDir m_dir(QStringLiteral("/lib")); 0457 dirBox->insertItem(0, m_url.toDisplayString()); 0458 dirBox->addUrl(QUrl::fromLocalFile(QDir::homePath())); 0459 dirBox->addUrl(QUrl::fromLocalFile(QStringLiteral("/"))); 0460 dirBox->addUrl(QUrl::fromLocalFile(QStringLiteral("/usr"))); 0461 if (m_dir.exists()) { 0462 dirBox->addUrl(QUrl::fromLocalFile(QStringLiteral("lib"))); 0463 } 0464 dirBox->addUrl(QUrl::fromLocalFile(QStringLiteral("/home"))); 0465 dirBox->addUrl(QUrl::fromLocalFile(QStringLiteral("/etc"))); 0466 dirBox->addUrl(QUrl::fromLocalFile(QStringLiteral("/var"))); 0467 dirBox->addUrl(QUrl::fromLocalFile(QStringLiteral("/mnt"))); 0468 dirBox->setCurrentIndex(0); 0469 } 0470 0471 void KfindTabWidget::saveHistory() 0472 { 0473 save_pattern(nameBox, QStringLiteral("History"), QStringLiteral("Patterns")); 0474 save_pattern(dirBox, QStringLiteral("History"), QStringLiteral("Directories")); 0475 } 0476 0477 void KfindTabWidget::loadHistory() 0478 { 0479 // Load pattern history 0480 KConfigGroup conf(KSharedConfig::openConfig(), QStringLiteral("History")); 0481 QStringList sl = conf.readEntry(QStringLiteral("Patterns"), QStringList()); 0482 if (!sl.isEmpty()) { 0483 nameBox->addItems(sl); 0484 } else { 0485 nameBox->addItem(QStringLiteral("*")); 0486 } 0487 0488 sl = conf.readPathEntry(QStringLiteral("Directories"), QStringList()); 0489 if (!sl.isEmpty()) { 0490 dirBox->addItems(sl); 0491 // If the _searchPath already exists in the list we do not 0492 // want to add it again 0493 int indx = sl.indexOf(m_url.toDisplayString()); 0494 if (indx == -1) { 0495 dirBox->insertItem(0, m_url.toDisplayString()); // make it the first one 0496 dirBox->setCurrentIndex(0); 0497 } else { 0498 dirBox->setCurrentIndex(indx); 0499 } 0500 } else { 0501 fillDirBox(); 0502 } 0503 } 0504 0505 void KfindTabWidget::setFocus() 0506 { 0507 nameBox->setFocus(); 0508 nameBox->lineEdit()->selectAll(); 0509 } 0510 0511 void KfindTabWidget::slotSizeBoxChanged(int index) 0512 { 0513 sizeEdit->setEnabled((bool)(index != 0)); 0514 sizeUnitBox->setEnabled((bool)(index != 0)); 0515 } 0516 0517 void KfindTabWidget::setDefaults() 0518 { 0519 const QDate dt = QDate::currentDate().addYears(-1); 0520 0521 fromDate->setDate(dt); 0522 toDate->setDate(QDate::currentDate()); 0523 0524 timeBox->setValue(1); 0525 betweenType->setCurrentIndex(1); 0526 0527 typeBox->setCurrentIndex(0); 0528 sizeBox->setCurrentIndex(0); 0529 sizeUnitBox->setCurrentIndex(1); 0530 sizeEdit->setValue(1); 0531 } 0532 0533 /* 0534 Checks if dates are correct and popups a error box 0535 if they are not. 0536 */ 0537 bool KfindTabWidget::isDateValid() 0538 { 0539 // All files 0540 if (!findCreated->isChecked()) { 0541 return true; 0542 } 0543 0544 if (rb[1]->isChecked()) { 0545 if (timeBox->value() > 0) { 0546 return true; 0547 } 0548 0549 KMessageBox::error(this, i18n("Unable to search within a period which is less than a minute.")); 0550 return false; 0551 } 0552 0553 // If we can not parse either of the dates or 0554 // "from" date is bigger than "to" date return false. 0555 const QDate from = fromDate->date(); 0556 const QDate to = toDate->date(); 0557 0558 QString str; 0559 if (!from.isValid() || !to.isValid()) { 0560 str = i18n("The date is not valid."); 0561 } else if (from > to) { 0562 str = i18n("Invalid date range."); 0563 } else if (from > QDate::currentDate()) { 0564 str = i18n("Unable to search dates in the future."); 0565 } 0566 0567 if (!str.isEmpty()) { 0568 KMessageBox::error(nullptr, str); 0569 return false; 0570 } 0571 return true; 0572 } 0573 0574 void KfindTabWidget::setQuery(KQuery *query) 0575 { 0576 KIO::filesize_t size; 0577 KIO::filesize_t sizeunit; 0578 bool itemAlreadyContained(false); 0579 // only start if we have valid dates 0580 if (!isDateValid()) { 0581 return; 0582 } 0583 0584 const QString trimmedDirBoxText = dirBox->currentText().trimmed(); 0585 const QString tildeExpandedPath = KShell::tildeExpand(trimmedDirBoxText); 0586 0587 query->setPath(QUrl::fromUserInput(tildeExpandedPath, m_url.toLocalFile(), QUrl::AssumeLocalFile)); 0588 0589 for (int idx = 0; idx < dirBox->count(); idx++) { 0590 if (dirBox->itemText(idx) == dirBox->currentText()) { 0591 itemAlreadyContained = true; 0592 } 0593 } 0594 0595 if (!itemAlreadyContained) { 0596 dirBox->addItem(dirBox->currentText().trimmed(), 0); 0597 } 0598 0599 QString regex = nameBox->currentText().isEmpty() ? QStringLiteral("*") : nameBox->currentText(); 0600 query->setRegExp(regex, caseSensCb->isChecked()); 0601 itemAlreadyContained = false; 0602 for (int idx = 0; idx < nameBox->count(); idx++) { 0603 if (nameBox->itemText(idx) == nameBox->currentText()) { 0604 itemAlreadyContained = true; 0605 } 0606 } 0607 0608 if (!itemAlreadyContained) { 0609 nameBox->addItem(nameBox->currentText(), 0); 0610 } 0611 0612 query->setRecursive(subdirsCb->isChecked()); 0613 0614 switch (sizeUnitBox->currentIndex()) { 0615 case 0: 0616 sizeunit = 1; //one byte 0617 break; 0618 case 2: 0619 sizeunit = 1048576; //1Mi 0620 break; 0621 case 3: 0622 sizeunit = 1073741824; //1Gi 0623 break; 0624 case 1: // fall to default case 0625 default: 0626 sizeunit = 1024; //1Ki 0627 break; 0628 } 0629 size = sizeEdit->value() * sizeunit; 0630 0631 // TODO: troeder: do we need this check since it is very unlikely 0632 // to exceed ULLONG_MAX with INT_MAX * 1024^3. 0633 // Or is there an arch where this can happen? 0634 #if 0 0635 if (size < 0) { // overflow 0636 if (KMessageBox::warningTwoActions(this, i18n("Size is too big. Set maximum size value?"), i18n("Error"), i18n("Set"), i18n("Do Not Set")) 0637 == KMessageBox::ButtonCode::PrimaryAction) { 0638 sizeEdit->setValue(INT_MAX); 0639 sizeUnitBox->setCurrentIndex(0); 0640 size = INT_MAX; 0641 } else { 0642 return; 0643 } 0644 } 0645 #endif 0646 0647 // set range mode and size value 0648 query->setSizeRange(sizeBox->currentIndex(), size, 0); 0649 0650 // dates 0651 QDateTime epoch; 0652 epoch.setSecsSinceEpoch(0); 0653 0654 // Add date predicate 0655 if (findCreated->isChecked()) { // Modified 0656 if (rb[0]->isChecked()) { // Between dates 0657 const QDate &from = fromDate->date(); 0658 const QDate &to = toDate->date(); 0659 // do not generate negative numbers .. find doesn't handle that 0660 time_t time1 = epoch.secsTo(QDateTime(from.startOfDay())); 0661 time_t time2 = epoch.secsTo(QDateTime(to.addDays(1).startOfDay())) - 1; // Include the last day 0662 0663 query->setTimeRange(time1, time2); 0664 } else { 0665 time_t cur = time(nullptr); 0666 time_t minutes = cur; 0667 0668 switch (betweenType->currentIndex()) { 0669 case 0: // minutes 0670 minutes = timeBox->value(); 0671 break; 0672 case 1: // hours 0673 minutes = 60 * timeBox->value(); 0674 break; 0675 case 2: // days 0676 minutes = 60 * 24 * timeBox->value(); 0677 break; 0678 case 3: // months 0679 minutes = 60 * 24 * (time_t)(timeBox->value() * 30.41667); 0680 break; 0681 case 4: // years 0682 minutes = 12 * 60 * 24 * (time_t)(timeBox->value() * 30.41667); 0683 break; 0684 } 0685 0686 query->setTimeRange(cur - minutes * 60, 0); 0687 } 0688 } else { 0689 query->setTimeRange(0, 0); 0690 } 0691 0692 query->setUsername(m_usernameBox->currentText()); 0693 query->setGroupname(m_groupBox->currentText()); 0694 0695 query->setFileType(typeBox->currentIndex()); 0696 0697 int id = typeBox->currentIndex() - specialMimeTypeCount - 1 /*the separator*/; 0698 0699 if ((id >= -4) && (id < (int)m_types.count())) { 0700 switch (id) { 0701 case -4: 0702 query->setMimeType(m_ImageTypes); 0703 break; 0704 case -3: 0705 query->setMimeType(m_VideoTypes); 0706 break; 0707 case -2: 0708 query->setMimeType(m_AudioTypes); 0709 break; 0710 default: 0711 query->setMimeType(QStringList() += m_types.value(id).name()); 0712 } 0713 } else { 0714 query->setMimeType(QStringList()); 0715 } 0716 0717 //Metainfo 0718 query->setMetaInfo(metainfoEdit->text(), metainfokeyEdit->text()); 0719 0720 //Use locate to speed-up search ? 0721 query->setUseFileIndex(useLocateCb->isChecked()); 0722 0723 query->setShowHiddenFiles(hiddenFilesCb->isChecked()); 0724 0725 query->setContext(textEdit->text(), caseContextCb->isChecked(), binaryContextCb->isChecked()); 0726 } 0727 0728 void KfindTabWidget::getDirectory() 0729 { 0730 const QString result 0731 = QFileDialog::getExistingDirectory(this, QString(), dirBox->currentText().trimmed()); 0732 0733 if (!result.isEmpty()) { 0734 for (int i = 0; i < dirBox->count(); i++) { 0735 if (result == dirBox->itemText(i)) { 0736 dirBox->setCurrentIndex(i); 0737 return; 0738 } 0739 } 0740 dirBox->insertItem(0, result); 0741 dirBox->setCurrentIndex(0); 0742 } 0743 } 0744 0745 void KfindTabWidget::beginSearch() 0746 { 0747 /// dirlister->openUrl(KUrl(dirBox->currentText().trimmed())); 0748 0749 saveHistory(); 0750 0751 for(QWidget *page : pages) { 0752 page->setEnabled(false); 0753 } 0754 } 0755 0756 void KfindTabWidget::endSearch() 0757 { 0758 for(QWidget *page : pages) { 0759 page->setEnabled(true); 0760 } 0761 } 0762 0763 /* 0764 Disables/enables all edit fields depending on their 0765 respective check buttons. 0766 */ 0767 void KfindTabWidget::fixLayout() 0768 { 0769 int i; 0770 // If "All files" is checked - disable all edits 0771 // and second radio group on page two 0772 0773 if (!findCreated->isChecked()) { 0774 fromDate->setEnabled(false); 0775 toDate->setEnabled(false); 0776 andL->setEnabled(false); 0777 timeBox->setEnabled(false); 0778 for (i = 0; i < 2; ++i) { 0779 rb[i]->setEnabled(false); 0780 } 0781 betweenType->setEnabled(false); 0782 } else { 0783 for (i = 0; i < 2; ++i) { 0784 rb[i]->setEnabled(true); 0785 } 0786 0787 fromDate->setEnabled(rb[0]->isChecked()); 0788 toDate->setEnabled(rb[0]->isChecked()); 0789 andL->setEnabled(rb[0]->isEnabled()); 0790 timeBox->setEnabled(rb[1]->isChecked()); 0791 betweenType->setEnabled(rb[1]->isChecked()); 0792 } 0793 0794 // Size box on page three 0795 sizeEdit->setEnabled(sizeBox->currentIndex() != 0); 0796 sizeUnitBox->setEnabled(sizeBox->currentIndex() != 0); 0797 } 0798 0799 bool KfindTabWidget::isSearchRecursive() 0800 { 0801 return subdirsCb->isChecked(); 0802 } 0803 0804 void KfindTabWidget::slotUpdateDateLabelsForNumber(int value) 0805 { 0806 updateDateLabels(betweenType->currentIndex(), value); 0807 } 0808 0809 void KfindTabWidget::slotUpdateDateLabelsForType(int index) 0810 { 0811 updateDateLabels(index, timeBox->value()); 0812 } 0813 0814 void KfindTabWidget::updateDateLabels(int type, int value) 0815 { 0816 QString typeKey(type == 0 ? QLatin1Char('i') : type == 1 ? QLatin1Char('h') : type == 2 ? QLatin1Char('d') : type == 3 ? QLatin1Char('m') : QLatin1Char('y')); 0817 rb[1]->setText(ki18ncp("during the previous minute(s)/hour(s)/...; " 0818 "dynamic context 'type': 'i' minutes, 'h' hours, 'd' days, 'm' months, 'y' years", 0819 "&during the previous", "&during the previous").subs(value).inContext(QStringLiteral("type"), typeKey).toString()); 0820 betweenType->setItemText(0, i18ncp("use date ranges to search files by modified time", "minute", "minutes", value)); 0821 betweenType->setItemText(1, i18ncp("use date ranges to search files by modified time", "hour", "hours", value)); 0822 betweenType->setItemText(2, i18ncp("use date ranges to search files by modified time", "day", "days", value)); 0823 betweenType->setItemText(3, i18ncp("use date ranges to search files by modified time", "month", "months", value)); 0824 betweenType->setItemText(4, i18ncp("use date ranges to search files by modified time", "year", "years", value)); 0825 } 0826 0827 void KfindTabWidget::slotUpdateByteComboBox(int value) 0828 { 0829 sizeUnitBox->setItemText(0, i18np("Byte", "Bytes", value)); 0830 } 0831 0832 //******************************************************* 0833 // Static utility functions 0834 //******************************************************* 0835 static void save_pattern(KComboBox *obj, const QString &group, const QString &entry) 0836 { 0837 // QComboBox allows insertion of items more than specified by 0838 // maxCount() (QT bug?). This API call will truncate list if needed. 0839 obj->setMaxCount(15); 0840 0841 // make sure the current item is saved first so it will be the 0842 // default when started next time 0843 QStringList sl; 0844 QString cur = obj->itemText(obj->currentIndex()); 0845 sl.append(cur); 0846 for (int i = 0; i < obj->count(); i++) { 0847 if (cur != obj->itemText(i)) { 0848 sl.append(obj->itemText(i)); 0849 } 0850 } 0851 0852 KConfigGroup conf(KSharedConfig::openConfig(), group); 0853 conf.writePathEntry(entry, sl); 0854 } 0855 0856 QSize KfindTabWidget::sizeHint() const 0857 { 0858 // #44662: avoid a huge default size when the comboboxes have very large items 0859 // Like in minicli, we changed the combobox size policy so that they can resize down, 0860 // and then we simply provide a reasonable size hint for the whole window, depending 0861 // on the screen width. 0862 QSize sz = QTabWidget::sizeHint(); 0863 const int halfScreenWidth = screen()->availableGeometry().width() / 2; 0864 if (sz.width() > halfScreenWidth) { 0865 sz.setWidth(halfScreenWidth); 0866 } 0867 return sz; 0868 } 0869 0870 #include "moc_kftabdlg.cpp"