|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The KPart embedding the FSView widget
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <tqclipboard.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <tqwhatsthis.h>
|
|
|
|
|
|
|
|
#include <kinstance.h>
|
|
|
|
#include <tdefiledialog.h>
|
|
|
|
#include <tdefileitem.h>
|
|
|
|
#include <tdeparts/genericfactory.h>
|
|
|
|
#include <tdeapplication.h>
|
|
|
|
#include <tdeaboutdata.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <tdeaction.h>
|
|
|
|
#include <tdepopupmenu.h>
|
|
|
|
#include <tdeglobalsettings.h>
|
|
|
|
#include <kprotocolinfo.h>
|
|
|
|
#include <tdeio/job.h>
|
|
|
|
#include <tdemessagebox.h>
|
|
|
|
|
|
|
|
// from tdebase/libkonq...
|
|
|
|
#include <konq_operations.h>
|
|
|
|
#include <konq_drag.h>
|
|
|
|
|
|
|
|
#include "fsview_part.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef KParts::GenericFactory<FSViewPart> FSViewPartFactory;
|
|
|
|
K_EXPORT_COMPONENT_FACTORY( libfsviewpart, FSViewPartFactory )
|
|
|
|
|
|
|
|
|
|
|
|
// FSJob, for progress
|
|
|
|
|
|
|
|
FSJob::FSJob(FSView* v)
|
|
|
|
: TDEIO::Job(false)
|
|
|
|
{
|
|
|
|
_view = v;
|
|
|
|
TQObject::connect(v, TQ_SIGNAL(progress(int,int,const TQString&)),
|
|
|
|
this, TQ_SLOT(progressSlot(int,int,const TQString&)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSJob::kill(bool quietly)
|
|
|
|
{
|
|
|
|
_view->stop();
|
|
|
|
|
|
|
|
Job::kill(quietly);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSJob::progressSlot(int percent, int dirs, const TQString& cDir)
|
|
|
|
{
|
|
|
|
if (percent<100) {
|
|
|
|
emitPercent(percent, 100);
|
|
|
|
slotInfoMessage(this, i18n("Read 1 folder, in %1",
|
|
|
|
"Read %n folders, in %1",
|
|
|
|
dirs ).arg(cDir));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
slotInfoMessage(this, i18n("1 folder", "%n folders", dirs));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// FSViewPart
|
|
|
|
|
|
|
|
TDEAboutData* FSViewPart::createAboutData()
|
|
|
|
{
|
|
|
|
TDEAboutData* aboutData;
|
|
|
|
aboutData = new TDEAboutData("fsview", I18N_NOOP("FSView"), "0.1.1",
|
|
|
|
I18N_NOOP("Filesystem Utilization Viewer"),
|
|
|
|
TDEAboutData::License_GPL,
|
|
|
|
I18N_NOOP("(c) 2003-2005, Josef Weidendorfer"));
|
|
|
|
return aboutData;
|
|
|
|
}
|
|
|
|
|
|
|
|
FSViewPart::FSViewPart(TQWidget *parentWidget, const char *widgetName,
|
|
|
|
TQObject *parent, const char *name,
|
|
|
|
const TQStringList& /* args */)
|
|
|
|
: KParts::ReadOnlyPart(parent, name)
|
|
|
|
{
|
|
|
|
// we need an instance
|
|
|
|
setInstance( FSViewPartFactory::instance() );
|
|
|
|
|
|
|
|
_view = new FSView(new Inode(), parentWidget, widgetName);
|
|
|
|
TQWhatsThis::add(_view, i18n("<p>This is the FSView plugin, a graphical "
|
|
|
|
"browsing mode showing filesystem utilization "
|
|
|
|
"by using a tree map visualization.</p>"
|
|
|
|
"<p>Note that in this mode, automatic updating "
|
|
|
|
"when filesystem changes are made "
|
|
|
|
"is intentionally <b>not</b> done.</p>"
|
|
|
|
"<p>For details on usage and options available, "
|
|
|
|
"see the online help under "
|
|
|
|
"menu 'Help/FSView Manual'.</p>"));
|
|
|
|
|
|
|
|
_view->show();
|
|
|
|
setWidget(_view);
|
|
|
|
|
|
|
|
_ext = new FSViewBrowserExtension(this);
|
|
|
|
_job = 0;
|
|
|
|
|
|
|
|
_areaMenu = new TDEActionMenu (i18n("Stop at Area"),
|
|
|
|
actionCollection(), "treemap_areadir");
|
|
|
|
_depthMenu = new TDEActionMenu (i18n("Stop at Depth"),
|
|
|
|
actionCollection(), "treemap_depthdir");
|
|
|
|
_visMenu = new TDEActionMenu (i18n("Visualization"),
|
|
|
|
actionCollection(), "treemap_visdir");
|
|
|
|
_colorMenu = new TDEActionMenu (i18n("Color Mode"),
|
|
|
|
actionCollection(), "treemap_colordir");
|
|
|
|
|
|
|
|
TDEAction* action;
|
|
|
|
action = new TDEAction( i18n( "&FSView Manual" ), "fsview",
|
|
|
|
TDEShortcut(), this, TQ_SLOT(showHelp()),
|
|
|
|
actionCollection(), "help_fsview" );
|
|
|
|
action->setToolTip(i18n("Show FSView manual"));
|
|
|
|
action->setWhatsThis(i18n("Opens the help browser with the "
|
|
|
|
"FSView documentation"));
|
|
|
|
|
|
|
|
TQObject::connect (_visMenu->popupMenu(), TQ_SIGNAL (aboutToShow()),
|
|
|
|
TQ_SLOT (slotShowVisMenu()));
|
|
|
|
TQObject::connect (_areaMenu->popupMenu(), TQ_SIGNAL (aboutToShow()),
|
|
|
|
TQ_SLOT (slotShowAreaMenu()));
|
|
|
|
TQObject::connect (_depthMenu->popupMenu(), TQ_SIGNAL (aboutToShow()),
|
|
|
|
TQ_SLOT (slotShowDepthMenu()));
|
|
|
|
TQObject::connect (_colorMenu->popupMenu(), TQ_SIGNAL (aboutToShow()),
|
|
|
|
TQ_SLOT (slotShowColorMenu()));
|
|
|
|
|
|
|
|
slotSettingsChanged(TDEApplication::SETTINGS_MOUSE);
|
|
|
|
if (kapp)
|
|
|
|
connect( kapp, TQ_SIGNAL( settingsChanged(int) ),
|
|
|
|
TQ_SLOT( slotSettingsChanged(int) ) );
|
|
|
|
|
|
|
|
TQObject::connect(_view,TQ_SIGNAL(returnPressed(TreeMapItem*)),
|
|
|
|
_ext,TQ_SLOT(selected(TreeMapItem*)));
|
|
|
|
TQObject::connect(_view,TQ_SIGNAL(selectionChanged()),
|
|
|
|
_ext,TQ_SLOT(updateActions()));
|
|
|
|
TQObject::connect(_view,
|
|
|
|
TQ_SIGNAL(contextMenuRequested(TreeMapItem*,const TQPoint&)),
|
|
|
|
_ext,
|
|
|
|
TQ_SLOT(contextMenu(TreeMapItem*, const TQPoint&)));
|
|
|
|
|
|
|
|
TQObject::connect(_view, TQ_SIGNAL(started()), this, TQ_SLOT(startedSlot()));
|
|
|
|
TQObject::connect(_view, TQ_SIGNAL(completed(int)),
|
|
|
|
this, TQ_SLOT(completedSlot(int)));
|
|
|
|
|
|
|
|
TQTimer::singleShot(1, this, TQ_SLOT(showInfo()));
|
|
|
|
|
|
|
|
setXMLFile( "fsview_part.rc" );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FSViewPart::~FSViewPart()
|
|
|
|
{
|
|
|
|
kdDebug(90100) << "FSViewPart Destructor" << endl;
|
|
|
|
|
|
|
|
delete _job;
|
|
|
|
_view->saveFSOptions();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSViewPart::slotSettingsChanged(int category)
|
|
|
|
{
|
|
|
|
if (category != TDEApplication::SETTINGS_MOUSE) return;
|
|
|
|
|
|
|
|
TQObject::disconnect(_view,TQ_SIGNAL(clicked(TreeMapItem*)),
|
|
|
|
_ext,TQ_SLOT(selected(TreeMapItem*)));
|
|
|
|
TQObject::disconnect(_view,TQ_SIGNAL(doubleClicked(TreeMapItem*)),
|
|
|
|
_ext,TQ_SLOT(selected(TreeMapItem*)));
|
|
|
|
|
|
|
|
if (TDEGlobalSettings::singleClick())
|
|
|
|
TQObject::connect(_view,TQ_SIGNAL(clicked(TreeMapItem*)),
|
|
|
|
_ext,TQ_SLOT(selected(TreeMapItem*)));
|
|
|
|
else
|
|
|
|
TQObject::connect(_view,TQ_SIGNAL(doubleClicked(TreeMapItem*)),
|
|
|
|
_ext,TQ_SLOT(selected(TreeMapItem*)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSViewPart::showInfo()
|
|
|
|
{
|
|
|
|
TQString info;
|
|
|
|
info = i18n("FSView intentionally does not support automatic updates "
|
|
|
|
"when changes are made to files or directories, "
|
|
|
|
"currently visible in FSView, from the outside.\n"
|
|
|
|
"For details, see the 'Help/FSView Manual'.");
|
|
|
|
|
|
|
|
KMessageBox::information( _view, info, TQString(), "ShowFSViewInfo");
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSViewPart::showHelp()
|
|
|
|
{
|
|
|
|
TDEApplication::startServiceByDesktopName("khelpcenter",
|
|
|
|
TQString("help:/konq-plugins/fsview/index.html"));
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSViewPart::startedSlot()
|
|
|
|
{
|
|
|
|
_job = new FSJob(_view);
|
|
|
|
emit started(_job);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSViewPart::completedSlot(int dirs)
|
|
|
|
{
|
|
|
|
if (_job) {
|
|
|
|
_job->progressSlot(100, dirs, TQString());
|
|
|
|
delete _job;
|
|
|
|
_job = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
TDEConfigGroup cconfig(_view->config(), TQCString("MetricCache"));
|
|
|
|
_view->saveMetric(&cconfig);
|
|
|
|
|
|
|
|
emit completed();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSViewPart::slotShowVisMenu()
|
|
|
|
{
|
|
|
|
_visMenu->popupMenu()->clear();
|
|
|
|
_view->addVisualizationItems(_visMenu->popupMenu(), 1301);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSViewPart::slotShowAreaMenu()
|
|
|
|
{
|
|
|
|
_areaMenu->popupMenu()->clear();
|
|
|
|
_view->addAreaStopItems(_areaMenu->popupMenu(), 1001, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSViewPart::slotShowDepthMenu()
|
|
|
|
{
|
|
|
|
_depthMenu->popupMenu()->clear();
|
|
|
|
_view->addDepthStopItems(_depthMenu->popupMenu(), 1501, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSViewPart::slotShowColorMenu()
|
|
|
|
{
|
|
|
|
_colorMenu->popupMenu()->clear();
|
|
|
|
_view->addColorItems(_colorMenu->popupMenu(), 1401);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FSViewPart::openFile() // never called since openURL is reimplemented
|
|
|
|
{
|
|
|
|
kdDebug(90100) << "FSViewPart::openFile " << m_file << endl;
|
|
|
|
_view->setPath(m_file);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FSViewPart::openURL(const KURL &url)
|
|
|
|
{
|
|
|
|
kdDebug(90100) << "FSViewPart::openURL " << url.path() << endl;
|
|
|
|
|
|
|
|
if (!url.isValid()) return false;
|
|
|
|
if (!url.isLocalFile()) return false;
|
|
|
|
|
|
|
|
m_url = url;
|
|
|
|
emit setWindowCaption( m_url.prettyURL() );
|
|
|
|
|
|
|
|
_view->setPath(url.path());
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FSViewPart::closeURL()
|
|
|
|
{
|
|
|
|
kdDebug(90100) << "FSViewPart::closeURL " << endl;
|
|
|
|
|
|
|
|
_view->stop();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FSViewBrowserExtension
|
|
|
|
|
|
|
|
FSViewBrowserExtension::FSViewBrowserExtension(FSViewPart* viewPart,
|
|
|
|
const char *name)
|
|
|
|
:KParts::BrowserExtension(viewPart, name)
|
|
|
|
{
|
|
|
|
_view = viewPart->view();
|
|
|
|
}
|
|
|
|
|
|
|
|
FSViewBrowserExtension::~FSViewBrowserExtension()
|
|
|
|
{}
|
|
|
|
|
|
|
|
void FSViewBrowserExtension::updateActions()
|
|
|
|
{
|
|
|
|
TreeMapItemList s = _view->selection();
|
|
|
|
TreeMapItem* i;
|
|
|
|
int canDel = 0, canCopy = 0;
|
|
|
|
KURL::List urls;
|
|
|
|
|
|
|
|
for(i=s.first();i;i=s.next()) {
|
|
|
|
KURL u;
|
|
|
|
u.setPath( ((Inode*)i)->path() );
|
|
|
|
urls.append(u);
|
|
|
|
canCopy++;
|
|
|
|
if ( KProtocolInfo::supportsDeleting( u ) ) canDel++;
|
|
|
|
}
|
|
|
|
emit enableAction( "copy", canCopy > 0 );
|
|
|
|
emit enableAction( "cut", canDel > 0 );
|
|
|
|
emit enableAction( "trash", canDel > 0);
|
|
|
|
emit enableAction( "del", canDel > 0 );
|
|
|
|
emit enableAction( "editMimeType", ( s.count() == 1 ) );
|
|
|
|
|
|
|
|
emit selectionInfo(urls);
|
|
|
|
|
|
|
|
kdDebug(90100) << "FSViewPart::updateActions, deletable " << canDel << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FSViewBrowserExtension::del()
|
|
|
|
{
|
|
|
|
KonqOperations::del(_view, KonqOperations::DEL, _view->selectedUrls());
|
|
|
|
// How to get notified of end of delete operation?
|
|
|
|
// - search for the KonqOperations child of _view (name "KonqOperations")
|
|
|
|
// - connect to destroyed signal
|
|
|
|
KonqOperations* o = (KonqOperations*) _view->child("KonqOperations");
|
|
|
|
if (o) connect(o, TQ_SIGNAL(destroyed()), TQ_SLOT(refresh()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSViewBrowserExtension::trash()
|
|
|
|
{
|
|
|
|
KonqOperations::del(_view, KonqOperations::TRASH, _view->selectedUrls());
|
|
|
|
KonqOperations* o = (KonqOperations*) _view->child("KonqOperations");
|
|
|
|
if (o) connect(o, TQ_SIGNAL(destroyed()), TQ_SLOT(refresh()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSViewBrowserExtension::copySelection( bool move )
|
|
|
|
{
|
|
|
|
KonqDrag *urlData = KonqDrag::newDrag( _view->selectedUrls(), move );
|
|
|
|
TQApplication::clipboard()->setData( urlData );
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSViewBrowserExtension::editMimeType()
|
|
|
|
{
|
|
|
|
Inode* i = (Inode*) _view->selection().first();
|
|
|
|
if (i)
|
|
|
|
KonqOperations::editMimeType( i->mimeType()->name() );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// refresh treemap at end of TDEIO jobs
|
|
|
|
void FSViewBrowserExtension::refresh()
|
|
|
|
{
|
|
|
|
// only need to refresh common ancestor for all selected items
|
|
|
|
TreeMapItemList s = _view->selection();
|
|
|
|
TreeMapItem *i, *commonParent = s.first();
|
|
|
|
if (!commonParent) return;
|
|
|
|
while( (i=s.next()) )
|
|
|
|
commonParent = commonParent->commonParent(i);
|
|
|
|
|
|
|
|
/* if commonParent is a file, update parent directory */
|
|
|
|
if ( !((Inode*)commonParent)->isDir() ) {
|
|
|
|
commonParent = commonParent->parent();
|
|
|
|
if (!commonParent) return;
|
|
|
|
}
|
|
|
|
|
|
|
|
kdDebug(90100) << "FSViewPart::refreshing "
|
|
|
|
<< ((Inode*)commonParent)->path() << endl;
|
|
|
|
|
|
|
|
_view->requestUpdate( (Inode*)commonParent );
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSViewBrowserExtension::selected(TreeMapItem* i)
|
|
|
|
{
|
|
|
|
if (!i) return;
|
|
|
|
|
|
|
|
KURL url;
|
|
|
|
url.setPath( ((Inode*)i)->path() );
|
|
|
|
emit openURLRequest(url);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FSViewBrowserExtension::contextMenu(TreeMapItem* /*item*/,const TQPoint& p)
|
|
|
|
{
|
|
|
|
TreeMapItemList s = _view->selection();
|
|
|
|
TreeMapItem* i;
|
|
|
|
KFileItemList items;
|
|
|
|
items.setAutoDelete(true);
|
|
|
|
|
|
|
|
for(i=s.first();i;i=s.next()) {
|
|
|
|
KURL u;
|
|
|
|
u.setPath( ((Inode*)i)->path() );
|
|
|
|
TQString mimetype = ((Inode*)i)->mimeType()->name();
|
|
|
|
const TQFileInfo& info = ((Inode*)i)->fileInfo();
|
|
|
|
mode_t mode =
|
|
|
|
info.isFile() ? S_IFREG :
|
|
|
|
info.isDir() ? S_IFDIR :
|
|
|
|
info.isSymLink() ? S_IFLNK : (mode_t)-1;
|
|
|
|
items.append(new KFileItem(u, mimetype, mode));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (items.count()>0)
|
|
|
|
emit popupMenu(_view->mapToGlobal(p), items);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#include "fsview_part.moc"
|