xref: /glogg/src/data/logfiltereddata.h (revision f869e41d2c129cd0f2f3eccb5e9d0d80a5998201)
1 /*
2  * Copyright (C) 2009, 2010, 2011, 2012, 2017 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 <memory>
24 
25 #include <QObject>
26 #include <QByteArray>
27 #include <QList>
28 #include <QStringList>
29 #include <QRegularExpression>
30 
31 #include "abstractlogdata.h"
32 #include "logfiltereddataworkerthread.h"
33 #include "marks.h"
34 
35 class LogData;
36 class Marks;
37 
38 // A list of matches found in a LogData, it stores all the matching lines,
39 // which can be accessed using the AbstractLogData interface, together with
40 // the original line number where they were found.
41 // Constructing such objet does not start the search.
42 // This object should be constructed by a LogData.
43 class LogFilteredData : public AbstractLogData {
44   Q_OBJECT
45 
46   public:
47     // Creates an empty LogFilteredData
48     LogFilteredData();
49     // Constructor used by LogData
50     LogFilteredData( const LogData* logData );
51 
52     ~LogFilteredData();
53 
54     // Starts the async search, sending newDataAvailable() when new data found.
55     // If a search is already in progress this function will block until
56     // it is done, so the application should call interruptSearch() first.
57     void runSearch(const QRegularExpression &regExp );
58     // Add to the existing search, starting at the line when the search was
59     // last stopped. Used when the file on disk has been added too.
60     void updateSearch();
61     // Interrupt the running search if one is in progress.
62     // Nothing is done if no search is in progress.
63     void interruptSearch();
64     // Clear the search and the list of results.
65     void clearSearch();
66     // Returns the line number in the original LogData where the element
67     // 'index' was found.
68     qint64 getMatchingLineNumber( int index ) const;
69     // Returns whether the line number passed is in our list of matching ones.
70     bool isLineInMatchingList( qint64 lineNumber );
71 
72     // Returns the line 'index' in filterd log data that matches
73     // given original line number
74     int getLineIndexNumber( quint64 lineNumber ) const;
75 
76     // Returns the number of lines in the source log data
77     LineNumber getNbTotalLines() const;
78     // Returns the number of matches (independently of the visibility)
79     LineNumber getNbMatches() const;
80     // Returns the number of marks (independently of the visibility)
81     LineNumber getNbMarks() const;
82 
83     // Returns the reason why the line at the passed index is in the filtered
84     // data.  It can be because it is either a mark or a match.
85     enum FilteredLineType { Match, Mark };
86     FilteredLineType filteredLineTypeByIndex( int index ) const;
87 
88     // Marks interface (delegated to a Marks object)
89 
90     // Add a mark at the given line, optionally identified by the given char
91     // If a mark for this char already exist, the previous one is replaced.
92     void addMark( qint64 line, QChar mark = QChar() );
93     // Get the (unique) mark identified by the passed char.
94     qint64 getMark( QChar mark ) const;
95     // Returns wheither the passed line has a mark on it.
96     bool isLineMarked( qint64 line ) const;
97     // Get the first mark after the line passed (-1 if none)
98     qint64 getMarkAfter( qint64 line ) const;
99     // Get the first mark before the line passed (-1 if none)
100     qint64 getMarkBefore( qint64 line ) const;
101     // Delete the mark identified by the passed char.
102     void deleteMark( QChar mark );
103     // Delete the mark present on the passed line or do nothing if there is
104     // none.
105     void deleteMark( qint64 line );
106     // Completely clear the marks list.
107     void clearMarks();
108 
109     // Changes what the AbstractLogData returns via its getXLines/getNbLines
110     // API.
111     enum Visibility { MatchesOnly, MarksOnly, MarksAndMatches };
112     void setVisibility( Visibility visibility );
113 
114   signals:
115     // Sent when the search has progressed, give the number of matches (so far)
116     // and the percentage of completion
117     // Also include the initial position to allow the client to distinguish
118     // between full and partial searches
119     void searchProgressed( int nbMatches, int progress, qint64 initial_position );
120 
121   private slots:
122     void handleSearchProgressed( int NbMatches, int progress, qint64 initial_position );
123 
124   private:
125     class FilteredItem;
126 
127     // Implementation of virtual functions
128     QString doGetLineString( qint64 line ) const;
129     QString doGetExpandedLineString( qint64 line ) const;
130     QStringList doGetLines( qint64 first, int number ) const;
131     QStringList doGetExpandedLines( qint64 first, int number ) const;
132     qint64 doGetNbLine() const;
133     int doGetMaxLength() const;
134     int doGetLineLength( qint64 line ) const;
135     void doSetDisplayEncoding( Encoding encoding );
136     void doSetMultibyteEncodingOffsets( int before_cr, int after_cr ) override;
137 
138     // List of the matching line numbers
139     SearchResultArray matching_lines_;
140 
141     const LogData* sourceLogData_;
142     QRegularExpression currentRegExp_;
143     bool searchDone_;
144     int maxLength_;
145     int maxLengthMarks_;
146     // Number of lines of the LogData that has been searched for:
147     qint64 nbLinesProcessed_;
148 
149     Visibility visibility_;
150 
151     // Cache used to combine Marks and Matches
152     // when visibility_ == MarksAndMatches
153     // (QVector store actual objects instead of pointers)
154     mutable std::vector<FilteredItem> filteredItemsCache_;
155     mutable bool filteredItemsCacheDirty_;
156 
157     LogFilteredDataWorkerThread workerThread_;
158     Marks marks_;
159 
160     // Utility functions
161     LineNumber findLogDataLine( LineNumber lineNum ) const;
162     LineNumber findFilteredLine( LineNumber lineNum ) const;
163 
164     void regenerateFilteredItemsCache() const;
165 };
166 
167 // A class representing a Mark or Match.
168 // Conceptually it should be a base class for Mark and MatchingLine,
169 // but we implement it this way for performance reason as we create plenty of
170 // those everytime we refresh the cache.
171 // Specifically it allows to store this in the cache by value instead
172 // of pointer (less small allocations and no RTTI).
173 class LogFilteredData::FilteredItem {
174   public:
175     // A default ctor seems to be necessary for QVector
176     FilteredItem()
177     { lineNumber_ = 0; }
178     FilteredItem( LineNumber lineNumber, FilteredLineType type )
179     { lineNumber_ = lineNumber; type_ = type; }
180 
181     LineNumber lineNumber() const
182     { return lineNumber_; }
183     FilteredLineType type() const
184     { return type_; }
185 
186     bool operator <( const LogFilteredData::FilteredItem& other ) const
187     { return lineNumber_ < other.lineNumber_; }
188 
189     bool operator <( const LineNumber& lineNumber ) const
190     { return lineNumber_ < lineNumber; }
191 
192   private:
193     LineNumber lineNumber_;
194     FilteredLineType type_;
195 };
196 
197 #endif
198