xref: /glogg/src/crawlerwidget.cpp (revision 039481acd3250c79a914161903e50a979998e1cb)
1bb02e0acSNicolas Bonnefon /*
2bb02e0acSNicolas Bonnefon  * Copyright (C) 2009, 2010, 2011, 2012, 2013 Nicolas Bonnefon and other contributors
3bb02e0acSNicolas Bonnefon  *
4bb02e0acSNicolas Bonnefon  * This file is part of glogg.
5bb02e0acSNicolas Bonnefon  *
6bb02e0acSNicolas Bonnefon  * glogg is free software: you can redistribute it and/or modify
7bb02e0acSNicolas Bonnefon  * it under the terms of the GNU General Public License as published by
8bb02e0acSNicolas Bonnefon  * the Free Software Foundation, either version 3 of the License, or
9bb02e0acSNicolas Bonnefon  * (at your option) any later version.
10bb02e0acSNicolas Bonnefon  *
11bb02e0acSNicolas Bonnefon  * glogg is distributed in the hope that it will be useful,
12bb02e0acSNicolas Bonnefon  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13bb02e0acSNicolas Bonnefon  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14bb02e0acSNicolas Bonnefon  * GNU General Public License for more details.
15bb02e0acSNicolas Bonnefon  *
16bb02e0acSNicolas Bonnefon  * You should have received a copy of the GNU General Public License
17bb02e0acSNicolas Bonnefon  * along with glogg.  If not, see <http://www.gnu.org/licenses/>.
18bb02e0acSNicolas Bonnefon  */
19bb02e0acSNicolas Bonnefon 
20bb02e0acSNicolas Bonnefon // This file implements the CrawlerWidget class.
21bb02e0acSNicolas Bonnefon // It is responsible for creating and managing the two views and all
22bb02e0acSNicolas Bonnefon // the UI elements.  It implements the connection between the UI elements.
23bb02e0acSNicolas Bonnefon // It also owns the sets of data (full and filtered).
24bb02e0acSNicolas Bonnefon 
25bb02e0acSNicolas Bonnefon #include "log.h"
26bb02e0acSNicolas Bonnefon 
27*039481acSNicolas Bonnefon #include <cassert>
28*039481acSNicolas Bonnefon 
29bb02e0acSNicolas Bonnefon #include <Qt>
30bb02e0acSNicolas Bonnefon #include <QApplication>
31bb02e0acSNicolas Bonnefon #include <QFile>
32bb02e0acSNicolas Bonnefon #include <QLineEdit>
33bb02e0acSNicolas Bonnefon #include <QFileInfo>
34bb02e0acSNicolas Bonnefon #include <QKeyEvent>
35bb02e0acSNicolas Bonnefon #include <QStandardItemModel>
36bb02e0acSNicolas Bonnefon #include <QHeaderView>
37bb02e0acSNicolas Bonnefon #include <QListView>
38bb02e0acSNicolas Bonnefon 
39bb02e0acSNicolas Bonnefon #include "crawlerwidget.h"
40bb02e0acSNicolas Bonnefon 
41bb02e0acSNicolas Bonnefon #include "quickfindpattern.h"
42bb02e0acSNicolas Bonnefon #include "overview.h"
43bb02e0acSNicolas Bonnefon #include "infoline.h"
44bb02e0acSNicolas Bonnefon #include "savedsearches.h"
45bb02e0acSNicolas Bonnefon #include "quickfindwidget.h"
46bb02e0acSNicolas Bonnefon #include "persistentinfo.h"
47bb02e0acSNicolas Bonnefon #include "configuration.h"
48bb02e0acSNicolas Bonnefon 
49bb02e0acSNicolas Bonnefon // Palette for error signaling (yellow background)
50bb02e0acSNicolas Bonnefon const QPalette CrawlerWidget::errorPalette( QColor( "yellow" ) );
51bb02e0acSNicolas Bonnefon 
52*039481acSNicolas Bonnefon // Constructor only does trivial construction. The real work is done once
53*039481acSNicolas Bonnefon // the data is attached.
54bb02e0acSNicolas Bonnefon CrawlerWidget::CrawlerWidget(SavedSearches* searches, QWidget *parent)
55bb02e0acSNicolas Bonnefon         : QSplitter(parent)
56bb02e0acSNicolas Bonnefon {
57*039481acSNicolas Bonnefon     logData_         = nullptr;
58*039481acSNicolas Bonnefon     logFilteredData_ = nullptr;
59*039481acSNicolas Bonnefon 
60*039481acSNicolas Bonnefon     savedSearches    = searches;
61*039481acSNicolas Bonnefon }
62*039481acSNicolas Bonnefon 
63*039481acSNicolas Bonnefon // The top line is first one on the main display
64*039481acSNicolas Bonnefon int CrawlerWidget::getTopLine() const
65*039481acSNicolas Bonnefon {
66*039481acSNicolas Bonnefon     return logMainView->getTopLine();
67*039481acSNicolas Bonnefon }
68*039481acSNicolas Bonnefon 
69*039481acSNicolas Bonnefon QString CrawlerWidget::getSelectedText() const
70*039481acSNicolas Bonnefon {
71*039481acSNicolas Bonnefon     if ( filteredView->hasFocus() )
72*039481acSNicolas Bonnefon         return filteredView->getSelection();
73*039481acSNicolas Bonnefon     else
74*039481acSNicolas Bonnefon         return logMainView->getSelection();
75*039481acSNicolas Bonnefon }
76*039481acSNicolas Bonnefon 
77*039481acSNicolas Bonnefon void CrawlerWidget::selectAll()
78*039481acSNicolas Bonnefon {
79*039481acSNicolas Bonnefon     activeView()->selectAll();
80*039481acSNicolas Bonnefon }
81*039481acSNicolas Bonnefon 
82*039481acSNicolas Bonnefon // Return a pointer to the view in which we should do the QuickFind
83*039481acSNicolas Bonnefon SearchableWidgetInterface* CrawlerWidget::getActiveSearchable() const
84*039481acSNicolas Bonnefon {
85*039481acSNicolas Bonnefon     QWidget* searchableWidget;
86*039481acSNicolas Bonnefon 
87*039481acSNicolas Bonnefon     // Search in the window that has focus, or the window where 'Find' was
88*039481acSNicolas Bonnefon     // called from, or the main window.
89*039481acSNicolas Bonnefon     if ( filteredView->hasFocus() || logMainView->hasFocus() )
90*039481acSNicolas Bonnefon         searchableWidget = QApplication::focusWidget();
91*039481acSNicolas Bonnefon     else
92*039481acSNicolas Bonnefon         searchableWidget = qfSavedFocus_;
93*039481acSNicolas Bonnefon 
94*039481acSNicolas Bonnefon     if ( AbstractLogView* view = qobject_cast<AbstractLogView*>( searchableWidget ) )
95*039481acSNicolas Bonnefon         return view;
96*039481acSNicolas Bonnefon     else
97*039481acSNicolas Bonnefon         return logMainView;
98*039481acSNicolas Bonnefon }
99*039481acSNicolas Bonnefon 
100*039481acSNicolas Bonnefon //
101*039481acSNicolas Bonnefon // Protected functions
102*039481acSNicolas Bonnefon //
103*039481acSNicolas Bonnefon void CrawlerWidget::doSetData(
104*039481acSNicolas Bonnefon         std::shared_ptr<LogData> log_data,
105*039481acSNicolas Bonnefon         std::shared_ptr<LogFilteredData> filtered_data )
106*039481acSNicolas Bonnefon {
107*039481acSNicolas Bonnefon     logData_         = log_data.get();
108*039481acSNicolas Bonnefon     logFilteredData_ = filtered_data.get();
109*039481acSNicolas Bonnefon 
110*039481acSNicolas Bonnefon     setup();
111*039481acSNicolas Bonnefon }
112*039481acSNicolas Bonnefon 
113*039481acSNicolas Bonnefon //
114*039481acSNicolas Bonnefon // Events handlers
115*039481acSNicolas Bonnefon //
116*039481acSNicolas Bonnefon 
117*039481acSNicolas Bonnefon void CrawlerWidget::keyPressEvent( QKeyEvent* keyEvent )
118*039481acSNicolas Bonnefon {
119*039481acSNicolas Bonnefon     LOG(logDEBUG4) << "keyPressEvent received";
120*039481acSNicolas Bonnefon 
121*039481acSNicolas Bonnefon     switch ( (keyEvent->text())[0].toLatin1() ) {
122*039481acSNicolas Bonnefon         case '/':
123*039481acSNicolas Bonnefon             displayQuickFindBar( QuickFindMux::Forward );
124*039481acSNicolas Bonnefon             break;
125*039481acSNicolas Bonnefon         case '?':
126*039481acSNicolas Bonnefon             displayQuickFindBar( QuickFindMux::Backward );
127*039481acSNicolas Bonnefon             break;
128*039481acSNicolas Bonnefon         default:
129*039481acSNicolas Bonnefon             keyEvent->ignore();
130*039481acSNicolas Bonnefon     }
131*039481acSNicolas Bonnefon 
132*039481acSNicolas Bonnefon     if ( !keyEvent->isAccepted() )
133*039481acSNicolas Bonnefon         QSplitter::keyPressEvent( keyEvent );
134*039481acSNicolas Bonnefon }
135*039481acSNicolas Bonnefon 
136*039481acSNicolas Bonnefon //
137*039481acSNicolas Bonnefon // Slots
138*039481acSNicolas Bonnefon //
139*039481acSNicolas Bonnefon 
140*039481acSNicolas Bonnefon void CrawlerWidget::startNewSearch()
141*039481acSNicolas Bonnefon {
142*039481acSNicolas Bonnefon     // Record the search line in the recent list
143*039481acSNicolas Bonnefon     // (reload the list first in case another glogg changed it)
144*039481acSNicolas Bonnefon     GetPersistentInfo().retrieve( "savedSearches" );
145*039481acSNicolas Bonnefon     savedSearches->addRecent( searchLineEdit->currentText() );
146*039481acSNicolas Bonnefon     GetPersistentInfo().save( "savedSearches" );
147*039481acSNicolas Bonnefon 
148*039481acSNicolas Bonnefon     // Update the SearchLine (history)
149*039481acSNicolas Bonnefon     updateSearchCombo();
150*039481acSNicolas Bonnefon     // Call the private function to do the search
151*039481acSNicolas Bonnefon     replaceCurrentSearch( searchLineEdit->currentText() );
152*039481acSNicolas Bonnefon }
153*039481acSNicolas Bonnefon 
154*039481acSNicolas Bonnefon void CrawlerWidget::stopSearch()
155*039481acSNicolas Bonnefon {
156*039481acSNicolas Bonnefon     logFilteredData_->interruptSearch();
157*039481acSNicolas Bonnefon     searchState_.stopSearch();
158*039481acSNicolas Bonnefon     printSearchInfoMessage();
159*039481acSNicolas Bonnefon }
160*039481acSNicolas Bonnefon 
161*039481acSNicolas Bonnefon // When receiving the 'newDataAvailable' signal from LogFilteredData
162*039481acSNicolas Bonnefon void CrawlerWidget::updateFilteredView( int nbMatches, int progress )
163*039481acSNicolas Bonnefon {
164*039481acSNicolas Bonnefon     LOG(logDEBUG) << "updateFilteredView received.";
165*039481acSNicolas Bonnefon 
166*039481acSNicolas Bonnefon     if ( progress == 100 ) {
167*039481acSNicolas Bonnefon         // Searching done
168*039481acSNicolas Bonnefon         printSearchInfoMessage( nbMatches );
169*039481acSNicolas Bonnefon         searchInfoLine->hideGauge();
170*039481acSNicolas Bonnefon         // De-activate the stop button
171*039481acSNicolas Bonnefon         stopButton->setEnabled( false );
172*039481acSNicolas Bonnefon     }
173*039481acSNicolas Bonnefon     else {
174*039481acSNicolas Bonnefon         // Search in progress
175*039481acSNicolas Bonnefon         // We ignore 0% and 100% to avoid a flash when the search is very short
176*039481acSNicolas Bonnefon         if ( progress > 0 ) {
177*039481acSNicolas Bonnefon             searchInfoLine->setText(
178*039481acSNicolas Bonnefon                     tr("Search in progress (%1 %)... %2 match%3 found so far.")
179*039481acSNicolas Bonnefon                     .arg( progress )
180*039481acSNicolas Bonnefon                     .arg( nbMatches )
181*039481acSNicolas Bonnefon                     .arg( nbMatches > 1 ? "es" : "" ) );
182*039481acSNicolas Bonnefon             searchInfoLine->displayGauge( progress );
183*039481acSNicolas Bonnefon         }
184*039481acSNicolas Bonnefon     }
185*039481acSNicolas Bonnefon 
186*039481acSNicolas Bonnefon     // Recompute the content of the filtered window.
187*039481acSNicolas Bonnefon     filteredView->updateData();
188*039481acSNicolas Bonnefon 
189*039481acSNicolas Bonnefon     // Update the match overview
190*039481acSNicolas Bonnefon     overview_->updateData( logData_->getNbLine() );
191*039481acSNicolas Bonnefon 
192*039481acSNicolas Bonnefon     // Also update the top window for the coloured bullets.
193*039481acSNicolas Bonnefon     update();
194*039481acSNicolas Bonnefon }
195*039481acSNicolas Bonnefon 
196*039481acSNicolas Bonnefon void CrawlerWidget::jumpToMatchingLine(int filteredLineNb)
197*039481acSNicolas Bonnefon {
198*039481acSNicolas Bonnefon     int mainViewLine = logFilteredData_->getMatchingLineNumber(filteredLineNb);
199*039481acSNicolas Bonnefon     logMainView->selectAndDisplayLine(mainViewLine);  // FIXME: should be done with a signal.
200*039481acSNicolas Bonnefon }
201*039481acSNicolas Bonnefon 
202*039481acSNicolas Bonnefon void CrawlerWidget::markLineFromMain( qint64 line )
203*039481acSNicolas Bonnefon {
204*039481acSNicolas Bonnefon     if ( logFilteredData_->isLineMarked( line ) )
205*039481acSNicolas Bonnefon         logFilteredData_->deleteMark( line );
206*039481acSNicolas Bonnefon     else
207*039481acSNicolas Bonnefon         logFilteredData_->addMark( line );
208*039481acSNicolas Bonnefon 
209*039481acSNicolas Bonnefon     // Recompute the content of the filtered window.
210*039481acSNicolas Bonnefon     filteredView->updateData();
211*039481acSNicolas Bonnefon 
212*039481acSNicolas Bonnefon     // Update the match overview
213*039481acSNicolas Bonnefon     overview_->updateData( logData_->getNbLine() );
214*039481acSNicolas Bonnefon 
215*039481acSNicolas Bonnefon     // Also update the top window for the coloured bullets.
216*039481acSNicolas Bonnefon     update();
217*039481acSNicolas Bonnefon }
218*039481acSNicolas Bonnefon 
219*039481acSNicolas Bonnefon void CrawlerWidget::markLineFromFiltered( qint64 line )
220*039481acSNicolas Bonnefon {
221*039481acSNicolas Bonnefon     qint64 line_in_file = logFilteredData_->getMatchingLineNumber( line );
222*039481acSNicolas Bonnefon     if ( logFilteredData_->filteredLineTypeByIndex( line )
223*039481acSNicolas Bonnefon             == LogFilteredData::Mark )
224*039481acSNicolas Bonnefon         logFilteredData_->deleteMark( line_in_file );
225*039481acSNicolas Bonnefon     else
226*039481acSNicolas Bonnefon         logFilteredData_->addMark( line_in_file );
227*039481acSNicolas Bonnefon 
228*039481acSNicolas Bonnefon     // Recompute the content of the filtered window.
229*039481acSNicolas Bonnefon     filteredView->updateData();
230*039481acSNicolas Bonnefon 
231*039481acSNicolas Bonnefon     // Update the match overview
232*039481acSNicolas Bonnefon     overview_->updateData( logData_->getNbLine() );
233*039481acSNicolas Bonnefon 
234*039481acSNicolas Bonnefon     // Also update the top window for the coloured bullets.
235*039481acSNicolas Bonnefon     update();
236*039481acSNicolas Bonnefon }
237*039481acSNicolas Bonnefon 
238*039481acSNicolas Bonnefon void CrawlerWidget::applyConfiguration()
239*039481acSNicolas Bonnefon {
240*039481acSNicolas Bonnefon     Configuration& config = Persistent<Configuration>( "settings" );
241*039481acSNicolas Bonnefon     QFont font = config.mainFont();
242*039481acSNicolas Bonnefon 
243*039481acSNicolas Bonnefon     LOG(logDEBUG) << "CrawlerWidget::applyConfiguration";
244*039481acSNicolas Bonnefon 
245*039481acSNicolas Bonnefon     // Whatever font we use, we should NOT use kerning
246*039481acSNicolas Bonnefon     font.setKerning( false );
247*039481acSNicolas Bonnefon     font.setFixedPitch( true );
248*039481acSNicolas Bonnefon #if QT_VERSION > 0x040700
249*039481acSNicolas Bonnefon     // Necessary on systems doing subpixel positionning (e.g. Ubuntu 12.04)
250*039481acSNicolas Bonnefon     font.setStyleStrategy( QFont::ForceIntegerMetrics );
251*039481acSNicolas Bonnefon #endif
252*039481acSNicolas Bonnefon     logMainView->setFont(font);
253*039481acSNicolas Bonnefon     filteredView->setFont(font);
254*039481acSNicolas Bonnefon 
255*039481acSNicolas Bonnefon     logMainView->setLineNumbersVisible( config.mainLineNumbersVisible() );
256*039481acSNicolas Bonnefon     filteredView->setLineNumbersVisible( config.filteredLineNumbersVisible() );
257*039481acSNicolas Bonnefon 
258*039481acSNicolas Bonnefon     overview_->setVisible( config.isOverviewVisible() );
259*039481acSNicolas Bonnefon     logMainView->refreshOverview();
260*039481acSNicolas Bonnefon 
261*039481acSNicolas Bonnefon     logMainView->updateDisplaySize();
262*039481acSNicolas Bonnefon     logMainView->update();
263*039481acSNicolas Bonnefon     filteredView->updateDisplaySize();
264*039481acSNicolas Bonnefon     filteredView->update();
265*039481acSNicolas Bonnefon 
266*039481acSNicolas Bonnefon     // Update the SearchLine (history)
267*039481acSNicolas Bonnefon     updateSearchCombo();
268*039481acSNicolas Bonnefon }
269*039481acSNicolas Bonnefon 
270*039481acSNicolas Bonnefon void CrawlerWidget::loadingFinishedHandler( bool success )
271*039481acSNicolas Bonnefon {
272*039481acSNicolas Bonnefon     // We need to refresh the main window because the view lines on the
273*039481acSNicolas Bonnefon     // overview have probably changed.
274*039481acSNicolas Bonnefon     overview_->updateData( logData_->getNbLine() );
275*039481acSNicolas Bonnefon 
276*039481acSNicolas Bonnefon     // FIXME, handle topLine
277*039481acSNicolas Bonnefon     // logMainView->updateData( logData_, topLine );
278*039481acSNicolas Bonnefon     logMainView->updateData();
279*039481acSNicolas Bonnefon 
280*039481acSNicolas Bonnefon         // Shall we Forbid starting a search when loading in progress?
281*039481acSNicolas Bonnefon         // searchButton->setEnabled( false );
282*039481acSNicolas Bonnefon 
283*039481acSNicolas Bonnefon     // searchButton->setEnabled( true );
284*039481acSNicolas Bonnefon 
285*039481acSNicolas Bonnefon     // See if we need to auto-refresh the search
286*039481acSNicolas Bonnefon     if ( searchState_.isAutorefreshAllowed() ) {
287*039481acSNicolas Bonnefon         LOG(logDEBUG) << "Refreshing the search";
288*039481acSNicolas Bonnefon         logFilteredData_->updateSearch();
289*039481acSNicolas Bonnefon     }
290*039481acSNicolas Bonnefon 
291*039481acSNicolas Bonnefon     emit loadingFinished( success );
292*039481acSNicolas Bonnefon }
293*039481acSNicolas Bonnefon 
294*039481acSNicolas Bonnefon void CrawlerWidget::fileChangedHandler( LogData::MonitoredFileStatus status )
295*039481acSNicolas Bonnefon {
296*039481acSNicolas Bonnefon     // Handle the case where the file has been truncated
297*039481acSNicolas Bonnefon     if ( status == LogData::Truncated ) {
298*039481acSNicolas Bonnefon         // Clear all marks (TODO offer the option to keep them)
299*039481acSNicolas Bonnefon         logFilteredData_->clearMarks();
300*039481acSNicolas Bonnefon         if ( ! searchInfoLine->text().isEmpty() ) {
301*039481acSNicolas Bonnefon             // Invalidate the search
302*039481acSNicolas Bonnefon             logFilteredData_->clearSearch();
303*039481acSNicolas Bonnefon             filteredView->updateData();
304*039481acSNicolas Bonnefon             searchState_.truncateFile();
305*039481acSNicolas Bonnefon             printSearchInfoMessage();
306*039481acSNicolas Bonnefon         }
307*039481acSNicolas Bonnefon     }
308*039481acSNicolas Bonnefon }
309*039481acSNicolas Bonnefon 
310*039481acSNicolas Bonnefon void CrawlerWidget::displayQuickFindBar( QuickFindMux::QFDirection direction )
311*039481acSNicolas Bonnefon {
312*039481acSNicolas Bonnefon     LOG(logDEBUG) << "CrawlerWidget::displayQuickFindBar";
313*039481acSNicolas Bonnefon 
314*039481acSNicolas Bonnefon     // Remember who had the focus
315*039481acSNicolas Bonnefon     qfSavedFocus_ = QApplication::focusWidget();
316*039481acSNicolas Bonnefon 
317*039481acSNicolas Bonnefon     quickFindMux_->setDirection( direction );
318*039481acSNicolas Bonnefon     quickFindWidget_->userActivate();
319*039481acSNicolas Bonnefon }
320*039481acSNicolas Bonnefon 
321*039481acSNicolas Bonnefon void CrawlerWidget::hideQuickFindBar()
322*039481acSNicolas Bonnefon {
323*039481acSNicolas Bonnefon     // Restore the focus once the QFBar has been hidden
324*039481acSNicolas Bonnefon     qfSavedFocus_->setFocus();
325*039481acSNicolas Bonnefon }
326*039481acSNicolas Bonnefon 
327*039481acSNicolas Bonnefon void CrawlerWidget::changeQFPattern( const QString& newPattern )
328*039481acSNicolas Bonnefon {
329*039481acSNicolas Bonnefon     quickFindWidget_->changeDisplayedPattern( newPattern );
330*039481acSNicolas Bonnefon }
331*039481acSNicolas Bonnefon 
332*039481acSNicolas Bonnefon // Returns a pointer to the window in which the search should be done
333*039481acSNicolas Bonnefon AbstractLogView* CrawlerWidget::activeView() const
334*039481acSNicolas Bonnefon {
335*039481acSNicolas Bonnefon     QWidget* activeView;
336*039481acSNicolas Bonnefon 
337*039481acSNicolas Bonnefon     // Search in the window that has focus, or the window where 'Find' was
338*039481acSNicolas Bonnefon     // called from, or the main window.
339*039481acSNicolas Bonnefon     if ( filteredView->hasFocus() || logMainView->hasFocus() )
340*039481acSNicolas Bonnefon         activeView = QApplication::focusWidget();
341*039481acSNicolas Bonnefon     else
342*039481acSNicolas Bonnefon         activeView = qfSavedFocus_;
343*039481acSNicolas Bonnefon 
344*039481acSNicolas Bonnefon     if ( AbstractLogView* view = qobject_cast<AbstractLogView*>( activeView ) )
345*039481acSNicolas Bonnefon         return view;
346*039481acSNicolas Bonnefon     else
347*039481acSNicolas Bonnefon         return logMainView;
348*039481acSNicolas Bonnefon }
349*039481acSNicolas Bonnefon 
350*039481acSNicolas Bonnefon void CrawlerWidget::searchForward()
351*039481acSNicolas Bonnefon {
352*039481acSNicolas Bonnefon     LOG(logDEBUG) << "CrawlerWidget::searchForward";
353*039481acSNicolas Bonnefon 
354*039481acSNicolas Bonnefon     activeView()->searchForward();
355*039481acSNicolas Bonnefon }
356*039481acSNicolas Bonnefon 
357*039481acSNicolas Bonnefon void CrawlerWidget::searchBackward()
358*039481acSNicolas Bonnefon {
359*039481acSNicolas Bonnefon     LOG(logDEBUG) << "CrawlerWidget::searchBackward";
360*039481acSNicolas Bonnefon 
361*039481acSNicolas Bonnefon     activeView()->searchBackward();
362*039481acSNicolas Bonnefon }
363*039481acSNicolas Bonnefon 
364*039481acSNicolas Bonnefon void CrawlerWidget::searchRefreshChangedHandler( int state )
365*039481acSNicolas Bonnefon {
366*039481acSNicolas Bonnefon     searchState_.setAutorefresh( state == Qt::Checked );
367*039481acSNicolas Bonnefon     printSearchInfoMessage( logFilteredData_->getNbMatches() );
368*039481acSNicolas Bonnefon }
369*039481acSNicolas Bonnefon 
370*039481acSNicolas Bonnefon void CrawlerWidget::searchTextChangeHandler()
371*039481acSNicolas Bonnefon {
372*039481acSNicolas Bonnefon     // We suspend auto-refresh
373*039481acSNicolas Bonnefon     searchState_.changeExpression();
374*039481acSNicolas Bonnefon     printSearchInfoMessage( logFilteredData_->getNbMatches() );
375*039481acSNicolas Bonnefon }
376*039481acSNicolas Bonnefon 
377*039481acSNicolas Bonnefon void CrawlerWidget::changeFilteredViewVisibility( int index )
378*039481acSNicolas Bonnefon {
379*039481acSNicolas Bonnefon     QStandardItem* item = visibilityModel_->item( index );
380*039481acSNicolas Bonnefon     FilteredView::Visibility visibility =
381*039481acSNicolas Bonnefon         static_cast< FilteredView::Visibility>( item->data().toInt() );
382*039481acSNicolas Bonnefon 
383*039481acSNicolas Bonnefon     filteredView->setVisibility( visibility );
384*039481acSNicolas Bonnefon }
385*039481acSNicolas Bonnefon 
386*039481acSNicolas Bonnefon void CrawlerWidget::addToSearch( const QString& string )
387*039481acSNicolas Bonnefon {
388*039481acSNicolas Bonnefon     QString text = searchLineEdit->currentText();
389*039481acSNicolas Bonnefon 
390*039481acSNicolas Bonnefon     if ( text.isEmpty() )
391*039481acSNicolas Bonnefon         text = string;
392*039481acSNicolas Bonnefon     else {
393*039481acSNicolas Bonnefon         // Escape the regexp chars from the string before adding it.
394*039481acSNicolas Bonnefon         text += ( '|' + QRegExp::escape( string ) );
395*039481acSNicolas Bonnefon     }
396*039481acSNicolas Bonnefon 
397*039481acSNicolas Bonnefon     searchLineEdit->setEditText( text );
398*039481acSNicolas Bonnefon 
399*039481acSNicolas Bonnefon     // Set the focus to lineEdit so that the user can press 'Return' immediately
400*039481acSNicolas Bonnefon     searchLineEdit->lineEdit()->setFocus();
401*039481acSNicolas Bonnefon }
402*039481acSNicolas Bonnefon 
403*039481acSNicolas Bonnefon void CrawlerWidget::mouseHoveredOverMatch( qint64 line )
404*039481acSNicolas Bonnefon {
405*039481acSNicolas Bonnefon     qint64 line_in_mainview = logFilteredData_->getMatchingLineNumber( line );
406*039481acSNicolas Bonnefon 
407*039481acSNicolas Bonnefon     overviewWidget_->highlightLine( line_in_mainview );
408*039481acSNicolas Bonnefon }
409*039481acSNicolas Bonnefon 
410*039481acSNicolas Bonnefon //
411*039481acSNicolas Bonnefon // Private functions
412*039481acSNicolas Bonnefon //
413*039481acSNicolas Bonnefon 
414*039481acSNicolas Bonnefon // Build the widget and connect all the signals, this must be done once
415*039481acSNicolas Bonnefon // the data are attached.
416*039481acSNicolas Bonnefon void CrawlerWidget::setup()
417*039481acSNicolas Bonnefon {
418bb02e0acSNicolas Bonnefon     setOrientation(Qt::Vertical);
419bb02e0acSNicolas Bonnefon 
420*039481acSNicolas Bonnefon     assert( logData_ );
421*039481acSNicolas Bonnefon     assert( logFilteredData_ );
422bb02e0acSNicolas Bonnefon 
423bb02e0acSNicolas Bonnefon     // The matches overview
424bb02e0acSNicolas Bonnefon     overview_ = new Overview();
425bb02e0acSNicolas Bonnefon 
426bb02e0acSNicolas Bonnefon     // Initialise the QF Mux to send requests from the QFWidget
427bb02e0acSNicolas Bonnefon     // to the right window
428bb02e0acSNicolas Bonnefon     quickFindMux_ = new QuickFindMux( this );
429bb02e0acSNicolas Bonnefon 
430bb02e0acSNicolas Bonnefon     // The views
431bb02e0acSNicolas Bonnefon     bottomWindow = new QWidget;
432bb02e0acSNicolas Bonnefon     overviewWidget_ = new OverviewWidget();
433bb02e0acSNicolas Bonnefon     logMainView     = new LogMainView(
434bb02e0acSNicolas Bonnefon             logData_, quickFindMux_->getPattern(), overview_, overviewWidget_ );
435bb02e0acSNicolas Bonnefon     filteredView    = new FilteredView(
436bb02e0acSNicolas Bonnefon             logFilteredData_, quickFindMux_->getPattern() );
437bb02e0acSNicolas Bonnefon 
438bb02e0acSNicolas Bonnefon     overviewWidget_->setOverview( overview_ );
439bb02e0acSNicolas Bonnefon     overviewWidget_->setParent( logMainView );
440bb02e0acSNicolas Bonnefon 
441bb02e0acSNicolas Bonnefon     quickFindMux_->registerSearchable( logMainView );
442bb02e0acSNicolas Bonnefon     quickFindMux_->registerSearchable( filteredView );
443bb02e0acSNicolas Bonnefon 
444bb02e0acSNicolas Bonnefon     // Construct the visibility button
445bb02e0acSNicolas Bonnefon     visibilityModel_ = new QStandardItemModel( this );
446bb02e0acSNicolas Bonnefon 
447bb02e0acSNicolas Bonnefon     QStandardItem *marksAndMatchesItem = new QStandardItem( tr( "Marks and matches" ) );
448bb02e0acSNicolas Bonnefon     QPixmap marksAndMatchesPixmap( 16, 10 );
449bb02e0acSNicolas Bonnefon     marksAndMatchesPixmap.fill( Qt::gray );
450bb02e0acSNicolas Bonnefon     marksAndMatchesItem->setIcon( QIcon( marksAndMatchesPixmap ) );
451bb02e0acSNicolas Bonnefon     marksAndMatchesItem->setData( FilteredView::MarksAndMatches );
452bb02e0acSNicolas Bonnefon     visibilityModel_->appendRow( marksAndMatchesItem );
453bb02e0acSNicolas Bonnefon 
454bb02e0acSNicolas Bonnefon     QStandardItem *marksItem = new QStandardItem( tr( "Marks" ) );
455bb02e0acSNicolas Bonnefon     QPixmap marksPixmap( 16, 10 );
456bb02e0acSNicolas Bonnefon     marksPixmap.fill( Qt::blue );
457bb02e0acSNicolas Bonnefon     marksItem->setIcon( QIcon( marksPixmap ) );
458bb02e0acSNicolas Bonnefon     marksItem->setData( FilteredView::MarksOnly );
459bb02e0acSNicolas Bonnefon     visibilityModel_->appendRow( marksItem );
460bb02e0acSNicolas Bonnefon 
461bb02e0acSNicolas Bonnefon     QStandardItem *matchesItem = new QStandardItem( tr( "Matches" ) );
462bb02e0acSNicolas Bonnefon     QPixmap matchesPixmap( 16, 10 );
463bb02e0acSNicolas Bonnefon     matchesPixmap.fill( Qt::red );
464bb02e0acSNicolas Bonnefon     matchesItem->setIcon( QIcon( matchesPixmap ) );
465bb02e0acSNicolas Bonnefon     matchesItem->setData( FilteredView::MatchesOnly );
466bb02e0acSNicolas Bonnefon     visibilityModel_->appendRow( matchesItem );
467bb02e0acSNicolas Bonnefon 
468bb02e0acSNicolas Bonnefon     QListView *visibilityView = new QListView( this );
469bb02e0acSNicolas Bonnefon     visibilityView->setMovement( QListView::Static );
470bb02e0acSNicolas Bonnefon     visibilityView->setMinimumWidth( 170 ); // Only needed with custom style-sheet
471bb02e0acSNicolas Bonnefon 
472bb02e0acSNicolas Bonnefon     visibilityBox = new QComboBox();
473bb02e0acSNicolas Bonnefon     visibilityBox->setModel( visibilityModel_ );
474bb02e0acSNicolas Bonnefon     visibilityBox->setView( visibilityView );
475bb02e0acSNicolas Bonnefon 
476bb02e0acSNicolas Bonnefon     // Select "Marks and matches" by default (same default as the filtered view)
477bb02e0acSNicolas Bonnefon     visibilityBox->setCurrentIndex( 0 );
478bb02e0acSNicolas Bonnefon 
479bb02e0acSNicolas Bonnefon     // TODO: Maybe there is some way to set the popup width to be
480bb02e0acSNicolas Bonnefon     // sized-to-content (as it is when the stylesheet is not overriden) in the
481bb02e0acSNicolas Bonnefon     // stylesheet as opposed to setting a hard min-width on the view above.
482bb02e0acSNicolas Bonnefon     visibilityBox->setStyleSheet( " \
483bb02e0acSNicolas Bonnefon         QComboBox:on {\
484bb02e0acSNicolas Bonnefon             padding: 1px 2px 1px 6px;\
485bb02e0acSNicolas Bonnefon             width: 19px;\
486bb02e0acSNicolas Bonnefon         } \
487bb02e0acSNicolas Bonnefon         QComboBox:!on {\
488bb02e0acSNicolas Bonnefon             padding: 1px 2px 1px 7px;\
489bb02e0acSNicolas Bonnefon             width: 19px;\
490bb02e0acSNicolas Bonnefon             height: 16px;\
491bb02e0acSNicolas Bonnefon             border: 1px solid gray;\
492bb02e0acSNicolas Bonnefon         } \
493bb02e0acSNicolas Bonnefon         QComboBox::drop-down::down-arrow {\
494bb02e0acSNicolas Bonnefon             width: 0px;\
495bb02e0acSNicolas Bonnefon             border-width: 0px;\
496bb02e0acSNicolas Bonnefon         } \
497bb02e0acSNicolas Bonnefon " );
498bb02e0acSNicolas Bonnefon 
499bb02e0acSNicolas Bonnefon     // Construct the Search Info line
500bb02e0acSNicolas Bonnefon     searchInfoLine = new InfoLine();
501bb02e0acSNicolas Bonnefon     searchInfoLine->setFrameStyle( QFrame::WinPanel | QFrame::Sunken );
502bb02e0acSNicolas Bonnefon     searchInfoLine->setLineWidth( 1 );
503bb02e0acSNicolas Bonnefon     searchInfoLineDefaultPalette = searchInfoLine->palette();
504bb02e0acSNicolas Bonnefon 
505bb02e0acSNicolas Bonnefon     ignoreCaseCheck = new QCheckBox( "Ignore &case" );
506bb02e0acSNicolas Bonnefon     searchRefreshCheck = new QCheckBox( "Auto-&refresh" );
507bb02e0acSNicolas Bonnefon 
508bb02e0acSNicolas Bonnefon     // Construct the Search line
509bb02e0acSNicolas Bonnefon     searchLabel = new QLabel(tr("&Text: "));
510bb02e0acSNicolas Bonnefon     searchLineEdit = new QComboBox;
511bb02e0acSNicolas Bonnefon     searchLineEdit->setEditable( true );
512bb02e0acSNicolas Bonnefon     searchLineEdit->setCompleter( 0 );
513bb02e0acSNicolas Bonnefon     searchLineEdit->addItems( savedSearches->recentSearches() );
514bb02e0acSNicolas Bonnefon     searchLineEdit->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
515bb02e0acSNicolas Bonnefon     searchLineEdit->setSizeAdjustPolicy( QComboBox::AdjustToMinimumContentsLengthWithIcon );
516bb02e0acSNicolas Bonnefon 
517bb02e0acSNicolas Bonnefon     searchLabel->setBuddy( searchLineEdit );
518bb02e0acSNicolas Bonnefon 
519bb02e0acSNicolas Bonnefon     searchButton = new QToolButton();
520bb02e0acSNicolas Bonnefon     searchButton->setText( tr("&Search") );
521bb02e0acSNicolas Bonnefon     searchButton->setAutoRaise( true );
522bb02e0acSNicolas Bonnefon 
523bb02e0acSNicolas Bonnefon     stopButton = new QToolButton();
524bb02e0acSNicolas Bonnefon     stopButton->setIcon( QIcon(":/images/stop16.png") );
525bb02e0acSNicolas Bonnefon     stopButton->setAutoRaise( true );
526bb02e0acSNicolas Bonnefon     stopButton->setEnabled( false );
527bb02e0acSNicolas Bonnefon 
528bb02e0acSNicolas Bonnefon     // Construct the QuickFind bar
529bb02e0acSNicolas Bonnefon     quickFindWidget_ = new QuickFindWidget();
530bb02e0acSNicolas Bonnefon 
531bb02e0acSNicolas Bonnefon     QHBoxLayout* searchLineLayout = new QHBoxLayout;
532bb02e0acSNicolas Bonnefon     searchLineLayout->addWidget(searchLabel);
533bb02e0acSNicolas Bonnefon     searchLineLayout->addWidget(searchLineEdit);
534bb02e0acSNicolas Bonnefon     searchLineLayout->addWidget(searchButton);
535bb02e0acSNicolas Bonnefon     searchLineLayout->addWidget(stopButton);
536bb02e0acSNicolas Bonnefon     searchLineLayout->setContentsMargins(6, 0, 6, 0);
537bb02e0acSNicolas Bonnefon     stopButton->setSizePolicy( QSizePolicy( QSizePolicy::Maximum, QSizePolicy::Maximum ) );
538bb02e0acSNicolas Bonnefon     searchButton->setSizePolicy( QSizePolicy( QSizePolicy::Maximum, QSizePolicy::Maximum ) );
539bb02e0acSNicolas Bonnefon 
540bb02e0acSNicolas Bonnefon     QHBoxLayout* searchInfoLineLayout = new QHBoxLayout;
541bb02e0acSNicolas Bonnefon     searchInfoLineLayout->addWidget( visibilityBox );
542bb02e0acSNicolas Bonnefon     searchInfoLineLayout->addWidget( searchInfoLine );
543bb02e0acSNicolas Bonnefon     searchInfoLineLayout->addWidget( ignoreCaseCheck );
544bb02e0acSNicolas Bonnefon     searchInfoLineLayout->addWidget( searchRefreshCheck );
545bb02e0acSNicolas Bonnefon 
546bb02e0acSNicolas Bonnefon     // Construct the bottom window
547bb02e0acSNicolas Bonnefon     quickFindWidget_->hide();
548bb02e0acSNicolas Bonnefon     QVBoxLayout* bottomMainLayout = new QVBoxLayout;
549bb02e0acSNicolas Bonnefon     bottomMainLayout->addLayout(searchLineLayout);
550bb02e0acSNicolas Bonnefon     bottomMainLayout->addLayout(searchInfoLineLayout);
551bb02e0acSNicolas Bonnefon     bottomMainLayout->addWidget(filteredView);
552bb02e0acSNicolas Bonnefon     bottomMainLayout->addWidget(quickFindWidget_);
553bb02e0acSNicolas Bonnefon     bottomMainLayout->setContentsMargins(2, 1, 2, 1);
554bb02e0acSNicolas Bonnefon     bottomWindow->setLayout(bottomMainLayout);
555bb02e0acSNicolas Bonnefon 
556bb02e0acSNicolas Bonnefon     addWidget( logMainView );
557bb02e0acSNicolas Bonnefon     addWidget( bottomWindow );
558bb02e0acSNicolas Bonnefon 
559bb02e0acSNicolas Bonnefon     // Default splitter position (usually overridden by the config file)
560bb02e0acSNicolas Bonnefon     QList<int> splitterSizes;
561bb02e0acSNicolas Bonnefon     splitterSizes += 400;
562bb02e0acSNicolas Bonnefon     splitterSizes += 100;
563bb02e0acSNicolas Bonnefon     setSizes( splitterSizes );
564bb02e0acSNicolas Bonnefon 
565bb02e0acSNicolas Bonnefon     // Connect the signals
566bb02e0acSNicolas Bonnefon     connect(searchLineEdit->lineEdit(), SIGNAL( returnPressed() ),
567bb02e0acSNicolas Bonnefon             searchButton, SIGNAL( clicked() ));
568bb02e0acSNicolas Bonnefon     connect(searchLineEdit->lineEdit(), SIGNAL( textEdited( const QString& ) ),
569bb02e0acSNicolas Bonnefon             this, SLOT( searchTextChangeHandler() ));
570bb02e0acSNicolas Bonnefon     connect(searchButton, SIGNAL( clicked() ),
571bb02e0acSNicolas Bonnefon             this, SLOT( startNewSearch() ) );
572bb02e0acSNicolas Bonnefon     connect(stopButton, SIGNAL( clicked() ),
573bb02e0acSNicolas Bonnefon             this, SLOT( stopSearch() ) );
574bb02e0acSNicolas Bonnefon 
575bb02e0acSNicolas Bonnefon     connect(visibilityBox, SIGNAL( currentIndexChanged( int ) ),
576bb02e0acSNicolas Bonnefon             this, SLOT( changeFilteredViewVisibility( int ) ) );
577bb02e0acSNicolas Bonnefon 
578bb02e0acSNicolas Bonnefon     connect(logMainView, SIGNAL( newSelection( int ) ),
579bb02e0acSNicolas Bonnefon             logMainView, SLOT( update() ) );
580bb02e0acSNicolas Bonnefon     connect(filteredView, SIGNAL( newSelection( int ) ),
581bb02e0acSNicolas Bonnefon             this, SLOT( jumpToMatchingLine( int ) ) );
582bb02e0acSNicolas Bonnefon     connect(filteredView, SIGNAL( newSelection( int ) ),
583bb02e0acSNicolas Bonnefon             filteredView, SLOT( update() ) );
584bb02e0acSNicolas Bonnefon     connect(logMainView, SIGNAL( updateLineNumber( int ) ),
585bb02e0acSNicolas Bonnefon             this, SIGNAL( updateLineNumber( int ) ) );
586bb02e0acSNicolas Bonnefon     connect(logMainView, SIGNAL( markLine( qint64 ) ),
587bb02e0acSNicolas Bonnefon             this, SLOT( markLineFromMain( qint64 ) ) );
588bb02e0acSNicolas Bonnefon     connect(filteredView, SIGNAL( markLine( qint64 ) ),
589bb02e0acSNicolas Bonnefon             this, SLOT( markLineFromFiltered( qint64 ) ) );
590bb02e0acSNicolas Bonnefon 
591bb02e0acSNicolas Bonnefon     connect(logMainView, SIGNAL( addToSearch( const QString& ) ),
592bb02e0acSNicolas Bonnefon             this, SLOT( addToSearch( const QString& ) ) );
593bb02e0acSNicolas Bonnefon     connect(filteredView, SIGNAL( addToSearch( const QString& ) ),
594bb02e0acSNicolas Bonnefon             this, SLOT( addToSearch( const QString& ) ) );
595bb02e0acSNicolas Bonnefon 
596bb02e0acSNicolas Bonnefon     connect(filteredView, SIGNAL( mouseHoveredOverLine( qint64 ) ),
597bb02e0acSNicolas Bonnefon             this, SLOT( mouseHoveredOverMatch( qint64 ) ) );
598bb02e0acSNicolas Bonnefon     connect(filteredView, SIGNAL( mouseLeftHoveringZone() ),
599bb02e0acSNicolas Bonnefon             overviewWidget_, SLOT( removeHighlight() ) );
600bb02e0acSNicolas Bonnefon 
601bb02e0acSNicolas Bonnefon     // Follow option (up and down)
602bb02e0acSNicolas Bonnefon     connect(this, SIGNAL( followSet( bool ) ),
603bb02e0acSNicolas Bonnefon             logMainView, SLOT( followSet( bool ) ) );
604bb02e0acSNicolas Bonnefon     connect(this, SIGNAL( followSet( bool ) ),
605bb02e0acSNicolas Bonnefon             filteredView, SLOT( followSet( bool ) ) );
606bb02e0acSNicolas Bonnefon     connect(logMainView, SIGNAL( followDisabled() ),
607bb02e0acSNicolas Bonnefon             this, SIGNAL( followDisabled() ) );
608bb02e0acSNicolas Bonnefon     connect(filteredView, SIGNAL( followDisabled() ),
609bb02e0acSNicolas Bonnefon             this, SIGNAL( followDisabled() ) );
610bb02e0acSNicolas Bonnefon 
611bb02e0acSNicolas Bonnefon     connect( logFilteredData_, SIGNAL( searchProgressed( int, int ) ),
612bb02e0acSNicolas Bonnefon             this, SLOT( updateFilteredView( int, int ) ) );
613bb02e0acSNicolas Bonnefon 
614bb02e0acSNicolas Bonnefon     // QuickFind
615bb02e0acSNicolas Bonnefon     connect( quickFindWidget_, SIGNAL( close() ),
616bb02e0acSNicolas Bonnefon              this, SLOT( hideQuickFindBar() ) );
617bb02e0acSNicolas Bonnefon     connect( quickFindWidget_, SIGNAL( patternConfirmed( const QString&, bool ) ),
618bb02e0acSNicolas Bonnefon              quickFindMux_, SLOT( confirmPattern( const QString&, bool ) ) );
619bb02e0acSNicolas Bonnefon     connect( quickFindWidget_, SIGNAL( patternUpdated( const QString&, bool ) ),
620bb02e0acSNicolas Bonnefon              quickFindMux_, SLOT( setNewPattern( const QString&, bool ) ) );
621bb02e0acSNicolas Bonnefon     connect( quickFindWidget_, SIGNAL( cancelSearch() ),
622bb02e0acSNicolas Bonnefon              quickFindMux_, SLOT( cancelSearch() ) );
623bb02e0acSNicolas Bonnefon     connect( quickFindWidget_, SIGNAL( searchForward() ),
624bb02e0acSNicolas Bonnefon              quickFindMux_, SLOT( searchForward() ) );
625bb02e0acSNicolas Bonnefon     connect( quickFindWidget_, SIGNAL( searchBackward() ),
626bb02e0acSNicolas Bonnefon              quickFindMux_, SLOT( searchBackward() ) );
627bb02e0acSNicolas Bonnefon     connect( quickFindWidget_, SIGNAL( searchNext() ),
628bb02e0acSNicolas Bonnefon              quickFindMux_, SLOT( searchNext() ) );
629bb02e0acSNicolas Bonnefon 
630bb02e0acSNicolas Bonnefon     // QuickFind changes coming from the views
631bb02e0acSNicolas Bonnefon     connect( quickFindMux_, SIGNAL( patternChanged( const QString& ) ),
632bb02e0acSNicolas Bonnefon              this, SLOT( changeQFPattern( const QString& ) ) );
633bb02e0acSNicolas Bonnefon     connect( quickFindMux_, SIGNAL( notify( const QFNotification& ) ),
634bb02e0acSNicolas Bonnefon              quickFindWidget_, SLOT( notify( const QFNotification& ) ) );
635bb02e0acSNicolas Bonnefon     connect( quickFindMux_, SIGNAL( clearNotification() ),
636bb02e0acSNicolas Bonnefon              quickFindWidget_, SLOT( clearNotification() ) );
637bb02e0acSNicolas Bonnefon 
638bb02e0acSNicolas Bonnefon     // Sent load file update to MainWindow (for status update)
639bb02e0acSNicolas Bonnefon     connect( logData_, SIGNAL( loadingProgressed( int ) ),
640bb02e0acSNicolas Bonnefon             this, SIGNAL( loadingProgressed( int ) ) );
641bb02e0acSNicolas Bonnefon     connect( logData_, SIGNAL( loadingFinished( bool ) ),
642bb02e0acSNicolas Bonnefon             this, SLOT( loadingFinishedHandler( bool ) ) );
643bb02e0acSNicolas Bonnefon     connect( logData_, SIGNAL( fileChanged( LogData::MonitoredFileStatus ) ),
644bb02e0acSNicolas Bonnefon             this, SLOT( fileChangedHandler( LogData::MonitoredFileStatus ) ) );
645bb02e0acSNicolas Bonnefon 
646bb02e0acSNicolas Bonnefon     // Search auto-refresh
647bb02e0acSNicolas Bonnefon     connect( searchRefreshCheck, SIGNAL( stateChanged( int ) ),
648bb02e0acSNicolas Bonnefon             this, SLOT( searchRefreshChangedHandler( int ) ) );
649bb02e0acSNicolas Bonnefon }
650bb02e0acSNicolas Bonnefon 
651bb02e0acSNicolas Bonnefon // Create a new search using the text passed, replace the currently
652bb02e0acSNicolas Bonnefon // used one and destroy the old one.
653bb02e0acSNicolas Bonnefon void CrawlerWidget::replaceCurrentSearch( const QString& searchText )
654bb02e0acSNicolas Bonnefon {
655bb02e0acSNicolas Bonnefon     // Interrupt the search if it's ongoing
656bb02e0acSNicolas Bonnefon     logFilteredData_->interruptSearch();
657bb02e0acSNicolas Bonnefon 
658bb02e0acSNicolas Bonnefon     // We have to wait for the last search update (100%)
659bb02e0acSNicolas Bonnefon     // before clearing/restarting to avoid having remaining results.
660bb02e0acSNicolas Bonnefon 
661bb02e0acSNicolas Bonnefon     // FIXME: this is a bit of a hack, we call processEvents
662bb02e0acSNicolas Bonnefon     // for Qt to empty its event queue, including (hopefully)
663bb02e0acSNicolas Bonnefon     // the search update event sent by logFilteredData_. It saves
664bb02e0acSNicolas Bonnefon     // us the overhead of having proper sync.
665bb02e0acSNicolas Bonnefon     QApplication::processEvents( QEventLoop::ExcludeUserInputEvents );
666bb02e0acSNicolas Bonnefon 
667bb02e0acSNicolas Bonnefon     if ( !searchText.isEmpty() ) {
668bb02e0acSNicolas Bonnefon         // Determine the type of regexp depending on the config
669bb02e0acSNicolas Bonnefon         QRegExp::PatternSyntax syntax;
670bb02e0acSNicolas Bonnefon         static Configuration& config = Persistent<Configuration>( "settings" );
671bb02e0acSNicolas Bonnefon         switch ( config.mainRegexpType() ) {
672bb02e0acSNicolas Bonnefon             case Wildcard:
673bb02e0acSNicolas Bonnefon                 syntax = QRegExp::Wildcard;
674bb02e0acSNicolas Bonnefon                 break;
675bb02e0acSNicolas Bonnefon             case FixedString:
676bb02e0acSNicolas Bonnefon                 syntax = QRegExp::FixedString;
677bb02e0acSNicolas Bonnefon                 break;
678bb02e0acSNicolas Bonnefon             default:
679bb02e0acSNicolas Bonnefon                 syntax = QRegExp::RegExp2;
680bb02e0acSNicolas Bonnefon                 break;
681bb02e0acSNicolas Bonnefon         }
682bb02e0acSNicolas Bonnefon 
683bb02e0acSNicolas Bonnefon         // Set the pattern case insensitive if needed
684bb02e0acSNicolas Bonnefon         Qt::CaseSensitivity case_sensitivity = Qt::CaseSensitive;
685bb02e0acSNicolas Bonnefon         if ( ignoreCaseCheck->checkState() == Qt::Checked )
686bb02e0acSNicolas Bonnefon             case_sensitivity = Qt::CaseInsensitive;
687bb02e0acSNicolas Bonnefon 
688bb02e0acSNicolas Bonnefon         // Constructs the regexp
689bb02e0acSNicolas Bonnefon         QRegExp regexp( searchText, case_sensitivity, syntax );
690bb02e0acSNicolas Bonnefon 
691bb02e0acSNicolas Bonnefon         if ( regexp.isValid() ) {
692bb02e0acSNicolas Bonnefon             // Activate the stop button
693bb02e0acSNicolas Bonnefon             stopButton->setEnabled( true );
694bb02e0acSNicolas Bonnefon             // Start a new asynchronous search
695bb02e0acSNicolas Bonnefon             logFilteredData_->runSearch( regexp );
696bb02e0acSNicolas Bonnefon             // Accept auto-refresh of the search
697bb02e0acSNicolas Bonnefon             searchState_.startSearch();
698bb02e0acSNicolas Bonnefon         }
699bb02e0acSNicolas Bonnefon         else {
700bb02e0acSNicolas Bonnefon             // The regexp is wrong
701bb02e0acSNicolas Bonnefon             logFilteredData_->clearSearch();
702bb02e0acSNicolas Bonnefon             filteredView->updateData();
703bb02e0acSNicolas Bonnefon             searchState_.resetState();
704bb02e0acSNicolas Bonnefon 
705bb02e0acSNicolas Bonnefon             // Inform the user
706bb02e0acSNicolas Bonnefon             QString errorMessage = tr("Error in expression: ");
707bb02e0acSNicolas Bonnefon             errorMessage += regexp.errorString();
708bb02e0acSNicolas Bonnefon             searchInfoLine->setPalette( errorPalette );
709bb02e0acSNicolas Bonnefon             searchInfoLine->setText( errorMessage );
710bb02e0acSNicolas Bonnefon         }
711bb02e0acSNicolas Bonnefon     }
712bb02e0acSNicolas Bonnefon     else {
713bb02e0acSNicolas Bonnefon         logFilteredData_->clearSearch();
714bb02e0acSNicolas Bonnefon         filteredView->updateData();
715bb02e0acSNicolas Bonnefon         searchState_.resetState();
716bb02e0acSNicolas Bonnefon         printSearchInfoMessage();
717bb02e0acSNicolas Bonnefon     }
718bb02e0acSNicolas Bonnefon     // Connect the search to the top view
719bb02e0acSNicolas Bonnefon     logMainView->useNewFiltering( logFilteredData_ );
720bb02e0acSNicolas Bonnefon }
721bb02e0acSNicolas Bonnefon 
722bb02e0acSNicolas Bonnefon // Updates the content of the drop down list for the saved searches,
723bb02e0acSNicolas Bonnefon // called when the SavedSearch has been changed.
724bb02e0acSNicolas Bonnefon void CrawlerWidget::updateSearchCombo()
725bb02e0acSNicolas Bonnefon {
726bb02e0acSNicolas Bonnefon     const QString text = searchLineEdit->lineEdit()->text();
727bb02e0acSNicolas Bonnefon     searchLineEdit->clear();
728bb02e0acSNicolas Bonnefon     searchLineEdit->addItems( savedSearches->recentSearches() );
729bb02e0acSNicolas Bonnefon     // In case we had something that wasn't added to the list (blank...):
730bb02e0acSNicolas Bonnefon     searchLineEdit->lineEdit()->setText( text );
731bb02e0acSNicolas Bonnefon }
732bb02e0acSNicolas Bonnefon 
733bb02e0acSNicolas Bonnefon // Print the search info message.
734bb02e0acSNicolas Bonnefon void CrawlerWidget::printSearchInfoMessage( int nbMatches )
735bb02e0acSNicolas Bonnefon {
736bb02e0acSNicolas Bonnefon     QString text;
737bb02e0acSNicolas Bonnefon 
738bb02e0acSNicolas Bonnefon     switch ( searchState_.getState() ) {
739bb02e0acSNicolas Bonnefon         case SearchState::NoSearch:
740bb02e0acSNicolas Bonnefon             // Blank text is fine
741bb02e0acSNicolas Bonnefon             break;
742bb02e0acSNicolas Bonnefon         case SearchState::Static:
743bb02e0acSNicolas Bonnefon             text = tr("%1 match%2 found.").arg( nbMatches )
744bb02e0acSNicolas Bonnefon                 .arg( nbMatches > 1 ? "es" : "" );
745bb02e0acSNicolas Bonnefon             break;
746bb02e0acSNicolas Bonnefon         case SearchState::Autorefreshing:
747bb02e0acSNicolas Bonnefon             text = tr("%1 match%2 found. Search is auto-refreshing...").arg( nbMatches )
748bb02e0acSNicolas Bonnefon                 .arg( nbMatches > 1 ? "es" : "" );
749bb02e0acSNicolas Bonnefon             break;
750bb02e0acSNicolas Bonnefon         case SearchState::FileTruncated:
751bb02e0acSNicolas Bonnefon             text = tr("File truncated on disk, previous search results are not valid anymore.");
752bb02e0acSNicolas Bonnefon             break;
753bb02e0acSNicolas Bonnefon     }
754bb02e0acSNicolas Bonnefon 
755bb02e0acSNicolas Bonnefon     searchInfoLine->setPalette( searchInfoLineDefaultPalette );
756bb02e0acSNicolas Bonnefon     searchInfoLine->setText( text );
757bb02e0acSNicolas Bonnefon }
758bb02e0acSNicolas Bonnefon 
759bb02e0acSNicolas Bonnefon //
760bb02e0acSNicolas Bonnefon // SearchState implementation
761bb02e0acSNicolas Bonnefon //
762bb02e0acSNicolas Bonnefon void CrawlerWidget::SearchState::resetState()
763bb02e0acSNicolas Bonnefon {
764bb02e0acSNicolas Bonnefon     state_ = NoSearch;
765bb02e0acSNicolas Bonnefon }
766bb02e0acSNicolas Bonnefon 
767bb02e0acSNicolas Bonnefon void CrawlerWidget::SearchState::setAutorefresh( bool refresh )
768bb02e0acSNicolas Bonnefon {
769bb02e0acSNicolas Bonnefon     autoRefreshRequested_ = refresh;
770bb02e0acSNicolas Bonnefon 
771bb02e0acSNicolas Bonnefon     if ( refresh ) {
772bb02e0acSNicolas Bonnefon         if ( state_ == Static )
773bb02e0acSNicolas Bonnefon             state_ = Autorefreshing;
774bb02e0acSNicolas Bonnefon     }
775bb02e0acSNicolas Bonnefon     else {
776bb02e0acSNicolas Bonnefon         if ( state_ == Autorefreshing )
777bb02e0acSNicolas Bonnefon             state_ = Static;
778bb02e0acSNicolas Bonnefon     }
779bb02e0acSNicolas Bonnefon }
780bb02e0acSNicolas Bonnefon 
781bb02e0acSNicolas Bonnefon void CrawlerWidget::SearchState::truncateFile()
782bb02e0acSNicolas Bonnefon {
783bb02e0acSNicolas Bonnefon     state_ = FileTruncated;
784bb02e0acSNicolas Bonnefon }
785bb02e0acSNicolas Bonnefon 
786bb02e0acSNicolas Bonnefon void CrawlerWidget::SearchState::changeExpression()
787bb02e0acSNicolas Bonnefon {
788bb02e0acSNicolas Bonnefon     if ( state_ == Autorefreshing )
789bb02e0acSNicolas Bonnefon         state_ = Static;
790bb02e0acSNicolas Bonnefon }
791bb02e0acSNicolas Bonnefon 
792bb02e0acSNicolas Bonnefon void CrawlerWidget::SearchState::stopSearch()
793bb02e0acSNicolas Bonnefon {
794bb02e0acSNicolas Bonnefon     if ( state_ == Autorefreshing )
795bb02e0acSNicolas Bonnefon         state_ = Static;
796bb02e0acSNicolas Bonnefon }
797bb02e0acSNicolas Bonnefon 
798bb02e0acSNicolas Bonnefon void CrawlerWidget::SearchState::startSearch()
799bb02e0acSNicolas Bonnefon {
800bb02e0acSNicolas Bonnefon     if ( autoRefreshRequested_ )
801bb02e0acSNicolas Bonnefon         state_ = Autorefreshing;
802bb02e0acSNicolas Bonnefon     else
803bb02e0acSNicolas Bonnefon         state_ = Static;
804bb02e0acSNicolas Bonnefon }
805