File: logfiltereddata.cpp

package info (click to toggle)
glogg 0.9.0-1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 832 kB
  • sloc: cpp: 6,649; sh: 66; perl: 32; sed: 25; makefile: 11
file content (404 lines) | stat: -rw-r--r-- 11,191 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
/*
 * Copyright (C) 2009, 2010, 2011, 2012 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 <http://www.gnu.org/licenses/>.
 */

// This file implements LogFilteredData
// It stores a pointer to the LogData that created it,
// so should always be destroyed before the LogData.

#include "log.h"

#include <QString>
#include <cassert>
#include <limits>

#include "utils.h"
#include "logdata.h"
#include "marks.h"
#include "logfiltereddata.h"

// Creates an empty set. It must be possible to display it without error.
// FIXME
LogFilteredData::LogFilteredData() : AbstractLogData()
{
    matchingLineList = QList<MatchingLine>();
    /* Prevent any more searching */
    maxLength_ = 0;
    maxLengthMarks_ = 0;
    searchDone_ = true;
    visibility_ = MarksAndMatches;

    workerThread_ = new LogFilteredDataWorkerThread( NULL );
    marks_ = new Marks();
}

// Usual constructor: just copy the data, the search is started by runSearch()
LogFilteredData::LogFilteredData( const LogData* logData )
    : AbstractLogData(), currentRegExp_()
{
    // Starts with an empty result list
    matchingLineList = SearchResultArray();
    maxLength_ = 0;
    maxLengthMarks_ = 0;
    nbLinesProcessed_ = 0;

    sourceLogData_ = logData;

    searchDone_ = false;

    visibility_ = MarksAndMatches;

    workerThread_ = new LogFilteredDataWorkerThread( logData );
    marks_ = new Marks();
    //
    // Forward the update signal
    connect( workerThread_, SIGNAL( searchProgressed( int, int ) ),
            this, SLOT( handleSearchProgressed( int, int ) ) );

    // Starts the worker thread
    workerThread_->start();
}

//
// Public functions
//

// Run the search and send newDataAvailable() signals.
void LogFilteredData::runSearch( const QRegExp& regExp )
{
    LOG(logDEBUG) << "Entering runSearch";

    // Reset the search
    currentRegExp_ = regExp;
    matchingLineList.clear();
    maxLength_ = 0;
    maxLengthMarks_ = 0;

    workerThread_->search( currentRegExp_ );
}

void LogFilteredData::updateSearch()
{
    LOG(logDEBUG) << "Entering updateSearch";

    workerThread_->updateSearch( currentRegExp_, nbLinesProcessed_ );
}

void LogFilteredData::interruptSearch()
{
    LOG(logDEBUG) << "Entering interruptSearch";

    workerThread_->interrupt();
}

void LogFilteredData::clearSearch()
{
    currentRegExp_ = QRegExp();
    matchingLineList.clear();
    maxLength_ = 0;
    filteredItemsCacheDirty_ = true;
}

qint64 LogFilteredData::getMatchingLineNumber( int matchNum ) const
{
    qint64 matchingLine = findLogDataLine( matchNum );

    return matchingLine;
}

// Scan the list for the 'lineNumber' passed
bool LogFilteredData::isLineInMatchingList( qint64 lineNumber )
{
    int index;                                    // Not used
    return lookupLineNumber<SearchResultArray>(
            matchingLineList, lineNumber, &index);
}


int LogFilteredData::getNbMatches() const
{
    return matchingLineList.size();
}

int LogFilteredData::getNbMarks() const
{
    return marks_->size();
}

LogFilteredData::FilteredLineType
    LogFilteredData::filteredLineTypeByIndex( int index ) const
{
    // If we are only showing one type, the line is there because
    // it is of this type.
    if ( visibility_ == MatchesOnly )
        return Match;
    else if ( visibility_ == MarksOnly )
        return Mark;
    else {
        // If it is MarksAndMatches, we have to look.
        // Regenerate the cache if needed
        if ( filteredItemsCacheDirty_ )
            regenerateFilteredItemsCache();

        return filteredItemsCache_[ index ].type();
    }
}

// Delegation to our Marks object

void LogFilteredData::addMark( qint64 line, QChar mark )
{
    assert( marks_ );

    if ( ( line >= 0 ) && ( line < sourceLogData_->getNbLine() ) ) {
        marks_->addMark( line, mark );
        maxLengthMarks_ = qMax( maxLengthMarks_,
                sourceLogData_->getLineLength( line ) );
        filteredItemsCacheDirty_ = true;
    }
    else
        LOG(logERROR) << "LogFilteredData::addMark\
 trying to create a mark outside of the file.";
}

qint64 LogFilteredData::getMark( QChar mark ) const
{
    assert( marks_ );

    return marks_->getMark( mark );
}

bool LogFilteredData::isLineMarked( qint64 line ) const
{
    assert( marks_ );

    return marks_->isLineMarked( line );
}

void LogFilteredData::deleteMark( QChar mark )
{
    assert( marks_ );

    marks_->deleteMark( mark );
    filteredItemsCacheDirty_ = true;

    // FIXME: maxLengthMarks_
}

void LogFilteredData::deleteMark( qint64 line )
{
    assert( marks_ );

    marks_->deleteMark( line );
    filteredItemsCacheDirty_ = true;

    // Now update the max length if needed
    if ( sourceLogData_->getLineLength( line ) >= maxLengthMarks_ ) {
        LOG(logDEBUG) << "deleteMark recalculating longest mark";
        maxLengthMarks_ = 0;
        for ( Marks::const_iterator i = marks_->begin();
                i != marks_->end(); ++i ) {
            LOG(logDEBUG) << "line " << i->lineNumber();
            maxLengthMarks_ = qMax( maxLengthMarks_,
                    sourceLogData_->getLineLength( i->lineNumber() ) );
        }
    }
}

