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 // 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