Warning, file /utilities/krusader/app/DiskUsage/filelightParts/fileTree.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2004 Max Howell <max.howell@methylblue.com> 0003 SPDX-FileCopyrightText: 2004-2022 Krusader Krew <https://krusader.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #ifndef FILETREE_H 0009 #define FILETREE_H 0010 0011 #include <QString> 0012 0013 #include <KIO/Global> 0014 0015 #include <stdlib.h> 0016 #include <sys/types.h> 0017 #include <time.h> 0018 #include <unistd.h> 0019 0020 // TODO these are pointlessly general purpose now, make them incredibly specific 0021 0022 typedef KIO::filesize_t FileSize; 0023 0024 template<class T> 0025 class Iterator; 0026 template<class T> 0027 class ConstIterator; 0028 template<class T> 0029 class Chain; 0030 0031 template<class T> 0032 class Link 0033 { 0034 public: 0035 explicit Link(T *const t) 0036 : prev(this) 0037 , next(this) 0038 , data(t) 0039 { 0040 } 0041 Link() 0042 : prev(this) 0043 , next(this) 0044 , data(nullptr) 0045 { 0046 } 0047 0048 // TODO unlinking is slow and you don't use it very much in this context. 0049 // ** Perhaps you can make a faster deletion system that doesn't bother tidying up first 0050 // ** and then you MUST call some kind of detach() function when you remove elements otherwise 0051 ~Link() 0052 { 0053 delete data; 0054 unlink(); 0055 } 0056 0057 friend class Iterator<T>; 0058 friend class ConstIterator<T>; 0059 friend class Chain<T>; 0060 0061 private: 0062 void unlink() 0063 { 0064 prev->next = next; 0065 next->prev = prev; 0066 prev = next = this; 0067 } 0068 0069 Link<T> *prev; 0070 Link<T> *next; 0071 0072 T *data; // ensure only iterators have access to this 0073 }; 0074 0075 template<class T> 0076 class Iterator 0077 { 0078 public: 0079 Iterator() 0080 : link(nullptr) 0081 { 0082 } //**** remove this, remove this REMOVE THIS!!! dangerous as your implementation doesn't test for null links, always assumes they can be dereferenced 0083 explicit Iterator(Link<T> *p) 0084 : link(p) 0085 { 0086 } 0087 0088 bool operator==(const Iterator<T> &it) const 0089 { 0090 return link == it.link; 0091 } 0092 bool operator!=(const Iterator<T> &it) const 0093 { 0094 return link != it.link; 0095 } 0096 bool operator!=(const Link<T> *p) const 0097 { 0098 return p != link; 0099 } 0100 0101 // here we have a choice, really I should make two classes one const the other not 0102 const T *operator*() const 0103 { 0104 return link->data; 0105 } 0106 T *operator*() 0107 { 0108 return link->data; 0109 } 0110 0111 Iterator<T> &operator++() 0112 { 0113 link = link->next; 0114 return *this; 0115 } //**** does it waste time returning in places where we don't use the retval? 0116 0117 bool isNull() const 0118 { 0119 return (link == 0); 0120 } // REMOVE WITH ABOVE REMOVAL you don't want null iterators to be possible 0121 0122 void transferTo(Chain<T> &chain) 0123 { 0124 chain.append(remove()); 0125 } 0126 0127 T *remove() 0128 { // remove from list, delete Link, data is returned NOT deleted 0129 T *const d = link->data; 0130 Link<T> *const p = link->prev; 0131 0132 link->data = nullptr; 0133 delete link; 0134 link = p; // make iterator point to previous element, YOU must check this points to an element 0135 0136 return d; 0137 } 0138 0139 private: 0140 Link<T> *link; 0141 }; 0142 0143 template<class T> 0144 class ConstIterator 0145 { 0146 public: 0147 explicit ConstIterator(Link<T> *p) 0148 : link(p) 0149 { 0150 } 0151 0152 bool operator==(const Iterator<T> &it) const 0153 { 0154 return link == it.link; 0155 } 0156 bool operator!=(const Iterator<T> &it) const 0157 { 0158 return link != it.link; 0159 } 0160 bool operator!=(const Link<T> *p) const 0161 { 0162 return p != link; 0163 } 0164 0165 const T *operator*() const 0166 { 0167 return link->data; 0168 } 0169 0170 ConstIterator<T> &operator++() 0171 { 0172 link = link->next; 0173 return *this; 0174 } 0175 0176 private: 0177 const Link<T> *link; 0178 }; 0179 0180 //**** try to make a generic list class and then a brief full list template that inlines 0181 // thus reducing code bloat 0182 template<class T> 0183 class Chain 0184 { 0185 public: 0186 Chain() 0187 { 0188 } 0189 virtual ~Chain() 0190 { 0191 empty(); 0192 } 0193 0194 void append(T *const data) 0195 { 0196 Link<T> *const link = new Link<T>(data); 0197 0198 link->prev = head.prev; 0199 link->next = &head; 0200 0201 head.prev->next = link; 0202 head.prev = link; 0203 } 0204 0205 void transferTo(Chain &c) 0206 { 0207 if (isEmpty()) 0208 return; 0209 0210 Link<T> *const first = head.next; 0211 Link<T> *const last = head.prev; 0212 0213 head.unlink(); 0214 0215 first->prev = c.head.prev; 0216 c.head.prev->next = first; 0217 0218 last->next = &c.head; 0219 c.head.prev = last; 0220 } 0221 0222 void empty() 0223 { 0224 while (head.next != &head) { 0225 delete head.next; 0226 } 0227 } 0228 0229 Iterator<T> iterator() const 0230 { 0231 return Iterator<T>(head.next); 0232 } 0233 ConstIterator<T> constIterator() const 0234 { 0235 return ConstIterator<T>(head.next); 0236 } 0237 const Link<T> *end() const 0238 { 0239 return &head; 0240 } 0241 bool isEmpty() const 0242 { 0243 return (head.next == &head); 0244 } 0245 0246 private: 0247 Link<T> head; 0248 void operator=(const Chain &) 0249 { 0250 } 0251 }; 0252 0253 class Directory; 0254 0255 class File 0256 { 0257 protected: 0258 Directory *m_parent; // 0 if this is treeRoot 0259 QString m_name; //< file name 0260 QString m_directory; //< the directory of the file 0261 FileSize m_size; //< size with subdirectories 0262 FileSize m_ownSize; //< size without subdirectories 0263 mode_t m_mode; //< file mode 0264 QString m_owner; //< file owner name 0265 QString m_group; //< file group name 0266 QString m_perm; //< file permissions string 0267 time_t m_time; //< file modification in time_t format 0268 bool m_symLink; //< true if the file is a symlink 0269 QString m_mimeType; //< file mimetype 0270 bool m_excluded; //< flag if the file is excluded from du 0271 int m_percent; //< percent flag 0272 0273 public: 0274 File(Directory *parentIn, 0275 const QString &nameIn, 0276 const QString &dir, 0277 FileSize sizeIn, 0278 mode_t modeIn, 0279 const QString &ownerIn, 0280 const QString &groupIn, 0281 const QString &permIn, 0282 time_t timeIn, 0283 bool symLinkIn, 0284 const QString &mimeTypeIn) 0285 : m_parent(parentIn) 0286 , m_name(nameIn) 0287 , m_directory(dir) 0288 , m_size(sizeIn) 0289 , m_ownSize(sizeIn) 0290 , m_mode(modeIn) 0291 , m_owner(ownerIn) 0292 , m_group(groupIn) 0293 , m_perm(permIn) 0294 , m_time(timeIn) 0295 , m_symLink(symLinkIn) 0296 , m_mimeType(mimeTypeIn) 0297 , m_excluded(false) 0298 , m_percent(-1) 0299 { 0300 } 0301 0302 File(const QString &nameIn, FileSize sizeIn) 0303 : m_parent(nullptr) 0304 , m_name(nameIn) 0305 , m_directory(QString()) 0306 , m_size(sizeIn) 0307 , m_ownSize(sizeIn) 0308 , m_mode(0) 0309 , m_owner(QString()) 0310 , m_group(QString()) 0311 , m_perm(QString()) 0312 , m_time(-1) 0313 , m_symLink(false) 0314 , m_mimeType(QString()) 0315 , m_excluded(false) 0316 , m_percent(-1) 0317 { 0318 } 0319 0320 virtual ~File() 0321 { 0322 } 0323 0324 inline const QString &name() const 0325 { 0326 return m_name; 0327 } 0328 inline const QString &directory() const 0329 { 0330 return m_directory; 0331 } 0332 inline FileSize size() const 0333 { 0334 return m_excluded ? 0 : m_size; 0335 } 0336 inline FileSize ownSize() const 0337 { 0338 return m_excluded ? 0 : m_ownSize; 0339 } 0340 inline mode_t mode() const 0341 { 0342 return m_mode; 0343 } 0344 inline const QString &owner() const 0345 { 0346 return m_owner; 0347 } 0348 inline const QString &group() const 0349 { 0350 return m_group; 0351 } 0352 inline const QString &perm() const 0353 { 0354 return m_perm; 0355 } 0356 inline time_t time() const 0357 { 0358 return m_time; 0359 } 0360 inline const QString &mime() const 0361 { 0362 return m_mimeType; 0363 } 0364 inline bool isSymLink() const 0365 { 0366 return m_symLink; 0367 } 0368 virtual bool isDir() const 0369 { 0370 return false; 0371 } 0372 inline bool isExcluded() const 0373 { 0374 return m_excluded; 0375 } 0376 inline void exclude(bool flag) 0377 { 0378 m_excluded = flag; 0379 } 0380 inline int intPercent() const 0381 { 0382 return m_percent; 0383 } 0384 inline const QString percent() const 0385 { 0386 if (m_percent < 0) 0387 return "INV"; 0388 QString buf; 0389 buf.asprintf("%d.%02d%%", m_percent / 100, m_percent % 100); 0390 return buf; 0391 } 0392 inline void setPercent(int p) 0393 { 0394 m_percent = p; 0395 } 0396 inline const Directory *parent() const 0397 { 0398 return m_parent; 0399 } 0400 0401 inline void setSizes(KIO::filesize_t totalSize, KIO::filesize_t ownSize) 0402 { 0403 m_ownSize = ownSize; 0404 m_size = totalSize; 0405 } 0406 0407 enum UnitPrefix { kilo, mega, giga, tera }; 0408 0409 static const FileSize DENOMINATOR[4]; 0410 static const char PREFIX[5][2]; 0411 0412 QString fullPath(const Directory * = nullptr) const; 0413 QString humanReadableSize(UnitPrefix key = mega) const; 0414 0415 static QString humanReadableSize(FileSize size, UnitPrefix Key = mega); 0416 0417 friend class Directory; 0418 }; 0419 0420 // TODO when you modify this to take into account hardlinks you should make the Chain layered not inherited 0421 class Directory : public Chain<File>, public File 0422 { 0423 public: 0424 Directory(Directory *parentIn, 0425 const QString &nameIn, 0426 const QString &dir, 0427 FileSize sizeIn, 0428 mode_t modeIn, 0429 const QString &ownerIn, 0430 const QString &groupIn, 0431 const QString &permIn, 0432 time_t timeIn, 0433 bool symLinkIn, 0434 const QString &mimeTypeIn) 0435 : File(parentIn, nameIn, dir, sizeIn, modeIn, ownerIn, groupIn, permIn, timeIn, symLinkIn, mimeTypeIn) 0436 , m_fileCount(0) 0437 { 0438 } 0439 0440 Directory(const QString &name, QString url) 0441 : File(name, 0) 0442 , m_fileCount(0) 0443 { 0444 m_directory = url; 0445 } 0446 0447 virtual ~Directory() 0448 { 0449 } 0450 virtual bool isDir() const override 0451 { 0452 return true; 0453 } 0454 0455 void append(File *p) 0456 { 0457 ++m_fileCount; 0458 0459 Directory *parent = m_parent; 0460 while (parent) { 0461 parent->m_fileCount++; 0462 parent = parent->m_parent; 0463 } 0464 0465 Chain<File>::append(p); 0466 p->m_parent = this; 0467 } 0468 0469 void remove(File *p) 0470 { 0471 for (Iterator<File> it = Chain<File>::iterator(); it != Chain<File>::end(); ++it) 0472 if ((*it) == p) { 0473 --m_fileCount; 0474 0475 Directory *parent = m_parent; 0476 while (parent) { 0477 parent->m_fileCount--; 0478 parent = parent->m_parent; 0479 } 0480 0481 it.remove(); 0482 break; 0483 } 0484 } 0485 0486 uint fileCount() const 0487 { 0488 return m_fileCount; 0489 } 0490 0491 private: 0492 Directory(const Directory &); 0493 void operator=(const Directory &); 0494 0495 uint m_fileCount; 0496 }; 0497 0498 #endif