summaryrefslogtreecommitdiffstats
path: root/kio/kio/kdirlister_p.h
blob: a98521905e1fa9def70ba9c3c7b2e61a70e4a877 (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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
/* This file is part of the KDE project
   Copyright (C) 2002 Michael Brade <brade@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#ifndef kdirlister_p_h
#define kdirlister_p_h

#include "kfileitem.h"

#include <tqmap.h>
#include <tqdict.h>
#include <tqcache.h>
#include <tqwidget.h>

#include <kurl.h>
#include <kio/global.h>
#include <kdirwatch.h>
#include <dcopclient.h>

class TQTimer;
class KDirLister;
namespace KIO { class Job; class ListJob; }


class KDirLister::KDirListerPrivate
{
public:
  KDirListerPrivate()
  {
    complete = false;

    autoUpdate = false;
    isShowingDotFiles = false;
    dirOnlyMode = false;

    autoErrorHandling = false;
    errorParent = 0;

    delayedMimeTypes = false;

    rootFileItem = 0;
    lstNewItems = 0;
    lstRefreshItems = 0;
    lstMimeFilteredItems = 0;
    lstRemoveItems = 0;
    refreshItemWasFiltered = false;

    changes = NONE;

    window = 0;

    lstFilters.setAutoDelete( true );
    oldFilters.setAutoDelete( true );
  }

  /**
   * List of dirs handled by this dirlister. The first entry is the base URL.
   * For a tree view, it contains all the dirs shown.
   */
  KURL::List lstDirs;

  // toplevel URL
  KURL url;

  bool complete;

  bool autoUpdate;
  bool isShowingDotFiles;
  bool dirOnlyMode;

  bool autoErrorHandling;
  TQWidget *errorParent;

  bool delayedMimeTypes;

  struct JobData {
    long unsigned int percent, speed;
    KIO::filesize_t processedSize, totalSize;
  };

  TQMap<KIO::ListJob *, JobData> jobData;

  // file item for the root itself (".")
  KFileItem *rootFileItem;

  KFileItemList *lstNewItems, *lstRefreshItems;
  KFileItemList *lstMimeFilteredItems, *lstRemoveItems;

  bool refreshItemWasFiltered;

  int changes;

  TQWidget *window; // Main window ths lister is associated with

  TQString nameFilter;
  TQPtrList<TQRegExp> lstFilters, oldFilters;
  TQStringList mimeFilter, oldMimeFilter;
  TQStringList mimeExcludeFilter, oldMimeExcludeFilter;
};

/**
 * Design of the cache:
 * There is a single KDirListerCache for the whole process.
 * It holds all the items used by the dir listers (itemsInUse)
 * as well as a cache of the recently used items (itemsCached).
 * Those items are grouped by directory (a DirItem represents a whole directory).
 *
 * KDirListerCache also runs all the jobs for listing directories, whether they are for
 * normal listing or for updates.
 * For faster lookups, it also stores two dicts:
 * a URL -> dirlister holding that URL (urlsCurrentlyHeld)
 * a URL -> dirlister currently listing that URL (urlsCurrentlyListed)
 */
class KDirListerCache : public TQObject, KDirNotify
{
  Q_OBJECT
public:
  KDirListerCache( int maxCount = 10 );
  ~KDirListerCache();

  bool listDir( KDirLister *lister, const KURL& _url, bool _keep, bool _reload );
  bool validURL( const KDirLister *lister, const KURL& _url ) const;

  // stop all running jobs for lister
  void stop( KDirLister *lister );
  // stop just the job listing url for lister
  void stop( KDirLister *lister, const KURL &_url );

  void setAutoUpdate( KDirLister *lister, bool enable );

  void forgetDirs( KDirLister *lister );
  void forgetDirs( KDirLister *lister, const KURL &_url, bool notify );

  void updateDirectory( const KURL &_dir );

  KFileItemList *itemsForDir( const KURL &_dir ) const;

  KFileItem *findByName( const KDirLister *lister, const TQString &_name ) const;
  // if lister is set, it is checked that the url is held by the lister
  KFileItem *findByURL( const KDirLister *lister, const KURL &_url ) const;

  /**
   * Notify that files have been added in @p directory
   * The receiver will list that directory again to find
   * the new items (since it needs more than just the names anyway).
   * Reimplemented from KDirNotify.
   */
  virtual void FilesAdded( const KURL &directory );

  /**
   * Notify that files have been deleted.
   * This call passes the exact urls of the deleted files
   * so that any view showing them can simply remove them
   * or be closed (if its current dir was deleted)
   * Reimplemented from KDirNotify.
   */
  virtual void FilesRemoved( const KURL::List &fileList );

  /**
   * Notify that files have been changed.
   * At the moment, this is only used for new icon, but it could be
   * used for size etc. as well.
   * Note: this is ASYNC so that it can be used with a broadcast
   */
  virtual void FilesChanged( const KURL::List &fileList );
  virtual void FileRenamed( const KURL &src, const KURL &dst );

  static KDirListerCache *self();

  static bool exists(); 

private slots:
  void slotFileDirty( const TQString &_file );
  void slotFileCreated( const TQString &_file );
  void slotFileDeleted( const TQString &_file );

