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 number of lines in the source log data 73 LineNumber getNbTotalLines() const; 74 // Returns the number of matches (independently of the visibility) 75 LineNumber getNbMatches() const; 76 // Returns the number of marks (independently of the visibility) 77 LineNumber getNbMarks() const; 78 79 // Returns the reason why the line at the passed index is in the filtered 80 // data. It can be because it is either a mark or a match. 81 enum FilteredLineType { Match, Mark }; 82 FilteredLineType filteredLineTypeByIndex( int index ) const; 83 84 // Marks interface (delegated to a Marks object) 85 86 // Add a mark at the given line, optionally identified by the given char 87 // If a mark for this char already exist, the previous one is replaced. 88 void addMark( qint64 line, QChar mark = QChar() ); 89 // Get the (unique) mark identified by the passed char. 90 qint64 getMark( QChar mark ) const; 91 // Returns wheither the passed line has a mark on it. 92 bool isLineMarked( qint64 line ) const; 93 // Get the first mark after the line passed (-1 if none) 94 qint64 getMarkAfter( qint64 line ) const; 95 // Get the first mark before the line passed (-1 if none) 96 qint64 getMarkBefore( qint64 line ) const; 97 // Delete the mark identified by the passed char. 98 void deleteMark( QChar mark ); 99 // Delete the mark present on the passed line or do nothing if there is 100 // none. 101 void deleteMark( qint64 line ); 102 // Completely clear the marks list. 103 void clearMarks(); 104 105 // Changes what the AbstractLogData returns via its getXLines/getNbLines 106 // API. 107 enum Visibility { MatchesOnly, MarksOnly, MarksAndMatches }; 108 void setVisibility( Visibility visibility ); 109 110 signals: 111 // Sent when the search has progressed, give the number of matches (so far) 112 // and the percentage of completion 113 void searchProgressed( int nbMatches, int progress ); 114 115 private slots: 116 void handleSearchProgressed( int NbMatches, int progress ); 117 118 private: 119 class FilteredItem; 120 121 // Implementation of virtual functions 122 QString doGetLineString( qint64 line ) const; 123 QString doGetExpandedLineString( qint64 line ) const; 124 QStringList doGetLines( qint64 first, int number ) const; 125 QStringList doGetExpandedLines( qint64 first, int number ) const; 126 qint64 doGetNbLine() const; 127 int doGetMaxLength() const; 128 int doGetLineLength( qint64 line ) const; 129 void doSetDisplayEncoding( Encoding encoding ); 130 void doSetMultibyteEncodingOffsets( int before_cr, int after_cr ) override; 131 132 // List of the matching line numbers 133 SearchResultArray matching_lines_; 134 135 const LogData* sourceLogData_; 136 QRegularExpression currentRegExp_; 137 bool searchDone_; 138 int maxLength_; 139 int maxLengthMarks_; 140 // Number of lines of the LogData that has been searched for: 141 qint64 nbLinesProcessed_; 142 143 Visibility visibility_; 144 145 // Cache used to combine Marks and Matches 146 // when visibility_ == MarksAndMatches 147 // (QVector store actual objects instead of pointers) 148 mutable std::vector<FilteredItem> filteredItemsCache_; 149 mutable bool filteredItemsCacheDirty_; 150 151 LogFilteredDataWorkerThread workerThread_; 152 Marks marks_; 153 154 // Utility functions 155 LineNumber findLogDataLine( LineNumber lineNum ) const; 156 void regenerateFilteredItemsCache() const; 157 }; 158 159 // A class representing a Mark or Match. 160 // Conceptually it should be a base class for Mark and MatchingLine, 161 // but we implement it this way for performance reason as we create plenty of 162 // those everytime we refresh the cache. 163 // Specifically it allows to store this in the cache by value instead 164 // of pointer (less small allocations and no RTTI). 165 class LogFilteredData::FilteredItem { 166 public: 167 // A default ctor seems to be necessary for QVector 168 FilteredItem() 169 { lineNumber_ = 0; } 170 FilteredItem( LineNumber lineNumber, FilteredLineType type ) 171 { lineNumber_ = lineNumber; type_ = type; } 172 173 LineNumber lineNumber() const 174 { return lineNumber_; } 175 FilteredLineType type() const 176 { return type_; } 177 178 private: 179 LineNumber lineNumber_; 180 FilteredLineType type_; 181 }; 182 183 #endif 184