summaryrefslogtreecommitdiffstats
path: root/konq-plugins/fsview/fsview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'konq-plugins/fsview/fsview.cpp')
-rw-r--r--konq-plugins/fsview/fsview.cpp540
1 files changed, 540 insertions, 0 deletions
diff --git a/konq-plugins/fsview/fsview.cpp b/konq-plugins/fsview/fsview.cpp
new file mode 100644
index 0000000..b0c82d8
--- /dev/null
+++ b/konq-plugins/fsview/fsview.cpp
@@ -0,0 +1,540 @@
+/* This file is part of FSView.
+ Copyright (C) 2002, 2003 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ 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 <qdir.h>
+#include <qpopupmenu.h>
+#include <qtimer.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+#include <kurl.h>
+
+#include <kio/global.h>
+
+#include "fsview.h"
+
+
+// FSView
+
+QMap<QString, MetricEntry> FSView::_dirMetric;
+
+FSView::FSView(Inode* base, QWidget* 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, QCString("TreeMap"));
+ restoreOptions(&tmconfig);
+ QString str = tmconfig.readEntry("ColorMode");
+ if (!str.isEmpty()) setColorMode(str);
+
+ if (_dirMetric.count() == 0) {
+ // restore metric cache
+ KConfigGroup cconfig(_config, QCString("MetricCache"));
+ int ccount = cconfig.readNumEntry("Count", 0);
+ int i, f, d;
+ double s;
+ QString str;
+ for (i=1;i<=ccount;i++) {
+ str = QString("Dir%1").arg(i);
+ if (!cconfig.hasKey(str)) continue;
+ str = cconfig.readPathEntry(str);
+ s = cconfig.readDoubleNumEntry(QString("Size%1").arg(i), 0.0);
+ f = cconfig.readNumEntry(QString("Files%1").arg(i), 0);
+ d = cconfig.readNumEntry(QString("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(QString p)
+{
+ Inode* b = (Inode*)base();
+ if (!b) return;
+
+ //kdDebug(90100) << "FSView::setPath " << p << endl;
+
+ // stop any previous updating
+ stop();
+
+ QFileInfo 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))
+ {
+ QString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, u.prettyURL());
+ KMessageBox::queuedMessageBox(this, KMessageBox::Sorry, msg);
+ }
+
+ ScanDir* d = _sm.setTop(_path);
+
+ b->setPeer(d);
+
+ setCaption(QString("%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 QString& k,
+ double& s, unsigned int& f, unsigned int& d)
+{
+ QMap<QString, MetricEntry>::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 QString& 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()) {
+ QTimer::singleShot(0, this, SLOT(doUpdate()));
+ QTimer::singleShot(100, this, 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 QPoint& p)
+{
+ QPopupMenu popup;
+
+ QPopupMenu* spopup = new QPopupMenu();
+ QPopupMenu* dpopup = new QPopupMenu();
+ QPopupMenu* apopup = new QPopupMenu();
+ QPopupMenu* fpopup = new QPopupMenu();
+
+ // 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();
+
+ QPopupMenu* cpopup = new QPopupMenu();
+ addColorItems(cpopup, 1401);
+ popup.insertItem(i18n("Color Mode"), cpopup, 1400);
+ QPopupMenu* vpopup = new QPopupMenu();
+ 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)
+{
+ QMap<QString, MetricEntry>::iterator it;
+ int c = 1;
+ for (it=_dirMetric.begin();it!=_dirMetric.end();++it) {
+ g->writePathEntry(QString("Dir%1").arg(c), it.key());
+ g->writeEntry(QString("Size%1").arg(c), (*it).size);
+ g->writeEntry(QString("Files%1").arg(c), (*it).fileCount);
+ g->writeEntry(QString("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(QString 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;
+}
+
+QString FSView::colorModeString() const
+{
+ QString 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(QPopupMenu* popup, int id)
+{
+ _colorID = id;
+ popup->setCheckable(true);
+
+ connect(popup, SIGNAL(activated(int)),
+ this, 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, QCString("TreeMap"));
+ saveOptions(&tmconfig);
+ tmconfig.writeEntry("ColorMode", colorModeString());
+
+ KConfigGroup gconfig(_config, QCString("General"));
+ gconfig.writeEntry("Path", _path);
+
+ KConfigGroup cconfig(_config, QCString("MetricCache"));
+ saveMetric(&cconfig);
+}
+
+void FSView::quit()
+{
+ saveFSOptions();
+ KApplication::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) {
+ QTimer::singleShot(500, this, 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())
+ QTimer::singleShot(0, this, SLOT(doUpdate()));
+ else
+ emit completed(_dirsFinished);
+}
+
+#include "fsview.moc"