blob: 13b1c7d606431b0093a962b576150d942565518a [file] [log] [blame]
jareda9541812013-01-09 00:08:46 -08001#include "filesystemwatcher.h"
2#include "ui_filesystemwatcher.h"
3
Jared Lindblom4d1d00a2013-01-11 01:14:23 -08004FileSystemWatcher::FileSystemWatcher(QString dirPath, QWidget *parent) :
jareda9541812013-01-09 00:08:46 -08005 QMainWindow(parent),
Jared Lindblom4d1d00a2013-01-11 01:14:23 -08006 m_ui(new Ui::FileSystemWatcher),
jareda9541812013-01-09 00:08:46 -08007 m_watcher(new QFileSystemWatcher()),
8 m_listViewModel(new QStringListModel()),
9 m_listView(new QListView()),
Jared Lindbloma9996302013-01-12 00:25:16 -080010 m_timer(new QTimer(this)),
jareda9541812013-01-09 00:08:46 -080011 m_dirPath(dirPath)
12{
13 // setup user interface
14 m_ui->setupUi(this);
15
16 // add main directory to monitor
17 m_watcher->addPath(m_dirPath);
18
19 // create the view
20 m_listView->setModel(m_listViewModel);
21 setCentralWidget(m_listView);
22
23 // set title
24 setWindowTitle("ChronoShare");
25
26 // register signals (callback functions)
Jared Lindblomf8d32ad2013-01-12 11:32:27 -080027 connect(m_watcher, SIGNAL(directoryChanged(QString)), this, SLOT(watcherCallbackSlot(QString)));
28 connect(m_timer, SIGNAL(timeout()), this, SLOT(timerCallbackSlot()));
jareda9541812013-01-09 00:08:46 -080029
Jared Lindbloma9996302013-01-12 00:25:16 -080030 // bootstrap
Jared Lindblomf8d32ad2013-01-12 11:32:27 -080031 timerCallbackSlot();
Jared Lindbloma9996302013-01-12 00:25:16 -080032
33 // start timer
Jared Lindblom8278b982013-01-12 15:45:09 -080034 m_timer->start(300000);
jareda9541812013-01-09 00:08:46 -080035}
36
Jared Lindblom4d1d00a2013-01-11 01:14:23 -080037FileSystemWatcher::~FileSystemWatcher()
jareda9541812013-01-09 00:08:46 -080038{
39 // clean up
40 delete m_ui;
41 delete m_watcher;
42 delete m_listViewModel;
43 delete m_listView;
Jared Lindbloma9996302013-01-12 00:25:16 -080044 delete m_timer;
jareda9541812013-01-09 00:08:46 -080045}
46
Jared Lindblomf8d32ad2013-01-12 11:32:27 -080047void FileSystemWatcher::watcherCallbackSlot(QString dirPath)
48{
49 // watcher specific steps
Jared Lindblomc1259722013-01-12 16:47:32 -080050#if DEBUG
Jared Lindblomf8d32ad2013-01-12 11:32:27 -080051 qDebug() << endl << "[WATCHER] Triggered Path: " << dirPath;
Jared Lindblomc1259722013-01-12 16:47:32 -080052#endif
Jared Lindblomf8d32ad2013-01-12 11:32:27 -080053 handleCallback(dirPath);
54}
55
56void FileSystemWatcher::timerCallbackSlot()
57{
58 // timer specific steps
Jared Lindblomc1259722013-01-12 16:47:32 -080059#if DEBUG
Jared Lindblomf8d32ad2013-01-12 11:32:27 -080060 qDebug() << endl << "[TIMER] Triggered Path: " << m_dirPath;
Jared Lindblomc1259722013-01-12 16:47:32 -080061#endif
Jared Lindblomf8d32ad2013-01-12 11:32:27 -080062 handleCallback(m_dirPath);
63}
64
65void FileSystemWatcher::handleCallback(QString dirPath)
jareda9541812013-01-09 00:08:46 -080066{
Jared Lindblom4d1d00a2013-01-11 01:14:23 -080067 // scan directory and populate file list
Jared Lindblom8278b982013-01-12 15:45:09 -080068 QHash<QString, qint64> currentState = scanDirectory(dirPath);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -080069
Jared Lindblom264310d2013-01-12 01:18:58 -080070 // reconcile directory and report changes
Jared Lindblomc1259722013-01-12 16:47:32 -080071 std::vector<sEventInfo> dirChanges = reconcileDirectory(currentState, dirPath);
Jared Lindbloma9996302013-01-12 00:25:16 -080072
Jared Lindblomc1259722013-01-12 16:47:32 -080073 emit dirEventSignal(dirChanges);
74
75#if DEBUG
76 // DEBUG: Print Changes
77 printChanges(dirChanges);
78#endif
jareda9541812013-01-09 00:08:46 -080079}
80
Jared Lindblom8278b982013-01-12 15:45:09 -080081QHash<QString, qint64> FileSystemWatcher::scanDirectory(QString dirPath)
Jared Lindbloma9996302013-01-12 00:25:16 -080082{
jareda9541812013-01-09 00:08:46 -080083 // list of files in directory
Jared Lindblom8278b982013-01-12 15:45:09 -080084 QHash<QString, qint64> currentState;
jareda9541812013-01-09 00:08:46 -080085
86 // directory iterator (recursive)
Jared Lindblom4d1d00a2013-01-11 01:14:23 -080087 QDirIterator dirIterator(dirPath, QDirIterator::Subdirectories |
jareda9541812013-01-09 00:08:46 -080088 QDirIterator::FollowSymlinks);
89
90 // iterate through directory recursively
91 while(dirIterator.hasNext())
92 {
93 // Get Next File/Dir
94 dirIterator.next();
95
96 // Get FileInfo
97 QFileInfo fileInfo = dirIterator.fileInfo();
98
99 // if not this directory or previous directory
100 if(fileInfo.absoluteFilePath() != ".." && fileInfo.absoluteFilePath() != ".")
101 {
Jared Lindbloma9996302013-01-12 00:25:16 -0800102 QString absFilePath = fileInfo.absoluteFilePath();
103
jareda9541812013-01-09 00:08:46 -0800104 // if this is a directory
105 if(fileInfo.isDir())
106 {
107 QStringList dirList = m_watcher->directories();
108
109 // if the directory is not already being watched
Jared Lindbloma9996302013-01-12 00:25:16 -0800110 if (absFilePath.startsWith(m_dirPath) && !dirList.contains(absFilePath))
jareda9541812013-01-09 00:08:46 -0800111 {
112 // add this directory to the watch list
Jared Lindbloma9996302013-01-12 00:25:16 -0800113 m_watcher->addPath(absFilePath);
jareda9541812013-01-09 00:08:46 -0800114 }
115 }
116 else
117 {
118 // add this file to the file list
Jared Lindblom8278b982013-01-12 15:45:09 -0800119 currentState.insert(absFilePath, fileInfo.created().toMSecsSinceEpoch());
jareda9541812013-01-09 00:08:46 -0800120 }
121 }
122 }
123
Jared Lindbloma9996302013-01-12 00:25:16 -0800124 return currentState;
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800125}
126
Jared Lindblomc1259722013-01-12 16:47:32 -0800127std::vector<sEventInfo> FileSystemWatcher::reconcileDirectory(QHash<QString, qint64> currentState, QString dirPath)
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800128{
Jared Lindbloma9996302013-01-12 00:25:16 -0800129 // list of files changed
Jared Lindblomc1259722013-01-12 16:47:32 -0800130 std::vector<sEventInfo> dirChanges;
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800131
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800132 // compare result (database/stored snapshot) to fileList (current snapshot)
Jared Lindblom8278b982013-01-12 15:45:09 -0800133 QMutableHashIterator<QString, qint64> i(m_storedState);
Jared Lindblom264310d2013-01-12 01:18:58 -0800134
Jared Lindbloma9996302013-01-12 00:25:16 -0800135 while(i.hasNext())
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800136 {
Jared Lindbloma9996302013-01-12 00:25:16 -0800137 i.next();
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800138
Jared Lindbloma9996302013-01-12 00:25:16 -0800139 QString absFilePath = i.key();
Jared Lindblom8278b982013-01-12 15:45:09 -0800140 qint64 storedCreated = i.value();
Jared Lindbloma9996302013-01-12 00:25:16 -0800141
Jared Lindblom8278b982013-01-12 15:45:09 -0800142 // if this file is in a level higher than
143 // this directory, ignore
Jared Lindblomf8d32ad2013-01-12 11:32:27 -0800144 if(!absFilePath.startsWith(dirPath))
145 {
146 continue;
147 }
148
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800149 // check file existence
Jared Lindbloma9996302013-01-12 00:25:16 -0800150 if(currentState.contains(absFilePath))
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800151 {
Jared Lindblom8278b982013-01-12 15:45:09 -0800152 qint64 currentCreated = currentState.value(absFilePath);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800153
Jared Lindblom8278b982013-01-12 15:45:09 -0800154 if(storedCreated != currentCreated)
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800155 {
Jared Lindbloma9996302013-01-12 00:25:16 -0800156 // update stored state
Jared Lindblom8278b982013-01-12 15:45:09 -0800157 i.setValue(currentCreated);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800158
159 // this file has been modified
Jared Lindblom264310d2013-01-12 01:18:58 -0800160 sEventInfo eventInfo;
161 eventInfo.event = MODIFIED;
Jared Lindblom8278b982013-01-12 15:45:09 -0800162 eventInfo.absFilePath = absFilePath.toStdString();
Jared Lindblom264310d2013-01-12 01:18:58 -0800163 dirChanges.push_back(eventInfo);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800164 }
165
Jared Lindbloma9996302013-01-12 00:25:16 -0800166 // delete this file from fileList we have processed it
167 currentState.remove(absFilePath);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800168 }
169 else
170 {
Jared Lindbloma9996302013-01-12 00:25:16 -0800171 // delete from stored state
172 i.remove();
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800173
174 // this file has been deleted
Jared Lindblom264310d2013-01-12 01:18:58 -0800175 sEventInfo eventInfo;
176 eventInfo.event = DELETED;
Jared Lindblom8278b982013-01-12 15:45:09 -0800177 eventInfo.absFilePath = absFilePath.toStdString();
Jared Lindblom264310d2013-01-12 01:18:58 -0800178 dirChanges.push_back(eventInfo);
Jared Lindbloma9996302013-01-12 00:25:16 -0800179 }
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800180 }
181
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800182 // any files left in fileList have been added
Jared Lindblom8278b982013-01-12 15:45:09 -0800183 for(QHash<QString, qint64>::iterator i = currentState.begin(); i != currentState.end(); ++i)
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800184 {
185 QString absFilePath = i.key();
Jared Lindblom8278b982013-01-12 15:45:09 -0800186 qint64 currentCreated = i.value();
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800187
Jared Lindblom8278b982013-01-12 15:45:09 -0800188 m_storedState.insert(absFilePath, currentCreated);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800189
190 // this file has been added
Jared Lindblom264310d2013-01-12 01:18:58 -0800191 sEventInfo eventInfo;
192 eventInfo.event = ADDED;
Jared Lindblom8278b982013-01-12 15:45:09 -0800193 eventInfo.absFilePath = absFilePath.toStdString();
Jared Lindblom264310d2013-01-12 01:18:58 -0800194 dirChanges.push_back(eventInfo);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800195 }
196
Jared Lindbloma9996302013-01-12 00:25:16 -0800197 return dirChanges;
jareda9541812013-01-09 00:08:46 -0800198}
Alexander Afanasyevff731962013-01-09 17:16:28 -0800199
Jared Lindblomf8d32ad2013-01-12 11:32:27 -0800200QByteArray FileSystemWatcher::calcChecksum(QString absFilePath)
201{
202 // initialize checksum
203 QCryptographicHash crypto(QCryptographicHash::Md5);
204
205 // open file
206 QFile file(absFilePath);
207 file.open(QFile::ReadOnly);
208
209 // calculate checksum
210 while(!file.atEnd())
211 {
212 crypto.addData(file.read(8192));
213 }
214
215 return crypto.result();
216}
217
Jared Lindblomc1259722013-01-12 16:47:32 -0800218void FileSystemWatcher::printChanges(std::vector<sEventInfo> dirChanges)
Jared Lindblomf8d32ad2013-01-12 11:32:27 -0800219{
Jared Lindblomc1259722013-01-12 16:47:32 -0800220 if(!dirChanges.empty())
Jared Lindblomf8d32ad2013-01-12 11:32:27 -0800221 {
222 QStringList dirChangesList;
223
Jared Lindblomc1259722013-01-12 16:47:32 -0800224 for(size_t i = 0; i < dirChanges.size(); i++)
Jared Lindblomf8d32ad2013-01-12 11:32:27 -0800225 {
226 QString tempString;
227
228 eEvent event = dirChanges[i].event;
Jared Lindblom8278b982013-01-12 15:45:09 -0800229 QString absFilePath = QString::fromStdString(dirChanges[i].absFilePath);
Jared Lindblomf8d32ad2013-01-12 11:32:27 -0800230
231 switch(event)
232 {
233 case ADDED:
234 tempString.append("ADDED: ");
235 break;
236 case MODIFIED:
237 tempString.append("MODIFIED: ");
238 break;
239 case DELETED:
240 tempString.append("DELETED: ");
241 break;
242 }
243
244 tempString.append(absFilePath);
Jared Lindblomc1259722013-01-12 16:47:32 -0800245#if DEBUG
Jared Lindblomf8d32ad2013-01-12 11:32:27 -0800246 qDebug() << "\t" << tempString;
Jared Lindblomc1259722013-01-12 16:47:32 -0800247#endif
248 dirChangesList.append(tempString);
Jared Lindblomf8d32ad2013-01-12 11:32:27 -0800249 }
250
251 m_listViewModel->setStringList(dirChangesList);
252 }
Jared Lindblomc1259722013-01-12 16:47:32 -0800253 else
254 {
255#if DEBUG
256 qDebug() << "\t[EMPTY]";
257#endif
258 }
Jared Lindblomf8d32ad2013-01-12 11:32:27 -0800259}
260
Alexander Afanasyevff731962013-01-09 17:16:28 -0800261#if WAF
262#include "filesystemwatcher.moc"
263#include "filesystemwatcher.cpp.moc"
264#endif