• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

kleopatra

  • sources
  • kde-4.14
  • kdepim
  • kleopatra
  • utils
filesystemwatcher.cpp
Go to the documentation of this file.
1 /* -*- mode: c++; c-basic-offset:4 -*-
2  filesystemwatcher.cpp
3 
4  This file is part of Kleopatra, the KDE keymanager
5  Copyright (c) 2008 Klarälvdalens Datakonsult AB
6 
7  Kleopatra is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  Kleopatra is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 
21  In addition, as a special exception, the copyright holders give
22  permission to link the code of this program with any edition of
23  the Qt library by Trolltech AS, Norway (or with modified versions
24  of Qt that use the same license as Qt), and distribute linked
25  combinations including the two. You must obey the GNU General
26  Public License in all respects for all of the code used other than
27  Qt. If you modify this file, you may extend this exception to
28  your version of the file, but you are not obligated to do so. If
29  you do not wish to do so, delete this exception statement from
30  your version.
31 */
32 
33 #include <config-kleopatra.h>
34 
35 #include "filesystemwatcher.h"
36 
37 #include <KDebug>
38 
39 #include <QFileSystemWatcher>
40 #include <QString>
41 #include <QStringList>
42 #include <QTimer>
43 #include <QDir>
44 
45 #include <kleo/stl_util.h>
46 
47 #ifndef Q_MOC_RUN
48 #include <boost/bind.hpp>
49 #endif
50 
51 #include <set>
52 #include <cassert>
53 
54 using namespace Kleo;
55 using namespace boost;
56 
57 class FileSystemWatcher::Private {
58  FileSystemWatcher* const q;
59 public:
60  explicit Private( FileSystemWatcher* qq, const QStringList& paths=QStringList() );
61  ~Private() {
62  delete m_watcher;
63  }
64 
65  void onFileChanged( const QString& path );
66  void onDirectoryChanged( const QString& path );
67  void handleTimer();
68  void onTimeout();
69 
70  void connectWatcher();
71 
72  QFileSystemWatcher* m_watcher;
73  QTimer m_timer;
74  std::set<QString> m_seenPaths;
75  std::set<QString> m_cachedDirectories;
76  std::set<QString> m_cachedFiles;
77  QStringList m_paths, m_blacklist, m_whitelist;
78 };
79 
80 FileSystemWatcher::Private::Private( FileSystemWatcher* qq, const QStringList& paths )
81  : q( qq ),
82  m_watcher( 0 ),
83  m_paths( paths )
84 {
85  m_timer.setSingleShot( true );
86  connect( &m_timer, SIGNAL(timeout()), q, SLOT(onTimeout()) );
87 }
88 
89 static bool is_matching( const QString & file, const QStringList & list ) {
90  Q_FOREACH( const QString & entry, list )
91  if ( QRegExp( entry, Qt::CaseInsensitive, QRegExp::Wildcard ).exactMatch( file ) ) {
92  return true;
93  }
94  return false;
95 }
96 
97 static bool is_blacklisted( const QString & file, const QStringList & blacklist ) {
98  return is_matching( file, blacklist );
99 }
100 
101 static bool is_whitelisted( const QString & file, const QStringList & whitelist ) {
102  if ( whitelist.empty() )
103  return true; // special case
104  return is_matching( file, whitelist );
105 }
106 
107 void FileSystemWatcher::Private::onFileChanged( const QString& path )
108 {
109  const QFileInfo fi( path );
110  if ( is_blacklisted( fi.fileName(), m_blacklist ) )
111  return;
112  if ( !is_whitelisted( fi.fileName(), m_whitelist ) )
113  return;
114  kDebug() << path;
115  m_seenPaths.insert( path );
116  m_cachedFiles.insert( path );
117  handleTimer();
118 }
119 
120 static QStringList list_dir_absolute( const QString & path, const QStringList & blacklist, const QStringList & whitelist ) {
121  QDir dir( path );
122  QStringList entries = dir.entryList( QDir::AllEntries|QDir::NoDotAndDotDot );
123  QStringList::iterator end =
124  std::remove_if( entries.begin(), entries.end(),
125  boost::bind( is_blacklisted, _1, cref( blacklist ) ) );
126  if ( !whitelist.empty() )
127  end = std::remove_if( entries.begin(), end,
128  !boost::bind( is_whitelisted, _1, cref( whitelist ) ) );
129  entries.erase( end, entries.end() );
130  kdtools::sort( entries );
131 
132  std::transform( entries.begin(), entries.end(), entries.begin(),
133  boost::bind( &QDir::absoluteFilePath, &dir, _1 ) );
134 
135  return entries;
136 }
137 
138 static QStringList find_new_files( const QStringList & current, const std::set<QString> & seen ) {
139  QStringList result;
140  std::set_difference( current.begin(), current.end(),
141  seen.begin(), seen.end(),
142  std::back_inserter( result ) );
143  return result;
144 }
145 
146 void FileSystemWatcher::Private::onDirectoryChanged( const QString& path )
147 {
148  const QFileInfo fi( path );
149  if ( is_blacklisted( fi.fileName(), m_blacklist ) )
150  return;
151  if ( !is_whitelisted( fi.fileName(), m_whitelist ) )
152  return;
153 
154  kDebug() << path;
155 
156  const QStringList newFiles = find_new_files( list_dir_absolute( path, m_blacklist, m_whitelist ), m_seenPaths );
157 
158  if ( newFiles.empty() )
159  return;
160 
161  kDebug() << "newFiles" << newFiles;
162 
163  m_cachedFiles.insert( newFiles.begin(), newFiles.end() );
164  q->addPaths( newFiles );
165 
166  m_cachedDirectories.insert( path );
167  handleTimer();
168 }
169 
170 void FileSystemWatcher::Private::onTimeout()
171 {
172  std::set<QString> dirs, files;
173 
174  dirs.swap( m_cachedDirectories );
175  files.swap( m_cachedFiles );
176 
177  if ( dirs.empty() && files.empty() )
178  return;
179 
180  emit q->triggered();
181 
182  Q_FOREACH( const QString& i, dirs )
183  emit q->directoryChanged( i );
184  Q_FOREACH( const QString& i, files )
185  emit q->fileChanged( i );
186 }
187 
188 void FileSystemWatcher::Private::handleTimer()
189 {
190  if ( m_timer.interval() == 0 ) {
191  onTimeout();
192  return;
193  }
194  m_timer.start();
195 }
196 
197 void FileSystemWatcher::Private::connectWatcher() {
198  if ( !m_watcher )
199  return;
200  connect( m_watcher, SIGNAL(directoryChanged(QString)),
201  q, SLOT(onDirectoryChanged(QString)) );
202  connect( m_watcher, SIGNAL(fileChanged(QString)),
203  q, SLOT(onFileChanged(QString)) );
204 }
205 
206 FileSystemWatcher::FileSystemWatcher( QObject* p )
207  : QObject( p ), d( new Private( this ) )
208 {
209  setEnabled( true );
210 }
211 
212 FileSystemWatcher::FileSystemWatcher( const QStringList& paths, QObject* p )
213  : QObject( p ), d( new Private( this, paths ) )
214 {
215  setEnabled( true );
216 }
217 
218 void FileSystemWatcher::setEnabled( bool enable )
219 {
220  if ( isEnabled() == enable )
221  return;
222  if ( enable ) {
223  assert( !d->m_watcher );
224  d->m_watcher = new QFileSystemWatcher;
225  if ( !d->m_paths.empty() )
226  d->m_watcher->addPaths( d->m_paths );
227  d->connectWatcher();
228  } else {
229  assert( d->m_watcher );
230  delete d->m_watcher;
231  d->m_watcher = 0;
232  }
233 }
234 
235 bool FileSystemWatcher::isEnabled() const
236 {
237  return d->m_watcher != 0;
238 }
239 
240 FileSystemWatcher::~FileSystemWatcher()
241 {
242 }
243 
244 void FileSystemWatcher::setDelay( int ms )
245 {
246  assert( ms >= 0 );
247  d->m_timer.setInterval( ms );
248 }
249 
250 int FileSystemWatcher::delay() const
251 {
252  return d->m_timer.interval();
253 }
254 
255 void FileSystemWatcher::blacklistFiles( const QStringList& paths )
256 {
257  d->m_blacklist += paths;
258  QStringList blacklisted;
259  d->m_paths.erase( kdtools::separate_if( d->m_paths.begin(), d->m_paths.end(),
260  std::back_inserter( blacklisted ), d->m_paths.begin(),
261  boost::bind( is_blacklisted, _1, cref( d->m_blacklist ) ) ).second, d->m_paths.end() );
262  if ( d->m_watcher && !blacklisted.empty() )
263  d->m_watcher->removePaths( blacklisted );
264 }
265 
266 void FileSystemWatcher::whitelistFiles( const QStringList & patterns )
267 {
268  d->m_whitelist += patterns;
269  // ### would be nice to add newly-matching paths here right away,
270  // ### but it's not as simple as blacklisting above, esp. since we
271  // ### don't want to subject addPath()'ed paths to whitelisting.
272 }
273 
274 static QStringList resolve( const QStringList & paths, const QStringList & blacklist, const QStringList & whitelist ) {
275  if ( paths.empty() )
276  return QStringList();
277  QStringList result;
278  Q_FOREACH( const QString & path, paths )
279  if ( QDir( path ).exists() )
280  result += list_dir_absolute( path, blacklist, whitelist );
281  return result + resolve( result, blacklist, whitelist );
282 }
283 
284 void FileSystemWatcher::addPaths( const QStringList& paths )
285 {
286  if ( paths.empty() )
287  return;
288  const QStringList newPaths = paths + resolve( paths, d->m_blacklist, d->m_whitelist );
289  kDebug( !newPaths.empty() ) << "adding\n " << newPaths.join( QLatin1String("\n ") ) << "\n/end";
290  d->m_paths += newPaths;
291  d->m_seenPaths.insert( newPaths.begin(), newPaths.end() );
292  if ( d->m_watcher && !newPaths.empty() )
293  d->m_watcher->addPaths( newPaths );
294 }
295 
296 void FileSystemWatcher::addPath( const QString& path )
297 {
298  addPaths( QStringList( path ) );
299 }
300 
301 void FileSystemWatcher::removePaths( const QStringList& paths )
302 {
303  if ( paths.empty() )
304  return;
305  Q_FOREACH ( const QString& i, paths )
306  d->m_paths.removeAll( i );
307  if ( d->m_watcher )
308  d->m_watcher->removePaths( paths );
309 }
310 
311 void FileSystemWatcher::removePath( const QString& path )
312 {
313  removePaths( QStringList( path ) );
314 }
315 
316 #include "moc_filesystemwatcher.cpp"
list_dir_absolute
static QStringList list_dir_absolute(const QString &path, const QStringList &blacklist, const QStringList &whitelist)
Definition: filesystemwatcher.cpp:120
is_blacklisted
static bool is_blacklisted(const QString &file, const QStringList &blacklist)
Definition: filesystemwatcher.cpp:97
Kleo::FileSystemWatcher::setEnabled
void setEnabled(bool enable)
Definition: filesystemwatcher.cpp:218
Kleo::FileSystemWatcher::addPath
void addPath(const QString &path)
Definition: filesystemwatcher.cpp:296
Kleo::FileSystemWatcher::whitelistFiles
void whitelistFiles(const QStringList &patterns)
Definition: filesystemwatcher.cpp:266
Kleo::FileSystemWatcher::isEnabled
bool isEnabled() const
Definition: filesystemwatcher.cpp:235
QList::erase
iterator erase(iterator pos)
QStringList::join
QString join(const QString &separator) const
resolve
static QStringList resolve(const QStringList &paths, const QStringList &blacklist, const QStringList &whitelist)
Definition: filesystemwatcher.cpp:274
QRegExp
d
#define d
Definition: adduseridcommand.cpp:89
QString::insert
QString & insert(int position, QChar ch)
QList::empty
bool empty() const
QTimer
Kleo::FileSystemWatcher
Definition: filesystemwatcher.h:45
QObject
Kleo::FileSystemWatcher::FileSystemWatcher
FileSystemWatcher(QObject *parent=0)
Definition: filesystemwatcher.cpp:206
Kleo::FileSystemWatcher::removePath
void removePath(const QString &path)
Definition: filesystemwatcher.cpp:311
QString
find_new_files
static QStringList find_new_files(const QStringList &current, const std::set< QString > &seen)
Definition: filesystemwatcher.cpp:138
QList::iterator
QStringList
QFileInfo
QList::end
iterator end()
QDir
dir
static QString dir(const QString &id)
Definition: filedialog.cpp:54
is_matching
static bool is_matching(const QString &file, const QStringList &list)
Definition: filesystemwatcher.cpp:89
QFileSystemWatcher
filesystemwatcher.h
Kleo::FileSystemWatcher::setDelay
void setDelay(int ms)
Definition: filesystemwatcher.cpp:244
QLatin1String
QList::insert
void insert(int i, const T &value)
Kleo::FileSystemWatcher::addPaths
void addPaths(const QStringList &paths)
Definition: filesystemwatcher.cpp:284
QDir::entryList
QStringList entryList(QFlags< QDir::Filter > filters, QFlags< QDir::SortFlag > sort) const
q
#define q
Definition: adduseridcommand.cpp:90
Kleo::FileSystemWatcher::removePaths
void removePaths(const QStringList &path)
Definition: filesystemwatcher.cpp:301
QDir::absoluteFilePath
QString absoluteFilePath(const QString &fileName) const
Kleo::FileSystemWatcher::delay
int delay() const
Definition: filesystemwatcher.cpp:250
Kleo::FileSystemWatcher::~FileSystemWatcher
~FileSystemWatcher()
Definition: filesystemwatcher.cpp:240
QList::begin
iterator begin()
is_whitelisted
static bool is_whitelisted(const QString &file, const QStringList &whitelist)
Definition: filesystemwatcher.cpp:101
Kleo::FileSystemWatcher::blacklistFiles
void blacklistFiles(const QStringList &patterns)
Definition: filesystemwatcher.cpp:255
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:33:11 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kleopatra

Skip menu "kleopatra"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer
  • pimprint

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal