blob: 3184cd90e700ed4b7429089538f31208d9718438 [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 Lindbloma9996302013-01-12 00:25:16 -080027 connect(m_watcher, SIGNAL(directoryChanged(QString)), this, SLOT(handleCallback()));
28 connect(m_timer, SIGNAL(timeout()), this, SLOT(handleCallback()));
jareda9541812013-01-09 00:08:46 -080029
Jared Lindbloma9996302013-01-12 00:25:16 -080030 // bootstrap
31 handleCallback();
32
33 // start timer
34 m_timer->start(10000);
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 Lindbloma9996302013-01-12 00:25:16 -080047void FileSystemWatcher::handleCallback()
jareda9541812013-01-09 00:08:46 -080048{
Jared Lindblom4d1d00a2013-01-11 01:14:23 -080049 // scan directory and populate file list
Jared Lindbloma9996302013-01-12 00:25:16 -080050 QHash<QString, sFileInfo> currentState = scanDirectory(m_dirPath);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -080051
Jared Lindblom264310d2013-01-12 01:18:58 -080052 // reconcile directory and report changes
53 QVector<sEventInfo> dirChanges = reconcileDirectory(currentState);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -080054
55 // update gui with list of changes in this directory
Jared Lindbloma9996302013-01-12 00:25:16 -080056 qDebug() << endl << m_watcher->directories() << endl;
57
Jared Lindblom264310d2013-01-12 01:18:58 -080058 // DEBUG: Print to Gui
Jared Lindbloma9996302013-01-12 00:25:16 -080059 if(!dirChanges.isEmpty())
Jared Lindblom264310d2013-01-12 01:18:58 -080060 {
61 QStringList dirChangesList;
62
63 for(int i = 0; i < dirChanges.size(); i++)
64 {
65 QString tempString;
66
67 eEvent event = dirChanges[i].event;
68 QString absFilePath = dirChanges[i].absFilePath;
69
70 switch(event)
71 {
72 case ADDED:
73 tempString.append("ADDED: ");
74 break;
75 case MODIFIED:
76 tempString.append("MODIFIED: ");
77 break;
78 case DELETED:
79 tempString.append("DELETED: ");
80 break;
81 }
82
83 tempString.append(absFilePath);
84
85 dirChangesList.append(tempString);
86 }
87
88 m_listViewModel->setStringList(dirChangesList);
89 }
jareda9541812013-01-09 00:08:46 -080090}
91
Jared Lindbloma9996302013-01-12 00:25:16 -080092QHash<QString, sFileInfo> FileSystemWatcher::scanDirectory(QString dirPath)
93{
jareda9541812013-01-09 00:08:46 -080094 // list of files in directory
Jared Lindbloma9996302013-01-12 00:25:16 -080095 QHash<QString, sFileInfo> currentState;
jareda9541812013-01-09 00:08:46 -080096
97 // directory iterator (recursive)
Jared Lindblom4d1d00a2013-01-11 01:14:23 -080098 QDirIterator dirIterator(dirPath, QDirIterator::Subdirectories |
jareda9541812013-01-09 00:08:46 -080099 QDirIterator::FollowSymlinks);
100
101 // iterate through directory recursively
102 while(dirIterator.hasNext())
103 {
104 // Get Next File/Dir
105 dirIterator.next();
106
107 // Get FileInfo
108 QFileInfo fileInfo = dirIterator.fileInfo();
109
110 // if not this directory or previous directory
111 if(fileInfo.absoluteFilePath() != ".." && fileInfo.absoluteFilePath() != ".")
112 {
Jared Lindbloma9996302013-01-12 00:25:16 -0800113 QString absFilePath = fileInfo.absoluteFilePath();
114
jareda9541812013-01-09 00:08:46 -0800115 // if this is a directory
116 if(fileInfo.isDir())
117 {
118 QStringList dirList = m_watcher->directories();
119
120 // if the directory is not already being watched
Jared Lindbloma9996302013-01-12 00:25:16 -0800121 if (absFilePath.startsWith(m_dirPath) && !dirList.contains(absFilePath))
jareda9541812013-01-09 00:08:46 -0800122 {
123 // add this directory to the watch list
Jared Lindbloma9996302013-01-12 00:25:16 -0800124 m_watcher->addPath(absFilePath);
jareda9541812013-01-09 00:08:46 -0800125 }
126 }
127 else
128 {
Jared Lindbloma9996302013-01-12 00:25:16 -0800129 // construct struct
130 sFileInfo fileInfoStruct;
131 fileInfoStruct.fileInfo = fileInfo;
132
133 // initialize checksum
134 QCryptographicHash crypto(QCryptographicHash::Md5);
135
136 // open file
137 QFile file(fileInfo.absoluteFilePath());
138 file.open(QFile::ReadOnly);
139
140 // calculate checksum
141 while(!file.atEnd())
142 {
143 crypto.addData(file.read(8192));
144 }
145
146 fileInfoStruct.hash = crypto.result();
147
jareda9541812013-01-09 00:08:46 -0800148 // add this file to the file list
Jared Lindbloma9996302013-01-12 00:25:16 -0800149 currentState.insert(absFilePath, fileInfoStruct);
jareda9541812013-01-09 00:08:46 -0800150 }
151 }
152 }
153
Jared Lindbloma9996302013-01-12 00:25:16 -0800154 return currentState;
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800155}
156
Jared Lindblom264310d2013-01-12 01:18:58 -0800157QVector<sEventInfo> FileSystemWatcher::reconcileDirectory(QHash<QString, sFileInfo> currentState)
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800158{
Jared Lindbloma9996302013-01-12 00:25:16 -0800159 // list of files changed
Jared Lindblom264310d2013-01-12 01:18:58 -0800160 QVector<sEventInfo> dirChanges;
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800161
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800162 // compare result (database/stored snapshot) to fileList (current snapshot)
Jared Lindbloma9996302013-01-12 00:25:16 -0800163 QMutableHashIterator<QString, sFileInfo> i(m_storedState);
Jared Lindblom264310d2013-01-12 01:18:58 -0800164
Jared Lindbloma9996302013-01-12 00:25:16 -0800165 while(i.hasNext())
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800166 {
Jared Lindbloma9996302013-01-12 00:25:16 -0800167 i.next();
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800168
Jared Lindbloma9996302013-01-12 00:25:16 -0800169 QString absFilePath = i.key();
170
171 sFileInfo storedFileInfoStruct = i.value();
172 QFileInfo storedFileInfo = storedFileInfoStruct.fileInfo;
173 QByteArray storedHash = storedFileInfoStruct.hash;
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800174
175 // check file existence
Jared Lindbloma9996302013-01-12 00:25:16 -0800176 if(currentState.contains(absFilePath))
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800177 {
Jared Lindbloma9996302013-01-12 00:25:16 -0800178 sFileInfo currentFileInfoStruct = currentState.value(absFilePath);
179 QFileInfo currentFileInfo = currentFileInfoStruct.fileInfo;
180 QByteArray currentHash = currentFileInfoStruct.hash;
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800181
Jared Lindbloma9996302013-01-12 00:25:16 -0800182 if((storedFileInfo != currentFileInfo) || (storedHash != currentHash))
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800183 {
Jared Lindbloma9996302013-01-12 00:25:16 -0800184 // update stored state
185 i.setValue(currentFileInfoStruct);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800186
187 // this file has been modified
Jared Lindblom264310d2013-01-12 01:18:58 -0800188 sEventInfo eventInfo;
189 eventInfo.event = MODIFIED;
190 eventInfo.absFilePath = absFilePath;
191 dirChanges.push_back(eventInfo);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800192 }
193
Jared Lindbloma9996302013-01-12 00:25:16 -0800194 // delete this file from fileList we have processed it
195 currentState.remove(absFilePath);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800196 }
197 else
198 {
Jared Lindbloma9996302013-01-12 00:25:16 -0800199 // delete from stored state
200 i.remove();
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800201
202 // this file has been deleted
Jared Lindblom264310d2013-01-12 01:18:58 -0800203 sEventInfo eventInfo;
204 eventInfo.event = DELETED;
205 eventInfo.absFilePath = absFilePath;
206 dirChanges.push_back(eventInfo);
Jared Lindbloma9996302013-01-12 00:25:16 -0800207 }
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800208 }
209
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800210 // any files left in fileList have been added
Jared Lindbloma9996302013-01-12 00:25:16 -0800211 for(QHash<QString, sFileInfo>::iterator i = currentState.begin(); i != currentState.end(); ++i)
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800212 {
213 QString absFilePath = i.key();
Jared Lindbloma9996302013-01-12 00:25:16 -0800214 sFileInfo currentFileInfoStruct = i.value();
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800215
Jared Lindbloma9996302013-01-12 00:25:16 -0800216 m_storedState.insert(absFilePath, currentFileInfoStruct);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800217
218 // this file has been added
Jared Lindblom264310d2013-01-12 01:18:58 -0800219 sEventInfo eventInfo;
220 eventInfo.event = ADDED;
221 eventInfo.absFilePath = absFilePath;
222 dirChanges.push_back(eventInfo);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800223 }
224
Jared Lindbloma9996302013-01-12 00:25:16 -0800225 return dirChanges;
jareda9541812013-01-09 00:08:46 -0800226}
Alexander Afanasyevff731962013-01-09 17:16:28 -0800227
228#if WAF
229#include "filesystemwatcher.moc"
230#include "filesystemwatcher.cpp.moc"
231#endif