/* * Copyright (C) 2010, 2013 Nicolas Bonnefon and other contributors * * This file is part of glogg. * * glogg is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * glogg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with glogg. If not, see . */ // This file implements QuickFind. // This class implements the Quick Find mechanism using references // to the logData, the QFP and the selection passed. // Search is started just after the selection and the selection is updated // if a match is found. #include #include "log.h" #include "quickfindpattern.h" #include "selection.h" #include "data/abstractlogdata.h" #include "quickfind.h" void SearchingNotifier::reset() { dotToDisplay_ = 0; startTime_ = QTime::currentTime(); } void SearchingNotifier::sendNotification( qint64 current_line, qint64 nb_lines ) { LOG( logDEBUG ) << "Emitting Searching...."; qint64 progress; if ( current_line < 0 ) progress = ( nb_lines + current_line ) * 100 / nb_lines; else progress = current_line * 100 / nb_lines; emit notify( QFNotificationProgress( progress ) ); QApplication::processEvents( QEventLoop::ExcludeUserInputEvents ); startTime_ = QTime::currentTime().addMSecs( -800 ); } void QuickFind::LastMatchPosition::set( int line, int column ) { if ( ( line_ == -1 ) || ( ( line <= line_ ) && ( column < column_ ) ) ) { line_ = line; column_ = column; } } void QuickFind::LastMatchPosition::set( const FilePosition &position ) { set( position.line(), position.column() ); } bool QuickFind::LastMatchPosition::isLater( int line, int column ) const { if ( line_ == -1 ) return false; else if ( ( line == line_ ) && ( column >= column_ ) ) return true; else if ( line > line_ ) return true; else return false; } bool QuickFind::LastMatchPosition::isLater( const FilePosition &position ) const { return isLater( position.line(), position.column() ); } bool QuickFind::LastMatchPosition::isSooner( int line, int column ) const { if ( line_ == -1 ) return false; else if ( ( line == line_ ) && ( column <= column_ ) ) return true; else if ( line < line_ ) return true; else return false; } bool QuickFind::LastMatchPosition::isSooner( const FilePosition &position ) const { return isSooner( position.line(), position.column() ); } QuickFind::QuickFind( const AbstractLogData* const logData, Selection* selection, const QuickFindPattern* const quickFindPattern ) : logData_( logData ), selection_( selection ), quickFindPattern_( quickFindPattern ), lastMatch_(), firstMatch_(), searchingNotifier_(), incrementalSearchStatus_() { connect( &searchingNotifier_, SIGNAL( notify( const QFNotification& ) ), this, SIGNAL( notify( const QFNotification& ) ) ); } void QuickFind::incrementalSearchStop() { if ( incrementalSearchStatus_.isOngoing() ) { if ( selection_->isEmpty() ) { // Nothing found? // We reset the selection to what it was *selection_ = incrementalSearchStatus_.initialSelection(); } incrementalSearchStatus_ = IncrementalSearchStatus(); } } void QuickFind::incrementalSearchAbort() { if ( incrementalSearchStatus_.isOngoing() ) { // We reset the selection to what it was *selection_ = incrementalSearchStatus_.initialSelection(); incrementalSearchStatus_ = IncrementalSearchStatus(); } } qint64 QuickFind::incrementallySearchForward() { LOG( logDEBUG ) << "QuickFind::incrementallySearchForward"; // Position where we start the search from FilePosition start_position = selection_->getNextPosition(); if ( incrementalSearchStatus_.direction() == Forward ) { // An incremental search is active, we restart the search // from the initial point LOG( logDEBUG ) << "Restart search from initial point"; start_position = incrementalSearchStatus_.position(); } else { // It's a new search so we search from the selection incrementalSearchStatus_ = IncrementalSearchStatus( Forward, start_position, *selection_ ); } qint64 line_found = doSearchForward( start_position ); if ( line_found >= 0 ) { // We have found a result... // ... the caller will jump to this line. return line_found; } else { // No result... // ... we want the client to show the initial line. selection_->clear(); return incrementalSearchStatus_.position().line(); } } qint64 QuickFind::incrementallySearchBackward() { LOG( logDEBUG ) << "QuickFind::incrementallySearchBackward"; // Position where we start the search from FilePosition start_position = selection_->getPreviousPosition(); if ( incrementalSearchStatus_.direction() == Backward ) { // An incremental search is active, we restart the search // from the initial point LOG( logDEBUG ) << "Restart search from initial point"; start_position = incrementalSearchStatus_.position(); } else { // It's a new search so we search from the selection incrementalSearchStatus_ = IncrementalSearchStatus( Backward, start_position, *selection_ ); } qint64 line_found = doSearchBackward( start_position ); if ( line_found >= 0 ) { // We have found a result... // ... the caller will jump to this line. return line_found; } else { // No result... // ... we want the client to show the initial line. selection_->clear(); return incrementalSearchStatus_.position().line(); } } qint64 QuickFind::searchForward() { incrementalSearchStatus_ = IncrementalSearchStatus(); // Position where we start the search from FilePosition start_position = selection_->getNextPosition(); return doSearchForward( start_position ); } qint64 QuickFind::searchBackward() { incrementalSearchStatus_ = IncrementalSearchStatus(); // Position where we start the search from FilePosition start_position = selection_->getPreviousPosition(); return doSearchBackward( start_position ); } // Internal implementation of forward search, // returns the line where the pattern is found or -1 if not found. // Parameters are the position the search shall start qint64 QuickFind::doSearchForward( const FilePosition &start_position ) { bool found = false; int found_start_col; int found_end_col; if ( ! quickFindPattern_->isActive() ) return -1; // Optimisation: if we are already after the last match, // we don't do any search at all. if ( lastMatch_.isLater( start_position ) ) { // Send a notification emit notify( QFNotificationReachedEndOfFile() ); return -1; } qint64 line = start_position.line(); LOG( logDEBUG ) << "Start searching at line " << line; // We look at the rest of the first line if ( quickFindPattern_->isLineMatching( logData_->getExpandedLineString( line ), start_position.column() ) ) { quickFindPattern_->getLastMatch( &found_start_col, &found_end_col ); found = true; } else { searchingNotifier_.reset(); // And then the rest of the file qint64 nb_lines = logData_->getNbLine(); line++; while ( line < nb_lines ) { if ( quickFindPattern_->isLineMatching( logData_->getExpandedLineString( line ) ) ) { quickFindPattern_->getLastMatch( &found_start_col, &found_end_col ); found = true; break; } line++; // See if we need to notify of the ongoing search searchingNotifier_.ping( line, nb_lines ); } } if ( found ) { selection_->selectPortion( line, found_start_col, found_end_col ); // Clear any notification emit clearNotification(); return line; } else { // Update the position of the last match FilePosition last_match_position = selection_->getPreviousPosition(); lastMatch_.set( last_match_position ); // Send a notification emit notify( QFNotificationReachedEndOfFile() ); return -1; } } // Internal implementation of backward search, // returns the line where the pattern is found or -1 if not found. // Parameters are the position the search shall start qint64 QuickFind::doSearchBackward( const FilePosition &start_position ) { bool found = false; int start_col; int end_col; if ( ! quickFindPattern_->isActive() ) return -1; // Optimisation: if we are already before the first match, // we don't do any search at all. if ( firstMatch_.isSooner( start_position ) ) { // Send a notification emit notify( QFNotificationReachedBegininningOfFile() ); return -1; } qint64 line = start_position.line(); LOG( logDEBUG ) << "Start searching at line " << line; // We look at the beginning of the first line if ( ( start_position.column() > 0 ) && ( quickFindPattern_->isLineMatchingBackward( logData_->getExpandedLineString( line ), start_position.column() ) ) ) { quickFindPattern_->getLastMatch( &start_col, &end_col ); found = true; } else { searchingNotifier_.reset(); // And then the rest of the file qint64 nb_lines = logData_->getNbLine(); line--; while ( line >= 0 ) { if ( quickFindPattern_->isLineMatchingBackward( logData_->getExpandedLineString( line ) ) ) { quickFindPattern_->getLastMatch( &start_col, &end_col ); found = true; break; } line--; // See if we need to notify of the ongoing search searchingNotifier_.ping( -line, nb_lines ); } } if ( found ) { selection_->selectPortion( line, start_col, end_col ); // Clear any notification emit clearNotification(); return line; } else { // Update the position of the first match FilePosition first_match_position = selection_->getNextPosition(); firstMatch_.set( first_match_position ); // Send a notification LOG( logDEBUG ) << "QF: Send BOF notification."; emit notify( QFNotificationReachedBegininningOfFile() ); return -1; } } void QuickFind::resetLimits() { lastMatch_.reset(); firstMatch_.reset(); }