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