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