Source Code (Use browser search to find items of interest.)

Class Index

kdelibs'KDirWatch (./kdelibs/kio/kdirwatch.h:53)

class KDirWatch : public QObject
{
  Q_OBJECT
    
  public:
   /**
    * Constructor. Does not begin with scanning until @ref startScan
    * is called. Default frequency is 500 ms. The created list of
    * directories has deep copies.
    */
   KDirWatch ( int freq = 500 );

   /**
    * Destructor. Stops scanning and cleans up.
    */
   ~KDirWatch();

   /**
    * Adds directory to list of directories to be watched. (The list
    * makes deep copies).
    */
   void addDir(const QString& path);

   /**
    * Returns the time the directory was last changed.
    */
   time_t ctime(const QString& path);

   /**
    * Removes directory from list of scanned directories. If specified
    * path is not in the list, does nothing.
    */
   void removeDir(const QString& path);

   /**
    * Stops scanning for specified path. Does not delete dir from list,
    * just skips it. Call this function when you make an huge operation
    * on this directory (copy/move big files or lot of files). When finished,
    * call @ref #restartDirScan (path).
    * Returns 'false' if specified path is not in list, 'true' otherwise.
    */
   bool stopDirScan(const QString& path);

   /**
    * Restarts scanning for specified path. Resets ctime. It doesn't notify
    * the change, since ctime value is reset. Call it when you are finished
    * with big operations on that path, *and* when *you* have refreshed that
    * path.
    * Returns 'false' if specified path is not in list, 'true' otherwise.
    */
   bool restartDirScan(const QString& path);

   /**
    * Starts scanning of all dirs in list. If notify is true, all changed
    * dirs (since @ref #stopScan call) will be notified for refresh. If
    * notify is false, all ctimes will be reset (except those who are stopped,
    * but only if skippedToo is false) and changed dirs won't be
    * notified. You can start scanning even if the list is empty. First call
    * should be called with 'false' or else all dirs in list will be notified.
    * Note that direcories that were.
    * If 'skippedToo' is true, the skipped dirs, (scanning of which was
    * stopped with @ref #stopDirScan ) will be reset and notified for change.
    * Otherwise, stopped dirs will continue to be unnotified.
    */
   void startScan( bool notify=false, bool skippedToo=false );

   /**
    * Stops scanning of all dirs in list. List is not cleared, just the
    * timer is stopped.
    */
   void stopScan();
  
   bool contains( const QString& path ) const;
  
   /** @see signal fileDirty */
   void setFileDirty( const QString & _file );

   static KDirWatch* self();
    
 signals:

   /**
    * This signal is emited when directory is changed. The new ctime is set
    * before the signal is emited.
    */
   void dirty (const QString& dir);
   
   /**
    * This signal is emited when KDirWatch learns that the file
    * _file has changed. This happens for instance when a .desktop file 
    * gets a new icon - but this isn't automatic, one has to call 
    * setFileDirty() for this signal to be emitted.
    */
   void fileDirty (const QString& _file);

   /**
    * This signal is emited when directory is deleted. When you receive
    * this signal, directory is not yet deleted from the list. You will
    * receive this signal only once, because one directory cannot be
    * deleted more than once. Please, forget the last^H^H^H^Hprevious
    * sentence.
    */
   void deleted (const QString& dir);
     
 protected:
   void resetList (bool reallyall);
   
 protected slots:
   void slotRescan();
   void famEventReceived();
   
 private:
  struct Entry
  {
    time_t m_ctime;
    int m_clients;    
#ifdef USE_FAM
    FAMRequest fr;
#endif
  };
  
  QTimer *timer;
  QMap<QString,Entry> m_mapDirs;

  int freq;
  struct stat statbuff;

  static KDirWatch* s_pSelf;

#ifdef USE_FAM
  QSocketNotifier *sn;
  FAMConnection fc;
  FAMEvent fe;
  int use_fam;
  bool emitEvents;
#endif
};

kdelibs'KDirWatch::self() (./kdelibs/kio/kdirwatch.cpp:45)

KDirWatch* KDirWatch::self()
{
  if ( !s_pSelf )
    s_pSelf = new KDirWatch;
  return s_pSelf;
}


kdelibs'KDirWatch::KDirWatch() (./kdelibs/kio/kdirwatch.cpp:52)

KDirWatch::KDirWatch (int _freq)
{
  timer = new QTimer(this);
  connect (timer, SIGNAL(timeout()), this, SLOT(slotRescan()));

  freq = _freq;

#ifdef USE_FAM
  // It's possible that FAM server can't be started
  if (FAMOpen(&fc) ==0) {
    qDebug("KDirWatch: Using FAM");
    use_fam=1;
    emitEvents = true;
    sn = new QSocketNotifier( FAMCONNECTION_GETFD(&fc), 
			      QSocketNotifier::Read, this);
    connect( sn, SIGNAL(activated(int)),
	     this, SLOT(famEventReceived()) );
  }
  else {
    qDebug("KDirWatch: Can't use FAM");
    use_fam=0;
  }
#endif
}


