/* This file is part of FSView. Copyright (C) 2002, 2003 Josef Weidendorfer KCachegrind is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * FSView specialisaton of TreeMap classes. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "fsview.h" // FSView TQMap FSView::_dirMetric; FSView::FSView(Inode* base, TQWidget* parent, const char* name) : TreeMapWidget(base, parent, name) { setFieldType(0, i18n("Name")); setFieldType(1, i18n("Size")); setFieldType(2, i18n("File Count")); setFieldType(3, i18n("Directory Count")); setFieldType(4, i18n("Last Modified")); setFieldType(5, i18n("Owner")); setFieldType(6, i18n("Group")); setFieldType(7, i18n("Mime Type")); // defaults setVisibleWidth(4, true); setSplitMode(TreeMapItem::Rows); setFieldForced(0, true); // show directory names setFieldForced(1, true); // show directory sizes setSelectionMode(TreeMapWidget::Extended); _colorMode = Depth; _pathDepth = 0; _allowRefresh = true; _progressPhase = 0; _chunkData1 = 0; _chunkData2 = 0; _chunkData3 = 0; _chunkSize1 = 0; _chunkSize2 = 0; _chunkSize3 = 0; _progressSize = 0; _progress = 0; _dirsFinished = 0; _lastDir = 0; _config = new KConfig("fsviewrc"); // restore TreeMap visualization options of last execution KConfigGroup tmconfig(_config, TQCString("TreeMap")); restoreOptions(&tmconfig); TQString str = tmconfig.readEntry("ColorMode"); if (!str.isEmpty()) setColorMode(str); if (_dirMetric.count() == 0) { // restore metric cache KConfigGroup cconfig(_config, TQCString("MetricCache")); int ccount = cconfig.readNumEntry("Count", 0); int i, f, d; double s; TQString str; for (i=1;i<=ccount;i++) { str = TQString("Dir%1").arg(i); if (!cconfig.hasKey(str)) continue; str = cconfig.readPathEntry(str); s = cconfig.readDoubleNumEntry(TQString("Size%1").arg(i), 0.0); f = cconfig.readNumEntry(TQString("Files%1").arg(i), 0); d = cconfig.readNumEntry(TQString("Dirs%1").arg(i), 0); if (s==0.0 || f==0 || d==0) continue; setDirMetric(str, s, f, d); } } _sm.setListener(this); } FSView::~FSView() { delete _config; } void FSView::stop() { _sm.stopScan(); } void FSView::setPath(TQString p) { Inode* b = (Inode*)base(); if (!b) return; //kdDebug(90100) << "FSView::setPath " << p << endl; // stop any previous updating stop(); TQFileInfo fi(p); _path = fi.absFilePath(); if (!fi.isDir()) { _path = fi.dirPath(true); } _pathDepth = _path.contains('/'); KURL u; u.setPath(_path); if (!kapp->authorizeURLAction("list", KURL(), u)) { TQString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, u.prettyURL()); KMessageBox::queuedMessageBox(this, KMessageBox::Sorry, msg); } ScanDir* d = _sm.setTop(_path); b->setPeer(d); setCaption(TQString("%1 - FSView").arg(_path)); requestUpdate(b); } KURL::List FSView::selectedUrls() { TreeMapItemList s = selection(); TreeMapItem* i; KURL::List urls; for(i=s.first();i;i=s.next()) { KURL u; u.setPath( ((Inode*)i)->path() ); urls.append(u); } return urls; } bool FSView::getDirMetric(const TQString& k, double& s, unsigned int& f, unsigned int& d) { TQMap::iterator it; it = _dirMetric.find(k); if (it == _dirMetric.end()) return false; s = (*it).size; f = (*it).fileCount; d = (*it).dirCount; if (0) kdDebug(90100) << "getDirMetric " << k << endl; if (0) kdDebug(90100) << " - got size " << s << ", files " << f << endl; return true; } void FSView::setDirMetric(const TQString& k, double s, unsigned int f, unsigned int d) { if (0) kdDebug(90100) << "setDirMetric '" << k << "': size " << s << ", files " << f << ", dirs " << d << endl; _dirMetric.insert(k, MetricEntry(s, f, d)); } void FSView::requestUpdate(Inode* i) { if (0) kdDebug(90100) << "FSView::requestUpdate(" << i->path() << ")" << endl; ScanDir* peer = i->dirPeer(); if (!peer) return; peer->clear(); i->clear(); if (!_sm.scanRunning()) { TQTimer::singleShot(0, this, TQT_SLOT(doUpdate())); TQTimer::singleShot(100, this, TQT_SLOT(doRedraw())); /* start new progress chunk */ _progressPhase = 1; _chunkData1 += 3; _chunkData2 = _chunkData1 + 1; _chunkData3 = _chunkData1 + 2; _chunkSize1 = 0; _chunkSize2 = 0; _chunkSize3 = 0; peer->setData(_chunkData1); _progressSize = 0; _progress = 0; _dirsFinished = 0; _lastDir = 0; emit started(); } _sm.startScan(peer); } void FSView::scanFinished(ScanDir* d) { /* if finished directory was from last progress chunk, increment */ int data = d->data(); switch(_progressPhase) { case 1: if (data == _chunkData1) _chunkSize1--; break; case 2: if (data == _chunkData1) _progress++; if (data == _chunkData2) _chunkSize2--; break; case 3: if ((data == _chunkData1) || (data == _chunkData2)) _progress++; if (data == _chunkData3) _chunkSize3--; break; case 4: if ((data == _chunkData1) || (data == _chunkData2) || (data == _chunkData3)) _progress++; break; default: break; } _lastDir = d; _dirsFinished++; if (0) kdDebug(90100) << "FSFiew::scanFinished: " << d->path() << ", Data " << data << ", Progress " << _progress << "/" << _progressSize << endl; } void FSView::selected(TreeMapItem* i) { setPath(((Inode*)i)->path()); } void FSView::contextMenu(TreeMapItem* i, const TQPoint& p) { TQPopupMenu popup; TQPopupMenu* spopup = new TQPopupMenu(); TQPopupMenu* dpopup = new TQPopupMenu(); TQPopupMenu* apopup = new TQPopupMenu(); TQPopupMenu* fpopup = new TQPopupMenu(); // choosing from the selection menu will give a selectionChanged() signal addSelectionItems(spopup, 901, i); popup.insertItem(i18n("Go To"), spopup, 900); popup.insertItem(i18n("Go Up"), 2); popup.insertSeparator(); popup.insertItem(i18n("Stop Refresh"), 3); popup.setItemEnabled(3, _sm.scanRunning()); popup.insertItem(i18n("Refresh"), 5); popup.setItemEnabled(5, !_sm.scanRunning()); if (i) popup.insertItem(i18n("Refresh '%1'").arg(i->text(0)), 4); popup.insertSeparator(); addDepthStopItems(dpopup, 1001, i); popup.insertItem(i18n("Stop at Depth"), dpopup, 1000); addAreaStopItems(apopup, 1101, i); popup.insertItem(i18n("Stop at Area"), apopup, 1100); addFieldStopItems(fpopup, 1201, i); popup.insertItem(i18n("Stop at Name"), fpopup, 1200); popup.insertSeparator(); TQPopupMenu* cpopup = new TQPopupMenu(); addColorItems(cpopup, 1401); popup.insertItem(i18n("Color Mode"), cpopup, 1400); TQPopupMenu* vpopup = new TQPopupMenu(); addVisualizationItems(vpopup, 1301); popup.insertItem(i18n("Visualization"), vpopup, 1300); _allowRefresh = false; int r = popup.exec(mapToGlobal(p)); _allowRefresh = true; if (r==1) selected(i); else if (r==2) { Inode* i = (Inode*) base(); if (i) setPath(i->path()+"/.."); } else if (r==3) stop(); else if (r==4) { //((Inode*)i)->refresh(); requestUpdate( (Inode*)i ); } else if (r==5) { Inode* i = (Inode*) base(); if (i) requestUpdate(i); } } void FSView::saveMetric(KConfigGroup* g) { TQMap::iterator it; int c = 1; for (it=_dirMetric.begin();it!=_dirMetric.end();++it) { g->writePathEntry(TQString("Dir%1").arg(c), it.key()); g->writeEntry(TQString("Size%1").arg(c), (*it).size); g->writeEntry(TQString("Files%1").arg(c), (*it).fileCount); g->writeEntry(TQString("Dirs%1").arg(c), (*it).dirCount); c++; } g->writeEntry("Count", c-1); } void FSView::setColorMode(FSView::ColorMode cm) { if (_colorMode == cm) return; _colorMode = cm; redraw(); } bool FSView::setColorMode(TQString mode) { if (mode == "None") setColorMode(None); else if (mode == "Depth") setColorMode(Depth); else if (mode == "Name") setColorMode(Name); else if (mode == "Owner") setColorMode(Owner); else if (mode == "Group") setColorMode(Group); else if (mode == "Mime") setColorMode(Mime); else return false; return true; } TQString FSView::colorModeString() const { TQString mode; switch(_colorMode) { case None: mode = "None"; break; case Depth: mode = "Depth"; break; case Name: mode = "Name"; break; case Owner: mode = "Owner"; break; case Group: mode = "Group"; break; case Mime: mode = "Mime"; break; default: mode = "Unknown"; break; } return mode; } void FSView::addColorItems(TQPopupMenu* popup, int id) { _colorID = id; popup->setCheckable(true); connect(popup, TQT_SIGNAL(activated(int)), this, TQT_SLOT(colorActivated(int))); popup->insertItem(i18n("None"), id); popup->insertItem(i18n("Depth"), id+1); popup->insertItem(i18n("Name"), id+2); popup->insertItem(i18n("Owner"), id+3); popup->insertItem(i18n("Group"), id+4); popup->insertItem(i18n("Mime Type"), id+5); switch(colorMode()) { case None: popup->setItemChecked(id,true); break; case Depth: popup->setItemChecked(id+1,true); break; case Name: popup->setItemChecked(id+2,true); break; case Owner: popup->setItemChecked(id+3,true); break; case Group: popup->setItemChecked(id+4,true); break; case Mime: popup->setItemChecked(id+5,true); break; default: break; } } void FSView::colorActivated(int id) { if (id == _colorID) setColorMode(None); else if (id == _colorID+1) setColorMode(Depth); else if (id == _colorID+2) setColorMode(Name); else if (id == _colorID+3) setColorMode(Owner); else if (id == _colorID+4) setColorMode(Group); else if (id == _colorID+5) setColorMode(Mime); } void FSView::saveFSOptions() { KConfigGroup tmconfig(_config, TQCString("TreeMap")); saveOptions(&tmconfig); tmconfig.writeEntry("ColorMode", colorModeString()); KConfigGroup gconfig(_config, TQCString("General")); gconfig.writeEntry("Path", _path); KConfigGroup cconfig(_config, TQCString("MetricCache")); saveMetric(&cconfig); } void FSView::quit() { saveFSOptions(); TDEApplication::kApplication()->quit(); } void FSView::doRedraw() { // we update progress every 1/4 second, and redraw every second static int redrawCounter = 0; bool redo = _sm.scanRunning(); if (!redo) redrawCounter = 0; if ((_progress>0) && (_progressSize>0) && _lastDir) { int percent = _progress * 100 / _progressSize; if (0) kdDebug(90100) << "FSView::progress " << _progress << "/" << _progressSize << "= " << percent << "%, " << _dirsFinished << " dirs read, in " << _lastDir->path() << endl; emit progress(percent, _dirsFinished, _lastDir->path()); } if (_allowRefresh && ((redrawCounter%4)==0)) { if (0) kdDebug(90100) << "doRedraw " << _sm.scanLength() << endl; redraw(); } else redo = true; if (redo) { TQTimer::singleShot(500, this, TQT_SLOT(doRedraw())); redrawCounter++; } } void FSView::doUpdate() { for(int i=0;i<5;i++) { switch(_progressPhase) { case 1: _chunkSize1 += _sm.scan(_chunkData1); if (_chunkSize1 > 100) { _progressPhase = 2; /* Go to maximally 33% by scaling with 3 */ _progressSize = 3 * _chunkSize1; if (1) kdDebug(90100) << "Phase 2: CSize " << _chunkSize1 << endl; } break; case 2: /* progress phase 2 */ _chunkSize2 += _sm.scan(_chunkData2); /* switch to Phase 3 if we reach 80 % of Phase 2 */ if (_progress * 3 > _progressSize * 8/10) { _progressPhase = 3; /* Goal: Keep percentage equal from phase 2 to 3 */ double percent = (double)_progress / _progressSize; /* We scale by factor 2/3 aferwards */ percent = percent * 3/2; int todo = _chunkSize2 + (_progressSize/3 - _progress); _progressSize = (int) ((double)todo / (1.0 - percent)); _progress = _progressSize - todo; /* Go to maximally 66% by scaling with 1.5 */ _progressSize = _progressSize *3/2; if (1) kdDebug(90100) << "Phase 3: CSize " << _chunkSize2 << ", Todo " << todo << ", Progress " << _progress << "/" << _progressSize << endl; } break; case 3: /* progress phase 3 */ _chunkSize3 += _sm.scan(_chunkData3); /* switch to Phase 4 if we reach 80 % of Phase 3 */ if (_progress * 3/2 > _progressSize * 8/10) { _progressPhase = 4; /* Goal: Keep percentage equal from phase 2 to 3 */ double percent = (double)_progress / _progressSize; int todo = _chunkSize3 + (_progressSize*2/3 - _progress); _progressSize = (int)((double)todo / (1.0 - percent) + .5); _progress = _progressSize - todo; if (1) kdDebug(90100) << "Phase 4: CSize " << _chunkSize3 << ", Todo " << todo << ", Progress " << _progress << "/" << _progressSize << endl; } default: _sm.scan(-1); break; } } if (_sm.scanRunning()) TQTimer::singleShot(0, this, TQT_SLOT(doUpdate())); else emit completed(_dirsFinished); } #include "fsview.moc"