blob: d6e82eeb7ccd072fc2daf7f90618b1778fce6b4b [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
50 qDebug() << endl << "[WATCHER] Triggered Path: " << dirPath;
51
52 handleCallback(dirPath);
53}
54
55void FileSystemWatcher::timerCallbackSlot()
56{
57 // timer specific steps
58 qDebug() << endl << "[TIMER] Triggered Path: " << m_dirPath;
59
60 handleCallback(m_dirPath);
61}
62
63void FileSystemWatcher::handleCallback(QString dirPath)
jareda9541812013-01-09 00:08:46 -080064{
Jared Lindblom4d1d00a2013-01-11 01:14:23 -080065 // scan directory and populate file list
Jared Lindblom8278b982013-01-12 15:45:09 -080066 QHash<QString, qint64> currentState = scanDirectory(dirPath);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -080067
Jared Lindblom264310d2013-01-12 01:18:58 -080068 // reconcile directory and report changes
Jared Lindblomf8d32ad2013-01-12 11:32:27 -080069 QVector<sEventInfo> dirChanges = reconcileDirectory(currentState, dirPath);
Jared Lindbloma9996302013-01-12 00:25:16 -080070
Jared Lindblom264310d2013-01-12 01:18:58 -080071 // DEBUG: Print to Gui
Jared Lindblomf8d32ad2013-01-12 11:32:27 -080072 printToGui(dirChanges);
jareda9541812013-01-09 00:08:46 -080073}
74
Jared Lindblom8278b982013-01-12 15:45:09 -080075QHash<QString, qint64> FileSystemWatcher::scanDirectory(QString dirPath)
Jared Lindbloma9996302013-01-12 00:25:16 -080076{
jareda9541812013-01-09 00:08:46 -080077 // list of files in directory
Jared Lindblom8278b982013-01-12 15:45:09 -080078 QHash<QString, qint64> currentState;
jareda9541812013-01-09 00:08:46 -080079
80 // directory iterator (recursive)
Jared Lindblom4d1d00a2013-01-11 01:14:23 -080081 QDirIterator dirIterator(dirPath, QDirIterator::Subdirectories |
jareda9541812013-01-09 00:08:46 -080082 QDirIterator::FollowSymlinks);
83
84 // iterate through directory recursively
85 while(dirIterator.hasNext())
86 {
87 // Get Next File/Dir
88 dirIterator.next();
89
90 // Get FileInfo
91 QFileInfo fileInfo = dirIterator.fileInfo();
92
93 // if not this directory or previous directory
94 if(fileInfo.absoluteFilePath() != ".." && fileInfo.absoluteFilePath() != ".")
95 {
Jared Lindbloma9996302013-01-12 00:25:16 -080096 QString absFilePath = fileInfo.absoluteFilePath();
97
jareda9541812013-01-09 00:08:46 -080098 // if this is a directory
99 if(fileInfo.isDir())
100 {
101 QStringList dirList = m_watcher->directories();
102
103 // if the directory is not already being watched
Jared Lindbloma9996302013-01-12 00:25:16 -0800104 if (absFilePath.startsWith(m_dirPath) && !dirList.contains(absFilePath))
jareda9541812013-01-09 00:08:46 -0800105 {
106 // add this directory to the watch list
Jared Lindbloma9996302013-01-12 00:25:16 -0800107 m_watcher->addPath(absFilePath);
jareda9541812013-01-09 00:08:46 -0800108 }
109 }
110 else
111 {
112 // add this file to the file list
Jared Lindblom8278b982013-01-12 15:45:09 -0800113 currentState.insert(absFilePath, fileInfo.created().toMSecsSinceEpoch());
jareda9541812013-01-09 00:08:46 -0800114 }
115 }
116 }
117
Jared Lindbloma9996302013-01-12 00:25:16 -0800118 return currentState;
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800119}
120
Jared Lindblom8278b982013-01-12 15:45:09 -0800121QVector<sEventInfo> FileSystemWatcher::reconcileDirectory(QHash<QString, qint64> currentState, QString dirPath)
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800122{
Jared Lindbloma9996302013-01-12 00:25:16 -0800123 // list of files changed
Jared Lindblom264310d2013-01-12 01:18:58 -0800124 QVector<sEventInfo> dirChanges;
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800125
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800126 // compare result (database/stored snapshot) to fileList (current snapshot)
Jared Lindblom8278b982013-01-12 15:45:09 -0800127 QMutableHashIterator<QString, qint64> i(m_storedState);
Jared Lindblom264310d2013-01-12 01:18:58 -0800128
Jared Lindbloma9996302013-01-12 00:25:16 -0800129 while(i.hasNext())
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800130 {
Jared Lindbloma9996302013-01-12 00:25:16 -0800131 i.next();
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800132
Jared Lindbloma9996302013-01-12 00:25:16 -0800133 QString absFilePath = i.key();
Jared Lindblom8278b982013-01-12 15:45:09 -0800134 qint64 storedCreated = i.value();
Jared Lindbloma9996302013-01-12 00:25:16 -0800135
Jared Lindblom8278b982013-01-12 15:45:09 -0800136 // if this file is in a level higher than
137 // this directory, ignore
Jared Lindblomf8d32ad2013-01-12 11:32:27 -0800138 if(!absFilePath.startsWith(dirPath))
139 {
140 continue;
141 }
142
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800143 // check file existence
Jared Lindbloma9996302013-01-12 00:25:16 -0800144 if(currentState.contains(absFilePath))
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800145 {
Jared Lindblom8278b982013-01-12 15:45:09 -0800146 qint64 currentCreated = currentState.value(absFilePath);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800147
Jared Lindblom8278b982013-01-12 15:45:09 -0800148 if(storedCreated != currentCreated)
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800149 {
Jared Lindbloma9996302013-01-12 00:25:16 -0800150 // update stored state
Jared Lindblom8278b982013-01-12 15:45:09 -0800151 i.setValue(currentCreated);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800152
153 // this file has been modified
Jared Lindblom264310d2013-01-12 01:18:58 -0800154 sEventInfo eventInfo;
155 eventInfo.event = MODIFIED;
Jared Lindblom8278b982013-01-12 15:45:09 -0800156 eventInfo.absFilePath = absFilePath.toStdString();
Jared Lindblom264310d2013-01-12 01:18:58 -0800157 dirChanges.push_back(eventInfo);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800158 }
159
Jared Lindbloma9996302013-01-12 00:25:16 -0800160 // delete this file from fileList we have processed it
161 currentState.remove(absFilePath);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800162 }
163 else
164 {
Jared Lindbloma9996302013-01-12 00:25:16 -0800165 // delete from stored state
166 i.remove();
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800167
168 // this file has been deleted
Jared Lindblom264310d2013-01-12 01:18:58 -0800169 sEventInfo eventInfo;
170 eventInfo.event = DELETED;
Jared Lindblom8278b982013-01-12 15:45:09 -0800171 eventInfo.absFilePath = absFilePath.toStdString();
Jared Lindblom264310d2013-01-12 01:18:58 -0800172 dirChanges.push_back(eventInfo);
Jared Lindbloma9996302013-01-12 00:25:16 -0800173 }
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800174 }
175
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800176 // any files left in fileList have been added
Jared Lindblom8278b982013-01-12 15:45:09 -0800177 for(QHash<QString, qint64>::iterator i = currentState.begin(); i != currentState.end(); ++i)
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800178 {
179 QString absFilePath = i.key();
Jared Lindblom8278b982013-01-12 15:45:09 -0800180 qint64 currentCreated = i.value();
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800181
Jared Lindblom8278b982013-01-12 15:45:09 -0800182 m_storedState.insert(absFilePath, currentCreated);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800183
184 // this file has been added
Jared Lindblom264310d2013-01-12 01:18:58 -0800185 sEventInfo eventInfo;
186 eventInfo.event = ADDED;
Jared Lindblom8278b982013-01-12 15:45:09 -0800187 eventInfo.absFilePath = absFilePath.toStdString();
Jared Lindblom264310d2013-01-12 01:18:58 -0800188 dirChanges.push_back(eventInfo);
Jared Lindblom4d1d00a2013-01-11 01:14:23 -0800189 }
190
Jared Lindbloma9996302013-01-12 00:25:16 -0800191 return dirChanges;
jareda9541812013-01-09 00:08:46 -0800192}
Alexander Afanasyevff731962013-01-09 17:16:28 -0800193
Jared Lindblomf8d32ad2013-01-12 11:32:27 -0800194QByteArray FileSystemWatcher::calcChecksum(QString absFilePath)
195{
196 // initialize checksum
197 QCryptographicHash crypto(QCryptographicHash::Md5);
198
199 // open file
200 QFile file(absFilePath);
201 file.open(QFile::ReadOnly);
202
203 // calculate checksum
204 while(!file.atEnd())
205 {
206 crypto.addData(file.read(8192));
207 }
208
209 return crypto.result();
210}
211
212void FileSystemWatcher::printToGui(QVector<sEventInfo> dirChanges)
213{
214 if(!dirChanges.isEmpty())
215 {
216 QStringList dirChangesList;
217
218 for(int i = 0; i < dirChanges.size(); i++)
219 {
220 QString tempString;
221
222 eEvent event = dirChanges[i].event;
Jared Lindblom8278b982013-01-12 15:45:09 -0800223 QString absFilePath = QString::fromStdString(dirChanges[i].absFilePath);
Jared Lindblomf8d32ad2013-01-12 11:32:27 -0800224
225 switch(event)
226 {
227 case ADDED:
228 tempString.append("ADDED: ");
229 break;
230 case MODIFIED:
231 tempString.append("MODIFIED: ");
232 break;
233 case DELETED:
234 tempString.append("DELETED: ");
235 break;
236 }
237
238 tempString.append(absFilePath);
239
240 dirChangesList.append(tempString);
241
242 qDebug() << "\t" << tempString;
243 }
244
245 m_listViewModel->setStringList(dirChangesList);
246 }
247}
248
Alexander Afanasyevff731962013-01-09 17:16:28 -0800249#if WAF
250#include "filesystemwatcher.moc"
251#include "filesystemwatcher.cpp.moc"
252#endif