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