  void slotFileDirtyDelayed();

  void slotEntries( KIO::Job *job, const KIO::UDSEntryList &entries );
  void slotResult( KIO::Job *j );
  void slotRedirection( KIO::Job *job, const KURL &url );

  void slotUpdateEntries( KIO::Job *job, const KIO::UDSEntryList &entries );
  void slotUpdateResult( KIO::Job *job );

private:
  KIO::ListJob *jobForUrl( const TQString& url, KIO::ListJob *not_job = 0 );
  const KURL& joburl( KIO::ListJob *job );

  void killJob( KIO::ListJob *job );

  // check if _url is held by some lister and return true,
  // otherwise schedule a delayed update and return false
  bool checkUpdate( const TQString& _url );
  // when there were items deleted from the filesystem all the listers holding
  // the parent directory need to be notified, the unmarked items have to be deleted
  // and removed from the cache including all the childs.
  void deleteUnmarkedItems( TQPtrList<KDirLister> *, KFileItemList * );
  void processPendingUpdates();
  // common for slotRedirection and FileRenamed
  void renameDir( const KURL &oldUrl, const KURL &url );
  // common for deleteUnmarkedItems and FilesRemoved
  void deleteDir( const KURL& dirUrl );
  // remove directory from cache (itemsCached), including all child dirs
  void removeDirFromCache( const KURL& dir );
  // helper for renameDir
  void emitRedirections( const KURL &oldUrl, const KURL &url );

  void aboutToRefreshItem( KFileItem *fileitem );
  void emitRefreshItem( KFileItem *fileitem );

#ifndef NDEBUG
  void printDebug();
#endif

  struct DirItem
  {
    DirItem( const KURL &dir )
      : url(dir), rootItem(0), lstItems(new KFileItemList)
    {
      autoUpdates = 0;
      complete = false;
      lstItems->setAutoDelete( true );
    }

    ~DirItem()
    {
      if ( autoUpdates )
      {
        if ( KDirWatch::exists() && url.isLocalFile() )
          kdirwatch->removeDir( url.path() );
        sendSignal( false, url );
      }
      delete rootItem;
      delete lstItems;
    }
    
    void sendSignal( bool entering, const KURL& url )
    {
      DCOPClient *client = DCOPClient::mainClient();
      if ( !client )
        return;
      TQByteArray data;
      TQDataStream arg( data, IO_WriteOnly );
      arg << url;
      client->emitDCOPSignal( "KDirNotify", entering ? "enteredDirectory(KURL)" : "leftDirectory(KURL)", data );
    }

    void redirect( const KURL& newUrl )
    {
      if ( autoUpdates )
      {
        if ( url.isLocalFile() )
          kdirwatch->removeDir( url.path() );
        sendSignal( false, url );

        if ( newUrl.isLocalFile() )
          kdirwatch->addDir( newUrl.path() );
        sendSignal( true, newUrl );
      }

      url = newUrl;

      if ( rootItem )
        rootItem->setURL( newUrl );
    }

    void incAutoUpdate()
    {
      if ( autoUpdates++ == 0 )
      { 
        if ( url.isLocalFile() )
          kdirwatch->addDir( url.path() );
        sendSignal( true, url );
      }
    }

    void decAutoUpdate()
    {
      if ( --autoUpdates == 0 )
      {
        if ( url.isLocalFile() )
          kdirwatch->removeDir( url.path() );
        sendSignal( false, url );
      }

      else if ( autoUpdates < 0 )
        autoUpdates = 0;
    }

    // number of KDirListers using autoUpdate for this dir
    short autoUpdates;

    // this directory is up-to-date
    bool complete;

    // the complete url of this directory
    KURL url;

    // KFileItem representing the root of this directory.
    // Remember that this is optional. FTP sites don't return '.' in
    // the list, so they give no root item
    KFileItem *rootItem;
    KFileItemList *lstItems;
  };

  static const unsigned short MAX_JOBS_PER_LISTER;
  TQMap<KIO::ListJob *, KIO::UDSEntryList> jobs;

  // an item is a complete directory
  TQDict<DirItem> itemsInUse;
  TQCache<DirItem> itemsCached;

  // A lister can be EITHER in urlsCurrentlyListed OR urlsCurrentlyHeld but NOT
  // in both at the same time.
  //     On the other hand there can be some listers in urlsCurrentlyHeld
  // and some in urlsCurrentlyListed for the same url!
  // Or differently said, there can be an entry for url in urlsCurrentlyListed
  // and urlsCurrentlyHeld. This happens if more listers are requesting url at
  // the same time and one lister was stopped during the listing of files.

  // saves all urls that are currently being listed and maps them
  // to their KDirListers
  TQDict< TQPtrList<KDirLister> > urlsCurrentlyListed;

  // saves all KDirListers that are just holding url
  TQDict< TQPtrList<KDirLister> > urlsCurrentlyHeld;

  // running timers for the delayed update
  TQDict<TQTimer> pendingUpdates;

  static KDirListerCache *s_pSelf;
};

const unsigned short KDirListerCache::MAX_JOBS_PER_LISTER = 5;

#define s_pCache KDirListerCache::self()

#endif