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