Commit bb8c2a6b authored by Robert Knight's avatar Robert Knight

Make history search work again. Add a delay after changing the search box...

Make history search work again.  Add a delay after changing the search box text before performing the search, makes the operation feel slicker.  Move searching code from Emulation to SessionController class.

svn path=/branches/work/konsole-split-view/; revision=657444
parent 2bd31b84
......@@ -108,8 +108,7 @@ Emulation::Emulation() :
listenToKeyPress(false),
m_codec(0),
decoder(0),
keytrans(0),
m_findPos(-1)
keytrans(0)
{
//initialize screens with a default size
......@@ -428,109 +427,6 @@ int Emulation::lines()
return currentScreen->getLines() + currentScreen->getHistLines();
}
void Emulation::findTextBegin()
{
m_findPos = -1;
}
bool Emulation::findTextNext( const QString &str, bool forward, bool isCaseSensitive, bool isRegExp )
{
int pos = -1;
QString string;
//text stream to read history into string for pattern or regular expression searching
QTextStream searchStream(&string);
PlainTextDecoder decoder;
//setup first and last lines depending on search direction
int line = 0;
if (forward)
line = (m_findPos == -1 ? 0 : m_findPos+1);
else
line = (m_findPos == -1? (currentScreen->getHistLines()+currentScreen->getLines() ):m_findPos-1);
int lastLine = 0;
if (forward)
lastLine = currentScreen->getHistLines() + currentScreen->getLines();
else
lastLine = 0;
//read through and search history in blocks of 10K lines.
//this balances the need to retrieve lots of data from the history each time (for efficient searching)
//without using silly amounts of memory if the history is very large.
int delta = forward ? 10000 : -10000;
//setup case sensitivity and regular expression if enabled
Qt::CaseSensitivity caseSensitivity = isCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
QRegExp regExp;
if (isRegExp)
regExp = QRegExp(str,caseSensitivity);
//loop through history in blocks of <delta> lines.
while ( line != lastLine )
{
QApplication::processEvents();
int endLine = 0;
if (forward)
endLine = qMin(line+delta,lastLine);
else
endLine = qMax(line+delta,lastLine);
currentScreen->writeToStream(&searchStream,&decoder, qMin(endLine,line) , qMax(endLine,line) );
pos = -1;
if (forward)
{
if (isRegExp)
pos = string.indexOf(regExp);
else
pos = string.indexOf(str,0,caseSensitivity);
}
else
{
if (isRegExp)
pos = string.lastIndexOf(regExp);
else
pos = string.lastIndexOf(str, -1, caseSensitivity);
}
//if a match is found, position the cursor on that line and update the screen
if ( pos != -1 )
{
//work out how many lines into the current block of text the search result was found
//- looks a little painful, but it only has to be done once per search.
m_findPos = line + string.left(pos + 1).count(QChar('\n'));
//TODO - Reimplement moving active view to focus on current match now that
// that multiple views can show different parts of the screen at the same
// time.
//
// if ( m_findPos > currentScreen->getHistLines() )
// currentScreen->setHistCursor(currentScreen->getHistLines());
// else
// currentScreen->setHistCursor(m_findPos);
//cause target line to be selected
//currentScreen->getHistoryLine(m_findPos);
//update display to show area of history containing selection
showBulk();
return true;
}
//clear the current block of text and move to the next one
string.clear();
line = endLine;
}
return false;
}
// Refreshing -------------------------------------------------------------- --
#define BULK_TIMEOUT1 10
......
......@@ -109,25 +109,6 @@ public:
/** Sets the codec used to decode incoming characters. */
void setCodec(const QTextCodec *);
/**
* Initiates a text-search of the output history. This sets the current search position
* to the start of the output
*/
virtual void findTextBegin();
/**
* Searches the output history for the next occurrence of a particular string or pattern and
* scrolls the the screen to the first occurrence found.
*
* @param str The string or pattern to search for within the output history
* @param forward @c true to search forward or @c false to search backwards in the output history.
* @param caseSensitive @c true for a case-sensitive search or @c false for a case-insensitive search.
* @param regExp @c true to treat @p str as a regular expression or @c false to treat
* str as plain text.
*
* @returns true if a match is found or false otherwise.
*/
virtual bool findTextNext( const QString &str, bool forward, bool caseSensitive, bool regExp );
public Q_SLOTS: // signals incoming from TerminalDisplay
/** Change the size of the emulation's image */
......@@ -281,9 +262,6 @@ private:
QTimer bulk_timer1;
QTimer bulk_timer2;
int m_findPos;
};
};
......
......@@ -24,6 +24,7 @@
#include <QLineEdit>
#include <QProgressBar>
#include <QShowEvent>
#include <QTimer>
#include <QToolButton>
// KDE
......@@ -67,7 +68,11 @@ IncrementalSearchBar::IncrementalSearchBar(Features features , QWidget* parent)
_searchEdit->setMinimumWidth(maxWidth*6);
_searchEdit->setMaximumWidth(maxWidth*10);
connect( _searchEdit , SIGNAL(textChanged(const QString&)) , this , SIGNAL(searchChanged(const QString&)));
_searchTimer = new QTimer(this);
_searchTimer->setInterval(250);
_searchTimer->setSingleShot(true);
connect( _searchTimer , SIGNAL(timeout()) , this , SLOT(notifySearchChanged()) );
connect( _searchEdit , SIGNAL(textChanged(const QString&)) , _searchTimer , SLOT(start()));
QToolButton* findNext = new QToolButton(this);
findNext->setObjectName("find-next-button");
......@@ -141,7 +146,10 @@ IncrementalSearchBar::IncrementalSearchBar(Features features , QWidget* parent)
setLayout(layout);
}
void IncrementalSearchBar::notifySearchChanged()
{
emit searchChanged( searchText() );
}
QString IncrementalSearchBar::searchText()
{
return _searchEdit->text();
......
......@@ -27,6 +27,7 @@ class QCheckBox;
class QLabel;
class QLineEdit;
class QProgressBar;
class QTimer;
namespace Konsole
{
......@@ -173,6 +174,9 @@ signals:
protected:
virtual bool eventFilter( QObject* watched , QEvent* event );
private slots:
void notifySearchChanged();
private:
bool _foundMatch;
QCheckBox* _matchCaseBox;
......@@ -183,6 +187,7 @@ private:
QLabel* _continueLabel;
QProgressBar* _progress;
QTimer* _searchTimer;
};
};
......
......@@ -103,7 +103,7 @@ int ScreenWindow::windowColumns() const
int ScreenWindow::lineCount() const
{
return _screen->getHistLines();
return _screen->getHistLines() + _screen->getLines();
}
int ScreenWindow::columnCount() const
......@@ -130,6 +130,9 @@ void ScreenWindow::scrollBy( RelativeScrollMode mode , int amount )
void ScreenWindow::scrollTo( int line )
{
if ( (lineCount() - windowLines()) < line )
line = qMax(0,lineCount() - windowLines());
const int delta = line - _currentLine;
_currentLine = line;
......
......@@ -23,6 +23,9 @@
// Qt
#include <QObject>
// Konsole
#include "TECommon.h"
namespace Konsole
{
......
......@@ -621,7 +621,11 @@ const QString& Session::title() const
void Session::setIconName(const QString& iconName)
{
_iconName = iconName;
if ( iconName != _iconName )
{
_iconName = iconName;
emit updateTitle();
}
}
void Session::setIconText(const QString& iconText)
......
......@@ -15,6 +15,7 @@
#include "Filter.h"
#include "HistorySizeDialog.h"
#include "IncrementalSearchBar.h"
#include "ScreenWindow.h"
#include "Session.h"
#include "TerminalDisplay.h"
#include "SessionController.h"
......@@ -477,10 +478,10 @@ void SessionController::searchHistory(bool showSearchBar)
searchTextChanged(currentSearchText);
}
//SessionTask* task = new SearchHistoryTask();
//task->setAutoDelete(true);
//task->addSession( _session );
//task->execute();
SessionTask* task = new SearchHistoryTask(_view->screenWindow());
task->setAutoDelete(true);
task->addSession( _session );
task->execute();
}
else
{
......@@ -494,6 +495,10 @@ void SessionController::searchHistory(bool showSearchBar)
}
}
void SessionController::searchTextChanged(const QString& text)
{
beginSearch(text , SearchHistoryTask::Forwards);
}
void SessionController::beginSearch(const QString& text , int direction)
{
Q_ASSERT( _searchBar );
......@@ -504,12 +509,12 @@ void SessionController::searchTextChanged(const QString& text)
if ( !regExp.isEmpty() )
{
SearchHistoryTask* task = new SearchHistoryTask(this);
SearchHistoryTask* task = new SearchHistoryTask(_view->screenWindow(),this);
task->setRegExp(regExp);
task->setMatchCase( _searchBar->matchCase() );
task->setMatchRegExp( _searchBar->matchRegExp() );
task->setSearchDirection( SearchHistoryTask::Forwards );
task->setSearchDirection( (SearchHistoryTask::SearchDirection)direction );
task->setAutoDelete(true);
task->addSession( _session );
task->execute();
......@@ -533,11 +538,11 @@ void SessionController::searchTextChanged(const QString& text)
}
void SessionController::findNextInHistory()
{
qDebug() << "find next";
beginSearch(_searchBar->searchText(),SearchHistoryTask::Forwards);
}
void SessionController::findPreviousInHistory()
{
qDebug() << "find previous";
beginSearch(_searchBar->searchText(),SearchHistoryTask::Backwards);
}
void SessionController::historyOptions()
{
......@@ -862,19 +867,122 @@ void SearchHistoryTask::execute()
Q_ASSERT( sessions().first() );
Emulation* emulation = sessions().first()->emulation();
if ( !_regExp.isEmpty() )
{
emulation->findTextBegin();
emulation->findTextNext(_regExp.pattern() , true , false , false );
const int startLine = _screenWindow->currentLine();
int pos = -1;
int findPos = -1;
const bool forwards = ( _direction == Forwards );
const int lastLine = _screenWindow->lineCount() - 1;
QString string;
//text stream to read history into string for pattern or regular expression searching
QTextStream searchStream(&string);
PlainTextDecoder decoder;
//setup first and last lines depending on search direction
int line = startLine;
//read through and search history in blocks of 10K lines.
//this balances the need to retrieve lots of data from the history each time (for efficient searching)
//without using silly amounts of memory if the history is very large.
const int maxDelta = qMin(_screenWindow->lineCount(),10000);
int delta = forwards ? maxDelta : -maxDelta;
//setup case sensitivity and regular expression if enabled
_regExp.setCaseSensitivity( _matchCase ? Qt::CaseSensitive : Qt::CaseInsensitive );
if (_matchRegExp)
_regExp.setPatternSyntax(QRegExp::RegExp);
else
_regExp.setPatternSyntax(QRegExp::FixedString);
int endLine = -1;
bool hasWrapped = false; // set to true when we reach the top/bottom
// of the output and continue from the other
// end
//loop through history in blocks of <delta> lines.
while ( endLine != startLine )
{
QApplication::processEvents();
// calculate lines to search in this iteration
if ( hasWrapped )
{
if ( endLine == lastLine )
line = 0;
else if ( endLine == 0 )
line = lastLine;
endLine += delta;
if ( forwards )
endLine = qMin( startLine , endLine );
else
endLine = qMax( startLine , endLine );
}
else
{
endLine += delta;
if ( endLine > lastLine )
{
hasWrapped = true;
endLine = lastLine;
} else if ( endLine < 0 )
{
hasWrapped = true;
endLine = 0;
}
}
//qDebug() << "Searching lines " << qMin(endLine,line) << " to " << qMax(endLine,line);
emulation->writeToStream(&searchStream,&decoder, qMin(endLine,line) , qMax(endLine,line) );
//qDebug() << "Stream contents length: " << string;
pos = -1;
if (forwards)
pos = string.indexOf(_regExp);
else
pos = string.lastIndexOf(_regExp);
//if a match is found, position the cursor on that line and update the screen
if ( pos != -1 )
{
//work out how many lines into the current block of text the search result was found
//- looks a little painful, but it only has to be done once per search.
findPos = qMin(line,endLine) + string.left(pos + 1).count(QChar('\n'));
qDebug() << "Found result at line " << findPos;
//update display to show area of history containing selection
_screenWindow->scrollTo(findPos);
//qDebug() << "Current line " << _screenWindow->currentLine();
_screenWindow->setTrackOutput(false);
_screenWindow->notifyOutputChanged();
//qDebug() << "Post update current line " << _screenWindow->currentLine();
return;
}
//clear the current block of text and move to the next one
string.clear();
line = endLine;
}
}
}
SearchHistoryTask::SearchHistoryTask(QObject* parent)
SearchHistoryTask::SearchHistoryTask(ScreenWindow* window , QObject* parent)
: SessionTask(parent)
, _matchRegExp(false)
, _matchCase(false)
, _direction(Forwards)
, _screenWindow(window)
{
}
......
......@@ -30,6 +30,7 @@ namespace Konsole
{
class Session;
class ScreenWindow;
class TerminalDisplay;
class IncrementalSearchBar;
class UrlFilter;
......@@ -142,6 +143,11 @@ private slots:
void debugProcess();
private:
// begins the search
// text - pattern to search for
// direction - value from SearchHistoryTask::SearchDirection enum to specify
// the search direction
void beginSearch(const QString& text , int direction);
void setupActions();
void removeSearchFilter(); // remove and delete the current search filter if set
......@@ -266,13 +272,6 @@ class SearchHistoryThread;
* TODO - Implementation requirements:
* Must provide progress feedback to the user when searching very large output logs.
*
* Multi-threading?
* - The search is performed asynchronously in another thread when execute() is called.
* *** Not done yet - currently we do everything in the main thread and rely on calling QApplication::processEvents() every so often
* inside Emulation::findTextNext() to prevent the interface from becoming unresponsive.
* The actual searching is currently done in the Emulation class and was not originally designed with multi-threading in mind.
*
*
* - Remember where the search got to when it reaches the end of the output in each session
* calling execute() subsequently should continue the search.
* This allows the class to be used for both the "Search history for text"
......@@ -291,7 +290,7 @@ public:
Backwards
};
SearchHistoryTask(QObject* parent = 0);
SearchHistoryTask(ScreenWindow* window , QObject* parent = 0);
/** Sets the regular expression which is searched for when execute() is called */
void setRegExp(const QRegExp& regExp);
......@@ -326,6 +325,8 @@ private:
bool _matchCase;
SearchDirection _direction;
ScreenWindow* _screenWindow;
static QPointer<SearchHistoryThread> _thread;
};
......
......@@ -1678,7 +1678,7 @@ void TerminalDisplay::setScroll(int cursor, int slines)
}
disconnect(_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scrollChanged(int)));
_scrollBar->setRange(0,slines);
_scrollBar->setRange(0,slines - _lines);
_scrollBar->setSingleStep(1);
_scrollBar->setPageStep(_lines);
_scrollBar->setValue(cursor);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment