Commit ceda166d authored by Kåre Särs's avatar Kåre Särs

Remove duplicate search in open/disk-files

parent a9ee0f16
......@@ -12,10 +12,9 @@ endif(NOT KDE4_FOUND)
set(katesearchplugin_PART_SRCS
plugin_search.cpp
search_while_typing.cpp
search_open_files.cpp
search_folder.cpp
search_project.cpp
SearchDiskFiles.cpp
FolderFilesList.cpp
replace_matches.cpp
htmldelegate.cpp
)
......
/* Kate search plugin
*
* Copyright (C) 2011 by Kåre Särs <kare.sars@iki.fi>
* Copyright (C) 2013 by Kåre Särs <kare.sars@iki.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -18,33 +18,48 @@
* MA 02110-1301, USA.
*/
#include "search_folder.h"
#include "search_folder.moc"
#include "FolderFilesList.h"
#include "FolderFilesList.moc"
#include <kmimetype.h>
#include <kdebug.h>
#include <QDir>
#include <QFileInfo>
#include <QFileInfoList>
SearchFolder::SearchFolder(QObject *parent) : QThread(parent)
FolderFilesList::FolderFilesList(QObject *parent) : QThread(parent) {}
FolderFilesList::~FolderFilesList()
{
m_cancelSearch = true;
wait();
}
void FolderFilesList::run()
{
m_files.clear();
QFileInfo folderInfo(m_folder);
checkNextItem(folderInfo);
if (m_cancelSearch) m_files.clear();
}
void SearchFolder::startSearch(const QString &folder,
bool recursive,
bool hidden,
bool symlinks,
bool binary,
const QString &types,
const QString &excludes,
const QRegExp &regexp)
void FolderFilesList::generateList(const QString &folder,
bool recursive,
bool hidden,
bool symlinks,
bool binary,
const QString &types,
const QString &excludes)
{
m_cancelSearch = false;
m_folder = folder;
m_recursive = recursive;
m_hidden = hidden;
m_symlinks = symlinks;
m_binary = binary;
m_folder = folder;
m_regExp = regexp;
m_types = types.split(',');
m_types = types.split(',');
QStringList tmpExcludes = excludes.split(',');
m_excludeList.clear();
......@@ -57,29 +72,24 @@ void SearchFolder::startSearch(const QString &folder,
start();
}
void SearchFolder::run()
{
handleNextItem(QFileInfo(m_folder));
emit searchDone();
}
QStringList FolderFilesList::fileList() { return m_files; }
void SearchFolder::cancelSearch()
void FolderFilesList::cancelSearch()
{
m_cancelSearch = true;
}
void SearchFolder::handleNextItem(const QFileInfo &item)
void FolderFilesList::checkNextItem(const QFileInfo &item)
{
if (m_cancelSearch) {
return;
}
if (item.isFile()) {
return searchFile(item);
m_files << item.absoluteFilePath();
}
else {
QDir currentDir(item.absoluteFilePath());
if (!currentDir.isReadable()) {
kDebug() << currentDir.absolutePath() << "Not readable";
return;
......@@ -94,7 +104,6 @@ void SearchFolder::handleNextItem(const QFileInfo &item)
bool skip;
for (int i = 0; i<currentItems.size(); ++i) {
if (m_cancelSearch) return;
skip = false;
for (int j=0; j<m_excludeList.size(); j++) {
if (m_excludeList[j].exactMatch(currentItems[i].fileName())) {
......@@ -103,40 +112,9 @@ void SearchFolder::handleNextItem(const QFileInfo &item)
}
}
if (!skip) {
handleNextItem(currentItems[i]);
checkNextItem(currentItems[i]);
}
}
}
}
void SearchFolder::searchFile(const QFileInfo &item)
{
if (m_cancelSearch) return;
if (!m_binary && KMimeType::isBinaryData(item.absoluteFilePath())) {
return;
}
QFile file (item.absoluteFilePath());
if (!file.open(QFile::ReadOnly)) {
return;
}
QTextStream stream (&file);
QString line;
int i = 0;
int column;
while (!(line=stream.readLine()).isNull()) {
if (m_cancelSearch) return;
column = m_regExp.indexIn(line);
while (column != -1) {
if (m_regExp.cap().isEmpty()) break;
// limit line length
if (line.length() > 512) line = line.left(512);
emit matchFound(item.absoluteFilePath(), i, column, line, m_regExp.matchedLength());
column = m_regExp.indexIn(line, column + m_regExp.cap().size());
}
i++;
}
}
/* Kate search plugin
*
* Copyright (C) 2011 by Kåre Särs <kare.sars@iki.fi>
* Copyright (C) 2013 by Kåre Särs <kare.sars@iki.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -18,54 +18,52 @@
* MA 02110-1301, USA.
*/
#ifndef _SEARCH_FOLDER_H_
#define _SEARCH_FOLDER_H_
#ifndef FolderFilesList_h
#define FolderFilesList_h
#include <QThread>
#include <QRegExp>
#include <QFileInfo>
#include <ktexteditor/document.h>
#include <QVector>
#include <QStringList>
class SearchFolder: public QThread
class FolderFilesList: public QThread
{
Q_OBJECT
public:
SearchFolder(QObject *parent = 0);
FolderFilesList(QObject *parent = 0);
~FolderFilesList();
void startSearch(const QString &folder,
bool recursive,
bool hidden,
bool symlinks,
bool binary,
const QString &types,
const QString &excludes,
const QRegExp &regexp);
void run();
void generateList(const QString &folder,
bool recursive,
bool hidden,
bool symlinks,
bool binary,
const QString &types,
const QString &excludes);
QStringList fileList();
public Q_SLOTS:
void cancelSearch();
Q_SIGNALS:
void matchFound(const QString &url, int line, int column,
const QString &lineContent, int matchLen);
void searchDone();
private:
void handleNextItem(const QFileInfo &item);
void searchFile(const QFileInfo &item);
void checkNextItem(const QFileInfo &item);
private:
QRegExp m_regExp;
QString m_folder;
QStringList m_files;
bool m_cancelSearch;
bool m_recursive;
bool m_hidden;
bool m_symlinks;
bool m_binary;
QStringList m_types;
QString m_folder;
QVector<QRegExp> m_excludeList;
};
......
/* Kate search plugin
*
* Copyright (C) 2011 by Kåre Särs <kare.sars@iki.fi>
*
* Copyright (C) 2011-2013 by Kåre Särs <kare.sars@iki.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -18,19 +18,29 @@
* MA 02110-1301, USA.
*/
#include "search_project.h"
#include "search_project.moc"
#include "SearchDiskFiles.h"
#include "SearchDiskFiles.moc"
#include <kmimetype.h>
#include <kdebug.h>
#include <QDir>
#include <QTextStream>
SearchDiskFiles::SearchDiskFiles(QObject *parent) : QThread(parent) {}
SearchProject::SearchProject(QObject *parent) : QThread(parent)
SearchDiskFiles::~SearchDiskFiles()
{
m_cancelSearch = true;
wait();
}
void SearchProject::startSearch(const QStringList &files,
const QRegExp &regexp)
void SearchDiskFiles::startSearch(const QStringList &files,
const QRegExp &regexp)
{
if (files.size() == 0) {
emit searchDone();
return;
}
m_cancelSearch = false;
m_files = files;
m_regExp = regexp;
......@@ -38,11 +48,12 @@ void SearchProject::startSearch(const QStringList &files,
start();
}
void SearchProject::run()
void SearchDiskFiles::run()
{
foreach (QString fileName, m_files) {
if (m_cancelSearch)
if (m_cancelSearch) {
break;
}
QFile file (fileName);
......@@ -69,7 +80,7 @@ void SearchProject::run()
emit searchDone();
}
void SearchProject::cancelSearch()
void SearchDiskFiles::cancelSearch()
{
m_cancelSearch = true;
}
/* Kate search plugin
*
* Copyright (C) 2011 by Kåre Särs <kare.sars@iki.fi>
*
* Copyright (C) 2011-2013 by Kåre Särs <kare.sars@iki.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -18,22 +18,25 @@
* MA 02110-1301, USA.
*/
#ifndef _SEARCH_PROJECT_H_
#define _SEARCH_PROJECT_H_
#ifndef SearchDiskFiles_h
#define SearchDiskFiles_h
#include <QThread>
#include <QRegExp>
#include <QFileInfo>
#include <ktexteditor/document.h>
#include <QVector>
#include <QMutex>
#include <QStringList>
class SearchProject: public QThread
class SearchDiskFiles: public QThread
{
Q_OBJECT
public:
SearchProject(QObject *parent = 0);
SearchDiskFiles(QObject *parent = 0);
~SearchDiskFiles();
void startSearch(const QStringList &files,
void startSearch(const QStringList &iles,
const QRegExp &regexp);
void run();
......@@ -44,11 +47,12 @@ Q_SIGNALS:
void matchFound(const QString &url, int line, int column,
const QString &lineContent, int matchLen);
void searchDone();
private:
QRegExp m_regExp;
bool m_cancelSearch;
QStringList m_files;
bool m_cancelSearch;
};
#endif
......@@ -235,8 +235,8 @@ m_projectPluginView(0)
connect(m_ui.matchCase, SIGNAL(stateChanged(int)), this, SLOT(searchPatternChanged()));
connect(m_ui.useRegExp, SIGNAL(stateChanged(int)), this, SLOT(searchPatternChanged()));
connect(m_ui.stopButton, SIGNAL(clicked()), &m_searchOpenFiles, SLOT(cancelSearch()));
connect(m_ui.stopButton, SIGNAL(clicked()), &m_searchFolder, SLOT(cancelSearch()));
connect(m_ui.stopButton, SIGNAL(clicked()), &m_searchProject, SLOT(cancelSearch()));
connect(m_ui.stopButton, SIGNAL(clicked()), &m_searchDiskFiles, SLOT(cancelSearch()));
connect(m_ui.stopButton, SIGNAL(clicked()), &m_folderFilesList, SLOT(cancelSearch()));
m_ui.displayOptions->setChecked(true);
......@@ -244,17 +244,11 @@ m_projectPluginView(0)
this, SLOT(matchFound(QString,int,int,QString,int)));
connect(&m_searchOpenFiles, SIGNAL(searchDone()), this, SLOT(searchDone()));
connect(&m_searchFolder, SIGNAL(matchFound(QString,int,int,QString,int)),
this, SLOT(matchFound(QString,int,int,QString,int)));
connect(&m_searchFolder, SIGNAL(searchDone()), this, SLOT(searchDone()));
connect(&m_searchProject, SIGNAL(matchFound(QString,int,int,QString,int)),
this, SLOT(matchFound(QString,int,int,QString,int)));
connect(&m_searchProject, SIGNAL(searchDone()), this, SLOT(searchDone()));
connect(&m_folderFilesList, SIGNAL(finished()), this, SLOT(folderFileListChanged()));
connect(&m_searchWhileTyping, SIGNAL(matchFound(QString,int,int,QString,int)),
connect(&m_searchDiskFiles, SIGNAL(matchFound(QString,int,int,QString,int)),
this, SLOT(matchFound(QString,int,int,QString,int)));
connect(&m_searchWhileTyping, SIGNAL(searchDone()), this, SLOT(searchWhileTypingDone()));
connect(&m_searchDiskFiles, SIGNAL(searchDone()), this, SLOT(searchDone()));
connect(m_kateApp->documentManager(), SIGNAL(documentWillBeDeleted(KTextEditor::Document*)),
&m_searchOpenFiles, SLOT(cancelSearch()));
......@@ -431,15 +425,16 @@ void KatePluginSearchView::startSearch()
}
else if (m_ui.searchPlaceCombo->currentIndex() == 1) {
m_resultBaseDir = m_ui.folderRequester->text();
m_searchFolder.startSearch(m_ui.folderRequester->text(),
m_ui.recursiveCheckBox->isChecked(),
m_ui.hiddenCheckBox->isChecked(),
m_ui.symLinkCheckBox->isChecked(),
m_ui.binaryCheckBox->isChecked(),
m_ui.filterCombo->currentText(),
m_ui.excludeCombo->currentText(),
reg);
} else {
m_folderFilesList.generateList(m_ui.folderRequester->text(),
m_ui.recursiveCheckBox->isChecked(),
m_ui.hiddenCheckBox->isChecked(),
m_ui.symLinkCheckBox->isChecked(),
m_ui.binaryCheckBox->isChecked(),
m_ui.filterCombo->currentText(),
m_ui.excludeCombo->currentText());
// the file list will be ready when the thread returns (connected to folderFileListChanged)
}
else {
/**
* init search with file list from current project, if any
*/
......@@ -452,7 +447,7 @@ void KatePluginSearchView::startSearch()
}
files = m_projectPluginView->property ("projectFiles").toStringList();
}
m_searchProject.startSearch(files, reg);
m_searchDiskFiles.startSearch(files, reg);
}
m_toolView->setCursor(Qt::WaitCursor);
......@@ -483,7 +478,6 @@ void KatePluginSearchView::searchPatternChanged()
{
m_ui.searchButton->setDisabled(m_ui.searchCombo->currentText().isEmpty());
if (m_ui.searchCombo->currentText().length() < 3) return;
if (!mainWindow()->activeView()) return;
KTextEditor::Document *doc = mainWindow()->activeView()->document();
......@@ -510,7 +504,22 @@ void KatePluginSearchView::searchPatternChanged()
disconnect(m_curResults->tree, SIGNAL(itemChanged(QTreeWidgetItem*,int)), m_curResults, SLOT(checkCheckedState()));
m_resultBaseDir.clear();
m_searchWhileTyping.startSearch(doc, reg);
if (m_ui.searchCombo->currentText().length() >= 3) {
m_searchOpenFiles.searchOpenFile(doc, reg, 50);
}
searchWhileTypingDone();
}
void KatePluginSearchView::folderFileListChanged()
{
if (!m_curResults) {
kWarning() << "This is a bug";
searchDone();
return;
}
m_searchDiskFiles.startSearch(m_folderFilesList.fileList(), m_curResults->regExp);
}
QTreeWidgetItem * KatePluginSearchView::rootFileItem(const QString &url)
......@@ -880,8 +889,8 @@ void KatePluginSearchView::readSessionConfig(KConfigBase* config, const QString&
m_ui.symLinkCheckBox->setChecked(cg.readEntry("FollowSymLink", false));
m_ui.binaryCheckBox->setChecked(cg.readEntry("BinaryFiles", false));
m_ui.folderRequester->comboBox()->clear();
m_ui.folderRequester->comboBox()->addItems(cg.readEntry("SearchFolders", QStringList()));
m_ui.folderRequester->setText(cg.readEntry("SearchFolder", QString()));
m_ui.folderRequester->comboBox()->addItems(cg.readEntry("SearchDiskFiless", QStringList()));
m_ui.folderRequester->setText(cg.readEntry("SearchDiskFiles", QString()));
m_ui.filterCombo->clear();
m_ui.filterCombo->addItems(cg.readEntry("Filters", QStringList()));
m_ui.filterCombo->setCurrentIndex(cg.readEntry("CurrentFilter", 0));
......@@ -907,8 +916,8 @@ void KatePluginSearchView::writeSessionConfig(KConfigBase* config, const QString
for (int i=0; i<qMin(m_ui.folderRequester->comboBox()->count(), 10); i++) {
folders << m_ui.folderRequester->comboBox()->itemText(i);
}
cg.writeEntry("SearchFolders", folders);
cg.writeEntry("SearchFolder", m_ui.folderRequester->text());
cg.writeEntry("SearchDiskFiless", folders);
cg.writeEntry("SearchDiskFiles", m_ui.folderRequester->text());
QStringList filterItems;
for (int i=0; i<qMin(m_ui.filterCombo->count(), 10); i++) {
filterItems << m_ui.filterCombo->itemText(i);
......@@ -956,8 +965,7 @@ void KatePluginSearchView::closeTab(QWidget *widget)
Results *tmp = qobject_cast<Results *>(widget);
if (m_curResults == tmp) {
m_searchOpenFiles.cancelSearch();
m_searchFolder.cancelSearch();
m_searchProject.cancelSearch();
m_searchDiskFiles.cancelSearch();
}
if (m_ui.resultTabWidget->count() > 1) {
delete tmp; // remove the tab
......
......@@ -31,10 +31,9 @@
#include "ui_search.h"
#include "ui_results.h"
#include "search_while_typing.h"
#include "search_open_files.h"
#include "search_folder.h"
#include "search_project.h"
#include "SearchDiskFiles.h"
#include "FolderFilesList.h"
#include "replace_matches.h"
class KateSearchCommand;
......@@ -103,6 +102,8 @@ private Q_SLOTS:
void searchPlaceChanged();
void searchPatternChanged();
void folderFileListChanged();
void matchFound(const QString &fileName, int line, int column,
const QString &lineContent, int matchLen);
......@@ -141,9 +142,8 @@ private:
QWidget *m_toolView;
Kate::Application *m_kateApp;
SearchOpenFiles m_searchOpenFiles;
SearchFolder m_searchFolder;
SearchProject m_searchProject;
SearchWhileTyping m_searchWhileTyping;
FolderFilesList m_folderFilesList;
SearchDiskFiles m_searchDiskFiles;
ReplaceMatches m_replacer;
KAction *m_matchCase;
KAction *m_useRegExp;
......
/* Kate search plugin
*
* Copyright (C) 2011 by Kåre Särs <kare.sars@iki.fi>
* Copyright (C) 2011-2013 by Kåre Särs <kare.sars@iki.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -21,11 +21,15 @@
#include "search_open_files.h"
#include "search_open_files.moc"
SearchOpenFiles::SearchOpenFiles(QObject *parent) : QObject(parent), m_nextIndex(-1)
#include <QTime>
SearchOpenFiles::SearchOpenFiles(QObject *parent) : QObject(parent), m_nextIndex(-1), m_cancelSearch(true)
{
connect(this, SIGNAL(searchNextFile()), this, SLOT(doSearchNextFile()), Qt::QueuedConnection);
}
bool SearchOpenFiles::searching() { return !m_cancelSearch; }
void SearchOpenFiles::startSearch(const QList<KTextEditor::Document*> &list, const QRegExp &regexp)
{
if (m_nextIndex != -1) return;
......@@ -46,39 +50,45 @@ void SearchOpenFiles::doSearchNextFile()
{
if (m_cancelSearch) {
m_nextIndex = -1;
m_cancelSearch = true;
emit searchDone();
return;
}
int column;
// NOTE The document managers signal documentWillBeDeleted() must be connected to
// cancelSearch(). A closed file could lead to a crash if it is not handled.
for (int line =0; line < m_docList[m_nextIndex]->lines(); line++) {
column = m_regExp.indexIn(m_docList[m_nextIndex]->line(line));
while (column != -1) {
if (m_regExp.cap().isEmpty()) break;
if (m_docList[m_nextIndex]->url().isLocalFile() ) {
emit matchFound(m_docList[m_nextIndex]->url().path(), line, column,
m_docList[m_nextIndex]->line(line), m_regExp.matchedLength());
}
else {
emit matchFound(m_docList[m_nextIndex]->url().prettyUrl(), line, column,
m_docList[m_nextIndex]->line(line), m_regExp.matchedLength());
}
column = m_regExp.indexIn(m_docList[m_nextIndex]->line(line), column + m_regExp.cap().size());
}
}
searchOpenFile(m_docList[m_nextIndex], m_regExp, 500);
m_nextIndex++;
if (m_nextIndex == m_docList.size()) {
m_nextIndex = -1;
m_cancelSearch = true;
emit searchDone();
}
else {
emit searchNextFile();
}
}
void SearchOpenFiles::searchOpenFile(KTextEditor::Document *doc, const QRegExp &regExp, int maxSearchTime)
{
int column;
QTime maxTime;
maxTime.start();
for (int line =0; line < doc->lines(); line++) {
if (maxTime.elapsed() > maxSearchTime) {
kDebug() << "Search time exceeded -> stop" << maxTime.elapsed() << line;
break;
}
column = regExp.indexIn(doc->line(line));
while (column != -1) {
if (regExp.cap().isEmpty()) break;
emit matchFound(doc->url().pathOrUrl(), line, column,
doc->line(line), regExp.matchedLength());
column = regExp.indexIn(doc->line(line), column + regExp.cap().size());
}
}
}
......@@ -33,10 +33,13 @@ public:
SearchOpenFiles(QObject *parent = 0);
void startSearch(const QList<KTextEditor::Document*> &list,const QRegExp &regexp);
bool searching();
public Q_SLOTS:
void cancelSearch();
void searchOpenFile(KTextEditor::Document *doc, const QRegExp &regExp, int maxSearchTime);