1 /* 2 * Copyright (C) 2009, 2010, 2013, 2014, 2015 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 LOGDATA_H 21 #define LOGDATA_H 22 23 #include <memory> 24 25 #include <QObject> 26 #include <QString> 27 #include <QFile> 28 #include <QVector> 29 #include <QMutex> 30 #include <QDateTime> 31 #include <QTextCodec> 32 33 #include "utils.h" 34 35 #include "abstractlogdata.h" 36 #include "logdataworkerthread.h" 37 #include "filewatcher.h" 38 #include "loadingstatus.h" 39 40 class LogFilteredData; 41 42 // Thrown when trying to attach an already attached LogData 43 class CantReattachErr {}; 44 45 // Represents a complete set of data to be displayed (ie. a log file content) 46 // This class is thread-safe. 47 class LogData : public AbstractLogData { 48 Q_OBJECT 49 50 public: 51 // Creates an empty LogData 52 LogData(); 53 // Destroy an object 54 ~LogData(); 55 56 enum MonitoredFileStatus { Unchanged, DataAdded, Truncated }; 57 58 // Attaches the LogData to a file on disk 59 // It starts the asynchronous indexing and returns (almost) immediately 60 // Attaching to a non existant file works and the file is reported 61 // to be empty. 62 // Reattaching is forbidden and will throw. 63 void attachFile( const QString& fileName ); 64 // Interrupt the loading and report a null file. 65 // Does nothing if no loading in progress. 66 void interruptLoading(); 67 // Creates a new filtered data. 68 // ownership is passed to the caller 69 LogFilteredData* getNewFilteredData() const; 70 // Returns the size if the file in bytes 71 qint64 getFileSize() const; 72 // Returns the last modification date for the file. 73 // Null if the file is not on disk. 74 QDateTime getLastModifiedDate() const; 75 // Throw away all the file data and reload/reindex. 76 void reload(); 77 78 // Update the polling interval (in ms, 0 means disabled) 79 void setPollingInterval( uint32_t interval_ms ); 80 81 // Get the auto-detected encoding for the indexed text. 82 EncodingSpeculator::Encoding getDetectedEncoding() const; 83 84 signals: 85 // Sent during the 'attach' process to signal progress 86 // percent being the percentage of completion. 87 void loadingProgressed( int percent ); 88 // Signal the client the file is fully loaded and available. 89 void loadingFinished( LoadingStatus status ); 90 // Sent when the file on disk has changed, will be followed 91 // by loadingProgressed if needed and then a loadingFinished. 92 void fileChanged( LogData::MonitoredFileStatus status ); 93 94 private slots: 95 // Consider reloading the file when it changes on disk updated 96 void fileChangedOnDisk(); 97 // Called when the worker thread signals the current operation ended 98 void indexingFinished( LoadingStatus status ); 99 100 private: 101 // This class models an indexing operation. 102 // It exists to permit LogData to delay the operation if another 103 // one is ongoing (operations are asynchronous) 104 class LogDataOperation { 105 public: 106 LogDataOperation( const QString& fileName ) : filename_( fileName ) {} 107 // Permit each child to have its destructor 108 virtual ~LogDataOperation() {}; 109 110 void start( LogDataWorkerThread& workerThread ) const 111 { doStart( workerThread ); } 112 const QString& getFilename() const { return filename_; } 113 114 protected: 115 virtual void doStart( LogDataWorkerThread& workerThread ) const = 0; 116 QString filename_; 117 }; 118 119 // Attaching a new file (change name + full index) 120 class AttachOperation : public LogDataOperation { 121 public: 122 AttachOperation( const QString& fileName ) 123 : LogDataOperation( fileName ) {} 124 ~AttachOperation() {}; 125 126 protected: 127 void doStart( LogDataWorkerThread& workerThread ) const; 128 }; 129 130 // Reindexing the current file 131 class FullIndexOperation : public LogDataOperation { 132 public: 133 FullIndexOperation() : LogDataOperation( QString() ) {} 134 ~FullIndexOperation() {}; 135 136 protected: 137 void doStart( LogDataWorkerThread& workerThread ) const; 138 }; 139 140 // Indexing part of the current file (from fileSize) 141 class PartialIndexOperation : public LogDataOperation { 142 public: 143 PartialIndexOperation() : LogDataOperation( QString() ) {} 144 ~PartialIndexOperation() {}; 145 146 protected: 147 void doStart( LogDataWorkerThread& workerThread ) const; 148 }; 149 150 std::shared_ptr<FileWatcher> fileWatcher_; 151 MonitoredFileStatus fileChangedOnDisk_; 152 153 // Implementation of virtual functions 154 QString doGetLineString( qint64 line ) const override; 155 QString doGetExpandedLineString( qint64 line ) const override; 156 QStringList doGetLines( qint64 first, int number ) const override; 157 QStringList doGetExpandedLines( qint64 first, int number ) const override; 158 qint64 doGetNbLine() const override; 159 int doGetMaxLength() const override; 160 int doGetLineLength( qint64 line ) const override; 161 void doSetDisplayEncoding( const char* encoding ) override; 162 163 void enqueueOperation( std::shared_ptr<const LogDataOperation> newOperation ); 164 void startOperation(); 165 166 QString indexingFileName_; 167 std::unique_ptr<QFile> attached_file_; 168 169 // Indexing data, read by us, written by the worker thread 170 IndexingData indexing_data_; 171 172 QDateTime lastModifiedDate_; 173 std::shared_ptr<const LogDataOperation> currentOperation_; 174 std::shared_ptr<const LogDataOperation> nextOperation_; 175 176 // Codec to decode text 177 QTextCodec* codec_; 178 179 // To protect the file: 180 mutable QMutex fileMutex_; 181 // (are mutable to allow 'const' function to touch it, 182 // while remaining const) 183 // When acquiring both, data should be help before locking file. 184 185 LogDataWorkerThread workerThread_; 186 }; 187 188 Q_DECLARE_METATYPE( LogData::MonitoredFileStatus ); 189 190 #endif 191