summaryrefslogtreecommitdiffstats
path: root/src/app/DiskUsage
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/DiskUsage')
-rw-r--r--src/app/DiskUsage/Makefile.am17
-rw-r--r--src/app/DiskUsage/diskusage.cpp1147
-rw-r--r--src/app/DiskUsage/diskusage.h206
-rw-r--r--src/app/DiskUsage/diskusagegui.cpp227
-rw-r--r--src/app/DiskUsage/diskusagegui.h90
-rw-r--r--src/app/DiskUsage/dufilelight.cpp236
-rw-r--r--src/app/DiskUsage/dufilelight.h81
-rw-r--r--src/app/DiskUsage/dulines.cpp522
-rw-r--r--src/app/DiskUsage/dulines.h79
-rw-r--r--src/app/DiskUsage/dulistview.cpp293
-rw-r--r--src/app/DiskUsage/dulistview.h145
-rw-r--r--src/app/DiskUsage/filelightParts/Config.cpp50
-rw-r--r--src/app/DiskUsage/filelightParts/Config.h37
-rw-r--r--src/app/DiskUsage/filelightParts/Makefile.am9
-rw-r--r--src/app/DiskUsage/filelightParts/debug.h14
-rw-r--r--src/app/DiskUsage/filelightParts/fileTree.cpp78
-rw-r--r--src/app/DiskUsage/filelightParts/fileTree.h299
-rw-r--r--src/app/DiskUsage/radialMap/Makefile.am13
-rw-r--r--src/app/DiskUsage/radialMap/builder.cpp139
-rw-r--r--src/app/DiskUsage/radialMap/builder.h37
-rw-r--r--src/app/DiskUsage/radialMap/labels.cpp342
-rw-r--r--src/app/DiskUsage/radialMap/map.cpp432
-rw-r--r--src/app/DiskUsage/radialMap/radialMap.h71
-rw-r--r--src/app/DiskUsage/radialMap/segmentTip.cpp163
-rw-r--r--src/app/DiskUsage/radialMap/segmentTip.h33
-rw-r--r--src/app/DiskUsage/radialMap/sincos.h17
-rw-r--r--src/app/DiskUsage/radialMap/widget.cpp199
-rw-r--r--src/app/DiskUsage/radialMap/widget.h111
-rw-r--r--src/app/DiskUsage/radialMap/widgetEvents.cpp241
29 files changed, 5328 insertions, 0 deletions
diff --git a/src/app/DiskUsage/Makefile.am b/src/app/DiskUsage/Makefile.am
new file mode 100644
index 0000000..691d045
--- /dev/null
+++ b/src/app/DiskUsage/Makefile.am
@@ -0,0 +1,17 @@
+SUBDIRS = \
+ radialMap \
+ filelightParts
+
+
+noinst_LIBRARIES = libDiskUsage.a
+
+INCLUDES = $(all_includes)
+
+libDiskUsage_a_METASOURCES = AUTO
+
+libDiskUsage_a_SOURCES = \
+ diskusagegui.cpp \
+ diskusage.cpp \
+ dulistview.cpp \
+ dulines.cpp \
+ dufilelight.cpp
diff --git a/src/app/DiskUsage/diskusage.cpp b/src/app/DiskUsage/diskusage.cpp
new file mode 100644
index 0000000..c372e8c
--- /dev/null
+++ b/src/app/DiskUsage/diskusage.cpp
@@ -0,0 +1,1147 @@
+/***************************************************************************
+ diskusage.cpp - description
+ -------------------
+ copyright : (C) 2004 + by Csaba Karai
+ e-mail : krusader@users.sourceforge.net
+ web site : http://krusader.sourceforge.net
+ ---------------------------------------------------------------------------
+ Description
+ ***************************************************************************
+
+ A
+
+ db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b.
+ 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D
+ 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY'
+ 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b
+ 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88.
+ YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD
+
+ S o u r c e F i l e
+
+ ***************************************************************************
+ * *
+ * This program 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <time.h>
+#include <tqlayout.h>
+#include <tdelocale.h>
+#include <tdepopupmenu.h>
+#include <kmimetype.h>
+#include <tdemessagebox.h>
+#include <tdeglobalsettings.h>
+#include <tdeio/job.h>
+#include <tqpushbutton.h>
+#include <tqhbox.h>
+#include <tqapplication.h>
+#include <tqcursor.h>
+#include <tqpixmapcache.h>
+#include <tqgroupbox.h>
+#include <tqguardedptr.h>
+#include "diskusage.h"
+#include "../VFS/krpermhandler.h"
+#include "../VFS/krvfshandler.h"
+#include "../kicons.h"
+#include "../defaults.h"
+#include "../krusader.h"
+#include "../krusaderview.h"
+#include "../Panel/listpanel.h"
+#include "../Panel/panelfunc.h"
+#include "filelightParts/Config.h"
+
+#include "dulines.h"
+#include "dulistview.h"
+#include "dufilelight.h"
+
+// these are the values that will exist in the menu
+#define DELETE_ID 90
+#define EXCLUDE_ID 91
+#define PARENT_DIR_ID 92
+#define NEW_SEARCH_ID 93
+#define REFRESH_ID 94
+#define STEP_INTO_ID 95
+#define INCLUDE_ALL_ID 96
+#define VIEW_POPUP_ID 97
+#define LINES_VIEW_ID 98
+#define DETAILED_VIEW_ID 99
+#define FILELIGHT_VIEW_ID 100
+#define NEXT_VIEW_ID 101
+#define PREVIOUS_VIEW_ID 102
+#define ADDITIONAL_POPUP_ID 103
+
+#define MAX_FILENUM 100
+
+LoaderWidget::LoaderWidget( TQWidget *parent, const char *name ) : TQScrollView( parent, name ), cancelled( false )
+{
+ viewport()->setEraseColor( TQt::white );
+ widget = new TQWidget( parent );
+
+ TQGridLayout *loaderLayout = new TQGridLayout( widget );
+ loaderLayout->setSpacing( 0 );
+ loaderLayout->setMargin( 0 );
+
+ TQGroupBox *loaderBox = new TQGroupBox( widget, "loaderGroupBox" );
+ loaderBox->setFrameShape( TQGroupBox::Box );
+ loaderBox->setFrameShadow( TQGroupBox::Sunken );
+ loaderBox->setColumnLayout(0, TQt::Vertical );
+ loaderBox->layout()->setSpacing( 0 );
+ loaderBox->layout()->setMargin( 0 );
+ loaderBox->setSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed );
+ loaderBox->setFrameStyle( TQFrame::Panel + TQFrame::Raised );
+ loaderBox->setLineWidth( 2 );
+
+ TQGridLayout *synchGrid = new TQGridLayout( loaderBox->layout() );
+ synchGrid->setSpacing( 6 );
+ synchGrid->setMargin( 11 );
+
+ TQLabel *titleLabel = new TQLabel( i18n( "Loading Usage Information" ), loaderBox, "titleLabel" );
+ titleLabel->setAlignment( TQt::AlignHCenter );
+ synchGrid->addMultiCellWidget( titleLabel, 0, 0, 0, 1 );
+
+ TQLabel *filesLabel = new TQLabel( i18n( "Files:" ), loaderBox, "filesLabel" );
+ filesLabel->setFrameShape( TQLabel::StyledPanel );
+ filesLabel->setFrameShadow( TQLabel::Sunken );
+ synchGrid->addWidget( filesLabel, 1, 0 );
+
+ TQLabel *directoriesLabel = new TQLabel( i18n( "Directories:" ), loaderBox, "directoriesLabel" );
+ directoriesLabel->setFrameShape( TQLabel::StyledPanel );
+ directoriesLabel->setFrameShadow( TQLabel::Sunken );
+ synchGrid->addWidget( directoriesLabel, 2, 0 );
+
+ TQLabel *totalSizeLabel = new TQLabel( i18n( "Total Size:" ), loaderBox, "totalSizeLabel" );
+ totalSizeLabel->setFrameShape( TQLabel::StyledPanel );
+ totalSizeLabel->setFrameShadow( TQLabel::Sunken );
+ synchGrid->addWidget( totalSizeLabel, 3, 0 );
+
+ files = new TQLabel( loaderBox, "files" );
+ files->setFrameShape( TQLabel::StyledPanel );
+ files->setFrameShadow( TQLabel::Sunken );
+ files->setAlignment( TQt::AlignRight );
+ synchGrid->addWidget( files, 1, 1 );
+
+ directories = new TQLabel( loaderBox, "directories" );
+ directories->setFrameShape( TQLabel::StyledPanel );
+ directories->setFrameShadow( TQLabel::Sunken );
+ directories->setAlignment( TQt::AlignRight );
+ synchGrid->addWidget( directories, 2, 1 );
+
+ totalSize = new TQLabel( loaderBox, "totalSize" );
+ totalSize->setFrameShape( TQLabel::StyledPanel );
+ totalSize->setFrameShadow( TQLabel::Sunken );
+ totalSize->setAlignment( TQt::AlignRight );
+ synchGrid->addWidget( totalSize, 3, 1 );
+
+ int width;
+ searchedDirectory = new KSqueezedTextLabel( loaderBox, "searchedDirectory" );
+ searchedDirectory->setFrameShape( TQLabel::StyledPanel );
+ searchedDirectory->setFrameShadow( TQLabel::Sunken );
+ searchedDirectory->setMinimumWidth( width = TQFontMetrics(searchedDirectory->font()).width("W") * 30 );
+ searchedDirectory->setMaximumWidth( width );
+ synchGrid->addMultiCellWidget( searchedDirectory, 4, 4, 0, 1 );
+
+ TQFrame *line = new TQFrame( loaderBox, "duLine" );
+ line->setFrameStyle( TQFrame::HLine | TQFrame::Sunken );
+ synchGrid->addMultiCellWidget( line, 5, 5, 0, 1 );
+
+ TQHBox *hbox = new TQHBox( loaderBox, "hbox" );
+ TQSpacerItem* spacer = new TQSpacerItem( 0, 0, TQSizePolicy::Minimum, TQSizePolicy::Expanding );
+ hbox->layout()->addItem( spacer );
+ TQPushButton *cancelButton = new TQPushButton( hbox, "cancelButton" );
+ cancelButton->setText( i18n( "Cancel" ) );
+ synchGrid->addWidget( hbox, 6, 1 );
+
+ loaderLayout->addWidget( loaderBox, 0, 0 );
+
+ addChild( widget );
+
+ connect( cancelButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( slotCancelled() ) );
+}
+
+void LoaderWidget::resizeEvent ( TQResizeEvent *e )
+{
+ TQScrollView::resizeEvent( e );
+
+ int x = ( viewport()->width() - widget->width() ) / 2;
+ int y = ( viewport()->height() - widget->height() ) / 2;
+ if( x < 0 ) x=0;
+ if( y < 0 ) y=0;
+
+ moveChild( widget, x, y );
+}
+
+void LoaderWidget::init()
+{
+ cancelled = false;
+}
+
+void LoaderWidget::setCurrentURL( KURL url )
+{
+ searchedDirectory->setText( vfs::pathOrURL( url, 1) );
+}
+
+void LoaderWidget::setValues( int fileNum, int dirNum, TDEIO::filesize_t total )
+{
+ files->setText( TQString("%1").arg( fileNum ) );
+ directories->setText( TQString("%1").arg( dirNum ) );
+ totalSize->setText( TQString("%1").arg( KRpermHandler::parseSize( total ).stripWhiteSpace() ) );
+}
+
+void LoaderWidget::slotCancelled()
+{
+ cancelled = true;
+}
+
+DiskUsage::DiskUsage( TQString confGroup, TQWidget *parent, char *name ) : TQWidgetStack( parent, name ),
+ currentDirectory( 0 ), root( 0 ), configGroup( confGroup ), loading( false ),
+ abortLoading( false ), clearAfterAbort( false ), deleting( false ), searchVfs( 0 )
+{
+ listView = new DUListView( this, "DU ListView" );
+ lineView = new DULines( this, "DU LineView" );
+ filelightView = new DUFilelight( this, "Filelight canvas" );
+ loaderView = new LoaderWidget( this, "Loading view" );
+
+ addWidget( listView );
+ addWidget( lineView );
+ addWidget( filelightView );
+ addWidget( loaderView );
+
+ setView( VIEW_LINES );
+
+ Filelight::Config::read();
+ propertyMap.setAutoDelete( true );
+
+ connect( &loadingTimer, TQ_SIGNAL( timeout() ), this, TQ_SLOT( slotLoadDirectory() ) );
+}
+
+DiskUsage::~DiskUsage()
+{
+ if( root )
+ delete root;
+
+ if( listView ) // don't remove these lines. The module will crash at exit if removed
+ delete listView;
+ if( lineView )
+ delete lineView;
+ if( filelightView )
+ delete filelightView;
+}
+
+void DiskUsage::load( KURL baseDir )
+{
+ if( searchVfs && !searchVfs->vfs_canDelete() ) {
+ return;
+ }
+
+ fileNum = dirNum = 0;
+ currentSize = 0;
+
+ emit status( i18n( "Loading the disk usage information..." ) );
+
+ clear();
+
+ baseURL = baseDir;
+ baseURL.setPath( baseDir.path( -1 ) );
+
+ root = new Directory( baseURL.fileName(), vfs::pathOrURL( baseDir ) );
+
+ directoryStack.clear();
+ parentStack.clear();
+
+ directoryStack.push( "" );
+ parentStack.push( root );
+
+ if( searchVfs )
+ {
+ delete searchVfs;
+ searchVfs = 0;
+ }
+ searchVfs = KrVfsHandler::getVfs( baseDir );
+ if( searchVfs == 0 )
+ {
+ loading = abortLoading = clearAfterAbort = false;
+ emit loadFinished( false );
+ return;
+ }
+
+ searchVfs->vfs_setQuiet( true );
+ currentVfile = 0;
+
+ if( !loading )
+ {
+ viewBeforeLoad = activeView;
+ setView( VIEW_LOADER );
+ }
+
+ loading = true;
+
+ loaderView->init();
+ loaderView->setCurrentURL( baseURL );
+ loaderView->setValues( fileNum, dirNum, currentSize );
+
+ loadingTimer.start( 0, true );
+}
+
+void DiskUsage::slotLoadDirectory()
+{
+ if( searchVfs && !searchVfs->vfs_canDelete() ) { // recursive call from slotLoadDirectory?
+ loadingTimer.start( 100, true ); // as it can cause crash, ignore it and wait while
+ return; // the recursion finishes
+ }
+ if( ( currentVfile == 0 && directoryStack.isEmpty() ) || loaderView->wasCancelled() || abortLoading )
+ {
+ if( searchVfs )
+ delete searchVfs;
+
+ searchVfs = 0;
+ currentVfile = 0;
+
+ setView( viewBeforeLoad );
+
+ if( clearAfterAbort )
+ clear();
+ else {
+ calculateSizes();
+ changeDirectory( root );
+ }
+
+ emit loadFinished( !( loaderView->wasCancelled() || abortLoading ) );
+
+ loading = abortLoading = clearAfterAbort = false;
+ }
+ else if( loading )
+ {
+ for( int counter = 0; counter != MAX_FILENUM; counter ++ )
+ {
+ if( currentVfile == 0 )
+ {
+ if( directoryStack.isEmpty() )
+ break;
+
+ dirToCheck = directoryStack.pop();
+ currentParent = parentStack.pop();
+
+ contentMap.insert( dirToCheck, currentParent );
+
+ KURL url = baseURL;
+
+ if( !dirToCheck.isEmpty() )
+ url.addPath( dirToCheck );
+
+#if defined(BSD)
+ if ( url.isLocalFile() && url.path().left( 7 ) == "/procfs" )
+ break;
+#else
+ if ( url.isLocalFile() && url.path().left( 5 ) == "/proc" )
+ break;
+#endif
+
+ loaderView->setCurrentURL( url );
+
+ if( !searchVfs->vfs_refresh( url ) )
+ break;
+
+ dirNum++;
+
+ currentVfile = searchVfs->vfs_getFirstFile();
+ }
+ else
+ {
+ fileNum++;
+ File *newItem = 0;
+
+ TQString mime = currentVfile->vfile_getMime(true); // fast == not using mimetype magic
+
+ if( currentVfile->vfile_isDir() && !currentVfile->vfile_isSymLink() )
+ {
+ newItem = new Directory( currentParent, currentVfile->vfile_getName(), dirToCheck, currentVfile->vfile_getSize(),
+ currentVfile->vfile_getMode(), currentVfile->vfile_getOwner(), currentVfile->vfile_getGroup(),
+ currentVfile->vfile_getPerm(), currentVfile->vfile_getTime_t(), currentVfile->vfile_isSymLink(),
+ mime );
+ directoryStack.push( (dirToCheck.isEmpty() ? "" : dirToCheck + "/" )+ currentVfile->vfile_getName() );
+ parentStack.push( dynamic_cast<Directory *>( newItem ) );
+ }
+ else
+ {
+ newItem = new File( currentParent, currentVfile->vfile_getName(), dirToCheck, currentVfile->vfile_getSize(),
+ currentVfile->vfile_getMode(), currentVfile->vfile_getOwner(), currentVfile->vfile_getGroup(),
+ currentVfile->vfile_getPerm(), currentVfile->vfile_getTime_t(), currentVfile->vfile_isSymLink(),
+ mime );
+ currentSize += currentVfile->vfile_getSize();
+ }
+ currentParent->append( newItem );
+
+ currentVfile = searchVfs->vfs_getNextFile();
+ }
+ }
+
+ loaderView->setValues( fileNum, dirNum, currentSize );
+ loadingTimer.start( 0, true );
+ }
+}
+
+void DiskUsage::stopLoad()
+{
+ abortLoading = true;
+}
+
+void DiskUsage::close()
+{
+ if( loading )
+ {
+ abortLoading = true;
+ clearAfterAbort = true;
+ }
+}
+
+void DiskUsage::dirUp()
+{
+ if( currentDirectory != 0 )
+ {
+ if ( currentDirectory->parent() != 0 )
+ changeDirectory( (Directory *)(currentDirectory->parent()) );
+ else
+ {
+ KURL up = baseURL.upURL();
+
+ if( KMessageBox::questionYesNo( this, i18n( "Stepping into the parent directory requires "
+ "loading the content of the \"%1\" URL. Do you wish "
+ "to continue?" )
+ .arg( vfs::pathOrURL( up ) ),
+ i18n( "Krusader::DiskUsage" ), KStdGuiItem::yes(),
+ KStdGuiItem::no(), "DiskUsageLoadParentDir"
+ ) == KMessageBox::Yes )
+ load( up );
+ }
+ }
+}
+
+Directory * DiskUsage::getDirectory( TQString dir )
+{
+ while( dir.endsWith( "/" ) )
+ dir.truncate( dir.length() - 1 );
+
+ if( dir.isEmpty() )
+ return root;
+
+ return contentMap.find( dir );
+}
+
+File * DiskUsage::getFile( TQString path )
+{
+ if( path == "" )
+ return root;
+
+ TQString dir = path;
+
+ int ndx = path.findRev( '/' );
+ TQString file = path.mid( ndx + 1 );
+
+ if( ndx == -1 )
+ dir = "";
+ else
+ dir.truncate( ndx );
+
+ Directory *dirEntry = getDirectory( dir );
+ if( dirEntry == 0 )
+ return 0;
+
+ for( Iterator<File> it = dirEntry->iterator(); it != dirEntry->end(); ++it )
+ if( (*it)->name() == file )
+ return *it;
+
+ return 0;
+}
+
+void DiskUsage::clear()
+{
+ baseURL = KURL();
+ emit clearing();
+ propertyMap.clear();
+ contentMap.clear();
+ if( root )
+ delete root;
+ root = currentDirectory = 0;
+}
+
+int DiskUsage::calculateSizes( Directory *dirEntry, bool emitSig, int depth )
+{
+ int changeNr = 0;
+
+ if( dirEntry == 0 )
+ dirEntry = root;
+
+ TDEIO::filesize_t own = 0, total = 0;
+
+ for( Iterator<File> it = dirEntry->iterator(); it != dirEntry->end(); ++it )
+ {
+ File * item = *it;
+
+ if( !item->isExcluded() )
+ {
+ if( item->isDir() )
+ changeNr += calculateSizes( dynamic_cast<Directory *>( item ), emitSig, depth + 1 );
+ else
+ own += item->size();
+
+ total += item->size();
+ }
+ }
+
+ TDEIO::filesize_t oldOwn = dirEntry->ownSize(), oldTotal = dirEntry->size();
+ dirEntry->setSizes( total, own );
+
+ if( dirEntry == currentDirectory )
+ currentSize = total;
+
+ if( emitSig && ( own != oldOwn || total != oldTotal ) ) {
+ emit changed( dirEntry );
+ changeNr++;
+ }
+
+ if( depth == 0 && changeNr != 0 )
+ emit changeFinished();
+ return changeNr;
+}
+
+int DiskUsage::exclude( File *file, bool calcPercents, int depth )
+{
+ int changeNr = 0;
+
+ if( !file->isExcluded() )
+ {
+ file->exclude( true );
+ emit changed( file );
+ changeNr++;
+
+ if( file->isDir() )
+ {
+ Directory *dir = dynamic_cast<Directory *>( file );
+ for( Iterator<File> it = dir->iterator(); it != dir->end(); ++it )
+ changeNr += exclude( *it, false, depth + 1 );
+ }
+ }
+
+ if( calcPercents )
+ {
+ calculateSizes( root, true );
+ calculatePercents( true );
+ createStatus();
+ }
+
+ if( depth == 0 && changeNr != 0 )
+ emit changeFinished();
+
+ return changeNr;
+}
+
+int DiskUsage::include( Directory *dir, int depth )
+{
+ int changeNr = 0;
+
+ if( dir == 0 )
+ return 0;
+
+ for( Iterator<File> it = dir->iterator(); it != dir->end(); ++it )
+ {
+ File *item = *it;
+
+ if( item->isDir() )
+ changeNr += include( dynamic_cast<Directory *>( item ), depth + 1 );
+
+ if( item->isExcluded() )
+ {
+ item->exclude( false );
+ emit changed( item );
+ changeNr++;
+ }
+ }
+
+ if( depth == 0 && changeNr != 0 )
+ emit changeFinished();
+
+ return changeNr;
+}
+
+void DiskUsage::includeAll()
+{
+ include( root );
+ calculateSizes( root, true );
+ calculatePercents( true );
+ createStatus();
+}
+
+int DiskUsage::del( File *file, bool calcPercents, int depth )
+{
+ int deleteNr = 0;
+
+ if( file == root )
+ return 0;
+
+ krConfig->setGroup( "General" );
+ bool trash = krConfig->readBoolEntry( "Move To Trash", _MoveToTrash );
+ KURL url = vfs::fromPathOrURL( file->fullPath() );
+
+ if( calcPercents )
+ {
+ // now ask the user if he want to delete:
+ krConfig->setGroup( "Advanced" );
+ if ( krConfig->readBoolEntry( "Confirm Delete", _ConfirmDelete ) ) {
+ TQString s, b;
+ if ( trash && url.isLocalFile() ) {
+ s = i18n( "Do you really want to move this item to the trash?" );
+ b = i18n( "&Trash" );
+ } else {
+ s = i18n( "Do you really want to delete this item?" );
+ b = i18n( "&Delete" );
+ }
+
+ TQStringList name;
+ name.append( file->fullPath() );
+ // show message
+ // note: i'm using continue and not yes/no because the yes/no has cancel as default button
+ if ( KMessageBox::warningContinueCancelList( krApp, s, name, i18n( "Warning" ), b ) != KMessageBox::Continue )
+ return 0;
+ }
+
+ emit status( i18n( "Deleting %1..." ).arg( file->name() ) );
+ }
+
+ if( file == currentDirectory )
+ dirUp();
+
+ if( file->isDir() )
+ {
+ Directory *dir = dynamic_cast<Directory *>( file );
+
+ Iterator<File> it;
+ while( ( it = dir->iterator() ) != dir->end() )
+ deleteNr += del( *it, false, depth + 1 );
+
+ TQString path;
+ for( const Directory *d = (Directory*)file; d != root && d && d->parent() != 0; d = d->parent() )
+ {
+ if( !path.isEmpty() )
+ path = "/" + path;
+
+ path = d->name() + path;
+ }
+
+ contentMap.remove( path );
+ }
+
+ emit deleted( file );
+ deleteNr++;
+
+ TQGuardedPtr<TDEIO::Job> job;
+
+ if( trash )
+ {
+#if KDE_IS_VERSION(3,4,0)
+ job = TDEIO::trash( url, true );
+#else
+ job = new TDEIO::CopyJob( url,TDEGlobalSettings::trashPath(),TDEIO::CopyJob::Move,false,true );
+#endif
+ connect(job,TQ_SIGNAL(result(TDEIO::Job*)),krApp,TQ_SLOT(changeTrashIcon()));
+ }
+ else
+ {
+ job = new TDEIO::DeleteJob( vfs::fromPathOrURL( file->fullPath() ), false, false);
+ }
+
+ deleting = true; // during tqApp->processEvent strange things can occur
+ grabMouse(); // that's why we disable the mouse and keyboard events
+ grabKeyboard();
+
+ while( !job.isNull() )
+ tqApp->processEvents();
+
+ releaseMouse();
+ releaseKeyboard();
+ deleting = false;
+
+ ((Directory *)(file->parent()))->remove( file );
+ delete file;
+
+ if( depth == 0 )
+ createStatus();
+
+ if( calcPercents )
+ {
+ calculateSizes( root, true );
+ calculatePercents( true );
+ createStatus();
+ emit enteringDirectory( currentDirectory );
+ }
+
+ if( depth == 0 && deleteNr != 0 )
+ emit deleteFinished();
+
+ return deleteNr;
+}
+
+void * DiskUsage::getProperty( File *item, TQString key )
+{
+ Properties * props = propertyMap.find( item );
+ if( props == 0 )
+ return 0;
+ return props->find( key );
+}
+
+void DiskUsage::addProperty( File *item, TQString key, void * prop )
+{
+ Properties * props = propertyMap.find( item );
+ if( props == 0 )
+ {
+ props = new Properties();
+ propertyMap.insert( item, props );
+ }
+ props->insert( key, prop );
+}
+
+void DiskUsage::removeProperty( File *item, TQString key )
+{
+ Properties * props = propertyMap.find( item );
+ if( props == 0 )
+ return;
+ props->remove( key );
+ if( props->count() == 0 )
+ propertyMap.remove( item );
+}
+
+void DiskUsage::createStatus()
+{
+ Directory *dirEntry = currentDirectory;
+
+ if( dirEntry == 0 )
+ return;
+
+ KURL url = baseURL;
+ if( dirEntry != root )
+ url.addPath( dirEntry->directory() );
+
+ emit status( i18n( "Current directory:%1, Total size:%2, Own size:%3" )
+ .arg( vfs::pathOrURL( url, -1 ) )
+ .arg( " "+KRpermHandler::parseSize( dirEntry->size() ) )
+ .arg( " "+KRpermHandler::parseSize( dirEntry->ownSize() ) ) );
+}
+
+void DiskUsage::changeDirectory( Directory *dir )
+{
+ currentDirectory = dir;
+
+ currentSize = dir->size();
+ calculatePercents( true, dir );
+
+ createStatus();
+ emit enteringDirectory( dir );
+}
+
+Directory* DiskUsage::getCurrentDir()
+{
+ return currentDirectory;
+}
+
+void DiskUsage::rightClickMenu( File *fileItem, TDEPopupMenu *addPopup, TQString addPopupName )
+{
+ TDEPopupMenu popup( this );
+
+ popup.insertTitle( i18n("Disk Usage"));
+
+ if( fileItem != 0 )
+ {
+ popup.insertItem( i18n("Delete"), DELETE_ID);
+ popup.setAccel( Key_Delete, DELETE_ID );
+ popup.insertItem( i18n("Exclude"), EXCLUDE_ID);
+ popup.setAccel( CTRL + Key_E, EXCLUDE_ID );
+ popup.insertSeparator();
+ }
+
+ popup.insertItem( i18n("Up one directory"), PARENT_DIR_ID);
+ popup.setAccel( SHIFT + Key_Up, PARENT_DIR_ID );
+ popup.insertItem( i18n("New search"), NEW_SEARCH_ID);
+ popup.setAccel( CTRL + Key_N, NEW_SEARCH_ID );
+ popup.insertItem( i18n("Refresh"), REFRESH_ID);
+ popup.setAccel( CTRL + Key_R, REFRESH_ID );
+ popup.insertItem( i18n("Include all"), INCLUDE_ALL_ID);
+ popup.setAccel( CTRL + Key_I, INCLUDE_ALL_ID );
+ popup.insertItem( i18n("Step into"), STEP_INTO_ID);
+ popup.setAccel( SHIFT + Key_Down, STEP_INTO_ID );
+ popup.insertSeparator();
+
+
+ if( addPopup != 0 )
+ {
+ popup.insertItem( TQPixmap(), addPopup, ADDITIONAL_POPUP_ID );
+ popup.changeItem( ADDITIONAL_POPUP_ID, addPopupName );
+ }
+
+ TDEPopupMenu viewPopup;
+ viewPopup.insertItem(i18n("Lines"), LINES_VIEW_ID);
+ viewPopup.setAccel( CTRL + Key_L, LINES_VIEW_ID );
+ viewPopup.insertItem(i18n("Detailed"), DETAILED_VIEW_ID);
+ viewPopup.setAccel( CTRL + Key_D, DETAILED_VIEW_ID );
+ viewPopup.insertItem(i18n("Filelight"), FILELIGHT_VIEW_ID);
+ viewPopup.setAccel( CTRL + Key_F, FILELIGHT_VIEW_ID );
+ viewPopup.insertSeparator();
+ viewPopup.insertItem(i18n("Next"), NEXT_VIEW_ID);
+ viewPopup.setAccel( SHIFT + Key_Right, NEXT_VIEW_ID );
+ viewPopup.insertItem(i18n("Previous"), PREVIOUS_VIEW_ID);
+ viewPopup.setAccel( SHIFT + Key_Left, PREVIOUS_VIEW_ID );
+
+ popup.insertItem( TQPixmap(), &viewPopup, VIEW_POPUP_ID );
+ popup.changeItem( VIEW_POPUP_ID, i18n( "View" ) );
+
+ int result=popup.exec(TQCursor::pos());
+
+ executeAction( result, fileItem );
+}
+
+void DiskUsage::executeAction( int action, File * fileItem )
+{
+ // check out the user's option
+ switch ( action )
+ {
+ case DELETE_ID:
+ if( fileItem )
+ del( fileItem );
+ break;
+ case EXCLUDE_ID:
+ if( fileItem )
+ exclude( fileItem );
+ break;
+ case PARENT_DIR_ID:
+ dirUp();
+ break;
+ case NEW_SEARCH_ID:
+ emit newSearch();
+ break;
+ case REFRESH_ID:
+ load( baseURL );
+ break;
+ case INCLUDE_ALL_ID:
+ includeAll();
+ break;
+ case STEP_INTO_ID:
+ {
+ TQString uri;
+ if( fileItem && fileItem->isDir() )
+ uri = fileItem->fullPath();
+ else
+ uri = currentDirectory->fullPath();
+ ACTIVE_FUNC->openUrl(vfs::fromPathOrURL( uri ));
+ }
+ break;
+ case LINES_VIEW_ID:
+ setView( VIEW_LINES );
+ break;
+ case DETAILED_VIEW_ID:
+ setView( VIEW_DETAILED );
+ break;
+ case FILELIGHT_VIEW_ID:
+ setView( VIEW_FILELIGHT );
+ break;
+ case NEXT_VIEW_ID:
+ setView( ( activeView + 1 ) % 3 );
+ break;
+ case PREVIOUS_VIEW_ID:
+ setView( ( activeView + 2 ) % 3 );
+ break;
+ }
+ visibleWidget()->setFocus();
+}
+
+void DiskUsage::keyPressEvent( TQKeyEvent *e )
+{
+ if( activeView != VIEW_LOADER )
+ {
+ switch ( e->key() )
+ {
+ case Key_E:
+ if( e->state() == ControlButton )
+ {
+ executeAction( EXCLUDE_ID, getCurrentFile() );
+ return;
+ }
+ case Key_D:
+ if( e->state() == ControlButton )
+ {
+ executeAction( DETAILED_VIEW_ID );
+ return;
+ }
+ case Key_F:
+ if( e->state() == ControlButton )
+ {
+ executeAction( FILELIGHT_VIEW_ID );
+ return;
+ }
+ case Key_I:
+ if( e->state() == ControlButton )
+ {
+ executeAction( INCLUDE_ALL_ID );
+ return;
+ }
+ break;
+ case Key_L:
+ if( e->state() == ControlButton )
+ {
+ executeAction( LINES_VIEW_ID );
+ return;
+ }
+ case Key_N:
+ if( e->state() == ControlButton )
+ {
+ executeAction( NEW_SEARCH_ID );
+ return;
+ }
+ break;
+ case Key_R:
+ if( e->state() == ControlButton )
+ {
+ executeAction( REFRESH_ID );
+ return;
+ }
+ break;
+ case Key_Up:
+ if( e->state() == ShiftButton )
+ {
+ executeAction( PARENT_DIR_ID );
+ return;
+ }
+ break;
+ case Key_Down:
+ if( e->state() == ShiftButton )
+ {
+ executeAction( STEP_INTO_ID );
+ return;
+ }
+ break;
+ case Key_Left:
+ if( e->state() == ShiftButton )
+ {
+ executeAction( PREVIOUS_VIEW_ID );
+ return;
+ }
+ break;
+ case Key_Right:
+ if( e->state() == ShiftButton )
+ {
+ executeAction( NEXT_VIEW_ID );
+ return;
+ }
+ break;
+ case Key_Delete:
+ if( !e->state() )
+ {
+ executeAction( DELETE_ID, getCurrentFile() );
+ return;
+ }
+ case Key_Plus:
+ if( activeView == VIEW_FILELIGHT )
+ {
+ filelightView->zoomIn();
+ return;
+ }
+ break;
+ case Key_Minus:
+ if( activeView == VIEW_FILELIGHT )
+ {
+ filelightView->zoomOut();
+ return;
+ }
+ break;
+ }
+ }
+ TQWidgetStack::keyPressEvent( e );
+}
+
+TQPixmap DiskUsage::getIcon( TQString mime )
+{
+ TQPixmap icon;
+
+ if ( !TQPixmapCache::find( mime, icon ) )
+ {
+ // get the icon.
+ if ( mime == "Broken Link !" )
+ icon = FL_LOADICON( "file_broken" );
+ else
+ icon = FL_LOADICON( KMimeType::mimeType( mime ) ->icon( TQString(), true ) );
+
+ // insert it into the cache
+ TQPixmapCache::insert( mime, icon );
+ }
+ return icon;
+}
+
+int DiskUsage::calculatePercents( bool emitSig, Directory *dirEntry, int depth )
+{
+ int changeNr = 0;
+
+ if( dirEntry == 0 )
+ dirEntry = root;
+
+ for( Iterator<File> it = dirEntry->iterator(); it != dirEntry->end(); ++it )
+ {
+ File *item = *it;
+
+ if( !item->isExcluded() )
+ {
+ int newPerc;
+
+ if( dirEntry->size() == 0 && item->size() == 0 )
+ newPerc = 0;
+ else if( dirEntry->size() == 0 )
+ newPerc = -1;
+ else
+ newPerc = (int)((double)item->size() / (double)currentSize * 10000. + 0.5);
+
+ int oldPerc = item->intPercent();
+ item->setPercent( newPerc );
+
+ if( emitSig && newPerc != oldPerc ) {
+ emit changed( item );
+ changeNr++;
+ }
+
+ if( item->isDir() )
+ changeNr += calculatePercents( emitSig, dynamic_cast<Directory *>( item ), depth + 1 );
+ }
+ }
+
+ if( depth == 0 && changeNr != 0 )
+ emit changeFinished();
+ return changeNr;
+}
+
+TQString DiskUsage::getToolTip( File *item )
+{
+ KMimeType::Ptr mimePtr = KMimeType::mimeType( item->mime() );
+ TQString mime = mimePtr->comment();
+
+ time_t tma = item->time();
+ struct tm* t=localtime((time_t *)&tma);
+ TQDateTime tmp(TQDate(t->tm_year+1900, t->tm_mon+1, t->tm_mday), TQTime(t->tm_hour, t->tm_min));
+ TQString date = TDEGlobal::locale()->formatDateTime(tmp);
+
+ TQString str = "<qt><h5><table><tr><td>" + i18n( "Name:" ) + "</td><td>" + item->name() + "</td></tr>"+
+ "<tr><td>" + i18n( "Type:" ) + "</td><td>" + mime + "</td></tr>"+
+ "<tr><td>" + i18n( "Size:" ) + "</td><td>" + KRpermHandler::parseSize( item->size() ) + "</td></tr>";
+
+ if( item->isDir() )
+ str += "<tr><td>" + i18n( "Own size:" ) + "</td><td>" + KRpermHandler::parseSize( item->ownSize() ) + "</td></tr>";
+
+ str += "<tr><td>" + i18n( "Last modified:" ) + "</td><td>" + date + "</td></tr>"+
+ "<tr><td>" + i18n( "Permissions:" ) + "</td><td>" + item->perm() + "</td></tr>"+
+ "<tr><td>" + i18n( "Owner:" ) + "</td><td>" + item->owner() + " - " + item->group() + "</td></tr>"+
+ "</table></h5></qt>";
+ str.replace( " ", "&nbsp;" );
+ return str;
+}
+
+void DiskUsage::setView( int view )
+{
+ switch( view )
+ {
+ case VIEW_LINES:
+ raiseWidget( lineView );
+ break;
+ case VIEW_DETAILED:
+ raiseWidget( listView );
+ break;
+ case VIEW_FILELIGHT:
+ raiseWidget( filelightView );
+ break;
+ case VIEW_LOADER:
+ raiseWidget( loaderView );
+ break;
+ }
+
+ visibleWidget()->setFocus();
+ emit viewChanged( activeView = view );
+}
+
+File * DiskUsage::getCurrentFile()
+{
+ File * file = 0;
+
+ switch( activeView )
+ {
+ case VIEW_LINES:
+ file = lineView->getCurrentFile();
+ break;
+ case VIEW_DETAILED:
+ file = listView->getCurrentFile();
+ break;
+ case VIEW_FILELIGHT:
+ file = filelightView->getCurrentFile();
+ break;
+ }
+
+ return file;
+}
+
+bool DiskUsage::event( TQEvent * e )
+{
+ if( deleting ) { // if we are deleting, disable the mouse and
+ switch( e->type() ) { // keyboard events
+ case TQEvent::MouseButtonPress:
+ case TQEvent::MouseButtonRelease:
+ case TQEvent::MouseButtonDblClick:
+ case TQEvent::MouseMove:
+ case TQEvent::KeyPress:
+ case TQEvent::KeyRelease:
+ return true;
+ default:
+ break;
+ }
+ }
+
+ if ( e->type() == TQEvent::AccelOverride )
+ {
+ TQKeyEvent* ke = (TQKeyEvent*) e;
+
+ if ( ke->state() == TQt::NoButton || ke->state() == Keypad )
+ {
+ switch ( ke->key() )
+ {
+ case Key_Delete:
+ case Key_Plus:
+ case Key_Minus:
+ ke->accept();
+ break;
+ }
+ }else if( ke->state() == ShiftButton )
+ {
+ switch ( ke->key() )
+ {
+ case Key_Left:
+ case Key_Right:
+ case Key_Up:
+ case Key_Down:
+ ke->accept();
+ break;
+ }
+ }else if ( ke->state() & ControlButton )
+ {
+ switch ( ke->key() )
+ {
+ case Key_D:
+ case Key_E:
+ case Key_F:
+ case Key_I:
+ case Key_L:
+ case Key_N:
+ case Key_R:
+ ke->accept();
+ break;
+ }
+ }
+ }
+ return TQWidgetStack::event( e );
+}
+
+#include "diskusage.moc"
diff --git a/src/app/DiskUsage/diskusage.h b/src/app/DiskUsage/diskusage.h
new file mode 100644
index 0000000..ae70bdd
--- /dev/null
+++ b/src/app/DiskUsage/diskusage.h
@@ -0,0 +1,206 @@
+/***************************************************************************
+ diskusage.h - description
+ -------------------
+ copyright : (C) 2004 by Csaba Karai
+ e-mail : krusader@users.sourceforge.net
+ web site : http://krusader.sourceforge.net
+ ---------------------------------------------------------------------------
+ Description
+ ***************************************************************************
+
+ A
+
+ db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b.
+ 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D
+ 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY'
+ 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b
+ 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88.
+ YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD
+
+ H e a d e r F i l e
+
+ ***************************************************************************
+ * *
+ * This program 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __DISK_USAGE_H__
+#define __DISK_USAGE_H__
+
+#include "../VFS/vfs.h"
+#include "filelightParts/fileTree.h"
+
+#include <tqdialog.h>
+#include <tqlabel.h>
+#include <tqdict.h>
+#include <tqptrlist.h>
+#include <tqptrdict.h>
+#include <tqvaluestack.h>
+#include <tqptrstack.h>
+#include <kurl.h>
+#include <ksqueezedtextlabel.h>
+#include <tqwidgetstack.h>
+#include <tqscrollview.h>
+#include <tqtimer.h>
+
+#define VIEW_LINES 0
+#define VIEW_DETAILED 1
+#define VIEW_FILELIGHT 2
+#define VIEW_LOADER 3
+
+typedef TQDict<void> Properties;
+
+class DUListView;
+class DULines;
+class DUFilelight;
+class TDEPopupMenu;
+class LoaderWidget;
+
+class DiskUsage : public TQWidgetStack
+{
+ TQ_OBJECT
+
+
+public:
+ DiskUsage( TQString confGroup, TQWidget *parent = 0, char *name = 0);
+ ~DiskUsage();
+
+ void load( KURL dirName );
+ void close();
+ void stopLoad();
+ bool isLoading() { return loading; }
+
+ void setView( int view );
+ int getActiveView() { return activeView; }
+
+ Directory* getDirectory( TQString path );
+ File * getFile( TQString path );
+
+ TQString getConfigGroup() { return configGroup; }
+
+ void * getProperty( File *, TQString );
+ void addProperty( File *, TQString, void * );
+ void removeProperty( File *, TQString );
+
+ int exclude( File *file, bool calcPercents = true, int depth = 0 );
+ void includeAll();
+
+ int del( File *file, bool calcPercents = true, int depth = 0 );
+
+ TQString getToolTip( File * );
+
+ void rightClickMenu( File *, TDEPopupMenu * = 0, TQString = TQString() );
+
+ void changeDirectory( Directory *dir );
+
+ Directory* getCurrentDir();
+ File* getCurrentFile();
+
+ TQPixmap getIcon( TQString mime );
+
+ KURL getBaseURL() { return baseURL; }
+
+public slots:
+ void dirUp();
+ void clear();
+
+signals:
+ void enteringDirectory( Directory * );
+ void clearing();
+ void changed( File * );
+ void changeFinished();
+ void deleted( File * );
+ void deleteFinished();
+ void status( TQString );
+ void viewChanged( int );
+ void loadFinished( bool );
+ void newSearch();
+
+protected slots:
+ void slotLoadDirectory();
+
+protected:
+ TQDict< Directory > contentMap;
+ TQPtrDict<Properties> propertyMap;
+
+ Directory* currentDirectory;
+ TDEIO::filesize_t currentSize;
+
+ virtual void keyPressEvent( TQKeyEvent * );
+ virtual bool event( TQEvent * );
+
+ int calculateSizes( Directory *dir = 0, bool emitSig = false, int depth = 0 );
+ int calculatePercents( bool emitSig = false, Directory *dir = 0 , int depth = 0 );
+ int include( Directory *dir, int depth = 0 );
+ void createStatus();
+ void executeAction( int, File * = 0 );
+
+ KURL baseURL; //< the base URL of loading
+
+ DUListView *listView;
+ DULines *lineView;
+ DUFilelight *filelightView;
+ LoaderWidget *loaderView;
+
+ Directory *root;
+
+ int activeView;
+
+ TQString configGroup;
+
+ bool first;
+ bool loading;
+ bool abortLoading;
+ bool clearAfterAbort;
+ bool deleting;
+
+ TQValueStack<TQString> directoryStack;
+ TQPtrStack<Directory> parentStack;
+
+ vfs * searchVfs;
+ vfile * currentVfile;
+ Directory * currentParent;
+ TQString dirToCheck;
+
+ int fileNum;
+ int dirNum;
+ int viewBeforeLoad;
+
+ TQTimer loadingTimer;
+};
+
+
+class LoaderWidget : public TQScrollView
+{
+ TQ_OBJECT
+
+
+public:
+ LoaderWidget( TQWidget *parent = 0, const char *name = 0 );
+
+ void init();
+ void setCurrentURL( KURL url );
+ void setValues( int fileNum, int dirNum, TDEIO::filesize_t total );
+ bool wasCancelled() { return cancelled; }
+
+public slots:
+ void slotCancelled();
+
+protected:
+ virtual void resizeEvent ( TQResizeEvent *e );
+
+ TQLabel *totalSize;
+ TQLabel *files;
+ TQLabel *directories;
+
+ KSqueezedTextLabel *searchedDirectory;
+ TQWidget *widget;
+
+ bool cancelled;
+};
+
+#endif /* __DISK_USAGE_GUI_H__ */
diff --git a/src/app/DiskUsage/diskusagegui.cpp b/src/app/DiskUsage/diskusagegui.cpp
new file mode 100644
index 0000000..28b52ce
--- /dev/null
+++ b/src/app/DiskUsage/diskusagegui.cpp
@@ -0,0 +1,227 @@
+/***************************************************************************
+ diskusagegui.cpp - description
+ -------------------
+ copyright : (C) 2004 by Csaba Karai
+ e-mail : krusader@users.sourceforge.net
+ web site : http://krusader.sourceforge.net
+ ---------------------------------------------------------------------------
+ Description
+ ***************************************************************************
+
+ A
+
+ db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b.
+ 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D
+ 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY'
+ 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b
+ 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88.
+ YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD
+
+ S o u r c e F i l e
+
+ ***************************************************************************
+ * *
+ * This program 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "diskusagegui.h"
+#include "../kicons.h"
+#include "../krusader.h"
+#include "../VFS/vfs.h"
+#include "../Dialogs/krdialogs.h"
+
+#include <tqtimer.h>
+#include <tqhbox.h>
+#include <tdelocale.h>
+#include <tqtooltip.h>
+
+DiskUsageGUI::DiskUsageGUI( KURL openDir, TQWidget* parent, const char *name )
+ : TQDialog( parent, name, false, 0 ), exitAtFailure( true )
+{
+ setCaption( i18n("Krusader::Disk Usage") );
+
+ baseDirectory = openDir;
+ if( !newSearch() )
+ return;
+
+ TQGridLayout *duGrid = new TQGridLayout( this );
+ duGrid->setSpacing( 6 );
+ duGrid->setMargin( 11 );
+
+ TQHBox *duTools = new TQHBox( this, "duTools" );
+ duTools->setSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Fixed );
+
+ btnNewSearch = new TQToolButton( duTools, "btnNewSearch" );
+ btnNewSearch->setIconSet( TQIconSet(krLoader->loadIcon("document-open",TDEIcon::Desktop)) );
+ TQToolTip::add( btnNewSearch, i18n( "Start new disk usage search" ) );
+
+ btnRefresh = new TQToolButton( duTools, "btnRefresh" );
+ btnRefresh->setIconSet( TQIconSet(krLoader->loadIcon("reload",TDEIcon::Desktop)) );
+ TQToolTip::add( btnRefresh, i18n( "Refresh" ) );
+
+ btnDirUp = new TQToolButton( duTools, "btnDirUp" );
+ btnDirUp->setIconSet( TQIconSet(krLoader->loadIcon("go-up",TDEIcon::Desktop)) );
+ TQToolTip::add( btnDirUp, i18n( "Parent directory" ) );
+
+ TQWidget * separatorWidget = new TQWidget( duTools, "separatorWidget" );
+ separatorWidget->setMinimumWidth( 10 );
+
+ btnLines = new TQToolButton( duTools, "btnLines" );
+ btnLines->setIconSet( TQIconSet(krLoader->loadIcon("format-justify-left",TDEIcon::Desktop)) );
+ btnLines->setToggleButton( true );
+ TQToolTip::add( btnLines, i18n( "Line view" ) );
+
+ btnDetailed = new TQToolButton( duTools, "btnDetailed" );
+ btnDetailed->setIconSet( TQIconSet(krLoader->loadIcon("view_detailed",TDEIcon::Desktop)) );
+ btnDetailed->setToggleButton( true );
+ TQToolTip::add( btnDetailed, i18n( "Detailed view" ) );
+
+ btnFilelight = new TQToolButton( duTools, "btnFilelight" );
+ btnFilelight->setIconSet( TQIconSet(krLoader->loadIcon("kr_diskusage",TDEIcon::Desktop)) );
+ btnFilelight->setToggleButton( true );
+ TQToolTip::add( btnFilelight, i18n( "Filelight view" ) );
+
+ TQWidget *spacerWidget = new TQWidget( duTools, "spacerWidget" );
+ TQHBoxLayout *hboxlayout = new TQHBoxLayout( spacerWidget );
+ TQSpacerItem* spacer = new TQSpacerItem( 0, 0, TQSizePolicy::Expanding, TQSizePolicy::Fixed );
+ hboxlayout->addItem( spacer );
+
+ duGrid->addWidget( duTools, 0, 0 );
+
+ diskUsage = new DiskUsage( "DiskUsage", this );
+ duGrid->addWidget( diskUsage, 1, 0 );
+
+ status = new KSqueezedTextLabel( this );
+ status->setFrameShape( TQLabel::StyledPanel );
+ status->setFrameShadow( TQLabel::Sunken );
+ duGrid->addWidget( status, 2, 0 );
+
+ connect( diskUsage, TQ_SIGNAL( status( TQString ) ), this, TQ_SLOT( setStatus( TQString ) ) );
+ connect( diskUsage, TQ_SIGNAL( viewChanged( int ) ), this, TQ_SLOT( slotViewChanged( int ) ) );
+ connect( diskUsage, TQ_SIGNAL( newSearch() ), this, TQ_SLOT( newSearch() ) );
+ connect( diskUsage, TQ_SIGNAL( loadFinished( bool ) ), this, TQ_SLOT( slotLoadFinished( bool ) ) );
+ connect( btnNewSearch, TQ_SIGNAL( clicked() ), this, TQ_SLOT( newSearch() ) );
+ connect( btnRefresh, TQ_SIGNAL( clicked() ), this, TQ_SLOT( loadUsageInfo() ) );
+ connect( btnDirUp, TQ_SIGNAL( clicked() ), diskUsage, TQ_SLOT( dirUp() ) );
+ connect( btnLines, TQ_SIGNAL( clicked() ), this, TQ_SLOT( selectLinesView() ) );
+ connect( btnDetailed, TQ_SIGNAL( clicked() ), this, TQ_SLOT( selectListView() ) );
+ connect( btnFilelight, TQ_SIGNAL( clicked() ), this, TQ_SLOT( selectFilelightView() ) );
+
+ krConfig->setGroup( "DiskUsage" );
+
+ int view = krConfig->readNumEntry( "View", VIEW_LINES );
+ if( view < VIEW_LINES || view > VIEW_FILELIGHT )
+ view = VIEW_LINES;
+ diskUsage->setView( view );
+
+ sizeX = krConfig->readNumEntry( "Window Width", TQFontMetrics(font()).width("W") * 70 );
+ sizeY = krConfig->readNumEntry( "Window Height", TQFontMetrics(font()).height() * 25 );
+ resize( sizeX, sizeY );
+
+ if( krConfig->readBoolEntry( "Window Maximized", false ) )
+ showMaximized();
+ else
+ show();
+
+ exec();
+}
+
+DiskUsageGUI::~DiskUsageGUI()
+{
+}
+
+void DiskUsageGUI::slotLoadFinished( bool result )
+{
+ if( exitAtFailure && !result )
+ reject();
+ else
+ exitAtFailure = false;
+}
+
+void DiskUsageGUI::enableButtons( bool isOn )
+{
+ btnNewSearch->setEnabled( isOn );
+ btnRefresh->setEnabled( isOn );
+ btnDirUp->setEnabled( isOn );
+ btnLines->setEnabled( isOn );
+ btnDetailed->setEnabled( isOn );
+ btnFilelight->setEnabled( isOn );
+}
+
+void DiskUsageGUI::resizeEvent( TQResizeEvent *e )
+{
+ if( !isMaximized() )
+ {
+ sizeX = e->size().width();
+ sizeY = e->size().height();
+ }
+ TQDialog::resizeEvent( e );
+}
+
+void DiskUsageGUI::reject()
+{
+ krConfig->setGroup( "DiskUsage" );
+ krConfig->writeEntry("Window Width", sizeX );
+ krConfig->writeEntry("Window Height", sizeY );
+ krConfig->writeEntry("Window Maximized", isMaximized() );
+ krConfig->writeEntry("View", diskUsage->getActiveView() );
+
+ TQDialog::reject();
+}
+
+void DiskUsageGUI::loadUsageInfo()
+{
+ diskUsage->load( baseDirectory );
+}
+
+void DiskUsageGUI::setStatus( TQString stat )
+{
+ status->setText( stat );
+}
+
+void DiskUsageGUI::slotViewChanged( int view )
+{
+ if( view == VIEW_LOADER )
+ {
+ enableButtons( false );
+ return;
+ }
+ enableButtons( true );
+
+ btnLines->setOn( false );
+ btnDetailed->setOn( false );
+ btnFilelight->setOn( false );
+
+ switch( view )
+ {
+ case VIEW_LINES:
+ btnLines->setOn( true );
+ break;
+ case VIEW_DETAILED:
+ btnDetailed->setOn( true );
+ break;
+ case VIEW_FILELIGHT:
+ btnFilelight->setOn( true );
+ break;
+ case VIEW_LOADER:
+ break;
+ }
+}
+
+bool DiskUsageGUI::newSearch()
+{
+ // ask the user for the copy dest
+
+ KURL tmp = KChooseDir::getDir(i18n( "Viewing the usage of directory:" ), baseDirectory, baseDirectory);
+ if (tmp.isEmpty()) return false;
+ baseDirectory = tmp;
+
+ TQTimer::singleShot( 0, this, TQ_SLOT( loadUsageInfo() ) );
+ return true;
+}
+
+#include "diskusagegui.moc"
diff --git a/src/app/DiskUsage/diskusagegui.h b/src/app/DiskUsage/diskusagegui.h
new file mode 100644
index 0000000..1c75a79
--- /dev/null
+++ b/src/app/DiskUsage/diskusagegui.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+ diskusagegui.h - description
+ -------------------
+ copyright : (C) 2004 by Csaba Karai
+ e-mail : krusader@users.sourceforge.net
+ web site : http://krusader.sourceforge.net
+ ---------------------------------------------------------------------------
+ Description
+ ***************************************************************************
+
+ A
+
+ db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b.
+ 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D
+ 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY'
+ 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b
+ 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88.
+ YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD
+
+ H e a d e r F i l e
+
+ ***************************************************************************
+ * *
+ * This program 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __DISK_USAGE_GUI_H__
+#define __DISK_USAGE_GUI_H__
+
+#include <tqdialog.h>
+#include <tqlayout.h>
+#include <tqtoolbutton.h>
+#include <kurl.h>
+#include <ksqueezedtextlabel.h>
+
+#include "diskusage.h"
+
+class DiskUsageGUI : public TQDialog
+{
+ TQ_OBJECT
+
+
+public:
+ DiskUsageGUI( KURL openDir, TQWidget* parent=0, const char *name = 0 );
+ ~DiskUsageGUI();
+
+
+public slots:
+ void loadUsageInfo();
+ bool newSearch();
+ void setStatus( TQString );
+
+ void selectLinesView() { diskUsage->setView( VIEW_LINES ); }
+ void selectListView() { diskUsage->setView( VIEW_DETAILED ); }
+ void selectFilelightView() { diskUsage->setView( VIEW_FILELIGHT ); }
+
+protected slots:
+ virtual void reject();
+ void slotViewChanged( int view );
+ void enableButtons( bool );
+ void slotLoadFinished( bool );
+
+protected:
+ virtual void resizeEvent( TQResizeEvent *e );
+
+ DiskUsage *diskUsage;
+ KURL baseDirectory;
+
+ KSqueezedTextLabel *status;
+
+ TQToolButton *btnNewSearch;
+ TQToolButton *btnRefresh;
+ TQToolButton *btnDirUp;
+
+ TQToolButton *btnLines;
+ TQToolButton *btnDetailed;
+ TQToolButton *btnFilelight;
+
+ int sizeX;
+ int sizeY;
+
+ bool exitAtFailure;
+};
+
+#endif /* __DISK_USAGE_GUI_H__ */
+
diff --git a/src/app/DiskUsage/dufilelight.cpp b/src/app/DiskUsage/dufilelight.cpp
new file mode 100644
index 0000000..debdb06
--- /dev/null
+++ b/src/app/DiskUsage/dufilelight.cpp
@@ -0,0 +1,236 @@
+/***************************************************************************
+ dufilelight.cpp - description
+ -------------------
+ copyright : (C) 2004 by Csaba Karai
+ e-mail : krusader@users.sourceforge.net
+ web site : http://krusader.sourceforge.net
+ ---------------------------------------------------------------------------
+ Description
+ ***************************************************************************
+
+ A
+
+ db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b.
+ 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D
+ 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY'
+ 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b
+ 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88.
+ YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD
+
+ S o u r c e F i l e
+
+ ***************************************************************************
+ * *
+ * This program 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "dufilelight.h"
+#include "radialMap/radialMap.h"
+#include <tdepopupmenu.h>
+#include <tdelocale.h>
+#include <kinputdialog.h>
+
+#define SCHEME_POPUP_ID 6730
+
+DUFilelight::DUFilelight( DiskUsage *usage, const char *name )
+ : RadialMap::Widget( usage, name ), diskUsage( usage ), currentDir( 0 ), refreshNeeded( true )
+{
+ setFocusPolicy( TQWidget::StrongFocus );
+
+ connect( diskUsage, TQ_SIGNAL( enteringDirectory( Directory * ) ), this, TQ_SLOT( slotDirChanged( Directory * ) ) );
+ connect( diskUsage, TQ_SIGNAL( clearing() ), this, TQ_SLOT( clear() ) );
+ connect( diskUsage, TQ_SIGNAL( changed( File * ) ), this, TQ_SLOT( slotChanged( File * ) ) );
+ connect( diskUsage, TQ_SIGNAL( deleted( File * ) ), this, TQ_SLOT( slotChanged( File * ) ) );
+ connect( diskUsage, TQ_SIGNAL( changeFinished() ), this, TQ_SLOT( slotRefresh() ) );
+ connect( diskUsage, TQ_SIGNAL( deleteFinished() ), this, TQ_SLOT( slotRefresh() ) );
+ connect( diskUsage, TQ_SIGNAL( aboutToShow( TQWidget * ) ), this, TQ_SLOT( slotAboutToShow( TQWidget * ) ) );
+}
+
+void DUFilelight::slotDirChanged( Directory *dir )
+{
+ if( diskUsage->visibleWidget() != this )
+ return;
+
+ if( currentDir != dir )
+ {
+ currentDir = dir;
+
+ invalidate( false );
+ create( dir );
+ refreshNeeded = false;
+ }
+}
+
+void DUFilelight::clear()
+{
+ invalidate( false );
+ currentDir = 0;
+}
+
+File * DUFilelight::getCurrentFile()
+{
+ const RadialMap::Segment * focus = focusSegment();
+
+ if( !focus || focus->isFake() || focus->file() == currentDir )
+ return 0;
+
+ return (File *)focus->file();
+}
+
+void DUFilelight::mousePressEvent( TQMouseEvent *event )
+{
+ if( event->button() == TQt::RightButton )
+ {
+ File * file = 0;
+
+ const RadialMap::Segment * focus = focusSegment();
+
+ if( focus && !focus->isFake() && focus->file() != currentDir )
+ file = (File *)focus->file();
+
+ TDEPopupMenu filelightPopup;
+ filelightPopup.insertItem( i18n("Zoom In"), this, TQ_SLOT( zoomIn() ), Key_Plus );
+ filelightPopup.insertItem( i18n("Zoom Out"), this, TQ_SLOT( zoomOut() ), Key_Minus );
+
+ TDEPopupMenu schemePopup;
+ schemePopup.insertItem( i18n("Rainbow"), this, TQ_SLOT( schemeRainbow() ) );
+ schemePopup.insertItem( i18n("High Contrast"), this, TQ_SLOT( schemeHighContrast() ) );
+ schemePopup.insertItem( i18n("TDE"), this, TQ_SLOT( schemeKDE() ) );
+
+ filelightPopup.insertItem( TQPixmap(), &schemePopup, SCHEME_POPUP_ID );
+ filelightPopup.changeItem( SCHEME_POPUP_ID, i18n( "Scheme" ) );
+
+ filelightPopup.insertItem( i18n("Increase contrast"), this, TQ_SLOT( increaseContrast() ) );
+ filelightPopup.insertItem( i18n("Decrease contrast"), this, TQ_SLOT( decreaseContrast() ) );
+
+ int aid = filelightPopup.insertItem( i18n("Use anti-aliasing" ), this, TQ_SLOT( changeAntiAlias() ) );
+ filelightPopup.setItemChecked( aid, Filelight::Config::antiAliasFactor > 1 );
+
+ int sid = filelightPopup.insertItem( i18n("Show small files" ), this, TQ_SLOT( showSmallFiles() ) );
+ filelightPopup.setItemChecked( sid, Filelight::Config::showSmallFiles );
+
+ int vid = filelightPopup.insertItem( i18n("Vary label font sizes" ), this, TQ_SLOT( varyLabelFontSizes() ) );
+ filelightPopup.setItemChecked( vid, Filelight::Config::varyLabelFontSizes );
+
+ filelightPopup.insertItem( i18n("Minimum font size"), this, TQ_SLOT( minFontSize() ) );
+
+ diskUsage->rightClickMenu( file, &filelightPopup, i18n( "Filelight" ) );
+ return;
+ }else if( event->button() == TQt::LeftButton )
+ {
+ const RadialMap::Segment * focus = focusSegment();
+
+ if( focus && !focus->isFake() && focus->file() == currentDir )
+ {
+ diskUsage->dirUp();
+ return;
+ }
+ else if( focus && !focus->isFake() && focus->file()->isDir() )
+ {
+ diskUsage->changeDirectory( (Directory *)focus->file() );
+ return;
+ }
+ }
+
+ RadialMap::Widget::mousePressEvent( event );
+}
+
+void DUFilelight::setScheme( Filelight::MapScheme scheme )
+{
+ Filelight::Config::scheme = scheme;
+ Filelight::Config::write();
+ slotRefresh();
+}
+
+void DUFilelight::increaseContrast()
+{
+ if( ( Filelight::Config::contrast += 10 ) > 100 )
+ Filelight::Config::contrast = 100;
+
+ Filelight::Config::write();
+ slotRefresh();
+}
+
+void DUFilelight::decreaseContrast()
+{
+ if( ( Filelight::Config::contrast -= 10 ) > 100 )
+ Filelight::Config::contrast = 0;
+
+ Filelight::Config::write();
+ slotRefresh();
+}
+
+void DUFilelight::changeAntiAlias()
+{
+ Filelight::Config::antiAliasFactor = 1 + ( Filelight::Config::antiAliasFactor == 1 );
+ Filelight::Config::write();
+ slotRefresh();
+}
+
+void DUFilelight::showSmallFiles()
+{
+ Filelight::Config::showSmallFiles = !Filelight::Config::showSmallFiles;
+ Filelight::Config::write();
+ slotRefresh();
+}
+
+void DUFilelight::varyLabelFontSizes()
+{
+ Filelight::Config::varyLabelFontSizes = !Filelight::Config::varyLabelFontSizes;
+ Filelight::Config::write();
+ slotRefresh();
+}
+
+void DUFilelight::minFontSize()
+{
+ bool ok = false;
+
+ int result = KInputDialog::getInteger( i18n( "Krusader::Filelight" ),
+ i18n( "Minimum font size" ), (int)Filelight::Config::minFontPitch, 1, 100, 1, &ok, this );
+
+ if ( ok )
+ {
+ Filelight::Config::minFontPitch = (uint)result;
+
+ Filelight::Config::write();
+ slotRefresh();
+ }
+}
+
+void DUFilelight::slotAboutToShow( TQWidget *widget )
+{
+ if( widget == this && ( diskUsage->getCurrentDir() != currentDir || refreshNeeded ) )
+ {
+ refreshNeeded = false;
+ if( ( currentDir = diskUsage->getCurrentDir() ) != 0 )
+ {
+ invalidate( false );
+ create( currentDir );
+ }
+ }
+}
+
+void DUFilelight::slotRefresh()
+{
+ if( diskUsage->visibleWidget() != this )
+ return;
+
+ refreshNeeded = false;
+ if( currentDir && currentDir == diskUsage->getCurrentDir() )
+ {
+ invalidate( false );
+ create( currentDir );
+ }
+}
+
+void DUFilelight::slotChanged( File * )
+{
+ if( !refreshNeeded )
+ refreshNeeded = true;
+}
+
+#include "dufilelight.moc"
diff --git a/src/app/DiskUsage/dufilelight.h b/src/app/DiskUsage/dufilelight.h
new file mode 100644
index 0000000..9ef8ccb
--- /dev/null
+++ b/src/app/DiskUsage/dufilelight.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+ dufilelight.h - description
+ -------------------
+ copyright : (C) 2004 by Csaba Karai
+ e-mail : krusader@users.sourceforge.net
+ web site : http://krusader.sourceforge.net
+ ---------------------------------------------------------------------------
+ Description
+ ***************************************************************************
+
+ A
+
+ db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b.
+ 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D
+ 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY'
+ 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b
+ 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88.
+ YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD
+
+ H e a d e r F i l e
+
+ ***************************************************************************
+ * *
+ * This program 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __DU_FILELIGHT_H__
+#define __DU_FILELIGHT_H__
+
+#include "diskusage.h"
+#include "radialMap/widget.h"
+#include "filelightParts/Config.h"
+
+class DUFilelight : public RadialMap::Widget
+{
+ TQ_OBJECT
+
+
+public:
+ DUFilelight( DiskUsage *usage, const char *name );
+
+ File * getCurrentFile();
+
+public slots:
+ void slotDirChanged( Directory * );
+ void clear();
+ void slotChanged( File * );
+ void slotRefresh();
+
+protected slots:
+ void slotAboutToShow( TQWidget *widget );
+
+ void schemeRainbow() { setScheme( Filelight::Rainbow ); }
+ void schemeHighContrast() { setScheme( Filelight::HighContrast ); }
+ void schemeKDE() { setScheme( Filelight::KDE ); }
+
+ void increaseContrast();
+ void decreaseContrast();
+ void changeAntiAlias();
+ void showSmallFiles();
+ void varyLabelFontSizes();
+ void minFontSize();
+
+protected:
+ virtual void mousePressEvent( TQMouseEvent* );
+
+ void setScheme( Filelight::MapScheme );
+
+ DiskUsage *diskUsage;
+ Directory *currentDir;
+
+private:
+ bool refreshNeeded;
+};
+
+#endif /* __DU_FILELIGHT_H__ */
+
diff --git a/src/app/DiskUsage/dulines.cpp b/src/app/DiskUsage/dulines.cpp
new file mode 100644
index 0000000..ba10a04
--- /dev/null
+++ b/src/app/DiskUsage/dulines.cpp
@@ -0,0 +1,522 @@
+/***************************************************************************
+ dulines.cpp - description
+ -------------------
+ copyright : (C) 2004 by Csaba Karai
+ e-mail : krusader@users.sourceforge.net
+ web site : http://krusader.sourceforge.net
+ ---------------------------------------------------------------------------
+ Description
+ ***************************************************************************
+
+ A
+
+ db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b.
+ 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D
+ 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY'
+ 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b
+ 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88.
+ YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD
+
+ S o u r c e F i l e
+
+ ***************************************************************************
+ * *
+ * This program 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "dulines.h"
+#include "../kicons.h"
+#include "../krusader.h"
+#include "../VFS/krpermhandler.h"
+#include <tqheader.h>
+#include <tdelocale.h>
+#include <tqpen.h>
+#include <tqpainter.h>
+#include <tqfontmetrics.h>
+#include <tqtimer.h>
+#include <tqtooltip.h>
+#include <tdepopupmenu.h>
+
+class DULinesItem : public TQListViewItem
+{
+public:
+ DULinesItem( DiskUsage *diskUsageIn, File *fileItem, TQListView * parent, TQString label1,
+ TQString label2, TQString label3, unsigned int italicPos ) : TQListViewItem( parent, label1, label2, label3 ),
+ diskUsage( diskUsageIn ), file( fileItem ), isTruncated( false ), italicTextPos( italicPos ) {}
+ DULinesItem( DiskUsage *diskUsageIn, File *fileItem, TQListView * parent, TQListViewItem * after,
+ TQString label1, TQString label2, TQString label3, unsigned int italicPos ) : TQListViewItem( parent, after, label1,
+ label2, label3 ), diskUsage( diskUsageIn ), file( fileItem ), isTruncated( false ), italicTextPos( italicPos ) {}
+
+ virtual int compare ( TQListViewItem * i, int col, bool ascending ) const
+ {
+ if( text(0) == ".." ) return ascending ? -1 : 1;
+ if( i->text(0) == "..") return ascending ? 1 : -1;
+
+ DULinesItem *compWith = dynamic_cast< DULinesItem * >( i );
+
+ TQString buf1,buf2;
+
+ switch( col )
+ {
+ case 0:
+ case 1:
+ buf1.sprintf("%025llu",file->size());
+ buf2.sprintf("%025llu",compWith->file->size());
+ return -TQString::compare( buf1, buf2 );
+ default:
+ return TQListViewItem::compare( i, col, ascending );
+ }
+ }
+
+ virtual void paintCell( TQPainter * p, const TQColorGroup & cg, int column, int width, int align )
+ {
+ if( column == 2 )
+ {
+ if ( isSelected() )
+ p->fillRect( 0, 0, width, height(), cg.brush( TQColorGroup::Highlight ) );
+ else
+ p->fillRect( 0, 0, width, height(), cg.brush( TQColorGroup::Base ) );
+
+ TQListView *lv = listView();
+
+ int pos = lv->itemMargin();
+
+ const TQPixmap *icon = pixmap( column );
+ if( icon )
+ {
+ int iconWidth = icon->width() + lv->itemMargin();
+ int xo = pos;
+ int yo = ( height() - icon->height() ) / 2;
+
+ p->drawPixmap( xo, yo, *icon );
+
+ pos += iconWidth;
+ }
+
+ TQFontMetrics fm( p->fontMetrics() );
+
+ if( isSelected() )
+ p->setPen( cg.highlightedText() );
+ else
+ p->setPen( cg.text() );
+
+ TQString t = text( column );
+ TQString b;
+
+ if( t.length() > italicTextPos )
+ {
+ b = t.mid( italicTextPos );
+ t.truncate( italicTextPos );
+ }
+
+ isTruncated = false;
+ if( !t.isEmpty() )
+ {
+ int remWidth = width-pos;
+
+ if( fm.width( t ) > remWidth )
+ {
+ while( !t.isEmpty() )
+ {
+ t.truncate( t.length() - 1 );
+ if( fm.width( t + "..." ) <= remWidth )
+ break;
+ }
+ t += "...";
+ isTruncated = true;
+ }
+
+ p->drawText( pos, 0, width, height(), align, t );
+ pos += fm.width( t );
+ }
+
+ if( !b.isEmpty() && !isTruncated )
+ {
+ TQFont font( p->font() );
+ font.setItalic( true );
+ p->setFont( font );
+
+ TQFontMetrics fm2( p->fontMetrics() );
+
+ int remWidth = width-pos;
+
+ if( fm2.width( b ) > remWidth )
+ {
+ while( !b.isEmpty() )
+ {
+ b.truncate( b.length() - 1 );
+ if( fm2.width( b + "..." ) <= remWidth )
+ break;
+ }
+ b += "...";
+ isTruncated = true;
+ }
+
+ p->drawText( pos, 0, width, height(), align, b );
+ }
+ }
+ else
+ TQListViewItem::paintCell( p, cg, column, width, align );
+ }
+
+ inline File * getFile() { return file; }
+
+private:
+ DiskUsage *diskUsage;
+ File *file;
+
+ bool isTruncated;
+ unsigned int italicTextPos;
+};
+
+class DULinesToolTip : public TQToolTip
+{
+public:
+ DULinesToolTip( DiskUsage *usage, TQWidget *parent, TQListView *lv );
+ void maybeTip( const TQPoint &pos );
+
+ virtual ~DULinesToolTip() {}
+private:
+ TQListView *view;
+ DiskUsage *diskUsage;
+};
+
+DULinesToolTip::DULinesToolTip( DiskUsage *usage, TQWidget *parent, TQListView *lv )
+ : TQToolTip( parent ), view( lv ), diskUsage( usage )
+{
+}
+
+void DULinesToolTip::maybeTip( const TQPoint &pos )
+{
+ TQListViewItem *item = view->itemAt( pos );
+ TQPoint contentsPos = view->viewportToContents( pos );
+ if ( !item )
+ return;
+
+ int col = view->header()->sectionAt( contentsPos.x() );
+
+ int width = item->width( TQFontMetrics( view->font() ), view, col );
+
+ TQRect r = view->itemRect( item );
+ int headerPos = view->header()->sectionPos( col );
+ r.setLeft( headerPos );
+ r.setRight( headerPos + view->header()->sectionSize( col ) );
+
+ if( col != 0 && width > view->columnWidth( col ) )
+ tip( r, item->text( col ) );
+ else if( col == 1 && item->text( 0 ) != ".." )
+ {
+ File *fileItem = ((DULinesItem *)item)->getFile();
+ tip( r, diskUsage->getToolTip( fileItem ) );
+ }
+}
+
+DULines::DULines( DiskUsage *usage, const char *name )
+ : TQListView( usage, name ), diskUsage( usage ), refreshNeeded( false )
+{
+ setAllColumnsShowFocus(true);
+ setVScrollBarMode(TQScrollView::Auto);
+ setHScrollBarMode(TQScrollView::Auto);
+ setShowSortIndicator(true);
+ setTreeStepSize( 10 );
+
+ int defaultSize = TQFontMetrics(font()).width("W");
+
+ krConfig->setGroup( diskUsage->getConfigGroup() );
+
+ showFileSize = krConfig->readBoolEntry( "L Show File Size", true );
+
+ int lineWidth = krConfig->readNumEntry("L Line Width", defaultSize * 20 );
+ addColumn( i18n("Line View"), lineWidth );
+ setColumnWidthMode(0,TQListView::Manual);
+ int precentWidth = krConfig->readNumEntry("L Percent Width", defaultSize * 6 );
+ addColumn( i18n("Percent"), precentWidth );
+ setColumnWidthMode(1,TQListView::Manual);
+ int nameWidth = krConfig->readNumEntry("L Name Width", defaultSize * 20 );
+ addColumn( i18n("Name"), nameWidth );
+ setColumnWidthMode(2,TQListView::Manual);
+
+ setColumnAlignment( 1, TQt::AlignRight );
+
+ header()->setStretchEnabled( true, 0 );
+
+ setSorting( 1 );
+
+ toolTip = new DULinesToolTip( diskUsage, viewport(), this );
+
+ connect( diskUsage, TQ_SIGNAL( enteringDirectory( Directory * ) ), this, TQ_SLOT( slotDirChanged( Directory * ) ) );
+ connect( diskUsage, TQ_SIGNAL( clearing() ), this, TQ_SLOT( clear() ) );
+
+ connect( header(), TQ_SIGNAL( sizeChange( int, int, int ) ), this, TQ_SLOT( sectionResized( int ) ) );
+
+ connect( this, TQ_SIGNAL(rightButtonPressed(TQListViewItem *, const TQPoint &, int)),
+ this, TQ_SLOT( slotRightClicked(TQListViewItem *) ) );
+ connect( diskUsage, TQ_SIGNAL( changed( File * ) ), this, TQ_SLOT( slotChanged( File * ) ) );
+ connect( diskUsage, TQ_SIGNAL( deleted( File * ) ), this, TQ_SLOT( slotDeleted( File * ) ) );
+}
+
+DULines::~DULines()
+{
+ krConfig->setGroup( diskUsage->getConfigGroup() );
+ krConfig->writeEntry("L Line Width", columnWidth( 0 ) );
+ krConfig->writeEntry("L Percent Width", columnWidth( 1 ) );
+ krConfig->writeEntry("L Name Width", columnWidth( 2 ) );
+ krConfig->writeEntry("L Show File Size", showFileSize );
+
+ delete toolTip;
+}
+
+void DULines::slotDirChanged( Directory *dirEntry )
+{
+ clear();
+
+ TQListViewItem * lastItem = 0;
+
+ if( ! ( dirEntry->parent() == 0 ) )
+ {
+ lastItem = new TQListViewItem( this, ".." );
+ lastItem->setPixmap( 0, FL_LOADICON( "go-up" ) );
+ lastItem->setSelectable( false );
+ }
+
+ int maxPercent = -1;
+ for( Iterator<File> it = dirEntry->iterator(); it != dirEntry->end(); ++it )
+ {
+ File *item = *it;
+ if( !item->isExcluded() && item->intPercent() > maxPercent )
+ maxPercent = item->intPercent();
+ }
+
+ for( Iterator<File> it = dirEntry->iterator(); it != dirEntry->end(); ++it )
+ {
+ File *item = *it;
+
+ TQString fileName = item->name();
+
+ unsigned int italicStart = fileName.length();
+
+ if( showFileSize )
+ fileName += " [" + TDEIO::convertSize( item->size() ) + "]";
+
+ if( lastItem == 0 )
+ lastItem = new DULinesItem( diskUsage, item, this, "", item->percent() + " ", fileName, italicStart );
+ else
+ lastItem = new DULinesItem( diskUsage, item, this, lastItem, "", item->percent() + " ", fileName, italicStart );
+
+ if( item->isExcluded() )
+ lastItem->setVisible( false );
+
+ lastItem->setPixmap( 2, diskUsage->getIcon( item->mime() ) );
+ lastItem->setPixmap( 0, createPixmap( item->intPercent(), maxPercent, columnWidth( 0 ) - itemMargin() ) );
+ }
+
+ setCurrentItem( firstChild() );
+}
+
+TQPixmap DULines::createPixmap( int percent, int maxPercent, int maxWidth )
+{
+ if( percent < 0 || percent > maxPercent || maxWidth < 2 || maxPercent == 0 )
+ return TQPixmap();
+ maxWidth -= 2;
+
+ int actualWidth = maxWidth*percent/maxPercent;
+ if( actualWidth == 0 )
+ return TQPixmap();
+
+ TQPen pen;
+ pen.setColor( TQt::black );
+ TQPainter painter;
+
+ int size = TQFontMetrics(font()).height()-2;
+ TQRect rect( 0, 0, actualWidth, size );
+ TQPixmap pixmap( rect.width(), rect.height() );
+
+ painter.begin( &pixmap );
+ painter.setPen( pen );
+
+ for( int i = 1; i < actualWidth - 1; i++ )
+ {
+ int color = (511*i/maxWidth);
+ if( color < 256 )
+ pen.setColor( TQColor( 255-color, 255, 0 ) );
+ else
+ pen.setColor( TQColor( color-256, 511-color, 0 ) );
+
+ painter.setPen( pen );
+ painter.drawLine( i, 1, i, size-1 );
+ }
+
+ pen.setColor( TQt::black );
+ painter.setPen( pen );
+ painter.drawRect( rect );
+ painter.end();
+ pixmap.detach();
+ return pixmap;
+}
+
+void DULines::sectionResized( int column )
+{
+ if( childCount() == 0 || column != 0 )
+ return;
+
+ Directory * currentDir = diskUsage->getCurrentDir();
+ if( currentDir == 0 )
+ return;
+
+ int maxPercent = -1;
+ for( Iterator<File> it = currentDir->iterator(); it != currentDir->end(); ++it )
+ {
+ File *item = *it;
+
+ if( !item->isExcluded() && item->intPercent() > maxPercent )
+ maxPercent = item->intPercent();
+ }
+
+ DULinesItem *duItem = (DULinesItem *)firstChild();
+ while( duItem )
+ {
+ if( duItem->text( 0 ) != ".." )
+ duItem->setPixmap( 0, createPixmap( duItem->getFile()->intPercent(), maxPercent, columnWidth( 0 ) ) );
+ duItem = (DULinesItem *)duItem->nextSibling();
+ }
+}
+
+bool DULines::doubleClicked( TQListViewItem * item )
+{
+ if( item )
+ {
+ if( item->text( 0 ) != ".." )
+ {
+ File *fileItem = ((DULinesItem *)item)->getFile();
+ if( fileItem->isDir() )
+ diskUsage->changeDirectory( dynamic_cast<Directory *> ( fileItem ) );
+ return true;
+ }
+ else
+ {
+ Directory *upDir = (Directory *)diskUsage->getCurrentDir()->parent();
+
+ if( upDir )
+ diskUsage->changeDirectory( upDir );
+ return true;
+ }
+ }
+ return false;
+}
+
+void DULines::contentsMouseDoubleClickEvent ( TQMouseEvent * e )
+{
+ if ( e || e->button() == TQt::LeftButton )
+ {
+ TQPoint vp = contentsToViewport(e->pos());
+ TQListViewItem * item = itemAt( vp );
+
+ if( doubleClicked( item ) )
+ return;
+
+ }
+ TQListView::contentsMouseDoubleClickEvent( e );
+}
+
+
+void DULines::keyPressEvent( TQKeyEvent *e )
+{
+ switch ( e->key() )
+ {
+ case Key_Return :
+ case Key_Enter :
+ if( doubleClicked( currentItem() ) )
+ return;
+ break;
+ case Key_Left :
+ case Key_Right :
+ case Key_Up :
+ case Key_Down :
+ if( e->state() == ShiftButton )
+ {
+ e->ignore();
+ return;
+ }
+ break;
+ case Key_Delete :
+ e->ignore();
+ return;
+ }
+ TQListView::keyPressEvent( e );
+}
+
+void DULines::slotRightClicked( TQListViewItem *item )
+{
+ File * file = 0;
+
+ if ( item && item->text( 0 ) != ".." )
+ file = ((DULinesItem *)item)->getFile();
+
+ TDEPopupMenu linesPopup;
+ int lid = linesPopup.insertItem( i18n("Show file sizes"), this, TQ_SLOT( slotShowFileSizes() ) );
+ linesPopup.setItemChecked( lid, showFileSize );
+
+ diskUsage->rightClickMenu( file, &linesPopup, i18n( "Lines" ) );
+}
+
+void DULines::slotShowFileSizes()
+{
+ showFileSize = !showFileSize;
+ slotDirChanged( diskUsage->getCurrentDir() );
+}
+
+File * DULines::getCurrentFile()
+{
+ TQListViewItem *item = currentItem();
+
+ if( item == 0 || item->text( 0 ) == ".." )
+ return 0;
+
+ return ((DULinesItem *)item)->getFile();
+}
+
+void DULines::slotChanged( File * item )
+{
+ TQListViewItem *lvitem = firstChild();
+ while( lvitem )
+ {
+ if( lvitem->text( 0 ) != ".." ) {
+ DULinesItem *duItem = (DULinesItem *)( lvitem );
+ if( duItem->getFile() == item )
+ {
+ duItem->setVisible( !item->isExcluded() );
+ duItem->setText( 1, item->percent() );
+ if( !refreshNeeded )
+ {
+ refreshNeeded = true;
+ TQTimer::singleShot( 0, this, TQ_SLOT( slotRefresh() ) );
+ }
+ break;
+ }
+ }
+ lvitem = lvitem->nextSibling();
+ }
+}
+
+void DULines::slotDeleted( File * item )
+{
+ TQListViewItem *lvitem = firstChild();
+ while( lvitem )
+ {
+ if( lvitem->text( 0 ) != ".." ) {
+ DULinesItem *duItem = (DULinesItem *)( lvitem );
+ if( duItem->getFile() == item )
+ {
+ delete duItem;
+ break;
+ }
+ }
+ lvitem = lvitem->nextSibling();
+ }
+}
+
+#include "dulines.moc"
diff --git a/src/app/DiskUsage/dulines.h b/src/app/DiskUsage/dulines.h
new file mode 100644
index 0000000..7531c86
--- /dev/null
+++ b/src/app/DiskUsage/dulines.h
@@ -0,0 +1,79 @@
+/***************************************************************************
+ dulines.h - description
+ -------------------
+ copyright : (C) 2004 by Csaba Karai
+ e-mail : krusader@users.sourceforge.net
+ web site : http://krusader.sourceforge.net
+ ---------------------------------------------------------------------------
+ Description
+ ***************************************************************************
+
+ A
+
+ db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b.
+ 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D
+ 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY'
+ 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b
+ 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88.
+ YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD
+
+ H e a d e r F i l e
+
+ ***************************************************************************
+ * *
+ * This program 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __DU_LINES_H__
+#define __DU_LINES_H__
+
+#include <tqlistview.h>
+#include <tqpixmap.h>
+#include "diskusage.h"
+
+class DULinesToolTip;
+
+class DULines : public TQListView
+{
+ TQ_OBJECT
+
+
+public:
+ DULines( DiskUsage *usage, const char *name );
+ ~DULines();
+
+ File * getCurrentFile();
+
+public slots:
+ void slotDirChanged( Directory *dirEntry );
+ void sectionResized( int );
+ void slotRightClicked(TQListViewItem *);
+ void slotChanged( File * );
+ void slotDeleted( File * );
+ void slotShowFileSizes();
+ void slotRefresh() { refreshNeeded = false; sectionResized( 0 ); }
+
+protected:
+ DiskUsage *diskUsage;
+
+ virtual void contentsMouseDoubleClickEvent ( TQMouseEvent * e );
+ virtual void keyPressEvent( TQKeyEvent *e );
+
+private:
+ TQPixmap createPixmap( int percent, int maxPercent, int maxWidth );
+
+ bool doubleClicked( TQListViewItem * item );
+
+ bool refreshNeeded;
+
+ bool showFileSize;
+
+ DULinesToolTip *toolTip;
+};
+
+#endif /* __DU_LINES_H__ */
+
diff --git a/src/app/DiskUsage/dulistview.cpp b/src/app/DiskUsage/dulistview.cpp
new file mode 100644
index 0000000..dc40690
--- /dev/null
+++ b/src/app/DiskUsage/dulistview.cpp
@@ -0,0 +1,293 @@
+/***************************************************************************
+ dulistview.cpp - description
+ -------------------
+ copyright : (C) 2004 by Csaba Karai
+ e-mail : krusader@users.sourceforge.net
+ web site : http://krusader.sourceforge.net
+ ---------------------------------------------------------------------------
+ Description
+ ***************************************************************************
+
+ A
+
+ db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b.
+ 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D
+ 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY'
+ 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b
+ 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88.
+ YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD
+
+ S o u r c e F i l e
+
+ ***************************************************************************
+ * *
+ * This program 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "dulistview.h"
+#include "../krusader.h"
+#include "../kicons.h"
+#include "../VFS/krpermhandler.h"
+#include <tqfontmetrics.h>
+#include <tdelocale.h>
+#include <kmimetype.h>
+#include <tdeglobal.h>
+#include <tqheader.h>
+#include <time.h>
+
+DUListView::DUListView( DiskUsage *usage, const char *name )
+ : TQListView( usage, name ), diskUsage( usage )
+{
+ setAllColumnsShowFocus(true);
+ setVScrollBarMode(TQScrollView::Auto);
+ setHScrollBarMode(TQScrollView::Auto);
+ setShowSortIndicator(true);
+ setRootIsDecorated( true );
+ setTreeStepSize( 10 );
+
+ int defaultSize = TQFontMetrics(font()).width("W");
+
+ krConfig->setGroup( diskUsage->getConfigGroup() );
+ int nameWidth = krConfig->readNumEntry("D Name Width", defaultSize * 20 );
+ addColumn( i18n("Name"), nameWidth );
+ setColumnWidthMode(0,TQListView::Manual);
+ int percentWidth = krConfig->readNumEntry("D Percent Width", defaultSize * 5 );
+ addColumn( i18n("Percent"), percentWidth );
+ setColumnWidthMode(1,TQListView::Manual);
+ int totalSizeWidth = krConfig->readNumEntry("D Total Size Width", defaultSize * 10 );
+ addColumn( i18n("Total size"), totalSizeWidth );
+ setColumnWidthMode(1,TQListView::Manual);
+ int ownSizeWidth = krConfig->readNumEntry("D Own Size Width", defaultSize * 10 );
+ addColumn( i18n("Own size"), ownSizeWidth );
+ setColumnWidthMode(2,TQListView::Manual);
+ int typeWidth = krConfig->readNumEntry("D Type Width", defaultSize * 10 );
+ addColumn( i18n("Type"), typeWidth );
+ setColumnWidthMode(3,TQListView::Manual);
+ int dateWidth = krConfig->readNumEntry("D Date Width", defaultSize * 10 );
+ addColumn( i18n("Date"), dateWidth );
+ setColumnWidthMode(4,TQListView::Manual);
+ int permissionsWidth = krConfig->readNumEntry("D Permissions Width", defaultSize * 6 );
+ addColumn( i18n("Permissions"), permissionsWidth );
+ setColumnWidthMode(5,TQListView::Manual);
+ int ownerWidth = krConfig->readNumEntry("D Owner Width", defaultSize * 5 );
+ addColumn( i18n("Owner"), ownerWidth );
+ setColumnWidthMode(6,TQListView::Manual);
+ int groupWidth = krConfig->readNumEntry("D Group Width", defaultSize * 5 );
+ addColumn( i18n("Group"), groupWidth );
+ setColumnWidthMode(7,TQListView::Manual);
+
+ setColumnAlignment( 1, TQt::AlignRight );
+ setColumnAlignment( 2, TQt::AlignRight );
+ setColumnAlignment( 3, TQt::AlignRight );
+
+ setSorting( 2 );
+
+ connect( diskUsage, TQ_SIGNAL( enteringDirectory( Directory * ) ), this, TQ_SLOT( slotDirChanged( Directory * ) ) );
+ connect( diskUsage, TQ_SIGNAL( clearing() ), this, TQ_SLOT( clear() ) );
+ connect( diskUsage, TQ_SIGNAL( changed( File * ) ), this, TQ_SLOT( slotChanged( File * ) ) );
+ connect( diskUsage, TQ_SIGNAL( deleted( File * ) ), this, TQ_SLOT( slotDeleted( File * ) ) );
+
+ connect( this, TQ_SIGNAL(rightButtonPressed(TQListViewItem *, const TQPoint &, int)),
+ this, TQ_SLOT( slotRightClicked(TQListViewItem *) ) );
+ connect( this, TQ_SIGNAL( expanded ( TQListViewItem * ) ),
+ this, TQ_SLOT( slotExpanded( TQListViewItem * ) ) );
+}
+
+DUListView::~ DUListView()
+{
+ krConfig->setGroup( diskUsage->getConfigGroup() );
+ krConfig->writeEntry("D Name Width", columnWidth( 0 ) );
+ krConfig->writeEntry("D Percent Width", columnWidth( 1 ) );
+ krConfig->writeEntry("D Total Size Width", columnWidth( 2 ) );
+ krConfig->writeEntry("D Own Size Width", columnWidth( 3 ) );
+ krConfig->writeEntry("D Type Width", columnWidth( 4 ) );
+ krConfig->writeEntry("D Date Width", columnWidth( 5 ) );
+ krConfig->writeEntry("D Permissions Width", columnWidth( 6 ) );
+ krConfig->writeEntry("D Owner Width", columnWidth( 7 ) );
+ krConfig->writeEntry("D Group Width", columnWidth( 8 ) );
+}
+
+void DUListView::addDirectory( Directory *dirEntry, TQListViewItem *parent )
+{
+ TQListViewItem * lastItem = 0;
+
+ if( parent == 0 && ! ( dirEntry->parent() == 0 ) )
+ {
+ lastItem = new TQListViewItem( this, ".." );
+ lastItem->setPixmap( 0, FL_LOADICON( "go-up" ) );
+ lastItem->setSelectable( false );
+ }
+
+ for( Iterator<File> it = dirEntry->iterator(); it != dirEntry->end(); ++it )
+ {
+ File *item = *it;
+
+ KMimeType::Ptr mimePtr = KMimeType::mimeType( item->mime() );
+ TQString mime = mimePtr->comment();
+
+ time_t tma = item->time();
+ struct tm* t=localtime((time_t *)&tma);
+ TQDateTime tmp(TQDate(t->tm_year+1900, t->tm_mon+1, t->tm_mday), TQTime(t->tm_hour, t->tm_min));
+ TQString date = TDEGlobal::locale()->formatDateTime(tmp);
+
+ TQString totalSize = KRpermHandler::parseSize( item->size() ) + " ";
+ TQString ownSize = KRpermHandler::parseSize( item->ownSize() ) + " ";
+ TQString percent = item->percent();
+
+ if( lastItem == 0 && parent == 0 )
+ lastItem = new DUListViewItem( diskUsage, item, this, item->name(), percent, totalSize, ownSize,
+ mime, date, item->perm(), item->owner(), item->group() );
+ else if ( lastItem == 0 )
+ lastItem = new DUListViewItem( diskUsage, item, parent, item->name(), percent, totalSize, ownSize,
+ mime, date, item->perm(), item->owner(), item->group() );
+ else if ( parent == 0 )
+ lastItem = new DUListViewItem( diskUsage, item, this, lastItem, item->name(), percent, totalSize,
+ ownSize, mime, date, item->perm(), item->owner(), item->group() );
+ else
+ lastItem = new DUListViewItem( diskUsage, item, parent, lastItem, item->name(), percent, totalSize,
+ ownSize, mime, date, item->perm(), item->owner(), item->group() );
+
+ if( item->isExcluded() )
+ lastItem->setVisible( false );
+
+ lastItem->setPixmap( 0, diskUsage->getIcon( item->mime() ) );
+
+ if( item->isDir() && !item->isSymLink() )
+ lastItem->setExpandable( true );
+ }
+
+ TQListViewItem *first = firstChild();
+ if( first )
+ setCurrentItem( first );
+}
+
+void DUListView::slotDirChanged( Directory *dirEntry )
+{
+ clear();
+ addDirectory( dirEntry, 0 );
+}
+
+File * DUListView::getCurrentFile()
+{
+ TQListViewItem *item = currentItem();
+
+ if( item == 0 || item->text( 0 ) == ".." )
+ return 0;
+
+ return ((DUListViewItem *)item)->getFile();
+}
+
+void DUListView::slotChanged( File * item )
+{
+ void * itemPtr = diskUsage->getProperty( item, "ListView-Ref" );
+ if( itemPtr == 0 )
+ return;
+
+ DUListViewItem *duItem = (DUListViewItem *)itemPtr;
+ duItem->setVisible( !item->isExcluded() );
+ duItem->setText( 1, item->percent() );
+ duItem->setText( 2, KRpermHandler::parseSize( item->size() ) + " " );
+ duItem->setText( 3, KRpermHandler::parseSize( item->ownSize() ) + " " );
+}
+
+void DUListView::slotDeleted( File * item )
+{
+ void * itemPtr = diskUsage->getProperty( item, "ListView-Ref" );
+ if( itemPtr == 0 )
+ return;
+
+ DUListViewItem *duItem = (DUListViewItem *)itemPtr;
+ delete duItem;
+}
+
+void DUListView::slotRightClicked( TQListViewItem *item )
+{
+ File * file = 0;
+
+ if ( item && item->text( 0 ) != ".." )
+ file = ((DUListViewItem *)item)->getFile();
+
+ diskUsage->rightClickMenu( file );
+}
+
+bool DUListView::doubleClicked( TQListViewItem * item )
+{
+ if( item )
+ {
+ if( item->text( 0 ) != ".." )
+ {
+ File *fileItem = ((DUListViewItem *)item)->getFile();
+ if( fileItem->isDir() )
+ diskUsage->changeDirectory( dynamic_cast<Directory *> ( fileItem ) );
+ return true;
+ }
+ else
+ {
+ Directory *upDir = (Directory *)diskUsage->getCurrentDir()->parent();
+
+ if( upDir )
+ diskUsage->changeDirectory( upDir );
+ return true;
+ }
+ }
+ return false;
+}
+
+void DUListView::contentsMouseDoubleClickEvent ( TQMouseEvent * e )
+{
+ if ( e || e->button() == TQt::LeftButton )
+ {
+ TQPoint vp = contentsToViewport(e->pos());
+ TQListViewItem * item = itemAt( vp );
+
+ if( doubleClicked( item ) )
+ return;
+
+ }
+ TQListView::contentsMouseDoubleClickEvent( e );
+}
+
+void DUListView::keyPressEvent( TQKeyEvent *e )
+{
+ switch ( e->key() )
+ {
+ case Key_Return :
+ case Key_Enter :
+ if( doubleClicked( currentItem() ) )
+ return;
+ break;
+ case Key_Left :
+ case Key_Right :
+ case Key_Up :
+ case Key_Down :
+ if( e->state() == ShiftButton )
+ {
+ e->ignore();
+ return;
+ }
+ break;
+ case Key_Delete :
+ e->ignore();
+ return;
+ }
+ TQListView::keyPressEvent( e );
+}
+
+void DUListView::slotExpanded( TQListViewItem *item )
+{
+ if( item == 0 || item->text( 0 ) == ".." )
+ return;
+
+ if( item->childCount() == 0 )
+ {
+ File *fileItem = ((DUListViewItem *)item)->getFile();
+ if( fileItem->isDir() )
+ addDirectory( dynamic_cast<Directory *>( fileItem ), item );
+ }
+}
+
+#include "dulistview.moc"
diff --git a/src/app/DiskUsage/dulistview.h b/src/app/DiskUsage/dulistview.h
new file mode 100644
index 0000000..9e9fdb4
--- /dev/null
+++ b/src/app/DiskUsage/dulistview.h
@@ -0,0 +1,145 @@
+/***************************************************************************
+ dulistview.h - description
+ -------------------
+ copyright : (C) 2004 by Csaba Karai
+ e-mail : krusader@users.sourceforge.net
+ web site : http://krusader.sourceforge.net
+ ---------------------------------------------------------------------------
+ Description
+ ***************************************************************************
+
+ A
+
+ db dD d8888b. db db .d8888. .d8b. d8888b. d88888b d8888b.
+ 88 ,8P' 88 `8D 88 88 88' YP d8' `8b 88 `8D 88' 88 `8D
+ 88,8P 88oobY' 88 88 `8bo. 88ooo88 88 88 88ooooo 88oobY'
+ 88`8b 88`8b 88 88 `Y8b. 88~~~88 88 88 88~~~~~ 88`8b
+ 88 `88. 88 `88. 88b d88 db 8D 88 88 88 .8D 88. 88 `88.
+ YP YD 88 YD ~Y8888P' `8888Y' YP YP Y8888D' Y88888P 88 YD
+
+ H e a d e r F i l e
+
+ ***************************************************************************
+ * *
+ * This program 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; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __DU_LISTVIEW_H__
+#define __DU_LISTVIEW_H__
+
+#include <tqlistview.h>
+#include "diskusage.h"
+
+class DUListViewItem : public TQListViewItem
+{
+public:
+ DUListViewItem( DiskUsage *diskUsageIn, File *fileIn, TQListView * parent, TQString label1,
+ TQString label2, TQString label3, TQString label4, TQString label5, TQString label6,
+ TQString label7, TQString label8, TQString label9 )
+ : TQListViewItem( parent, label1, label2, label3, label4, label5, label6, label7, label8),
+ diskUsage( diskUsageIn ), file( fileIn )
+ {
+ setText( 8, label9 );
+ diskUsage->addProperty( file, "ListView-Ref", this );
+ }
+ DUListViewItem( DiskUsage *diskUsageIn, File *fileIn, TQListViewItem * parent, TQString label1,
+ TQString label2, TQString label3, TQString label4, TQString label5, TQString label6,
+ TQString label7, TQString label8, TQString label9 )
+ : TQListViewItem( parent, label1, label2, label3, label4, label5, label6, label7, label8),
+ diskUsage( diskUsageIn ), file( fileIn )
+ {
+ setText( 8, label9 );
+ diskUsage->addProperty( file, "ListView-Ref", this );
+ }
+ DUListViewItem( DiskUsage *diskUsageIn, File *fileIn, TQListView * parent, TQListViewItem * after,
+ TQString label1, TQString label2, TQString label3, TQString label4, TQString label5,
+ TQString label6, TQString label7, TQString label8, TQString label9 )
+ : TQListViewItem( parent, after, label1, label2, label3, label4, label5, label6, label7, label8),
+ diskUsage( diskUsageIn ), file( fileIn )
+ {
+ setText( 8, label9 );
+ diskUsage->addProperty( file, "ListView-Ref", this );
+ }
+ DUListViewItem( DiskUsage *diskUsageIn, File *fileIn, TQListViewItem * parent, TQListViewItem * after,
+ TQString label1, TQString label2, TQString label3, TQString label4, TQString label5,
+ TQString label6, TQString label7, TQString label8, TQString label9 )
+ : TQListViewItem( parent, after, label1, label2, label3, label4, label5, label6, label7, label8),
+ diskUsage( diskUsageIn ), file( fileIn )
+ {
+ setText( 8, label9 );
+ diskUsage->addProperty( file, "ListView-Ref", this );
+ }
+ ~DUListViewItem()
+ {
+ diskUsage->removeProperty( file, "ListView-Ref" );
+ }
+
+ virtual int compare ( TQListViewItem * i, int col, bool ascending ) const
+ {
+ if( text(0) == ".." ) return ascending ? -1 : 1;
+ if( i->text(0) == "..") return ascending ? 1 : -1;
+
+ DUListViewItem *compWith = dynamic_cast< DUListViewItem * >( i );
+
+ TQString buf1,buf2;
+
+ switch( col )
+ {
+ case 1:
+ case 2:
+ buf1.sprintf("%025llu",file->size());
+ buf2.sprintf("%025llu",compWith->file->size());
+ return -TQString::compare( buf1, buf2 );
+ case 3:
+ buf1.sprintf("%025llu",file->ownSize());
+ buf2.sprintf("%025llu",compWith->file->ownSize());
+ return -TQString::compare( buf1, buf2 );
+ case 5:
+ return TQListViewItem::compare( i, col, !ascending );
+ default:
+ return TQListViewItem::compare( i, col, ascending );
+ }
+ }
+
+ inline File * getFile() { return file; }
+
+private:
+ DiskUsage *diskUsage;
+ File *file;
+};
+
+class DUListView : public TQListView
+{
+ TQ_OBJECT
+
+
+public:
+ DUListView( DiskUsage *usage, const char *name );
+ ~DUListView();
+
+ File * getCurrentFile();
+
+public slots:
+ void slotDirChanged( Directory * );
+ void slotChanged( File * );
+ void slotDeleted( File * );
+ void slotRightClicked(TQListViewItem *);
+ void slotExpanded( TQListViewItem * );
+
+protected:
+ DiskUsage *diskUsage;
+
+ virtual void contentsMouseDoubleClickEvent ( TQMouseEvent * e );
+ virtual void keyPressEvent( TQKeyEvent *e );
+
+private:
+ void addDirectory( Directory *dirEntry, TQListViewItem *parent );
+ bool doubleClicked( TQListViewItem * item );
+};
+
+#endif /* __DU_LISTVIEW_H__ */
+
diff --git a/src/app/DiskUsage/filelightParts/Config.cpp b/src/app/DiskUsage/filelightParts/Config.cpp
new file mode 100644
index 0000000..bf25a29
--- /dev/null
+++ b/src/app/DiskUsage/filelightParts/Config.cpp
@@ -0,0 +1,50 @@
+
+#include "Config.h"
+#include <tdeconfig.h>
+#include <tdeglobal.h>
+
+
+bool Config::varyLabelFontSizes = true;
+bool Config::showSmallFiles = false;
+uint Config::contrast = 50;
+uint Config::antiAliasFactor = 2;
+uint Config::minFontPitch = 10;
+uint Config::defaultRingDepth = 4;
+Filelight::MapScheme Config::scheme;
+
+
+inline TDEConfig&
+Filelight::Config::tdeconfig()
+{
+ TDEConfig *config = TDEGlobal::config();
+ config->setGroup( "DiskUsage" );
+ return *config;
+}
+
+void
+Filelight::Config::read()
+{
+ const TDEConfig &config = tdeconfig();
+
+ varyLabelFontSizes = config.readBoolEntry( "varyLabelFontSizes", true );
+ showSmallFiles = config.readBoolEntry( "showSmallFiles", false );
+ contrast = config.readNumEntry( "contrast", 50 );
+ antiAliasFactor = config.readNumEntry( "antiAliasFactor", 2 );
+ minFontPitch = config.readNumEntry( "minFontPitch", TQFont().pointSize() - 3);
+ scheme = (MapScheme) config.readNumEntry( "scheme", 0 );
+
+ defaultRingDepth = 4;
+}
+
+void
+Filelight::Config::write()
+{
+ TDEConfig &config = tdeconfig();
+
+ config.writeEntry( "varyLabelFontSizes", varyLabelFontSizes );
+ config.writeEntry( "showSmallFiles", showSmallFiles);
+ config.writeEntry( "contrast", contrast );
+ config.writeEntry( "antiAliasFactor", antiAliasFactor );
+ config.writeEntry( "minFontPitch", minFontPitch );
+ config.writeEntry( "scheme", scheme );
+}
diff --git a/src/app/DiskUsage/filelightParts/Config.h b/src/app/DiskUsage/filelightParts/Config.h
new file mode 100644
index 0000000..52a98b7
--- /dev/null
+++ b/src/app/DiskUsage/filelightParts/Config.h
@@ -0,0 +1,37 @@
+
+#ifndef Config_H
+#define Config_H
+
+#include <tqstringlist.h>
+
+class TDEConfig;
+
+
+namespace Filelight
+{
+ enum MapScheme { Rainbow, HighContrast, KDE, FileDensity, ModTime };
+
+ class Config
+ {
+ static TDEConfig& tdeconfig();
+
+ public:
+ static void read();
+ static void write();
+
+ //keep everything positive, avoid using DON'T, NOT or NO
+
+ static bool varyLabelFontSizes;
+ static bool showSmallFiles;
+ static uint contrast;
+ static uint antiAliasFactor;
+ static uint minFontPitch;
+ static uint defaultRingDepth;
+
+ static MapScheme scheme;
+ };
+}
+
+using Filelight::Config;
+
+#endif
diff --git a/src/app/DiskUsage/filelightParts/Makefile.am b/src/app/DiskUsage/filelightParts/Makefile.am
new file mode 100644
index 0000000..002f461
--- /dev/null
+++ b/src/app/DiskUsage/filelightParts/Makefile.am
@@ -0,0 +1,9 @@
+noinst_LIBRARIES = libfilelightparts.a
+
+INCLUDES = $(all_includes)
+
+METASOURCES = AUTO
+
+libfilelightparts_a_SOURCES = \
+ Config.cpp \
+ fileTree.cpp
diff --git a/src/app/DiskUsage/filelightParts/debug.h b/src/app/DiskUsage/filelightParts/debug.h
new file mode 100644
index 0000000..252a001
--- /dev/null
+++ b/src/app/DiskUsage/filelightParts/debug.h
@@ -0,0 +1,14 @@
+//Author: Max Howell <max.howell@methylblue.com>, (C) 2003-4
+//Copyright: See COPYING file that comes with this distribution
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <kdebug.h>
+
+#define debug kdDebug
+#define error kdError
+#define fatal kdFatal
+#define warning kdWarning
+
+#endif
diff --git a/src/app/DiskUsage/filelightParts/fileTree.cpp b/src/app/DiskUsage/filelightParts/fileTree.cpp
new file mode 100644
index 0000000..0afd4d4
--- /dev/null
+++ b/src/app/DiskUsage/filelightParts/fileTree.cpp
@@ -0,0 +1,78 @@
+//Author: Max Howell <max.howell@methylblue.com>, (C) 2004
+//Copyright: See COPYING file that comes with this distribution
+
+#include "fileTree.h"
+#include <tdeglobal.h>
+#include <tdelocale.h>
+#include <tqstring.h>
+
+//static definitions
+const FileSize File::DENOMINATOR[4] = { 1ull, 1ull<<10, 1ull<<20, 1ull<<30 };
+const char File::PREFIX[5][2] = { "", "K", "M", "G", "T" };
+
+TQString
+File::fullPath( const Directory *root /*= 0*/ ) const
+{
+ TQString path;
+
+ if( root == this ) root = 0; //prevent returning empty string when there is something we could return
+
+ const File *d;
+
+ for( d = this; d != root && d && d->parent() != 0; d = d->parent() )
+ {
+ if( !path.isEmpty() )
+ path = "/" + path;
+
+ path = d->name() + path;
+ }
+
+ if( d )
+ {
+ while( d->parent() )
+ d = d->parent();
+
+ if( d->directory().endsWith( "/" ) )
+ return d->directory() + path;
+ else
+ return d->directory() + "/" + path;
+ }
+ else
+ return path;
+}
+
+TQString
+File::humanReadableSize( UnitPrefix key /*= mega*/ ) const //FIXME inline
+{
+ return humanReadableSize( m_size, key );
+}
+
+TQString
+File::humanReadableSize( FileSize size, UnitPrefix key /*= mega*/ ) //static
+{
+ TQString s;
+ double prettySize = (double)size / (double)DENOMINATOR[key];
+ const TDELocale &locale = *TDEGlobal::locale();
+
+ if( prettySize >= 0.01 )
+ {
+ if( prettySize < 1 ) s = locale.formatNumber( prettySize, 2 );
+ else if( prettySize < 100 ) s = locale.formatNumber( prettySize, 1 );
+ else s = locale.formatNumber( prettySize, 0 );
+
+ s += ' ';
+ s += PREFIX[key];
+ s += 'B';
+ }
+
+ if( prettySize < 0.1 )
+ {
+ s += " (";
+ s += locale.formatNumber( size / DENOMINATOR[ key ? key - 1 : 0 ], 0 );
+ s += ' ';
+ s += PREFIX[key];
+ s += "B)";
+ }
+
+ return s;
+}
diff --git a/src/app/DiskUsage/filelightParts/fileTree.h b/src/app/DiskUsage/filelightParts/fileTree.h
new file mode 100644
index 0000000..2ba79ae
--- /dev/null
+++ b/src/app/DiskUsage/filelightParts/fileTree.h
@@ -0,0 +1,299 @@
+//Author: Max Howell <max.howell@methylblue.com>, (C) 2004
+//Copyright: See COPYING file that comes with this distribution
+
+#ifndef FILETREE_H
+#define FILETREE_H
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <tdeio/global.h>
+
+//TODO these are pointlessly general purpose now, make them incredibly specific
+
+
+
+typedef TDEIO::filesize_t FileSize;
+
+template <class T> class Iterator;
+template <class T> class ConstIterator;
+template <class T> class Chain;
+
+template <class T>
+class Link
+{
+public:
+ Link( T* const t ) : prev( this ), next( this ), data( t ) {}
+ Link() : prev( this ), next( this ), data( 0 ) {}
+
+ //TODO unlinking is slow and you don't use it very much in this context.
+ // ** Perhaps you can make a faster deletion system that doesn't bother tidying up first
+ // ** and then you MUST call some kind of detach() function when you remove elements otherwise
+ ~Link() { delete data; unlink(); }
+
+ friend class Iterator<T>;
+ friend class ConstIterator<T>;
+ friend class Chain<T>;
+
+private:
+ void unlink() { prev->next = next; next->prev = prev; prev = next = this; }
+
+ Link<T>* prev;
+ Link<T>* next;
+
+ T* data; //ensure only iterators have access to this
+};
+
+
+template <class T>
+class Iterator
+{
+public:
+ Iterator() : link( 0 ) { } //**** remove this, remove this REMOVE THIS!!! dangerous as your implementation doesn't test for null links, always assumes they can be derefenced
+ Iterator( Link<T> *p ) : link( p ) { }
+
+ bool operator==( const Iterator<T>& it ) const { return link == it.link; }
+ bool operator!=( const Iterator<T>& it ) const { return link != it.link; }
+ bool operator!=( const Link<T> *p ) const { return p != link; }
+
+ //here we have a choice, really I should make two classes one const the other not
+ const T* operator*() const { return link->data; }
+ T* operator*() { return link->data; }
+
+ Iterator<T>& operator++() { link = link->next; return *this; } //**** does it waste time returning in places where we don't use the retval?
+
+ bool isNull() const { return (link == 0); } //REMOVE WITH ABOVE REMOVAL you don't want null iterators to be possible
+
+ void transferTo( Chain<T> &chain )
+ {
+ chain.append( remove() );
+ }
+
+ T* const remove() //remove from list, delete Link, data is returned NOT deleted
+ {
+ T* const d = link->data;
+ Link<T>* const p = link->prev;
+
+ link->data = 0;
+ delete link;
+ link = p; //make iterator point to previous element, YOU must check this points to an element
+
+ return d;
+ }
+
+private:
+ Link<T> *link;
+};
+
+
+template <class T>
+class ConstIterator
+{
+public:
+ ConstIterator( Link<T> *p ) : link( p ) { }
+
+ bool operator==( const Iterator<T>& it ) const { return link == it.link; }
+ bool operator!=( const Iterator<T>& it ) const { return link != it.link; }
+ bool operator!=( const Link<T> *p ) const { return p != link; }
+
+ const T* operator*() const { return link->data; }
+
+ ConstIterator<T>& operator++() { link = link->next; return *this; }
+
+private:
+ const Link<T> *link;
+};
+
+//**** try to make a generic list class and then a brief full list template that inlines
+// thus reducing code bloat
+template <class T>
+class Chain
+{
+public:
+ Chain() { }
+ virtual ~Chain() { empty(); }
+
+ void append( T* const data )
+ {
+ Link<T>* const link = new Link<T>( data );
+
+ link->prev = head.prev;
+ link->next = &head;
+
+ head.prev->next = link;
+ head.prev = link;
+ }
+
+ void transferTo( Chain &c )
+ {
+ if( isEmpty() ) return;
+
+ Link<T>* const first = head.next;
+ Link<T>* const last = head.prev;
+
+ head.unlink();
+
+ first->prev = c.head.prev;
+ c.head.prev->next = first;
+
+ last->next = &c.head;
+ c.head.prev = last;
+ }
+
+ void empty() { while( head.next != &head ) { delete head.next; } }
+
+ Iterator<T> iterator() const { return Iterator<T>( head.next ); }
+ ConstIterator<T> constIterator() const { return ConstIterator<T>( head.next ); }
+ const Link<T> *end() const { return &head; }
+ bool isEmpty() const { return ( head.next == &head ); }
+
+private:
+ Link<T> head;
+ void operator=( const Chain& ) {}
+};
+
+
+class Directory;
+class TQString;
+class KURL;
+
+class File
+{
+protected:
+ Directory *m_parent; //0 if this is treeRoot
+ TQString m_name; //< file name
+ TQString m_directory;//< the directory of the file
+ FileSize m_size; //< size with subdirectories
+ FileSize m_ownSize; //< size without subdirectories
+ mode_t m_mode; //< file mode
+ TQString m_owner; //< file owner name
+ TQString m_group; //< file group name
+ TQString m_perm; //< file permissions string
+ time_t m_time; //< file modification in time_t format
+ bool m_symLink; //< true if the file is a symlink
+ TQString m_mimeType; //< file mimetype
+ bool m_excluded; //< flag if the file is excluded from du
+ int m_percent; //< percent flag
+
+public:
+ File( Directory *parentIn, const TQString &nameIn, const TQString &dir, FileSize sizeIn, mode_t modeIn,
+ const TQString &ownerIn, const TQString &groupIn, const TQString &permIn, time_t timeIn, bool symLinkIn,
+ const TQString &mimeTypeIn )
+ : m_parent( parentIn ), m_name( nameIn ), m_directory( dir ), m_size( sizeIn ), m_ownSize( sizeIn ), m_mode( modeIn ),
+ m_owner( ownerIn ), m_group( groupIn ), m_perm( permIn ), m_time( timeIn ), m_symLink( symLinkIn ),
+ m_mimeType( mimeTypeIn ), m_excluded( false ), m_percent( -1 ) {}
+
+ File( const TQString &nameIn, FileSize sizeIn )
+ : m_parent( 0 ), m_name( nameIn ), m_directory( TQString() ), m_size( sizeIn ), m_ownSize( sizeIn ), m_mode( 0 ),
+ m_owner( TQString() ), m_group( TQString() ), m_perm( TQString() ), m_time( -1 ),
+ m_symLink( false ), m_mimeType( TQString() ), m_excluded( false ), m_percent( -1 )
+ {
+ }
+
+ virtual ~File() {}
+
+ inline const TQString & name() const {return m_name;}
+ inline const TQString & directory() const {return m_directory;}
+ inline const FileSize size() const {return m_excluded ? 0 : m_size;}
+ inline const FileSize ownSize() const {return m_excluded ? 0 : m_ownSize;}
+ inline const mode_t mode() const {return m_mode;}
+ inline const TQString & owner() const {return m_owner;}
+ inline const TQString & group() const {return m_group;}
+ inline const TQString & perm() const {return m_perm;}
+ inline const time_t time() const {return m_time;}
+ inline const TQString & mime() const {return m_mimeType;}
+ inline const bool isSymLink() const {return m_symLink;}
+ virtual const bool isDir() const {return false;}
+ inline const bool isExcluded() const {return m_excluded;}
+ inline void exclude( bool flag ) {m_excluded = flag;}
+ inline const int intPercent() const {return m_percent;}
+ inline const TQString percent() const {if( m_percent < 0 )
+ return "INV";
+ TQString buf;
+ buf.sprintf( "%d.%02d%%", m_percent / 100, m_percent % 100 );
+ return buf;}
+ inline void setPercent( int p ) {m_percent = p;}
+ inline const Directory* parent() const {return m_parent;}
+
+ inline void setSizes( TDEIO::filesize_t totalSize, TDEIO::filesize_t ownSize )
+ {
+ m_ownSize = ownSize;
+ m_size = totalSize;
+ }
+
+ enum UnitPrefix { kilo, mega, giga, tera };
+
+ static const FileSize DENOMINATOR[4];
+ static const char PREFIX[5][2];
+
+ TQString fullPath( const Directory* = 0 ) const;
+ TQString humanReadableSize( UnitPrefix key = mega ) const;
+
+ static TQString humanReadableSize( FileSize size, UnitPrefix Key = mega );
+
+ friend class Directory;
+};
+
+
+//TODO when you modify this to take into account hardlinks you should make the Chain layered not inherited
+class Directory : public Chain<File>, public File
+{
+public:
+ Directory( Directory *parentIn, const TQString &nameIn, const TQString &dir, FileSize sizeIn, mode_t modeIn,
+ const TQString &ownerIn, const TQString &groupIn, const TQString &permIn, time_t timeIn, bool symLinkIn,
+ const TQString &mimeTypeIn )
+ : File( parentIn, nameIn, dir, sizeIn, modeIn, ownerIn, groupIn, permIn, timeIn, symLinkIn, mimeTypeIn ),
+ m_fileCount( 0 )
+ {}
+
+ Directory( const TQString &name, TQString url ) : File( name, 0 ), m_fileCount( 0 )
+ {
+ m_directory = url;
+ }
+
+ virtual ~Directory() {}
+ virtual const bool isDir() const {return true;}
+
+ void append( File *p )
+ {
+ ++m_fileCount;
+
+ Directory *parent = m_parent;
+ while( parent )
+ {
+ parent->m_fileCount++;
+ parent = parent->m_parent;
+ }
+
+ Chain<File>::append( p );
+ p->m_parent = this;
+ }
+
+ void remove( File *p )
+ {
+ for( Iterator<File> it = Chain<File>::iterator(); it != Chain<File>::end(); ++it )
+ if( (*it) == p )
+ {
+ --m_fileCount;
+
+ Directory *parent = m_parent;
+ while( parent )
+ {
+ parent->m_fileCount--;
+ parent = parent->m_parent;
+ }
+
+ it.remove();
+ break;
+ }
+ }
+
+ uint fileCount() const { return m_fileCount; }
+
+private:
+ Directory( const Directory& );
+ void operator=( const Directory& );
+
+ uint m_fileCount;
+};
+
+#endif
diff --git a/src/app/DiskUsage/radialMap/Makefile.am b/src/app/DiskUsage/radialMap/Makefile.am
new file mode 100644
index 0000000..ab5effd
--- /dev/null
+++ b/src/app/DiskUsage/radialMap/Makefile.am
@@ -0,0 +1,13 @@
+noinst_LIBRARIES = libradialmap.a
+
+INCLUDES = -I$(top_srcdir)/src/app/DiskUsage/filelightParts $(all_includes)
+
+METASOURCES = AUTO
+
+libradialmap_a_SOURCES = \
+ widget.cpp \
+ builder.cpp \
+ map.cpp \
+ widgetEvents.cpp \
+ labels.cpp \
+ segmentTip.cpp
diff --git a/src/app/DiskUsage/radialMap/builder.cpp b/src/app/DiskUsage/radialMap/builder.cpp
new file mode 100644
index 0000000..8edb70c
--- /dev/null
+++ b/src/app/DiskUsage/radialMap/builder.cpp
@@ -0,0 +1,139 @@
+//Author: Max Howell <max.howell@methylblue.com>, (C) 2003-4
+//Copyright: See COPYING file that comes with this distribution
+
+#include "builder.h"
+#include "Config.h"
+#include "fileTree.h"
+#include <tdeglobal.h> //locale object
+#include <tdelocale.h>
+#include "widget.h"
+
+
+//**** REMOVE NEED FOR the +1 with MAX_RING_DEPTH uses
+//**** add some angle bounds checking (possibly in Segment ctor? can I delete in a ctor?)
+//**** this class is a mess
+
+RadialMap::Builder::Builder( RadialMap::Map *m, const Directory* const d, bool fast )
+ : m_map( m )
+ , m_root( d )
+ , m_minSize( static_cast<FileSize>((d->size() * 3) / (PI * m->height() - m->MAP_2MARGIN )) )
+ , m_depth( &m->m_visibleDepth )
+{
+ m_signature = new Chain<Segment> [*m_depth + 1];
+
+ if( !fast )//|| *m_depth == 0 ) //depth 0 is special case usability-wise //**** WHY?!
+ {
+ //determine depth rather than use old one
+ findVisibleDepth( d ); //sets m_depth
+ }
+
+ m_map->setRingBreadth();
+ setLimits( m_map->m_ringBreadth );
+ build( d );
+
+ m_map->m_signature = m_signature;
+
+ delete []m_limits;
+}
+
+
+void
+RadialMap::Builder::findVisibleDepth( const Directory* const dir, const unsigned int depth )
+{
+ //**** because I don't use the same minimumSize criteria as in the visual function
+ // this can lead to incorrect visual representation
+ //**** BUT, you can't set those limits until you know m_depth!
+
+ //**** also this function doesn't check to see if anything is actually visible
+ // it just assumes that when it reaches a new level everything in it is visible
+ // automatically. This isn't right especially as there might be no files in the
+ // dir provided to this function!
+
+ static uint stopDepth = 0;
+
+ if( dir == m_root )
+ {
+ stopDepth = *m_depth;
+ *m_depth = 0;
+ }
+
+ if( *m_depth < depth ) *m_depth = depth;
+ if( *m_depth >= stopDepth ) return;
+
+ for( ConstIterator<File> it = dir->constIterator(); it != dir->end(); ++it )
+ if( (*it)->isDir() && (*it)->size() > m_minSize )
+ findVisibleDepth( (Directory *)*it, depth + 1 ); //if no files greater than min size the depth is still recorded
+}
+
+void
+RadialMap::Builder::setLimits( const uint &b ) //b = breadth?
+{
+ double size3 = m_root->size() * 3;
+ double pi2B = PI * 2 * b;
+
+ m_limits = new FileSize [*m_depth + 1]; //FIXME delete!
+
+ for( unsigned int d = 0; d <= *m_depth; ++d )
+ m_limits[d] = (FileSize)(size3 / (double)(pi2B * (d + 1))); //min is angle that gives 3px outer diameter for that depth
+}
+
+
+//**** segments currently overlap at edges (i.e. end of first is start of next)
+bool
+RadialMap::Builder::build( const Directory* const dir, const unsigned int depth, unsigned int a_start, const unsigned int a_end )
+{
+ //first iteration: dir == m_root
+
+ if( dir->fileCount() == 0 ) //we do fileCount rather than size to avoid chance of divide by zero later
+ return false;
+
+ FileSize hiddenSize = 0;
+ uint hiddenFileCount = 0;
+
+ for( ConstIterator<File> it = dir->constIterator(); it != dir->end(); ++it )
+ {
+ if( (*it)->size() > m_limits[depth] )
+ {
+ unsigned int a_len = (unsigned int)(5760 * ((double)(*it)->size() / (double)m_root->size()));
+
+ Segment *s = new Segment( *it, a_start, a_len );
+
+ (m_signature + depth)->append( s );
+
+ if( (*it)->isDir() )
+ {
+ if( depth != *m_depth )
+ {
+ //recurse
+ s->m_hasHiddenChildren = build( (Directory*)*it, depth + 1, a_start, a_start + a_len );
+ }
+ else s->m_hasHiddenChildren = true;
+ }
+
+ a_start += a_len; //**** should we add 1?
+
+ } else {
+
+ hiddenSize += (*it)->size();
+
+ if( (*it)->isDir() ) //**** considered virtual, but dir wouldn't count itself!
+ hiddenFileCount += static_cast<const Directory*>(*it)->fileCount(); //need to add one to count the dir as well
+
+ ++hiddenFileCount;
+ }
+ }
+
+ if( hiddenFileCount == dir->fileCount() && !Config::showSmallFiles )
+
+ return true;
+
+ else if( (Config::showSmallFiles && hiddenSize > m_limits[depth]) || (depth == 0 && (hiddenSize > dir->size()/8)) /*|| > size() * 0.75*/ )
+ {
+ //append a segment for unrepresented space - a "fake" segment
+
+ const TQString s = i18n( "%1 files: ~ %2" ).arg( TDEGlobal::locale()->formatNumber( hiddenFileCount, 0 ) ).arg( File::humanReadableSize( hiddenSize/hiddenFileCount ) );
+ (m_signature + depth)->append( new Segment( new File( s, hiddenSize ), a_start, a_end - a_start, true ) );
+ }
+
+ return false;
+}
diff --git a/src/app/DiskUsage/radialMap/builder.h b/src/app/DiskUsage/radialMap/builder.h
new file mode 100644
index 0000000..2fddbe0
--- /dev/null
+++ b/src/app/DiskUsage/radialMap/builder.h
@@ -0,0 +1,37 @@
+//Author: Max Howell <max.howell@methylblue.com>, (C) 2003-4
+//Copyright: See COPYING file that comes with this distribution
+
+#ifndef BUILDER_H
+#define BUILDER_H
+
+#include "radialMap.h" //Segment, defines
+#include "fileTree.h"
+
+template <class T> class Chain;
+
+namespace RadialMap
+{
+ class Map;
+
+ //temporary class that builds the Map signature
+
+ class Builder
+ {
+ public:
+ Builder( Map*, const Directory* const, bool fast=false );
+
+ private:
+ void findVisibleDepth( const Directory* const dir, const uint=0 );
+ void setLimits( const uint& );
+ bool build( const Directory* const, const uint=0, uint=0, const uint=5760 );
+
+ Map *m_map;
+ const Directory* const m_root;
+ const FileSize m_minSize;
+ uint *m_depth;
+ Chain<Segment> *m_signature;
+ FileSize *m_limits;
+ };
+}
+
+#endif
diff --git a/src/app/DiskUsage/radialMap/labels.cpp b/src/app/DiskUsage/radialMap/labels.cpp
new file mode 100644
index 0000000..5d61b7a
--- /dev/null
+++ b/src/app/DiskUsage/radialMap/labels.cpp
@@ -0,0 +1,342 @@
+//Author: Max Howell <max.howell@methylblue.com>, (C) 2003-4
+//Copyright: See COPYING file that comes with this distribution
+
+#include <kstringhandler.h>
+#include <tqfont.h>
+#include <tqfontmetrics.h>
+#include <tqpainter.h>
+#include <tqptrlist.h>
+
+#include "Config.h"
+#include "fileTree.h"
+#include "radialMap.h"
+#include "sincos.h"
+#include "widget.h"
+
+
+
+namespace RadialMap
+{
+ struct Label
+ {
+ Label( const RadialMap::Segment *s, int l ) : segment( s ), lvl( l ), a( segment->start() + (segment->length() / 2) ) { }
+
+ bool tooClose( const int &aa ) const { return ( a > aa - LABEL_ANGLE_MARGIN && a < aa + LABEL_ANGLE_MARGIN ); }
+
+ const RadialMap::Segment *segment;
+ const unsigned int lvl;
+ const int a;
+
+ int x1, y1, x2, y2, x3;
+ int tx, ty;
+
+ TQString qs;
+ };
+
+ class LabelList : public TQPtrList<Label>
+ {
+ protected:
+ int compareItems( TQPtrCollection::Item item1, TQPtrCollection::Item item2 )
+ {
+ //you add 1440 to work round the fact that later you want the circle split vertically
+ //and as it is you start at 3 o' clock. It's to do with rightPrevY, stops annoying bug
+
+ int a1 = ((Label*)item1)->a + 1440;
+ int a2 = ((Label*)item2)->a + 1440;
+
+ if( a1 == a2 )
+ return 0;
+
+ if( a1 > 5760 ) a1 -= 5760;
+ if( a2 > 5760 ) a2 -= 5760;
+
+ if( a1 > a2 )
+ return 1;
+
+ return -1;
+ }
+ };
+}
+
+
+void
+RadialMap::Widget::paintExplodedLabels( TQPainter &paint ) const
+{
+ //we are a friend of RadialMap::Map
+
+ LabelList list; list.setAutoDelete( true );
+ TQPtrListIterator<Label> it( list );
+ unsigned int startLevel = 0;
+
+
+ //1. Create list of labels sorted in the order they will be rendered
+
+ if( m_focus != NULL && m_focus->file() != m_tree ) //separate behavior for selected vs unselected segments
+ {
+ //don't bother with files
+ if( m_focus->file() == 0 || !m_focus->file()->isDir() ) return;
+
+ //find the range of levels we will be potentially drawing labels for
+ for( const Directory *p = (const Directory *)m_focus->file();
+ p != m_tree;
+ ++startLevel ) //startLevel is the level above whatever m_focus is in
+ {
+ p = p->parent();
+ }
+
+ //range=2 means 2 levels to draw labels for
+
+ unsigned int a1, a2, minAngle;
+
+ a1 = m_focus->start();
+ a2 = m_focus->end(); //boundry angles
+ minAngle = int(m_focus->length() * LABEL_MIN_ANGLE_FACTOR);
+
+
+ #define segment (*it)
+ #define ring (m_map.m_signature + i)
+
+ //**** Levels should be on a scale starting with 0
+ //**** range is a useless parameter
+ //**** keep a topblock var which is the lowestLevel OR startLevel for identation purposes
+ for( unsigned int i = startLevel; i <= m_map.m_visibleDepth; ++i )
+ {
+ for( Iterator<Segment> it = ring->iterator(); it != ring->end(); ++it )
+ if( segment->start() >= a1 && segment->end() <= a2 )
+ if( segment->length() > minAngle )
+ list.inSort( new Label( segment, i ) );
+ }
+
+ #undef ring
+ #undef segment
+
+ } else {
+
+ #define ring m_map.m_signature
+
+ for( Iterator<Segment> it = ring->iterator(); it != ring->end(); ++it )
+ if( (*it)->length() > 288 )
+ list.inSort( new Label( (*it), 0 ) );
+
+ #undef ring
+
+ }
+
+ //2. Check to see if any adjacent labels are too close together
+ // if so, remove the least significant labels
+
+ it.toFirst();
+ TQPtrListIterator<Label> jt( it );
+ ++jt;
+
+ while( jt ) //**** no need to check _it_ as jt will be NULL if _it_ was too
+ {
+ //this method is fairly efficient
+
+ if( (*it)->tooClose( (*jt)->a ) )
+ {
+ if( (*it)->lvl > (*jt)->lvl )
+ {
+ list.remove( *it );
+ it = jt;
+ }
+ else
+ list.remove( *jt );
+ }
+ else
+ ++it;
+
+ jt = it;
+ ++jt;
+ }
+
+ //used in next two steps
+ bool varySizes;
+ //**** should perhaps use doubles
+ int *sizes = new int [ m_map.m_visibleDepth + 1 ]; //**** make sizes an array of floats I think instead (or doubles)
+
+ do
+ {
+ //3. Calculate font sizes
+
+ {
+ //determine current range of levels to draw for
+ unsigned int range = 0;
+
+ for( it.toFirst(); it != 0; ++it )
+ {
+ unsigned int lvl = (*it)->lvl;
+ if( lvl > range )
+ range = lvl;
+
+ //**** better way would just be to assign if nothing is range
+ }
+
+ range -= startLevel; //range 0 means 1 level of labels
+
+ varySizes = Config::varyLabelFontSizes && (range != 0);
+
+ if( varySizes )
+ {
+ //create an array of font sizes for various levels
+ //will exceed normal font pitch automatically if necessary, but not minPitch
+ //**** this needs to be checked lots
+
+ //**** what if this is negative (min size gtr than default size)
+ unsigned int step = (paint.font().pointSize() - Config::minFontPitch) / range;
+ if( step == 0 ) step = 1;
+
+ for( unsigned int x = range + startLevel, y = Config::minFontPitch;
+ x >= startLevel;
+ y += step, --x )
+ {
+ sizes[x] = y;
+ }
+ }
+ }
+
+ //4. determine label co-ordinates
+
+ int x1, y1, x2, y2, x3, tx, ty; //coords
+ double sinra, cosra, ra; //angles
+
+ int cx = m_map.width() / 2 + m_offset.x(); //centre relative to canvas
+ int cy = m_map.height() / 2 + m_offset.y();
+
+ int spacer, preSpacer = int(m_map.m_ringBreadth * 0.5) + m_map.m_innerRadius;
+ int fullStrutLength = ( m_map.width() - m_map.MAP_2MARGIN ) / 2 + LABEL_MAP_SPACER; //full length of a strut from map center
+
+ int prevLeftY = 0;
+ int prevRightY = height();
+
+ bool rightSide;
+
+ TQFont font;
+
+ for( it.toFirst(); it != 0; ++it )
+ {
+ //** bear in mind that text is drawn with TQPoint param as BOTTOM left corner of text box
+ if( varySizes ) font.setPointSize( sizes[(*it)->lvl] );
+ TQFontMetrics fm( font );
+ int fmh = fm.height(); //used to ensure label texts don't overlap
+ int fmhD4 = fmh / 4;
+
+ fmh += LABEL_TEXT_VMARGIN;
+
+ rightSide = ( (*it)->a < 1440 || (*it)->a > 4320 );
+
+ ra = M_PI/2880 * (*it)->a; //convert to radians
+#if 0
+ sincos( ra, &sinra, &cosra );
+#endif
+ sinra = sin(ra); cosra = cos(ra);
+
+ spacer = preSpacer + m_map.m_ringBreadth * (*it)->lvl;
+
+ x1 = cx + (int)(cosra * spacer);
+ y1 = cy - (int)(sinra * spacer);
+ y2 = y1 - (int)(sinra * (fullStrutLength - spacer));
+
+ if( rightSide ) { //righthand side, going upwards
+
+ if( y2 > prevRightY /*- fmh*/ ) //then it is too low, needs to be drawn higher
+ y2 = prevRightY /*- fmh*/;
+
+ } else { //lefthand side, going downwards
+
+ if( y2 < prevLeftY/* + fmh*/ ) //then we're too high, need to be drawn lower
+ y2 = prevLeftY /*+ fmh*/;
+ }
+
+ x2 = x1 - int(double(y2 - y1) / tan( ra ));
+ ty = y2 + fmhD4;
+
+ TQString qs;
+ if( rightSide ) {
+
+ if( x2 > width() || ty < fmh || x2 < x1 )
+ {
+ //skip this strut
+ //**** don't duplicate this code
+ list.remove( *it ); //will delete the label and set it to list.current() which _should_ be the next ptr
+ break;
+ }
+
+ prevRightY = ty - fmh - fmhD4; //must be after above's "continue"
+
+ qs = KStringHandler::cPixelSqueeze( (*it)->segment->file()->name(), fm, width() - x2 );
+
+ x3 = width() - fm.width( qs )
+ - LABEL_HMARGIN //outer margin
+ - LABEL_TEXT_HMARGIN //margin between strut and text
+ //- ((*it)->lvl - startLevel) * LABEL_HMARGIN //indentation
+ ;
+ if( x3 < x2 ) x3 = x2;
+ tx = x3 + LABEL_TEXT_HMARGIN;
+
+ } else {
+
+ if( x2 < 0 || ty > height() || x2 > x1 )
+ {
+ //skip this strut
+ list.remove( *it ); //will delete the label and set it to list.current() which _should_ be the next ptr
+ break;
+ }
+
+ prevLeftY = ty + fmh - fmhD4;
+
+ qs = KStringHandler::cPixelSqueeze( (*it)->segment->file()->name(), fm, x2 );
+
+ //**** needs a little tweaking:
+
+ tx = fm.width( qs ) + LABEL_HMARGIN/* + ((*it)->lvl - startLevel) * LABEL_HMARGIN*/;
+ if( tx > x2 ) { //text is too long
+ tx = LABEL_HMARGIN + x2 - tx; //some text will be lost from sight
+ x3 = x2; //no text margin (right side of text here)
+ } else {
+ x3 = tx + LABEL_TEXT_HMARGIN;
+ tx = LABEL_HMARGIN /* + ((*it)->lvl - startLevel) * LABEL_HMARGIN*/;
+ }
+ }
+
+ (*it)->x1 = x1;
+ (*it)->y1 = y1;
+ (*it)->x2 = x2;
+ (*it)->y2 = y2;
+ (*it)->x3 = x3;
+ (*it)->tx = tx;
+ (*it)->ty = ty;
+ (*it)->qs = qs;
+ }
+
+ //if an element is deleted at this stage, we need to do this whole
+ //iteration again, thus the following loop
+ //**** in rare case that deleted label was last label in top level
+ // and last in labelList too, this will not work as expected (not critical)
+
+ } while( it != 0 );
+
+
+ //5. Render labels
+
+ paint.setPen( TQPen( TQt::black, 1 ) );
+
+ for( it.toFirst(); it != 0; ++it )
+ {
+ if( varySizes )
+ {
+ //**** how much overhead in making new TQFont each time?
+ // (implicate sharing remember)
+ TQFont font = paint.font();
+ font.setPointSize( sizes[(*it)->lvl] );
+ paint.setFont( font );
+ }
+
+ paint.drawEllipse( (*it)->x1 - 3, (*it)->y1 - 3, 7, 7 ); //**** CPU intensive! better to use a pixmap
+ paint.drawLine( (*it)->x1, (*it)->y1, (*it)->x2, (*it)->y2 );
+ paint.drawLine( (*it)->x2, (*it)->y2, (*it)->x3, (*it)->y2);
+ paint.drawText( (*it)->tx, (*it)->ty, (*it)->qs );
+ }
+
+ delete [] sizes;
+}
diff --git a/src/app/DiskUsage/radialMap/map.cpp b/src/app/DiskUsage/radialMap/map.cpp
new file mode 100644
index 0000000..329b8bc
--- /dev/null
+++ b/src/app/DiskUsage/radialMap/map.cpp
@@ -0,0 +1,432 @@
+//Author: Max Howell <max.howell@methylblue.com>, (C) 2003-4
+//Copyright: See COPYING file that comes with this distribution
+
+#include <kcursor.h> //make()
+#include <tdeglobalsettings.h> //kdeColours
+#include <kimageeffect.h> //desaturate()
+#include <tqapplication.h> //make()
+#include <tqimage.h> //make() & paint()
+#include <tqfont.h> //ctor
+#include <tqfontmetrics.h> //ctor
+#include <tqpainter.h>
+
+#include "builder.h"
+#include "Config.h"
+#include "fileTree.h"
+#include "sincos.h"
+#include "widget.h"
+
+#define COLOR_GREY TQColor( 0, 0, 140, TQColor::Hsv )
+
+
+RadialMap::Map::Map()
+ : m_signature( 0 )
+ , m_ringBreadth( MIN_RING_BREADTH )
+ , m_innerRadius( 0 )
+ , m_visibleDepth( DEFAULT_RING_DEPTH )
+{
+ //FIXME this is all broken. No longer is a maximum depth!
+ const int fmh = TQFontMetrics( TQFont() ).height();
+ const int fmhD4 = fmh / 4;
+ MAP_2MARGIN = 2 * ( fmh - (fmhD4 - LABEL_MAP_SPACER) ); //margin is dependent on fitting in labels at top and bottom
+}
+
+RadialMap::Map::~Map()
+{
+ delete [] m_signature;
+}
+
+void
+RadialMap::Map::invalidate( const bool desaturateTheImage )
+{
+ delete [] m_signature;
+ m_signature = 0;
+
+ if( desaturateTheImage )
+ {
+ TQImage img = this->convertToImage();
+
+ KImageEffect::desaturate( img, 0.7 );
+ KImageEffect::toGray( img, true );
+
+ this->convertFromImage( img );
+ }
+
+ m_visibleDepth = Config::defaultRingDepth;
+}
+
+void
+RadialMap::Map::make( const Directory *tree, bool refresh )
+{
+ //**** determineText seems pointless optimisation
+ // but is it good to keep the text consistent?
+ // even if it makes it a lie?
+
+ //slow operation so set the wait cursor
+ TQApplication::setOverrideCursor( KCursor::waitCursor() );
+
+ {
+ //build a signature of visible components
+ delete [] m_signature;
+ Builder builder( this, tree, refresh );
+ }
+
+ //colour the segments
+ colorise();
+
+ //determine centerText
+ if( !refresh )
+ {
+ int i;
+
+ for( i = 3; i > 0; --i )
+ if( tree->size() > File::DENOMINATOR[i] )
+ break;
+
+ m_centerText = tree->humanReadableSize( (File::UnitPrefix)i );
+ }
+
+ //paint the pixmap
+ aaPaint();
+
+ TQApplication::restoreOverrideCursor();
+}
+
+void
+RadialMap::Map::setRingBreadth()
+{
+ m_ringBreadth = (height() - MAP_2MARGIN) / (2 * m_visibleDepth + 4);
+
+ if( m_ringBreadth < MIN_RING_BREADTH ) m_ringBreadth = MIN_RING_BREADTH;
+ else if( m_ringBreadth > MAX_RING_BREADTH ) m_ringBreadth = MAX_RING_BREADTH;
+}
+
+bool
+RadialMap::Map::resize( const TQRect &rect )
+{
+ //there's a MAP_2MARGIN border
+
+ #define mw width()
+ #define mh height()
+ #define cw rect.width()
+ #define ch rect.height()
+
+ if( cw < mw || ch < mh || (cw > mw && ch > mh) )
+ {
+ uint size = (( cw < ch ) ? cw : ch) - MAP_2MARGIN;
+
+ //this also causes uneven sizes to always resize when resizing but map is small in that dimension
+ //size -= size % 2; //even sizes mean less staggered non-antialiased resizing
+
+ {
+ const uint minSize = MIN_RING_BREADTH * 2 * (m_visibleDepth + 2);
+ const uint mD2 = MAP_2MARGIN / 2;
+
+ if( size < minSize ) size = minSize;
+
+ //this TQRect is used by paint()
+ m_rect.setRect( mD2, mD2, size, size );
+ }
+
+ //resize the pixmap
+ size += MAP_2MARGIN;
+ KPixmap::resize( size, size );
+
+ if( m_signature != NULL )
+ {
+ setRingBreadth();
+ paint();
+ }
+ else fill(); //FIXME I don't like having to do this..
+
+ return true;
+ }
+
+ #undef mw
+ #undef mh
+ #undef cw
+ #undef ch
+
+ return false;
+}
+
+void
+RadialMap::Map::colorise()
+{
+ TQColor cp, cb;
+ double darkness = 1;
+ double contrast = (double)Config::contrast / (double)100;
+ int h, s1, s2, v1, v2;
+
+ TQColor kdeColour[2] = { TDEGlobalSettings::inactiveTitleColor(), TDEGlobalSettings::activeTitleColor() };
+
+ double deltaRed = (double)(kdeColour[0].red() - kdeColour[1].red()) / 2880; //2880 for semicircle
+ double deltaGreen = (double)(kdeColour[0].green() - kdeColour[1].green()) / 2880;
+ double deltaBlue = (double)(kdeColour[0].blue() - kdeColour[1].blue()) / 2880;
+
+ for( uint i = 0; i <= m_visibleDepth; ++i, darkness += 0.04 )
+ {
+ for( Iterator<Segment> it = m_signature[i].iterator(); it != m_signature[i].end(); ++it )
+ {
+ switch( Config::scheme )
+ {
+ case 2000: //HACK for summary view
+
+ if( (*it)->file()->name() == "Used" ) {
+ cb = TQApplication::palette().active().color( TQColorGroup::Highlight );
+ cb.hsv( &h, &s1, &v1 );
+
+ if( s1 > 80 )
+ s1 = 80;
+
+ v2 = v1 - int(contrast * v1);
+ s2 = s1 + int(contrast * (255 - s1));
+
+ cb.setHsv( h, s1, v1 );
+ cp.setHsv( h, s2, v2 );
+ }
+ else {
+ cp = TQt::gray;
+ cb = TQt::white;
+ }
+
+ (*it)->setPalette( cp, cb );
+
+ continue;
+ case Filelight::KDE:
+ {
+ //gradient will work by figuring out rgb delta values for 360 degrees
+ //then each component is angle*delta
+
+ int a = (*it)->start();
+
+ if( a > 2880 ) a = 2880 - (a - 2880);
+
+ h = (int)(deltaRed * a) + kdeColour[1].red();
+ s1 = (int)(deltaGreen * a) + kdeColour[1].green();
+ v1 = (int)(deltaBlue * a) + kdeColour[1].blue();
+
+ cb.setRgb( h, s1, v1 );
+ cb.hsv( &h, &s1, &v1 );
+
+ break;
+ }
+
+ case Filelight::HighContrast:
+
+ cp.setHsv( 0, 0, 0 ); //values of h, s and v are irrelevant
+ cb.setHsv( 180, 0, int(255.0 * contrast) );
+ (*it)->setPalette( cp, cb );
+ continue;
+
+ default:
+ h = int((*it)->start() / 16);
+ s1 = 160;
+ v1 = (int)(255.0 / darkness); //****doing this more often than once seems daft!
+ }
+
+ v2 = v1 - int(contrast * v1);
+ s2 = s1 + int(contrast * (255 - s1));
+
+ if( s1 < 80 ) s1 = 80; //can fall too low and makes contrast between the files hard to discern
+
+ if( (*it)->isFake() ) //multi-file
+ {
+ cb.setHsv( h, s2, (v2 < 90) ? 90 : v2 ); //too dark if < 100
+ cp.setHsv( h, 17, v1 );
+ }
+ else if( !(*it)->file()->isDir() ) //file
+ {
+ cb.setHsv( h, 17, v1 );
+ cp.setHsv( h, 17, v2 );
+ }
+ else //directory
+ {
+ cb.setHsv( h, s1, v1 ); //v was 225
+ cp.setHsv( h, s2, v2 ); //v was 225 - delta
+ }
+
+ (*it)->setPalette( cp, cb );
+
+ //**** may be better to store KDE colours as H and S and vary V as others
+ //**** perhaps make saturation difference for s2 dependent on contrast too
+ //**** fake segments don't work with highContrast
+ //**** may work better with cp = cb rather than TQt::white
+ //**** you have to ensure the grey of files is sufficient, currently it works only with rainbow (perhaps use contrast there too)
+ //**** change v1,v2 to vp, vb etc.
+ //**** using percentages is not strictly correct as the eye doesn't work like that
+ //**** darkness factor is not done for kde_colour scheme, and also value for files is incorrect really for files in this scheme as it is not set like rainbow one is
+ }
+ }
+}
+
+void
+RadialMap::Map::aaPaint()
+{
+ //paint() is called during continuous processes
+ //aaPaint() is not and is slower so set overidecursor (make sets it too)
+ TQApplication::setOverrideCursor( KCursor::waitCursor() );
+ paint( Config::antiAliasFactor );
+ TQApplication::restoreOverrideCursor();
+}
+
+void
+RadialMap::Map::paint( unsigned int scaleFactor )
+{
+ if( scaleFactor == 0 ) //just in case
+ scaleFactor = 1;
+
+ TQPainter paint;
+ TQRect rect = m_rect;
+ int step = m_ringBreadth;
+ int excess = -1;
+
+ //scale the pixmap, or do intelligent distribution of excess to prevent nasty resizing
+ if( scaleFactor > 1 )
+ {
+ int x1, y1, x2, y2;
+ rect.coords( &x1, &y1, &x2, &y2 );
+ x1 *= scaleFactor;
+ y1 *= scaleFactor;
+ x2 *= scaleFactor;
+ y2 *= scaleFactor;
+ rect.setCoords( x1, y1, x2, y2 );
+
+ step *= scaleFactor;
+ KPixmap::resize( this->size() * (int)scaleFactor );
+ }
+ else if( m_ringBreadth != MAX_RING_BREADTH && m_ringBreadth != MIN_RING_BREADTH ) {
+ excess = rect.width() % m_ringBreadth;
+ ++step;
+ }
+
+ //**** best option you can think of is to make the circles slightly less perfect,
+ // ** i.e. slightly eliptic when resizing inbetween
+
+
+ paint.begin( this );
+
+ fill(); //erase background
+
+ for( int x = m_visibleDepth; x >= 0; --x )
+ {
+ int width = rect.width() / 2;
+ //clever geometric trick to find largest angle that will give biggest arrow head
+ int a_max = int(acos( (double)width / double((width + 5) * scaleFactor) ) * (180*16 / M_PI));
+
+ for( ConstIterator<Segment> it = m_signature[x].constIterator(); it != m_signature[x].end(); ++it )
+ {
+ //draw the pie segments, most of this code is concerned with drawing the little
+ //arrows on the ends of segments when they have hidden files
+
+ paint.setPen( (*it)->pen() );
+
+ if( (*it)->hasHiddenChildren() )
+ {
+ //draw arrow head to indicate undisplayed files/directories
+ TQPointArray pts( 3 );
+ TQPoint pos, cpos = rect.center();
+ uint a[3] = { (*it)->start(), (*it)->length(), 0 };
+
+ a[2] = a[0] + (a[1] / 2); //assign to halfway between
+ if( a[1] > a_max )
+ {
+ a[1] = a_max;
+ a[0] = a[2] - a_max / 2;
+ }
+
+ a[1] += a[0];
+
+ for( int i = 0, radius = width; i < 3; ++i )
+ {
+ double ra = M_PI/(180*16) * a[i], sinra, cosra;
+
+ if( i == 2 )
+ radius += 5 * scaleFactor;
+#if 0
+ sincos( ra, &sinra, &cosra );
+#endif
+ sinra = sin(ra); cosra = cos(ra);
+ pos.rx() = cpos.x() + static_cast<int>(cosra * radius);
+ pos.ry() = cpos.y() - static_cast<int>(sinra * radius);
+ pts.setPoint( i, pos );
+ }
+
+ paint.setBrush( (*it)->pen() );
+ paint.drawPolygon( pts );
+ }
+
+ paint.setBrush( (*it)->brush() );
+ paint.drawPie( rect, (*it)->start(), (*it)->length() );
+
+ if( (*it)->hasHiddenChildren() )
+ {
+ //**** code is bloated!
+ paint.save();
+ TQPen pen = paint.pen();
+ int width = 2 * scaleFactor;
+ pen.setWidth( width );
+ paint.setPen( pen );
+ TQRect rect2 = rect;
+ width /= 2;
+ rect2.addCoords( width, width, -width, -width );
+ paint.drawArc( rect2, (*it)->start(), (*it)->length() );
+ paint.restore();
+ }
+ }
+
+ if( excess >= 0 ) { //excess allows us to resize more smoothly (still crud tho)
+ if( excess < 2 ) //only decrease rect by more if even number of excesses left
+ --step;
+ excess -= 2;
+ }
+
+ rect.addCoords( step, step, -step, -step );
+ }
+
+ // if( excess > 0 ) rect.addCoords( excess, excess, 0, 0 ); //ugly
+
+ paint.setPen( COLOR_GREY );
+ paint.setBrush( TQt::white );
+ paint.drawEllipse( rect );
+
+ if( scaleFactor > 1 )
+ {
+ //have to end in order to smoothscale()
+ paint.end();
+
+ int x1, y1, x2, y2;
+ rect.coords( &x1, &y1, &x2, &y2 );
+ x1 /= scaleFactor;
+ y1 /= scaleFactor;
+ x2 /= scaleFactor;
+ y2 /= scaleFactor;
+ rect.setCoords( x1, y1, x2, y2 );
+
+ TQImage img = this->convertToImage();
+ img = img.smoothScale( this->size() / (int)scaleFactor );
+ this->convertFromImage( img );
+
+ paint.begin( this );
+ paint.setPen( COLOR_GREY );
+ paint.setBrush( TQt::white );
+ }
+
+ paint.drawText( rect, TQt::AlignCenter, m_centerText );
+
+ m_innerRadius = rect.width() / 2; //rect.width should be multiple of 2
+
+ paint.end();
+}
+#if 0
+#if __GLIBC__ < 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
+
+ void
+ sincos( double angleRadians, double *Sin, double *Cos )
+ {
+ *Sin = sin( angleRadians );
+ *Cos = cos( angleRadians );
+ }
+
+#endif
+#endif
diff --git a/src/app/DiskUsage/radialMap/radialMap.h b/src/app/DiskUsage/radialMap/radialMap.h
new file mode 100644
index 0000000..c5edf65
--- /dev/null
+++ b/src/app/DiskUsage/radialMap/radialMap.h
@@ -0,0 +1,71 @@
+//Author: Max Howell <max.howell@methylblue.com>, (C) 2003-4
+//Copyright: See COPYING file that comes with this distribution
+
+#ifndef RADIALMAP_H
+#define RADIALMAP_H
+
+#include <tqcolor.h>
+
+class File;
+
+
+namespace RadialMap
+{
+ class Segment //all angles are in 16ths of degrees
+ {
+ public:
+ Segment( const File *f, uint s, uint l, bool isFake = false )
+ : m_angleStart( s )
+ , m_angleSegment( l )
+ , m_file( f )
+ , m_hasHiddenChildren( false )
+ , m_fake( isFake ) {}
+ ~Segment();
+
+ uint start() const { return m_angleStart; }
+ uint length() const { return m_angleSegment; }
+ uint end() const { return m_angleStart + m_angleSegment; }
+ const File *file() const { return m_file; }
+ const TQColor& pen() const { return m_pen; }
+ const TQColor& brush() const { return m_brush; }
+
+ bool isFake() const { return m_fake; }
+ bool hasHiddenChildren() const { return m_hasHiddenChildren; }
+
+ bool intersects( uint a ) const { return ( ( a >= start() ) && ( a < end() ) ); }
+
+ friend class Map;
+ friend class Builder;
+
+ private:
+ void setPalette( const TQColor &p, const TQColor &b ) { m_pen = p; m_brush = b; }
+
+ const uint m_angleStart, m_angleSegment;
+ const File* const m_file;
+ TQColor m_pen, m_brush;
+ bool m_hasHiddenChildren;
+ const bool m_fake;
+ };
+}
+
+
+#ifndef PI
+#define PI 3.141592653589793
+#endif
+#ifndef M_PI
+#define M_PI 3.14159265358979323846264338327
+#endif
+
+#define MIN_RING_BREADTH 20
+#define MAX_RING_BREADTH 60
+#define DEFAULT_RING_DEPTH 4 //first level = 0
+#define MIN_RING_DEPTH 0
+
+#define LABEL_MAP_SPACER 7
+#define LABEL_HMARGIN 10
+#define LABEL_TEXT_HMARGIN 5
+#define LABEL_TEXT_VMARGIN 0
+#define LABEL_ANGLE_MARGIN 32
+#define LABEL_MIN_ANGLE_FACTOR 0.05
+
+#endif
diff --git a/src/app/DiskUsage/radialMap/segmentTip.cpp b/src/app/DiskUsage/radialMap/segmentTip.cpp
new file mode 100644
index 0000000..2f2b31c
--- /dev/null
+++ b/src/app/DiskUsage/radialMap/segmentTip.cpp
@@ -0,0 +1,163 @@
+//Author: Max Howell <max.howell@methylblue.com>, (C) 2003-4
+//Copyright: See COPYING file that comes with this distribution
+
+#include "fileTree.h"
+#include "segmentTip.h"
+
+#include <tdeapplication.h> //installing eventFilters
+#include <tdeglobal.h>
+#include <tdeglobalsettings.h>
+#include <tdelocale.h>
+#include <kpixmapeffect.h>
+#include <tqpainter.h>
+#include <tqtooltip.h> //for its palette
+
+
+
+namespace RadialMap {
+
+SegmentTip::SegmentTip( uint h )
+ : TQWidget( 0, 0, WNoAutoErase | WStyle_Customize | WStyle_NoBorder | WStyle_Tool | WStyle_StaysOnTop | WX11BypassWM )
+ , m_cursorHeight( -h )
+{
+ setBackgroundMode( TQt::NoBackground );
+}
+
+void
+SegmentTip::moveto( TQPoint p, const TQWidget &canvas, bool placeAbove )
+{
+ //**** this function is very slow and seems to be visibly influenced by operations like mapFromGlobal() (who knows why!)
+ // ** so any improvements are much desired
+
+ //TODO uints could improve the class
+ p.rx() -= rect().center().x();
+ p.ry() -= (placeAbove ? 8 + height() : m_cursorHeight - 8);
+
+ const TQRect screen = TDEGlobalSettings::desktopGeometry( parentWidget() );
+
+ const int x = p.x();
+ const int y = p.y();
+ const int x2 = x + width();
+ const int y2 = y + height(); //how's it ever gunna get below screen height?! (well you never know I spose)
+ const int sw = screen.width();
+ const int sh = screen.height();
+
+ if( x < 0 ) p.setX( 0 );
+ if( y < 0 ) p.setY( 0 );
+ if( x2 > sw ) p.rx() -= x2 - sw;
+ if( y2 > sh ) p.ry() -= y2 - sh;
+
+
+ //I'm using this TQPoint to determine where to offset the bitBlt in m_pixmap
+ TQPoint offset = canvas.mapToGlobal( TQPoint() ) - p;
+ if( offset.x() < 0 ) offset.setX( 0 );
+ if( offset.y() < 0 ) offset.setY( 0 );
+
+
+ const TQRect alphaMaskRect( canvas.mapFromGlobal( p ), size() );
+ const TQRect intersection( alphaMaskRect.intersect( canvas.rect() ) );
+
+ m_pixmap.resize( size() ); //move to updateTip once you are sure it can never be null
+ bitBlt( &m_pixmap, offset, &canvas, intersection, TQt::CopyROP );
+
+ TQPainter paint( &m_pixmap );
+ paint.setPen( TQt::black );
+ paint.setBrush( TQt::NoBrush );
+ paint.drawRect( rect() );
+ paint.end();
+
+ m_pixmap = KPixmapEffect::fade( m_pixmap, 0.6, TQToolTip::palette().color( TQPalette::Active, TQColorGroup::Background ) );
+
+ paint.begin( &m_pixmap );
+ paint.drawText( rect(), AlignCenter, m_text );
+ paint.end();
+
+ p += screen.topLeft(); //for Xinerama users
+
+ move( x, y );
+ show();
+ update();
+}
+
+void
+SegmentTip::updateTip( const File* const file, const Directory* const root )
+{
+ const TQString s1 = file->fullPath( root );
+ TQString s2 = file->humanReadableSize();
+ TDELocale *loc = TDEGlobal::locale();
+ const uint MARGIN = 3;
+ const uint pc = 100 * file->size() / root->size();
+ uint maxw = 0;
+ uint h = fontMetrics().height()*2 + 2*MARGIN;
+
+ if( pc > 0 ) s2 += TQString( " (%1%)" ).arg( loc->formatNumber( pc, 0 ) );
+
+ m_text = s1;
+ m_text += '\n';
+ m_text += s2;
+
+ if( file->isDir() )
+ {
+ double files = static_cast<const Directory*>(file)->fileCount();
+ const uint pc = uint((100 * files) / (double)root->fileCount());
+ TQString s3 = i18n( "Files: %1" ).arg( loc->formatNumber( files, 0 ) );
+
+ if( pc > 0 ) s3 += TQString( " (%1%)" ).arg( loc->formatNumber( pc, 0 ) );
+
+ maxw = fontMetrics().width( s3 );
+ h += fontMetrics().height();
+ m_text += '\n';
+ m_text += s3;
+ }
+
+ uint
+ w = fontMetrics().width( s1 ); if( w > maxw ) maxw = w;
+ w = fontMetrics().width( s2 ); if( w > maxw ) maxw = w;
+
+ resize( maxw + 2 * MARGIN, h );
+}
+
+bool
+SegmentTip::event( TQEvent *e )
+{
+ switch( e->type() )
+ {
+ case TQEvent::Show:
+ kapp->installEventFilter( this );
+ break;
+ case TQEvent::Hide:
+ kapp->removeEventFilter( this );
+ break;
+ case TQEvent::Paint:
+ {
+ //TQPainter( this ).drawPixmap( 0, 0, m_pixmap );
+ bitBlt( this, 0, 0, &m_pixmap );
+ return true;
+ }
+ default:
+ ;
+ }
+
+ return false/*TQWidget::event( e )*/;
+}
+
+bool
+SegmentTip::eventFilter( TQObject*, TQEvent *e )
+{
+ switch ( e->type() )
+ {
+ case TQEvent::Leave:
+// case TQEvent::MouseButtonPress:
+// case TQEvent::MouseButtonRelease:
+ case TQEvent::KeyPress:
+ case TQEvent::KeyRelease:
+ case TQEvent::FocusIn:
+ case TQEvent::FocusOut:
+ case TQEvent::Wheel:
+ hide(); //FALL THROUGH
+ default:
+ return false; //allow this event to passed to target
+ }
+}
+
+} //namespace RadialMap
diff --git a/src/app/DiskUsage/radialMap/segmentTip.h b/src/app/DiskUsage/radialMap/segmentTip.h
new file mode 100644
index 0000000..7f279cb
--- /dev/null
+++ b/src/app/DiskUsage/radialMap/segmentTip.h
@@ -0,0 +1,33 @@
+// Author: Max Howell <max.howell@methylblue.com>, (C) 2004
+// Copyright: See COPYING file that comes with this distribution
+
+#ifndef SEGMENTTIP_H
+#define SEGMENTTIP_H
+
+#include <kpixmap.h>
+#include <tqwidget.h>
+
+class File;
+class Directory;
+
+namespace RadialMap
+{
+ class SegmentTip : public TQWidget
+ {
+ public:
+ SegmentTip( uint );
+
+ void updateTip( const File*, const Directory* );
+ void moveto( TQPoint, const TQWidget&, bool );
+
+ private:
+ virtual bool eventFilter( TQObject*, TQEvent* );
+ virtual bool event( TQEvent* );
+
+ uint m_cursorHeight;
+ KPixmap m_pixmap;
+ TQString m_text;
+ };
+}
+
+#endif
diff --git a/src/app/DiskUsage/radialMap/sincos.h b/src/app/DiskUsage/radialMap/sincos.h
new file mode 100644
index 0000000..5e66e54
--- /dev/null
+++ b/src/app/DiskUsage/radialMap/sincos.h
@@ -0,0 +1,17 @@
+//Author: Max Howell <max.howell@methylblue.com>, (C) 2003-4
+//Copyright: See COPYING file that comes with this distribution
+
+#ifndef SINCOS_H
+#define SINCOS_H
+
+#include <math.h>
+#if 0
+#if __GLIBC__ < 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
+
+ void
+ sincos( double angleRadians, double *Sin, double *Cos );
+
+#endif
+
+#endif
+#endif
diff --git a/src/app/DiskUsage/radialMap/widget.cpp b/src/app/DiskUsage/radialMap/widget.cpp
new file mode 100644
index 0000000..4ed038f
--- /dev/null
+++ b/src/app/DiskUsage/radialMap/widget.cpp
@@ -0,0 +1,199 @@
+//Author: Max Howell <max.howell@methylblue.com>, (C) 2003-4
+//Copyright: See COPYING file that comes with this distribution
+
+#include <kcursor.h> //ctor
+#include <tdelocale.h>
+#include <kurl.h>
+#include <tqapplication.h> //sendEvent
+#include <tqbitmap.h> //ctor - finding cursor size
+#include <tqcursor.h> //slotPostMouseEvent()
+#include <tqtimer.h> //member
+
+#include "Config.h"
+#include "debug.h"
+#include "fileTree.h"
+#include "radialMap.h" //constants
+#include "widget.h"
+
+
+
+RadialMap::Widget::Widget( TQWidget *parent, const char *name )
+ : TQWidget( parent, name, TQt::WNoAutoErase )
+ , m_tree( 0 )
+ , m_focus( 0 )
+ , m_tip( KCursor::handCursor().bitmap()->height() ) //needs to know cursor height
+ , m_rootSegment( 0 ) //TODO we don't delete it, *shrug*
+{
+ setBackgroundColor( TQt::white );
+
+ connect( this, TQ_SIGNAL(created( const Directory* )), TQ_SLOT(sendFakeMouseEvent()) );
+ connect( this, TQ_SIGNAL(created( const Directory* )), TQ_SLOT(update()) );
+ connect( &m_timer, TQ_SIGNAL(timeout()), TQ_SLOT(resizeTimeout()) );
+}
+
+TQString
+RadialMap::Widget::path() const
+{
+ if( m_tree == 0 )
+ return TQString();
+ return m_tree->fullPath();
+}
+
+KURL
+RadialMap::Widget::url( File const * const file ) const
+{
+ if( file == 0 && m_tree == 0 )
+ return KURL();
+
+ return KURL::fromPathOrURL( file ? file->fullPath() : m_tree->fullPath() );
+}
+
+void
+RadialMap::Widget::invalidate( const bool b )
+{
+ if( isValid() )
+ {
+ //**** have to check that only way to invalidate is this function frankly
+ //**** otherwise you may get bugs..
+
+ //disable mouse tracking
+ setMouseTracking( false );
+
+ KURL urlInv = url();
+
+ //ensure this class won't think we have a map still
+ m_tree = 0;
+ m_focus = 0;
+
+ delete m_rootSegment;
+ m_rootSegment = 0;
+
+ //FIXME move this disablement thing no?
+ // it is confusing in other areas, like the whole createFromCache() thing
+ m_map.invalidate( b ); //b signifies whether the pixmap is made to look disabled or not
+ if( b )
+ update();
+
+ //tell rest of Filelight
+ emit invalidated( urlInv );
+ }
+}
+
+void
+RadialMap::Widget::create( const Directory *tree )
+{
+ //it is not the responsibility of create() to invalidate first
+ //skip invalidation at your own risk
+
+ //FIXME make it the responsibility of create to invalidate first
+
+ if( tree )
+ {
+ m_focus = 0;
+ //generate the filemap image
+ m_map.make( tree );
+
+ //this is the inner circle in the center
+ m_rootSegment = new Segment( tree, 0, 16*360 );
+
+ setMouseTracking( true );
+ }
+
+ m_tree = tree;
+
+ //tell rest of Filelight
+ emit created( tree );
+}
+
+void
+RadialMap::Widget::createFromCache( const Directory *tree )
+{
+ //no scan was necessary, use cached tree, however we MUST still emit invalidate
+ invalidate( false );
+ create( tree );
+}
+
+void
+RadialMap::Widget::sendFakeMouseEvent() //slot
+{
+ TQMouseEvent me( TQEvent::MouseMove, mapFromGlobal( TQCursor::pos() ), TQt::NoButton, TQt::NoButton );
+ TQApplication::sendEvent( this, &me );
+}
+
+void
+RadialMap::Widget::resizeTimeout() //slot
+{
+ // the segments are about to erased!
+ // this was a horrid bug, and proves the OO programming should be obeyed always!
+ m_focus = 0;
+ if( m_tree )
+ m_map.make( m_tree, true );
+ update();
+}
+
+void
+RadialMap::Widget::refresh( int filth )
+{
+ //TODO consider a more direct connection
+
+ if( !m_map.isNull() )
+ {
+ switch( filth )
+ {
+ case 1:
+ m_focus = 0;
+ if( m_tree )
+ m_map.make( m_tree, true ); //true means refresh only
+ break;
+
+ case 2:
+ m_map.aaPaint();
+ break;
+
+ case 3:
+ m_map.colorise(); //FALL THROUGH!
+ case 4:
+ m_map.paint();
+
+ default:
+ break;
+ }
+
+ update();
+ }
+}
+
+void
+RadialMap::Widget::zoomIn() //slot
+{
+ if( m_map.m_visibleDepth > MIN_RING_DEPTH )
+ {
+ m_focus = 0;
+ --m_map.m_visibleDepth;
+ if( m_tree )
+ m_map.make( m_tree );
+ Config::defaultRingDepth = m_map.m_visibleDepth;
+ update();
+ }
+}
+
+void
+RadialMap::Widget::zoomOut() //slot
+{
+ m_focus = 0;
+ ++m_map.m_visibleDepth;
+ if( m_tree )
+ m_map.make( m_tree );
+ if( m_map.m_visibleDepth > Config::defaultRingDepth )
+ Config::defaultRingDepth = m_map.m_visibleDepth;
+ update();
+}
+
+
+RadialMap::Segment::~Segment()
+{
+ if( isFake() )
+ delete m_file; //created by us in Builder::build()
+}
+
+#include "widget.moc"
diff --git a/src/app/DiskUsage/radialMap/widget.h b/src/app/DiskUsage/radialMap/widget.h
new file mode 100644
index 0000000..83c6baa
--- /dev/null
+++ b/src/app/DiskUsage/radialMap/widget.h
@@ -0,0 +1,111 @@
+//Author: Max Howell <max.howell@methylblue.com>, (C) 2004
+//Copyright: See COPYING file that comes with this distribution
+
+#ifndef WIDGET_H
+#define WIDGET_H
+
+#include <kurl.h>
+#include <tqtimer.h>
+#include "segmentTip.h"
+
+template <class T> class Chain;
+class Directory;
+class File;
+namespace TDEIO { class Job; }
+class KURL;
+
+namespace RadialMap
+{
+ class Segment;
+
+ class Map : public KPixmap
+ {
+ public:
+ Map();
+ ~Map();
+
+ void make( const Directory *, bool = false );
+ bool resize( const TQRect& );
+
+ bool isNull() const { return ( m_signature == 0 ); }
+ void invalidate( const bool );
+
+ friend class Builder;
+ friend class Widget;
+
+ private:
+ void paint( uint = 1 );
+ void aaPaint();
+ void colorise();
+ void setRingBreadth();
+
+ Chain<Segment> *m_signature;
+
+ TQRect m_rect;
+ uint m_ringBreadth; ///ring breadth
+ uint m_innerRadius; ///radius of inner circle
+ uint m_visibleDepth; ///visible level depth of system
+ TQString m_centerText;
+
+ uint MAP_2MARGIN;
+ };
+
+ class Widget : public TQWidget
+ {
+ TQ_OBJECT
+
+
+ public:
+ Widget( TQWidget* = 0, const char* = 0 );
+
+ TQString path() const;
+ KURL url( File const * const = 0 ) const;
+
+ bool isValid() const { return m_tree != 0; }
+
+ friend class Label; //FIXME badness
+
+ public slots:
+ void zoomIn();
+ void zoomOut();
+ void create( const Directory* );
+ void invalidate( const bool = true );
+ void refresh( int );
+
+ private slots:
+ void resizeTimeout();
+ void sendFakeMouseEvent();
+ void deleteJobFinished( TDEIO::Job* );
+ void createFromCache( const Directory* );
+
+ signals:
+ void activated( const KURL& );
+ void invalidated( const KURL& );
+ void created( const Directory* );
+ void mouseHover( const TQString& );
+
+ protected:
+ virtual void paintEvent( TQPaintEvent* );
+ virtual void resizeEvent( TQResizeEvent* );
+ virtual void mouseMoveEvent( TQMouseEvent* );
+ virtual void mousePressEvent( TQMouseEvent* );
+
+ protected:
+ const Segment *segmentAt( TQPoint& ) const; //FIXME const reference for a library others can use
+ const Segment *rootSegment() const { return m_rootSegment; } ///never == 0
+ const Segment *focusSegment() const { return m_focus; } ///0 == nothing in focus
+
+ private:
+ void paintExplodedLabels( TQPainter& ) const;
+
+ const Directory *m_tree;
+ const Segment *m_focus;
+ TQPoint m_offset;
+ TQTimer m_timer;
+ Map m_map;
+ SegmentTip m_tip;
+ Segment *m_rootSegment;
+ };
+}
+
+#endif
diff --git a/src/app/DiskUsage/radialMap/widgetEvents.cpp b/src/app/DiskUsage/radialMap/widgetEvents.cpp
new file mode 100644
index 0000000..0cc11af
--- /dev/null
+++ b/src/app/DiskUsage/radialMap/widgetEvents.cpp
@@ -0,0 +1,241 @@
+//Author: Max Howell <max.howell@methylblue.com>, (C) 2003-4
+//Copyright: See COPYING file that comes with this distribution
+
+#include "fileTree.h"
+#include "radialMap.h" //class Segment
+#include "widget.h"
+
+#include <kcursor.h> //::mouseMoveEvent()
+#include <kiconeffect.h> //::mousePressEvent()
+#include <kiconloader.h> //::mousePressEvent()
+#include <tdeio/job.h> //::mousePressEvent()
+#include <tdelocale.h>
+#include <tdemessagebox.h> //::mousePressEvent()
+#include <tdepopupmenu.h> //::mousePressEvent()
+#include <krun.h> //::mousePressEvent()
+#include <math.h> //::segmentAt()
+#include <tqapplication.h>//TQApplication::setOverrideCursor()
+#include <tqpainter.h>
+#include <tqtimer.h> //::resizeEvent()
+
+
+
+void
+RadialMap::Widget::resizeEvent( TQResizeEvent* )
+{
+ if( m_map.resize( rect() ) )
+ m_timer.start( 500, true ); //will cause signature to rebuild for new size
+
+ //always do these as they need to be initialised on creation
+ m_offset.rx() = (width() - m_map.width()) / 2;
+ m_offset.ry() = (height() - m_map.height()) / 2;
+}
+
+void
+RadialMap::Widget::paintEvent( TQPaintEvent* )
+{
+ //bltBit for some TQt setups will bitBlt _after_ the labels are painted. Which buggers things up!
+ //shame as bitBlt is faster, possibly TQt bug? Should report the bug? - seems to be race condition
+ //bitBlt( this, m_offset, &m_map );
+
+ TQPainter paint( this );
+
+ paint.drawPixmap( m_offset, m_map );
+
+ //vertical strips
+ if( m_map.width() < width() )
+ {
+ paint.eraseRect( 0, 0, m_offset.x(), height() );
+ paint.eraseRect( m_map.width() + m_offset.x(), 0, m_offset.x() + 1, height() );
+ }
+ //horizontal strips
+ if( m_map.height() < height() )
+ {
+ paint.eraseRect( 0, 0, width(), m_offset.y() );
+ paint.eraseRect( 0, m_map.height() + m_offset.y(), width(), m_offset.y() + 1 );
+ }
+
+ //exploded labels
+ if( !m_map.isNull() && !m_timer.isActive() )
+ paintExplodedLabels( paint );
+}
+
+const RadialMap::Segment*
+RadialMap::Widget::segmentAt( TQPoint &e ) const
+{
+ //determine which segment TQPoint e is above
+
+ e -= m_offset;
+
+ if( e.x() <= m_map.width() && e.y() <= m_map.height() )
+ {
+ //transform to cartesian coords
+ e.rx() -= m_map.width() / 2; //should be an int
+ e.ry() = m_map.height() / 2 - e.y();
+
+ double length = hypot( e.x(), e.y() );
+
+ if( length >= m_map.m_innerRadius ) //not hovering over inner circle
+ {
+ uint depth = ((int)length - m_map.m_innerRadius) / m_map.m_ringBreadth;
+
+ if( depth <= m_map.m_visibleDepth ) //**** do earlier since you can //** check not outside of range
+ {
+ //vector calculation, reduces to simple trigonometry
+ //cos angle = (aibi + ajbj) / albl
+ //ai = x, bi=1, aj=y, bj=0
+ //cos angle = x / (length)
+
+ uint a = (uint)(acos( (double)e.x() / length ) * 916.736); //916.7324722 = #radians in circle * 16
+
+ //acos only understands 0-180 degrees
+ if( e.y() < 0 ) a = 5760 - a;
+
+ #define ring (m_map.m_signature + depth)
+ for( ConstIterator<Segment> it = ring->constIterator(); it != ring->end(); ++it )
+ if( (*it)->intersects( a ) )
+ return *it;
+ #undef ring
+ }
+ }
+ else return m_rootSegment; //hovering over inner circle
+ }
+
+ return 0;
+}
+
+void
+RadialMap::Widget::mouseMoveEvent( TQMouseEvent *e )
+{
+ //set m_focus to what we hover over, update UI if it's a new segment
+
+ Segment const * const oldFocus = m_focus;
+ TQPoint p = e->pos();
+
+ m_focus = segmentAt( p ); //NOTE p is passed by non-const reference
+
+ if( m_focus && m_focus->file() != m_tree )
+ {
+ if( m_focus != oldFocus ) //if not same as last time
+ {
+ setCursor( KCursor::handCursor() );
+ m_tip.updateTip( m_focus->file(), m_tree );
+ emit mouseHover( m_focus->file()->fullPath() );
+
+ //repaint required to update labels now before transparency is generated
+ repaint( false );
+ }
+
+ m_tip.moveto( e->globalPos(), *this, ( p.y() < 0 ) ); //updates tooltip psuedo-tranparent background
+ }
+ else if( oldFocus && oldFocus->file() != m_tree )
+ {
+ unsetCursor();
+ m_tip.hide();
+ update();
+
+ emit mouseHover( TQString() );
+ }
+}
+
+void
+RadialMap::Widget::mousePressEvent( TQMouseEvent *e )
+{
+ //m_tip is hidden already by event filter
+ //m_focus is set correctly (I've been strict, I assure you it is correct!)
+
+ if( m_focus && !m_focus->isFake() )
+ {
+ const KURL url = Widget::url( m_focus->file() );
+ const bool isDir = m_focus->file()->isDir();
+
+ if( e->button() == TQt::RightButton )
+ {
+ TDEPopupMenu popup;
+ popup.insertTitle( m_focus->file()->fullPath( m_tree ) );
+
+ if( isDir )
+ {
+ popup.insertItem( SmallIconSet( "konqueror" ), i18n( "Open &Konqueror Here" ), 0 );
+ if( url.protocol() == "file" )
+ popup.insertItem( SmallIconSet( "konsole" ), i18n( "Open &Konsole Here" ), 1 );
+
+ if( m_focus->file() != m_tree )
+ {
+ popup.insertSeparator();
+ popup.insertItem( SmallIconSet( "viewmag" ), i18n( "&Center Map Here" ), 2 );
+ }
+ }
+ else popup.insertItem( SmallIconSet( "document-open" ), i18n( "&Open" ), 3 );
+
+ popup.insertSeparator();
+ popup.insertItem( SmallIconSet( "edit-delete" ), i18n( "&Delete" ), 4 );
+
+ switch( popup.exec( e->globalPos(), 1 ) ) {
+ case 0:
+ //KRun::runCommand will show an error message if there was trouble
+ KRun::runCommand( TQString( "kfmclient openURL '%1'" ).arg( url.url() ) );
+ break;
+
+ case 1:
+ KRun::runCommand( TQString( "konsole --workdir '%1'" ).arg( url.url() ) );
+ break;
+
+ case 2:
+ case 3:
+ goto sectionTwo;
+
+ case 4:
+ {
+ const KURL url = Widget::url( m_focus->file() );
+ const TQString message = ( m_focus->file()->isDir()
+ ? i18n( "<qt>The directory at <i>'%1'</i> will be <b>recursively</b> and <b>permanently</b> deleted!</qt>" )
+ : i18n( "<qt><i>'%1'</i> will be <b>permanently</b> deleted!</qt>" )).arg( url.prettyURL() );
+ const int userIntention = KMessageBox::warningContinueCancel( this, message, TQString(), KGuiItem( i18n("&Delete"), "edit-delete" ) );
+
+ if( userIntention == KMessageBox::Continue ) {
+ TDEIO::Job *job = TDEIO::del( url );
+ job->setWindow( this );
+ connect( job, TQ_SIGNAL(result( TDEIO::Job* )), TQ_SLOT(deleteJobFinished( TDEIO::Job* )) );
+ TQApplication::setOverrideCursor( KCursor::workingCursor() );
+ }
+ }
+
+ default:
+ //ensure m_focus is set for new mouse position
+ sendFakeMouseEvent();
+ }
+
+ } else {
+
+ sectionTwo:
+
+ const TQRect rect( e->x() - 20, e->y() - 20, 40, 40 );
+
+ m_tip.hide(); //user expects this
+
+ if( !isDir || e->button() == TQt::MidButton )
+ {
+ TDEIconEffect::visualActivate( this, rect );
+ new KRun( url, this, true ); //FIXME see above
+ }
+ else if( m_focus->file() != m_tree ) //is left mouse button
+ {
+ TDEIconEffect::visualActivate( this, rect );
+ emit activated( url ); //activate first, this will cause UI to prepare itself
+ if( m_focus )
+ createFromCache( (Directory *)m_focus->file() );
+ }
+ }
+ }
+}
+
+void
+RadialMap::Widget::deleteJobFinished( TDEIO::Job *job )
+{
+ TQApplication::restoreOverrideCursor();
+ if( !job->error() )
+ invalidate();
+ else
+ job->showErrorDialog( this );
+}