]> git.lyx.org Git - lyx.git/blob - src/support/FileMonitor.cpp
bdd6444ff677e6aa0f0f2759e7240e3d94e692d3
[lyx.git] / src / support / FileMonitor.cpp
1 /**
2  * \file FileMonitor.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Angus Leeming
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "support/FileMonitor.h"
14
15 #include "support/FileName.h"
16 #include "support/Timeout.h"
17
18 #include "support/bind.h"
19 #include <boost/signals2/trackable.hpp>
20
21 using namespace std;
22
23 namespace lyx {
24 namespace support {
25
26 class FileMonitor::Impl : public boost::signals2::trackable {
27 public:
28
29         ///
30         Impl(FileName const & file_with_path, int interval);
31
32         ///
33         void monitorFile();
34
35         ///
36         FileName filename_;
37
38         ///
39         Timeout timer_;
40
41         /// This signal is emitted if the file is modified (has a new checksum).
42         FileMonitor::FileChangedSig fileChanged_;
43
44         /** We use these to ascertain whether a file (once loaded successfully)
45          *  has changed.
46          */
47         time_t timestamp_;
48         ///
49         unsigned long checksum_;
50 };
51
52
53 FileMonitor::FileMonitor(FileName const & file_with_path, int interval)
54         : pimpl_(new Impl(file_with_path, interval))
55 {}
56
57
58 FileMonitor::~FileMonitor()
59 {
60         delete pimpl_;
61 }
62
63
64 void FileMonitor::reset(FileName const & file_with_path) const
65 {
66         if (pimpl_->filename_ == file_with_path)
67                 return;
68
69         bool const monitor = pimpl_->timer_.running();
70         if (monitor)
71                 stop();
72
73         pimpl_->filename_ = file_with_path;
74
75         if (monitor)
76                 start();
77 }
78
79
80 FileName const & FileMonitor::filename() const
81 {
82         return pimpl_->filename_;
83 }
84
85
86 void FileMonitor::start() const
87 {
88         if (monitoring())
89                 return;
90
91         if (!pimpl_->filename_.exists())
92                 return;
93
94         pimpl_->timestamp_ = pimpl_->filename_.lastModified();
95         pimpl_->checksum_ = pimpl_->filename_.checksum();
96
97         if (pimpl_->timestamp_ && pimpl_->checksum_) {
98                 pimpl_->timer_.start();
99         } else {
100                 pimpl_->timestamp_ = 0;
101                 pimpl_->checksum_ = 0;
102         }
103 }
104
105
106 void FileMonitor::stop() const
107 {
108         pimpl_->timestamp_ = 0;
109         pimpl_->checksum_ = 0;
110         pimpl_->timer_.stop();
111 }
112
113
114 bool FileMonitor::monitoring() const
115 {
116         return pimpl_->timer_.running();
117 }
118
119
120 unsigned long FileMonitor::checksum() const
121 {
122         // If we aren't actively monitoring the file, then recompute the
123         // checksum explicitly.
124         if (!pimpl_->timer_.running() && !pimpl_->filename_.empty())
125                 return pimpl_->filename_.checksum();
126
127         return pimpl_->checksum_;
128 }
129
130
131 boost::signals2::connection FileMonitor::connect(slot_type const & slot) const
132 {
133         return pimpl_->fileChanged_.connect(slot);
134 }
135
136
137 //------------------------------
138 // Implementation details follow
139 //------------------------------
140
141
142 FileMonitor::Impl::Impl(FileName const & file_with_path, int interval)
143         : filename_(file_with_path),
144           timer_(interval, Timeout::ONETIME),
145           timestamp_(0),
146           checksum_(0)
147 {
148         timer_.timeout.connect(bind(&Impl::monitorFile, this));
149 }
150
151
152 void FileMonitor::Impl::monitorFile()
153 {
154         bool changed = false;
155
156         if (!filename_.exists()) {
157                 changed = timestamp_ || checksum_;
158                 timestamp_ = 0;
159                 checksum_ = 0;
160
161         } else {
162                 time_t const new_timestamp = filename_.lastModified();
163
164                 if (new_timestamp != timestamp_) {
165                         timestamp_ = new_timestamp;
166
167                         unsigned long const new_checksum = filename_.checksum();
168                         if (new_checksum != checksum_) {
169                                 checksum_ = new_checksum;
170                                 changed = true;
171                         }
172                 }
173         }
174
175         timer_.start();
176         if (changed)
177                 fileChanged_();
178 }
179
180 } // namespace support
181 } // namespace lyx