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 ®Exp ); 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 void searchProgressed( int nbMatches, int progress ); 118 119 private slots: 120 void handleSearchProgressed( int NbMatches, int progress ); 121 122 private: 123 class FilteredItem; 124 125 // Implementation of virtual functions 126 QString doGetLineString( qint64 line ) const; 127 QString doGetExpandedLineString( qint64 line ) const; 128 QStringList doGetLines( qint64 first, int number ) const; 129 QStringList doGetExpandedLines( qint64 first, int number ) const; 130 qint64 doGetNbLine() const; 131 int doGetMaxLength() const; 132 int doGetLineLength( qint64 line ) const; 133 void doSetDisplayEncoding( Encoding encoding ); 134 void doSetMultibyteEncodingOffsets( int before_cr, int after_cr ) override; 135 136 // List of the matching line numbers 137 SearchResultArray matching_lines_; 138 139 const LogData* sourceLogData_; 140 QRegularExpression currentRegExp_; 141 bool searchDone_; 142 int maxLength_; 143 int maxLengthMarks_; 144 // Number of lines of the LogData that has been searched for: 145 qint64 nbLinesProcessed_; 146 147 Visibility visibility_; 148 149 // Cache used to combine Marks and Matches 150 // when visibility_ == MarksAndMatches 151 // (QVector store actual objects instead of pointers) 152 mutable std::vector<FilteredItem> filteredItemsCache_; 153 mutable bool filteredItemsCacheDirty_; 154 155 LogFilteredDataWorkerThread workerThread_; 156 Marks marks_; 157 158 // Utility functions 159 LineNumber findLogDataLine( LineNumber lineNum ) const; 160 LineNumber findFilteredLine( LineNumber lineNum ) const; 161 162 void regenerateFilteredItemsCache() const; 163 }; 164 165 // A class representing a Mark or Match. 166 // Conceptually it should be a base class for Mark and MatchingLine, 167 // but we implement it this way for performance reason as we create plenty of 168 // those everytime we refresh the cache. 169 // Specifically it allows to store this in the cache by value instead 170 // of pointer (less small allocations and no RTTI). 171 class LogFilteredData::FilteredItem { 172 public: 173 // A default ctor seems to be necessary for QVector 174 FilteredItem() 175 { lineNumber_ = 0; } 176 FilteredItem( LineNumber lineNumber, FilteredLineType type ) 177 { lineNumber_ = lineNumber; type_ = type; } 178 179 LineNumber lineNumber() const 180 { return lineNumber_; } 181 FilteredLineType type() const 182 { return type_; } 183 184 bool operator <( const LogFilteredData::FilteredItem& other ) const 185 { return lineNumber_ < other.lineNumber_; } 186 187 bool operator <( const LineNumber& lineNumber ) const 188 { return lineNumber_ < lineNumber; } 189 190 private: 191 LineNumber lineNumber_; 192 FilteredLineType type_; 193 }; 194 195 #endif 196