File indexing completed on 2024-03-24 05:00:56
0001 /* This file is part of FSView. 0002 SPDX-FileCopyrightText: 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-only 0005 */ 0006 0007 /* 0008 * FSView specialization of TreeMapItem class. 0009 */ 0010 0011 #include "inode.h" 0012 0013 #include <kiconloader.h> 0014 #include <KLocalizedString> 0015 0016 #include <QMimeDatabase> 0017 0018 #include "fsview.h" 0019 #include "fsviewdebug.h" 0020 0021 // Inode 0022 0023 Inode::Inode() 0024 { 0025 _dirPeer = nullptr; 0026 _filePeer = nullptr; 0027 init(QString()); 0028 } 0029 0030 Inode::Inode(ScanDir *d, Inode *parent) 0031 : TreeMapItem(parent) 0032 { 0033 QString absPath; 0034 if (parent) { 0035 absPath = parent->path(); 0036 if (!absPath.endsWith(QLatin1Char('/'))) { 0037 absPath += QLatin1Char('/'); 0038 } 0039 } 0040 absPath += d->name(); 0041 0042 _dirPeer = d; 0043 _filePeer = nullptr; 0044 0045 init(absPath); 0046 } 0047 0048 Inode::Inode(ScanFile *f, Inode *parent) 0049 : TreeMapItem(parent) 0050 { 0051 QString absPath; 0052 if (parent) { 0053 absPath = parent->path() + QLatin1Char('/'); 0054 } 0055 absPath += f->name(); 0056 0057 _dirPeer = nullptr; 0058 _filePeer = f; 0059 0060 init(absPath); 0061 } 0062 0063 Inode::~Inode() 0064 { 0065 if (0) qCDebug(FSVIEWLOG) << "~Inode [" << path() 0066 << "]"; 0067 0068 /* reset Listener of old Peer */ 0069 if (_dirPeer) { 0070 _dirPeer->setListener(nullptr); 0071 } 0072 if (_filePeer) { 0073 _filePeer->setListener(nullptr); 0074 } 0075 } 0076 0077 void Inode::setPeer(ScanDir *d) 0078 { 0079 /* reset Listener of old Peer */ 0080 if (_dirPeer) { 0081 _dirPeer->setListener(nullptr); 0082 } 0083 if (_filePeer) { 0084 _filePeer->setListener(nullptr); 0085 } 0086 0087 _dirPeer = d; 0088 _filePeer = nullptr; 0089 init(d->name()); 0090 } 0091 0092 QString Inode::path() const 0093 { 0094 return _info.absoluteFilePath(); 0095 } 0096 0097 void Inode::init(const QString &path) 0098 { 0099 if (0) qCDebug(FSVIEWLOG) << "Inode::init [" << path 0100 << "]"; 0101 0102 _info = QFileInfo(path); 0103 0104 if (!FSView::getDirMetric(path, _sizeEstimation, 0105 _fileCountEstimation, 0106 _dirCountEstimation)) { 0107 _sizeEstimation = 0.0; 0108 _fileCountEstimation = 0; 0109 _dirCountEstimation = 0; 0110 } 0111 0112 _mimeSet = false; 0113 _mimePixmapSet = false; 0114 _resortNeeded = false; 0115 0116 clear(); 0117 0118 /* we want to get notifications about dir changes */ 0119 if (_dirPeer) { 0120 _dirPeer->setListener(this); 0121 } 0122 if (_filePeer) { 0123 _filePeer->setListener(this); 0124 } 0125 0126 if (_dirPeer && _dirPeer->scanFinished()) { 0127 scanFinished(_dirPeer); 0128 } 0129 } 0130 0131 /* ScanListener interface */ 0132 void Inode::sizeChanged(ScanDir *d) 0133 { 0134 if (0) qCDebug(FSVIEWLOG) << "Inode::sizeChanged [" << path() << "] in " 0135 << d->name() << ": size " << d->size(); 0136 0137 _resortNeeded = true; 0138 } 0139 0140 void Inode::scanFinished(ScanDir *d) 0141 { 0142 if (0) qCDebug(FSVIEWLOG) << "Inode::scanFinished [" << path() << "] in " 0143 << d->name() << ": size " << d->size(); 0144 0145 _resortNeeded = true; 0146 0147 /* no estimation any longer */ 0148 _sizeEstimation = 0.0; 0149 _fileCountEstimation = 0; 0150 _dirCountEstimation = 0; 0151 0152 // cache metrics if "important" (for "/usr" is dd==3) 0153 int dd = ((FSView *)widget())->pathDepth() + depth(); 0154 int files = d->fileCount(); 0155 int dirs = d->dirCount(); 0156 0157 if ((files < 500) && (dirs < 50)) { 0158 if (dd > 4 && (files < 50) && (dirs < 5)) { 0159 return; 0160 } 0161 } 0162 0163 FSView::setDirMetric(path(), d->size(), files, dirs); 0164 } 0165 0166 void Inode::destroyed(ScanDir *d) 0167 { 0168 if (_dirPeer == d) { 0169 _dirPeer = nullptr; 0170 } 0171 0172 // remove children 0173 clear(); 0174 } 0175 0176 void Inode::destroyed(ScanFile *f) 0177 { 0178 if (_filePeer == f) { 0179 _filePeer = nullptr; 0180 } 0181 } 0182 0183 TreeMapItemList *Inode::children() 0184 { 0185 if (!_dirPeer) { 0186 return nullptr; 0187 } 0188 0189 if (!_children) { 0190 if (!_dirPeer->scanStarted()) { 0191 return nullptr; 0192 } 0193 0194 _children = new TreeMapItemList; 0195 0196 setSorting(-1); 0197 0198 ScanFileVector &files = _dirPeer->files(); 0199 if (files.count() > 0) { 0200 ScanFileVector::iterator it; 0201 for (it = files.begin(); it != files.end(); ++it) { 0202 new Inode(&(*it), this); 0203 } 0204 } 0205 0206 ScanDirVector &dirs = _dirPeer->dirs(); 0207 if (dirs.count() > 0) { 0208 ScanDirVector::iterator it; 0209 for (it = dirs.begin(); it != dirs.end(); ++it) { 0210 new Inode(&(*it), this); 0211 } 0212 } 0213 0214 setSorting(-2); 0215 _resortNeeded = false; 0216 } 0217 0218 if (_resortNeeded) { 0219 resort(); 0220 _resortNeeded = false; 0221 } 0222 0223 return _children; 0224 } 0225 0226 double Inode::size() const 0227 { 0228 // sizes of files are always correct 0229 if (_filePeer) { 0230 return _filePeer->size(); 0231 } 0232 if (!_dirPeer) { 0233 return 0; 0234 } 0235 0236 double size = _dirPeer->size(); 0237 return (_sizeEstimation > size) ? _sizeEstimation : size; 0238 } 0239 0240 double Inode::value() const 0241 { 0242 return size(); 0243 } 0244 0245 unsigned int Inode::fileCount() const 0246 { 0247 unsigned int fileCount = 1; 0248 0249 if (_dirPeer) { 0250 fileCount = _dirPeer->fileCount(); 0251 } 0252 0253 if (_fileCountEstimation > fileCount) { 0254 fileCount = _fileCountEstimation; 0255 } 0256 0257 return fileCount; 0258 } 0259 0260 unsigned int Inode::dirCount() const 0261 { 0262 unsigned int dirCount = 0; 0263 0264 if (_dirPeer) { 0265 dirCount = _dirPeer->dirCount(); 0266 } 0267 0268 if (_dirCountEstimation > dirCount) { 0269 dirCount = _dirCountEstimation; 0270 } 0271 0272 return dirCount; 0273 } 0274 0275 QColor Inode::backColor() const 0276 { 0277 QString n; 0278 int id = 0; 0279 0280 switch (((FSView *)widget())->colorMode()) { 0281 case FSView::Depth: { 0282 int d = ((FSView *)widget())->pathDepth() + depth(); 0283 return QColor::fromHsv((100 * d) % 360, 192, 128); 0284 } 0285 0286 case FSView::Name: n = text(0); break; 0287 case FSView::Owner: id = _info.ownerId(); break; 0288 case FSView::Group: id = _info.groupId(); break; 0289 case FSView::Mime: n = text(7); break; 0290 0291 default: 0292 break; 0293 } 0294 0295 if (id > 0) { 0296 n = QString::number(id); 0297 } 0298 0299 if (n.isEmpty()) { 0300 return widget()->palette().button().color(); 0301 } 0302 0303 QByteArray tmpBuf = n.toLocal8Bit(); 0304 const char *str = tmpBuf.data(); 0305 int h = 0, s = 100; 0306 while (*str) { 0307 h = (h * 37 + s * (unsigned) * str) % 256; 0308 s = (s * 17 + h * (unsigned) * str) % 192; 0309 str++; 0310 } 0311 return QColor::fromHsv(h, 64 + s, 192); 0312 } 0313 0314 QMimeType Inode::mimeType() const 0315 { 0316 if (!_mimeSet) { 0317 QMimeDatabase db; 0318 _mimeType = db.mimeTypeForUrl(QUrl::fromLocalFile(path())); 0319 0320 _mimeSet = true; 0321 } 0322 return _mimeType; 0323 } 0324 0325 QString Inode::text(int i) const 0326 { 0327 if (i == 0) { 0328 QString name; 0329 if (_dirPeer) { 0330 name = _dirPeer->name(); 0331 if (!name.endsWith(QLatin1Char('/'))) { 0332 name += QLatin1Char('/'); 0333 } 0334 } else if (_filePeer) { 0335 name = _filePeer->name(); 0336 } 0337 0338 return name; 0339 } 0340 if (i == 1) { 0341 QString text = KIO::convertSize(static_cast<KIO::filesize_t>(size()+0.5)); 0342 if (_sizeEstimation > 0) { 0343 text += QChar::fromLatin1('+'); 0344 } 0345 return text; 0346 } 0347 0348 if ((i == 2) || (i == 3)) { 0349 /* file/dir count makes no sense for files */ 0350 if (_filePeer) { 0351 return QString(); 0352 } 0353 0354 QString text; 0355 unsigned int f = (i == 2) ? fileCount() : dirCount(); 0356 0357 if (f > 0) { 0358 while (f > 1000) { 0359 text = QStringLiteral("%1 %2").arg(QString::number(f).right(3)).arg(text); 0360 f /= 1000; 0361 } 0362 text = QStringLiteral("%1 %2").arg(QString::number(f)).arg(text); 0363 if (_fileCountEstimation > 0) { 0364 text += '+'; 0365 } 0366 } 0367 return text; 0368 } 0369 0370 if (i == 4) { 0371 return _info.lastModified().toString(); 0372 } 0373 if (i == 5) { 0374 return _info.owner(); 0375 } 0376 if (i == 6) { 0377 return _info.group(); 0378 } 0379 if (i == 7) { 0380 return mimeType().comment(); 0381 } 0382 return QString(); 0383 } 0384 0385 QPixmap Inode::pixmap(int i) const 0386 { 0387 if (i != 0) { 0388 return QPixmap(); 0389 } 0390 0391 if (!_mimePixmapSet) { 0392 QUrl u = QUrl::fromLocalFile(path()); 0393 const QIcon icon = QIcon::fromTheme(KIO::iconNameForUrl(u), QIcon::fromTheme(QStringLiteral("application-octet-stream"))); 0394 _mimePixmap = icon.pixmap(KIconLoader::SizeSmall); 0395 _mimePixmapSet = true; 0396 } 0397 return _mimePixmap; 0398 }