File indexing completed on 2024-07-21 05:13:05

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     QList<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(QList<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(), QStringLiteral("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"