xref: /glogg/src/data/logfiltereddata.h (revision bb02e0acf44ddb4e4f83d6127a1e488789162922)
1 /*
2  * Copyright (C) 2009, 2010, 2011, 2012 Nicolas Bonnefon and other contributors
3  *
4  * This file is part of glogg.
5  *
6  * glogg is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * glogg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with glogg.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef LOGFILTEREDDATA_H
21 #define LOGFILTEREDDATA_H
22 
23 #include <QObject>
24 #include <QByteArray>
25 #include <QList>
26 #include <QVector>
27 #include <QStringList>
28 #include <QRegExp>
29 
30 #include "abstractlogdata.h"
31 #include "logfiltereddataworkerthread.h"
32 
33 class LogData;
34 class Marks;
35 
36 // A list of matches found in a LogData, it stores all the matching lines,
37 // which can be accessed using the AbstractLogData interface, together with
38 // the original line number where they were found.
39 // Constructing such objet does not start the search.
40 // This object should be constructed by a LogData.
41 class LogFilteredData : public AbstractLogData {
42   Q_OBJECT
43 
44   public:
45     // Creates an empty LogFilteredData
46     LogFilteredData();
47     // Constructor used by LogData
48     LogFilteredData( const LogData* logData );
49 
50     // Starts the async search, sending newDataAvailable() when new data found.
51     // If a search is already in progress this function will block until
52     // it is done, so the application should call interruptSearch() first.
53     void runSearch( const QRegExp& regExp );
54     // Add to the existing search, starting at the line when the search was
55     // last stopped. Used when the file on disk has been added too.
56     void updateSearch();
57     // Interrupt the running search if one is in progress.
58     // Nothing is done if no search is in progress.
59     void interruptSearch();
60     // Clear the search and the list of results.
61     void clearSearch();
62     // Returns the line number in the original LogData where the element
63     // 'index' was found.
64     qint64 getMatchingLineNumber( int index ) const;
65     // Returns whether the line number passed is in our list of matching ones.
66     bool isLineInMatchingList( qint64 lineNumber );
67 
68     // Returns the number of lines in the source log data
69     qint64 getNbTotalLines() const;
70     // Returns the number of matches (independently of the visibility)
71     int getNbMatches() const;
72     // Returns the number of marks (independently of the visibility)
73     int getNbMarks() const;
74 
75     // Returns the reason why the line at the passed index is in the filtered
76     // data.  It can be because it is either a mark or a match.
77     enum FilteredLineType { Match, Mark };
78     FilteredLineType filteredLineTypeByIndex( int index ) const;
79 
80     // Marks interface (delegated to a Marks object)
81 
82     // Add a mark at the given line, optionally identified by the given char
83     // If a mark for this char already exist, the previous one is replaced.
84     void addMark( qint64 line, QChar mark = QChar() );
85     // Get the (unique) mark identified by the passed char.
86     qint64 getMark( QChar mark ) const;
87     // Returns wheither the passed line has a mark on it.
88     bool isLineMarked( qint64 line ) const;
89     // Delete the mark identified by the passed char.
90     void deleteMark( QChar mark );
91     // Delete the mark present on the passed line or do nothing if there is
92     // none.
93     void deleteMark( qint64 line );
94     // Completely clear the marks list.
95     void clearMarks();
96 
97     // Changes what the AbstractLogData returns via its getXLines/getNbLines
98     // API.
99     enum Visibility { MatchesOnly, MarksOnly, MarksAndMatches };
100     void setVisibility( Visibility visibility );
101 
102   signals:
103     // Sent when the search has progressed, give the number of matches (so far)
104     // and the percentage of completion
105     void searchProgressed( int nbMatches, int progress );
106 
107   private slots:
108     void handleSearchProgressed( int NbMatches, int progress );
109 
110   private:
111     class FilteredItem;
112 
113     // Implementation of virtual functions
114     QString doGetLineString( qint64 line ) const;
115     QString doGetExpandedLineString( qint64 line ) const;
116     QStringList doGetLines( qint64 first, int number ) const;
117     QStringList doGetExpandedLines( qint64 first, int number ) const;
118     qint64 doGetNbLine() const;
119     int doGetMaxLength() const;
120     int doGetLineLength( qint64 line ) const;
121 
122     QList<MatchingLine> matchingLineList;
123 
124     const LogData* sourceLogData_;
125     QRegExp currentRegExp_;
126     bool searchDone_;
127     int maxLength_;
128     int maxLengthMarks_;
129     // Number of lines of the LogData that has been searched for:
130     qint64 nbLinesProcessed_;
131 
132     Visibility visibility_;
133 
134     // Cache used to combine Marks and Matches
135     // when visibility_ == MarksAndMatches
136     // (QVector store actual objects instead of pointers)
137     mutable QVector<FilteredItem> filteredItemsCache_;
138     mutable bool filteredItemsCacheDirty_;
139 
140     LogFilteredDataWorkerThread* workerThread_;
141     Marks* marks_;
142 
143     // Utility functions
144     qint64 findLogDataLine( qint64 lineNum ) const;
145     void regenerateFilteredItemsCache() const;
146 };
147 
148 // A class representing a Mark or Match.
149 // Conceptually it should be a base class for Mark and MatchingLine,
150 // but we implement it this way for performance reason as we create plenty of
151 // those everytime we refresh the cache.
152 // Specifically it allows to store this in the cache by value instead
153 // of pointer (less small allocations and no RTTI).
154 class LogFilteredData::FilteredItem {
155   public:
156     // A default ctor seems to be necessary for QVector
157     FilteredItem()
158     { lineNumber_ = 0; }
159     FilteredItem( qint64 lineNumber, FilteredLineType type )
160     { lineNumber_ = lineNumber; type_ = type; }
161 
162     qint64 lineNumber() const
163     { return lineNumber_; }
164     FilteredLineType type() const
165     { return type_; }
166 
167   private:
168     qint64 lineNumber_;
169     FilteredLineType type_;
170 };
171 
172 #endif
173