summaryrefslogtreecommitdiffstats
path: root/src/part/scan.cpp
blob: 2101624dacf0085c3501af5c501eddf8c942593e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
//Author:    Max Howell <max.howell@methylblue.com>, (C) 2003-4
//Copyright: See COPYING file that comes with this distribution

#include "debug.h"
#include "fileTree.h"
#include <kcursor.h>
#include "localLister.h"
#include <qapplication.h>
#include "remoteLister.h"
#include "scan.h"


namespace Filelight
{
   bool ScanManager::s_abort = false;
   uint ScanManager::s_files = 0;

   ScanManager::ScanManager( QObject *parent )
      : QObject( parent )
      , m_thread( 0 )
      , m_cache( new Chain<Directory> )
   {
      Filelight::LocalLister::readMounts();
   }

   ScanManager::~ScanManager()
   {
      if( m_thread ) {
         debug() << "Attempting to abort scan operation...\n";
         s_abort = true;
         m_thread->wait();
      }

      delete m_cache;

      //RemoteListers are QObjects and get automatically deleted
   }

   bool
   ScanManager::running() const
   {
      //FIXME not complete
      return m_thread && m_thread->running();
   }

   bool
   ScanManager::start( const KURL &url )
   {
      //url is guarenteed clean and safe

      debug() << "Scan requested for: " << url.prettyURL() << endl;

      if( running() ) {
         //shouldn't happen, but lets prevent mega-disasters just in case eh?
         kdWarning() << "Attempted to run 2 scans concurrently!\n";
         //TODO give user an error
         return false;
      }

      s_files = 0;
      s_abort = false;

      if( url.protocol() == "file" )
      {
         const QString path = url.path( 1 );

         Chain<Directory> *trees = new Chain<Directory>;

         /* CHECK CACHE
         *   user wants: /usr/local/
         *   cached:     /usr/
         *
         *   user wants: /usr/
         *   cached:     /usr/local/, /usr/include/
         */

         for( Iterator<Directory> it = m_cache->iterator(); it != m_cache->end(); ++it )
         {
            QString cachePath = (*it)->name();

            if( path.startsWith( cachePath ) ) //then whole tree already scanned
            {
               //find a pointer to the requested branch

               debug() << "Cache-(a)hit: " << cachePath << endl;

               QStringList split = QStringList::split( '/', path.mid( cachePath.length() ) );
               Directory *d = *it;
               Iterator<File> jt;

               while( !split.isEmpty() && d != NULL ) //if NULL we have got lost so abort!!
               {
                  jt = d->iterator();

                  const Link<File> *end = d->end();
                  QString s = split.first(); s += '/';

                  for( d = 0; jt != end; ++jt )
                  if( s == (*jt)->name() )
                  {
                     d = (Directory*)*jt;
                     break;
                  }

                  split.pop_front();
               }

               if( d )
               {
                  delete trees;

                  //we found a completed tree, thus no need to scan
                  debug() << "Found cache-handle, generating map..\n";

                  //1001 indicates that this should not be cached
                  QCustomEvent *e = new QCustomEvent( 1001 );
                  e->setData( d );
                  QApplication::postEvent( this, e );

                  return true;
               }
               else
               {
                  //something went wrong, we couldn't find the directory we were expecting
                  error() << "Didn't find " << path << " in the cache!\n";
                  delete it.remove(); //safest to get rid of it
                  break; //do a full scan
               }
            }
            else if( cachePath.startsWith( path ) ) //then part of the requested tree is already scanned
            {
               debug() << "Cache-(b)hit: " << cachePath << endl;
               it.transferTo( *trees );
            }
         }

         m_url.setPath( path ); //FIXME stop switching between paths and KURLs all the time
         QApplication::setOverrideCursor( KCursor::workingCursor() );
         //starts listing by itself
         m_thread = new Filelight::LocalLister( path, trees, this );
         return true;
      }

      m_url = url;
      QApplication::setOverrideCursor( KCursor::workingCursor() );
      //will start listing straight away
      QObject *o = new Filelight::RemoteLister( url, (QWidget*)parent() );
      insertChild( o );
      o->setName( "remote_lister" );
      return true;
   }

   bool
   ScanManager::abort()
   {
      s_abort = true;

      delete child( "remote_lister" );

      return m_thread && m_thread->running();
   }

   void
   ScanManager::emptyCache()
   {
      s_abort = true;

      if( m_thread && m_thread->running() )
         m_thread->wait();

      emit aboutToEmptyCache();

      m_cache->empty();
   }

   void
   ScanManager::customEvent( QCustomEvent *e )
   {
      Directory *tree = (Directory*)e->data();

      if( m_thread ) {
          m_thread->terminate();
          m_thread->wait();
          delete m_thread; //note the lister deletes itself
          m_thread = 0;
      }

      emit completed( tree );

      if( tree ) {
         //we don't cache foreign stuff
         //we don't recache stuff (thus only type 1000 events)
         if( e->type() == 1000 && m_url.protocol() == "file" )
            //TODO sanity check the cache
            m_cache->append( tree );
      }
      else //scan failed
         m_cache->empty(); //FIXME this is safe but annoying

      QApplication::restoreOverrideCursor();
   }
}

#include "scan.moc"