kdelibs'KDirWatch::~KDirWatch() (./kdelibs/kio/kdirwatch.cpp:77)

KDirWatch::~KDirWatch()
{
  timer->stop();
  //  delete timer; timer was created with 'this' as parent!

#ifdef USE_FAM
  if (use_fam) {
    FAMClose(&fc);
    qDebug("KDirWatch deleted (FAM closed)");
  }
#endif
}


kdelibs'KDirWatch::addDir() (./kdelibs/kio/kdirwatch.cpp:90)

void KDirWatch::addDir( const QString& _path )
{
  QString path = _path;

  if ( path.right(1) == "/" )
    path.truncate( path.length() - 1 );

  QMap<QString,Entry>::Iterator it = m_mapDirs.find( path );
  if ( it != m_mapDirs.end() )
  {
    (*it).m_clients++;
    return;
  }

  stat( QFile::encodeName(path), &statbuff );
  Entry e;
  e.m_clients = 1;
  e.m_ctime = statbuff.st_ctime;

#ifdef USE_FAM
  if (use_fam) {
    FAMMonitorDirectory(&fc, QFile::encodeName(path), &(e.fr), 0);
    //    qDebug("KDirWatch added %s -> FAMReq %d", 
    //	   QFile::encodeName(path),  FAMREQUEST_GETREQNUM(&(e.fr)) );
  }
#endif

  m_mapDirs.insert( path, e );



#ifdef USE_FAM
  // if FAM server can't be used, fall back to good old timer...
  if (!use_fam)
#endif
  if ( m_mapDirs.count() == 1 ) // if this was first entry (=timer was stopped)
    timer->start(freq);      // then start the timer
}


kdelibs'KDirWatch::ctime() (./kdelibs/kio/kdirwatch.cpp:129)

time_t KDirWatch::ctime( const QString &_path )
{
  if ( m_mapDirs.isEmpty() )
    return 0;

  QString path = _path;

  if ( path.right(1) == "/" )
    path.truncate( path.length() - 1 );

  QMap<QString,Entry>::Iterator it = m_mapDirs.find( path );
  if ( it == m_mapDirs.end() )
    return 0;

  return (*it).m_ctime;
}


kdelibs'KDirWatch::removeDir() (./kdelibs/kio/kdirwatch.cpp:146)

void KDirWatch::removeDir( const QString& _path )
{
  if ( m_mapDirs.isEmpty() )
    return;

  QString path = _path;

  if ( path.right(1) == "/" )
    path.truncate( path.length() - 1 );

  QMap<QString,Entry>::Iterator it = m_mapDirs.find( path );
  if ( it == m_mapDirs.end() )
    return;

  (*it).m_clients--;
  if ( (*it).m_clients > 0 )
    return;

#ifdef USE_FAM
  if (use_fam) {
    FAMCancelMonitor(&fc, &((*it).fr) );
    //    qDebug("KDirWatch deleted: %s (FAMReq %d)", 
    //	   QFile::encodeName(path),  FAMREQUEST_GETREQNUM(&((*it).fr)) );
  }
#endif

  m_mapDirs.remove( it );

#ifdef USE_FAM
  if (!use_fam)
#endif
  if( m_mapDirs.isEmpty() )
    timer->stop(); // stop timer if list empty
}


kdelibs'KDirWatch::stopDirScan() (./kdelibs/kio/kdirwatch.cpp:181)

bool KDirWatch::stopDirScan( const QString& _path )
{
  if ( m_mapDirs.isEmpty() )
    return false;

  QString path = _path;
  if ( path.right(1) == "/" )
    path.truncate( path.length() - 1 );

  QMap<QString,Entry>::Iterator it = m_mapDirs.find( path );
  if ( it == m_mapDirs.end() )
    return false;

  (*it).m_ctime = NO_NOTIFY;

#ifdef USE_FAM
  if (use_fam) {
    FAMSuspendMonitor(&fc, &((*it).fr) );
  }
#endif

  return true;
}


kdelibs'KDirWatch::restartDirScan() (./kdelibs/kio/kdirwatch.cpp:205)

bool KDirWatch::restartDirScan( const QString& _path )
{
  if ( m_mapDirs.isEmpty() )
    return false;

  QString path = _path;
  if ( path.right(1) == "/" )
    path.truncate( path.length() - 1 );

  QMap<QString,Entry>::Iterator it = m_mapDirs.find( path );
  if ( it == m_mapDirs.end() )
    return false;

  stat( QFile::encodeName(path), &statbuff );
  (*it).m_ctime = statbuff.st_ctime;

#ifdef USE_FAM
  if (use_fam) {
    FAMResumeMonitor(&fc, &((*it).fr) );
  }
#endif

  return true;
}


kdelibs'KDirWatch::stopScan() (./kdelibs/kio/kdirwatch.cpp:230)

void KDirWatch::stopScan()
{
#ifdef USE_FAM
  if (use_fam)
    emitEvents = false;
  else
#endif
  timer->stop();
}