void LogFilteredData::clearMarks()
{
    assert( marks_ );

    marks_->clear();
    filteredItemsCacheDirty_ = true;
    maxLengthMarks_ = 0;
}

void LogFilteredData::setVisibility( Visibility visi )
{
    visibility_ = visi;
}

//
// Slots
//
void LogFilteredData::handleSearchProgressed( int nbMatches, int progress )
{
    LOG(logDEBUG) << "LogFilteredData::handleSearchProgressed matches="
        << nbMatches << " progress=" << progress;

    // searchDone_ = true;
    workerThread_->getSearchResult( &maxLength_, &matchingLineList, &nbLinesProcessed_ );
    filteredItemsCacheDirty_ = true;

    emit searchProgressed( nbMatches, progress );
}

qint64 LogFilteredData::findLogDataLine( qint64 lineNum ) const
{
    qint64 line = 0;
    if ( visibility_ == MatchesOnly ) {
        if ( lineNum < matchingLineList.size() ) {
            line = matchingLineList[lineNum].lineNumber();
        }
        else {
            LOG(logERROR) << "Index too big in LogFilteredData: " << lineNum;
        }
    }
    else if ( visibility_ == MarksOnly ) {
        if ( lineNum < marks_->size() )
            line = marks_->getLineMarkedByIndex( lineNum );
        else
            LOG(logERROR) << "Index too big in LogFilteredData: " << lineNum;
    }
    else {
        // Regenerate the cache if needed
        if ( filteredItemsCacheDirty_ )
            regenerateFilteredItemsCache();

        if ( lineNum < filteredItemsCache_.size() )
            line = filteredItemsCache_[ lineNum ].lineNumber();
        else
            LOG(logERROR) << "Index too big in LogFilteredData: " << lineNum;
    }

    return line;
}

// Implementation of the virtual function.
QString LogFilteredData::doGetLineString( qint64 lineNum ) const
{
    qint64 line = findLogDataLine( lineNum );

    QString string = sourceLogData_->getLineString( line );
    return string;
}

// Implementation of the virtual function.
QString LogFilteredData::doGetExpandedLineString( qint64 lineNum ) const
{
    qint64 line = findLogDataLine( lineNum );

    QString string = sourceLogData_->getExpandedLineString( line );
    return string;
}

// Implementation of the virtual function.
QStringList LogFilteredData::doGetLines( qint64 first_line, int number ) const
{
    QStringList list;

    for ( int i = first_line; i < first_line + number; i++ ) {
        list.append( doGetLineString( i ) );
    }

    return list;
}

// Implementation of the virtual function.
QStringList LogFilteredData::doGetExpandedLines( qint64 first_line, int number ) const
{
    QStringList list;

    for ( int i = first_line; i < first_line + number; i++ ) {
        list.append( doGetExpandedLineString( i ) );
    }

    return list;
}

// Implementation of the virtual function.
qint64 LogFilteredData::doGetNbLine() const
{
    qint64 nbLines;

    if ( visibility_ == MatchesOnly )
        nbLines = matchingLineList.size();
    else if ( visibility_ == MarksOnly )
        nbLines = marks_->size();
    else {
        // Regenerate the cache if needed
        if ( filteredItemsCacheDirty_ )
            regenerateFilteredItemsCache();
        nbLines = filteredItemsCache_.size();
    }

    return nbLines;
}

// Implementation of the virtual function.
int LogFilteredData::doGetMaxLength() const
{
    int max_length;

    if ( visibility_ == MatchesOnly )
        max_length = maxLength_;
    else if ( visibility_ == MarksOnly )
        max_length = maxLengthMarks_;
    else
        max_length = qMax( maxLength_, maxLengthMarks_ );

    return max_length;
}

// Implementation of the virtual function.
int LogFilteredData::doGetLineLength( qint64 lineNum ) const
{
    qint64 line = findLogDataLine( lineNum );
    return sourceLogData_->getExpandedLineString( line ).length();
}

// TODO: We might be a bit smarter and not regenerate the whole thing when
// e.g. stuff is added at the end of the search.
void LogFilteredData::regenerateFilteredItemsCache() const
{
    LOG(logDEBUG) << "regenerateFilteredItemsCache";

    filteredItemsCache_.clear();
    filteredItemsCache_.reserve( matchingLineList.size() + marks_->size() );
    // (it's an overestimate but probably not by much so it's fine)

    QList<MatchingLine>::const_iterator i = matchingLineList.begin();
    Marks::const_iterator j = marks_->begin();

    while ( ( i != matchingLineList.end() ) || ( j != marks_->end() ) ) {
        qint64 next_mark =
            ( j != marks_->end() ) ? j->lineNumber() : std::numeric_limits<qint64>::max();
        qint64 next_match =
            ( i != matchingLineList.end() ) ? i->lineNumber() : std::numeric_limits<qint64>::max();
        // We choose a Mark over a Match if a line is both, just an arbitrary choice really.
        if ( next_mark <= next_match ) {
            // LOG(logDEBUG) << "Add mark at " << next_mark;
            filteredItemsCache_.append( FilteredItem( next_mark, Mark ) );
            if ( j != marks_->end() )
                ++j;
            if ( ( next_mark == next_match ) && ( i != matchingLineList.end() ) )
                ++i;  // Case when it's both match and mark.
        }
        else {
            // LOG(logDEBUG) << "Add match at " << next_match;
            filteredItemsCache_.append( FilteredItem( next_match, Match ) );
            if ( i != matchingLineList.end() )
                ++i;
        }
    }

    filteredItemsCacheDirty_ = false;

    LOG(logDEBUG) << "finished regenerateFilteredItemsCache";
}