File indexing completed on 2024-05-05 17:57:23

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 "krsearchdialog.h"
0010 
0011 // QtCore
0012 #include <QMimeData>
0013 #include <QRegExp>
0014 // QtGui
0015 #include <QClipboard>
0016 #include <QCloseEvent>
0017 #include <QCursor>
0018 #include <QDrag>
0019 #include <QKeyEvent>
0020 #include <QResizeEvent>
0021 // QtWidgets
0022 #include <QApplication>
0023 #include <QGridLayout>
0024 #include <QHBoxLayout>
0025 #include <QInputDialog>
0026 #include <QMenu>
0027 
0028 #include <KConfigCore/KConfig>
0029 #include <KConfigWidgets/KStandardAction>
0030 #include <KI18n/KLocalizedString>
0031 #include <KWidgetsAddons/KMessageBox>
0032 
0033 #include "../Dialogs/krdialogs.h"
0034 #include "../Dialogs/krspecialwidgets.h"
0035 #include "../Dialogs/krsqueezedtextlabel.h"
0036 #include "../FileSystem/fileitem.h"
0037 #include "../FileSystem/krquery.h"
0038 #include "../FileSystem/virtualfilesystem.h"
0039 #include "../Filter/filtertabs.h"
0040 #include "../Filter/generalfilter.h"
0041 #include "../KViewer/krviewer.h"
0042 #include "../Panel/PanelView/krview.h"
0043 #include "../Panel/PanelView/krviewfactory.h"
0044 #include "../Panel/PanelView/krviewitem.h"
0045 #include "../Panel/krpanel.h"
0046 #include "../Panel/krsearchbar.h"
0047 #include "../Panel/panelfunc.h"
0048 #include "../defaults.h"
0049 #include "../filelisticon.h"
0050 #include "../kractions.h"
0051 #include "../krglobal.h"
0052 #include "../krservices.h"
0053 #include "../krslots.h"
0054 #include "../krusaderview.h"
0055 #include "../panelmanager.h"
0056 #include "krsearchmod.h"
0057 
0058 #define RESULTVIEW_TYPE 0
0059 
0060 class SearchResultContainer : public DirListerInterface
0061 {
0062 public:
0063     explicit SearchResultContainer(QObject *parent)
0064         : DirListerInterface(parent)
0065     {
0066     }
0067     ~SearchResultContainer() override
0068     {
0069         clear();
0070     }
0071 
0072     QList<FileItem *> fileItems() const override
0073     {
0074         return _fileItems;
0075     }
0076     unsigned long numFileItems() const override
0077     {
0078         return _fileItems.count();
0079     }
0080     bool isRoot() const override
0081     {
0082         return true;
0083     }
0084 
0085     void clear()
0086     {
0087         emit cleared();
0088         foreach (FileItem *fileitem, _fileItems)
0089             delete fileitem;
0090         _fileItems.clear();
0091         _foundText.clear();
0092     }
0093 
0094     void addItem(const FileItem &file, const QString &foundText)
0095     {
0096         const QString path = file.getUrl().toDisplayString(QUrl::PreferLocalFile);
0097         FileItem *fileitem = FileItem::createCopy(file, path);
0098         _fileItems << fileitem;
0099         if (!foundText.isEmpty())
0100             _foundText[fileitem] = foundText;
0101         emit addedFileItem(fileitem);
0102     }
0103 
0104     QString foundText(const FileItem *fileitem)
0105     {
0106         return _foundText[fileitem];
0107     }
0108 
0109 private:
0110     QList<FileItem *> _fileItems;
0111     QHash<const FileItem *, QString> _foundText;
0112 };
0113 
0114 KrSearchDialog *KrSearchDialog::SearchDialog = nullptr;
0115 
0116 QString KrSearchDialog::lastSearchText = QString('*');
0117 int KrSearchDialog::lastSearchType = 0;
0118 bool KrSearchDialog::lastSearchForCase = false;
0119 bool KrSearchDialog::lastContainsWholeWord = false;
0120 bool KrSearchDialog::lastContainsWithCase = false;
0121 bool KrSearchDialog::lastSearchInSubDirs = true;
0122 bool KrSearchDialog::lastSearchInArchives = false;
0123 bool KrSearchDialog::lastFollowSymLinks = false;
0124 bool KrSearchDialog::lastContainsRegExp = false;
0125 
0126 // class starts here /////////////////////////////////////////
0127 KrSearchDialog::KrSearchDialog(const QString &profile, QWidget *parent)
0128     : QDialog(parent)
0129     , query(nullptr)
0130     , searcher(nullptr)
0131     , isBusy(false)
0132     , closed(false)
0133 {
0134     KConfigGroup group(krConfig, "Search");
0135 
0136     setWindowTitle(i18n("Krusader::Search"));
0137     setWindowIcon(Icon("system-search"));
0138 
0139     auto *searchBaseLayout = new QGridLayout(this);
0140     searchBaseLayout->setSpacing(6);
0141     searchBaseLayout->setContentsMargins(11, 11, 11, 11);
0142 
0143     // creating the dialog buttons ( Search, Stop, Close )
0144 
0145     auto *buttonsLayout = new QHBoxLayout();
0146     buttonsLayout->setSpacing(6);
0147     buttonsLayout->setContentsMargins(0, 0, 0, 0);
0148 
0149     profileManager = new ProfileManager("SearcherProfile", this);
0150     buttonsLayout->addWidget(profileManager);
0151 
0152     searchTextToClipboard = new QCheckBox(this);
0153     searchTextToClipboard->setText(i18n("Query to clipboard"));
0154     searchTextToClipboard->setToolTip(i18n("Place search text to clipboard when a found file is opened."));
0155     searchTextToClipboard->setCheckState(static_cast<Qt::CheckState>(group.readEntry("QueryToClipboard", 0)));
0156     connect(searchTextToClipboard, &QCheckBox::stateChanged, this, [=](int state) {
0157         KConfigGroup group(krConfig, "Search");
0158         group.writeEntry("QueryToClipboard", state);
0159     });
0160     buttonsLayout->addWidget(searchTextToClipboard);
0161 
0162     auto *spacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
0163     buttonsLayout->addItem(spacer);
0164 
0165     mainSearchBtn = new QPushButton(this);
0166     mainSearchBtn->setText(i18n("Search"));
0167     mainSearchBtn->setIcon(Icon("edit-find"));
0168     mainSearchBtn->setDefault(true);
0169     buttonsLayout->addWidget(mainSearchBtn);
0170 
0171     mainStopBtn = new QPushButton(this);
0172     mainStopBtn->setEnabled(false);
0173     mainStopBtn->setText(i18n("Stop"));
0174     mainStopBtn->setIcon(Icon("process-stop"));
0175     buttonsLayout->addWidget(mainStopBtn);
0176 
0177     mainCloseBtn = new QPushButton(this);
0178     mainCloseBtn->setText(i18n("Close"));
0179     mainCloseBtn->setIcon(Icon("dialog-close"));
0180     buttonsLayout->addWidget(mainCloseBtn);
0181 
0182     searchBaseLayout->addLayout(buttonsLayout, 1, 0);
0183 
0184     // creating the searcher tabs
0185 
0186     searcherTabs = new QTabWidget(this);
0187 
0188     filterTabs = FilterTabs::addTo(searcherTabs, FilterTabs::Default);
0189     generalFilter = dynamic_cast<GeneralFilter *>(filterTabs->get("GeneralFilter"));
0190 
0191     // creating the result tab
0192 
0193     QWidget *resultTab = new QWidget(searcherTabs);
0194     auto *resultLayout = new QGridLayout(resultTab);
0195     resultLayout->setSpacing(6);
0196     resultLayout->setContentsMargins(6, 6, 6, 6);
0197 
0198     // actions
0199     viewAction = new QAction(Icon("document-edit-preview"), i18n("View File"), this);
0200     viewAction->setShortcut(Qt::Key_F3);
0201     connect(viewAction, &QAction::triggered, this, &KrSearchDialog::viewCurrent);
0202     addAction(viewAction);
0203 
0204     editAction = new QAction(Icon("document-edit-sign"), i18n("Edit File"), this);
0205     editAction->setShortcut(Qt::Key_F4);
0206     connect(editAction, &QAction::triggered, this, &KrSearchDialog::editCurrent);
0207     addAction(editAction);
0208 
0209     compareAction = new QAction(i18n("Compare by content"), this);
0210     compareAction->setShortcut(Qt::Key_F10);
0211     connect(compareAction, &QAction::triggered, this, &KrSearchDialog::compareByContent);
0212     addAction(compareAction);
0213 
0214     copyAction = KStandardAction::create(KStandardAction::Copy, this, SLOT(copyToClipBoard()), this);
0215     copyAction->setText(i18n("Copy to Clipboard"));
0216     addAction(copyAction);
0217 
0218     connect(searcherTabs, &QTabWidget::currentChanged, this, [=](int index) {
0219         bool resultTabShown = index == searcherTabs->indexOf(resultTab);
0220         viewAction->setEnabled(resultTabShown);
0221         editAction->setEnabled(resultTabShown);
0222         compareAction->setEnabled(resultTabShown);
0223         copyAction->setEnabled(resultTabShown);
0224     });
0225 
0226     // creating the result list view
0227     result = new SearchResultContainer(this);
0228     // the view
0229     resultView = KrViewFactory::createView(RESULTVIEW_TYPE, resultTab, krConfig);
0230     resultView->init(false);
0231     resultView->restoreSettings(KConfigGroup(&group, "ResultView"));
0232     resultView->setMainWindow(this);
0233     resultView->prepareForActive();
0234     resultView->refreshColors();
0235     resultView->setFiles(result);
0236     resultView->refresh();
0237     resultLayout->addWidget(resultView->widget(), 0, 0);
0238     // search bar - hidden by default
0239     searchBar = new KrSearchBar(resultView, this);
0240     searchBar->hide();
0241     resultLayout->addWidget(searchBar, 1, 0);
0242 
0243     // text found row
0244     foundTextFrame = new QFrame(resultTab);
0245     foundTextFrame->setFrameShape(QLabel::StyledPanel);
0246     foundTextFrame->setFrameShadow(QLabel::Sunken);
0247 
0248     auto *foundTextLayout = new QHBoxLayout();
0249     foundTextLayout->setSpacing(6);
0250 
0251     QLabel *textFoundLabel = new QLabel(i18n("Text found:"), resultTab);
0252     foundTextLayout->addWidget(textFoundLabel);
0253     foundTextLabel = new KrSqueezedTextLabel(resultTab);
0254     foundTextLayout->addWidget(foundTextLabel);
0255 
0256     foundTextFrame->setLayout(foundTextLayout);
0257     foundTextFrame->hide();
0258 
0259     resultLayout->addWidget(foundTextFrame, 2, 0);
0260 
0261     // result info row
0262     auto *resultLabelLayout = new QHBoxLayout();
0263     resultLabelLayout->setSpacing(6);
0264     resultLabelLayout->setContentsMargins(0, 0, 0, 0);
0265 
0266     searchingLabel = new KSqueezedTextLabel(i18n("Idle"), resultTab);
0267     resultLabelLayout->addWidget(searchingLabel);
0268 
0269     foundLabel = new QLabel("", resultTab);
0270     resultLabelLayout->addWidget(foundLabel);
0271 
0272     mainFeedToListBoxBtn = new QPushButton(QIcon::fromTheme("list-add"), i18n("Feed to listbox"), this);
0273     mainFeedToListBoxBtn->setEnabled(false);
0274     resultLabelLayout->addWidget(mainFeedToListBoxBtn);
0275 
0276     resultLayout->addLayout(resultLabelLayout, 3, 0);
0277 
0278     searcherTabs->addTab(resultTab, i18n("&Results"));
0279 
0280     searchBaseLayout->addWidget(searcherTabs, 0, 0);
0281 
0282     // signals and slots connections
0283 
0284     connect(mainSearchBtn, &QPushButton::clicked, this, &KrSearchDialog::startSearch);
0285     connect(mainStopBtn, &QPushButton::clicked, this, &KrSearchDialog::stopSearch);
0286     connect(mainCloseBtn, &QPushButton::clicked, this, &KrSearchDialog::closeDialog);
0287     connect(mainFeedToListBoxBtn, &QPushButton::clicked, this, &KrSearchDialog::feedToListBox);
0288 
0289     connect(profileManager, &ProfileManager::loadFromProfile, filterTabs, &FilterTabs::loadFromProfile);
0290     connect(profileManager, &ProfileManager::saveToProfile, filterTabs, &FilterTabs::saveToProfile);
0291 
0292     connect(resultView->op(), &KrViewOperator::currentChanged, this, &KrSearchDialog::currentChanged);
0293     connect(resultView->op(), &KrViewOperator::executed, this, &KrSearchDialog::executed);
0294     connect(resultView->op(), &KrViewOperator::contextMenu, this, &KrSearchDialog::contextMenu);
0295 
0296     // tab order
0297 
0298     setTabOrder(mainSearchBtn, mainCloseBtn);
0299     setTabOrder(mainCloseBtn, mainStopBtn);
0300     setTabOrder(mainStopBtn, searcherTabs);
0301     setTabOrder(searcherTabs, resultView->widget());
0302 
0303     sizeX = group.readEntry("Window Width", -1);
0304     sizeY = group.readEntry("Window Height", -1);
0305 
0306     if (sizeX != -1 && sizeY != -1)
0307         resize(sizeX, sizeY);
0308 
0309     if (group.readEntry("Window Maximized", false))
0310         showMaximized();
0311     else
0312         show();
0313 
0314     generalFilter->searchFor->setFocus();
0315 
0316     // finally, load a profile of apply defaults:
0317 
0318     if (profile.isEmpty()) {
0319         // load the last used values
0320         generalFilter->searchFor->setEditText(lastSearchText);
0321         generalFilter->searchFor->lineEdit()->selectAll();
0322         generalFilter->ofType->setCurrentIndex(lastSearchType);
0323         generalFilter->searchForCase->setChecked(lastSearchForCase);
0324         generalFilter->containsWholeWord->setChecked(lastContainsWholeWord);
0325         generalFilter->containsTextCase->setChecked(lastContainsWithCase);
0326         generalFilter->containsRegExp->setChecked(lastContainsRegExp);
0327         generalFilter->searchInDirs->setChecked(lastSearchInSubDirs);
0328         generalFilter->searchInArchives->setChecked(lastSearchInArchives);
0329         generalFilter->followLinks->setChecked(lastFollowSymLinks);
0330         // the path in the active panel should be the default search location
0331         generalFilter->searchIn->lineEdit()->setText(ACTIVE_PANEL->virtualPath().toDisplayString(QUrl::PreferLocalFile));
0332     } else
0333         profileManager->loadProfile(profile); // important: call this _after_ you've connected profileManager ot the loadFromProfile!!
0334 }
0335 
0336 KrSearchDialog::~KrSearchDialog()
0337 {
0338     delete query;
0339     query = nullptr;
0340     delete resultView;
0341     resultView = nullptr;
0342 }
0343 
0344 void KrSearchDialog::closeDialog(bool isAccept)
0345 {
0346     if (isBusy) {
0347         closed = true;
0348         return;
0349     }
0350 
0351     // stop the search if it's on-going
0352     if (searcher != nullptr) {
0353         delete searcher;
0354         searcher = nullptr;
0355     }
0356 
0357     // saving the searcher state
0358 
0359     KConfigGroup group(krConfig, "Search");
0360 
0361     group.writeEntry("Window Width", sizeX);
0362     group.writeEntry("Window Height", sizeY);
0363     group.writeEntry("Window Maximized", isMaximized());
0364 
0365     resultView->saveSettings(KConfigGroup(&group, "ResultView"));
0366 
0367     lastSearchText = generalFilter->searchFor->currentText();
0368     lastSearchType = generalFilter->ofType->currentIndex();
0369     lastSearchForCase = generalFilter->searchForCase->isChecked();
0370     lastContainsWholeWord = generalFilter->containsWholeWord->isChecked();
0371     lastContainsWithCase = generalFilter->containsTextCase->isChecked();
0372     lastContainsRegExp = generalFilter->containsRegExp->isChecked();
0373     lastSearchInSubDirs = generalFilter->searchInDirs->isChecked();
0374     lastSearchInArchives = generalFilter->searchInArchives->isChecked();
0375     lastFollowSymLinks = generalFilter->followLinks->isChecked();
0376     hide();
0377 
0378     SearchDialog = nullptr;
0379     if (isAccept)
0380         QDialog::accept();
0381     else
0382         QDialog::reject();
0383 
0384     this->deleteLater();
0385 }
0386 
0387 void KrSearchDialog::reject()
0388 {
0389     closeDialog(false);
0390 }
0391 
0392 void KrSearchDialog::resizeEvent(QResizeEvent *e)
0393 {
0394     if (!isMaximized()) {
0395         sizeX = e->size().width();
0396         sizeY = e->size().height();
0397     }
0398 }
0399 
0400 void KrSearchDialog::slotFound(const FileItem &file, const QString &foundText)
0401 {
0402     result->addItem(file, foundText);
0403     foundLabel->setText(i18np("Found %1 match.", "Found %1 matches.", result->numFileItems()));
0404 }
0405 
0406 bool KrSearchDialog::gui2query()
0407 {
0408     // prepare the query ...
0409     /////////////////// names, locations and greps
0410     if (query != nullptr) {
0411         delete query;
0412         query = nullptr;
0413     }
0414     query = new KrQuery();
0415 
0416     return filterTabs->fillQuery(query);
0417 }
0418 
0419 void KrSearchDialog::startSearch()
0420 {
0421     if (isBusy)
0422         return;
0423 
0424     // prepare the query /////////////////////////////////////////////
0425     if (!gui2query())
0426         return;
0427 
0428     // first, informative messages
0429     if (query->searchInArchives()) {
0430         KMessageBox::information(this,
0431                                  i18n("Since you chose to also search in archives, "
0432                                       "note the following limitations:\n"
0433                                       "You cannot search for text (grep) while doing"
0434                                       " a search that includes archives."),
0435                                  nullptr,
0436                                  "searchInArchives");
0437     }
0438 
0439     // prepare the gui ///////////////////////////////////////////////
0440     result->clear();
0441     resultView->setSortMode(KrViewProperties::NoColumn, 0);
0442 
0443     foundTextFrame->setVisible(!query->content().isEmpty());
0444     foundTextLabel->setText("");
0445 
0446     searchingLabel->setText("");
0447     foundLabel->setText(i18n("Found 0 matches."));
0448     mainFeedToListBoxBtn->setEnabled(false);
0449 
0450     mainSearchBtn->setEnabled(false);
0451     mainStopBtn->setEnabled(true);
0452     mainCloseBtn->setEnabled(false);
0453 
0454     searcherTabs->setCurrentIndex(2); // show the results page
0455 
0456     isBusy = true;
0457 
0458     qApp->processEvents();
0459 
0460     // start the search.
0461     if (searcher != nullptr)
0462         abort();
0463     searcher = new KrSearchMod(query);
0464     connect(searcher, &KrSearchMod::searching, searchingLabel, &KSqueezedTextLabel::setText);
0465     connect(searcher, &KrSearchMod::found, this, &KrSearchDialog::slotFound);
0466     connect(searcher, &KrSearchMod::finished, this, &KrSearchDialog::stopSearch);
0467 
0468     searcher->start();
0469 
0470     isBusy = false;
0471 
0472     delete searcher;
0473     searcher = nullptr;
0474 
0475     // gui stuff
0476     mainSearchBtn->setEnabled(true);
0477     mainCloseBtn->setEnabled(true);
0478     mainStopBtn->setEnabled(false);
0479     if (result->numFileItems())
0480         mainFeedToListBoxBtn->setEnabled(true);
0481     searchingLabel->setText(i18n("Finished searching."));
0482 
0483     // go to the first result. Note: `getFirst()` doesn't cause problems
0484     // if the results list is empty
0485     resultView->setCurrentKrViewItem(resultView->getFirst());
0486 
0487     if (closed)
0488         closeDialog();
0489 }
0490 
0491 void KrSearchDialog::stopSearch()
0492 {
0493     if (searcher != nullptr) {
0494         searcher->stop();
0495         disconnect(searcher, nullptr, nullptr, nullptr);
0496     }
0497 }
0498 
0499 void KrSearchDialog::executed(const QString &name)
0500 {
0501     // 'name' is (local) file path or complete URL
0502     QString path = name;
0503     QString fileName;
0504     if (!name.endsWith('/')) {
0505         // not a directory, split filename and path
0506         int idx = name.lastIndexOf("/");
0507         fileName = name.mid(idx + 1);
0508         path = name.left(idx);
0509     }
0510     QUrl url(path);
0511     if (url.scheme().isEmpty()) {
0512         url = QUrl::fromLocalFile(path);
0513     }
0514     ACTIVE_FUNC->openUrl(url, fileName);
0515     showMinimized();
0516 }
0517 
0518 void KrSearchDialog::currentChanged(KrViewItem *item)
0519 {
0520     if (!item)
0521         return;
0522     QString text = result->foundText(item->getFileItem());
0523     if (!text.isEmpty()) {
0524         // ugly hack: find the <b> and </b> in the text, then
0525         // use it to set the are which we don't want squeezed
0526         int idx = text.indexOf("<b>") - 4; // take "<qt>" into account
0527         int length = text.indexOf("</b>") - idx + 4;
0528         foundTextLabel->setText(text, idx, length);
0529     }
0530 }
0531 
0532 void KrSearchDialog::closeEvent(QCloseEvent *e)
0533 { /* if searching is in progress we must not close the window */
0534     if (isBusy) /* because qApp->processEvents() is called by the searcher and */
0535     { /* at window destruction, the searcher object will be deleted */
0536         stopSearch(); /* instead we stop searching */
0537         closed = true; /* and after stopping: startSearch can close the window */
0538         e->ignore(); /* ignoring the close event */
0539     } else
0540         QDialog::closeEvent(e); /* if no searching, let QDialog handle the event */
0541 }
0542 
0543 void KrSearchDialog::keyPressEvent(QKeyEvent *e)
0544 {
0545     // TODO: don't use hardcoded shortcuts
0546 
0547     if (isBusy && e->key() == Qt::Key_Escape) { /* at searching we must not close the window */
0548         stopSearch(); /* so we simply stop searching */
0549         return;
0550     }
0551     if (resultView->widget()->hasFocus()) {
0552         if ((e->key() | e->modifiers()) == (Qt::CTRL | Qt::Key_I)) {
0553             searchBar->showBar(KrSearchBar::MODE_FILTER);
0554         }
0555         if (e->key() == Qt::Key_Menu) {
0556             contextMenu(QCursor::pos());
0557         }
0558     }
0559     QDialog::keyPressEvent(e);
0560 }
0561 
0562 void KrSearchDialog::editCurrent()
0563 {
0564     tryPlaceSearchQueryToClipboard();
0565     KrViewItem *current = resultView->getCurrentKrViewItem();
0566     if (current)
0567         KrViewer::edit(current->getFileItem()->getUrl(), this);
0568 }
0569 
0570 void KrSearchDialog::viewCurrent()
0571 {
0572     tryPlaceSearchQueryToClipboard();
0573     KrViewItem *current = resultView->getCurrentKrViewItem();
0574     if (current)
0575         KrViewer::view(current->getFileItem()->getUrl(), this);
0576 }
0577 
0578 void KrSearchDialog::compareByContent()
0579 {
0580     const KrViewItemList list = resultView->getSelectedKrViewItems();
0581     if (list.count() != 2)
0582         return;
0583 
0584     SLOTS->compareContent(list[0]->getFileItem()->getUrl(), list[1]->getFileItem()->getUrl());
0585 }
0586 
0587 void KrSearchDialog::contextMenu(const QPoint &pos)
0588 {
0589     // create the menu
0590     QMenu popup;
0591     popup.setTitle(i18n("Krusader Search"));
0592 
0593     popup.addAction(viewAction);
0594     popup.addAction(editAction);
0595     popup.addAction(compareAction);
0596     compareAction->setEnabled(resultView->numSelected() == 2);
0597     popup.addSeparator();
0598     popup.addAction(copyAction);
0599 
0600     popup.exec(pos);
0601 }
0602 
0603 void KrSearchDialog::feedToListBox()
0604 {
0605     VirtualFileSystem virtFilesystem;
0606     virtFilesystem.scanDir(QUrl::fromLocalFile("/"));
0607 
0608     KConfigGroup group(krConfig, "Search");
0609     int listBoxNum = group.readEntry("Feed To Listbox Counter", 1);
0610     QString queryName;
0611     if (query) {
0612         const QString where = KrServices::toStringList(query->searchInDirs()).join(", ");
0613         queryName = query->content().isEmpty() ? i18n("Search results for \"%1\" in %2", query->nameFilter(), where)
0614                                                : i18n("Search results for \"%1\" containing \"%2\" in %3", query->nameFilter(), query->content(), where);
0615     }
0616     QString fileSystemName;
0617     do {
0618         fileSystemName = i18n("Search results") + QString(" %1").arg(listBoxNum++);
0619     } while (virtFilesystem.getFileItem(fileSystemName) != nullptr);
0620     group.writeEntry("Feed To Listbox Counter", listBoxNum);
0621 
0622     KConfigGroup ga(krConfig, "Advanced");
0623     if (ga.readEntry("Confirm Feed to Listbox", _ConfirmFeedToListbox)) {
0624         bool ok;
0625         fileSystemName = QInputDialog::getText(this, i18n("Query name"), i18n("Here you can name the file collection"), QLineEdit::Normal, fileSystemName, &ok);
0626         if (!ok)
0627             return;
0628     }
0629 
0630     QList<QUrl> urlList;
0631     foreach (FileItem *fileitem, result->fileItems())
0632         urlList.push_back(fileitem->getUrl());
0633 
0634     mainSearchBtn->setEnabled(false);
0635     mainCloseBtn->setEnabled(false);
0636     mainFeedToListBoxBtn->setEnabled(false);
0637 
0638     isBusy = true;
0639 
0640     const QUrl url = QUrl(QString("virt:/") + fileSystemName);
0641     virtFilesystem.scanDir(url);
0642     virtFilesystem.addFiles(urlList);
0643     virtFilesystem.setMetaInformation(queryName);
0644     // ACTIVE_FUNC->openUrl(url);
0645     ACTIVE_MNG->slotNewTab(url);
0646 
0647     isBusy = false;
0648 
0649     closeDialog();
0650 }
0651 
0652 void KrSearchDialog::copyToClipBoard()
0653 {
0654     const KrViewItemList selectedItems = resultView->getSelectedKrViewItems();
0655     QList<QUrl> urls;
0656     for (KrViewItem *item : selectedItems) {
0657         urls.append(item->getFileItem()->getUrl());
0658     }
0659 
0660     if (urls.count() == 0)
0661         return;
0662 
0663     auto *mimeData = new QMimeData;
0664     mimeData->setImageData(FileListIcon("file").pixmap());
0665     mimeData->setUrls(urls);
0666 
0667     QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
0668 }
0669 
0670 void KrSearchDialog::tryPlaceSearchQueryToClipboard()
0671 {
0672     if (searchTextToClipboard->isChecked() && !generalFilter->containsText->currentText().isEmpty()
0673         && QApplication::clipboard()->text() != generalFilter->containsText->currentText()) {
0674         QApplication::clipboard()->setText(generalFilter->containsText->currentText());
0675     }
0676 }