kdelibs'KDirWatch::startScan() (./kdelibs/kio/kdirwatch.cpp:240)

void KDirWatch::startScan( bool notify, bool skippedToo )
{
  if (!notify)
    resetList(skippedToo);
#ifdef USE_FAM
  if (use_fam)
    emitEvents = true;
  else
#endif
  timer->start(freq);
}

// Protected:


kdelibs'KDirWatch::resetList() (./kdelibs/kio/kdirwatch.cpp:254)

void KDirWatch::resetList( bool skippedToo )
{
  if ( m_mapDirs.isEmpty() )
    return;

  QMap<QString,Entry>::Iterator it = m_mapDirs.begin();
  for( ; it != m_mapDirs.end(); ++it )
  {
    if ( (*it).m_ctime != NO_NOTIFY || skippedToo )
    {
      stat( QFile::encodeName(it.key()), &statbuff );
      (*it).m_ctime = statbuff.st_ctime;
    }
  }
}


kdelibs'KDirWatch::slotRescan() (./kdelibs/kio/kdirwatch.cpp:270)

void KDirWatch::slotRescan()
{
  QStringList del;

  QMap<QString,Entry>::Iterator it = m_mapDirs.begin();
  for( ; it != m_mapDirs.end(); ++it )
  {
    if ( stat( QFile::encodeName(it.key()), &statbuff ) == -1 )
    {
      kdDebug(7001) << "Deleting " << it.key() << endl;
      emit deleted( it.key() );
      del.append( it.key() );
      continue; // iterator incremented
    }
    if ( statbuff.st_ctime != (*it).m_ctime &&
         (*it).m_ctime != NO_NOTIFY)
    {
      (*it).m_ctime = statbuff.st_ctime;
      qDebug("KDirWatch emitting dirty");
      emit dirty( it.key() );
    }
  }

  QStringList::Iterator it2 = del.begin();
  for( ; it2 != del.end(); ++it2 )
    m_mapDirs.remove( *it2 );
}


kdelibs'KDirWatch::contains() (./kdelibs/kio/kdirwatch.cpp:298)

bool KDirWatch::contains( const QString& _path ) const
{
  QString path = _path;
  if ( path.right(1) == "/" )
    path.truncate( path.length() - 1 );

  return m_mapDirs.contains( path );
}


kdelibs'KDirWatch::setFileDirty() (./kdelibs/kio/kdirwatch.cpp:307)

void KDirWatch::setFileDirty( const QString & _file )
{
  emit fileDirty( _file );
}

kdelibs'KDirWatch::famEventReceived() (./kdelibs/kio/kdirwatch.cpp:313)

void KDirWatch::famEventReceived()
{
  if (!use_fam || !emitEvents) return;
  
  FAMNextEvent(&fc, &fe);

  int reqNum = FAMREQUEST_GETREQNUM(&(fe.fr));

  // Don't be too verbose ;-)
  if (fe.code == FAMExists || fe.code == FAMEndExist) return;

  qDebug("KDirWatch processing FAM event (%s, %s, Req %d)", 
	 (fe.code == FAMChanged) ? "FAMChanged" : 
	 (fe.code == FAMDeleted) ? "FAMDeleted" : 
	 (fe.code == FAMStartExecuting) ? "FAMStartExecuting" : 
	 (fe.code == FAMStopExecuting) ? "FAMStopExecuting" : 
	 (fe.code == FAMCreated) ? "FAMCreated" : 
	 (fe.code == FAMMoved) ? "FAMMoved" : 
	 (fe.code == FAMAcknowledge) ? "FAMAcknowledge" : 
	 (fe.code == FAMExists) ? "FAMExists" : 
	 (fe.code == FAMEndExist) ? "FAMEndExist" : "Unkown Code",
	 &(fe.filename[0]), reqNum );
	 
  if (fe.code == FAMDeleted) {
    QMap<QString,Entry>::Iterator it = m_mapDirs.begin();
    for( ; it != m_mapDirs.end(); ++it )
      if ( FAMREQUEST_GETREQNUM( &((*it).fr) ) == reqNum ) {
	if (fe.filename[0] == '/') {
	  qDebug("KDirWatch emitting deleted");
	  emit deleted ( it.key() );
	  m_mapDirs.remove( it.key() );
	}
	else {
	  qDebug("KDirWatch emitting dirty");
	  emit dirty( it.key() );
	}
	return;
      }
  }
  else if (fe.code == FAMChanged || fe.code == FAMCreated) {
    QMap<QString,Entry>::Iterator it = m_mapDirs.begin();
    for( ; it != m_mapDirs.end(); ++it )
      if ( FAMREQUEST_GETREQNUM( &((*it).fr) ) == reqNum ) {
	qDebug("KDirWatch emitting dirty");
	emit dirty( it.key() );
	return;
      }
  } 
}

kdelibs'KDirWatch::famEventReceived() (./kdelibs/kio/kdirwatch.cpp:363)

void KDirWatch::famEventReceived() {}
#endif

#include "kdirwatch.moc"

//sven