/* * dirwatch.cpp - detect changes of directory content * Copyright (C) 2003 Justin Karneges * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include"dirwatch.h" #include #include #include #include #include static DirWatchPlatform *platform = 0; static int platform_ref = 0; struct file_info { QString name; uint size; QDateTime lastModified; }; typedef QValueList DirInfo; static DirInfo getDirInfo(const QString &dir) { DirInfo info; QDir d(dir); if(!d.exists()) return info; QStringList el = d.entryList(); for(QStringList::ConstIterator it = el.begin(); it != el.end(); ++it) { if(*it == "." || *it == "..") continue; QFileInfo fi(d.filePath(*it)); file_info i; i.name = fi.fileName(); i.size = fi.size(); i.lastModified = fi.lastModified(); info += i; } return info; } class DirWatch::Private { public: Private() {} QString dir; // for non-platform watching DirInfo info; QTimer checkTimer; int freq; int id; }; DirWatch::DirWatch(const QString &dir, QObject *parent) :QObject(parent) { d = new Private; d->freq = 5000; d->id = -1; // try to use platform if(!platform) { DirWatchPlatform *p = new DirWatchPlatform; if(p->init()) platform = p; else delete p; } if(platform) { ++platform_ref; connect(platform, SIGNAL(dirChanged(int)), SLOT(pf_dirChanged(int))); } else { connect(&d->checkTimer, SIGNAL(timeout()), SLOT(doCheck())); } if(!dir.isEmpty()) setDir(dir); } DirWatch::~DirWatch() { setDir(""); if(platform) { --platform_ref; if(platform_ref == 0) { delete platform; platform = 0; } } delete d; } bool DirWatch::usingPlatform() const { return (platform ? true: false); } QString DirWatch::dir() const { return d->dir; } void DirWatch::setDir(const QString &s) { if(d->dir == s) return; if(!d->dir.isEmpty()) { if(platform) { if(d->id != -1) platform->removeDir(d->id); } else d->checkTimer.stop(); d->dir = ""; } if(s.isEmpty()) return; d->dir = s; if(platform) { d->id = platform->addDir(d->dir); } else { d->info = getDirInfo(d->dir); d->checkTimer.start(d->freq); } } void DirWatch::doCheck() { DirInfo newInfo = getDirInfo(d->dir); bool info_changed = false; QDir dir(d->dir); file_info ni; // look for files that are missing or modified for(DirInfo::ConstIterator it = d->info.begin(); it != d->info.end(); ++it) { const file_info &i = *it; bool found = false; for(DirInfo::ConstIterator nit = newInfo.begin(); nit != newInfo.end(); ++nit) { const file_info &tmp = *nit; if(i.name == tmp.name) { found = true; ni = tmp; break; } } if(!found) { //printf("%s: not found\n", i.name.latin1()); info_changed = true; break; } if(i.lastModified != ni.lastModified || i.size != ni.size) { //printf("%s: modified (is: %s, was: %s)\n", i.name.latin1(), ni.lastModified.toString().latin1(), i.lastModified.toString().latin1()); info_changed = true; break; } //printf("%s: no change\n", i.name.latin1()); } // look for files that have been added for(DirInfo::ConstIterator nit = newInfo.begin(); nit != newInfo.end(); ++nit) { const file_info &i = *nit; bool found = false; for(DirInfo::ConstIterator it = d->info.begin(); it != d->info.end(); ++it) { const file_info &tmp = *it; if(i.name == tmp.name) { found = true; break; } } if(!found) { info_changed = true; break; } } d->info = newInfo; if(info_changed) changed(); } void DirWatch::pf_dirChanged(int id) { if(d->id != id) return; changed(); } class FileWatch::Private { public: Private() {} QString fname; DirWatch *dw; uint lastSize; QDateTime lastModified; }; FileWatch::FileWatch(const QString &fname, QObject *parent) :QObject(parent) { d = new Private; d->dw = 0; if(!fname.isEmpty()) setFileName(fname); } FileWatch::~FileWatch() { delete d; } QString FileWatch::fileName() const { return d->fname; } void FileWatch::setFileName(const QString &s) { if(d->fname == s) return; // remove old watch if necessary if(d->dw) { delete d->dw; d->dw = 0; } d->fname = s; if(d->fname.isEmpty()) return; // setup the watch d->dw = new DirWatch("", this); connect(d->dw, SIGNAL(changed()), SLOT(dirChanged())); QFileInfo fi(d->fname); d->lastSize = fi.size(); d->lastModified = fi.lastModified(); d->dw->setDir(fi.dirPath()); } void FileWatch::dirChanged() { bool doChange = false; QFileInfo fi(d->fname); if(fi.size() != d->lastSize || fi.lastModified() != d->lastModified) doChange = true; d->lastSize = fi.size(); d->lastModified = fi.lastModified(); if(doChange) changed(); }