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