From 83b9bf0e3bfb1d842b10b80bbe749095b2c661a1 Mon Sep 17 00:00:00 2001 From: tpearson Date: Mon, 22 Feb 2010 18:58:28 +0000 Subject: Added old KDE3 version of Krusader git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/krusader@1094427 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- krusader/Panel/Makefile.am | 29 + krusader/Panel/krbriefview.cpp | 1461 ++++++++++++++++++++++++++++++ krusader/Panel/krbriefview.h | 172 ++++ krusader/Panel/krbriefviewitem.cpp | 225 +++++ krusader/Panel/krbriefviewitem.h | 79 ++ krusader/Panel/krcalcspacedialog.cpp | 187 ++++ krusader/Panel/krcalcspacedialog.h | 106 +++ krusader/Panel/krcolorcache.cpp | 761 ++++++++++++++++ krusader/Panel/krcolorcache.h | 101 +++ krusader/Panel/krdetailedview.cpp | 1587 +++++++++++++++++++++++++++++++++ krusader/Panel/krdetailedview.h | 180 ++++ krusader/Panel/krdetailedviewitem.cpp | 313 +++++++ krusader/Panel/krdetailedviewitem.h | 73 ++ krusader/Panel/krdrag.cpp | 103 +++ krusader/Panel/krdrag.h | 62 ++ krusader/Panel/krpopupmenu.cpp | 354 ++++++++ krusader/Panel/krpopupmenu.h | 77 ++ krusader/Panel/krpreviewpopup.cpp | 68 ++ krusader/Panel/krpreviewpopup.h | 48 + krusader/Panel/krselectionmode.cpp | 61 ++ krusader/Panel/krselectionmode.h | 97 ++ krusader/Panel/krview.cpp | 332 +++++++ krusader/Panel/krview.h | 245 +++++ krusader/Panel/krviewitem.cpp | 105 +++ krusader/Panel/krviewitem.h | 76 ++ krusader/Panel/listpanel.cpp | 1115 +++++++++++++++++++++++ krusader/Panel/listpanel.h | 211 +++++ krusader/Panel/panelfunc.cpp | 1186 ++++++++++++++++++++++++ krusader/Panel/panelfunc.h | 105 +++ krusader/Panel/panelpopup.cpp | 400 +++++++++ krusader/Panel/panelpopup.h | 73 ++ 31 files changed, 9992 insertions(+) create mode 100644 krusader/Panel/Makefile.am create mode 100644 krusader/Panel/krbriefview.cpp create mode 100644 krusader/Panel/krbriefview.h create mode 100644 krusader/Panel/krbriefviewitem.cpp create mode 100644 krusader/Panel/krbriefviewitem.h create mode 100644 krusader/Panel/krcalcspacedialog.cpp create mode 100644 krusader/Panel/krcalcspacedialog.h create mode 100644 krusader/Panel/krcolorcache.cpp create mode 100644 krusader/Panel/krcolorcache.h create mode 100644 krusader/Panel/krdetailedview.cpp create mode 100644 krusader/Panel/krdetailedview.h create mode 100644 krusader/Panel/krdetailedviewitem.cpp create mode 100644 krusader/Panel/krdetailedviewitem.h create mode 100644 krusader/Panel/krdrag.cpp create mode 100644 krusader/Panel/krdrag.h create mode 100644 krusader/Panel/krpopupmenu.cpp create mode 100644 krusader/Panel/krpopupmenu.h create mode 100644 krusader/Panel/krpreviewpopup.cpp create mode 100644 krusader/Panel/krpreviewpopup.h create mode 100644 krusader/Panel/krselectionmode.cpp create mode 100644 krusader/Panel/krselectionmode.h create mode 100644 krusader/Panel/krview.cpp create mode 100644 krusader/Panel/krview.h create mode 100644 krusader/Panel/krviewitem.cpp create mode 100644 krusader/Panel/krviewitem.h create mode 100644 krusader/Panel/listpanel.cpp create mode 100644 krusader/Panel/listpanel.h create mode 100755 krusader/Panel/panelfunc.cpp create mode 100644 krusader/Panel/panelfunc.h create mode 100644 krusader/Panel/panelpopup.cpp create mode 100644 krusader/Panel/panelpopup.h (limited to 'krusader/Panel') diff --git a/krusader/Panel/Makefile.am b/krusader/Panel/Makefile.am new file mode 100644 index 0000000..3317a9b --- /dev/null +++ b/krusader/Panel/Makefile.am @@ -0,0 +1,29 @@ +if include_libkonq +AM_CPPFLAGS = -D__LIBKONQ__ +endif + + +noinst_LIBRARIES = libPanel.a + +INCLUDES = $(all_includes) + +libPanel_a_METASOURCES = AUTO + +libPanel_a_SOURCES = \ + krcolorcache.cpp \ + krcalcspacedialog.cpp \ + krpopupmenu.cpp \ + krpreviewpopup.cpp \ + krview.cpp \ + krviewitem.cpp \ + krdetailedviewitem.cpp \ + krdetailedview.cpp \ + panelfunc.cpp \ + listpanel.cpp \ + panelpopup.cpp \ + krdrag.cpp \ + krselectionmode.cpp \ + krbriefview.cpp \ + krbriefviewitem.cpp + + diff --git a/krusader/Panel/krbriefview.cpp b/krusader/Panel/krbriefview.cpp new file mode 100644 index 0000000..1fe8a36 --- /dev/null +++ b/krusader/Panel/krbriefview.cpp @@ -0,0 +1,1461 @@ +/*************************************************************************** + krbriefview.cpp + ------------------- +copyright : (C) 2000-2007 by Shie Erlich & Rafi Yanai & 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 "krbriefview.h" +#include "krbriefviewitem.h" +#include "krcolorcache.h" +#include "krselectionmode.h" +#include "../krusader.h" +#include "../kicons.h" +#include "../defaults.h" +#include "../krslots.h" +#include "../VFS/krarchandler.h" +#include "../VFS/krquery.h" +#include "../Dialogs/krspecialwidgets.h" +#include +#include + +#define CANCEL_TWO_CLICK_RENAME {singleClicked = false;renameTimer.stop();} +#define PROPS static_cast(_properties) +#define MAX_COLS 5 +#define VF getVfile() + + +class KrBriefViewToolTip : public QToolTip +{ +public: + KrBriefViewToolTip( KrBriefView *view, QWidget *parent ); + void maybeTip( const QPoint &pos ); + + virtual ~KrBriefViewToolTip() {} +private: + KrBriefView *view; +}; + +KrBriefViewToolTip::KrBriefViewToolTip( KrBriefView *lv, QWidget *parent ) + : QToolTip( parent ), view( lv ) +{ +} + +void KrBriefViewToolTip::maybeTip( const QPoint &pos ) +{ + QIconViewItem *item = view->findItem( view->viewportToContents( pos ) ); + + if ( !item ) + return; + + int width = QFontMetrics( view->font() ).width( item->text() ) + 4; + + QRect r = item->rect(); + r.setTopLeft( view->contentsToViewport( r.topLeft() ) ); + if( width > item->textRect().width() ) + tip( r, item->text() ); +} + + +KrBriefView::KrBriefView( QHeader * headerIn, QWidget *parent, bool &left, KConfig *cfg, const char *name ): + KIconView(parent, name), KrView( cfg ), header( headerIn ), _currDragItem( 0 ), + currentlyRenamedItem( 0 ), pressedItem( 0 ), mouseEvent( 0 ) { + setWidget( this ); + _nameInKConfig = QString( "KrBriefView" ) + QString( ( left ? "Left" : "Right" ) ); + krConfig->setGroup("Private"); + if (krConfig->readBoolEntry("Enable Input Method", true)) + setInputMethodEnabled(true); + toolTip = new KrBriefViewToolTip( this, viewport() ); +} + +void KrBriefView::setup() { + lastSwushPosition = 0; + + // use the {} so that KConfigGroupSaver will work correctly! + KConfigGroupSaver grpSvr( _config, "Look&Feel" ); + setFont( _config->readFontEntry( "Filelist Font", _FilelistFont ) ); + // decide on single click/double click selection + if ( _config->readBoolEntry( "Single Click Selects", _SingleClickSelects ) && + KGlobalSettings::singleClick() ) { + connect( this, SIGNAL( executed( QIconViewItem* ) ), this, SLOT( slotExecuted( QIconViewItem* ) ) ); + } else { + connect( this, SIGNAL( clicked( QIconViewItem* ) ), this, SLOT( slotClicked( QIconViewItem* ) ) ); + connect( this, SIGNAL( doubleClicked( QIconViewItem* ) ), this, SLOT( slotDoubleClicked( QIconViewItem* ) ) ); + } + + // a change in the selection needs to update totals + connect( this, SIGNAL( onItem( QIconViewItem* ) ), this, SLOT( slotItemDescription( QIconViewItem* ) ) ); + connect( this, SIGNAL( contextMenuRequested( QIconViewItem*, const QPoint& ) ), + this, SLOT( handleContextMenu( QIconViewItem*, const QPoint& ) ) ); + connect( this, SIGNAL( rightButtonPressed(QIconViewItem*, const QPoint&)), + this, SLOT(slotRightButtonPressed(QIconViewItem*, const QPoint&))); + connect( this, SIGNAL( currentChanged( QIconViewItem* ) ), this, SLOT( setNameToMakeCurrent( QIconViewItem* ) ) ); + connect( this, SIGNAL( currentChanged( QIconViewItem* ) ), this, SLOT( transformCurrentChanged( QIconViewItem* ) ) ); + connect( this, SIGNAL( mouseButtonClicked ( int, QIconViewItem *, const QPoint & ) ), + this, SLOT( slotMouseClicked ( int, QIconViewItem *, const QPoint & ) ) ); + connect( &KrColorCache::getColorCache(), SIGNAL( colorsRefreshed() ), this, SLOT( refreshColors() ) ); + + // add whatever columns are needed to the listview + krConfig->setGroup( nameInKConfig() ); + + // determine basic settings for the view + setAcceptDrops( true ); + setItemsMovable( false ); + setItemTextPos( QIconView::Right ); + setArrangement( QIconView::TopToBottom ); + setWordWrapIconText( false ); + setSpacing( 0 ); + horizontalScrollBar()->installEventFilter( this ); + + // allow in-place renaming + + connect( this, SIGNAL( itemRenamed ( QIconViewItem * ) ), + this, SLOT( inplaceRenameFinished( QIconViewItem * ) ) ); + connect( &renameTimer, SIGNAL( timeout() ), this, SLOT( renameCurrentItem() ) ); + connect( &contextMenuTimer, SIGNAL (timeout()), this, SLOT (showContextMenu())); + + setSelectionMode( QIconView::Extended ); + + setFocusPolicy( StrongFocus ); + restoreSettings(); + refreshColors(); + + CANCEL_TWO_CLICK_RENAME; + + // setting the header + while( header->count() ) + header->removeLabel( 0 ); + + header->addLabel( i18n( "Name" ) ); + header->setStretchEnabled( true ); + + header->setSortIndicator( 0, sortDirection() ? Qt::Ascending : Qt::Descending ); + connect( header, SIGNAL(clicked( int )), this, SLOT( changeSortOrder())); + + header->installEventFilter( this ); + header->show(); +} + +KrBriefView::~KrBriefView() { + delete _properties; _properties = 0; + delete _operator; _operator = 0; + if( mouseEvent ) + delete mouseEvent; + mouseEvent = 0; + delete toolTip; +} + +void KrBriefView::resizeEvent ( QResizeEvent * resEvent ) +{ + QPoint pnt( contentsX(), contentsY() ); + QRect viewportRect( pnt, resEvent->oldSize() ); + bool visible = false; + if( currentItem() ) + visible = viewportRect.contains( currentItem()->rect() ); + + KIconView::resizeEvent( resEvent ); + redrawColumns(); + + if( visible && currentItem() ) + ensureItemVisible( currentItem() ); +} + +void KrBriefView::redrawColumns() +{ + bool ascending = sortDirection(); + setSorting( false, ascending ); + + setGridX( width() / PROPS->numberOfColumns ); + + // QT bug, it's important for recalculating the bounding rectangle + for( QIconViewItem * item = firstItem(); item; item = item->nextItem() ) + { + QString txt = item->text(); + item->setText( "" ); + item->setText( txt ); + } + + setSorting( true, ascending ); + + arrangeItemsInGrid(); +} + +// if vfile passes the filter, create an item, otherwise, drop it +KrViewItem *KrBriefView::preAddItem( vfile *vf ) { + bool isDir = vf->vfile_isDir(); + if ( !isDir || ( isDir && ( _properties->filter & KrViewProperties::ApplyToDirs ) ) ) { + switch ( _properties->filter ) { + case KrViewProperties::All : + break; + case KrViewProperties::Custom : + if ( !_properties->filterMask.match( vf ) ) return 0; + break; + case KrViewProperties::Dirs: + if ( !vf->vfile_isDir() ) return 0; + break; + case KrViewProperties::Files: + if ( vf->vfile_isDir() ) return 0; + break; + case KrViewProperties::ApplyToDirs : + break; // no-op, stop compiler complaints + } + } + // passed the filter ... + return new KrBriefViewItem( this, lastItem(), vf ); +} + +bool KrBriefView::preDelItem(KrViewItem *item) { + if( item ) { + KrBriefViewItem * viewItem = dynamic_cast( item ); + if( viewItem == currentlyRenamedItem ) { + currentlyRenamedItem->cancelRename(); + currentlyRenamedItem = 0; + } + } + + return true; +} + +void KrBriefView::addItems( vfs *v, bool addUpDir ) { + QIconViewItem * item = firstItem(); + QIconViewItem * currentItem = item; + + // add the up-dir arrow if needed + if ( addUpDir ) { + new KrBriefViewItem( this, ( QIconViewItem* ) 0L, ( vfile* ) 0L ); + } + + + // text for updating the status bar + QString statusText = QString("%1/ ").arg( v->vfs_getOrigin().fileName() ) + i18n("Directory"); + + bool as = sortDirection(); + setSorting( false, as ); // disable sorting + + for ( vfile * vf = v->vfs_getFirstFile(); vf != 0 ; vf = v->vfs_getNextFile() ) { + bool isDir = vf->vfile_isDir(); + if ( !isDir || ( isDir && ( _properties->filter & KrViewProperties::ApplyToDirs ) ) ) { + switch ( _properties->filter ) { + case KrViewProperties::All : + break; + case KrViewProperties::Custom : + if ( !_properties->filterMask.match( vf ) ) + continue; + break; + case KrViewProperties::Dirs: + if ( !vf->vfile_isDir() ) + continue; + break; + case KrViewProperties::Files: + if ( vf->vfile_isDir() ) + continue; + break; + + case KrViewProperties::ApplyToDirs : + break; // no-op, stop compiler complaints + } + } + + KrBriefViewItem *bvitem = new KrBriefViewItem( this, item, vf ); + _dict.insert( vf->vfile_getName(), bvitem ); + if ( isDir ) + ++_numDirs; + else + _countSize += bvitem->VF->vfile_getSize(); + ++_count; + // if the item should be current - make it so + if ( bvitem->name() == nameToMakeCurrent() ) + { + currentItem = static_cast(bvitem); + statusText = bvitem->description(); + } + } + + + // re-enable sorting + setSorting( true, as ); + sort( as ); + + if ( !currentItem ) + currentItem = firstItem(); + KIconView::setCurrentItem( currentItem ); + ensureItemVisible( currentItem ); + + op()->emitItemDescription( statusText ); +} + +void KrBriefView::delItem( const QString &name ) { + KrView::delItem( name ); + arrangeItemsInGrid(); +} + +QString KrBriefView::getCurrentItem() const { + QIconViewItem * it = currentItem(); + if ( !it ) + return QString::null; + else + return dynamic_cast( it ) ->name(); +} + +void KrBriefView::setCurrentItem( const QString& name ) { + KrBriefViewItem * it = dynamic_cast(_dict[ name ]); + if ( it ) + KIconView::setCurrentItem( it ); +} + +void KrBriefView::clear() { + if( currentlyRenamedItem ) { + currentlyRenamedItem->cancelRename(); + currentlyRenamedItem = 0; + } + + op()->emitSelectionChanged(); /* to avoid rename crash at refresh */ + KIconView::clear(); + KrView::clear(); +} + +void KrBriefView::slotClicked( QIconViewItem *item ) { + if ( !item ) return ; + + if ( !modifierPressed ) { + if ( singleClicked && !renameTimer.isActive() ) { + KConfig * config = KGlobal::config(); + config->setGroup( "KDE" ); + int doubleClickInterval = config->readNumEntry( "DoubleClickInterval", 400 ); + + int msecsFromLastClick = clickTime.msecsTo( QTime::currentTime() ); + + if ( msecsFromLastClick > doubleClickInterval && msecsFromLastClick < 5 * doubleClickInterval ) { + singleClicked = false; + renameTimer.start( doubleClickInterval, true ); + return ; + } + } + + CANCEL_TWO_CLICK_RENAME; + singleClicked = true; + clickTime = QTime::currentTime(); + clickedItem = item; + } +} + +void KrBriefView::slotDoubleClicked( QIconViewItem *item ) { + CANCEL_TWO_CLICK_RENAME; + if ( !item ) + return ; + QString tmp = dynamic_cast( item ) ->name(); + op()->emitExecuted(tmp); +} + +void KrBriefView::prepareForActive() { + KrView::prepareForActive(); + setFocus(); + slotItemDescription( currentItem() ); +} + +void KrBriefView::prepareForPassive() { + KrView::prepareForPassive(); + CANCEL_TWO_CLICK_RENAME; + KConfigGroupSaver grpSvr( _config, "Look&Feel" ); + if ( _config->readBoolEntry( "New Style Quicksearch", _NewStyleQuicksearch ) ) { + if ( MAIN_VIEW ) { + if ( ACTIVE_PANEL ) { + if ( ACTIVE_PANEL->quickSearch ) { + if ( ACTIVE_PANEL->quickSearch->isShown() ) { + stopQuickSearch( 0 ); + } + } + } + } + } +} + +void KrBriefView::slotItemDescription( QIconViewItem * item ) { + KrViewItem * it = static_cast( item ); + if ( !it ) + return ; + QString desc = it->description(); + op()->emitItemDescription(desc); +} + +void KrBriefView::handleQuickSearchEvent( QKeyEvent * e ) { + switch ( e->key() ) { + case Key_Insert: + { + QKeyEvent ev = QKeyEvent( QKeyEvent::KeyPress, Key_Space, 0, 0 ); + KIconView::keyPressEvent( & ev ); + ev = QKeyEvent( QKeyEvent::KeyPress, Key_Down, 0, 0 ); + keyPressEvent( & ev ); + break; + } + case Key_Home: + { + QIconView::setCurrentItem( firstItem() ); + QKeyEvent ev = QKeyEvent( QKeyEvent::KeyPress, Key_Down, 0, 0 ); + keyPressEvent( & ev ); + break; + } + case Key_End: + { + QIconView::setCurrentItem( firstItem() ); + QKeyEvent ev = QKeyEvent( QKeyEvent::KeyPress, Key_Up, 0, 0 ); + keyPressEvent( & ev ); + break; + } + } +} + + +void KrBriefView::slotCurrentChanged( QIconViewItem * item ) { + CANCEL_TWO_CLICK_RENAME; + if ( !item ) + return ; + _nameToMakeCurrent = static_cast( item ) ->name(); +} + +void KrBriefView::contentsMousePressEvent( QMouseEvent * e ) { + bool callDefaultHandler = true, processEvent = true, selectionChanged = false; + pressedItem = 0; + + e = transformMouseEvent( e ); + + QIconViewItem * oldCurrent = currentItem(); + QIconViewItem *newCurrent = findItem( e->pos() ); + if (e->button() == RightButton) + { + if (KrSelectionMode::getSelectionHandler()->rightButtonSelects() || + (((e->state() & ShiftButton) || (e->state() & ControlButton))) && KrSelectionMode::getSelectionHandler()->shiftCtrlRightButtonSelects()) + { + if (KrSelectionMode::getSelectionHandler()->rightButtonPreservesSelection() && !(e->state() & ShiftButton) + && !(e->state() & ControlButton) && !(e->state() & AltButton)) + { + if (newCurrent) + { + if (KrSelectionMode::getSelectionHandler()->showContextMenu() >= 0) + { + swushSelects = !newCurrent->isSelected(); + lastSwushPosition = newCurrent; + } + newCurrent->setSelected(!newCurrent->isSelected(), true); + newCurrent->repaint(); + selectionChanged = true; + } + callDefaultHandler = false; + processEvent = false; + e->accept(); + } + + if( !KrSelectionMode::getSelectionHandler()->rightButtonPreservesSelection() && KrSelectionMode::getSelectionHandler()->showContextMenu() >= 0) + { + if( (e->state() & ControlButton) && !(e->state() & AltButton) ) + { + if( newCurrent ) + { + newCurrent->setSelected(!newCurrent->isSelected()); + newCurrent->repaint(); + selectionChanged = true; + callDefaultHandler = false; + e->accept(); + } + } + else if( !(e->state() & ControlButton) && !(e->state() & AltButton) ) + { + clearSelection(); + if( newCurrent ) + { + newCurrent->setSelected( true ); + newCurrent->repaint(); + } + selectionChanged = true; + callDefaultHandler = false; + e->accept(); + } + } + } + else + { + callDefaultHandler = false; + processEvent = false; + e->accept(); + } + } + if (e->button() == LeftButton) + { + dragStartPos = e->pos(); + if (KrSelectionMode::getSelectionHandler()->leftButtonSelects() || + (((e->state() & ShiftButton) || (e->state() & ControlButton))) && + KrSelectionMode::getSelectionHandler()->shiftCtrlLeftButtonSelects()) + { + if (KrSelectionMode::getSelectionHandler()->leftButtonPreservesSelection() && !(e->state() & ShiftButton) + && !(e->state() & ControlButton) && !(e->state() & AltButton)) + { + if (newCurrent) + { + newCurrent->setSelected(!newCurrent->isSelected(), true); + newCurrent->repaint(); + selectionChanged = true; + } + callDefaultHandler = false; + processEvent = false; + e->accept(); + } + } + else + { + callDefaultHandler = false; + processEvent = false; + e->accept(); + } + } + + modifierPressed = false; + if ( (e->state() & ShiftButton) || (e->state() & ControlButton) || (e->state() & AltButton) ) { + CANCEL_TWO_CLICK_RENAME; + modifierPressed = true; + } + + // stop quick search in case a mouse click occured + KConfigGroupSaver grpSvr( _config, "Look&Feel" ); + if ( _config->readBoolEntry( "New Style Quicksearch", _NewStyleQuicksearch ) ) { + if ( MAIN_VIEW ) { + if ( ACTIVE_PANEL ) { + if ( ACTIVE_PANEL->quickSearch ) { + if ( ACTIVE_PANEL->quickSearch->isShown() ) { + stopQuickSearch( 0 ); + } + } + } + } + } + + if ( !_focused ) + op()->emitNeedFocus(); + setFocus(); + + if (processEvent && ( (e->state() & ShiftButton) || (e->state() & ControlButton) || (e->state() & AltButton) ) && !KrSelectionMode::getSelectionHandler()->useQTSelection()){ + if ( oldCurrent && newCurrent && oldCurrent != newCurrent && e->state() & ShiftButton ) { + int oldPos = oldCurrent->index(); + int newPos = newCurrent->index(); + QIconViewItem *top = 0, *bottom = 0; + if ( oldPos > newPos ) { + top = newCurrent; + bottom = oldCurrent; + } else { + top = oldCurrent; + bottom = newCurrent; + } + while( top ) + { + if ( !top->isSelected() ) { + top->setSelected( true, true ); + selectionChanged = true; + } + if ( top == bottom ) + break; + top = top->nextItem(); + } + QIconView::setCurrentItem( newCurrent ); + callDefaultHandler = false; + } + if( e->state() & ShiftButton ) + callDefaultHandler = false; + } + + if (selectionChanged) + updateView(); // don't call triggerUpdate directly! + + if (callDefaultHandler) + { + dragStartPos = QPoint( -1, -1 ); + + QString name = QString::null; // will the file be deleted by the mouse event? + if( newCurrent ) // save the name of the file + name = static_cast( newCurrent ) ->name(); + + KIconView::contentsMousePressEvent( e ); + + if( name.isEmpty() || _dict.find( name ) == 0 ) // is the file still valid? + newCurrent = 0; // if not, don't do any crash... + } else { + // emitting the missing signals from QIconView::contentsMousePressEvent(); + // the right click signal is not emitted as it is used for selection + + QPoint vp = contentsToViewport( e->pos() ); + + if( !newCurrent ) { + emit pressed( pressedItem = newCurrent ); + emit pressed( newCurrent, viewport()->mapToGlobal( vp ) ); + } + + emit mouseButtonPressed( e->button(), newCurrent, viewport()->mapToGlobal( vp ) ); + } + + // if (i != 0) // comment in, if click sould NOT select + // setSelected(i, FALSE); + if (newCurrent) QIconView::setCurrentItem(newCurrent); + + if ( ACTIVE_PANEL->quickSearch->isShown() ) { + ACTIVE_PANEL->quickSearch->hide(); + ACTIVE_PANEL->quickSearch->clear(); + krDirUp->setEnabled( true ); + } + if ( OTHER_PANEL->quickSearch->isShown() ) { + OTHER_PANEL->quickSearch->hide(); + OTHER_PANEL->quickSearch->clear(); + krDirUp->setEnabled( true ); + } +} + +void KrBriefView::contentsMouseReleaseEvent( QMouseEvent * e ) { + if (e->button() == RightButton) + contextMenuTimer.stop(); + + e = transformMouseEvent( e ); + + KIconView::contentsMouseReleaseEvent( e ); + + if( pressedItem ) { + QPoint vp = contentsToViewport( e->pos() ); + QIconViewItem *newCurrent = findItem( e->pos() ); + + if( pressedItem == newCurrent ) { + // emitting the missing signals from QIconView::contentsMouseReleaseEvent(); + // the right click signal is not emitted as it is used for selection + + if( !newCurrent ) { + emit clicked( newCurrent ); + emit clicked( newCurrent, viewport()->mapToGlobal( vp ) ); + } + + emit mouseButtonClicked( e->button(), newCurrent, viewport()->mapToGlobal( vp ) ); + } + + pressedItem = 0; + } +} + +void KrBriefView::contentsMouseMoveEvent ( QMouseEvent * e ) { + e = transformMouseEvent( e ); + + if ( ( singleClicked || renameTimer.isActive() ) && findItem( e->pos() ) != clickedItem ) + CANCEL_TWO_CLICK_RENAME; + + if ( dragStartPos != QPoint( -1, -1 ) && + e->state() & LeftButton && ( dragStartPos - e->pos() ).manhattanLength() > QApplication::startDragDistance() ) + startDrag(); + if (KrSelectionMode::getSelectionHandler()->rightButtonPreservesSelection() + && KrSelectionMode::getSelectionHandler()->rightButtonSelects() + && KrSelectionMode::getSelectionHandler()->showContextMenu() >= 0 && e->state() == Qt::RightButton) + { + QIconViewItem *newItem = findItem( e->pos() ); + e->accept(); + if (newItem != lastSwushPosition && newItem) + { + // is the new item above or below the previous one? + QIconViewItem * above = newItem; + QIconViewItem * below = newItem; + for (;(above || below) && above != lastSwushPosition && below != lastSwushPosition;) + { + if (above) + above = above->nextItem(); + if (below) + below = below->prevItem(); + } + if (above && (above == lastSwushPosition)) + { + for (; above != newItem; above = above->prevItem()) + above->setSelected(swushSelects,true); + newItem->setSelected(swushSelects,true); + lastSwushPosition = newItem; + updateView(); + } + else if (below && (below == lastSwushPosition)) + { + for (; below != newItem; below = below->nextItem()) + below->setSelected(swushSelects,true); + newItem->setSelected(swushSelects,true); + lastSwushPosition = newItem; + updateView(); + } + contextMenuTimer.stop(); + } + // emitting the missing signals from QIconView::contentsMouseMoveEvent(); + if( newItem ) + emit onItem( newItem ); + else + emit onViewport(); + } + else + KIconView::contentsMouseMoveEvent( e ); +} + +void KrBriefView::contentsMouseDoubleClickEvent ( QMouseEvent * e ) +{ + e = transformMouseEvent ( e ); + KIconView::contentsMouseDoubleClickEvent( e ); +} + +void KrBriefView::handleContextMenu( QIconViewItem * it, const QPoint & pos ) { + if ( !_focused ) + op()->emitNeedFocus(); + setFocus(); + + if ( !it ) + return ; + if ( static_cast( it ) -> + name() == ".." ) + return ; + int i = KrSelectionMode::getSelectionHandler()->showContextMenu(); + contextMenuPoint = QPoint( pos.x(), pos.y() ); + if (i < 0) + showContextMenu(); + else if (i > 0) + contextMenuTimer.start(i, true); +} + +void KrBriefView::showContextMenu() +{ + if (lastSwushPosition) + lastSwushPosition->setSelected(true); + op()->emitContextMenu( contextMenuPoint ); +} + +KrViewItem *KrBriefView::getKrViewItemAt( const QPoint & vp ) { + return dynamic_cast( KIconView::findItem( vp ) ); +} + +bool KrBriefView::acceptDrag( QDropEvent* ) const { + return true; +} + +void KrBriefView::contentsDropEvent( QDropEvent * e ) { + _currDragItem = 0; + op()->emitGotDrop(e); + e->ignore(); + KIconView::contentsDropEvent( e ); +} + +void KrBriefView::contentsDragMoveEvent( QDragMoveEvent * e ) { + KrViewItem *oldDragItem = _currDragItem; + + _currDragItem = getKrViewItemAt( e->pos() ); + if( _currDragItem && !_currDragItem->VF->vfile_isDir() ) + _currDragItem = 0; + + KIconView::contentsDragMoveEvent( e ); + + if( _currDragItem != oldDragItem ) + { + if( oldDragItem ) + dynamic_cast( oldDragItem )->repaint(); + if( _currDragItem ) + dynamic_cast( _currDragItem )->repaint(); + } +} + +void KrBriefView::contentsDragLeaveEvent ( QDragLeaveEvent *e ) +{ + KrViewItem *oldDragItem = _currDragItem; + + _currDragItem = 0; + KIconView::contentsDragLeaveEvent( e ); + + if( oldDragItem ) + dynamic_cast( oldDragItem )->repaint(); +} + +void KrBriefView::imStartEvent(QIMEvent* e) +{ + if ( ACTIVE_PANEL->quickSearch->isShown() ) { + ACTIVE_PANEL->quickSearch->myIMStartEvent( e ); + return ; + }else { + KConfigGroupSaver grpSvr( _config, "Look&Feel" ); + if ( !_config->readBoolEntry( "New Style Quicksearch", _NewStyleQuicksearch ) ) + KIconView::imStartEvent( e ); + else { + // first, show the quicksearch if its hidden + if ( ACTIVE_PANEL->quickSearch->isHidden() ) { + ACTIVE_PANEL->quickSearch->show(); + // hack: if the pressed key requires a scroll down, the selected + // item is "below" the quick search window, as the icon view will + // realize its new size after the key processing. The following line + // will resize the icon view immediately. + ACTIVE_PANEL->layout->activate(); + // second, we need to disable the dirup action - hack! + krDirUp->setEnabled( false ); + } + // now, send the key to the quicksearch + ACTIVE_PANEL->quickSearch->myIMStartEvent( e ); + } + } +} + +void KrBriefView::imEndEvent(QIMEvent* e) +{ + if ( ACTIVE_PANEL->quickSearch->isShown() ) { + ACTIVE_PANEL->quickSearch->myIMEndEvent( e ); + return ; + } +} + +void KrBriefView::imComposeEvent(QIMEvent* e) +{ + if ( ACTIVE_PANEL->quickSearch->isShown() ) { + ACTIVE_PANEL->quickSearch->myIMComposeEvent( e ); + return ; + } +} + +void KrBriefView::keyPressEvent( QKeyEvent * e ) { + if ( !e || !firstItem() ) + return ; // subclass bug + if ( ACTIVE_PANEL->quickSearch->isShown() ) { + ACTIVE_PANEL->quickSearch->myKeyPressEvent( e ); + return ; + } + switch ( e->key() ) { + case Key_Up : + if ( e->state() == ControlButton ) { // let the panel handle it - jump to the Location Bar + e->ignore(); + break; + } else if (!KrSelectionMode::getSelectionHandler()->useQTSelection()) { + QIconViewItem * i = currentItem(); + if ( !i ) break; + if ( e->state() == ShiftButton ) setSelected( i, !i->isSelected(), true ); + i = i->prevItem(); + if ( i ) { + QIconView::setCurrentItem( i ); + QIconView::ensureItemVisible( i ); + } + } else KIconView::keyPressEvent(e); + break; + case Key_Down : + if ( e->state() == ControlButton || e->state() == ( ControlButton | ShiftButton ) ) { // let the panel handle it - jump to command line + e->ignore(); + break; + } else if (!KrSelectionMode::getSelectionHandler()->useQTSelection()){ + QIconViewItem * i = currentItem(); + if ( !i ) break; + if ( e->state() == ShiftButton ) setSelected( i, !i->isSelected(), true ); + i = i->nextItem(); + if ( i ) {QIconView::setCurrentItem( i ); QIconView::ensureItemVisible( i ); } + } else KIconView::keyPressEvent(e); + break; + case Key_Next: if (!KrSelectionMode::getSelectionHandler()->useQTSelection()){ + QIconViewItem * i = currentItem(), *j; + if ( !i ) break; + QRect r( i->rect() ); + if ( !r.height() ) break; + for ( int page = visibleHeight() / r.height() - 1; page > 0 && ( j = i->nextItem() ); --page ) + i = j; + if ( i ) {QIconView::setCurrentItem( i ); QIconView::ensureItemVisible( i ); } + } else KIconView::keyPressEvent(e); + break; + case Key_Prior: if (!KrSelectionMode::getSelectionHandler()->useQTSelection()){ + QIconViewItem * i = currentItem(), *j; + if ( !i ) break; + QRect r( i->rect() ); + if ( !r.height() ) break; + for ( int page = visibleHeight() / r.height() - 1; page > 0 && ( j = i->prevItem() ); --page ) + i = j; + if ( i ) {QIconView::setCurrentItem( i ); QIconView::ensureItemVisible( i ); } + } else KIconView::keyPressEvent(e); + break; + case Key_Home: if (!KrSelectionMode::getSelectionHandler()->useQTSelection()){ + if ( e->state() & ShiftButton ) /* Shift+Home */ + { + clearSelection(); + KIconView::keyPressEvent( e ); + op()->emitSelectionChanged(); + arrangeItemsInGrid(); + break; + } else { + QIconViewItem * i = firstItem(); + if ( i ) {QIconView::setCurrentItem( i ); QIconView::ensureItemVisible( i ); } + } + } else KIconView::keyPressEvent(e); + break; + case Key_End: if (!KrSelectionMode::getSelectionHandler()->useQTSelection()){ + if ( e->state() & ShiftButton ) /* Shift+End */ + { + clearSelection(); + KIconView::keyPressEvent( e ); + op()->emitSelectionChanged(); + arrangeItemsInGrid(); + break; + } else { + QIconViewItem *i = firstItem(), *j; + while ( ( j = i->nextItem() ) ) + i = j; + while ( ( j = i->nextItem() ) ) + i = j; + if ( i ) {QIconView::setCurrentItem( i ); QIconView::ensureItemVisible( i ); } + break; + } + } else KIconView::keyPressEvent(e); + break; + case Key_Enter : + case Key_Return : { + if ( e->state() & ControlButton ) // let the panel handle it + e->ignore(); + else { + KrViewItem * i = getCurrentKrViewItem(); + QString tmp = i->name(); + op()->emitExecuted(tmp); + } + break; + } + case Key_QuoteLeft : // Terminal Emulator bugfix + if ( e->state() == ControlButton ) { // let the panel handle it + e->ignore(); + break; + } else { // a normal click - do a lynx-like moving thing + SLOTS->home(); // ask krusader to move up a directory + return ; // safety + } + break; + case Key_Right : + if ( e->state() == ControlButton ) { // let the panel handle it + e->ignore(); + break; + } else if (!KrSelectionMode::getSelectionHandler()->useQTSelection()) { + QIconViewItem *i = currentItem(); + QIconViewItem *newCurrent = 0; + + if ( !i ) break; + + int minY = i->y() - i->height() / 2; + int minX = i->width() / 2 + i->x(); + + if ( e->state() == ShiftButton ) setSelected( i, !i->isSelected(), true ); + + while( i && i->x() <= minX ) + { + if ( e->state() == ShiftButton ) setSelected( i, !i->isSelected(), true ); + newCurrent = i; + i = i->nextItem(); + } + + while( i && i->y() < minY ) + { + if ( e->state() == ShiftButton ) setSelected( i, !i->isSelected(), true ); + newCurrent = i; + i = i->nextItem(); + } + + if( i ) + { + if ( e->state() == ShiftButton ) setSelected( i, !i->isSelected(), true ); + newCurrent = i; + } + + if( newCurrent ) + { + QIconView::setCurrentItem( newCurrent ); + QIconView::ensureItemVisible( newCurrent ); + } + } else KIconView::keyPressEvent(e); + break; + case Key_Backspace : // Terminal Emulator bugfix + if ( e->state() == ControlButton || e->state() == ShiftButton ) { // let the panel handle it + e->ignore(); + break; + } else { // a normal click - do a lynx-like moving thing + SLOTS->dirUp(); // ask krusader to move up a directory + return ; // safety + } + case Key_Left : + if ( e->state() == ControlButton ) { // let the panel handle it + e->ignore(); + break; + } else if (!KrSelectionMode::getSelectionHandler()->useQTSelection()) { + QIconViewItem *i = currentItem(); + QIconViewItem *newCurrent = 0; + + if ( !i ) break; + + int maxY = i->y() + i->height() / 2; + int maxX = i->x() - i->width() / 2; + + if ( e->state() == ShiftButton ) setSelected( i, !i->isSelected(), true ); + + while( i && i->x() >= maxX ) + { + if ( e->state() == ShiftButton ) setSelected( i, !i->isSelected(), true ); + newCurrent = i; + i = i->prevItem(); + } + + while( i && i->y() > maxY ) + { + if ( e->state() == ShiftButton ) setSelected( i, !i->isSelected(), true ); + newCurrent = i; + i = i->prevItem(); + } + if( i ) + { + if ( e->state() == ShiftButton ) setSelected( i, !i->isSelected(), true ); + newCurrent = i; + } + + if( newCurrent ) + { + QIconView::setCurrentItem( newCurrent ); + QIconView::ensureItemVisible( newCurrent ); + } + } else KIconView::keyPressEvent(e); + break; + + case Key_Delete : // kill file + SLOTS->deleteFiles( e->state() == ShiftButton || e->state() == ControlButton ); + + break ; + case Key_Insert : { + { + QIconViewItem *i = currentItem(); + if( !i ) + break; + + if (KrSelectionMode::getSelectionHandler()->insertMovesDown()) + { + setSelected( i, !i->isSelected(), true ); + if( i->nextItem() ) + { + QIconView::setCurrentItem( i->nextItem() ); + QIconView::ensureItemVisible( i->nextItem() ); + } + } + else + { + setSelected( i, !i->isSelected(), true ); + } + } + break ; + } + case Key_Space : { + { + QIconViewItem *i = currentItem(); + if( !i ) + break; + + if (KrSelectionMode::getSelectionHandler()->spaceMovesDown()) + { + setSelected( i, !i->isSelected(), true ); + if( i->nextItem() ) + { + QIconView::setCurrentItem( i->nextItem() ); + QIconView::ensureItemVisible( i->nextItem() ); + } + } + else + { + setSelected( i, !i->isSelected(), true ); + } + } + break ; + } + case Key_A : // mark all + if ( e->state() == ControlButton ) { + KIconView::keyPressEvent( e ); + updateView(); + break; + } + default: + if ( e->key() == Key_Escape ) { + QIconView::keyPressEvent( e ); return ; // otherwise the selection gets lost??!?? + } + // if the key is A..Z or 1..0 do quick search otherwise... + if ( e->text().length() > 0 && e->text() [ 0 ].isPrint() ) // better choice. Otherwise non-ascii characters like can not be the first character of a filename + /* if ( ( e->key() >= Key_A && e->key() <= Key_Z ) || + ( e->key() >= Key_0 && e->key() <= Key_9 ) || + ( e->key() == Key_Backspace ) || + ( e->key() == Key_Down ) || + ( e->key() == Key_Period ) ) */{ + // are we doing quicksearch? if not, send keys to panel + //if ( _config->readBoolEntry( "Do Quicksearch", _DoQuicksearch ) ) { + // are we using krusader's classic quicksearch, or wincmd style? + { + KConfigGroupSaver grpSvr( _config, "Look&Feel" ); + if ( !_config->readBoolEntry( "New Style Quicksearch", _NewStyleQuicksearch ) ) + KIconView::keyPressEvent( e ); + else { + // first, show the quicksearch if its hidden + if ( ACTIVE_PANEL->quickSearch->isHidden() ) { + ACTIVE_PANEL->quickSearch->show(); + // hack: if the pressed key requires a scroll down, the selected + // item is "below" the quick search window, as the icon view will + // realize its new size after the key processing. The following line + // will resize the icon view immediately. + ACTIVE_PANEL->layout->activate(); + // second, we need to disable the dirup action - hack! + krDirUp->setEnabled( false ); + } + // now, send the key to the quicksearch + ACTIVE_PANEL->quickSearch->myKeyPressEvent( e ); + } + } + //} else + // e->ignore(); // send to panel + } else { + if ( ACTIVE_PANEL->quickSearch->isShown() ) { + ACTIVE_PANEL->quickSearch->hide(); + ACTIVE_PANEL->quickSearch->clear(); + krDirUp->setEnabled( true ); + } + KIconView::keyPressEvent( e ); + } + } + // emit the new item description + slotItemDescription( currentItem() ); // actually send the QIconViewItem +} +// overridden to make sure EXTENTION won't be lost during rename +void KrBriefView::rename( QIconViewItem * item ) { + currentlyRenamedItem = dynamic_cast< KrBriefViewItem * >( item ); + currentlyRenamedItem->rename(); + //TODO: renameLineEdit() ->selectAll(); +} + +void KrBriefView::renameCurrentItem() { + QString newName, fileName; + + // handle inplace renaming, if possible + + KrBriefViewItem *it = static_cast(getCurrentKrViewItem()); + if ( it ) + fileName = it->name(); + else + return ; // quit if no current item available + // don't allow anyone to rename .. + if ( fileName == ".." ) + return ; + + rename( static_cast( it ) ); + // if applicable, select only the name without extension +/* TODO: + KConfigGroupSaver svr(krConfig,"Look&Feel"); + if (!krConfig->readBoolEntry("Rename Selects Extension", true)) { + if (it->hasExtension() && !it->VF->vfile_isDir() ) + renameLineEdit()->setSelection(0, it->name().findRev(it->extension())-1); + }*/ +} + +void KrBriefView::inplaceRenameFinished( QIconViewItem * it ) { + if ( !it ) { // major failure - call developers + krOut << "Major failure at inplaceRenameFinished(): item is null" << endl; + return; + } + + KrBriefViewItem *item = dynamic_cast( it ); + if( item->text() != item->name() ) + op()->emitRenameItem( item->name(), item->text() ); + + currentlyRenamedItem = 0; + setFocus(); +} + +// TODO: move the whole quicksearch mess out of here and into krview +void KrBriefView::quickSearch( const QString & str, int direction ) { + KrViewItem * item = getCurrentKrViewItem(); + if (!item) + return; + KConfigGroupSaver grpSvr( _config, "Look&Feel" ); + bool caseSensitive = _config->readBoolEntry( "Case Sensitive Quicksearch", _CaseSensitiveQuicksearch ); + if ( !direction ) { + if ( caseSensitive ? item->name().startsWith( str ) : item->name().lower().startsWith( str.lower() ) ) + return ; + direction = 1; + } + KrViewItem * startItem = item; + while ( true ) { + item = ( direction > 0 ) ? getNext( item ) : getPrev( item ); + if ( !item ) + item = ( direction > 0 ) ? getFirst() : getLast(); + if ( item == startItem ) + return ; + if ( caseSensitive ? item->name().startsWith( str ) : item->name().lower().startsWith( str.lower() ) ) { + setCurrentItem( item->name() ); + makeItemVisible( item ); + return ; + } + } +} + +void KrBriefView::stopQuickSearch( QKeyEvent * e ) { + if( ACTIVE_PANEL && ACTIVE_PANEL->quickSearch ) { + ACTIVE_PANEL->quickSearch->hide(); + ACTIVE_PANEL->quickSearch->clear(); + krDirUp->setEnabled( true ); + if ( e ) + keyPressEvent( e ); + } +} + +void KrBriefView::setNameToMakeCurrent( QIconViewItem * it ) { + if (!it) return; + KrView::setNameToMakeCurrent( static_cast( it ) ->name() ); +} + +void KrBriefView::slotMouseClicked( int button, QIconViewItem * item, const QPoint& ) { + pressedItem = 0; // if the signals are emitted, don't emit twice at contentsMouseReleaseEvent + if ( button == Qt::MidButton ) + emit middleButtonClicked( dynamic_cast( item ) ); +} + +void KrBriefView::refreshColors() { + krConfig->setGroup("Colors"); + bool kdeDefault = krConfig->readBoolEntry("KDE Default"); + if ( !kdeDefault ) { + // KDE default is not choosen: set the background color (as this paints the empty areas) and the alternate color + bool isActive = hasFocus(); + if ( MAIN_VIEW && ACTIVE_PANEL && ACTIVE_PANEL->view ) + isActive = ( static_cast( this ) == ACTIVE_PANEL->view ); + QColorGroup cg; + KrColorCache::getColorCache().getColors(cg, KrColorItemType(KrColorItemType::File, false, isActive, false, false)); + setPaletteBackgroundColor( cg.background() ); + } else { + // KDE default is choosen: set back the background color + setPaletteBackgroundColor( KGlobalSettings::baseColor() ); + } + slotUpdate(); +} + +bool KrBriefView::event( QEvent *e ) { + modifierPressed = false; + + switch ( e->type() ) { + case QEvent::Timer: + case QEvent::MouseMove: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + break; + default: + CANCEL_TWO_CLICK_RENAME; + } + if( e->type() == QEvent::Wheel ) + { + if ( !_focused ) + op()->emitNeedFocus(); + setFocus(); + } + return KIconView::event( e ); +} + + +bool KrBriefView::eventFilter( QObject * watched, QEvent * e ) +{ + if( watched == horizontalScrollBar() ) + { + if( e->type() == QEvent::Hide || e->type() == QEvent::Show ) + { + bool res = KIconView::eventFilter( watched, e ); + arrangeItemsInGrid(); + return res; + } + } + else if( watched == header ) + { + if( e->type() == QEvent::MouseButtonPress && ((QMouseEvent *)e )->button() == Qt::RightButton ) + { + setColumnNr(); + return TRUE; + } + return FALSE; + } + return KIconView::eventFilter( watched, e ); +} + +void KrBriefView::makeItemVisible( const KrViewItem *item ) { +// qApp->processEvents(); // Please don't remove the comment. Causes crash if it is inserted! + ensureItemVisible( (QIconViewItem *)( static_cast( item ) ) ); +} + +void KrBriefView::initOperator() { + _operator = new KrViewOperator(this, this); + // QIconView emits selection changed, so chain them to operator + connect(this, SIGNAL(selectionChanged()), _operator, SIGNAL(selectionChanged())); +} + +void KrBriefView::initProperties() { + // TODO: move this to a general location, maybe KrViewProperties constructor ? + _properties = new KrBriefViewProperties; + _properties->filter = KrViewProperties::All; + _properties->filterMask = KRQuery( "*" ); + KConfigGroupSaver grpSvr( _config, "Look&Feel" ); + _properties->displayIcons = _config->readBoolEntry( "With Icons", _WithIcons ); + bool dirsByNameAlways = _config->readBoolEntry("Always sort dirs by name", false); + _properties->sortMode = static_cast( KrViewProperties::Name | + KrViewProperties::Descending | KrViewProperties::DirsFirst | + (dirsByNameAlways ? KrViewProperties::AlwaysSortDirsByName : 0) ); + if ( !_config->readBoolEntry( "Case Sensative Sort", _CaseSensativeSort ) ) + _properties->sortMode = static_cast( _properties->sortMode | + KrViewProperties::IgnoreCase ); + _properties->humanReadableSize = krConfig->readBoolEntry("Human Readable Size", _HumanReadableSize); + _properties->localeAwareCompareIsCaseSensitive = QString( "a" ).localeAwareCompare( "B" ) > 0; // see KDE bug #40131 + + QStringList defaultAtomicExtensions; + defaultAtomicExtensions += ".tar.gz"; + defaultAtomicExtensions += ".tar.bz2"; + defaultAtomicExtensions += ".moc.cpp"; + QStringList atomicExtensions = krConfig->readListEntry("Atomic Extensions", defaultAtomicExtensions); + for (QStringList::iterator i = atomicExtensions.begin(); i != atomicExtensions.end(); ) + { + QString & ext = *i; + ext = ext.stripWhiteSpace(); + if (!ext.length()) + { + i = atomicExtensions.remove(i); + continue; + } + if (!ext.startsWith(".")) + ext.insert(0, '.'); + ++i; + } + _properties->atomicExtensions = atomicExtensions; + + _config->setGroup( nameInKConfig() ); + PROPS->numberOfColumns = _config->readNumEntry( "Number Of Brief Columns", _NumberOfBriefColumns ); + if( PROPS->numberOfColumns < 1 ) + PROPS->numberOfColumns = 1; + else if( PROPS->numberOfColumns > MAX_COLS ) + PROPS->numberOfColumns = MAX_COLS; +} + +void KrBriefView::setColumnNr() +{ + KPopupMenu popup( this ); + popup.insertTitle( i18n("Columns")); + + int COL_ID = 14700; + + for( int i=1; i <= MAX_COLS; i++ ) + { + popup.insertItem( QString( "%1" ).arg( i ), COL_ID + i ); + popup.setItemChecked( COL_ID + i, PROPS->numberOfColumns == i ); + } + + int result=popup.exec(QCursor::pos()); + + krConfig->setGroup( nameInKConfig() ); + + if( result > COL_ID && result <= COL_ID + MAX_COLS ) + { + krConfig->writeEntry( "Number Of Brief Columns", result - COL_ID ); + PROPS->numberOfColumns = result - COL_ID; + redrawColumns(); + } +} + +void KrBriefView::sortOrderChanged() { + ensureItemVisible(currentItem()); + + if( !_focused ) + op()->emitNeedFocus(); + +} + +void KrBriefView::updateView() { + arrangeItemsInGrid(); + op()->emitSelectionChanged(); +} + +void KrBriefView::updateItem(KrViewItem* item) { + dynamic_cast(item)->repaintItem(); +} + +void KrBriefView::slotRightButtonPressed(QIconViewItem*, const QPoint& point) { + op()->emitEmptyContextMenu(point); +} + +void KrBriefView::changeSortOrder() +{ + bool asc = !sortDirection(); + header->setSortIndicator( 0, asc ? Qt::Ascending : Qt::Descending ); + sort( asc ); +} + +QMouseEvent * KrBriefView::transformMouseEvent( QMouseEvent * e ) +{ + if( findItem( e->pos() ) != 0 ) + return e; + + QIconViewItem *closestItem = 0; + int mouseX = e->pos().x(), mouseY = e->pos().y(); + int closestDelta = 0x7FFFFFFF; + + int minX = ( mouseX / gridX() ) * gridX(); + int maxX = minX + gridX(); + + QIconViewItem *current = firstItem(); + while( current ) + { + if( current->x() >= minX && current->x() < maxX ) + { + int delta = mouseY - current->y(); + if( delta >= 0 && delta < closestDelta ) + { + closestDelta = delta; + closestItem = current; + } + } + current = current->nextItem(); + } + + if( closestItem != 0 ) + { + if( mouseX - closestItem->x() > gridX() ) + closestItem = 0; + else if( mouseY - closestItem->y() > closestItem->height() ) + closestItem = 0; + } + + if( closestItem != 0 ) + { + QRect rec = closestItem->textRect( false ); + if( mouseX < rec.x() ) + mouseX = rec.x(); + if( mouseY < rec.y() ) + mouseY = rec.y(); + if( mouseX > rec.x() + rec.width() -1 ) + mouseX = rec.x() + rec.width() -1; + if( mouseY > rec.y() + rec.height() -1 ) + mouseY = rec.y() + rec.height() -1; + QPoint newPos( mouseX, mouseY ); + QPoint glPos; + if( !e->globalPos().isNull() ) + { + glPos = QPoint( mouseX - e->pos().x() + e->globalPos().x(), + mouseY - e->pos().y() + e->globalPos().y() ); + } + + if( mouseEvent ) + delete mouseEvent; + return mouseEvent = new QMouseEvent( e->type(), newPos, glPos, e->button(), e->state() ); + } + + return e; +} + +#include "krbriefview.moc" diff --git a/krusader/Panel/krbriefview.h b/krusader/Panel/krbriefview.h new file mode 100644 index 0000000..8ba27f4 --- /dev/null +++ b/krusader/Panel/krbriefview.h @@ -0,0 +1,172 @@ +/*************************************************************************** + krbriefview.h + ------------------- + copyright : (C) 2000-2007 by Shie Erlich & Rafi Yanai & 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 KRBRIEFVIEW_H +#define KRBRIEFVIEW_H + +#include "krview.h" +#include "krviewitem.h" +#include +#include + +// extends KrViewProperties to add detailedview-only properties +class KrBriefViewProperties: public KrViewProperties { +public: + int numberOfColumns; // the number of columns in the view +}; + +class KrBriefViewItem; +class QDragMoveEvent; +class QToolTip; +class QHeader; + +/** + * KrBriefView implements everthing and anything regarding a brief view in a filemananger. + * IT MUST USE KrViewItem as the children to it's *KIconView. KrBriefView and KrViewItem are + * tightly coupled and the view will not work with other kinds of items. + * Apart from this, the view is self-reliant and you can use the vast interface to get whatever + * information is necessery from it. + */ +class KrBriefView: public KIconView, public KrView { + friend class KrBriefViewItem; + Q_OBJECT +public: + KrBriefView( QHeader *header, QWidget *parent, bool &left, KConfig *cfg = krConfig, const char *name = 0 ); + virtual ~KrBriefView(); + virtual inline KrViewItem *getFirst() { return dynamic_cast( firstItem() ); } + virtual inline KrViewItem *getLast() { return dynamic_cast( lastItem() ); } + virtual inline KrViewItem *getNext( KrViewItem *current ) { return dynamic_cast( dynamic_cast( current ) ->nextItem() ); } + virtual inline KrViewItem *getPrev( KrViewItem *current ) { return dynamic_cast( dynamic_cast( current ) ->prevItem() ); } + virtual inline KrViewItem *getCurrentKrViewItem() { return dynamic_cast( currentItem() ); } + virtual KrViewItem *getKrViewItemAt(const QPoint &vp); + virtual inline KrViewItem *findItemByName(const QString &name) { return dynamic_cast( findItem( name, Qt::ExactMatch ) ); } + virtual void addItems(vfs* v, bool addUpDir = true); + virtual void delItem(const QString &); + virtual QString getCurrentItem() const; + virtual void makeItemVisible(const KrViewItem * item ); + virtual void setCurrentItem(const QString& name ); + virtual void updateView(); + virtual void updateItem(KrViewItem* item ); + virtual void clear(); + virtual void sort() { if( sortDirection() ) sortOrderChanged();KIconView::sort( true ); } + virtual void sort( bool ascending ) { if( sortDirection() != ascending ) sortOrderChanged();KIconView::sort( ascending ); } + virtual void prepareForActive(); + virtual void prepareForPassive(); + virtual void saveSettings() {} + virtual void restoreSettings() {} + virtual QString nameInKConfig() {return _nameInKConfig;} + virtual void resizeEvent ( QResizeEvent * ); + +signals: + void middleButtonClicked( KrViewItem *item ); + void currentChanged( KrViewItem *item ); + +protected: + virtual void setup(); + virtual void initProperties(); + virtual void initOperator(); + virtual KrViewItem *preAddItem(vfile * vf); + virtual bool preDelItem(KrViewItem * item ); + + void setColumnNr(); + void redrawColumns(); + + virtual void keyPressEvent( QKeyEvent *e ); + virtual void imStartEvent( QIMEvent* e ); + virtual void imEndEvent( QIMEvent *e ); + virtual void imComposeEvent( QIMEvent *e ); + virtual void contentsMousePressEvent( QMouseEvent *e ); + virtual void contentsMouseReleaseEvent (QMouseEvent *e); + virtual void contentsMouseMoveEvent ( QMouseEvent * e ); + virtual void contentsMouseDoubleClickEvent ( QMouseEvent * e ); + virtual bool acceptDrag( QDropEvent* e ) const; + virtual void contentsDropEvent( QDropEvent *e ); + virtual void contentsDragMoveEvent( QDragMoveEvent *e ); + virtual void contentsDragLeaveEvent ( QDragLeaveEvent * ); + virtual void startDrag() { op()->startDrag(); } + virtual bool event( QEvent *e ); + virtual bool eventFilter( QObject * watched, QEvent * e ); + QMouseEvent * transformMouseEvent( QMouseEvent * ); + +protected slots: + void rename( QIconViewItem *item ); + void slotClicked( QIconViewItem *item ); + void slotDoubleClicked( QIconViewItem *item ); + void slotItemDescription( QIconViewItem * ); + void slotCurrentChanged( QIconViewItem *item ); + void handleContextMenu( QIconViewItem*, const QPoint& ); + virtual void renameCurrentItem(); + virtual void showContextMenu( ); + void inplaceRenameFinished( QIconViewItem *it ); + void setNameToMakeCurrent( QIconViewItem *it ); + void sortOrderChanged(); + void slotRightButtonPressed(QIconViewItem*, const QPoint& point); + void transformCurrentChanged( QIconViewItem * item ) { emit currentChanged( dynamic_cast(item ) ); } + + /** + * used internally to produce the signal middleButtonClicked() + */ + void slotMouseClicked( int button, QIconViewItem * item, const QPoint & pos ); + inline void slotExecuted( QIconViewItem* i ) { + QString tmp = dynamic_cast( i ) ->name(); + op()->emitExecuted( tmp ); + } + +public slots: + void refreshColors(); + void quickSearch( const QString &, int = 0 ); + void stopQuickSearch( QKeyEvent* ); + void handleQuickSearchEvent( QKeyEvent* ); + void changeSortOrder(); + + +signals: + void letsDrag(QStringList items, QPixmap icon); + void gotDrop(QDropEvent *); + +private: + QHeader * header; + bool swushSelects; + QPoint dragStartPos; + QIconViewItem *lastSwushPosition; + KrViewItem *_currDragItem; + bool singleClicked; + bool modifierPressed; + QTime clickTime; + QIconViewItem *clickedItem; + QTimer renameTimer; + QTimer contextMenuTimer; + QPoint contextMenuPoint; + KrBriefViewItem *currentlyRenamedItem; + QIconViewItem *pressedItem; + QMouseEvent *mouseEvent; + QToolTip *toolTip; +}; + +#endif diff --git a/krusader/Panel/krbriefviewitem.cpp b/krusader/Panel/krbriefviewitem.cpp new file mode 100644 index 0000000..533090f --- /dev/null +++ b/krusader/Panel/krbriefviewitem.cpp @@ -0,0 +1,225 @@ +#include "krbriefview.h" +#include "krbriefviewitem.h" +#include "../krusaderview.h" +#include "../defaults.h" +#include "../kicons.h" +#include "listpanel.h" +#include +#include "krcolorcache.h" + +#include +#include + +#define PROPS _viewProperties +#define VF getVfile() + +#ifdef FASTER +int KrBriefViewItem::expHeight = 0; +#endif // FASTER + +KrBriefViewItem::KrBriefViewItem(KrBriefView *parent, QIconViewItem *after, vfile *vf): + KIconViewItem(parent, after), KrViewItem(vf, parent->properties()) { +#ifdef FASTER + initiated = false; + // get the expected height of an item - should be done only once + if (expHeight == 0) { + KConfigGroupSaver svr(krConfig, "Look&Feel"); + expHeight = 2 + (krConfig->readEntry("Filelist Icon Size",_FilelistIconSize)).toInt(); + } + if( PROPS->displayIcons ) + itemIcon = QPixmap( expHeight, expHeight ); +#endif // FASTER + + // there's a special case, where if _vf is null, then we've got the ".." (updir) item + // in that case, create a special vfile for that item, and delete it, if needed + if (!_vf) { + dummyVfile = true; + _vf = new vfile("..", 0, "drw-r--r--", 0, false, 0, 0, QString::null, QString::null, 0); + + setText(".."); + if ( PROPS->displayIcons ) + setPixmap( FL_LOADICON( "up" ) ); + setSelectable( false ); + setDragEnabled( false ); + setDropEnabled( false ); +#ifdef FASTER + initiated = true; +#endif // FASTER + } + + setRenameEnabled( false ); + setDragEnabled( true ); + setDropEnabled( true ); + repaintItem(); +} + + +int KrBriefViewItem::compare(QIconViewItem *i ) const { + bool ignoreCase = (PROPS->sortMode & KrViewProperties::IgnoreCase); + + KrBriefViewItem *other = (KrBriefViewItem *)i; + int asc = iconView()->sortDirection() ? -1 : 1; + + bool thisDir = VF->vfile_isDir(); + bool otherDir = other->VF->vfile_isDir(); + + // handle directory sorting + if ( thisDir ){ + if ( !otherDir ) return 1*asc; + } else if( otherDir ) return -1*asc; + + if ( isDummy() ) return 1*asc; + if ( other->isDummy() ) return -1*asc; + + QString text0 = name(); + if (text0 == "..") return 1*asc; + + QString itext0 = other->name(); + if (itext0 == "..") return -1*asc; + + if( ignoreCase ) + { + text0 = text0.lower(); + itext0 = itext0.lower(); + } + + if ( isHidden() ) { + if ( !other->isHidden() ) return 1*asc; + } else if ( other->isHidden() ) return -1*asc; + + if (!ignoreCase && !PROPS->localeAwareCompareIsCaseSensitive) { + // sometimes, localeAwareCompare is not case sensative. in that case, + // we need to fallback to a simple string compare (KDE bug #40131) + return QString::compare(text0, itext0); + } else return QString::localeAwareCompare(text0,itext0); +} + +void KrBriefViewItem::paintItem(QPainter *p, const QColorGroup &cg) { +#ifdef FASTER + if (!initiated && !dummyVfile) { + // display an icon if needed + initiated = true; + if (PROPS->displayIcons) + itemIcon =KrView::getIcon(_vf); + } +#endif + + QColorGroup _cg(cg); + + KrColorItemType colorItemType; + colorItemType.m_activePanel = (dynamic_cast(iconView()) == ACTIVE_PANEL->view); + + int gridX = iconView()->gridX(); + int xpos = x() / gridX; + int ypos = y() / height(); + + colorItemType.m_alternateBackgroundColor = (xpos & 1) ^ (ypos & 1) ; + colorItemType.m_currentItem = (iconView()->currentItem() == this); + colorItemType.m_selectedItem = isSelected(); + if (VF->vfile_isSymLink()) + { + if (_vf->vfile_getMime() == "Broken Link !" ) + colorItemType.m_fileType = KrColorItemType::InvalidSymlink; + else + colorItemType.m_fileType = KrColorItemType::Symlink; + } + else if (VF->vfile_isDir()) + colorItemType.m_fileType = KrColorItemType::Directory; + else if (VF->vfile_isExecutable()) + colorItemType.m_fileType = KrColorItemType::Executable; + else + colorItemType.m_fileType = KrColorItemType::File; + KrColorCache::getColorCache().getColors(_cg, colorItemType); + + if( _cg.background() != iconView()->paletteBackgroundColor() ) + { + p->save(); + p->setPen( Qt::NoPen ); + p->setBrush( QBrush( _cg.background() ) ); + p->drawRect( rect() ); + p->restore(); + } + + QIconViewItem::paintItem(p, _cg); + + paintFocus( p, cg ); +} + +void KrBriefViewItem::paintFocus(QPainter *p, const QColorGroup &cg) { + if ( ( iconView()->hasFocus() && this == iconView()->currentItem() ) || + ((KrBriefView *)iconView())->_currDragItem == this ) + { + p->save(); + QPen pen( cg.shadow(), 0, Qt::DotLine ); + p->setPen( pen ); + + // we manually draw the focus rect by points + QRect rec = rect(); + QPointArray points( rec.right() - rec.left() + rec.bottom() - rec.top() + 4 ); + + int ndx = 0; + for( int x=rec.left(); x <= rec.right(); x+=2 ) + { + points.setPoint( ndx++, x, rec.top() ); + points.setPoint( ndx++, x, rec.bottom() ); + } + for( int y=rec.top(); y <= rec.bottom(); y+=2 ) + { + points.setPoint( ndx++, rec.left(), y ); + points.setPoint( ndx++, rec.right(), y ); + } + + p->drawPoints( points ); + p->restore(); + +// --- That didn't work with all themes +// iconView()->style().drawPrimitive(QStyle::PE_FocusRect, p, +// QRect( rect().x(), rect().y(), rect().width(), rect().height() ), cg, +// QStyle::Style_Default, cg.base() ); + } +} + +void KrBriefViewItem::itemHeightChanged() { +#ifdef FASTER + expHeight = 0; +#endif // FASTER +} + +void KrBriefViewItem::repaintItem() +{ + if ( dummyVfile ) return; + +#ifndef FASTER + if (PROPS->displayIcons) + setPixmap(KrView::getIcon(_vf)); +#endif // FASTER + setText( _vf->vfile_getName() ); +} + +// for keeping the exact item heights... +void KrBriefViewItem::calcRect ( const QString & text_ ) +{ + KIconViewItem::calcRect( text_ ); + QRect rec = rect(); + + int gridX = iconView()->gridX(); + int minX = ( rec.x() / gridX ) * gridX; + rec.setX( minX ); + rec.setWidth( gridX ); + rec.setHeight( expHeight ); + setItemRect( rec ); + + rec = pixmapRect(); + if( rec.height() > expHeight ) + { + rec.setHeight( expHeight ); + setPixmapRect( rec ); + } + + rec = textRect(); + if( rec.height() > expHeight ) + { + rec.setHeight( expHeight ); + setTextRect( rec ); + } +} diff --git a/krusader/Panel/krbriefviewitem.h b/krusader/Panel/krbriefviewitem.h new file mode 100644 index 0000000..e95c01b --- /dev/null +++ b/krusader/Panel/krbriefviewitem.h @@ -0,0 +1,79 @@ +/*************************************************************************** + krbriefviewitem.h + ------------------- + copyright : (C) 2000-2007 by Shie Erlich & Rafi Yanai & 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 KRBRIEFVIEWITEM_H +#define KRBRIEFVIEWITEM_H + +#include "krviewitem.h" +#include +#include "../VFS/vfile.h" +#include +#include + +#define FASTER + +class QPixmap; +class KrBriefView; + +class KrBriefViewItem : public KIconViewItem, public KrViewItem { +friend class KrBriefView; +friend class KrCalcSpaceDialog; +public: + KrBriefViewItem(KrBriefView *parent, QIconViewItem *after, vfile *vf); + inline bool isSelected() const { return KIconViewItem::isSelected(); } + inline void setSelected(bool s) { KIconViewItem::setSelected(s); } + inline void cancelRename() { removeRenameBox(); } + int compare(QIconViewItem *i) const; + virtual void repaintItem(); + static void itemHeightChanged(); // force the items to resize when icon/font size change + // TODO: virtual void setup(); // called when iconview needs to know the height of the item +#ifdef FASTER + virtual QPixmap * pixmap() const {return const_cast(&itemIcon);} + virtual void setPixmap ( const QPixmap &icon ) { itemIcon = icon;} +#endif + +protected: + virtual void paintItem(QPainter *p, const QColorGroup &cg); + virtual void paintFocus(QPainter *p, const QColorGroup &cg); + virtual void calcRect ( const QString & text_ = QString::null ); + +private: +#ifdef FASTER + bool initiated; + static int expHeight; + QPixmap itemIcon; +#endif // FASTER + // TODO: + static const QColor & setColorIfContrastIsSufficient(const QColor & /* background */, const QColor & /* color1 */, const QColor & /* color2 */ ) {static QColor col; return col;} + +// static int expHeight; +}; + +#endif diff --git a/krusader/Panel/krcalcspacedialog.cpp b/krusader/Panel/krcalcspacedialog.cpp new file mode 100644 index 0000000..aced7ed --- /dev/null +++ b/krusader/Panel/krcalcspacedialog.cpp @@ -0,0 +1,187 @@ +/*************************************************************************** + krcalcspacedialog.cpp - description + ------------------- + begin : Fri Jan 2 2004 + copyright : (C) 2004 by Shie Erlich & Rafi Yanai + 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. * +* * +***************************************************************************/ + +// Qt Includes +#include +#include +#include +// KDE Includes +#include +#include +// Krusader Includes +#include "krcalcspacedialog.h" +#include "listpanel.h" +#include "panelfunc.h" +#include "../krusader.h" +#include "../VFS/krpermhandler.h" + +/* --=={ Patch by Heiner }==-- */ +KrCalcSpaceDialog::CalcThread::CalcThread(KrCalcSpaceDialog * parent, ListPanel * panel, const QStringList & items) + : m_totalSize(0), m_currentSize(0), m_totalFiles(0), m_totalDirs(0), m_items(items), m_files(panel->func->files()), + m_view(panel->view), m_parent(parent), m_threadInUse(true), m_stop(false) {} + +void KrCalcSpaceDialog::CalcThread::cleanUp(){ + if (m_threadInUse || !finished()) + m_synchronizeUsageAccess.unlock(); + else{ + m_synchronizeUsageAccess.unlock(); // prevents a resource leak + // otherwise: no one needs this instance any more: delete it + delete this; + } +} + +void KrCalcSpaceDialog::CalcThread::deleteInstance(){ + // synchronize to avoid race condition. + m_synchronizeUsageAccess.lock(); + m_threadInUse = false; + cleanUp(); +} + +void KrCalcSpaceDialog::CalcThread::run(){ + if ( !m_items.isEmpty() ) // if something to do: do the calculation + for ( QStringList::ConstIterator it = m_items.begin(); it != m_items.end(); ++it ) + { + m_currentSize = 0; + m_files->vfs_calcSpace( *it, &m_currentSize, &m_totalFiles, &m_totalDirs , & m_stop); + if (m_stop) + break; + KrDetailedViewItem * viewItem = dynamic_cast(m_view->findItemByName ( *it ) ); + if (viewItem){ + KrCalcSpaceDialog::setDirSize(viewItem, m_currentSize); + //viewItem->repaintItem(); // crash in KrDetailedViewItem::repaintItem(): setPixmap(_view->column(KrDetailedView::Name),KrView::getIcon(_vf)) + } + m_totalSize += m_currentSize; + m_currentSize = 0; + } + // synchronize to avoid race condition. + m_synchronizeUsageAccess.lock(); + cleanUp(); // this does not need the instance any more +} + +void KrCalcSpaceDialog::CalcThread::stop(){ + // cancel was pressed + m_stop = true; +} + +KrCalcSpaceDialog::KrCalcSpaceDialog(QWidget *parent, ListPanel * files, const QStringList & items, bool autoclose) : + KDialogBase(parent, "KrCalcSpaceDialog", true, i18n("Calculate Occupied Space"), Ok|Cancel), + m_autoClose(autoclose), m_canceled(false), m_timerCounter(0){ + // the dialog: The Ok button is hidden until it is needed + showButtonOK(false); + m_thread = new CalcThread(this, files, items); + m_pollTimer = new QTimer(this); + QWidget * mainWidget = new QWidget( this ); + setMainWidget(mainWidget); + QVBoxLayout *topLayout = new QVBoxLayout( mainWidget, 0, spacingHint() ); + + m_label = new QLabel( "", mainWidget, "caption" ); + showResult(); // fill m_label with something usefull + topLayout->addWidget( m_label ); + topLayout->addStretch(10); +} + +void KrCalcSpaceDialog::calculationFinished(){ + // close dialog if auto close is true + if (m_autoClose){ + done(0); + return; + } + // otherwise hide cancel and show ok button + showButtonCancel(false); + showButtonOK(true); + showResult(); // and show final result +} + +/* This timer has two jobs: it polls the thread if it is finished. Polling is + better here as it might finish while the dialog builds up. Secondly it refreshes + the displayed result. + */ +void KrCalcSpaceDialog::timer(){ + // thread finished? + if (m_thread->finished()){ + // close dialog or switch buttons + calculationFinished(); + m_pollTimer->stop(); // stop the polling. No longer needed + return; + } + + // Every 10 pollings (1 second) refresh the displayed result + if (++m_timerCounter > 10){ + m_timerCounter = 0; + showResult(); + } +} + +void KrCalcSpaceDialog::showResult(){ + if (!m_thread) return; + QString msg; + QString fileName = ( ( m_thread->getItems().count() == 1 ) ? ( i18n( "Name: " ) + m_thread->getItems().first() + "\n" ) : QString( "" ) ); + msg = fileName + i18n( "Total occupied space: %1").arg( KIO::convertSize( m_thread->getTotalSize() ) ); + if (m_thread->getTotalSize() >= 1024) + msg += " (" + KRpermHandler::parseSize( m_thread->getTotalSize() ) + "bytes)"; + msg += "\n"; + msg += i18n("in %n directory", "in %n directories", m_thread->getTotalDirs() ); + msg += " "; + msg += i18n("and %n file", "and %n files", m_thread->getTotalFiles() ); + m_label->setText(msg); +} + +void KrCalcSpaceDialog::slotCancel(){ + m_thread->stop(); // notify teh thread to stop + m_canceled = true; // set the cancel flag + KDialogBase::slotCancel(); // close the dialog +} + +KrCalcSpaceDialog::~KrCalcSpaceDialog(){ + CalcThread * tmp = m_thread; + m_thread = 0; // do not access the thread anymore or core dump if smoe piece of code wrongly does + tmp->deleteInstance(); // Notify the thread, that the dialog does not need anymore. +} + +void KrCalcSpaceDialog::exec(){ + m_thread->start(); // start the thread + if (m_autoClose){ // autoclose + // set the cursor to busy mode and wait 3 seconds or until the thread finishes + krApp->setCursor( KCursor::waitCursor() ); + bool result = m_thread->wait(3000); + krApp->setCursor( KCursor::arrowCursor() ); // return the cursor to normal mode + if (result) return;// thread finished: do not show the dialog + showResult(); // fill the invisible dialog with usefull data + } + // prepare and start the poll timer + connect(m_pollTimer, SIGNAL(timeout()), this, SLOT(timer())); + m_pollTimer->start(100); + KDialogBase::exec(); // show the dialog +} +/* --=={ End of patch by Heiner }==-- */ + + +#include "krcalcspacedialog.moc" diff --git a/krusader/Panel/krcalcspacedialog.h b/krusader/Panel/krcalcspacedialog.h new file mode 100644 index 0000000..fcdbdce --- /dev/null +++ b/krusader/Panel/krcalcspacedialog.h @@ -0,0 +1,106 @@ +/*************************************************************************** + krcalcspacedialog.h - description + ------------------- + begin : Fri Jan 2 2004 + copyright : (C) 2004 by Shie Erlich & Rafi Yanai + 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 KRCALCSPACEDIALOG_H +#define KRCALCSPACEDIALOG_H + +/* --=={ Patch by Heiner }==-- */ + +// KDE Includes +#include +#include +// Qt Includes +#include +// Krusader Includes +#include "../VFS/vfs.h" +#include "krdetailedviewitem.h" +class ListPanel; +class KrView; + + +/* Dialog calculating showing the number of files and directories and its total size + in a dialog. If wanted, the dialog appears after 3 seconds of calculation, to + avoid a short appearence if the result was found quickly. Computes teh result in + a different thread. + */ +class KrCalcSpaceDialog : public KDialogBase{ + Q_OBJECT + /* Thread which does the actual calculation. Deletes itself, if no longer + needed. Creator must call finished(), if the thread is no longer needed. + */ + class CalcThread : public QThread{ + KIO::filesize_t m_totalSize, m_currentSize; + unsigned long m_totalFiles; + unsigned long m_totalDirs; + const QStringList m_items; + vfs * m_files; + KrView *m_view; + KrCalcSpaceDialog * m_parent; + QMutex m_synchronizeUsageAccess; + bool m_threadInUse; // true: caller needs the thread + bool m_stop; + void cleanUp(); // Deletes this, if possible + public: + KIO::filesize_t getTotalSize() const {return m_totalSize + m_currentSize;} // the result + unsigned long getTotalFiles() const {return m_totalFiles;} // the result + unsigned long getTotalDirs() const {return m_totalDirs;} // the result + const QStringList & getItems() const {return m_items;} // list of directories to calculate + CalcThread(KrCalcSpaceDialog * parent, ListPanel * panel, const QStringList & items); + void deleteInstance(); // thread is no longer needed. + void run(); // start calculation + void stop(); // stop it. Thread continues until vfs_calcSpace returns + } * m_thread; + friend class CalcThread; + class QTimer * m_pollTimer; + QLabel * m_label; + bool m_autoClose; // true: wait 3 sec. before showing the dialog. Close it, when done + bool m_canceled; // true: cancel was pressed + int m_timerCounter; // internal counter. The timer runs faster as the rehresh (see comment there) + void calculationFinished(); // called if the calulation is done + void showResult(); // show the current result in teh dialog + static void setDirSize(KrDetailedViewItem * viewItem, KIO::filesize_t size) {viewItem->setSize(size);} +protected slots: + void timer(); // poll timer was fired + void slotCancel(); // cancel was pressed +public: + // autoclose: wait 3 sec. before showing the dialog. Close it, when done + KrCalcSpaceDialog(QWidget *parent, ListPanel * panel, const QStringList & items, bool autoclose); + ~KrCalcSpaceDialog(); + KIO::filesize_t getTotalSize() const {return m_thread->getTotalSize();} // the result + unsigned long getTotalFiles() const {return m_thread->getTotalFiles();} // the result + unsigned long getTotalDirs() const {return m_thread->getTotalDirs();} // the result + bool wasCanceled() const {return m_canceled;} // cancel was pressed; result is probably wrong +public slots: + void exec(); // start calculation +}; +/* End of patch by Heiner */ + +#endif diff --git a/krusader/Panel/krcolorcache.cpp b/krusader/Panel/krcolorcache.cpp new file mode 100644 index 0000000..2c3351a --- /dev/null +++ b/krusader/Panel/krcolorcache.cpp @@ -0,0 +1,761 @@ +/*************************************************************************** + krcolorcache.cpp + ------------------- +copyright : (C) 2000-2002 by Shie Erlich & Rafi Yanai +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 "krcolorcache.h" +#include "../krusader.h" +#include "../defaults.h" +#include +#include + + +// Macro: set target = col, if col is valid +#define SETCOLOR(target, col) { if (col.isValid()) target = col; } + +/* +Static class, which lists all allowed keywords for a quick access. Just call a method to initialize it. +*/ +class KrColorSettingNames +{ + static QMap s_colorNames; + static QMap s_numNames; + static QMap s_boolNames; + static void initialize(); +public: + static QValueList getColorNames(); + static bool isColorNameValid(const QString & settingName); + static QValueList getNumNames(); + static bool isNumNameValid(const QString & settingName); + static QValueList getBoolNames(); + static bool isBoolNameValid(const QString & settingName); +} krColorSettingNames; + +QMap KrColorSettingNames::s_colorNames; +QMap KrColorSettingNames::s_numNames; +QMap KrColorSettingNames::s_boolNames; + +void KrColorSettingNames::initialize() +{ + if (!s_colorNames.empty()) + return; + s_colorNames["Foreground"] = true; + s_colorNames["Inactive Foreground"] = true; + s_colorNames["Directory Foreground"] = true; + s_colorNames["Inactive Directory Foreground"] = true; + s_colorNames["Executable Foreground"] = true; + s_colorNames["Inactive Executable Foreground"] = true; + s_colorNames["Symlink Foreground"] = true; + s_colorNames["Inactive Symlink Foreground"] = true; + s_colorNames["Invalid Symlink Foreground"] = true; + s_colorNames["Inactive Invalid Symlink Foreground"] = true; + s_colorNames["Marked Foreground"] = true; + s_colorNames["Inactive Marked Foreground"] = true; + s_colorNames["Marked Background"] = true; + s_colorNames["Inactive Marked Background"] = true; + s_colorNames["Current Foreground"] = true; + s_colorNames["Inactive Current Foreground"] = true; + s_colorNames["Current Background"] = true; + s_colorNames["Inactive Current Background"] = true; + s_colorNames["Marked Current Foreground"] = true; + s_colorNames["Inactive Marked Current Foreground"] = true; + s_colorNames["Alternate Background"] = true; + s_colorNames["Inactive Alternate Background"] = true; + s_colorNames["Background"] = true; + s_colorNames["Inactive Background"] = true; + s_colorNames["Alternate Marked Background"] = true; + s_colorNames["Inactive Alternate Marked Background"] = true; + s_colorNames["Dim Target Color"] = true; + + s_numNames["Dim Factor"] = true; + + s_boolNames["KDE Default"] = true; + s_boolNames["Enable Alternate Background"] = true; + s_boolNames["Show Current Item Always"] = true; + s_boolNames["Dim Inactive Colors"] = true; +} + +QValueList KrColorSettingNames::getColorNames() +{ + initialize(); + return s_colorNames.keys(); +} + +bool KrColorSettingNames::isColorNameValid(const QString & settingName) +{ + initialize(); + return s_colorNames.contains(settingName); +} + +QValueList KrColorSettingNames::getNumNames() +{ + initialize(); + return s_numNames.keys(); +} + +bool KrColorSettingNames::isNumNameValid(const QString & settingName) +{ + initialize(); + return s_numNames.contains(settingName); +} + +QValueList KrColorSettingNames::getBoolNames() +{ + initialize(); + return s_boolNames.keys(); +} + +bool KrColorSettingNames::isBoolNameValid(const QString & settingName) +{ + initialize(); + return s_boolNames.contains(settingName); +} + + + +/* +KrColorSettings implementation. Contains all properties in QMaps. loadFromConfig initializes them from krConfig. +*/ +class KrColorSettingsImpl +{ + friend class KrColorSettings; + QMap m_colorTextValues; + QMap m_colorValues; + QMap m_numValues; + QMap m_boolValues; + void loadFromConfig(); +}; + +void KrColorSettingsImpl::loadFromConfig() +{ + krConfig->setGroup("Colors"); + QValueList names = KrColorSettingNames::getColorNames(); + for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it ) + { + m_colorTextValues[*it] = krConfig->readEntry(*it, ""); + m_colorValues[*it] = krConfig->readColorEntry(*it); + } + names = KrColorSettingNames::getNumNames(); + for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it ) + { + if (krConfig->readEntry(*it) != QString::null) + m_numValues[*it] = krConfig->readNumEntry(*it); + } + names = KrColorSettingNames::getBoolNames(); + for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it ) + { + if (krConfig->readEntry(*it) != QString::null) + m_boolValues[*it] = krConfig->readBoolEntry(*it); + } +} + + + +KrColorSettings::KrColorSettings() +{ + m_impl = new KrColorSettingsImpl(); + m_impl->loadFromConfig(); +} + +KrColorSettings::KrColorSettings(const KrColorSettings & src) +{ + m_impl = new KrColorSettingsImpl(); + operator =(src); +} + +KrColorSettings::~KrColorSettings() +{ + delete m_impl; +} + +const KrColorSettings & KrColorSettings::operator= (const KrColorSettings & src) +{ + if (this == & src) + return * this; + QValueList names = KrColorSettingNames::getColorNames(); + for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it ) + { + m_impl->m_colorTextValues[*it] = src.m_impl->m_colorTextValues[*it]; + m_impl->m_colorValues[*it] = src.m_impl->m_colorValues[*it]; + } + for ( QMap::Iterator it = src.m_impl->m_numValues.begin(); it != src.m_impl->m_numValues.end(); ++it ) + { + m_impl->m_numValues[it.key()] = it.data(); + } + for ( QMap::Iterator it = src.m_impl->m_boolValues.begin(); it != src.m_impl->m_boolValues.end(); ++it ) + { + m_impl->m_boolValues[it.key()] = it.data(); + } + return * this; +} + +QValueList KrColorSettings::getColorNames() +{ + return KrColorSettingNames::getColorNames(); +} + +bool KrColorSettings::isColorNameValid(const QString & settingName) +{ + return KrColorSettingNames::isColorNameValid(settingName); +} + +bool KrColorSettings::setColorValue(const QString & settingName, const QColor & color) +{ + if (!isColorNameValid(settingName)) + { + krOut << "Invalid color setting name: " << settingName << endl; + return false; + } + m_impl->m_colorValues[settingName] = color; + return true; +} + +QColor KrColorSettings::getColorValue(const QString & settingName) const +{ + if (!isColorNameValid(settingName)) + { + krOut << "Invalid color setting name: " << settingName << endl; + return QColor(); + } + return m_impl->m_colorValues[settingName]; +} + +bool KrColorSettings::setColorTextValue(const QString & settingName, const QString & colorText) +{ + if (!isColorNameValid(settingName)) + { + krOut << "Invalid color setting name: " << settingName << endl; + return false; + } + m_impl->m_colorTextValues[settingName] = colorText; + return true; +} + +QString KrColorSettings::getColorTextValue(const QString & settingName) const +{ + if (!isColorNameValid(settingName)) + { + krOut << "Invalid color setting name: " << settingName << endl; + return QString(); + } + return m_impl->m_colorTextValues[settingName]; +} + +QValueList KrColorSettings::getNumNames() +{ + return KrColorSettingNames::getNumNames(); +} + +bool KrColorSettings::isNumNameValid(const QString & settingName) +{ + return KrColorSettingNames::isNumNameValid(settingName); +} + +bool KrColorSettings::setNumValue(const QString & settingName, int value) +{ + if (!isNumNameValid(settingName)) + { + krOut << "Invalid number setting name: " << settingName << endl; + return false; + } + m_impl->m_numValues[settingName] = value; + return true; +} + +int KrColorSettings::getNumValue(const QString & settingName, int defaultValue) const +{ + if (!isNumNameValid(settingName)) + { + krOut << "Invalid number setting name: " << settingName << endl; + return 0; + } + if (!m_impl->m_numValues.contains(settingName)) + return defaultValue; + return m_impl->m_numValues[settingName]; +} + +QValueList KrColorSettings::getBoolNames() +{ + return KrColorSettingNames::getBoolNames(); +} + +bool KrColorSettings::isBoolNameValid(const QString & settingName) +{ + return KrColorSettingNames::isBoolNameValid(settingName); +} + +bool KrColorSettings::setBoolValue(const QString & settingName, bool value) +{ + if (!isBoolNameValid(settingName)) + { + krOut << "Invalid bool setting name: " << settingName << endl; + return false; + } + m_impl->m_boolValues[settingName] = value; + return true; +} + +int KrColorSettings::getBoolValue(const QString & settingName, bool defaultValue) const +{ + if (!isBoolNameValid(settingName)) + { + krOut << "Invalid bool setting name: " << settingName << endl; + return false; + } + if (!m_impl->m_boolValues.contains(settingName)) + return defaultValue; + return m_impl->m_boolValues[settingName]; +} + + + +KrColorItemType::KrColorItemType() +{ + m_fileType = File; + m_alternateBackgroundColor = false; + m_activePanel = false; + m_currentItem = false; + m_selectedItem = false; +} + +KrColorItemType::KrColorItemType(FileType type, bool alternateBackgroundColor, bool activePanel, bool currentItem, bool selectedItem) +{ + m_fileType = type; + m_alternateBackgroundColor = alternateBackgroundColor; + m_activePanel = activePanel; + m_currentItem = currentItem; + m_selectedItem = selectedItem; +} + +KrColorItemType::KrColorItemType(const KrColorItemType & src) +{ + operator= (src); +} + +const KrColorItemType & KrColorItemType::operator= (const KrColorItemType & src) +{ + if (this == & src) + return * this; + m_fileType = src.m_fileType; + m_alternateBackgroundColor = src.m_alternateBackgroundColor; + m_activePanel = src.m_activePanel; + m_currentItem = src.m_currentItem; + m_selectedItem = src.m_selectedItem; + return * this; +} + + + + +/* +KrColorCache implementation. Contains the KrColorSettings used for teh calculation and the cache for the results. +getColors is the only method to call. All other are taken from the previous versions. +*/ +class KrColorCacheImpl +{ + friend class KrColorCache; + QMap m_cachedColors; + KrColorSettings m_colorSettings; + QColorGroup getColors(const KrColorItemType & type) const; + static const QColor & setColorIfContrastIsSufficient(const QColor & background, const QColor & color1, const QColor & color2); + QColor getForegroundColor(bool isActive) const; + QColor getSpecialForegroundColor(const QString & type, bool isActive) const; + QColor getBackgroundColor(bool isActive) const; + QColor getAlternateBackgroundColor(bool isActive) const; + QColor getMarkedForegroundColor(bool isActive) const; + QColor getMarkedBackgroundColor(bool isActive) const; + QColor getAlternateMarkedBackgroundColor(bool isActive) const; + QColor getCurrentForegroundColor(bool isActive) const; + QColor getCurrentBackgroundColor(bool isActive) const; + QColor getCurrentMarkedForegroundColor(bool isActive) const; + QColor dimColor(QColor color, bool isBackgroundColor) const; +}; + +QColorGroup KrColorCacheImpl::getColors(const KrColorItemType & type) const +{ + QColorGroup result; + if (m_colorSettings.getBoolValue("KDE Default", _KDEDefaultColors)) + { + // KDE default? Getcolors from KGlobalSettings. + bool enableAlternateBackground = m_colorSettings.getBoolValue("Enable Alternate Background", _AlternateBackground); + QColor background = enableAlternateBackground && type.m_alternateBackgroundColor ? + KGlobalSettings::alternateBackgroundColor() + : KGlobalSettings::baseColor(); + result.setColor(QColorGroup::Base, background); + result.setColor(QColorGroup::Background, background); + result.setColor(QColorGroup::Text, KGlobalSettings::textColor()); + result.setColor(QColorGroup::HighlightedText, KGlobalSettings::highlightedTextColor()); + result.setColor(QColorGroup::Highlight, KGlobalSettings::highlightColor()); + return result; + } + bool markCurrentAlways = m_colorSettings.getBoolValue("Show Current Item Always", _ShowCurrentItemAlways); + bool dimBackground = m_colorSettings.getBoolValue("Dim Inactive Colors", false); + + // cache m_activePanel flag. If color dimming is turned on, it is set to true, as the inactive colors + // are calculated from the active ones at the end. + bool isActive = type.m_activePanel; + if (dimBackground) + isActive = true; + + // First calculate fore- and background. + QColor background = type.m_alternateBackgroundColor ? + getAlternateBackgroundColor(isActive) + : getBackgroundColor(isActive); + QColor foreground; + switch(type.m_fileType) + { + case KrColorItemType::Directory : + foreground = getSpecialForegroundColor("Directory", isActive); + break; + case KrColorItemType::Executable : + foreground = getSpecialForegroundColor("Executable", isActive); + break; + case KrColorItemType::InvalidSymlink : + foreground = getSpecialForegroundColor("Invalid Symlink", isActive); + break; + case KrColorItemType::Symlink : + foreground = getSpecialForegroundColor("Symlink", isActive); + break; + default: + foreground = getForegroundColor(isActive); + } + + // set the background color + result.setColor(QColorGroup::Base, background); + result.setColor(QColorGroup::Background, background); + + // set the foreground color + result.setColor(QColorGroup::Text, foreground); + + // now the color of a marked item + QColor markedBackground = type.m_alternateBackgroundColor ? + getAlternateMarkedBackgroundColor(isActive) + : getMarkedBackgroundColor(isActive); + QColor markedForeground = getMarkedForegroundColor(isActive); + if (!markedForeground.isValid()) // transparent + // choose fore- or background, depending on its contrast compared to markedBackground + markedForeground = setColorIfContrastIsSufficient(markedBackground, foreground, background); + + // set it in the color group (different group color than normal foreground!) + result.setColor(QColorGroup::HighlightedText, markedForeground); + result.setColor(QColorGroup::Highlight, markedBackground); + + // In case the current item is a selected one, set the fore- and background colors for the contrast calculation below + if (type.m_selectedItem) + { + background = markedBackground; + foreground = markedForeground; + } + + // finally the current item + if (type.m_currentItem && (markCurrentAlways || isActive)) + { + // if this is the current item AND the panels has the focus OR the current should be marked always + QColor currentBackground = getCurrentBackgroundColor(isActive); + + if (!currentBackground.isValid()) // transparent + currentBackground = background; + + // set the background + result.setColor(QColorGroup::Highlight, currentBackground); + result.setColor(QColorGroup::Base, currentBackground); + result.setColor(QColorGroup::Background, currentBackground); + + QColor color; + if (type.m_selectedItem) + color = getCurrentMarkedForegroundColor(isActive); + if (!color.isValid()) // not used + { + color = getCurrentForegroundColor(isActive); + if (!color.isValid()) // transparent + // choose fore- or background, depending on its contrast compared to markedBackground + color = setColorIfContrastIsSufficient(currentBackground, foreground, background); + } + + // set the foreground + result.setColor(QColorGroup::Text, color); + result.setColor(QColorGroup::HighlightedText, color); + } + + if (dimBackground && !type.m_activePanel) + { + // if color dimming is choosen, dim the colors for the inactive panel + result.setColor(QColorGroup::Base, dimColor(result.base(), true)); + result.setColor(QColorGroup::Background, dimColor(result.base(), true)); + result.setColor(QColorGroup::Text, dimColor(result.text(), false)); + result.setColor(QColorGroup::HighlightedText, dimColor(result.highlightedText(), false)); + result.setColor(QColorGroup::Highlight, dimColor(result.highlight(), true)); + } + return result; +} + +const QColor & KrColorCacheImpl::setColorIfContrastIsSufficient(const QColor & background, const QColor & color1, const QColor & color2) +{ + #define sqr(x) ((x)*(x)) + int contrast = sqr(color1.red() - background.red()) + sqr(color1.green() - background.green()) + sqr(color1.blue() - background.blue()); + + // if the contrast between background and color1 is too small, take color2 instead. + if (contrast < 1000) + return color2; + return color1; +} + +QColor KrColorCacheImpl::getForegroundColor(bool isActive) const +{ + QColor color = KGlobalSettings::textColor(); + SETCOLOR(color, m_colorSettings.getColorValue("Foreground")); + if (!isActive) SETCOLOR(color, m_colorSettings.getColorValue("Inactive Foreground")); + return color; +} + +QColor KrColorCacheImpl::getSpecialForegroundColor(const QString & type, bool isActive) const +{ + QString colorName = "Inactive " + type + " Foreground"; + if (!isActive && m_colorSettings.getColorTextValue(colorName) == "Inactive Foreground") + return getForegroundColor(false); + QColor color = m_colorSettings.getColorValue(type + " Foreground"); + if (!isActive) SETCOLOR(color, m_colorSettings.getColorValue(colorName)); + if (!color.isValid()) + return getForegroundColor(isActive); + return color; +} + +QColor KrColorCacheImpl::getBackgroundColor(bool isActive) const +{ + QColor color = KGlobalSettings::baseColor(); + SETCOLOR(color, m_colorSettings.getColorValue("Background")); + if (!isActive) SETCOLOR(color, m_colorSettings.getColorValue("Inactive Background")); + return color; +} + +QColor KrColorCacheImpl::getAlternateBackgroundColor(bool isActive) const +{ + if (isActive && m_colorSettings.getColorTextValue("Alternate Background") == "Background") + return getBackgroundColor(true); + if (!isActive && m_colorSettings.getColorTextValue("Inactive Alternate Background") == "") + return getAlternateBackgroundColor(true); + if (!isActive && m_colorSettings.getColorTextValue("Inactive Alternate Background") == "Inactive Background") + return getBackgroundColor(false); + QColor color = isActive ? + m_colorSettings.getColorValue("Alternate Background") + : m_colorSettings.getColorValue("Inactive Alternate Background"); + if (!color.isValid()) + color = KGlobalSettings::alternateBackgroundColor(); + if (!color.isValid()) + color = KGlobalSettings::baseColor(); + return color; +} + +QColor KrColorCacheImpl::getMarkedForegroundColor(bool isActive) const +{ + QString colorName = isActive?"Marked Foreground":"Inactive Marked Foreground"; + if (m_colorSettings.getColorTextValue(colorName) == "transparent") + return QColor(); + if (isActive && m_colorSettings.getColorTextValue(colorName) == "") + return KGlobalSettings::highlightedTextColor(); + if (!isActive && m_colorSettings.getColorTextValue(colorName) == "") + return getMarkedForegroundColor(true); + return m_colorSettings.getColorValue(colorName); +} + +QColor KrColorCacheImpl::getMarkedBackgroundColor(bool isActive) const +{ + if (isActive && m_colorSettings.getColorTextValue("Marked Background") == "") + return KGlobalSettings::highlightColor(); + if (isActive && m_colorSettings.getColorTextValue("Marked Background") == "Background") + return getBackgroundColor(true); + if (!isActive && m_colorSettings.getColorTextValue("Inactive Marked Background") == "") + return getMarkedBackgroundColor(true); + if (!isActive && m_colorSettings.getColorTextValue("Inactive Marked Background") == "Inactive Background") + return getBackgroundColor(false); + return isActive ? + m_colorSettings.getColorValue("Marked Background") + : m_colorSettings.getColorValue("Inactive Marked Background"); +} + +QColor KrColorCacheImpl::getAlternateMarkedBackgroundColor(bool isActive) const +{ + if (isActive && m_colorSettings.getColorTextValue("Alternate Marked Background") == "Alternate Background") + return getAlternateBackgroundColor(true); + if (isActive && m_colorSettings.getColorTextValue("Alternate Marked Background") == "") + return getMarkedBackgroundColor(true); + if (!isActive && m_colorSettings.getColorTextValue("Inactive Alternate Marked Background") == "") + return getAlternateMarkedBackgroundColor(true); + if (!isActive && m_colorSettings.getColorTextValue("Inactive Alternate Marked Background") == "Inactive Alternate Background") + return getAlternateBackgroundColor(false); + if (!isActive && m_colorSettings.getColorTextValue("Inactive Alternate Marked Background") == "Inactive Marked Background") + return getMarkedBackgroundColor(false); + return isActive ? + m_colorSettings.getColorValue("Alternate Marked Background") + : m_colorSettings.getColorValue("Inactive Alternate Marked Background"); +} + +QColor KrColorCacheImpl::getCurrentForegroundColor(bool isActive) const +{ + QColor color = m_colorSettings.getColorValue("Current Foreground"); + if (!isActive) SETCOLOR(color, m_colorSettings.getColorValue("Inactive Current Foreground")); + return color; +} + +QColor KrColorCacheImpl::getCurrentBackgroundColor(bool isActive) const +{ + if (isActive && m_colorSettings.getColorTextValue("Current Background") == "") + return QColor(); + if (isActive && m_colorSettings.getColorTextValue("Current Background") == "Background") + return getBackgroundColor(true); + if (!isActive && m_colorSettings.getColorTextValue("Inactive Current Background") == "") + return getCurrentBackgroundColor(true); + if (!isActive && m_colorSettings.getColorTextValue("Inactive Current Background") == "Inactive Background") + return getBackgroundColor(false); + return isActive ? + m_colorSettings.getColorValue("Current Background") + : m_colorSettings.getColorValue("Inactive Current Background"); +} + +QColor KrColorCacheImpl::getCurrentMarkedForegroundColor(bool isActive) const +{ + QString colorName = isActive?"Marked Current Foreground":"Inactive Marked Current Foreground"; + if (isActive && m_colorSettings.getColorTextValue(colorName) == "") + return QColor(); + if (isActive && m_colorSettings.getColorTextValue(colorName) == "Marked Foreground") + return getMarkedForegroundColor(true); + if (!isActive && m_colorSettings.getColorTextValue(colorName) == "") + return getCurrentMarkedForegroundColor(true); + if (!isActive && m_colorSettings.getColorTextValue(colorName) == "Inactive Marked Foreground") + return getMarkedForegroundColor(false); + return m_colorSettings.getColorValue(colorName); +} + +QColor KrColorCacheImpl::dimColor(QColor color, bool /* isBackgroundColor */) const +{ + krConfig->setGroup("Colors"); + int dimFactor = m_colorSettings.getNumValue("Dim Factor", 100); + QColor targetColor = m_colorSettings.getColorValue("Dim Target Color"); + if (!targetColor.isValid()) + targetColor = QColor(255, 255, 255); + bool dimBackground = m_colorSettings.getBoolValue("Dim Inactive Colors", false); + bool dim = dimFactor >= 0 && dimFactor < 100 && dimBackground; + if (dim) + color = KrColorCache::dimColor(color, dimFactor, targetColor); + return color; +} + + + + + + +KrColorCache * KrColorCache::m_instance = 0; + +KrColorCache::KrColorCache() +{ + m_impl = new KrColorCacheImpl; +} + +KrColorCache::~KrColorCache() +{ + delete m_impl; +} + +KrColorCache & KrColorCache::getColorCache() +{ + if (!m_instance) + { + m_instance = new KrColorCache; + m_instance->refreshColors(); + } + return * m_instance; +} + +void KrColorCache::getColors(QColorGroup & result, const KrColorItemType & type) const +{ + // for the cache lookup: calculate a unique key from the type + char hashKey[128]; + switch(type.m_fileType) + { + case KrColorItemType::Directory : + strcpy(hashKey, "Directory"); + break; + case KrColorItemType::Executable : + strcpy(hashKey, "Executable"); + break; + case KrColorItemType::InvalidSymlink : + strcpy(hashKey, "InvalidSymlink"); + break; + case KrColorItemType::Symlink : + strcpy(hashKey, "Symlink"); + break; + default: + strcpy(hashKey, "File"); + } + if (type.m_activePanel) + strcat(hashKey, "-Active"); + if (type.m_alternateBackgroundColor) + strcat(hashKey, "-Alternate"); + if (type.m_currentItem) + strcat(hashKey, "-Current"); + if (type.m_selectedItem) + strcat(hashKey, "-Selected"); + + // lookup in cache + if (!m_impl->m_cachedColors.contains(hashKey)) + // not found: calculate color group and store it in cache + m_impl->m_cachedColors[hashKey] = m_impl->getColors(type); + + // get color group from cache + const QColorGroup & col = m_impl->m_cachedColors[hashKey]; + + // copy colors in question to result color group + result.setColor(QColorGroup::Base, col.base()); + result.setColor(QColorGroup::Background, col.base()); + result.setColor(QColorGroup::Text, col.text()); + result.setColor(QColorGroup::HighlightedText, col.highlightedText()); + result.setColor(QColorGroup::Highlight, col.highlight()); +} + +QColor KrColorCache::dimColor(const QColor & color, int dim, const QColor & targetColor) +{ + return QColor((targetColor.red() * (100 - dim) + color.red() * dim) / 100, + (targetColor.green() * (100 - dim) + color.green() * dim) / 100, + (targetColor.blue() * (100 - dim) + color.blue() * dim) / 100); +} + +void KrColorCache::refreshColors() +{ + m_impl->m_cachedColors.clear(); + m_impl->m_colorSettings = KrColorSettings(); + colorsRefreshed(); +} + +void KrColorCache::setColors(const KrColorSettings & colorSettings) +{ + m_impl->m_cachedColors.clear(); + m_impl->m_colorSettings = colorSettings; + colorsRefreshed(); +} + +#include "krcolorcache.moc" diff --git a/krusader/Panel/krcolorcache.h b/krusader/Panel/krcolorcache.h new file mode 100644 index 0000000..a213319 --- /dev/null +++ b/krusader/Panel/krcolorcache.h @@ -0,0 +1,101 @@ +#ifndef KRCOLORCACHE_H +#define KRCOLORCACHE_H + +#include +#include + +/* +Design goals: Color calculation is done on one place only. Configuration through krConfig OR through local settings. +Calculation must be fast through cacheing. + +This implementation exposes 3 classes: + +KrColorSettings: holds the color settings from krConfig, which can be changed locally +KrColorItemType: specifies the colors to be calculated +KrColorCache: perfomes the color calculation and caches the result. Uses KrColorSettings for the calculation +*/ + + +/* +Copies all used color settings from krConfig into a local cache on creation. It contains 3 types of properties: +color, numeric (int) and boolean. Color properties can have string or color values. Property values can be +changed. These changes does not go into krConfig! + +is*Valid checks, if a protery name is valid +get*Names returns a list of all allowed property names +set*Value overwrites a property with a new value +get*Value retunrs the current value + +For colors teh value can be returned as text or as color. If a text representation is not a valid color, +setColorValue(QColor()) should be called. +*/ +class KrColorSettings +{ + class KrColorSettingsImpl * m_impl; +public: + KrColorSettings(); + KrColorSettings(const KrColorSettings &); + ~KrColorSettings(); + const KrColorSettings & operator= (const KrColorSettings &); + + static bool isColorNameValid(const QString & settingName); + static QValueList getColorNames(); + bool setColorValue(const QString & settingName, const QColor & color); + QColor getColorValue(const QString & settingName) const; + bool setColorTextValue(const QString & settingName, const QString & colorText); + QString getColorTextValue(const QString & settingName) const; + + static bool isNumNameValid(const QString & settingName); + static QValueList getNumNames(); + bool setNumValue(const QString & settingName, int value); + int getNumValue(const QString & settingName, int defaultValue = 0) const; + + static bool isBoolNameValid(const QString & settingName); + static QValueList getBoolNames(); + bool setBoolValue(const QString & settingName, bool value); + int getBoolValue(const QString & settingName, bool defaultValue = false) const; +}; + +/* +A colletcion of properties which describe the color group to be calculated +*/ +class KrColorItemType +{ +public: + enum FileType {File, InvalidSymlink, Symlink, Directory, Executable}; + FileType m_fileType; + bool m_alternateBackgroundColor, m_activePanel, m_currentItem, m_selectedItem; + KrColorItemType(); + KrColorItemType(FileType type, bool alternateBackgroundColor, bool activePanel, bool currentItem, bool selectedItem); + KrColorItemType(const KrColorItemType &); + const KrColorItemType & operator= (const KrColorItemType &); +}; + +/* +The color calculation. It bases on an internal KrColorSettings instance. Via setColors it can be changed. +getColors does the color calculation. It sets the colors Base, Background, Text, HighlightedText and Highlight. +All calculated values are cached. The cache is deleted on refreshColors and setColors, which also trigger +colorsRefreshed. getColorCache returns a statis color cached for painting the panels. On the color cache +setColors should NEVER be called! +*/ +class KrColorCache : public QObject +{ + Q_OBJECT + static KrColorCache * m_instance; + class KrColorCacheImpl * m_impl; + KrColorCache(const KrColorCache &); + const KrColorCache & operator= (const KrColorCache &); +public: + KrColorCache(); + ~KrColorCache(); + static KrColorCache & getColorCache(); + void getColors(QColorGroup & result, const KrColorItemType & type) const; + static QColor dimColor(const QColor & color, int dim, const QColor & targetColor); +public slots: + void refreshColors(); + void setColors(const KrColorSettings &); +signals: + void colorsRefreshed(); +}; + +#endif diff --git a/krusader/Panel/krdetailedview.cpp b/krusader/Panel/krdetailedview.cpp new file mode 100644 index 0000000..633c2d7 --- /dev/null +++ b/krusader/Panel/krdetailedview.cpp @@ -0,0 +1,1587 @@ +/*************************************************************************** + krdetailedview.cpp + ------------------- +copyright : (C) 2000-2002 by Shie Erlich & Rafi Yanai +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 "krdetailedview.h" +#include "krdetailedviewitem.h" +#include "krcolorcache.h" +#include "krselectionmode.h" +#include "../krusader.h" +#include "../kicons.h" +#include "../defaults.h" +#include "../krusaderview.h" +#include "../krslots.h" +#include "../VFS/krpermhandler.h" +#include "../VFS/krarchandler.h" +#include "../GUI/kcmdline.h" +#include "../Dialogs/krspecialwidgets.h" +#include "../panelmanager.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +////////////////////////////////////////////////////////////////////////// +// The following is KrDetailedView's settings in KConfig: +// Group name: KrDetailedView +// +// Ext Column +#define _ExtColumn true +// Mime Column +#define _MimeColumn false +// Size Column +#define _SizeColumn true +// DateTime Column +#define _DateTimeColumn true +// Perm Column +#define _PermColumn false +// KrPerm Column +#define _KrPermColumn true +// Owner Column +#define _OwnerColumn false +// Group Column +#define _GroupColumn false +// Do Quicksearch +#define _DoQuicksearch true +////////////////////////////////////////////////////////////////////////// + +#define CANCEL_TWO_CLICK_RENAME {singleClicked = false;renameTimer.stop();} +#define COLUMN(X) static_cast(_properties)->column[ KrDetailedViewProperties::X ] +#define PROPS static_cast(_properties) +#define VF getVfile() + +#define COLUMN_POPUP_IDS 91 + +QString KrDetailedView::ColumnName[ KrDetailedViewProperties::MAX_COLUMNS ]; + +KrDetailedView::KrDetailedView( QWidget *parent, bool &left, KConfig *cfg, const char *name ) : + KListView( parent, name ), KrView( cfg ), _currDragItem( 0L ), currentlyRenamedItem( 0 ), + pressedItem( 0 ) { + setWidget( this ); + _nameInKConfig=QString( "KrDetailedView" ) + QString( ( left ? "Left" : "Right" ) ) ; + krConfig->setGroup("Private"); + if (krConfig->readBoolEntry("Enable Input Method", true)) + setInputMethodEnabled(true); +} + +void KrDetailedView::setup() { + lastSwushPosition = 0; + if ( ColumnName[ 0 ].isEmpty() ) { + ColumnName[ 0 ] = i18n( "Name" ); + ColumnName[ 1 ] = i18n( "Ext" ); + ColumnName[ 2 ] = i18n( "Type" ); + ColumnName[ 3 ] = i18n( "Size" ); + ColumnName[ 4 ] = i18n( "Modified" ); + ColumnName[ 5 ] = i18n( "Perms" ); + ColumnName[ 6 ] = i18n( "rwx" ); + ColumnName[ 7 ] = i18n( "Owner" ); + ColumnName[ 8 ] = i18n( "Group" ); + } + + /////////////////////////////// listview //////////////////////////////////// + { // use the {} so that KConfigGroupSaver will work correctly! + KConfigGroupSaver grpSvr( _config, "Look&Feel" ); + setFont( _config->readFontEntry( "Filelist Font", _FilelistFont ) ); + // decide on single click/double click selection + if ( _config->readBoolEntry( "Single Click Selects", _SingleClickSelects ) && + KGlobalSettings::singleClick() ) { + connect( this, SIGNAL( executed( QListViewItem* ) ), this, SLOT( slotExecuted( QListViewItem* ) ) ); + } else { + connect( this, SIGNAL( clicked( QListViewItem* ) ), this, SLOT( slotClicked( QListViewItem* ) ) ); + connect( this, SIGNAL( doubleClicked( QListViewItem* ) ), this, SLOT( slotDoubleClicked( QListViewItem* ) ) ); + } + + // a change in the selection needs to update totals + connect( this, SIGNAL( onItem( QListViewItem* ) ), this, SLOT( slotItemDescription( QListViewItem* ) ) ); + connect( this, SIGNAL( contextMenuRequested( QListViewItem*, const QPoint&, int ) ), + this, SLOT( handleContextMenu( QListViewItem*, const QPoint&, int ) ) ); + connect( this, SIGNAL( rightButtonPressed(QListViewItem*, const QPoint&, int)), + this, SLOT(slotRightButtonPressed(QListViewItem*, const QPoint&, int))); + connect( this, SIGNAL( currentChanged( QListViewItem* ) ), this, SLOT( setNameToMakeCurrent( QListViewItem* ) ) ); + connect( this, SIGNAL( currentChanged( QListViewItem* ) ), this, SLOT( transformCurrentChanged( QListViewItem* ) ) ); + connect( this, SIGNAL( mouseButtonClicked ( int, QListViewItem *, const QPoint &, int ) ), + this, SLOT( slotMouseClicked ( int, QListViewItem *, const QPoint &, int ) ) ); + connect( &KrColorCache::getColorCache(), SIGNAL( colorsRefreshed() ), this, SLOT( refreshColors() ) ); + connect( header(), SIGNAL(clicked(int)), this, SLOT(sortOrderChanged(int ))); + } + + // add whatever columns are needed to the listview + krConfig->setGroup( nameInKConfig() ); + + newColumn( KrDetailedViewProperties::Name ); // we always have a name + setColumnWidthMode( COLUMN(Name), QListView::Manual ); + if ( _config->readBoolEntry( "Ext Column", _ExtColumn ) ) { + newColumn( KrDetailedViewProperties::Extention ); + setColumnWidthMode( COLUMN(Extention), QListView::Manual ); + setColumnWidth( COLUMN(Extention), QFontMetrics( font() ).width( "tar.bz2" ) ); + } + if ( _config->readBoolEntry( "Mime Column", _MimeColumn ) ) { + newColumn( KrDetailedViewProperties::Mime ); + setColumnWidthMode( COLUMN(Mime), QListView::Manual ); + setColumnWidth( COLUMN(Mime), QFontMetrics( font() ).width( 'X' ) * 6 ); + } + if ( _config->readBoolEntry( "Size Column", _SizeColumn ) ) { + newColumn( KrDetailedViewProperties::Size ); + setColumnWidthMode( COLUMN(Size), QListView::Manual ); + setColumnWidth( COLUMN(Size), QFontMetrics( font() ).width( "9" ) * 10 ); + setColumnAlignment( COLUMN(Size), Qt::AlignRight ); // right-align numbers + } + if ( _config->readBoolEntry( "DateTime Column", _DateTimeColumn ) ) { + newColumn( KrDetailedViewProperties::DateTime ); + setColumnWidthMode( COLUMN(DateTime), QListView::Manual ); + //setColumnWidth( column( DateTime ), QFontMetrics( font() ).width( "99/99/99 99:99" ) ); + setColumnWidth( COLUMN(DateTime), QFontMetrics( font() ).width( KGlobal::locale() ->formatDateTime( + QDateTime ( QDate( 2099, 12, 29 ), QTime( 23, 59 ) ) ) ) + 3 ); + } + if ( _config->readBoolEntry( "Perm Column", _PermColumn ) ) { + newColumn( KrDetailedViewProperties::Permissions ); + setColumnWidthMode( COLUMN(Permissions), QListView::Manual ); + setColumnWidth( COLUMN(Permissions), QFontMetrics( font() ).width( "drwxrwxrwx" ) ); + } + if ( _config->readBoolEntry( "KrPerm Column", _KrPermColumn ) ) { + newColumn( KrDetailedViewProperties::KrPermissions ); + setColumnWidthMode( COLUMN(KrPermissions), QListView::Manual ); + setColumnWidth( COLUMN(KrPermissions), QFontMetrics( font() ).width( "RWX" ) ); + } + if ( _config->readBoolEntry( "Owner Column", _OwnerColumn ) ) { + newColumn( KrDetailedViewProperties::Owner ); + setColumnWidthMode( COLUMN(Owner), QListView::Manual ); + setColumnWidth( COLUMN(Owner), QFontMetrics( font() ).width( 'X' ) * 6 ); + } + if ( _config->readBoolEntry( "Group Column", _GroupColumn ) ) { + newColumn( KrDetailedViewProperties::Group ); + setColumnWidthMode( COLUMN(Group), QListView::Manual ); + setColumnWidth( COLUMN(Group), QFontMetrics( font() ).width( 'X' ) * 6 ); + } + + // determine basic settings for the listview + setAcceptDrops( true ); + setDragEnabled( true ); + setTooltipColumn( COLUMN(Name) ); + setDropVisualizer(false); + setDropHighlighter(true); + setSelectionModeExt( KListView::FileManager ); + setAllColumnsShowFocus( true ); + setShowSortIndicator( true ); + header() ->setStretchEnabled( true, COLUMN(Name) ); + + //---- don't enable these lines, as it causes an ugly bug with inplace renaming + //--> setItemsRenameable( true ); + //--> setRenameable( column( Name ), true ); + //------------------------------------------------------------------------------- + + header()->installEventFilter( this ); + renameLineEdit()->installEventFilter( this ); + + // allow in-place renaming + connect( renameLineEdit(), SIGNAL( done( QListViewItem *, int ) ), + this, SLOT( inplaceRenameFinished( QListViewItem*, int ) ) ); + connect( &renameTimer, SIGNAL( timeout() ), this, SLOT( renameCurrentItem() ) ); + connect( &contextMenuTimer, SIGNAL (timeout()), this, SLOT (showContextMenu())); + + connect( header(), SIGNAL(clicked(int)), this, SLOT(slotSortOrderChanged(int ))); + + setFocusPolicy( StrongFocus ); + restoreSettings(); + refreshColors(); + + CANCEL_TWO_CLICK_RENAME; +} + +KrDetailedView::~KrDetailedView() { + delete _properties; _properties = 0; + delete _operator; _operator = 0; +} + +void KrDetailedView::newColumn( KrDetailedViewProperties::ColumnType type ) { + // get the next available column + int max = KrDetailedViewProperties::Unused; + for (int i=0; icolumn[i]>=max) + max = PROPS->column[i]+1; + } + if ( max >= KrDetailedViewProperties::MAX_COLUMNS ) + perror( "KrDetailedView::newColumn() - too many columns" ); + + PROPS->column[type] = max; + addColumn( ColumnName[type], -1 ); +} + +/** + * returns the number of column which holds values of type 'type'. + * if such values are not presented in the view, -1 is returned. + */ +int KrDetailedView::column( KrDetailedViewProperties::ColumnType type ) { + return PROPS->column[type]; +} + +// if vfile passes the filter, create an item, otherwise, drop it +KrViewItem *KrDetailedView::preAddItem( vfile *vf ) { + QString size = KRpermHandler::parseSize( vf->vfile_getSize() ); + QString name = vf->vfile_getName(); + bool isDir = vf->vfile_isDir(); + if ( !isDir || ( isDir && ( _properties->filter & KrViewProperties::ApplyToDirs ) ) ) { + switch ( _properties->filter ) { + case KrViewProperties::All : + break; + case KrViewProperties::Custom : + if ( !_properties->filterMask.match( vf ) ) return 0; + break; + case KrViewProperties::Dirs: + if ( !vf->vfile_isDir() ) return 0; + break; + case KrViewProperties::Files: + if ( vf->vfile_isDir() ) return 0; + break; + case KrViewProperties::ApplyToDirs : + break; // no-op, stop compiler complaints + } + } + // passed the filter ... + return new KrDetailedViewItem( this, lastItem(), vf ); +} + +bool KrDetailedView::preDelItem(KrViewItem *item) { + /* KDE HACK START - the renaming item is not disappeared after delete */ + /* solution: we send an ESC key event to terminate the rename */ + if( item ) { + QListViewItem * viewItem = dynamic_cast( item ); + if( viewItem == currentlyRenamedItem ) { + currentlyRenamedItem = 0; + QKeyEvent escEvent( QEvent::KeyPress, Key_Escape, 27, 0 ); + QApplication::sendEvent( renameLineEdit(), &escEvent ); + } + } + /* KDE HACK END */ + return true; +} + +void KrDetailedView::addItems( vfs *v, bool addUpDir ) { + QListViewItem * item = firstChild(); + QListViewItem *currentItem = item; + QString size, name; + + // add the up-dir arrow if needed + if ( addUpDir ) { + new KrDetailedViewItem( this, ( QListViewItem* ) 0L, ( vfile* ) 0L ); + } + + // text for updating the status bar + QString statusText = QString("%1/ ").arg( v->vfs_getOrigin().fileName() ) + i18n("Directory"); + + int cnt = 0; + int cl = columnSorted(); + bool as = ascendingSort(); + setSorting( -1 ); // disable sorting + + for ( vfile * vf = v->vfs_getFirstFile(); vf != 0 ; vf = v->vfs_getNextFile() ) { + size = KRpermHandler::parseSize( vf->vfile_getSize() ); + name = vf->vfile_getName(); + bool isDir = vf->vfile_isDir(); + if ( !isDir || ( isDir && ( _properties->filter & KrViewProperties::ApplyToDirs ) ) ) { + switch ( _properties->filter ) { + case KrViewProperties::All : + break; + case KrViewProperties::Custom : + if ( !_properties->filterMask.match( vf ) ) + continue; + break; + case KrViewProperties::Dirs: + if ( !vf->vfile_isDir() ) + continue; + break; + case KrViewProperties::Files: + if ( vf->vfile_isDir() ) + continue; + break; + + case KrViewProperties::ApplyToDirs : + break; // no-op, stop compiler complaints + } + } + + KrDetailedViewItem *dvitem = new KrDetailedViewItem( this, item, vf ); + _dict.insert( vf->vfile_getName(), dvitem ); + if ( isDir ) + ++_numDirs; + else + _countSize += dvitem->VF->vfile_getSize(); + ++_count; + // if the item should be current - make it so + if ( dvitem->name() == nameToMakeCurrent() ) + { + currentItem = static_cast(dvitem); + statusText = dvitem->description(); + } + + cnt++; + } + + + // re-enable sorting + setSorting( cl, as ); + sort(); + + if ( !currentItem ) + currentItem = firstChild(); + KListView::setCurrentItem( currentItem ); + ensureItemVisible( currentItem ); + + op()->emitItemDescription( statusText ); +} + +QString KrDetailedView::getCurrentItem() const { + QListViewItem * it = currentItem(); + if ( !it ) + return QString::null; + else + return dynamic_cast( it ) ->name(); +} + +void KrDetailedView::setCurrentItem( const QString& name ) { + KrDetailedViewItem * it = dynamic_cast(_dict[ name ]); + if ( it ) + KListView::setCurrentItem( it ); +} + +void KrDetailedView::clear() { + /* KDE HACK START - the renaming item is not disappeared after clear */ + /* solution: we send an ESC key event to terminate the rename */ + if( currentlyRenamedItem ) { + currentlyRenamedItem = 0; + QKeyEvent escEvent( QEvent::KeyPress, Key_Escape, 27, 0 ); + QApplication::sendEvent( renameLineEdit(), &escEvent ); + } + /* KDE HACK END */ + + op()->emitSelectionChanged(); /* to avoid rename crash at refresh */ + KListView::clear(); + KrView::clear(); +} + +void KrDetailedView::setSortMode( KrViewProperties::SortSpec mode ) { + KrView::setSortMode(mode); // the KrViewItems will check it by themselves + bool ascending = !( mode & KrViewProperties::Descending ); + int cl = -1; + if ( mode & KrViewProperties::Name ) + cl = COLUMN( Name ); + else + if ( mode & KrViewProperties::Ext ) + cl = COLUMN( Extention ); + else + if ( mode & KrViewProperties::Size ) + cl = COLUMN( Size ); + else + if ( mode & KrViewProperties::Type ) + cl = COLUMN( Mime ); + else + if ( mode & KrViewProperties::Modified ) + cl = COLUMN( DateTime ); + else + if ( mode & KrViewProperties::Permissions ) + cl = COLUMN( Permissions ); + else + if ( mode & KrViewProperties::KrPermissions ) + cl = COLUMN( KrPermissions ); + else + if ( mode & KrViewProperties::Owner ) + cl = COLUMN( Owner ); + else + if ( mode & KrViewProperties::Group ) + cl = COLUMN( Group ); + setSorting( cl, ascending ); + KListView::sort(); +} + +void KrDetailedView::slotClicked( QListViewItem *item ) { + if ( !item ) return ; + + if ( !modifierPressed ) { + if ( singleClicked && !renameTimer.isActive() ) { + KConfig * config = KGlobal::config(); + config->setGroup( "KDE" ); + int doubleClickInterval = config->readNumEntry( "DoubleClickInterval", 400 ); + + int msecsFromLastClick = clickTime.msecsTo( QTime::currentTime() ); + + if ( msecsFromLastClick > doubleClickInterval && msecsFromLastClick < 5 * doubleClickInterval ) { + singleClicked = false; + renameTimer.start( doubleClickInterval, true ); + return ; + } + } + + CANCEL_TWO_CLICK_RENAME; + singleClicked = true; + clickTime = QTime::currentTime(); + clickedItem = item; + } +} + +void KrDetailedView::slotDoubleClicked( QListViewItem *item ) { + CANCEL_TWO_CLICK_RENAME; + if ( !item ) + return ; + QString tmp = dynamic_cast( item ) ->name(); + op()->emitExecuted(tmp); +} + +void KrDetailedView::prepareForActive() { + KrView::prepareForActive(); + setFocus(); + slotItemDescription( currentItem() ); +} + +void KrDetailedView::prepareForPassive() { + KrView::prepareForPassive(); + CANCEL_TWO_CLICK_RENAME; + if ( renameLineEdit() ->isVisible() ) + renameLineEdit() ->clearFocus(); + KConfigGroupSaver grpSvr( _config, "Look&Feel" ); + if ( _config->readBoolEntry( "New Style Quicksearch", _NewStyleQuicksearch ) ) { + if ( MAIN_VIEW ) { + if ( ACTIVE_PANEL ) { + if ( ACTIVE_PANEL->quickSearch ) { + if ( ACTIVE_PANEL->quickSearch->isShown() ) { + stopQuickSearch( 0 ); + } + } + } + } + } +} + +void KrDetailedView::slotItemDescription( QListViewItem * item ) { + KrViewItem * it = static_cast( item ); + if ( !it ) + return ; + QString desc = it->description(); + op()->emitItemDescription(desc); +} + +void KrDetailedView::handleQuickSearchEvent( QKeyEvent * e ) { + switch ( e->key() ) { + case Key_Insert: + { + QKeyEvent ev = QKeyEvent( QKeyEvent::KeyPress, Key_Space, 0, 0 ); + KListView::keyPressEvent( & ev ); + ev = QKeyEvent( QKeyEvent::KeyPress, Key_Down, 0, 0 ); + keyPressEvent( & ev ); + break; + } + case Key_Home: + { + QListView::setCurrentItem( firstChild() ); + QKeyEvent ev = QKeyEvent( QKeyEvent::KeyPress, Key_Down, 0, 0 ); + keyPressEvent( & ev ); + break; + } + case Key_End: + { + QListView::setCurrentItem( firstChild() ); + QKeyEvent ev = QKeyEvent( QKeyEvent::KeyPress, Key_Up, 0, 0 ); + keyPressEvent( & ev ); + break; + } + } +} + + +void KrDetailedView::slotCurrentChanged( QListViewItem * item ) { + CANCEL_TWO_CLICK_RENAME; + if ( !item ) + return ; + _nameToMakeCurrent = static_cast( item ) ->name(); +} + +void KrDetailedView::contentsMousePressEvent( QMouseEvent * e ) { + bool callDefaultHandler = true, processEvent = true, selectionChanged = false; + pressedItem = 0; + + QListViewItem * oldCurrent = currentItem(); + QListViewItem *newCurrent = itemAt( contentsToViewport( e->pos() ) ); + if (e->button() == RightButton) + { + if (KrSelectionMode::getSelectionHandler()->rightButtonSelects() || + (((e->state() & ShiftButton) || (e->state() & ControlButton))) && KrSelectionMode::getSelectionHandler()->shiftCtrlRightButtonSelects()) + { + if (KrSelectionMode::getSelectionHandler()->rightButtonPreservesSelection() && !(e->state() & ShiftButton) + && !(e->state() & ControlButton) && !(e->state() & AltButton)) + { + if (newCurrent) + { + if (KrSelectionMode::getSelectionHandler()->showContextMenu() >= 0) + { + swushSelects = !newCurrent->isSelected(); + lastSwushPosition = newCurrent; + } + newCurrent->setSelected(!newCurrent->isSelected()); + newCurrent->repaint(); + selectionChanged = true; + } + callDefaultHandler = false; + processEvent = false; + e->accept(); + } + + if( !KrSelectionMode::getSelectionHandler()->rightButtonPreservesSelection() && KrSelectionMode::getSelectionHandler()->showContextMenu() >= 0) + { + if( (e->state() & ControlButton) && !(e->state() & AltButton) ) + { + if( newCurrent ) + { + newCurrent->setSelected(!newCurrent->isSelected()); + newCurrent->repaint(); + selectionChanged = true; + callDefaultHandler = false; + e->accept(); + } + } + else if( !(e->state() & ControlButton) && !(e->state() & AltButton) ) + { + clearSelection(); + if( newCurrent ) + { + newCurrent->setSelected( true ); + newCurrent->repaint(); + } + selectionChanged = true; + callDefaultHandler = false; + e->accept(); + } + } + } + else + { + callDefaultHandler = false; + processEvent = false; + e->accept(); + } + } + if (e->button() == LeftButton) + { + dragStartPos = e->pos(); + if (KrSelectionMode::getSelectionHandler()->leftButtonSelects() || + (((e->state() & ShiftButton) || (e->state() & ControlButton))) && + KrSelectionMode::getSelectionHandler()->shiftCtrlLeftButtonSelects()) + { + if (KrSelectionMode::getSelectionHandler()->leftButtonPreservesSelection() && !(e->state() & ShiftButton) + && !(e->state() & ControlButton) && !(e->state() & AltButton)) + { + if (newCurrent) + { + newCurrent->setSelected(!newCurrent->isSelected()); + newCurrent->repaint(); + selectionChanged = true; + } + callDefaultHandler = false; + processEvent = false; + e->accept(); + } + } + else + { + callDefaultHandler = false; + processEvent = false; + e->accept(); + } + } + + modifierPressed = false; + if ( (e->state() & ShiftButton) || (e->state() & ControlButton) || (e->state() & AltButton) ) { + CANCEL_TWO_CLICK_RENAME; + modifierPressed = true; + } + + // stop quick search in case a mouse click occured + KConfigGroupSaver grpSvr( _config, "Look&Feel" ); + if ( _config->readBoolEntry( "New Style Quicksearch", _NewStyleQuicksearch ) ) { + if ( MAIN_VIEW ) { + if ( ACTIVE_PANEL ) { + if ( ACTIVE_PANEL->quickSearch ) { + if ( ACTIVE_PANEL->quickSearch->isShown() ) { + stopQuickSearch( 0 ); + } + } + } + } + } + + if ( !_focused ) + op()->emitNeedFocus(); + if (processEvent && ( (e->state() & ShiftButton) || (e->state() & ControlButton) || (e->state() & AltButton) ) && !KrSelectionMode::getSelectionHandler()->useQTSelection()){ + if ( oldCurrent && newCurrent && oldCurrent != newCurrent && e->state() & ShiftButton ) { + int oldPos = oldCurrent->itemPos(); + int newPos = newCurrent->itemPos(); + QListViewItem *top = 0, *bottom = 0; + if ( oldPos > newPos ) { + top = newCurrent; + bottom = oldCurrent; + } else { + top = oldCurrent; + bottom = newCurrent; + } + QListViewItemIterator it( top ); + for ( ; it.current(); ++it ) { + if ( !it.current() ->isSelected() ) { + it.current() ->setSelected( true ); + selectionChanged = true; + } + if ( it.current() == bottom ) + break; + } + QListView::setCurrentItem( newCurrent ); + callDefaultHandler = false; + } + } + + if (selectionChanged) + updateView(); // don't call triggerUpdate directly! + + // QListViewItem * i = itemAt( contentsToViewport( e->pos() ) ); + if (callDefaultHandler) + { + dragStartPos = QPoint( -1, -1 ); + + QString name = QString::null; // will the file be deleted by the mouse event? + if( newCurrent ) // save the name of the file + name = static_cast( newCurrent ) ->name(); + + KListView::contentsMousePressEvent( e ); + + if( name.isEmpty() || _dict.find( name ) == 0 ) // is the file still valid? + newCurrent = 0; // if not, don't do any crash... + } else { + // emitting the missing signals from QListView::contentsMousePressEvent(); + // the right click signal is not emitted as it is used for selection + + QPoint vp = contentsToViewport( e->pos() ); + + if( !newCurrent || ( newCurrent && newCurrent->isEnabled() ) ) { + emit pressed( pressedItem = newCurrent ); + emit pressed( newCurrent, viewport()->mapToGlobal( vp ), 0 ); + } + + emit mouseButtonPressed( e->button(), newCurrent, viewport()->mapToGlobal( vp ), 0 ); + } + + // if (i != 0) // comment in, if click sould NOT select + // setSelected(i, FALSE); + if (newCurrent) QListView::setCurrentItem(newCurrent); + + if ( ACTIVE_PANEL->quickSearch->isShown() ) { + ACTIVE_PANEL->quickSearch->hide(); + ACTIVE_PANEL->quickSearch->clear(); + krDirUp->setEnabled( true ); + } + if ( OTHER_PANEL->quickSearch->isShown() ) { + OTHER_PANEL->quickSearch->hide(); + OTHER_PANEL->quickSearch->clear(); + krDirUp->setEnabled( true ); + } +} + +void KrDetailedView::contentsMouseReleaseEvent( QMouseEvent * e ) { + if (e->button() == RightButton) + contextMenuTimer.stop(); + KListView::contentsMouseReleaseEvent( e ); + + if( pressedItem ) { + QPoint vp = contentsToViewport( e->pos() ); + QListViewItem *newCurrent = itemAt( vp ); + + if( pressedItem == newCurrent ) { + // emitting the missing signals from QListView::contentsMouseReleaseEvent(); + // the right click signal is not emitted as it is used for selection + + if( !newCurrent || ( newCurrent && newCurrent->isEnabled() ) ) { + emit clicked( newCurrent ); + emit clicked( newCurrent, viewport()->mapToGlobal( vp ), 0 ); + } + + emit mouseButtonClicked( e->button(), newCurrent, viewport()->mapToGlobal( vp ), 0 ); + } + + pressedItem = 0; + } +} + +void KrDetailedView::contentsMouseMoveEvent ( QMouseEvent * e ) { + if ( ( singleClicked || renameTimer.isActive() ) && itemAt( contentsToViewport( e->pos() ) ) != clickedItem ) + CANCEL_TWO_CLICK_RENAME; + if ( dragStartPos != QPoint( -1, -1 ) && + e->state() & LeftButton && ( dragStartPos - e->pos() ).manhattanLength() > QApplication::startDragDistance() ) + startDrag(); + if (KrSelectionMode::getSelectionHandler()->rightButtonPreservesSelection() + && KrSelectionMode::getSelectionHandler()->rightButtonSelects() + && KrSelectionMode::getSelectionHandler()->showContextMenu() >= 0 && e->state() == Qt::RightButton) + { + QListViewItem *newItem = itemAt( contentsToViewport( e->pos() ) ); + e->accept(); + if (newItem != lastSwushPosition && newItem) + { + // is the new item above or below the previous one? + QListViewItem * above = newItem; + QListViewItem * below = newItem; + for (;(above || below) && above != lastSwushPosition && below != lastSwushPosition;) + { + if (above) + above = above->itemAbove(); + if (below) + below = below->itemBelow(); + } + if (above && (above == lastSwushPosition)) + { + for (; above != newItem; above = above->itemBelow()) + above->setSelected(swushSelects); + newItem->setSelected(swushSelects); + lastSwushPosition = newItem; + updateView(); + } + else if (below && (below == lastSwushPosition)) + { + for (; below != newItem; below = below->itemAbove()) + below->setSelected(swushSelects); + newItem->setSelected(swushSelects); + lastSwushPosition = newItem; + updateView(); + } + contextMenuTimer.stop(); + } + // emitting the missing signals from QListView::contentsMouseMoveEvent(); + if( newItem ) + emit onItem( newItem ); + else + emit onViewport(); + } + else + KListView::contentsMouseMoveEvent( e ); +} + +void KrDetailedView::contentsWheelEvent( QWheelEvent * e ) { + if ( !_focused ) + op()->emitNeedFocus(); + KListView::contentsWheelEvent( e ); +} + +void KrDetailedView::handleContextMenu( QListViewItem * it, const QPoint & pos, int ) { + if ( !_focused ) + op()->emitNeedFocus(); + if ( !it ) + return ; + if ( static_cast( it ) -> + name() == ".." ) + return ; + int i = KrSelectionMode::getSelectionHandler()->showContextMenu(); + contextMenuPoint = QPoint( pos.x(), pos.y() - header() ->height() ); + if (i < 0) + showContextMenu(); + else if (i > 0) + contextMenuTimer.start(i, true); +} + +void KrDetailedView::showContextMenu() +{ + if (lastSwushPosition) + lastSwushPosition->setSelected(true); + op()->emitContextMenu( contextMenuPoint ); +} + +KrViewItem *KrDetailedView::getKrViewItemAt( const QPoint & vp ) { + return dynamic_cast( KListView::itemAt( vp ) ); +} + +bool KrDetailedView::acceptDrag( QDropEvent* ) const { + return true; +} + +QRect KrDetailedView::drawItemHighlighter(QPainter *painter, QListViewItem *item) +{ + QRect r; + if( _currDragItem && item ) { + r = itemRect(item); + + if (painter) + style().drawPrimitive(QStyle::PE_FocusRect, painter, r, colorGroup(), + QStyle::Style_FocusAtBorder, colorGroup().highlight()); + } + return r; +} + +void KrDetailedView::contentsDropEvent( QDropEvent * e ) { + e->setPoint( contentsToViewport( e->pos() ) ); + op()->emitGotDrop(e); + e->ignore(); + KListView::contentsDropEvent( e ); +} + +void KrDetailedView::contentsDragMoveEvent( QDragMoveEvent * e ) { + _currDragItem = getKrViewItemAt(contentsToViewport(e->pos())); + if( _currDragItem && !_currDragItem->VF->vfile_isDir() ) + _currDragItem = 0; + + KListView::contentsDragMoveEvent( e ); +} + +void KrDetailedView::imStartEvent(QIMEvent* e) +{ + if ( ACTIVE_PANEL->quickSearch->isShown() ) { + ACTIVE_PANEL->quickSearch->myIMStartEvent( e ); + return ; + }else { + KConfigGroupSaver grpSvr( _config, "Look&Feel" ); + if ( !_config->readBoolEntry( "New Style Quicksearch", _NewStyleQuicksearch ) ) + KListView::imStartEvent( e ); + else { + // first, show the quicksearch if its hidden + if ( ACTIVE_PANEL->quickSearch->isHidden() ) { + ACTIVE_PANEL->quickSearch->show(); + // hack: if the pressed key requires a scroll down, the selected + // item is "below" the quick search window, as the list view will + // realize its new size after the key processing. The following line + // will resize the list view immediately. + ACTIVE_PANEL->layout->activate(); + // second, we need to disable the dirup action - hack! + krDirUp->setEnabled( false ); + } + // now, send the key to the quicksearch + ACTIVE_PANEL->quickSearch->myIMStartEvent( e ); + } + } +} + +void KrDetailedView::imEndEvent(QIMEvent* e) +{ + if ( ACTIVE_PANEL->quickSearch->isShown() ) { + ACTIVE_PANEL->quickSearch->myIMEndEvent( e ); + return ; + } +} + +void KrDetailedView::imComposeEvent(QIMEvent* e) +{ + if ( ACTIVE_PANEL->quickSearch->isShown() ) { + ACTIVE_PANEL->quickSearch->myIMComposeEvent( e ); + return ; + } +} + +// TODO: for brief mode, move as much of this as possible to the viewOperator +void KrDetailedView::keyPressEvent( QKeyEvent * e ) { + if ( !e || !firstChild() ) + return ; // subclass bug + if ( ACTIVE_PANEL->quickSearch->isShown() ) { + ACTIVE_PANEL->quickSearch->myKeyPressEvent( e ); + return ; + } + switch ( e->key() ) { + case Key_Up : + if ( e->state() == ControlButton ) { // let the panel handle it - jump to the Location Bar + e->ignore(); + break; + } else if (!KrSelectionMode::getSelectionHandler()->useQTSelection()) { + QListViewItem * i = currentItem(); + if ( !i ) break; + if ( e->state() == ShiftButton ) setSelected( i, !i->isSelected() ); + i = i->itemAbove(); + if ( i ) { + QListView::setCurrentItem( i ); + QListView::ensureItemVisible( i ); + } + } else KListView::keyPressEvent(e); + break; + case Key_Down : + if ( e->state() == ControlButton || e->state() == ( ControlButton | ShiftButton ) ) { // let the panel handle it - jump to command line + e->ignore(); + break; + } else if (!KrSelectionMode::getSelectionHandler()->useQTSelection()){ + QListViewItem * i = currentItem(); + if ( !i ) break; + if ( e->state() == ShiftButton ) setSelected( i, !i->isSelected() ); + i = i->itemBelow(); + if ( i ) {QListView::setCurrentItem( i ); QListView::ensureItemVisible( i ); } + } else KListView::keyPressEvent(e); + break; + case Key_Next: if (!KrSelectionMode::getSelectionHandler()->useQTSelection()){ + QListViewItem * i = currentItem(), *j; + if ( !i ) break; + QRect r( itemRect( i ) ); + if ( !r.height() ) break; + for ( int page = visibleHeight() / r.height() - 1; page > 0 && ( j = i->itemBelow() ); --page ) + i = j; + if ( i ) {QListView::setCurrentItem( i ); QListView::ensureItemVisible( i ); } + } else KListView::keyPressEvent(e); + break; + case Key_Prior: if (!KrSelectionMode::getSelectionHandler()->useQTSelection()){ + QListViewItem * i = currentItem(), *j; + if ( !i ) break; + QRect r( itemRect( i ) ); + if ( !r.height() ) break; + for ( int page = visibleHeight() / r.height() - 1; page > 0 && ( j = i->itemAbove() ); --page ) + i = j; + if ( i ) {QListView::setCurrentItem( i ); QListView::ensureItemVisible( i ); } + } else KListView::keyPressEvent(e); + break; + case Key_Home: if (!KrSelectionMode::getSelectionHandler()->useQTSelection()){ + if ( e->state() & ShiftButton ) /* Shift+Home */ + { + clearSelection(); + KListView::keyPressEvent( e ); + op()->emitSelectionChanged(); + triggerUpdate(); + break; + } else { + QListViewItem * i = firstChild(); + if ( i ) {QListView::setCurrentItem( i ); QListView::ensureItemVisible( i ); } + } + } else KListView::keyPressEvent(e); + break; + case Key_End: if (!KrSelectionMode::getSelectionHandler()->useQTSelection()){ + if ( e->state() & ShiftButton ) /* Shift+End */ + { + clearSelection(); + KListView::keyPressEvent( e ); + op()->emitSelectionChanged(); + triggerUpdate(); + break; + } else { + QListViewItem *i = firstChild(), *j; + while ( ( j = i->nextSibling() ) ) + i = j; + while ( ( j = i->itemBelow() ) ) + i = j; + if ( i ) {QListView::setCurrentItem( i ); QListView::ensureItemVisible( i ); } + break; + } + } else KListView::keyPressEvent(e); + break; + case Key_Enter : + case Key_Return : { + if ( e->state() & ControlButton ) // let the panel handle it + e->ignore(); + else { + KrViewItem * i = getCurrentKrViewItem(); + QString tmp = i->name(); + op()->emitExecuted(tmp); + } + break; + } + case Key_QuoteLeft : // Terminal Emulator bugfix + if ( e->state() == ControlButton ) { // let the panel handle it + e->ignore(); + break; + } else { // a normal click - do a lynx-like moving thing + SLOTS->home(); // ask krusader to move up a directory + return ; // safety + } + break; + case Key_Right : + if ( e->state() == ControlButton || e->state() == ShiftButton ) { // let the panel handle it + e->ignore(); + break; + } else { // just a normal click - do a lynx-like moving thing + KrViewItem *i = getCurrentKrViewItem(); + if ( i->name() == ".." ) { // if clicking on the ".." entry + SLOTS->dirUp(); // ask krusader to move up a directory + return ; + } + if ( i->VF->vfile_isDir() ) { // we create a return-pressed event, + QString tmp = i->name(); + op()->emitExecuted(tmp); // thereby emulating a chdir + } else if( i->VF->vfile_getUrl().isLocalFile() ) { + bool encrypted; + KURL url = i->VF->vfile_getUrl(); + QString mime = ((vfile *)(i->VF))->vfile_getMime(); + QString type = KRarcHandler::getType( encrypted, url.path(), mime, false ); + + if( KRarcHandler::arcSupported( type ) ) { + KURL url = i->VF->vfile_getUrl(); + if( type == "-tar" || type == "-tgz" || type == "-tbz" ) + url.setProtocol( "tar" ); + else + url.setProtocol( "krarc" ); + ACTIVE_FUNC->openUrl( url ); + } + } + return ; // safety + } + case Key_Backspace : // Terminal Emulator bugfix + case Key_Left : + if ( e->state() == ControlButton || e->state() == ShiftButton ) { // let the panel handle it + e->ignore(); + break; + } else { // a normal click - do a lynx-like moving thing + SLOTS->dirUp(); // ask krusader to move up a directory + return ; // safety + } + //case Key_Up : + //KListView::keyPressEvent( e ); + //break; +/*#ifndef _newSelectionHandling + case Key_Down : + if ( e->state() == ControlButton ) { // let the panel handle it + e->ignore(); + break; + } else + KListView::keyPressEvent( e ); + break; +#endif*/ + case Key_Delete : // kill file + SLOTS->deleteFiles( e->state() == ShiftButton || e->state() == ControlButton ); + + break ; + case Key_Insert : { + if (KrSelectionMode::getSelectionHandler()->insertMovesDown()) + KListView::keyPressEvent( e ); + else + { + QKeyEvent ev = QKeyEvent( QKeyEvent::KeyPress, Key_Space, 0, 0 ); + KListView::keyPressEvent( & ev ); + } + break ; + } + case Key_Space : { + KrDetailedViewItem * viewItem = static_cast ( getCurrentKrViewItem() ); + if ( !viewItem || viewItem->name() == ".." ) { // wrong type, just mark(unmark it) + if (KrSelectionMode::getSelectionHandler()->spaceMovesDown()) + { + QKeyEvent ev = QKeyEvent( QKeyEvent::KeyPress, Key_Insert, 0, 0 ); + KListView::keyPressEvent( & ev ); + } + else + KListView::keyPressEvent( e ); + break ; + } + if ( viewItem->VF->vfile_isDir() && viewItem->VF->vfile_getSize() <= 0 && + KrSelectionMode::getSelectionHandler()->spaceCalculatesDiskSpace()) { + // + // NOTE: this is buggy incase somewhere down in the folder we're calculating, + // there's a folder we can't enter (permissions). in that case, the returned + // size will not be correct. + // + KIO::filesize_t totalSize = 0; + unsigned long totalFiles = 0, totalDirs = 0; + QStringList items; + items.push_back( viewItem->name() ); + if ( ACTIVE_PANEL->func->calcSpace( items, totalSize, totalFiles, totalDirs ) ) { + // did we succeed to calcSpace? we'll fail if we don't have permissions + if ( totalSize == 0 ) { // just mark it, and bail out + goto mark; + } + viewItem->setSize( totalSize ); + viewItem->repaintItem(); + } + } +mark: if (KrSelectionMode::getSelectionHandler()->spaceMovesDown()) + { + QKeyEvent ev = QKeyEvent( QKeyEvent::KeyPress, Key_Insert, 0, 0 ); + KListView::keyPressEvent( & ev ); + } + else + KListView::keyPressEvent( e ); + } + break; + case Key_A : // mark all + if ( e->state() == ControlButton ) { + KListView::keyPressEvent( e ); + updateView(); + break; + } + default: + if ( e->key() == Key_Escape ) { + QListView::keyPressEvent( e ); return ; // otherwise the selection gets lost??!?? + } + // if the key is A..Z or 1..0 do quick search otherwise... + if ( e->text().length() > 0 && e->text() [ 0 ].isPrint() ) // better choice. Otherwise non-ascii characters like can not be the first character of a filename + /* if ( ( e->key() >= Key_A && e->key() <= Key_Z ) || + ( e->key() >= Key_0 && e->key() <= Key_9 ) || + ( e->key() == Key_Backspace ) || + ( e->key() == Key_Down ) || + ( e->key() == Key_Period ) ) */{ + // are we doing quicksearch? if not, send keys to panel + //if ( _config->readBoolEntry( "Do Quicksearch", _DoQuicksearch ) ) { + // are we using krusader's classic quicksearch, or wincmd style? + { + KConfigGroupSaver grpSvr( _config, "Look&Feel" ); + if ( !_config->readBoolEntry( "New Style Quicksearch", _NewStyleQuicksearch ) ) + KListView::keyPressEvent( e ); + else { + // first, show the quicksearch if its hidden + if ( ACTIVE_PANEL->quickSearch->isHidden() ) { + ACTIVE_PANEL->quickSearch->show(); + // hack: if the pressed key requires a scroll down, the selected + // item is "below" the quick search window, as the list view will + // realize its new size after the key processing. The following line + // will resize the list view immediately. + ACTIVE_PANEL->layout->activate(); + // second, we need to disable the dirup action - hack! + krDirUp->setEnabled( false ); + } + // now, send the key to the quicksearch + ACTIVE_PANEL->quickSearch->myKeyPressEvent( e ); + } + } + //} else + // e->ignore(); // send to panel + } else { + if ( ACTIVE_PANEL->quickSearch->isShown() ) { + ACTIVE_PANEL->quickSearch->hide(); + ACTIVE_PANEL->quickSearch->clear(); + krDirUp->setEnabled( true ); + } + KListView::keyPressEvent( e ); + } + } + // emit the new item description + slotItemDescription( currentItem() ); // actually send the QListViewItem +} + +// overridden to make sure EXTENTION won't be lost during rename +void KrDetailedView::rename( QListViewItem * item, int c ) { + // do we have an EXT column? if so, handle differently: + // copy the contents of the EXT column over to the name + if ( COLUMN( Extention ) != -1 ) { + item->setText( COLUMN( Name ), static_cast( item ) ->name() ); + item->setText( COLUMN( Extention ), QString::null ); + repaintItem( item ); + } + + currentlyRenamedItem = item; + renameLineEdit()->setBackgroundMode(Qt::FixedColor); + renameLineEdit()->setPaletteBackgroundColor(Qt::white); + renameLineEdit()->setPaletteForegroundColor(Qt::black); + KListView::rename( item, c ); + renameLineEdit() ->selectAll(); +} + +void KrDetailedView::renameCurrentItem() { + int c; + QString newName, fileName; + + // handle inplace renaming, if possible + + KrDetailedViewItem *it = static_cast(getCurrentKrViewItem()); + if ( it ) + fileName = it->name(); + else + return ; // quit if no current item available + // don't allow anyone to rename .. + if ( fileName == ".." ) + return ; + + // determine which column is inplace renameable + for ( c = 0; c < columns(); c++ ) + if ( isRenameable( c ) ) + break; // one MUST be renamable + if ( !isRenameable( c ) ) + c = -1; // failsafe + + if ( c >= 0 ) { + rename( static_cast( it ), c ); + // if applicable, select only the name without extension + KConfigGroupSaver svr(krConfig,"Look&Feel"); + if (!krConfig->readBoolEntry("Rename Selects Extension", true)) { + if (it->hasExtension() && !it->VF->vfile_isDir() ) + renameLineEdit()->setSelection(0, it->name().findRev(it->extension())-1); + } + // signal will be emited when renaming is done, and finalization + // will occur in inplaceRenameFinished() + } else { + // do this in case inplace renaming is disabled + // this actually does the good old dialog box rename + KrView::renameCurrentItem(); + } +} + +void KrDetailedView::inplaceRenameFinished( QListViewItem * it, int ) { + if( currentlyRenamedItem == 0 ) + return; + + if ( !it ) { // major failure - call developers + krOut << "Major failure at inplaceRenameFinished(): item is null" << endl; + return; + } + + if( COLUMN( Extention ) != -1 && !currentlyRenamedItem ) + return; /* does the event filter restored the original state? */ + + // check if the item was indeed renamed + bool restoreView = false; + if ( it->text( COLUMN( Name ) ) != static_cast( it ) ->name() ) { // was renamed + op()->emitRenameItem( static_cast( it ) ->name(), it->text( COLUMN( Name ) ) ); + } else restoreView = true; + + // restore the view always! if the file was indeed renamed, we'll get a signal from the vfs about + // it, and update the view when needed +#if 0 + if ( COLUMN( Extention ) != -1 && restoreView ) { // nothing happened, restore the view (if needed) +#endif + + QString ext, name = static_cast( it ) ->name(); + if ( !static_cast( it ) ->VF->vfile_isDir() && COLUMN( Extention ) != -1 ) { + ext = static_cast( it ) ->extension(); + name = static_cast( it ) ->name( false ); + } + it->setText( COLUMN( Name ), name ); + it->setText( COLUMN( Extention ), ext ); + repaintItem( it ); +#if 0 + } +#endif + + setFocus(); + + currentlyRenamedItem = 0; +} + +// TODO: move the whole quicksearch mess out of here and into krview +void KrDetailedView::quickSearch( const QString & str, int direction ) { + KrViewItem * item = getCurrentKrViewItem(); + if (!item) + return; + KConfigGroupSaver grpSvr( _config, "Look&Feel" ); + bool caseSensitive = _config->readBoolEntry( "Case Sensitive Quicksearch", _CaseSensitiveQuicksearch ); + if ( !direction ) { + if ( caseSensitive ? item->name().startsWith( str ) : item->name().lower().startsWith( str.lower() ) ) + return ; + direction = 1; + } + KrViewItem * startItem = item; + while ( true ) { + item = ( direction > 0 ) ? getNext( item ) : getPrev( item ); + if ( !item ) + item = ( direction > 0 ) ? getFirst() : getLast(); + if ( item == startItem ) + return ; + if ( caseSensitive ? item->name().startsWith( str ) : item->name().lower().startsWith( str.lower() ) ) { + setCurrentItem( item->name() ); + makeItemVisible( item ); + return ; + } + } +} + +void KrDetailedView::stopQuickSearch( QKeyEvent * e ) { + if( ACTIVE_PANEL && ACTIVE_PANEL->quickSearch ) { + ACTIVE_PANEL->quickSearch->hide(); + ACTIVE_PANEL->quickSearch->clear(); + krDirUp->setEnabled( true ); + if ( e ) + keyPressEvent( e ); + } +} + +// internal: converts signal from qlistview to krview +void KrDetailedView::setNameToMakeCurrent( QListViewItem * it ) { + if (!it) return; + KrView::setNameToMakeCurrent( static_cast( it ) ->name() ); +} + +void KrDetailedView::slotMouseClicked( int button, QListViewItem * item, const QPoint&, int ) { + pressedItem = 0; // if the signals are emitted, don't emit twice at contentsMouseReleaseEvent + if ( button == Qt::MidButton ) + emit middleButtonClicked( dynamic_cast( item ) ); +} + +void KrDetailedView::refreshColors() { + krConfig->setGroup("Colors"); + bool kdeDefault = krConfig->readBoolEntry("KDE Default"); + bool alternateBackgroundEnabled = krConfig->readBoolEntry("Enable Alternate Background"); + if ( !kdeDefault ) { + // KDE default is not choosen: set the background color (as this paints the empty areas) and the alternate color + bool isActive = hasFocus(); + if ( MAIN_VIEW && ACTIVE_PANEL && ACTIVE_PANEL->view ) + isActive = ( static_cast( this ) == ACTIVE_PANEL->view ); + QColorGroup cg; + KrColorCache::getColorCache().getColors(cg, KrColorItemType(KrColorItemType::File, false, isActive, false, false)); + setPaletteBackgroundColor( cg.background() ); + + KrColorCache::getColorCache().getColors(cg, KrColorItemType(KrColorItemType::File, true, isActive, false, false)); + setAlternateBackground( cg.background() ); + } else { + // KDE default is choosen: set back the background color + setPaletteBackgroundColor( KGlobalSettings::baseColor() ); + // Set the alternate color to its default or to an invalid color, to turn alternate the background off. + setAlternateBackground( alternateBackgroundEnabled ? KGlobalSettings::alternateBackgroundColor() : QColor() ); + } +} + +bool KrDetailedView::event( QEvent *e ) { + modifierPressed = false; + + switch ( e->type() ) { + case QEvent::Timer: + case QEvent::MouseMove: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + break; + default: + CANCEL_TWO_CLICK_RENAME; + } + return KListView::event( e ); +} + +bool KrDetailedView::eventFilter( QObject * watched, QEvent * e ) +{ + if( watched == renameLineEdit() ) + { + if( currentlyRenamedItem && e->type() == QEvent::Hide ) + { + /* checking if the currentlyRenamedItem pointer is valid (vfs_refresh can delete this item) */ + for( QListViewItem *it = firstChild(); it; it = it->nextSibling() ) + if( it == currentlyRenamedItem ) + { + if ( it->text( COLUMN( Name ) ) == dynamic_cast( it ) ->name() && COLUMN( Extention ) != -1 ) + inplaceRenameFinished( it, COLUMN( Name ) ); + break; + } + } + return FALSE; + } + else if( watched == header() ) + { + if( e->type() == QEvent::MouseButtonPress && ((QMouseEvent *)e )->button() == Qt::RightButton ) + { + selectColumns(); + return TRUE; + } + return FALSE; + } + return KListView::eventFilter( watched, e ); +} + +void KrDetailedView::makeItemVisible( const KrViewItem *item ) { +// qApp->processEvents(); // Please don't remove the comment. Causes crash if it is inserted! + ensureItemVisible( static_cast( item ) ); +} + +void KrDetailedView::initOperator() { + _operator = new KrViewOperator(this, this); + // klistview emits selection changed, so chain them to operator + connect(this, SIGNAL(selectionChanged()), _operator, SIGNAL(selectionChanged())); +} + +void KrDetailedView::initProperties() { + _properties = new KrDetailedViewProperties; + KConfigGroupSaver grpSvr( _config, "Look&Feel" ); + for (int i=0; icolumn[i]=-1; + PROPS->displayIcons = _config->readBoolEntry( "With Icons", _WithIcons ); + bool dirsByNameAlways = _config->readBoolEntry("Always sort dirs by name", false); + PROPS->sortMode = static_cast( KrViewProperties::Name | + KrViewProperties::Descending | KrViewProperties::DirsFirst | + (dirsByNameAlways ? KrViewProperties::AlwaysSortDirsByName : 0) ); + PROPS->numericPermissions = _config->readBoolEntry("Numeric permissions", _NumericPermissions); + if ( !_config->readBoolEntry( "Case Sensative Sort", _CaseSensativeSort ) ) + PROPS->sortMode = static_cast( _properties->sortMode | + KrViewProperties::IgnoreCase ); + PROPS->humanReadableSize = krConfig->readBoolEntry("Human Readable Size", _HumanReadableSize); + PROPS->localeAwareCompareIsCaseSensitive = QString( "a" ).localeAwareCompare( "B" ) > 0; // see KDE bug #40131 + QStringList defaultAtomicExtensions; + defaultAtomicExtensions += ".tar.gz"; + defaultAtomicExtensions += ".tar.bz2"; + defaultAtomicExtensions += ".moc.cpp"; + QStringList atomicExtensions = krConfig->readListEntry("Atomic Extensions", defaultAtomicExtensions); + for (QStringList::iterator i = atomicExtensions.begin(); i != atomicExtensions.end(); ) + { + QString & ext = *i; + ext = ext.stripWhiteSpace(); + if (!ext.length()) + { + i = atomicExtensions.remove(i); + continue; + } + if (!ext.startsWith(".")) + ext.insert(0, '.'); + ++i; + } + PROPS->atomicExtensions = atomicExtensions; +} + +void KrDetailedView::selectColumns() +{ + KPopupMenu popup( this ); + popup.insertTitle( i18n("Columns")); + + bool refresh = false; + + bool hasExtention = COLUMN( Extention ) != -1; + bool hasMime = COLUMN( Mime ) != -1; + bool hasSize = COLUMN( Size ) != -1; + bool hasDate = COLUMN( DateTime ) != -1; + bool hasPerms = COLUMN( Permissions ) != -1; + bool hasKrPerms = COLUMN( KrPermissions ) != -1; + bool hasOwner = COLUMN( Owner ) != -1; + bool hasGroup = COLUMN( Group ) != -1; + + popup.insertItem( i18n( "Ext" ), COLUMN_POPUP_IDS + KrDetailedViewProperties::Extention ); + popup.setItemChecked( COLUMN_POPUP_IDS + KrDetailedViewProperties::Extention, hasExtention ); + + popup.insertItem( i18n( "Type" ), COLUMN_POPUP_IDS + KrDetailedViewProperties::Mime ); + popup.setItemChecked( COLUMN_POPUP_IDS + KrDetailedViewProperties::Mime, hasMime ); + + popup.insertItem( i18n( "Size" ), COLUMN_POPUP_IDS + KrDetailedViewProperties::Size ); + popup.setItemChecked( COLUMN_POPUP_IDS + KrDetailedViewProperties::Size, hasSize ); + + popup.insertItem( i18n( "Modified" ), COLUMN_POPUP_IDS + KrDetailedViewProperties::DateTime ); + popup.setItemChecked( COLUMN_POPUP_IDS + KrDetailedViewProperties::DateTime, hasDate ); + + popup.insertItem( i18n( "Perms" ), COLUMN_POPUP_IDS + KrDetailedViewProperties::Permissions ); + popup.setItemChecked( COLUMN_POPUP_IDS + KrDetailedViewProperties::Permissions, hasPerms ); + + popup.insertItem( i18n( "rwx" ), COLUMN_POPUP_IDS + KrDetailedViewProperties::KrPermissions ); + popup.setItemChecked( COLUMN_POPUP_IDS + KrDetailedViewProperties::KrPermissions, hasKrPerms ); + + popup.insertItem( i18n( "Owner" ), COLUMN_POPUP_IDS + KrDetailedViewProperties::Owner ); + popup.setItemChecked( COLUMN_POPUP_IDS + KrDetailedViewProperties::Owner, hasOwner ); + + popup.insertItem( i18n( "Group" ), COLUMN_POPUP_IDS + KrDetailedViewProperties::Group ); + popup.setItemChecked( COLUMN_POPUP_IDS + KrDetailedViewProperties::Group, hasGroup ); + + int result=popup.exec(QCursor::pos()); + + krConfig->setGroup( nameInKConfig() ); + + switch( result - COLUMN_POPUP_IDS ) + { + case KrDetailedViewProperties::Extention: + krConfig->writeEntry( "Ext Column", !hasExtention ); + refresh = true; + break; + case KrDetailedViewProperties::Mime: + krConfig->writeEntry( "Mime Column", !hasMime ); + refresh = true; + break; + case KrDetailedViewProperties::Size: + krConfig->writeEntry( "Size Column", !hasSize ); + refresh = true; + break; + case KrDetailedViewProperties::DateTime: + krConfig->writeEntry( "DateTime Column", !hasDate ); + refresh = true; + break; + case KrDetailedViewProperties::Permissions: + krConfig->writeEntry( "Perm Column", !hasPerms ); + refresh = true; + break; + case KrDetailedViewProperties::KrPermissions: + krConfig->writeEntry( "KrPerm Column", !hasKrPerms ); + refresh = true; + break; + case KrDetailedViewProperties::Owner: + krConfig->writeEntry( "Owner Column", !hasOwner ); + refresh = true; + break; + case KrDetailedViewProperties::Group: + krConfig->writeEntry( "Group Column", !hasGroup ); + refresh = true; + break; + } + + if( refresh ) + { + PanelManager *p = ACTIVE_PANEL->view == this ? ACTIVE_MNG : OTHER_MNG; + QTimer::singleShot( 0, p, SLOT( slotRecreatePanels() ) ); + } +} + +void KrDetailedView::sortOrderChanged(int) { + ensureItemVisible(currentItem()); +} + +void KrDetailedView::updateView() { + triggerUpdate(); + op()->emitSelectionChanged(); +} + +void KrDetailedView::updateItem(KrViewItem* item) { + dynamic_cast(item)->repaintItem(); +} + +void KrDetailedView::slotRightButtonPressed(QListViewItem*, const QPoint& point, int) { + op()->emitEmptyContextMenu(point); +} + +// hack: this needs to be done in a more cross-view way +void KrDetailedView::slotSortOrderChanged(int col) { + // map the column to a sort specification + KrViewProperties::SortSpec sp = KrViewProperties::Name; + int i; + for (i = 0; i < KrDetailedViewProperties::MAX_COLUMNS; ++i) { + if (PROPS->column[i] == col) break; + } + switch (i) { + case KrDetailedViewProperties::Name: + sp = KrViewProperties::Name; break; + case KrDetailedViewProperties::Extention: + sp = KrViewProperties::Ext; break; + case KrDetailedViewProperties::Mime: + sp = KrViewProperties::Type; break; + case KrDetailedViewProperties::Size: + sp = KrViewProperties::Size; break; + case KrDetailedViewProperties::DateTime: + sp = KrViewProperties::Modified; break; + case KrDetailedViewProperties::Permissions: + sp = KrViewProperties::Permissions; break; + case KrDetailedViewProperties::KrPermissions: + sp = KrViewProperties::KrPermissions; break; + case KrDetailedViewProperties::Owner: + sp = KrViewProperties::Owner; break; + case KrDetailedViewProperties::Group: + sp = KrViewProperties::Group; break; + default: qFatal("slotSortOrderChanged: unknown column"); + } + if (sortMode() & KrViewProperties::DirsFirst) + sp = static_cast(sp | KrViewProperties::DirsFirst); + if (sortMode() & KrViewProperties::IgnoreCase) + sp = static_cast(sp | KrViewProperties::IgnoreCase); + if (sortMode() & KrViewProperties::Descending) + sp = static_cast(sp | KrViewProperties::Descending); + if (sortMode() & KrViewProperties::AlwaysSortDirsByName) + sp = static_cast(sp | KrViewProperties::AlwaysSortDirsByName); + // fix the ascending/decending stuff + if (sortMode() == sp) { + if (sp & KrViewProperties::Descending) + sp = static_cast(sp &~ KrViewProperties::Descending); + else sp = static_cast(sp | KrViewProperties::Descending); + } + PROPS->sortMode = sp; + + if( !_focused ) + op()->emitNeedFocus(); +} + +#include "krdetailedview.moc" diff --git a/krusader/Panel/krdetailedview.h b/krusader/Panel/krdetailedview.h new file mode 100644 index 0000000..f0616fb --- /dev/null +++ b/krusader/Panel/krdetailedview.h @@ -0,0 +1,180 @@ +/*************************************************************************** + krdetailedview.h + ------------------- + copyright : (C) 2000-2002 by Shie Erlich & Rafi Yanai + 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 KRDETAILEDVIEW_H +#define KRDETAILEDVIEW_H + +#include +#include +#include +#include +#include +#include +#include "krview.h" +#include "krviewitem.h" + +// extends KrViewProperties to add detailedview-only properties +class KrDetailedViewProperties: public KrViewProperties { +public: + enum ColumnType { Unused = -1, Name = 0x0, Extention = 0x1, Mime = 0x2, Size = 0x3, DateTime = 0x4, + Permissions = 0x5, KrPermissions = 0x6, Owner = 0x7, Group = 0x8 }; + static const int MAX_COLUMNS = 9; + int column[ MAX_COLUMNS ]; // column[ColumnType] contains the number of the requested column. + // This is used by column() and whenever item uses text() or setText() + bool numericPermissions; // show full permission column as octal numbers + + KrDetailedViewProperties() { + for ( int i = 0; i < MAX_COLUMNS; i++ ) column[i] = Unused; + filter = KrViewProperties::All; + filterMask = KRQuery( "*" ); + } +}; + + +class QDragMoveEvent; +class KrRenameTimerObject; +class ListPanel; +class KrDetailedViewItem; + +/** + * KrDetailedView implements everthing and anything regarding a detailed view in a filemananger. + * IT MUST USE KrViewItem as the children to it's *KListView. KrDetailedView and KrViewItem are + * tightly coupled and the view will not work with other kinds of items. + * Apart from this, the view is self-reliant and you can use the vast interface to get whatever + * information is necessery from it. + */ +class KrDetailedView : public KListView, public KrView { + Q_OBJECT + friend class KrDetailedViewItem; + +public: + KrDetailedView( QWidget *parent, bool &left, KConfig *cfg = krConfig, const char *name = 0 ); + virtual ~KrDetailedView(); + virtual int column( KrDetailedViewProperties::ColumnType type ); + virtual inline KrViewItem *getFirst() { return dynamic_cast( firstChild() ); } + virtual inline KrViewItem *getLast() { return dynamic_cast( lastChild() ); } + virtual inline KrViewItem *getNext( KrViewItem *current ) { return dynamic_cast( dynamic_cast( current ) ->itemBelow() ); } + virtual inline KrViewItem *getPrev( KrViewItem *current ) { return dynamic_cast( dynamic_cast( current ) ->itemAbove() ); } + virtual inline KrViewItem *getCurrentKrViewItem() { return dynamic_cast( currentItem() ); } + virtual KrViewItem *getKrViewItemAt( const QPoint &vp ); + virtual inline KrViewItem *findItemByName( const QString &name ) { return dynamic_cast( findItem( name, 0 ) ); } + virtual void addItems( vfs *v, bool addUpDir = true ); + virtual QString getCurrentItem() const; + virtual void makeItemVisible( const KrViewItem *item ); + virtual void setCurrentItem( const QString& name ); + virtual void updateView(); + virtual void updateItem(KrViewItem* item); + virtual void clear(); + virtual void sort() { KListView::sort(); } + virtual void setSortMode( KrViewProperties::SortSpec mode ); + virtual void prepareForActive(); + virtual void prepareForPassive(); + virtual inline void saveSettings() { KListView::saveLayout( _config, nameInKConfig() ); } + virtual inline void restoreSettings() { KListView::restoreLayout( _config, nameInKConfig() ); } + +signals: + void middleButtonClicked( KrViewItem *item ); + void currentChanged( KrViewItem *item ); + +protected: + virtual void setup(); + virtual void initProperties(); + virtual void initOperator(); + virtual KrViewItem *preAddItem(vfile *vf); + virtual bool preDelItem(KrViewItem *item); + + void newColumn( KrDetailedViewProperties::ColumnType type ); + void selectColumns(); + + virtual void keyPressEvent( QKeyEvent *e ); + virtual void imStartEvent( QIMEvent* e ); + virtual void imEndEvent( QIMEvent *e ); + virtual void imComposeEvent( QIMEvent *e ); + virtual void contentsMousePressEvent( QMouseEvent *e ); + virtual void contentsMouseReleaseEvent (QMouseEvent *e); + virtual void contentsMouseMoveEvent ( QMouseEvent * e ); + virtual void contentsWheelEvent( QWheelEvent *e ); + virtual bool acceptDrag( QDropEvent* e ) const; + virtual void contentsDropEvent( QDropEvent *e ); + virtual void contentsDragMoveEvent( QDragMoveEvent *e ); + virtual QRect drawItemHighlighter(QPainter *painter, QListViewItem *item); + virtual void startDrag() { op()->startDrag(); } + virtual bool event( QEvent *e ); + virtual bool eventFilter( QObject * watched, QEvent * e ); + +protected slots: + void rename( QListViewItem *item, int c ); + void slotClicked( QListViewItem *item ); + void slotDoubleClicked( QListViewItem *item ); + void slotItemDescription( QListViewItem *item ); + void slotCurrentChanged( QListViewItem *item ); + void handleContextMenu( QListViewItem*, const QPoint&, int ); + virtual void renameCurrentItem(); + virtual void showContextMenu( ); + void inplaceRenameFinished( QListViewItem *it, int col ); + void setNameToMakeCurrent( QListViewItem *it ); + void sortOrderChanged(int); + void slotRightButtonPressed(QListViewItem*, const QPoint& point, int); + void slotSortOrderChanged(int col); + void transformCurrentChanged( QListViewItem * item ) { emit currentChanged( dynamic_cast(item ) ); } + + /** + * used internally to produce the signal middleButtonClicked() + */ + void slotMouseClicked( int button, QListViewItem * item, const QPoint & pos, int c ); + inline void slotExecuted( QListViewItem* i ) { + QString tmp = dynamic_cast( i ) ->name(); + op()->emitExecuted( tmp ); + } + +public slots: + void refreshColors(); + void quickSearch( const QString &, int = 0 ); + void stopQuickSearch( QKeyEvent* ); + void handleQuickSearchEvent( QKeyEvent* ); + +private: + static QString ColumnName[ KrDetailedViewProperties::MAX_COLUMNS ]; + bool swushSelects; + QPoint dragStartPos; + QListViewItem *lastSwushPosition; + bool caseSensitiveSort; + KrViewItem *_currDragItem; + bool singleClicked; + bool modifierPressed; + QTime clickTime; + QListViewItem *clickedItem; + QTimer renameTimer; + QTimer contextMenuTimer; + QPoint contextMenuPoint; + QListViewItem *currentlyRenamedItem; + QListViewItem *pressedItem; +}; + +#endif /* KRDETAILEDVIEW_H */ diff --git a/krusader/Panel/krdetailedviewitem.cpp b/krusader/Panel/krdetailedviewitem.cpp new file mode 100644 index 0000000..4d37854 --- /dev/null +++ b/krusader/Panel/krdetailedviewitem.cpp @@ -0,0 +1,313 @@ +/*************************************************************************** + krdetailedviewitem.cpp + ------------------- + copyright : (C) 2000 by Shie Erlich & Rafi Yanai + 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 "../krusader.h" +#include "../defaults.h" +#include "../kicons.h" +#include "../krusaderview.h" +#include "krdetailedviewitem.h" +#include "krdetailedview.h" +#include "krcolorcache.h" +#include "listpanel.h" +#include "../VFS/krpermhandler.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define COLUMN(X) static_cast(_viewProperties)-> \ + column[ KrDetailedViewProperties::X ] +#define PROPS static_cast(_viewProperties) +#define PERM_BITMASK (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) +#define VF getVfile() + +#ifdef FASTER +int KrDetailedViewItem::expHeight = 0; +#endif // FASTER + +KrDetailedViewItem::KrDetailedViewItem(KrDetailedView *parent, QListViewItem *after, vfile *vf): + KListViewItem(parent, after), KrViewItem(vf, parent->properties()) { +#ifdef FASTER + initiated = false; + // get the expected height of an item - should be done only once + if (expHeight == 0) { + KConfigGroupSaver svr(krConfig, "Look&Feel"); + expHeight = 2 + (krConfig->readEntry("Filelist Icon Size",_FilelistIconSize)).toInt(); + } + +#endif + // there's a special case, where if _vf is null, then we've got the ".." (updir) item + // in that case, create a special vfile for that item, and delete it, if needed + if (!_vf) { + dummyVfile = true; + _vf = new vfile("..", 0, "drw-r--r--", 0, false, 0, 0, QString::null, QString::null, 0); + + setText(COLUMN(Name), ".."); + setText(COLUMN(Size), i18n("") ); + if ( PROPS->displayIcons ) + setPixmap( COLUMN(Name), FL_LOADICON( "up" ) ); + setSelectable( false ); +#ifdef FASTER + initiated = true; +#endif + } + + repaintItem(); +} + +#ifdef FASTER +void KrDetailedViewItem::setup() { + // idea: when not having pixmaps in the first place, the height of the item is smaller then with + // the pixmap. when the pixmap is inserted, the item resizes, thereby making ensureItemVisible() + // become 'confused' and stop working. therefore, we set the correct height here and avoid the issue + KListViewItem::setup(); + setHeight(expHeight); +} +#endif + +void KrDetailedViewItem::repaintItem() { + if ( dummyVfile ) return; + QString tmp; + // set text in columns, according to what columns are available + int id = KrDetailedViewProperties::Unused; + if ((id = COLUMN(Mime)) != -1) { + tmp = KMimeType::mimeType(_vf->vfile_getMime())->comment(); + setText( id, tmp ); + } + if ((id = COLUMN(Size)) != -1) { + if (_vf->vfile_isDir() && _vf->vfile_getSize() <= 0) setText(id, i18n("")); + else setText(id, PROPS->humanReadableSize ? KIO::convertSize(_vf->vfile_getSize())+" " : + KRpermHandler::parseSize(_vf->vfile_getSize())+" "); + } + + if ((id = COLUMN(DateTime)) != -1) + setText(id, dateTime()); + if ((id = COLUMN(KrPermissions)) != -1) { + // first, build the krusader permissions + tmp=QString::null; + switch (_vf->vfile_isReadable()){ + case ALLOWED_PERM: tmp+='r'; break; + case UNKNOWN_PERM: tmp+='?'; break; + case NO_PERM: tmp+='-'; break; + } + switch (_vf->vfile_isWriteable()){ + case ALLOWED_PERM: tmp+='w'; break; + case UNKNOWN_PERM: tmp+='?'; break; + case NO_PERM: tmp+='-'; break; + } + switch (_vf->vfile_isExecutable()){ + case ALLOWED_PERM: tmp+='x'; break; + case UNKNOWN_PERM: tmp+='?'; break; + case NO_PERM: tmp+='-'; break; + } + setText(id, tmp); + } + if ((id = COLUMN(Permissions) ) != -1) { + if (PROPS->numericPermissions) { + setText(id, tmp.sprintf("%.4o", _vf->vfile_getMode() & PERM_BITMASK)); + } else setText(id, _vf->vfile_getPerm()); + } + if ((id = COLUMN(Owner)) != -1) { + setText(id, _vf->vfile_getOwner()); + } + if ((id = COLUMN(Group)) != -1) { + setText(id, _vf->vfile_getGroup()); + } + // if we've got an extention column, clip the name accordingly + QString name = this->name(), ext = ""; + if ((id = COLUMN(Extention)) != -1 && !_vf->vfile_isDir()) { + ext = this->extension(); + name = this->name(false); // request name without extension + setText(id, ext); + } + setText(COLUMN(Name), name); +#ifndef FASTER + // display an icon if needed + if (PROPS->displayIcons) + setPixmap(COLUMN(Name),KrView::getIcon(_vf)); +#endif +} + +QString num2qstring(KIO::filesize_t num){ + QString buf; + buf.sprintf("%025llu",num); + return buf; +} + +void KrDetailedViewItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align) { +#ifdef FASTER + if (!initiated && !dummyVfile) { + // display an icon if needed + if (PROPS->displayIcons) + setPixmap(COLUMN(Name),KrView::getIcon(_vf)); + + initiated = true; + } +#endif + + QColorGroup _cg(cg); + + // This is ugly! I had to dublicate KListViewItem::paintCell() code, as the + // KListViewItem::paintCell() overwrites my color settings. So KrDetailedViewItem::paintCell + // must dublicate the KListViewItem::paintCell() code, do the required color settings + // and call QListViewItem::paintCell() afterwards (the base class of KListViewItem). + // This tabooed in the object oriented heaven, but necessary here. Blame the KDE team for + // this really poor paintCell implementation! + + const QPixmap *pm = listView()->viewport()->backgroundPixmap(); + if (pm && !pm->isNull()) + { + _cg.setBrush(QColorGroup::Base, QBrush(backgroundColor(), *pm)); + p->setBrushOrigin( -listView()->contentsX(), -listView()->contentsY() ); + } + else if (isAlternate()) + if (listView()->viewport()->backgroundMode()==Qt::FixedColor) + _cg.setColor(QColorGroup::Background, static_cast< KListView* >(listView())->alternateBackground()); + else + _cg.setColor(QColorGroup::Base, static_cast< KListView* >(listView())->alternateBackground()); + + // end of uglyness + + KrColorItemType colorItemType; + colorItemType.m_activePanel = (dynamic_cast(listView()) == ACTIVE_PANEL->view); + colorItemType.m_alternateBackgroundColor = isAlternate(); + colorItemType.m_currentItem = (listView()->currentItem() == this); + colorItemType.m_selectedItem = isSelected(); + if (VF->vfile_isSymLink()) + { + if (_vf->vfile_getMime() == "Broken Link !" ) + colorItemType.m_fileType = KrColorItemType::InvalidSymlink; + else + colorItemType.m_fileType = KrColorItemType::Symlink; + } + else if (VF->vfile_isDir()) + colorItemType.m_fileType = KrColorItemType::Directory; + else if (VF->vfile_isExecutable()) + colorItemType.m_fileType = KrColorItemType::Executable; + else + colorItemType.m_fileType = KrColorItemType::File; + KrColorCache::getColorCache().getColors(_cg, colorItemType); + // center the thing if needed + if(column != COLUMN(Size)) + QListViewItem::paintCell(p, _cg, column, width, align); + else { + if (dummyVfile) { + QListViewItem::paintCell(p, _cg, column, width, Qt::AlignHCenter); // updir + } else { + if (_vf->vfile_isDir() && _vf->vfile_getSize()<=0) + QListViewItem::paintCell(p, _cg, column, width, Qt::AlignHCenter); + else QListViewItem::paintCell(p, _cg, column, width, align); // size + } + } +} + +const QColor & KrDetailedViewItem::setColorIfContrastIsSufficient(const QColor & background, const QColor & color1, const QColor & color2) +{ + #define sqr(x) ((x)*(x)) + int contrast = sqr(color1.red() - background.red()) + sqr(color1.green() - background.green()) + sqr(color1.blue() - background.blue()); + + // if the contrast between background and color1 is too small, take color2 instead. + if (contrast < 1000) + return color2; + return color1; +} + +int KrDetailedViewItem::compare(QListViewItem *i,int col,bool ascending ) const { + bool ignoreCase = (PROPS->sortMode & KrViewProperties::IgnoreCase); + bool alwaysSortDirsByName = (PROPS->sortMode & KrViewProperties::AlwaysSortDirsByName); + int asc = ( ascending ? -1 : 1 ); + KrDetailedViewItem *other = (KrDetailedViewItem *)(i); + + bool thisDir = VF->vfile_isDir(); + bool otherDir = other->VF->vfile_isDir(); + + // handle directory sorting + if ( thisDir ){ + if ( !otherDir ) return 1*asc; + } else if( otherDir ) return -1*asc; + + if ( isDummy() ) return 1*asc; + if ( other->isDummy() ) return -1*asc; + + if (col == COLUMN(Name) || + (alwaysSortDirsByName && thisDir && otherDir )) { + // localeAwareCompare doesn't handle names that start with a dot + QString text0 = name(); + QString itext0 = other->name(); + + if( ignoreCase ) + { + text0 = text0.lower(); + itext0 = itext0.lower(); + } + + if ( isHidden() ) { + if ( !other->isHidden() ) return 1*asc; + } else if ( other->isHidden() ) return -1*asc; + if (!ignoreCase && !PROPS->localeAwareCompareIsCaseSensitive) { + // sometimes, localeAwareCompare is not case sensative. in that case, + // we need to fallback to a simple string compare (KDE bug #40131) + return QString::compare(text0, itext0); + } else return QString::localeAwareCompare(text0,itext0); + } else if (col == COLUMN(Size) ) { + if( VF->vfile_getSize() == other->VF->vfile_getSize() ) + return 0; + return (VF->vfile_getSize() > other->VF->vfile_getSize() ? 1 : -1); + } else if (col == COLUMN(DateTime) ) { + if( VF->vfile_getTime_t() == other->VF->vfile_getTime_t() ) + return 0; + return (VF->vfile_getTime_t() > other->VF->vfile_getTime_t() ? 1 : -1); + } else if (col == COLUMN(Permissions) && PROPS->numericPermissions) { + int thisPerm = VF->vfile_getMode() & PERM_BITMASK; + int otherPerm = other->VF->vfile_getMode() & PERM_BITMASK; + if( thisPerm == otherPerm ) + return 0; + return ((thisPerm > otherPerm) ? 1 : -1); + } else { + QString e1 = (!ignoreCase ? text(col) : text(col).lower()); + QString e2 = (!ignoreCase ? i->text(col) : i->text(col).lower()); + if (!ignoreCase && !PROPS->localeAwareCompareIsCaseSensitive) { + // sometimes, localeAwareCompare is not case sensative. in that case, + // we need to fallback to a simple string compare (KDE bug #40131) + return QString::compare(e1, e2); + } else return QString::localeAwareCompare(e1, e2); + } +} + +void KrDetailedViewItem::itemHeightChanged() { +#ifdef FASTER + expHeight = 0; +#endif +} diff --git a/krusader/Panel/krdetailedviewitem.h b/krusader/Panel/krdetailedviewitem.h new file mode 100644 index 0000000..3ef9fcf --- /dev/null +++ b/krusader/Panel/krdetailedviewitem.h @@ -0,0 +1,73 @@ +/*************************************************************************** + krdetailedviewitem.h + ------------------- + copyright : (C) 2000-2002 by Shie Erlich & Rafi Yanai + 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 KRDETAILEDVIEWITEM_H +#define KRDETAILEDVIEWITEM_H + +#include "krviewitem.h" +#include +#include "../VFS/vfile.h" +#include +#include + +#define FASTER + +class QPixmap; +class KrDetailedView; + +class KrDetailedViewItem : public KListViewItem, public KrViewItem { +friend class KrDetailedView; +friend class KrCalcSpaceDialog; +public: + KrDetailedViewItem(KrDetailedView *parent, QListViewItem *after, vfile *vf); + inline bool isSelected() const { return KListViewItem::isSelected(); } + inline void setSelected(bool s) { KListViewItem::setSelected(s); } + int compare(QListViewItem *i,int col,bool ascending ) const; + void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align); + void repaintItem(); + static void itemHeightChanged(); // force the items to resize when icon/font size change +#ifdef FASTER + virtual void setup(); // called when listview needs to know the height of the item +#endif + +protected: + // text() was made protected in order to catch every place where text(x) is used + // to gain unlawful information on the object + virtual inline QString text(int column) const { return KListViewItem::text(column); } + +private: + static const QColor & setColorIfContrastIsSufficient(const QColor & background, const QColor & color1, const QColor & color2); +#ifdef FASTER + bool initiated; + static int expHeight; +#endif +}; + +#endif diff --git a/krusader/Panel/krdrag.cpp b/krusader/Panel/krdrag.cpp new file mode 100644 index 0000000..5e80b36 --- /dev/null +++ b/krusader/Panel/krdrag.cpp @@ -0,0 +1,103 @@ +/*************************************************************************** + krdrag.cpp + ------------------- +copyright : (C) 2003 by Heiner Eichmann +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. * +* * +***************************************************************************/ + +#include "krdrag.h" +#include + +KRDrag * KRDrag::newDrag( const KURL::List & urls, bool move, QWidget * dragSource, const char* name ) +{ + // See KURLDrag::newDrag + QStrList uris; + KURL::List::ConstIterator uit = urls.begin(); + KURL::List::ConstIterator uEnd = urls.end(); + // Get each URL encoded in utf8 - and since we get it in escaped + // form on top of that, .latin1() is fine. + for ( ; uit != uEnd ; ++uit ) + uris.append( KURLDrag::urlToString( *uit ).latin1() ); + return new KRDrag( uris, move, dragSource, name ); +} + +KRDrag::KRDrag( const QStrList & urls, bool move, QWidget * dragSource, const char* name ) + : QUriDrag( urls, dragSource, name ), + m_bCutSelection( move ), m_urls( urls ) +{} + +const char* KRDrag::format( int i ) const +{ + if ( i == 0 ) + return "text/uri-list"; + else if ( i == 1 ) + return "application/x-kde-cutselection"; + else if ( i == 2 ) + return "text/plain"; + else return 0; +} + +QByteArray KRDrag::encodedData( const char* mime ) const +{ + QByteArray a; + QCString mimetype( mime ); + if ( mimetype == "text/uri-list" ) + return QUriDrag::encodedData( mime ); + else if ( mimetype == "application/x-kde-cutselection" ) { + QCString s ( m_bCutSelection ? "1" : "0" ); + a.resize( s.length() + 1 ); // trailing zero + memcpy( a.data(), s.data(), s.length() + 1 ); + } + else if ( mimetype == "text/plain" ) + { + QStringList uris; + for (QStrListIterator it(m_urls); *it; ++it) + uris.append(KURLDrag::stringToUrl(*it).prettyURL()); + QCString s = uris.join( "\n" ).local8Bit(); + if( uris.count() > 1 ) + s.append( "\n" ); + a.resize( s.length() + 1 ); // trailing zero + memcpy( a.data(), s.data(), s.length() + 1 ); + } + return a; +} + +// + +// Used for KonqIconDrag too + +bool KRDrag::decodeIsCutSelection( const QMimeSource *e ) +{ + QByteArray a = e->encodedData( "application/x-kde-cutselection" ); + if ( a.isEmpty() ) + return false; + else + { + return (a.at(0) == '1'); // true if "1", or similar + } + } + +#include "krdrag.moc" diff --git a/krusader/Panel/krdrag.h b/krusader/Panel/krdrag.h new file mode 100644 index 0000000..1aa264f --- /dev/null +++ b/krusader/Panel/krdrag.h @@ -0,0 +1,62 @@ +/*************************************************************************** + krdrag.h + ------------------- +copyright : (C) 2003 by Heiner Eichmann +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 KRDRAG_H +#define KRDRAG_H + +#include +#include + +class KRDrag : public QUriDrag +{ + Q_OBJECT +public: + static KRDrag * newDrag( const KURL::List & urls, bool move, QWidget * dragSource = 0, const char* name = 0 ); + +protected: + KRDrag( const QStrList & urls, bool move, QWidget * dragSource, const char* name ); + +public: + virtual ~KRDrag() {} + + virtual const char* format( int i ) const; + virtual QByteArray encodedData( const char* mime ) const; + + void setMoveSelection( bool move ) { m_bCutSelection = move; } + + // Returns true if the data was cut (used for KonqIconDrag too) + static bool decodeIsCutSelection( const QMimeSource *e ); + +protected: + bool m_bCutSelection; + QStrList m_urls; +}; + +#endif /* KRDRAG_H */ diff --git a/krusader/Panel/krpopupmenu.cpp b/krusader/Panel/krpopupmenu.cpp new file mode 100644 index 0000000..fda6296 --- /dev/null +++ b/krusader/Panel/krpopupmenu.cpp @@ -0,0 +1,354 @@ +/*************************************************************************** + krpopupmenu.cpp - description + ------------------- + begin : Tue Aug 26 2003 + copyright : (C) 2003 by Shie Erlich & Rafi Yanai + email : + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 +#include +#include +#include +#include +#include +#include "../krservices.h" +#include "../defaults.h" +#include "../MountMan/kmountman.h" +#include "../krslots.h" +#include "krpopupmenu.h" +#include "krview.h" +#include "krviewitem.h" +#include "panelfunc.h" +#include "../krusaderview.h" +#include "../panelmanager.h" + +void KrPopupMenu::run(const QPoint &pos, ListPanel *panel) { + KrPopupMenu menu(panel); + int result = menu.exec(pos); + menu.performAction(result); +} + +KrPopupMenu::KrPopupMenu(ListPanel *thePanel, QWidget *parent) : KPopupMenu(parent), panel(thePanel), empty(false), + multipleSelections(false),actions(0) { +#ifdef __LIBKONQ__ + konqMenu = 0; +#endif + + panel->view->getSelectedKrViewItems( &items ); + if ( items.empty() ) { + addCreateNewMenu(); + insertSeparator(); + addEmptyMenuEntries(); + return; + } else if ( items.size() > 1 ) multipleSelections = true; + + item = items.first(); + vfile *vf = panel->func->getVFile(item); + + // ------------ the OPEN option - open prefered service + insertItem( i18n("Open/Run"), OPEN_ID ); + if ( !multipleSelections ) { // meaningful only if one file is selected + changeItem( OPEN_ID, item->icon(), vf->vfile_isExecutable() && !vf->vfile_isDir() ? i18n("Run") : i18n("Open") ); + // open in a new tab (if folder) + if ( vf->vfile_isDir() ) { + insertItem( i18n( "Open in New Tab" ), OPEN_TAB_ID ); + changeItem( OPEN_TAB_ID, krLoader->loadIcon( "tab_new", KIcon::Panel ), i18n( "Open in New Tab" ) ); + } + insertSeparator(); + } + + // ------------- Preview - normal vfs only ? + if ( panel->func->files()->vfs_getType() == vfs::NORMAL ) { + // create the preview popup + QStringList names; + panel->getSelectedNames( &names ); + preview.setUrls( panel->func->files() ->vfs_getFiles( &names ) ); + insertItem( i18n("Preview"), &preview, PREVIEW_ID ); + } + + // -------------- Open with: try to find-out which apps can open the file + // this too, is meaningful only if one file is selected or if all the files + // have the same mimetype ! + QString mime = panel->func->getVFile(item)->vfile_getMime(); + // check if all the list have the same mimetype + for ( unsigned int i = 1; i < items.size(); ++i ) { + if ( panel->func->getVFile(( *items.at( i ) )) ->vfile_getMime() != mime ) { + mime = QString::null; + break; + } + } + if ( !mime.isEmpty() ) { + offers = KServiceTypeProfile::offers( mime ); + for ( unsigned int i = 0; i < offers.count(); ++i ) { + KService::Ptr service = offers[ i ].service(); + if ( service->isValid() && service->type() == "Application" ) { + openWith.insertItem( service->name(), SERVICE_LIST_ID + i ); + openWith.changeItem( SERVICE_LIST_ID + i, service->pixmap( KIcon::Small ), service->name() ); + } + } + openWith.insertSeparator(); + if ( vf->vfile_isDir() ) + openWith.insertItem( krLoader->loadIcon( "konsole", KIcon::Small ), i18n( "Terminal" ), OPEN_TERM_ID ); + openWith.insertItem( i18n( "Other..." ), CHOOSE_ID ); + insertItem( QPixmap(), &openWith, OPEN_WITH_ID ); + changeItem( OPEN_WITH_ID, i18n( "Open With" ) ); + insertSeparator(); + } + + // --------------- user actions + insertItem( i18n("User Actions"), new UserActionPopupMenu( panel->func->files()->vfs_getFile( item->name() ).url() ) ); + _items.setAutoDelete( true ); + for ( KrViewItemList::Iterator it = items.begin(); it != items.end(); ++it ) { + vfile *file = panel->func->files()->vfs_search(((*it)->name())); + KURL url = file->vfile_getUrl(); + _items.append( new KFileItem( url, file->vfile_getMime(), file->vfile_getMode() ) ); + } + +#ifdef __LIBKONQ__ + // -------------- konqueror menu + actions = new KActionCollection(this); + konqMenu = new KonqPopupMenu( KonqBookmarkManager::self(), _items, panel->func->files()->vfs_getOrigin(), *actions, 0, this, + KonqPopupMenu::NoFlags, KParts::BrowserExtension::DefaultPopupItems ); + insertItem( QPixmap(), konqMenu, KONQ_MENU_ID ); + changeItem( KONQ_MENU_ID, i18n( "Konqueror Menu" ) ); +#endif + + // ------------- 'create new' submenu + addCreateNewMenu(); + insertSeparator(); + + // ---------- COPY + insertItem( i18n( "Copy..." ), COPY_ID ); + if ( panel->func->files() ->vfs_isWritable() ) { + // ------- MOVE + insertItem( i18n( "Move..." ), MOVE_ID ); + // ------- RENAME - only one file + if ( !multipleSelections ) + insertItem( i18n( "Rename" ), RENAME_ID ); + + // -------- MOVE TO TRASH + KConfigGroupSaver saver(krConfig, "General"); + bool trash = krConfig->readBoolEntry( "Move To Trash", _MoveToTrash ); + if( trash ) + insertItem( i18n( "Move to Trash" ), TRASH_ID ); + // -------- DELETE + insertItem( i18n( "Delete" ), DELETE_ID ); + // -------- SHRED - only one file + if ( panel->func->files() ->vfs_getType() == vfs::NORMAL && + !vf->vfile_isDir() && !multipleSelections ) + insertItem( i18n( "Shred" ), SHRED_ID ); + } + + // ---------- link handling + // create new shortcut or redirect links - only on local directories: + if ( panel->func->files() ->vfs_getType() == vfs::NORMAL ) { + insertSeparator(); + linkPopup.insertItem( i18n( "New Symlink..." ), NEW_SYMLINK_ID ); + linkPopup.insertItem( i18n( "New Hardlink..." ), NEW_LINK_ID ); + if ( panel->func->getVFile(item)->vfile_isSymLink() ) + linkPopup.insertItem( i18n( "Redirect Link..." ), REDIRECT_LINK_ID); + insertItem( QPixmap(), &linkPopup, LINK_HANDLING_ID ); + changeItem( LINK_HANDLING_ID, i18n( "Link Handling" ) ); + } + insertSeparator(); + + // ---------- calculate space + if ( panel->func->files() ->vfs_getType() == vfs::NORMAL && ( vf->vfile_isDir() || multipleSelections ) ) + krCalculate->plug( this ); + + // ---------- mount/umount/eject + if ( panel->func->files() ->vfs_getType() == vfs::NORMAL && vf->vfile_isDir() && !multipleSelections ) { + if ( krMtMan.getStatus( panel->func->files() ->vfs_getFile( item->name() ).path( -1 ) ) == KMountMan::MOUNTED ) + insertItem( i18n( "Unmount" ), UNMOUNT_ID ); + else if ( krMtMan.getStatus( panel->func->files() ->vfs_getFile( item->name() ).path( -1 ) ) == KMountMan::NOT_MOUNTED ) + insertItem( i18n( "Mount" ), MOUNT_ID ); + if ( krMtMan.ejectable( panel->func->files() ->vfs_getFile( item->name() ).path( -1 ) ) ) + insertItem( i18n( "Eject" ), EJECT_ID ); + } + + // --------- send by mail + if ( Krusader::supportedTools().contains( "MAIL" ) && !vf->vfile_isDir() ) { + insertItem( i18n( "Send by Email" ), SEND_BY_EMAIL_ID ); + } + + // --------- synchronize + if ( panel->view->numSelected() ) { + insertItem( i18n( "Synchronize Selected Files..." ), SYNC_SELECTED_ID ); + } + + // --------- copy/paste + insertSeparator(); + insertItem( i18n( "Copy to Clipboard" ), COPY_CLIP_ID ); + if ( panel->func->files() ->vfs_isWritable() ) + { + insertItem( i18n( "Cut to Clipboard" ), MOVE_CLIP_ID ); + insertItem( i18n( "Paste from Clipboard" ), PASTE_CLIP_ID ); + } + insertSeparator(); + + // --------- properties + krProperties->plug( this ); +} + +KrPopupMenu::~KrPopupMenu() { + if (actions) delete actions; +#ifdef __LIBKONQ__ + if (konqMenu) delete konqMenu; +#endif +} + +void KrPopupMenu::addEmptyMenuEntries() { + insertItem( i18n( "Paste from Clipboard" ), PASTE_CLIP_ID ); +} + +void KrPopupMenu::addCreateNewMenu() { + createNewPopup.insertItem( krLoader->loadIcon( "folder", KIcon::Small ), i18n("Folder..."), MKDIR_ID); + createNewPopup.insertItem( krLoader->loadIcon( "txt", KIcon::Small ), i18n("Text File..."), NEW_TEXT_FILE_ID); + + insertItem( QPixmap(), &createNewPopup, CREATE_NEW_ID); + changeItem( CREATE_NEW_ID, i18n( "Create New" ) ); + +} + +void KrPopupMenu::performAction(int id) { + KURL u; + KURL::List lst; + + switch ( id ) { + case - 1 : // the user clicked outside of the menu + return ; + case OPEN_TAB_ID : + // assuming only 1 file is selected (otherwise we won't get here) + ( ACTIVE_PANEL == LEFT_PANEL ? LEFT_MNG : RIGHT_MNG )-> + slotNewTab( panel->func->files()->vfs_getFile( item->name() ).url() ); + break; + case OPEN_ID : + for ( KrViewItemList::Iterator it = items.begin(); it != items.end(); ++it ) { + u = panel->func->files()->vfs_getFile( ( *it ) ->name() ); + KRun::runURL( u, panel->func->getVFile(item)->vfile_getMime() ); + } + break; + case COPY_ID : + panel->func->copyFiles(); + break; + case MOVE_ID : + panel->func->moveFiles(); + break; + case RENAME_ID : + SLOTS->rename(); + break; + case TRASH_ID : + panel->func->deleteFiles( false ); + break; + case DELETE_ID : + panel->func->deleteFiles( true ); + break; + case EJECT_ID : + KMountMan::eject( panel->func->files() ->vfs_getFile( item->name() ).path( -1 ) ); + break; + case SHRED_ID : + if ( KMessageBox::warningContinueCancel( krApp, + i18n("Do you really want to shred %1? Once shred, the file is gone forever!").arg(item->name()), + QString::null, KStdGuiItem::cont(), "Shred" ) == KMessageBox::Continue ) + KShred::shred( panel->func->files() ->vfs_getFile( item->name() ).path( -1 ) ); + break; + case OPEN_KONQ_ID : + kapp->startServiceByDesktopName( "konqueror", panel->func->files() ->vfs_getFile( item->name() ).url() ); + break; + case CHOOSE_ID : // open-with dialog + u = panel->func->files() ->vfs_getFile( item->name() ); + lst.append( u ); + KRun::displayOpenWithDialog( lst ); + break; + case MOUNT_ID : + krMtMan.mount( panel->func->files() ->vfs_getFile( item->name() ).path( -1 ) ); + break; + case NEW_LINK_ID : + panel->func->krlink( false ); + break; + case NEW_SYMLINK_ID : + panel->func->krlink( true ); + break; + case REDIRECT_LINK_ID : + panel->func->redirectLink(); + break; + case UNMOUNT_ID : + krMtMan.unmount( panel->func->files() ->vfs_getFile( item->name() ).path( -1 ) ); + break; + case COPY_CLIP_ID : + panel->func->copyToClipboard(); + break; + case MOVE_CLIP_ID : + panel->func->copyToClipboard( true ); + break; + case PASTE_CLIP_ID : + panel->func->pasteFromClipboard(); + break; + case SEND_BY_EMAIL_ID : + SLOTS->sendFileByEmail( panel->func->files() ->vfs_getFile( item->name() ).url() ); + break; + case MKDIR_ID : + SLOTS->mkdir(); + break; + case NEW_TEXT_FILE_ID: + SLOTS->editDlg(); + break; + case SYNC_SELECTED_ID : + { + QStringList selectedNames; + for ( KrViewItemList::Iterator it = items.begin(); it != items.end(); ++it ) + selectedNames.append( ( *it ) ->name() ); + if( panel->otherPanel->view->numSelected() ) { + KrViewItemList otherItems; + panel->otherPanel->view->getSelectedKrViewItems( &otherItems ); + + for ( KrViewItemList::Iterator it2 = otherItems.begin(); it2 != otherItems.end(); ++it2 ) { + QString name = ( *it2 ) ->name(); + if( !selectedNames.contains( name ) ) + selectedNames.append( name ); + } + } + SLOTS->slotSynchronizeDirs( selectedNames ); + } + break; + case OPEN_TERM_ID : + QString save = getcwd( 0, 0 ); + chdir( panel->func->files() ->vfs_getFile( item->name() ).path( -1 ).local8Bit() ); + KProcess proc; + { + KConfigGroupSaver saver(krConfig, "General"); + QString term = krConfig->readEntry( "Terminal", _Terminal ); + proc << KrServices::separateArgs( term ); + if ( !panel->func->getVFile(item)->vfile_isDir() ) proc << "-e" << item->name(); + if ( term.contains( "konsole" ) ) { /* KDE 3.2 bug (konsole is killed by pressing Ctrl+C) */ + /* Please remove the patch if the bug is corrected */ + proc << "&"; + proc.setUseShell( true ); + } + if ( !proc.start( KProcess::DontCare ) ) + KMessageBox::sorry( krApp, i18n( "Can't open \"%1\"" ).arg(term) ); + } // group-saver is blown out of scope here + chdir( save.local8Bit() ); + break; + } + + // check if something from the open-with-offered-services was selected + if ( id >= SERVICE_LIST_ID ) { + QStringList names; + panel->getSelectedNames( &names ); + KRun::run( *( offers[ id - SERVICE_LIST_ID ].service() ), + *( panel->func->files() ->vfs_getFiles( &names ) ) ); + } +} + +#include "krpopupmenu.moc" diff --git a/krusader/Panel/krpopupmenu.h b/krusader/Panel/krpopupmenu.h new file mode 100644 index 0000000..13157b4 --- /dev/null +++ b/krusader/Panel/krpopupmenu.h @@ -0,0 +1,77 @@ +#ifndef KRPOPUPMENU_H +#define KRPOPUPMENU_H + +#include +#include +#include +#include "listpanel.h" +#include "krpreviewpopup.h" +#include "../UserAction/useractionpopupmenu.h" +#ifdef __LIBKONQ__ +#include +#include +#endif + +// should be renamed to KrContextMenu or similar +class KrPopupMenu : public KPopupMenu { + Q_OBJECT +public: + static void run(const QPoint &pos, ListPanel *panel); + +protected: + KrPopupMenu(ListPanel *thePanel, QWidget *parent=0); + ~KrPopupMenu(); + void performAction(int id); + void addEmptyMenuEntries(); // adds the choices for a menu without selected items + void addCreateNewMenu(); // adds a "create new" submenu + + enum ID { + OPEN_ID, + OPEN_WITH_ID, + OPEN_KONQ_ID, + OPEN_TERM_ID, + OPEN_TAB_ID, + PREVIEW_ID, + KONQ_MENU_ID, + CHOOSE_ID, + DELETE_ID, + COPY_ID, + MOVE_ID, + RENAME_ID, + PROPERTIES_ID, + MOUNT_ID, + UNMOUNT_ID, + TRASH_ID, + SHRED_ID, + NEW_LINK_ID, + NEW_SYMLINK_ID, + REDIRECT_LINK_ID, + SYNC_SELECTED_ID, + SEND_BY_EMAIL_ID, + LINK_HANDLING_ID, + EJECT_ID, + COPY_CLIP_ID, + MOVE_CLIP_ID, + PASTE_CLIP_ID, + MKDIR_ID, + NEW_TEXT_FILE_ID, + CREATE_NEW_ID, + SERVICE_LIST_ID // ALWAYS KEEP THIS ONE LAST!!! + }; + +private: + ListPanel *panel; + bool empty, multipleSelections; + KPopupMenu openWith, linkPopup, createNewPopup; + KrPreviewPopup preview; + KActionCollection *actions; + KrViewItemList items; // list of selected items + KrViewItem *item; // the (first) selected item + KFileItemList _items; + QValueList offers; +#ifdef __LIBKONQ__ + KonqPopupMenu *konqMenu; +#endif +}; + +#endif diff --git a/krusader/Panel/krpreviewpopup.cpp b/krusader/Panel/krpreviewpopup.cpp new file mode 100644 index 0000000..53f4afd --- /dev/null +++ b/krusader/Panel/krpreviewpopup.cpp @@ -0,0 +1,68 @@ +/*************************************************************************** + krpreviewpopup.cpp - description + ------------------- + begin : Sun Dec 29 2002 + copyright : (C) 2002 by Shie Erlich & Rafi Yanai + web site : http://krusader.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 +#include "krpreviewpopup.h" +#include +#include +#include +#include "../KViewer/krviewer.h" +#include "../krusader.h" + +KrPreviewPopup::KrPreviewPopup(): id(1),noPreview(true){ + connect(this,SIGNAL(activated(int)),this,SLOT(view(int))); +} + +void KrPreviewPopup::setUrls(const KURL::List* urls){ + //insertItem(i18n("Configure preview"),0); + insertItem(i18n("Preview not available"),0); + + KIO::PreviewJob* pjob; + QStringList plugins = KIO::PreviewJob::availablePlugins(); + + for( unsigned int i=0; i< urls->count(); ++i){ + KFileItem* kfi = new KFileItem(KFileItem::Unknown,KFileItem::Unknown,*(urls->at(i))); + files.append(kfi); + } + + pjob = new KIO::PreviewJob(files,200,200,200,1,true,true,0); + connect(pjob,SIGNAL(gotPreview(const KFileItem*,const QPixmap&)), + this,SLOT(addPreview(const KFileItem*,const QPixmap&))); +} + +KrPreviewPopup::~KrPreviewPopup(){} + +void KrPreviewPopup::addPreview(const KFileItem* file,const QPixmap& preview){ + if(noPreview){ + removeItem(0); + noPreview = false; + } + insertItem(preview,id); + insertItem(file->text(),id++); + insertSeparator(); + availablePreviews.append(file->url()); +} + +void KrPreviewPopup::view(int id){ + if( id==0 ) return; + else { + KURL url = *(availablePreviews.at(id-1)); + KrViewer::view(url); + } +} + +#include "krpreviewpopup.moc" diff --git a/krusader/Panel/krpreviewpopup.h b/krusader/Panel/krpreviewpopup.h new file mode 100644 index 0000000..91b852c --- /dev/null +++ b/krusader/Panel/krpreviewpopup.h @@ -0,0 +1,48 @@ +/*************************************************************************** + krpreviewpopup.h - description + ------------------- + begin : Sun Dec 29 2002 + copyright : (C) 2002 by Shie Erlich & Rafi Yanai + web site : http://krusader.sourceforge.net + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 KRPREVIEWPOPUP_H +#define KRPREVIEWPOPUP_H + +#include +#include +#include +#include + +/** + *@author Shie Erlich & Rafi Yanai + */ + +class KrPreviewPopup : public QPopupMenu { + Q_OBJECT +public: + KrPreviewPopup(); + ~KrPreviewPopup(); + + void setUrls(const KURL::List* urls); +public slots: + void addPreview(const KFileItem* file,const QPixmap& preview); + void view(int id); + +protected: + KFileItemList files; + int id; + bool noPreview; + KURL::List availablePreviews; +}; + +#endif diff --git a/krusader/Panel/krselectionmode.cpp b/krusader/Panel/krselectionmode.cpp new file mode 100644 index 0000000..02d95b1 --- /dev/null +++ b/krusader/Panel/krselectionmode.cpp @@ -0,0 +1,61 @@ +#include "krselectionmode.h" +#include "../krusader.h" +#include "../defaults.h" + +static KrSelectionMode *__currentSelectionMode = 0; // uninitiated, at first + + +KonqSelectionMode konqSelectionMode; +OriginalSelectionMode originalSelectionMode; +TCSelectionMode tcSelectionMode; +UserSelectionMode userSelectionMode; + +KrSelectionMode* KrSelectionMode::getSelectionHandler() +{ + if (__currentSelectionMode) { // don't check krConfig every time + return __currentSelectionMode; + } else { // nothing yet, set the correct one + krConfig->setGroup( "Look&Feel" ); + QString mode = krConfig->readEntry("Mouse Selection", ""); + switch (mode.toInt()) { + case 0: + __currentSelectionMode = &originalSelectionMode; + break; + case 1: + __currentSelectionMode = &konqSelectionMode; + break; + case 2: + __currentSelectionMode = &tcSelectionMode; + break; + case 3: + __currentSelectionMode = &userSelectionMode; + userSelectionMode.init(); + break; + default: + break; + } + // init and return + __currentSelectionMode->init(); + return __currentSelectionMode; + } +} + +void KrSelectionMode::resetSelectionHandler() { + __currentSelectionMode = 0; +} + +void UserSelectionMode::init() { + krConfig->setGroup("Custom Selection Mode"); + _useQTSelection = krConfig->readBoolEntry("QT Selection", _QtSelection); + _leftButtonSelects = krConfig->readBoolEntry("Left Selects", _LeftSelects); + _leftButtonPreservesSelection = krConfig->readBoolEntry("Left Preserves", _LeftPreserves); + _shiftCtrlLeftButtonSelects = krConfig->readBoolEntry("ShiftCtrl Left Selects", _ShiftCtrlLeft); + _rightButtonSelects = krConfig->readBoolEntry("Right Selects", _RightSelects); + _rightButtonPreservesSelection = krConfig->readBoolEntry("Right Preserves", _RightPreserves); + _shiftCtrlRightButtonSelects = krConfig->readBoolEntry("ShiftCtrl Right Selects", _ShiftCtrlRight); + _spaceMovesDown = krConfig->readBoolEntry("Space Moves Down", _SpaceMovesDown); + _spaceCalculatesDiskSpace = krConfig->readBoolEntry("Space Calc Space", _SpaceCalcSpace); + _insertMovesDown = krConfig->readBoolEntry("Insert Moves Down", _InsertMovesDown); + _showContextMenu = (krConfig->readBoolEntry("Immediate Context Menu", _ImmediateContextMenu) ? -1 : 500); +} + diff --git a/krusader/Panel/krselectionmode.h b/krusader/Panel/krselectionmode.h new file mode 100644 index 0000000..4f9de2e --- /dev/null +++ b/krusader/Panel/krselectionmode.h @@ -0,0 +1,97 @@ +#ifndef KR_SELECTION_MODE_H +#define KR_SELECTION_MODE_H + +/** + Every selection mode inherits this class, and has to implement init(). + Usage: + KrSelectionMode::getSelectionHandler()->whateverFunctionYouNeed() + + \note You can call KrSelectionMode::resetSelectionHandler() if you want the + selection mode to be re-read. This is useful after a configuration where you + changed the selection mode. calling resetSelectionHandler() will cause the next + call to getSelectionHandler() to (possibly) select a different mode. +*/ +class KrSelectionMode { +public: + static KrSelectionMode * getSelectionHandler(); + static void resetSelectionHandler(); + + virtual void init() = 0; // everyone must implement this in order to be a selection mode + inline bool useQTSelection() { return _useQTSelection; } + inline bool spaceMovesDown() { return _spaceMovesDown; } + inline bool insertMovesDown() { return _insertMovesDown; } + inline bool spaceCalculatesDiskSpace() { return _spaceCalculatesDiskSpace; } + inline bool rightButtonSelects() { return _rightButtonSelects; } + inline bool leftButtonSelects() { return _leftButtonSelects; } + inline bool rightButtonPreservesSelection() { return _rightButtonPreservesSelection; } + inline bool leftButtonPreservesSelection() { return _leftButtonPreservesSelection; } + inline bool shiftCtrlRightButtonSelects() { return _shiftCtrlRightButtonSelects; } + inline bool shiftCtrlLeftButtonSelects() { return _shiftCtrlLeftButtonSelects; } + inline int showContextMenu() { return _showContextMenu; } // 0: no, -1: yes, n>0: after n milliseconds + + virtual ~KrSelectionMode() {} + +protected: + bool _useQTSelection, _spaceMovesDown, _insertMovesDown, _spaceCalculatesDiskSpace; + bool _rightButtonSelects, _leftButtonSelects, _rightButtonPreservesSelection; + bool _leftButtonPreservesSelection, _shiftCtrlRightButtonSelects, _shiftCtrlLeftButtonSelects; + int _showContextMenu; +}; + +class KonqSelectionMode : public KrSelectionMode { +public: + void init() { + _useQTSelection = true; + _spaceMovesDown = false; + _insertMovesDown = true; + _spaceCalculatesDiskSpace = false; + _rightButtonSelects = true; + _leftButtonSelects = true; + _rightButtonPreservesSelection = false; + _leftButtonPreservesSelection = false; + _shiftCtrlRightButtonSelects = false; + _shiftCtrlLeftButtonSelects = false; + _showContextMenu = -1; + } +}; + +class OriginalSelectionMode : public KrSelectionMode { +public: + void init() { + _useQTSelection = false; + _spaceMovesDown = true; + _insertMovesDown = true; + _spaceCalculatesDiskSpace = true; + _rightButtonSelects = true; + _leftButtonSelects = true; + _rightButtonPreservesSelection = false; + _leftButtonPreservesSelection = false; + _shiftCtrlRightButtonSelects = false; + _shiftCtrlLeftButtonSelects = false; + _showContextMenu = -1; + } +}; + +class TCSelectionMode : public KrSelectionMode { +public: + void init() { + _useQTSelection = false; + _spaceMovesDown = false; + _insertMovesDown = true; + _spaceCalculatesDiskSpace = true; + _rightButtonSelects = true; + _leftButtonSelects = false; + _rightButtonPreservesSelection = true; + _leftButtonPreservesSelection = false; + _shiftCtrlRightButtonSelects = false; + _shiftCtrlLeftButtonSelects = true; + _showContextMenu = 500; + } +}; + +class UserSelectionMode: public KrSelectionMode { +public: + void init(); +}; + +#endif // KR_SELECTION_MODE_H diff --git a/krusader/Panel/krview.cpp b/krusader/Panel/krview.cpp new file mode 100644 index 0000000..c44bcb6 --- /dev/null +++ b/krusader/Panel/krview.cpp @@ -0,0 +1,332 @@ +/*************************************************************************** + krview.cpp + ------------------- + copyright : (C) 2000-2002 by Shie Erlich & Rafi Yanai + 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 "krview.h" +#include "../kicons.h" +#include "../defaults.h" +#include "../VFS/krpermhandler.h" +#include "krviewitem.h" +#include +#include +#include +#include +#include +#include +#include + + +#define VF getVfile() + + +// ----------------------------- operator +KrViewOperator::KrViewOperator(KrView *view, QWidget *widget): _view(view), _widget(widget) { +} + +KrViewOperator::~KrViewOperator() { +} + +void KrViewOperator::startDrag() { + QStringList items; + _view->getSelectedItems( &items ); + if ( items.empty() ) + return ; // don't drag an empty thing + QPixmap px; + if ( items.count() > 1 ) + px = FL_LOADICON( "queue" ); // how much are we dragging + else + px = _view->getCurrentKrViewItem() ->icon(); + emit letsDrag( items, px ); +} + +// ----------------------------- krview + +KrView::KrView( KConfig *cfg ) : _config( cfg ), _widget(0), _nameToMakeCurrent( QString::null ), _nameToMakeCurrentIfAdded( QString::null ), +_numSelected( 0 ), _count( 0 ), _numDirs( 0 ), _countSize( 0 ), _selectedSize( 0 ), _properties(0), _focused( false ), _nameInKConfig(QString::null) { +} + +KrView::~KrView() { + if (_properties) + qFatal("A class inheriting KrView didn't delete _properties!"); + if (_operator) + qFatal("A class inheriting KrView didn't delete _operator!"); +} + +void KrView::init() { + // sanity checks: + if (_nameInKConfig.isEmpty()) + qFatal("_nameInKConfig must be set during construction of KrView inheritors"); + if (!_widget) + qFatal("_widget must be set during construction of KrView inheritors"); + // ok, continue + initProperties(); + initOperator(); + setup(); +} + +QPixmap KrView::getIcon( vfile *vf /*, KRListItem::cmpColor color*/ ) { + //krConfig->setGroup("Advanced"); + ////////////////////////////// + QPixmap icon; + QString icon_name = vf->vfile_getIcon(); + //QPixmapCache::setCacheLimit( krConfig->readNumEntry("Icon Cache Size",_IconCacheSize) ); + + if( icon_name.isNull() ) + icon_name=""; + + // first try the cache + if ( !QPixmapCache::find( icon_name, icon ) ) { + icon = FL_LOADICON( icon_name ); + // insert it into the cache + QPixmapCache::insert( icon_name, icon ); + } + // if it's a symlink - add an arrow overlay + if ( vf->vfile_isSymLink() ) { + QPixmap link( link_xpm ); + bitBlt ( &icon, 0, icon.height() - 11, &link, 0, 21, 10, 11, Qt::CopyROP, false ); + icon.setMask( icon.createHeuristicMask( false ) ); + } + + return icon; +} + +/** + * this function ADDs a list of selected item names into 'names'. + * it assumes the list is ready and doesn't initialize it, or clears it + */ +void KrView::getItemsByMask( QString mask, QStringList* names, bool dirs, bool files ) { + for ( KrViewItem * it = getFirst(); it != 0; it = getNext( it ) ) { + if ( ( it->name() == ".." ) || !QDir::match( mask, it->name() ) ) continue; + // if we got here, than the item fits the mask + if ( it->getVfile()->vfile_isDir() && !dirs ) continue; // do we need to skip folders? + if ( !it->getVfile()->vfile_isDir() && !files ) continue; // do we need to skip files + names->append( it->name() ); + } +} + +/** + * this function ADDs a list of selected item names into 'names'. + * it assumes the list is ready and doesn't initialize it, or clears it + */ +void KrView::getSelectedItems( QStringList *names ) { + for ( KrViewItem * it = getFirst(); it != 0; it = getNext( it ) ) + if ( it->isSelected() && ( it->name() != ".." ) ) names->append( it->name() ); + + // if all else fails, take the current item + QString item = getCurrentItem(); + if ( names->empty() && item!=QString::null && item!=".." ) names->append( item ); +} + +void KrView::getSelectedKrViewItems( KrViewItemList *items ) { + for ( KrViewItem * it = getFirst(); it != 0; it = getNext( it ) ) + if ( it->isSelected() && ( it->name() != ".." ) ) items->append( it ); + + // if all else fails, take the current item + QString item = getCurrentItem(); + if ( items->empty() && item!=QString::null && item!=".." ) items->append( getCurrentKrViewItem() ); +} + +QString KrView::statistics() { + _countSize = _numSelected = _selectedSize = 0; + + for ( KrViewItem * it = getFirst(); it != 0; it = getNext( it ) ){ + if ( it->isSelected() ) { + ++_numSelected; + _selectedSize += it->getVfile()->vfile_getSize(); + } + if (it->getVfile()->vfile_getSize() > 0) + _countSize += it->getVfile()->vfile_getSize(); + } + QString tmp = QString(i18n("%1 out of %2, %3 (%4) out of %5 (%6)")) + .arg( _numSelected ).arg( _count ).arg( KIO::convertSize( _selectedSize ) ) + .arg( KRpermHandler::parseSize(_selectedSize) ) + .arg( KIO::convertSize( _countSize ) ).arg( KRpermHandler::parseSize(_countSize) ); + // notify if we're running a filtered view + if (filter() != KrViewProperties::All) + tmp = ">> [ " + filterMask().nameFilter() + " ] "+tmp; + return tmp; +} + +void KrView::changeSelection( const KRQuery& filter, bool select, bool includeDirs ) { + KConfigGroupSaver grpSvr( _config, "Look&Feel" ); + bool markDirs = _config->readBoolEntry( "Mark Dirs", _MarkDirs ) || includeDirs; + + KrViewItem *temp = getCurrentKrViewItem(); + for ( KrViewItem * it = getFirst(); it != 0; it = getNext( it ) ) { + if ( it->name() == ".." ) continue; + if ( it->getVfile()->vfile_isDir() && !markDirs ) continue; + + vfile * file = it->getMutableVfile(); // filter::match calls getMimetype which isn't const + if( file == 0 ) continue; + + if( filter.match( file ) ) { + // we're increasing/decreasing the number of selected files + if ( select ) { + if ( !it->isSelected() ) { + ++_numSelected; + _selectedSize += it->getVfile()->vfile_getSize(); + } + } else { + if ( it->isSelected() ) { + --_numSelected; + _selectedSize -= it->getVfile()->vfile_getSize(); + } + } + it->setSelected( select ); + } + } + updateView(); + makeItemVisible( temp ); +} + +void KrView::invertSelection() { + KConfigGroupSaver grpSvr( _config, "Look&Feel" /*nameInKConfig()*/ ); + bool markDirs = _config->readBoolEntry( "Mark Dirs", _MarkDirs ); + + KrViewItem *temp = getCurrentKrViewItem(); + for ( KrViewItem * it = getFirst(); it != 0; it = getNext( it ) ) { + if ( it->name() == ".." ) continue; + if ( it->getVfile()->vfile_isDir() && !markDirs && !it->isSelected() ) continue; + if ( it->isSelected() ) { + --_numSelected; + _selectedSize -= it->getVfile()->vfile_getSize(); + } else { + ++_numSelected; + _selectedSize += it->getVfile()->vfile_getSize(); + } + it->setSelected( !it->isSelected() ); + } + updateView(); + makeItemVisible( temp ); +} + +QString KrView::firstUnmarkedBelowCurrent() { + KrViewItem * iterator = getNext( getCurrentKrViewItem() ); + while ( iterator && iterator->isSelected() ) + iterator = getNext( iterator ); + if ( !iterator ) { + iterator = getPrev( getCurrentKrViewItem() ); + while ( iterator && iterator->isSelected() ) + iterator = getPrev( iterator ); + } + if ( !iterator ) return QString::null; + return iterator->name(); +} + +void KrView::delItem(const QString &name) { + KrViewItem * it = _dict[ name ]; + if ( !it ) { + krOut << "got signal deletedVfile(" << name << ") but can't find KrViewItem" << endl; + return; + } + if (!preDelItem(it)) return; // do not delete this after all + + // remove from dict + if (it->VF->vfile_isDir()) { + --_numDirs; + } else { + _countSize -= it->VF->vfile_getSize(); + } + --_count; + _dict.remove( name ); + delete it; + op()->emitSelectionChanged(); +} + +KrViewItem *KrView::addItem( vfile *vf ) { + KrViewItem *item = preAddItem(vf); + if (!item) return 0; // don't add it after all + + // add to dictionary + _dict.insert( vf->vfile_getName(), item ); + if ( vf->vfile_isDir() ) + ++_numDirs; + else _countSize += vf->vfile_getSize(); + ++_count; + + if (item->name() == nameToMakeCurrent() ) { + setCurrentItem(item->name()); // dictionary based - quick + makeItemVisible( item ); + } + if (item->name() == nameToMakeCurrentIfAdded() ) { + setCurrentItem(item->name()); + setNameToMakeCurrentIfAdded(QString::null); + makeItemVisible( item ); + } + + + op()->emitSelectionChanged(); + return item; +} + +void KrView::updateItem(vfile *vf) { + // since we're deleting the item, make sure we keep + // it's properties first and repair it later + KrViewItem * it = _dict[ vf->vfile_getName() ]; + if ( !it ) { + krOut << "got signal updatedVfile(" << vf->vfile_getName() << ") but can't find KrViewItem" << endl; + } else { + bool selected = it->isSelected(); + bool current = ( getCurrentKrViewItem() == it ); + delItem( vf->vfile_getName() ); + KrViewItem *updatedItem = addItem( vf ); + // restore settings + ( _dict[ vf->vfile_getName() ] ) ->setSelected( selected ); + if ( current ) { + setCurrentItem( vf->vfile_getName() ); + makeItemVisible( updatedItem ); + } + } + op()->emitSelectionChanged(); +} + +void KrView::clear() { + _count = _numSelected = _numDirs = _selectedSize = _countSize = 0; + _dict.clear(); +} + +// good old dialog box +void KrView::renameCurrentItem() { + QString newName, fileName; + + KrViewItem *it = getCurrentKrViewItem(); + if ( it ) fileName = it->name(); + else return ; // quit if no current item available + + // don't allow anyone to rename .. + if ( fileName == ".." ) return ; + + bool ok = false; + newName = KInputDialog::getText( i18n( "Rename" ), i18n( "Rename " ) + fileName + i18n( " to:" ), + fileName, &ok, krApp ); + // if the user canceled - quit + if ( !ok || newName == fileName ) + return ; + op()->emitRenameItem(it->name(), newName); +} + diff --git a/krusader/Panel/krview.h b/krusader/Panel/krview.h new file mode 100644 index 0000000..a7c0932 --- /dev/null +++ b/krusader/Panel/krview.h @@ -0,0 +1,245 @@ +/*************************************************************************** + krview.h + ------------------- + copyright : (C) 2000-2002 by Shie Erlich & Rafi Yanai + 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 KRVIEW_H +#define KRVIEW_H + +#include +#include +#include +#include "../krusader.h" +#include "../VFS/vfile.h" +#include "../VFS/vfs.h" +#include "../VFS/krquery.h" + +#include + +class KrView; +class KrViewItem; +typedef QValueList KrViewItemList; + +// KrViewProperties +// This class is an interface class between KrView and KrViewItem +// In order for KrViewItem to be as independant as possible, KrView holds +// an instance of this class, and fills it with the correct data. A reference +// to this should be given to each KrViewItem, which then queries it for +// information regarding how things should be displayed in the current view. +// +// Every property that the item needs to know about the view must be here! +class KrViewProperties { +public: + enum SortSpec { Name=0x1, Ext=0x2, Size=0x4, Type=0x8, Modified=0x10, Permissions=0x20, + KrPermissions=0x40, Owner=0x80, Group=0x100, Descending=0x200, + DirsFirst=0x400, IgnoreCase=0x800, AlwaysSortDirsByName=0x1000 }; + enum FilterSpec { Dirs=0x1, Files=0x2, All=0x3, Custom=0x4, ApplyToDirs=0x8 }; + + bool displayIcons; // true if icons should be displayed in this view + SortSpec sortMode; // sort specifications + FilterSpec filter; // what items to show (all, custom, exec) + KRQuery filterMask; // what items to show (*.cpp, *.h etc) + bool localeAwareCompareIsCaseSensitive; // mostly, it is not! depends on LC_COLLATE + bool humanReadableSize; // display size as KB, MB or just as a long number + QStringList atomicExtensions; // list of strings, which will be treated as one extension. Must start with a dot. +}; + +// operator can handle two ways of doing things: +// 1. if the view is a widget (inherits krview and klistview for example) +// 2. if the view HAS A widget (a krview-son has a member of klistview) +// this is done by specifying the view and the widget in the constructor, +// even if they are actually the same object (specify it twice in that case) +class KrViewOperator: public QObject { + Q_OBJECT +public: + KrViewOperator(KrView *view, QWidget *widget); + ~KrViewOperator(); + KrView *view() const { return _view; } + QWidget *widget() const { return _widget; } + void startDrag(); + + void emitSelectionChanged() { emit selectionChanged(); } + void emitGotDrop(QDropEvent *e) { emit gotDrop(e); } + void emitLetsDrag(QStringList items, QPixmap icon ) { emit letsDrag(items, icon); } + void emitItemDescription(QString &desc) { emit itemDescription(desc); } + void emitContextMenu(const QPoint &point) { emit contextMenu(point); } + void emitEmptyContextMenu(const QPoint &point) { emit emptyContextMenu(point); } + void emitRenameItem(const QString &oldName, const QString &newName) { emit renameItem(oldName, newName); } + void emitExecuted( QString &name ) { emit executed(name); } + void emitNeedFocus() { emit needFocus(); } + +signals: + void selectionChanged(); + void gotDrop( QDropEvent *e ); + void letsDrag( QStringList items, QPixmap icon ); + void itemDescription( QString &desc ); + void contextMenu( const QPoint &point ); + void emptyContextMenu( const QPoint& point ); + void renameItem( const QString &oldName, const QString &newName ); + void executed( QString &name ); + void needFocus(); + + +protected: + // never delete those + KrView *_view; + QWidget *_widget; +}; + +/**************************************************************************** + * READ THIS FIRST: Using the view + * + * You always hold a pointer to KrView, thus you can only use functions declared + * in this class. If you need something else, either this class is missing something + * or you are ;-) Using a true name (like dynamic_cast) should be + * needed only when doing new(), or connect() - see example in listpanel.cpp + * + * The functions you'd usually want: + * 1) getSelectedItems - returns all selected items, or (if none) the current item. + * it never returns anything which includes the "..", and thus can return an empty list! + * 2) getSelectedKrViewItems - the same as (1), but returns a QValueList with KrViewItems + * 3) getCurrentItem, setCurrentItem - work with QString + * 4) getFirst, getNext, getPrev, getCurrentKrViewItem - all work with KrViewItems, and + * used to iterate through a list of items. note that getNext and getPrev accept a pointer + * to the current item (used in detailedview for safe iterating), thus your loop should be: + * for (KrViewItem *it = view->getFirst(); it!=0; it = view->getNext(it)) { blah; } + * 5) nameToMakeCurrent(), setNameToMakeCurrent() - work with QString + * + * IMPORTANT NOTE: every one who subclasses this must call initProperties() in the constructor !!! + */ +class KrView { +friend class KrViewItem; +public: + // instantiating a new view + // 1. new KrView + // 2. view->init() + // notes: constructor does as little as possible, setup() does the rest. esp, note that + // if you need something from operator or properties, move it into setup() + virtual void init(); + +protected: + virtual void initProperties() { qFatal("Please implement your own initProperties() method"); } + virtual void initOperator() { qFatal("Please implement your own initOperator() method"); } + virtual void setup() { qFatal("Please implement your own setup() method"); } + + /////////////////////////////////////////////////////// + // Every view must implement the following functions // + /////////////////////////////////////////////////////// +public: + virtual KrViewItem *getFirst() = 0; + virtual KrViewItem *getLast() = 0; + virtual KrViewItem *getNext(KrViewItem *current) = 0; + virtual KrViewItem *getPrev(KrViewItem *current) = 0; + virtual KrViewItem *getCurrentKrViewItem() = 0; + virtual KrViewItem *getKrViewItemAt(const QPoint &vp) = 0; + virtual KrViewItem *findItemByName(const QString &name) = 0; + virtual void addItems(vfs* v, bool addUpDir = true) = 0; // kill me, kill me now + virtual QString getCurrentItem() const = 0; + virtual void setCurrentItem(const QString& name) = 0; + virtual void makeItemVisible(const KrViewItem *item) = 0; + virtual void clear(); + virtual void updateView() = 0; + virtual void updateItem(KrViewItem* item) = 0; + virtual void sort() = 0; + virtual void saveSettings() = 0; + virtual void restoreSettings() = 0; + virtual void prepareForActive() { _focused = true; } + virtual void prepareForPassive() { _focused = false; } + virtual void renameCurrentItem(); // Rename current item. returns immediatly + virtual QString nameInKConfig() const { return _nameInKConfig; } + +protected: + virtual KrViewItem *preAddItem(vfile *vf) = 0; + virtual bool preDelItem(KrViewItem *item) = 0; + +public: + ////////////////////////////////////////////////////// + // the following functions are already implemented, // + // and normally - should NOT be re-implemented. // + ////////////////////////////////////////////////////// + virtual KrViewItem *addItem(vfile *vf); + virtual void updateItem(vfile *vf); + virtual void delItem(const QString &name); + virtual uint numSelected() const { return _numSelected; } + virtual KIO::filesize_t selectedSize() const { return _selectedSize; } + virtual uint numFiles() const { return _count-_numDirs; } + virtual uint numDirs() const { return _numDirs; } + virtual uint count() const { return _count; } + virtual KIO::filesize_t countSize() const { return _countSize; } + virtual void getSelectedItems(QStringList* names); + virtual void getItemsByMask(QString mask, QStringList* names, bool dirs = true, bool files = true); + virtual void getSelectedKrViewItems(KrViewItemList *items); + virtual void selectAllIncludingDirs() { changeSelection( KRQuery( "*" ), true, true); } + virtual void select( const KRQuery& filter = KRQuery( "*" ) ) { changeSelection(filter, true); } + virtual void unselect(const KRQuery& filter = KRQuery( "*" ) ) { changeSelection(filter, false); } + virtual void invertSelection(); + virtual QString nameToMakeCurrent() const { return _nameToMakeCurrent; } + virtual void setNameToMakeCurrent(const QString name) { _nameToMakeCurrent = name; } + virtual QString nameToMakeCurrentIfAdded() const { return _nameToMakeCurrentIfAdded; } + virtual void setNameToMakeCurrentIfAdded(const QString name) { _nameToMakeCurrentIfAdded = name; } + virtual QString firstUnmarkedBelowCurrent(); + virtual QString statistics(); + virtual const KrViewProperties* properties() const { return _properties; } + virtual KrViewOperator* op() const { return _operator; } + + ///////////////////////////////////////////////////////////// + // the following functions have a default and minimalistic // + // implementation, and may be re-implemented if needed // + ///////////////////////////////////////////////////////////// + virtual void setSortMode(KrViewProperties::SortSpec mode) { _properties->sortMode = mode; } + virtual KrViewProperties::SortSpec sortMode() const { return _properties->sortMode; } + virtual void setFilter(KrViewProperties::FilterSpec filter) { _properties->filter = filter; } + virtual KrViewProperties::FilterSpec filter() const { return _properties->filter; } + virtual void setFilterMask( KRQuery mask ) { _properties->filterMask = mask; } + virtual const KRQuery& filterMask() const { return _properties->filterMask; } + inline QWidget *widget() { return _widget; } + inline void setWidget(QWidget *w) { _widget = w; } + + // todo: what about selection modes ??? + virtual ~KrView(); +protected: + KrView(KConfig *cfg = krConfig); + static QPixmap getIcon(vfile *vf); + void changeSelection(const KRQuery& filter, bool select, bool includeDirs = false); + + +protected: + KConfig *_config; + QWidget *_widget; + QString _nameToMakeCurrent; + QString _nameToMakeCurrentIfAdded; + uint _numSelected, _count, _numDirs; + KIO::filesize_t _countSize, _selectedSize; + bool _left; + KrViewProperties *_properties; + KrViewOperator *_operator; + QDict _dict; + bool _focused; + QString _nameInKConfig; +}; + +#endif /* KRVIEW_H */ diff --git a/krusader/Panel/krviewitem.cpp b/krusader/Panel/krviewitem.cpp new file mode 100644 index 0000000..28500d4 --- /dev/null +++ b/krusader/Panel/krviewitem.cpp @@ -0,0 +1,105 @@ +#include "krviewitem.h" +#include "../VFS/krpermhandler.h" +#include +#include +#include +#include +#include + +#define PROPS static_cast(_viewProperties) + +QString atomicExtensions[] = { + ".tar.gz", + ".tar.bz2", + ".moc.cpp" +}; + +KrViewItem::KrViewItem(vfile *vf, const KrViewProperties* properties): + _vf(vf), dummyVfile(false), _viewProperties(properties), _hasExtension(false), _hidden(false), _extension("") { + if (vf) { + // check if the file has an extension + const QString& vfName = vf->vfile_getName(); + int loc = vfName.findRev('.'); + if (loc>0) { // avoid mishandling of .bashrc and friend + // check if it has one of the predefined 'atomic extensions' + for (QStringList::const_iterator i = PROPS->atomicExtensions.begin(); i != PROPS->atomicExtensions.end(); ++i) { + if (vfName.endsWith(*i)){ + loc = vfName.length() - (*i).length(); + break; + } + } + _name = vfName.left(loc); + _extension = vfName.mid(loc+1); + _hasExtension=true; + } + + if( vfName.startsWith(".") ) + _hidden = true; + } +} + +const QString& KrViewItem::name(bool withExtension) const { + if (!withExtension && _hasExtension) return _name; + else return _vf->vfile_getName(); +} + +QString KrViewItem::description() const { + if (dummyVfile) return i18n("Climb up the directory tree"); + // else is implied + QString text = _vf->vfile_getName(); + QString comment = KMimeType::mimeType(_vf->vfile_getMime())->comment(text, false); + QString myLinkDest = _vf->vfile_getSymDest(); + KIO::filesize_t mySize = _vf->vfile_getSize(); + + QString text2 = text.copy(); + mode_t m_fileMode = _vf->vfile_getMode(); + + if (_vf->vfile_isSymLink() ){ + QString tmp; + if ( comment.isEmpty() ) tmp = i18n ( "Symbolic Link" ) ; + else if( _vf->vfile_getMime() == "Broken Link !" ) tmp = i18n("(broken link !)"); + else tmp = i18n("%1 (Link)").arg(comment); + + text += "->"; + text += myLinkDest; + text += " "; + text += tmp; + } else if ( S_ISREG( m_fileMode ) ){ + text = QString("%1 (%2)").arg(text2).arg( PROPS->humanReadableSize ? + KRpermHandler::parseSize(_vf->vfile_getSize()) : KIO::convertSize( mySize ) ); + text += " "; + text += comment; + } else if ( S_ISDIR ( m_fileMode ) ){ + text += "/ "; + text += comment; + } else { + text += " "; + text += comment; + } + return text; +} + +QString KrViewItem::dateTime() const { + // convert the time_t to struct tm + time_t time = _vf->vfile_getTime_t(); + struct tm* t=localtime((time_t *)&time); + + QDateTime tmp(QDate(t->tm_year+1900, t->tm_mon+1, t->tm_mday), QTime(t->tm_hour, t->tm_min)); + return KGlobal::locale()->formatDateTime(tmp); +} + +QPixmap KrViewItem::icon() { +#if 0 + QPixmap *p; + + // This is bad - very bad. the function must return a valid reference, + // This is an interface flow - shie please fix it with a function that return QPixmap* + // this way we can return 0 - and do our error checking... + + // shie answers: why? what's the difference? if we return an empty pixmap, others can use it as it + // is, without worrying or needing to do error checking. empty pixmap displays nothing +#endif + if (dummyVfile || !_viewProperties->displayIcons) + return QPixmap(); + else return KrView::getIcon(_vf); +} diff --git a/krusader/Panel/krviewitem.h b/krusader/Panel/krviewitem.h new file mode 100644 index 0000000..2294b28 --- /dev/null +++ b/krusader/Panel/krviewitem.h @@ -0,0 +1,76 @@ +/*************************************************************************** + krviewitem.h + ------------------- + copyright : (C) 2000-2002 by Shie Erlich & Rafi Yanai + 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 KRVIEWITEM_H +#define KRVIEWITEM_H + +#include +#include +#include "../VFS/vfile.h" +#include "krview.h" + +class QString; +class QPixmap; + +class KrViewItem { + friend class KrView; + +public: + virtual const QString& name(bool withExtension=true) const; + virtual inline bool hasExtension() const { return _hasExtension; } + virtual inline const QString& extension() const { return _extension; } + virtual QString dateTime() const; + virtual QString description() const; + virtual bool isSelected() const = 0; + virtual void setSelected( bool s ) = 0; + virtual QPixmap icon(); + + KrViewItem(vfile *vf, const KrViewProperties* properties); + virtual ~KrViewItem() { if (dummyVfile) delete _vf; } + + // DON'T USE THOSE OUTSIDE THE VIEWS!!! + inline const vfile* getVfile() const { return _vf; } + inline vfile* getMutableVfile() { return _vf; } + inline bool isDummy() const { return dummyVfile; } + inline bool isHidden() const { return _hidden; } + +protected: + // used INTERNALLY when calculation of dir size changes the displayed size of the item + inline void setSize(KIO::filesize_t size) { _vf->vfile_setSize(size); } + + vfile* _vf; // each view item holds a pointer to a corrosponding vfile for fast access + bool dummyVfile; // used in case our item represents the ".." (updir) item + const KrViewProperties* _viewProperties; + bool _hasExtension; + bool _hidden; + QString _name; + QString _extension; +}; + +#endif diff --git a/krusader/Panel/listpanel.cpp b/krusader/Panel/listpanel.cpp new file mode 100644 index 0000000..5972eaf --- /dev/null +++ b/krusader/Panel/listpanel.cpp @@ -0,0 +1,1115 @@ +/*************************************************************************** + listpanel.cpp + ------------------- +copyright : (C) 2000 by Shie Erlich & Rafi Yanai +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 +#include +// QT includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +// KDE includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Krusader includes +#include "../krusader.h" +#include "../krslots.h" +#include "panelfunc.h" +#include "../kicons.h" +#include "../VFS/krpermhandler.h" +#include "listpanel.h" +#include "../krusaderview.h" +#include "../panelmanager.h" +#include "../defaults.h" +#include "../resources.h" +#include "../MountMan/kmountman.h" +#include "../Dialogs/krdialogs.h" +#include "../BookMan/krbookmarkbutton.h" +#include "../Dialogs/krspwidgets.h" +#include "../Dialogs/krspecialwidgets.h" +#include "../GUI/kcmdline.h" +#include "../Dialogs/percentalsplitter.h" +#include "krdetailedview.h" +#include "krbriefview.h" +#include "krpreviewpopup.h" +#include "../GUI/dirhistorybutton.h" +#include "../GUI/dirhistoryqueue.h" +#include "../GUI/mediabutton.h" +#include "../GUI/syncbrowsebutton.h" +#include "../krservices.h" +#include "panelpopup.h" +#include "../UserAction/useractionpopupmenu.h" +#include "../Dialogs/popularurls.h" +#include "krpopupmenu.h" + +#ifdef __LIBKONQ__ +#include +#include +#endif + +typedef QValueList OfferList; + +#define URL(X) KURL::fromPathOrURL(X) + +///////////////////////////////////////////////////// +// The list panel constructor // +///////////////////////////////////////////////////// +ListPanel::ListPanel( QString typeIn, QWidget *parent, bool &left, const char *name ) : + QWidget( parent, name ), panelType( typeIn ), colorMask( 255 ), compareMode( false ), currDragItem( 0 ), statsAgent( 0 ), + quickSearch( 0 ), cdRootButton( 0 ), cdUpButton( 0 ), popupBtn(0), popup(0),inlineRefreshJob(0), _left( left ) { + + func = new ListPanelFunc( this ); + setAcceptDrops( true ); + layout = new QGridLayout( this, 3, 3 ); + + mediaButton = new MediaButton( this, "mediaButton" ); + connect( mediaButton, SIGNAL( pressed() ), this, SLOT( slotFocusOnMe() ) ); + connect( mediaButton, SIGNAL( openUrl( const KURL& ) ), func, SLOT( openUrl( const KURL& ) ) ); + + status = new KrSqueezedTextLabel( this ); + krConfig->setGroup( "Look&Feel" ); + status->setFont( krConfig->readFontEntry( "Filelist Font", _FilelistFont ) ); + status->setBackgroundMode( PaletteBackground ); + status->setFrameStyle( QFrame::Box | QFrame::Raised ); + status->setLineWidth( 1 ); // a nice 3D touch :-) + status->setText( "" ); // needed for initialization code! + status->enableDrops( true ); + int sheight = QFontMetrics( status->font() ).height() + 4; + status->setMaximumHeight( sheight ); + QWhatsThis::add + ( status, i18n( "The statusbar displays information about the FILESYSTEM " + "which holds your current directory: Total size, free space, " + "type of filesystem, etc." ) ); + connect( status, SIGNAL( clicked() ), this, SLOT( slotFocusOnMe() ) ); + connect( status, SIGNAL( dropped( QDropEvent *) ), this, SLOT( handleDropOnStatus(QDropEvent *) ) ); + + // ... create the history button + dirHistoryQueue = new DirHistoryQueue( this ); + historyButton = new DirHistoryButton( dirHistoryQueue, this, "historyButton" ); + connect( historyButton, SIGNAL( pressed() ), this, SLOT( slotFocusOnMe() ) ); + connect( historyButton, SIGNAL( openUrl( const KURL& ) ), func, SLOT( openUrl( const KURL& ) ) ); + + bookmarksButton = new KrBookmarkButton(this); + connect( bookmarksButton, SIGNAL( pressed() ), this, SLOT( slotFocusOnMe() ) ); + connect( bookmarksButton, SIGNAL( openUrl( const KURL& ) ), func, SLOT( openUrl( const KURL& ) ) ); + QWhatsThis::add + ( bookmarksButton, i18n( "Open menu with bookmarks. You can also add " + "current location to the list, edit bookmarks " + "or add subfolder to the list." ) ); + + QHBoxLayout *totalsLayout = new QHBoxLayout; + totals = new KrSqueezedTextLabel( this ); + krConfig->setGroup( "Look&Feel" ); + totals->setFont( krConfig->readFontEntry( "Filelist Font", _FilelistFont ) ); + totals->setFrameStyle( QFrame::Box | QFrame::Raised ); + totals->setBackgroundMode( PaletteBackground ); + totals->setLineWidth( 1 ); // a nice 3D touch :-) + totals->setMaximumHeight( sheight ); + totals->enableDrops( true ); + QWhatsThis::add + ( totals, i18n( "The totals bar shows how many files exist, " + "how many selected and the bytes math" ) ); + connect( totals, SIGNAL( clicked() ), this, SLOT( slotFocusOnMe() ) ); + connect( totals, SIGNAL( dropped( QDropEvent *) ), this, SLOT( handleDropOnTotals(QDropEvent *) ) ); + + // a cancel button for the inplace refresh mechanism + inlineRefreshCancelButton = new KPushButton(this); + inlineRefreshCancelButton->setFixedSize( 22, 20 ); + inlineRefreshCancelButton->setPixmap(krLoader->loadIcon("cancel", KIcon::Toolbar, 16)); + connect(inlineRefreshCancelButton, SIGNAL(clicked()), this, SLOT(inlineRefreshCancel())); + + // a quick button to open the popup panel + popupBtn = new QToolButton( this, "popupbtn" ); + popupBtn->setFixedSize( 22, 20 ); + popupBtn->setPixmap(krLoader->loadIcon("1uparrow", KIcon::Toolbar, 16)); + connect(popupBtn, SIGNAL(clicked()), this, SLOT(togglePanelPopup())); + QToolTip::add( popupBtn, i18n( "Open the popup panel" ) ); + totalsLayout->addWidget(totals); + totalsLayout->addWidget(inlineRefreshCancelButton); inlineRefreshCancelButton->hide(); + totalsLayout->addWidget(popupBtn); + + quickSearch = new KrQuickSearch( this ); + krConfig->setGroup( "Look&Feel" ); + quickSearch->setFont( krConfig->readFontEntry( "Filelist Font", _FilelistFont ) ); + quickSearch->setFrameStyle( QFrame::Box | QFrame::Raised ); + quickSearch->setLineWidth( 1 ); // a nice 3D touch :-) + quickSearch->setMaximumHeight( sheight ); + + QHBox * hbox = new QHBox( this ); + + // clear-origin button + bool clearButton = krConfig->readBoolEntry("Clear Location Bar Visible", _ClearLocation); + if (clearButton){ + clearOrigin = new QToolButton(hbox, "clearorigin"); + clearOrigin->setPixmap(krLoader->loadIcon("locationbar_erase", KIcon::Toolbar, 16)); + QToolTip::add( clearOrigin, i18n( "Clear the location bar" ) ); + } + + QuickNavLineEdit *qnle = new QuickNavLineEdit(this); + origin = new KURLRequester( qnle, hbox ); + QPixmap pixMap = origin->button() ->iconSet() ->pixmap( QIconSet::Small, QIconSet::Normal ); + origin->button() ->setFixedSize( pixMap.width() + 4, pixMap.height() + 4 ); + QWhatsThis::add + ( origin, i18n( "Use superb KDE file dialog to choose location. " ) ); + origin->setShowLocalProtocol( false ); + origin->lineEdit() ->setURLDropsEnabled( true ); + origin->lineEdit() ->installEventFilter( this ); + QWhatsThis::add + ( origin->lineEdit(), i18n( "Name of directory where you are. You can also " + "enter name of desired location to move there. " + "Use of Net protocols like ftp or fish is possible." ) ); + origin->setMode( KFile::Directory | KFile::ExistingOnly ); + connect( origin, SIGNAL( returnPressed( const QString& ) ), func, SLOT( openUrl( const QString& ) ) ); + connect( origin, SIGNAL( returnPressed( const QString& ) ), this, SLOT( slotFocusOnMe() ) ); + connect( origin, SIGNAL( urlSelected( const QString& ) ), func, SLOT( openUrl( const QString& ) ) ); + connect( origin, SIGNAL( urlSelected( const QString& ) ), this, SLOT( slotFocusOnMe() ) ); + + // this is here on purpose, do not move up! + if (clearButton) { + clearOrigin->setFixedSize( 20, origin->button() ->height() ); + connect(clearOrigin, SIGNAL(clicked()), origin->lineEdit(), SLOT(clear())); + connect(clearOrigin, SIGNAL(clicked()), origin->lineEdit(), SLOT(setFocus())); + } + // + + cdOtherButton = new QToolButton( hbox, "cdOtherButton" ); + cdOtherButton->setFixedSize( 20, origin->button() ->height() ); + cdOtherButton->setText( i18n( "=" ) ); + QToolTip::add( cdOtherButton, i18n( "Equal" ) ); + connect( cdOtherButton, SIGNAL( clicked() ), this, SLOT( slotFocusAndCDOther() ) ); + + cdUpButton = new QToolButton( hbox, "cdUpButton" ); + cdUpButton->setFixedSize( 20, origin->button() ->height() ); + cdUpButton->setText( i18n( ".." ) ); + QToolTip::add( cdUpButton, i18n( "Up" ) ); + connect( cdUpButton, SIGNAL( clicked() ), this, SLOT( slotFocusAndCDup() ) ); + + cdHomeButton = new QToolButton( hbox, "cdHomeButton" ); + cdHomeButton->setFixedSize( 20, origin->button() ->height() ); + cdHomeButton->setText( i18n( "~" ) ); + QToolTip::add( cdHomeButton, i18n( "Home" ) ); + connect( cdHomeButton, SIGNAL( clicked() ), this, SLOT( slotFocusAndCDHome() ) ); + + cdRootButton = new QToolButton( hbox, "cdRootButton" ); + cdRootButton->setFixedSize( 20, origin->button() ->height() ); + cdRootButton->setText( i18n( "/" ) ); + QToolTip::add( cdRootButton, i18n( "Root" ) ); + connect( cdRootButton, SIGNAL( clicked() ), this, SLOT( slotFocusAndCDRoot() ) ); + + // ... creates the button for sync-browsing + syncBrowseButton = new SyncBrowseButton( hbox ); + + setPanelToolbar(); + + header = new QHeader( this ); + header->hide(); + + // create a splitter to hold the view and the popup + splt = new PercentalSplitter(this); + splt->setChildrenCollapsible(true); + splt->setOrientation(QObject::Vertical); + + createView(); + + // make sure that a focus/path change reflects in the command line and activePanel + connect( this, SIGNAL( cmdLineUpdate( QString ) ), SLOTS, SLOT( slotCurrentChanged( QString ) ) ); + connect( this, SIGNAL( activePanelChanged( ListPanel * ) ), SLOTS, SLOT( slotSetActivePanel( ListPanel * ) ) ); + + // add a popup + popup = new PanelPopup(splt, left); + connect(popup, SIGNAL(selection(const KURL&)), SLOTS, SLOT(refresh(const KURL&))); + connect(popup, SIGNAL(hideMe()), this, SLOT(togglePanelPopup())); + popup->hide(); + + // finish the layout + layout->addMultiCellWidget( hbox, 0, 0, 0, 3 ); + layout->addWidget( mediaButton, 1, 0 ); + layout->addWidget( status, 1, 1 ); + layout->addWidget( historyButton, 1, 2 ); + layout->addWidget( bookmarksButton, 1, 3 ); + layout->addMultiCellWidget( header, 2, 2, 0, 3 ); + layout->addMultiCellWidget( splt, 3, 3, 0, 3 ); + layout->addMultiCellWidget( quickSearch, 4, 4, 0, 3 ); + quickSearch->hide(); + layout->addMultiCellLayout( totalsLayout, 5, 5, 0, 3 ); + //filter = ALL; +} + +void ListPanel::createView() +{ + header->hide(); + if( panelType == "Brief" ) + { + view = new KrBriefView( header, splt, _left, krConfig ); + view->init(); + + connect( dynamic_cast( view ), SIGNAL( middleButtonClicked( KrViewItem * ) ), SLOTS, SLOT( newTab( KrViewItem * ) ) ); + connect( dynamic_cast( view ), SIGNAL( currentChanged( KrViewItem * ) ), + SLOTS, SLOT( updatePopupPanel( KrViewItem* ) ) ); + + // connect quicksearch + connect( quickSearch, SIGNAL( textChanged( const QString& ) ), + dynamic_cast( view ), SLOT( quickSearch( const QString& ) ) ); + connect( quickSearch, SIGNAL( otherMatching( const QString&, int ) ), + dynamic_cast( view ), SLOT( quickSearch( const QString& , int ) ) ); + connect( quickSearch, SIGNAL( stop( QKeyEvent* ) ), + dynamic_cast( view ), SLOT( stopQuickSearch( QKeyEvent* ) ) ); + connect( quickSearch, SIGNAL( process( QKeyEvent* ) ), + dynamic_cast( view ), SLOT( handleQuickSearchEvent( QKeyEvent* ) ) ); + } else { /* Detailed */ + panelType = "Detailed"; + view = new KrDetailedView( splt, _left, krConfig ); + view->init(); + connect( dynamic_cast( view ), SIGNAL( middleButtonClicked( KrViewItem * ) ), SLOTS, SLOT( newTab( KrViewItem * ) ) ); + connect( dynamic_cast( view ), SIGNAL( currentChanged( KrViewItem * ) ), + SLOTS, SLOT( updatePopupPanel( KrViewItem * ) ) ); + // connect quicksearch + connect( quickSearch, SIGNAL( textChanged( const QString& ) ), + dynamic_cast( view ), SLOT( quickSearch( const QString& ) ) ); + connect( quickSearch, SIGNAL( otherMatching( const QString&, int ) ), + dynamic_cast( view ), SLOT( quickSearch( const QString& , int ) ) ); + connect( quickSearch, SIGNAL( stop( QKeyEvent* ) ), + dynamic_cast( view ), SLOT( stopQuickSearch( QKeyEvent* ) ) ); + connect( quickSearch, SIGNAL( process( QKeyEvent* ) ), + dynamic_cast( view ), SLOT( handleQuickSearchEvent( QKeyEvent* ) ) ); + } + + connect( view->op(), SIGNAL( renameItem( const QString &, const QString & ) ), + func, SLOT( rename( const QString &, const QString & ) ) ); + connect( view->op(), SIGNAL( executed( QString& ) ), func, SLOT( execute( QString& ) ) ); + connect( view->op(), SIGNAL( needFocus() ), this, SLOT( slotFocusOnMe() ) ); + connect( view->op(), SIGNAL( selectionChanged() ), this, SLOT( slotUpdateTotals() ) ); + connect( view->op(), SIGNAL( itemDescription( QString& ) ), krApp, SLOT( statusBarUpdate( QString& ) ) ); + connect( view->op(), SIGNAL( contextMenu( const QPoint & ) ), this, SLOT( popRightClickMenu( const QPoint & ) ) ); + connect( view->op(), SIGNAL( emptyContextMenu( const QPoint &) ), + this, SLOT( popEmptyRightClickMenu( const QPoint & ) ) ); + connect( view->op(), SIGNAL( letsDrag( QStringList, QPixmap ) ), this, SLOT( startDragging( QStringList, QPixmap ) ) ); + connect( view->op(), SIGNAL( gotDrop( QDropEvent * ) ), this, SLOT( handleDropOnView( QDropEvent * ) ) ); +} + +void ListPanel::changeType( const QString & type ) +{ + if( panelType != type ) + { + panelType = type; + delete view; + createView(); + + slotStartUpdate(); + + if( panelType == "Brief" ) + dynamic_cast( view )->show(); + else /* Detailed */ + dynamic_cast( view )->show(); + } +} + +ListPanel::~ListPanel() { + delete func; + delete view; + delete status; + delete bookmarksButton; + delete totals; + delete quickSearch; + delete origin; + delete cdRootButton; + delete cdHomeButton; + delete cdUpButton; + delete cdOtherButton; + delete syncBrowseButton; + delete layout; +} + +int ListPanel::getProperties() +{ + int props = 0; + if( syncBrowseButton->state() == SYNCBROWSE_CD ) + props |= PROP_SYNC_BUTTON_ON; + return props; +} + +void ListPanel::setProperties( int prop ) +{ + if( prop & PROP_SYNC_BUTTON_ON ) + syncBrowseButton->setOn( true ); + else + syncBrowseButton->setOn( false ); +} + +bool ListPanel::eventFilter ( QObject * watched, QEvent * e ) { + if( e->type() == QEvent::KeyPress && origin->lineEdit() == watched ) { + QKeyEvent *ke = (QKeyEvent *)e; + + if( ( ke->key() == Key_Down ) && ( ke->state() == ControlButton ) ) { + slotFocusOnMe(); + return true; + } + } + return false; +} + + +void ListPanel::togglePanelPopup() { + if (popup->isHidden()) { + if (popupSizes.count() > 0) { + dynamic_cast(popup->parent())->setSizes(popupSizes); + } else { // on the first time, resize to 50% + QValueList lst; + lst << height()/2 << height()/2; + dynamic_cast(popup->parent())->setSizes(lst); + } + + popup->show(); + popupBtn->setPixmap(krLoader->loadIcon("1downarrow", KIcon::Toolbar, 16)); + QToolTip::add( popupBtn, i18n( "Close the popup panel" ) ); + } else { + popupSizes.clear(); + popupSizes = dynamic_cast(popup->parent())->sizes(); + popup->hide(); + popupBtn->setPixmap(krLoader->loadIcon("1uparrow", KIcon::Toolbar, 16)); + QToolTip::add( popupBtn, i18n( "Open the popup panel" ) ); + + QValueList lst; + lst << height() << 0; + dynamic_cast(popup->parent())->setSizes(lst); + if( ACTIVE_PANEL ) + ACTIVE_PANEL->slotFocusOnMe(); + } +} + +KURL ListPanel::virtualPath() const { + return func->files()->vfs_getOrigin(); +} + +QString ListPanel::realPath() const { + return _realPath.path(); +} + + +void ListPanel::setPanelToolbar() { + krConfig->setGroup( "Look&Feel" ); + + bool panelToolBarVisible = krConfig->readBoolEntry( "Panel Toolbar visible", _PanelToolBar ); + + if ( panelToolBarVisible && ( krConfig->readBoolEntry( "Root Button Visible", _cdRoot ) ) ) + cdRootButton->show(); + else + cdRootButton->hide(); + + if ( panelToolBarVisible && ( krConfig->readBoolEntry( "Home Button Visible", _cdHome ) ) ) + cdHomeButton->show(); + else + cdHomeButton->hide(); + + if ( panelToolBarVisible && ( krConfig->readBoolEntry( "Up Button Visible", _cdUp ) ) ) + cdUpButton->show(); + else + cdUpButton->hide(); + + if ( panelToolBarVisible && ( krConfig->readBoolEntry( "Equal Button Visible", _cdOther ) ) ) + cdOtherButton->show(); + else + cdOtherButton->hide(); + + if ( !panelToolBarVisible || ( krConfig->readBoolEntry( "Open Button Visible", _Open ) ) ) + origin->button() ->show(); + else + origin->button() ->hide(); + + if ( panelToolBarVisible && ( krConfig->readBoolEntry( "SyncBrowse Button Visible", _syncBrowseButton ) ) ) + syncBrowseButton->show(); + else + syncBrowseButton->hide(); +} + +void ListPanel::slotUpdateTotals() { + totals->setText( view->statistics() ); +} + +void ListPanel::slotFocusAndCDOther() { + slotFocusOnMe(); + func->openUrl( otherPanel->func->files() ->vfs_getOrigin() ); + +} + +void ListPanel::slotFocusAndCDHome() { + slotFocusOnMe(); + func->openUrl( QString( "~" ), QString::null ); +} + +void ListPanel::slotFocusAndCDup() { + slotFocusOnMe(); + func->dirUp(); +} + +void ListPanel::slotFocusAndCDRoot() { + slotFocusOnMe(); + func->openUrl( QString( "/" ), QString::null ); +} + +void ListPanel::select( KRQuery query, bool select) { + if ( !query.isNull() ) { + if ( select ) + view->select( query ); + else + view->unselect( query ); + } +} + +void ListPanel::select( bool select, bool all ) { + if ( all ) + { + if ( select ) + view->select( KRQuery( "*" ) ); + else + view->unselect( KRQuery( "*" ) ); + } + else { + KRQuery query = KRSpWidgets::getMask( ( select ? i18n( " Select Files " ) : i18n( " Unselect Files " ) ) ); + // if the user canceled - quit + if ( query.isNull() ) + return ; + if ( select ) + view->select( query ); + else + view->unselect( query ); + } +} + +void ListPanel::invertSelection() { + view->invertSelection(); +} + +void ListPanel::compareDirs() { + krConfig->setGroup( "Private" ); + int compareMode = krConfig->readNumEntry( "Compare Mode", 0 ); + krConfig->setGroup( "Look&Feel" ); + bool selectDirs = krConfig->readBoolEntry( "Mark Dirs", false ); + + KrViewItem *item, *otherItem; + + for( item = view->getFirst(); item != 0; item = view->getNext( item ) ) + { + if( item->name() == ".." ) + continue; + + for( otherItem = otherPanel->view->getFirst(); otherItem != 0 && otherItem->name() != item->name() ; + otherItem = otherPanel->view->getNext( otherItem ) ); + + bool isSingle = ( otherItem == 0 ), isDifferent = false, isNewer = false; + + if( func->getVFile(item)->vfile_isDir() && !selectDirs ) + { + item->setSelected( false ); + continue; + } + + if( otherItem ) + { + if( !func->getVFile(item)->vfile_isDir() ) + isDifferent = ITEM2VFILE(otherPanel,otherItem)->vfile_getSize() != func->getVFile(item)->vfile_getSize(); + isNewer = func->getVFile(item)->vfile_getTime_t() > ITEM2VFILE(otherPanel, otherItem)->vfile_getTime_t(); + } + + switch( compareMode ) + { + case 0: + item->setSelected( isNewer || isSingle ); + break; + case 1: + item->setSelected( isNewer ); + break; + case 2: + item->setSelected( isSingle ); + break; + case 3: + item->setSelected( isDifferent || isSingle ); + break; + case 4: + item->setSelected( isDifferent ); + break; + } + } + + view->updateView(); +} + +void ListPanel::slotFocusOnMe() { + // give this VFS the focus (the path bar) + // we start by calling the KVFS function + krConfig->setGroup( "Look&Feel" ); + + // take care of the 'otherpanel' + QPalette q( otherPanel->status->palette() ); + q.setColor( QColorGroup::Foreground, KGlobalSettings::textColor() ); + q.setColor( QColorGroup::Background, KGlobalSettings::baseColor() ); + + otherPanel->status->setPalette( q ); + otherPanel->totals->setPalette( q ); + otherPanel->view->prepareForPassive(); + + // now, take care of this panel + QPalette p( status->palette() ); + p.setColor( QColorGroup::Foreground, KGlobalSettings::highlightedTextColor() ); + p.setColor( QColorGroup::Background, KGlobalSettings::highlightColor() ); + status->setPalette( p ); + totals->setPalette( p ); + + view->prepareForActive(); + emit cmdLineUpdate( realPath() ); + emit activePanelChanged( this ); + + func->refreshActions(); + + Krusader::actDetailedView->setEnabled( panelType != "Detailed" ); // enable/disable the detailed view action + Krusader::actBriefView->setEnabled( panelType != "Brief" ); // enable/disable the brief view action + + if( panelType == "Brief" ) + { + KrBriefView * v = dynamic_cast( view ); + if ( v ) + v->refreshColors(); + } + else /* detailed */ + { + KrDetailedView * v = dynamic_cast( view ); + if ( v ) + v->refreshColors(); + } + + if( otherPanel->panelType == "Brief" ) + { + KrBriefView * v = dynamic_cast( otherPanel->view ); + if ( v ) + v->refreshColors(); + } + else /* detailed */ + { + KrDetailedView *v = dynamic_cast( otherPanel->view ); + if ( v ) + v->refreshColors(); + } +} + +// this is used to start the panel, AFTER setOther() has been used +////////////////////////////////////////////////////////////////// +void ListPanel::start( KURL url, bool immediate ) { + KURL virt; + + virt = url; + + if ( !virt.isValid() ) + virt = URL("/"); + if( virt.isLocalFile() ) _realPath = virt; + else _realPath = URL("/"); + + if( immediate ) + func->immediateOpenUrl( virt ); + else + func->openUrl( virt ); + + slotFocusOnMe(); + setJumpBack( virt ); +} + +void ListPanel::slotStartUpdate() { + while ( func->inRefresh ) + ; // wait until the last refresh finish + func->inRefresh = true; // make sure the next refresh wait for this one + if (inlineRefreshJob) + inlineRefreshListResult(0); + + if( this == ACTIVE_PANEL ){ + slotFocusOnMe(); + } + + setCursor( KCursor::workingCursor() ); + view->clear(); + + if ( func->files() ->vfs_getType() == vfs::NORMAL ) + _realPath = virtualPath(); + this->origin->setURL( vfs::pathOrURL( virtualPath() ) ); + emit pathChanged( this ); + emit cmdLineUpdate( realPath() ); // update the command line + + slotGetStats( virtualPath() ); + slotUpdate(); + if ( compareMode ) { + otherPanel->view->clear(); + otherPanel->slotUpdate(); + } + // return cursor to normal arrow + setCursor( KCursor::arrowCursor() ); + slotUpdateTotals(); + krApp->popularUrls->addUrl(virtualPath()); +} + +void ListPanel::slotUpdate() { + // if we are not at the root add the ".." entery + QString protocol = func->files() ->vfs_getOrigin().protocol(); + bool isFtp = ( protocol == "ftp" || protocol == "smb" || protocol == "sftp" || protocol == "fish" ); + + QString origin = virtualPath().prettyURL(-1); + if ( origin.right( 1 ) != "/" && !( ( func->files() ->vfs_getType() == vfs::FTP ) && isFtp && + origin.find( '/', origin.find( ":/" ) + 3 ) == -1 ) ) { + view->addItems( func->files() ); + } else + view->addItems( func->files(), false ); + + func->inRefresh = false; +} + + +void ListPanel::slotGetStats( const KURL& url ) { + if ( !url.isLocalFile() ) { + status->setText( i18n( "No space information on non-local filesystems" ) ); + return ; + } + + // check for special filesystems; + QString path = url.path(); // must be local url + if ( path.left(4) == "/dev") { + status->setText(i18n( "No space information on [dev]" )); + return; + } +#if defined(BSD) + if ( path.left( 5 ) == "/procfs" ) { // /procfs is a special case - no volume information + status->setText(i18n( "No space information on [procfs]" )); + return; + } +#else + if ( path.left( 5 ) == "/proc" ) { // /proc is a special case - no volume information + status->setText(i18n( "No space information on [proc]" )); + return; + } +#endif + + status->setText( i18n( "Mt.Man: working ..." ) ); + statsAgent = KDiskFreeSp::findUsageInfo( path ); + connect( statsAgent, SIGNAL( foundMountPoint( const QString &, unsigned long, unsigned long, unsigned long ) ), + this, SLOT( gotStats( const QString &, unsigned long, unsigned long, unsigned long ) ) ); +} + +void ListPanel::gotStats( const QString &mountPoint, unsigned long kBSize, + unsigned long, unsigned long kBAvail ) { + int perc = 0; + if (kBSize != 0) { // make sure that if totalsize==0, then perc=0 + perc = (int)(((float)kBAvail / (float)kBSize)*100.0); + } + // mount point information - find it in the list first + KMountPoint::List lst = KMountPoint::currentMountPoints(); + QString fstype = i18n("unknown"); + for (KMountPoint::List::iterator it = lst.begin(); it != lst.end(); ++it) { + if ((*it)->mountPoint() == mountPoint) { + fstype = (*it)->mountType(); + break; + } + } + + QString stats = i18n( "%1 free out of %2 (%3%) on %4 [ (%5) ]" ) + .arg( KIO::convertSizeFromKB( kBAvail ) ) + .arg( KIO::convertSizeFromKB( kBSize ) ).arg( perc ) + .arg( mountPoint ).arg( fstype ); + status->setText( stats ); +} + +void ListPanel::handleDropOnTotals( QDropEvent *e ) { + handleDropOnView( e, totals ); +} + +void ListPanel::handleDropOnStatus( QDropEvent *e ) { + handleDropOnView( e, status ); +} + +void ListPanel::handleDropOnView( QDropEvent *e, QWidget *widget ) { + // if copyToPanel is true, then we call a simple vfs_addfiles + bool copyToDirInPanel = false; + bool dragFromOtherPanel = false; + bool dragFromThisPanel = false; + bool isWritable = func->files() ->vfs_isWritable(); + + vfs* tempFiles = func->files(); + vfile *file; + KrViewItem *i = 0; + if( widget == 0 ) + { + i = view->getKrViewItemAt( e->pos() ); + widget = this; + } + + if ( e->source() == otherPanel ) + dragFromOtherPanel = true; + if ( e->source() == this ) + dragFromThisPanel = true; + + if ( i ) { + file = func->files() ->vfs_search( i->name() ); + + if ( !file ) { // trying to drop on the ".." + copyToDirInPanel = true; + } else { + if ( file->vfile_isDir() ) { + copyToDirInPanel = true; + isWritable = file->vfile_isWriteable(); + if ( isWritable ) { + // keep the folder_open icon until we're finished, do it only + // if the folder is writeable, to avoid flicker + } + } else + if ( e->source() == this ) + return ; // no dragging onto ourselves + } + } else // if dragged from this panel onto an empty spot in the panel... + if ( dragFromThisPanel ) { // leave! + e->ignore(); + return ; + } + + if ( !isWritable && getuid() != 0 ) { + e->ignore(); + KMessageBox::sorry( 0, i18n( "Can't drop here, no write permissions." ) ); + return ; + } + ////////////////////////////////////////////////////////////////////////////// + // decode the data + KURL::List URLs; + if ( !KURLDrag::decode( e, URLs ) ) { + e->ignore(); // not for us to handle! + return ; + } + + bool isLocal = true; + for( unsigned u = 0; u != URLs.count(); u++ ) + if( !URLs[ u ].isLocalFile() ) { + isLocal = false; + break; + } + + KIO::CopyJob::CopyMode mode = KIO::CopyJob::Copy; + + // the KURL::List is finished, let's go + // --> display the COPY/MOVE/LINK menu + QPopupMenu popup( this ); + popup.insertItem( i18n( "Copy Here" ), 1 ); + if ( func->files() ->vfs_isWritable() ) + popup.insertItem( i18n( "Move Here" ), 2 ); + if ( func->files() ->vfs_getType() == vfs::NORMAL && + isLocal ) + popup.insertItem( i18n( "Link Here" ), 3 ); + popup.insertItem( i18n( "Cancel" ), 4 ); + QPoint tmp = widget->mapToGlobal( e->pos() ); + int result = popup.exec( tmp ); + switch ( result ) { + case 1 : + mode = KIO::CopyJob::Copy; + break; + case 2 : + mode = KIO::CopyJob::Move; + break; + case 3 : + mode = KIO::CopyJob::Link; + break; + case - 1 : // user pressed outside the menu + case 4: + return ; // cancel was pressed; + } + + QString dir = ""; + if ( copyToDirInPanel ) { + dir = i->name(); + } + QWidget *notify = ( !e->source() ? 0 : e->source() ); + tempFiles->vfs_addFiles( &URLs, mode, notify, dir ); +} + +void ListPanel::startDragging( QStringList names, QPixmap px ) { + KURL::List * urls = func->files() ->vfs_getFiles( &names ); + + if ( urls->isEmpty() ) { // avoid draging empty urls + delete urls; + return ; + } + + KURLDrag *d = new KURLDrag(*urls, this); + d->setPixmap( px, QPoint( -7, 0 ) ); + d->dragCopy(); + + delete urls; // free memory +} + +// pops a right-click menu for items +void ListPanel::popRightClickMenu( const QPoint &loc ) { + // run it, on the mouse location + int j = QFontMetrics( font() ).height() * 2; + KrPopupMenu::run(QPoint( loc.x() + 5, loc.y() + j ), this); +} + +void ListPanel::popEmptyRightClickMenu( const QPoint &loc ) { + KrPopupMenu::run(loc, this); +} + +void ListPanel::setFilter( KrViewProperties::FilterSpec f ) { + switch ( f ) { + case KrViewProperties::All : + //case KrView::EXEC: + break; + case KrViewProperties::Custom : + filterMask = KRSpWidgets::getMask( i18n( " Select Files " ) ); + // if the user canceled - quit + if ( filterMask.isNull() ) + return; + view->setFilterMask( filterMask ); + break; + default: + return ; + } + view->setFilter( f ); // do that in any case + func->files()->vfs_invalidate(); + func->refresh(); +} + +QString ListPanel::getCurrentName() { + QString name = view->getCurrentItem(); + if ( name != ".." ) + return name; + else + return QString::null; +} + +void ListPanel::prepareToDelete() { + view->setNameToMakeCurrent( view->firstUnmarkedBelowCurrent() ); +} + +void ListPanel::keyPressEvent( QKeyEvent *e ) { + switch ( e->key() ) { + case Key_Enter : + case Key_Return : + if ( e->state() & ControlButton ) { + if (e->state() & AltButton) { + vfile *vf = func->files()->vfs_search(view->getCurrentKrViewItem()->name()); + if (vf && vf->vfile_isDir()) SLOTS->newTab(vf->vfile_getUrl()); + } else { + SLOTS->insertFileName( ( e->state() & ShiftButton ) != 0 ); + } + } else e->ignore(); + break; + case Key_Right : + case Key_Left : + if ( e->state() == ControlButton ) { + // user pressed CTRL+Right/Left - refresh other panel to the selected path if it's a + // directory otherwise as this one + if ( ( _left && e->key() == Key_Right ) || ( !_left && e->key() == Key_Left ) ) { + KURL newPath; + KrViewItem *it = view->getCurrentKrViewItem(); + + if( it->name() == ".." ) { + newPath = func->files()->vfs_getOrigin().upURL(); + } else { + vfile *v = func->getVFile( it ); + if ( v && v->vfile_isDir() && v->vfile_getName() != ".." ) { + newPath = v->vfile_getUrl(); + } else { + newPath = func->files() ->vfs_getOrigin(); + } + } + otherPanel->func->openUrl( newPath ); + } else func->openUrl( otherPanel->func->files() ->vfs_getOrigin() ); + return ; + } else + e->ignore(); + break; + + case Key_Down : + if ( e->state() == ControlButton ) { // give the keyboard focus to the command line + if ( MAIN_VIEW->cmdLine->isVisible() ) + MAIN_VIEW->cmdLineFocus(); + else + MAIN_VIEW->focusTerminalEmulator(); + return ; + } else if ( e->state() == ( ControlButton | ShiftButton ) ) { // give the keyboard focus to TE + MAIN_VIEW->focusTerminalEmulator(); + } else + e->ignore(); + break; + + case Key_Up : + if ( e->state() == ControlButton ) { // give the keyboard focus to the command line + origin->lineEdit()->setFocus(); + return ; + } else + e->ignore(); + break; + + default: + // if we got this, it means that the view is not doing + // the quick search thing, so send the characters to the commandline, if normal key + if ( e->state() == NoButton ) + MAIN_VIEW->cmdLine->addText( e->text() ); + + //e->ignore(); + } +} + +void ListPanel::slotItemAdded(vfile *vf) { + view->addItem(vf); +} + +void ListPanel::slotItemDeleted(const QString& name) { + view->delItem(name); +} + +void ListPanel::slotItemUpdated(vfile *vf) { + view->updateItem(vf); +} + +void ListPanel::slotCleared() { + view->clear(); +} + +void ListPanel::showEvent( QShowEvent *e ) { + panelActive(); + QWidget::showEvent(e); +} + +void ListPanel::hideEvent( QHideEvent *e ) { + panelInactive(); + QWidget::hideEvent(e); +} + +void ListPanel::panelActive() { + // don't refresh when not active (ie: hidden, application isn't focussed ...) + func->files()->vfs_enableRefresh(true); +} + +void ListPanel::panelInactive() { + func->files()->vfs_enableRefresh(false); +} + +void ListPanel::slotJobStarted(KIO::Job* job) { + // disable the parts of the panel we don't want touched + //static_cast(view)->setEnabled(false); + status->setEnabled(false); + origin->setEnabled(false); + cdRootButton->setEnabled(false); + cdHomeButton->setEnabled(false); + cdUpButton->setEnabled(false); + cdOtherButton->setEnabled(false); + popupBtn->setEnabled(false); + popup->setEnabled(false); + bookmarksButton->setEnabled(false); + historyButton->setEnabled(false); + syncBrowseButton->setEnabled(false); + + // connect to the job interface to provide in-panel refresh notification + connect( job, SIGNAL( infoMessage( KIO::Job*, const QString & ) ), + SLOT( inlineRefreshInfoMessage( KIO::Job*, const QString & ) ) ); + connect( job, SIGNAL( percent( KIO::Job*, unsigned long ) ), + SLOT( inlineRefreshPercent( KIO::Job*, unsigned long ) ) ); + connect(job,SIGNAL(result(KIO::Job*)), + this,SLOT(inlineRefreshListResult(KIO::Job*))); + connect(job,SIGNAL(canceled(KIO::Job*)), + this,SLOT(inlineRefreshListResult(KIO::Job*))); + + inlineRefreshJob = job; + + totals->setText(i18n(">> Reading...")); + inlineRefreshCancelButton->show(); +} + +void ListPanel::inlineRefreshCancel() { + if (inlineRefreshJob) { + inlineRefreshJob->kill(false); + inlineRefreshJob = 0; + } +} + +void ListPanel::inlineRefreshPercent( KIO::Job*, unsigned long perc) { + QString msg = QString(">> %1: %2 % complete...").arg(i18n("Reading")).arg(perc); + totals->setText(msg); +} + +void ListPanel::inlineRefreshInfoMessage( KIO::Job*, const QString &msg ) { + totals->setText(">> " + i18n("Reading: ") + msg); +} + +void ListPanel::inlineRefreshListResult(KIO::Job*) { + inlineRefreshJob = 0; + // reenable everything + //static_cast(view)->setEnabled(true); + status->setEnabled(true); + origin->setEnabled(true); + cdRootButton->setEnabled(true); + cdHomeButton->setEnabled(true); + cdUpButton->setEnabled(true); + cdOtherButton->setEnabled(true); + popupBtn->setEnabled(true); + popup->setEnabled(true); + bookmarksButton->setEnabled(true); + historyButton->setEnabled(true); + syncBrowseButton->setEnabled(true); + + inlineRefreshCancelButton->hide(); +} + +void ListPanel::jumpBack() { + func->openUrl( _jumpBackURL ); +} + +void ListPanel::setJumpBack( KURL url ) { + _jumpBackURL = url; +} + +#include "listpanel.moc" diff --git a/krusader/Panel/listpanel.h b/krusader/Panel/listpanel.h new file mode 100644 index 0000000..088fdfd --- /dev/null +++ b/krusader/Panel/listpanel.h @@ -0,0 +1,211 @@ +/*************************************************************************** + listpanel.h + ------------------- + begin : Thu May 4 2000 + copyright : (C) 2000 by Shie Erlich & Rafi Yanai + 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 LISTPANEL_H +#define LISTPANEL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "krview.h" +#include "../Dialogs/krsqueezedtextlabel.h" + +// use our version of it, until kde fixes theirs +#include "../MountMan/kdiskfreesp.h" + +#define PROP_SYNC_BUTTON_ON 1 + +class vfs; +class vfile; +class KRdirWatch; +class KrView; +class KURLRequester; +class BookmarksButton; +class KrQuickSearch; +class DirHistoryButton; +class DirHistoryQueue; +class MediaButton; +class PanelPopup; +class SyncBrowseButton; +class KrBookmarkButton; +class KPushButton; +class ListPanelFunc; +class QHeader; + +class ListPanel : public QWidget { + friend class ListPanelFunc; + Q_OBJECT +public: + #define ITEM2VFILE(PANEL_PTR, KRVIEWITEM) PANEL_PTR->func->files()->vfs_search(KRVIEWITEM->name()) + #define NAME2VFILE(PANEL_PTR, STRING_NAME) PANEL_PTR->func->files()->vfs_search(STRING_NAME) + // constructor create the panel, but DOESN'T fill it with data, use start() + ListPanel( QString panelType, QWidget *parent, bool &left, const char *name = 0 ); + ~ListPanel(); + void start( KURL url = KURL(), bool immediate = false ); + + const QString & getType() { return panelType; } + void changeType( const QString & ); + + KURL virtualPath() const; + QString realPath() const; + QString getCurrentName(); + void getSelectedNames( QStringList* fileNames ) { + view->getSelectedItems( fileNames ); + } + void setPanelToolbar(); + bool isLeft() {return _left;} + void jumpBack(); + void setJumpBack( KURL url ); + + int getProperties(); + void setProperties( int ); + +public slots: + void gotStats( const QString &mountPoint, unsigned long kBSize, unsigned long kBUsed, unsigned long kBAvail); // displays filesystem status + void popRightClickMenu( const QPoint& ); + void popEmptyRightClickMenu( const QPoint & ); + void select( KRQuery query, bool select); + void select( bool, bool ); // see doc in ListPanel + void invertSelection(); // see doc in ListPanel + void compareDirs(); + void slotFocusOnMe(); // give this VFS the focus (the path bar) + void slotUpdate(); // when the vfs finish to update... + void slotUpdateTotals(); + void slotStartUpdate(); // internal + void slotGetStats( const KURL& url ); // get the disk-free stats + void setFilter( KrViewProperties::FilterSpec f ); + void slotFocusAndCDRoot(); + void slotFocusAndCDHome(); + void slotFocusAndCDup(); + void slotFocusAndCDOther(); + void togglePanelPopup(); + // for signals from vfs' dirwatch + void slotItemAdded(vfile *vf); + void slotItemDeleted(const QString& name); + void slotItemUpdated(vfile *vf); + void slotCleared(); + void panelActive(); // called when the panel becomes active + void panelInactive(); // called when panel becomes inactive + + + ///////////////////////// service functions - called internally //////////////////////// + inline void setOther( ListPanel *panel ) { + otherPanel = panel; + } + void prepareToDelete(); // internal use only + +protected: + virtual void keyPressEvent( QKeyEvent *e ); + virtual void showEvent( QShowEvent * ); + virtual void hideEvent( QHideEvent * ); + virtual bool eventFilter ( QObject * watched, QEvent * e ); + + void createView(); + +protected slots: + void handleDropOnView(QDropEvent *, QWidget *destWidget=0); // handles drops on the view only + void handleDropOnTotals( QDropEvent * ); // handles drops on the totals line + void handleDropOnStatus( QDropEvent * ); // handles drops on the status line + void startDragging( QStringList, QPixmap ); + // those handle the in-panel refresh notifications + void slotJobStarted(KIO::Job* job); + void inlineRefreshInfoMessage( KIO::Job* job, const QString &msg ); + void inlineRefreshListResult(KIO::Job* job); + void inlineRefreshPercent( KIO::Job*, unsigned long ); + void inlineRefreshCancel(); + +signals: + void signalStatus( QString msg ); // emmited when we need to update the status bar + void cmdLineUpdate( QString p ); // emitted when we need to update the command line + void pathChanged( ListPanel *panel ); + void activePanelChanged( ListPanel *p ); // emitted when the user changes panels + void finishedDragging(); // currently + +public: + QString panelType; + ListPanelFunc *func; + KrView *view; + ListPanel *otherPanel; + int colorMask; + bool compareMode; + //FilterSpec filter; + KRQuery filterMask; + QPixmap currDragPix; + QListViewItem *currDragItem; + KDiskFreeSp* statsAgent; + KrSqueezedTextLabel *status, *totals; + KrQuickSearch *quickSearch; + KURLRequester *origin; + QGridLayout *layout; + QToolButton *cdRootButton; + QToolButton *cdHomeButton; + QToolButton *cdUpButton; + QToolButton *cdOtherButton; + QToolButton *popupBtn; + QToolButton *clearOrigin; + PanelPopup *popup; + KrBookmarkButton *bookmarksButton; + DirHistoryQueue* dirHistoryQueue; + DirHistoryButton* historyButton; + MediaButton *mediaButton; + SyncBrowseButton *syncBrowseButton; + KPushButton *inlineRefreshCancelButton; + KIO::Job *inlineRefreshJob; + QSplitter *splt; + QHeader * header; + +protected: + KURL _realPath; // named with _ to keep realPath() compatability + KURL _jumpBackURL; + + +private: + bool &_left; + QValueList popupSizes; +}; + +#endif diff --git a/krusader/Panel/panelfunc.cpp b/krusader/Panel/panelfunc.cpp new file mode 100755 index 0000000..735a0cf --- /dev/null +++ b/krusader/Panel/panelfunc.cpp @@ -0,0 +1,1186 @@ +/*************************************************************************** + panelfunc.cpp + ------------------- +copyright : (C) 2000 by Shie Erlich & Rafi Yanai +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 +// Qt Includes +#include +#include +#include +#include +// KDE Includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// Krusader Includes +#include "panelfunc.h" +#include "krcalcspacedialog.h" +#include "krdetailedview.h" +#include "../krusader.h" +#include "../krslots.h" +#include "../defaults.h" +#include "../VFS/vfile.h" +#include "../VFS/vfs.h" +#include "../VFS/virt_vfs.h" +#include "../VFS/krarchandler.h" +#include "../VFS/krpermhandler.h" +#include "../VFS/krvfshandler.h" +#include "../VFS/preservingcopyjob.h" +#include "../VFS/virtualcopyjob.h" +#include "../Dialogs/packgui.h" +#include "../Dialogs/krdialogs.h" +#include "../Dialogs/krpleasewait.h" +#include "../Dialogs/krspwidgets.h" +#include "../Dialogs/checksumdlg.h" +#include "../KViewer/krviewer.h" +#include "../resources.h" +#include "../krservices.h" +#include "../GUI/syncbrowsebutton.h" +#include "../Queue/queue_mgr.h" +#include "krdrag.h" +#include + +////////////////////////////////////////////////////////// +////// ---------- List Panel ------------- //////// +////////////////////////////////////////////////////////// + +ListPanelFunc::ListPanelFunc( ListPanel *parent ) : +panel( parent ), inRefresh( false ), vfsP( 0 ) { + urlStack.push( "file:/" ); + connect( &delayTimer, SIGNAL( timeout() ), this, SLOT( doOpenUrl() ) ); +} + +void ListPanelFunc::openUrl( const QString& url, const QString& nameToMakeCurrent ) { + openUrl( vfs::fromPathOrURL( + // KURLRequester is buggy: it should return a string containing "/home/shie/downloads" + // but it returns "~/downloads" which is parsed incorrectly by vfs::fromPathOrURL. + // replacedPath should replace ONLY $HOME and environment variables + panel->origin->completionObject()->replacedPath(url) ) + , nameToMakeCurrent ); +} + +void ListPanelFunc::immediateOpenUrl( const KURL& urlIn ) { + KURL url = urlIn; + url.cleanPath(); + + // check for special cases first - don't refresh here ! + // you may call openUrl or vfs_refresh() + if ( !url.isValid() ) { + if ( url.url() == "~" ) { + return openUrl( QDir::homeDirPath() ); + } else if ( !url.url().startsWith( "/" ) ) { + // possible relative URL - translate to full URL + url = files() ->vfs_getOrigin(); + url.addPath( urlIn.url() ); + //kdDebug()<< urlIn.url() << "," << url.url() <slotStartUpdate(); // refresh the panel + return ; + } + } + + // if we are not refreshing to current URL + bool is_equal_url = files() ->vfs_getOrigin().equals( url, true ); + + if ( !is_equal_url ) { + // change the cursor to busy + panel->setCursor( KCursor::waitCursor() ); + } + + if ( !nameToMakeCurrent.isEmpty() ) { + panel->view->setNameToMakeCurrent( nameToMakeCurrent ); + // if the url we're refreshing into is the current one, then the + // partial url will not generate the needed signals to actually allow the + // view to use nameToMakeCurrent. do it here instead (patch by Thomas Jarosch) + if ( is_equal_url ) { + panel->view->setCurrentItem( nameToMakeCurrent ); + panel->view->makeItemVisible( panel->view->getCurrentKrViewItem() ); + } + } + + vfs* v = 0; + if ( !urlStack.top().equals( url ) ) + urlStack.push( url ); + // count home many urls is in the stack, so later on, we'll know if the refresh was a success + uint stackSize = urlStack.size(); + bool refreshFailed = true; // assume the worst + while ( true ) { + KURL u = urlStack.pop(); + //u.adjustPath(-1); // remove trailing "/" + u.cleanPath(); // Resolves "." and ".." components in path. + v = KrVfsHandler::getVfs( u, panel, files() ); + if ( !v ) + continue; //this should not happen ! + if ( v != vfsP ) { + if( vfsP->vfs_canDelete() ) + delete vfsP; + else { + connect( vfsP, SIGNAL( deleteAllowed() ), vfsP, SLOT( deleteLater() ) ); + vfsP->vfs_requestDelete(); + } + vfsP = v; // v != 0 so this is safe + } else { + if( vfsP->vfs_isBusy() ) + { + delayURL = url; /* this function is useful for FTP url-s and bookmarks */ + delayTimer.start( 100, true ); /* if vfs is busy try refreshing later */ + return; + } + } + connect( files(), SIGNAL(startJob(KIO::Job* )), + panel, SLOT(slotJobStarted(KIO::Job* ))); + if ( vfsP->vfs_refresh( u ) ) { + break; // we have a valid refreshed URL now + } + if ( vfsP == 0 ) // the object was deleted during vfs_refresh? Hoping the best... + return; + // prevent repeated error messages + if ( vfsP->vfs_isDeleting() ) + break; + vfsP->vfs_setQuiet( true ); + } + vfsP->vfs_setQuiet( false ); + + // if we popped exactly 1 url from the stack, it means the url we were + // given was refreshed successfully. + if (stackSize == urlStack.size() + 1) + refreshFailed = false; + + // update the urls stack + if ( !files() ->vfs_getOrigin().equals( urlStack.top() ) ) { + urlStack.push( files() ->vfs_getOrigin() ); + } + // disconnect older signals + disconnect( files(), SIGNAL( addedVfile( vfile* ) ), 0, 0 ); + disconnect( files(), SIGNAL( updatedVfile( vfile* ) ), 0, 0 ); + disconnect( files(), SIGNAL( deletedVfile( const QString& ) ), 0, 0 ); + disconnect( files(), SIGNAL( cleared() ), 0, 0 ); + // connect to the vfs's dirwatch signals + connect( files(), SIGNAL( addedVfile( vfile* ) ), + panel, SLOT( slotItemAdded( vfile* ) ) ); + connect( files(), SIGNAL( updatedVfile( vfile* ) ), + panel, SLOT( slotItemUpdated( vfile* ) ) ); + connect( files(), SIGNAL( deletedVfile( const QString& ) ), + panel, SLOT( slotItemDeleted( const QString& ) ) ); + connect( files(), SIGNAL( cleared() ), + panel, SLOT( slotCleared() ) ); + + // on local file system change the working directory + if ( files() ->vfs_getType() == vfs::NORMAL ) + chdir( files() ->vfs_getOrigin().path().local8Bit() ); + + // see if the open url operation failed, and if so, + // put the attempted url in the origin bar and let the user change it + if (refreshFailed) { + panel->origin->setURL(urlIn.prettyURL()); + panel->origin->setFocus(); + } +} + +void ListPanelFunc::openUrl( const KURL& url, const QString& nameToMakeCurrent ) { + panel->inlineRefreshCancel(); + // first the other dir, then the active! Else the focus changes and the other becomes active + if ( panel->syncBrowseButton->state() == SYNCBROWSE_CD ) { + // prevents that the sync-browsing circles itself to death + static bool inSync = false; + if( ! inSync ){ + inSync = true; + //do sync-browse stuff.... + KURL otherDir = OTHER_PANEL->virtualPath(); + OTHER_FUNC->files() ->vfs_setQuiet( true ); + // the trailing slash is nessesary because krusader provides Dir's without it + // we can't use openUrl because the delay don't allow a check if the panel has realy changed! + OTHER_FUNC->immediateOpenUrl( KURL::relativeURL( panel->virtualPath().url() + "/", url.url() ) ); + OTHER_FUNC->files() ->vfs_setQuiet( false ); + // now we need to test ACTIVE_PANEL because the openURL has changed the active panel!! + if ( ACTIVE_PANEL->virtualPath().equals( otherDir ) ) { + // deactivating the sync-browse if syncbrowse not possible + panel->syncBrowseButton->setOn( false ); + } + inSync = false; + } + } + this->nameToMakeCurrent = nameToMakeCurrent; + delayURL = url; /* this function is useful for FTP url-s and bookmarks */ + delayTimer.start( 0, true ); /* to avoid qApp->processEvents() deadlock situaltion */ +} + +void ListPanelFunc::refresh() { + openUrl(panel->virtualPath()); // re-read the files +} + +void ListPanelFunc::doOpenUrl() { + immediateOpenUrl( delayURL ); +} + +void ListPanelFunc::goBack() { + if ( urlStack.isEmpty() ) + return ; + + if ( urlStack.top().equals( files() ->vfs_getOrigin() ) ) + urlStack.pop(); + openUrl( urlStack.top(), files() ->vfs_getOrigin().fileName() ); + + if ( urlStack.isEmpty() ) + krBack->setEnabled( false ); +} + +void ListPanelFunc::redirectLink() { + if ( files() ->vfs_getType() != vfs::NORMAL ) { + KMessageBox::sorry( krApp, i18n( "You can edit links only on local file systems" ) ); + return ; + } + + vfile *vf = files() ->vfs_search( panel->getCurrentName() ); + if ( !vf ) + return ; + + QString file = files() ->vfs_getFile( vf->vfile_getName() ).path( -1 ); + QString currentLink = vf->vfile_getSymDest(); + if ( currentLink.isEmpty() ) { + KMessageBox::sorry( krApp, i18n( "The current file is not a link, so I can't redirect it." ) ); + return ; + } + + // ask the user for a new destination + bool ok = false; + QString newLink = + KInputDialog::getText( i18n( "Link Redirection" ), + i18n( "Please enter the new link destination:" ), currentLink, &ok, krApp ); + + // if the user canceled - quit + if ( !ok || newLink == currentLink ) + return ; + // delete the current link + if ( unlink( file.local8Bit() ) == -1 ) { + KMessageBox::sorry( krApp, i18n( "Can't remove old link: " ) + file ); + return ; + } + // try to create a new symlink + if ( symlink( newLink.local8Bit(), file.local8Bit() ) == -1 ) { + KMessageBox:: /* --=={ Patch by Heiner }==-- */sorry( krApp, i18n( "Failed to create a new link: " ) + file ); + return ; + } +} + +void ListPanelFunc::krlink( bool sym ) { + if ( files() ->vfs_getType() != vfs::NORMAL ) { + KMessageBox::sorry( krApp, i18n( "You can create links only on local file systems" ) ); + return ; + } + + QString name = panel->getCurrentName(); + + // ask the new link name.. + bool ok = false; + QString linkName = + KInputDialog::getText( i18n( "New link" ), i18n( "Create a new link to: " ) + name, name, &ok, krApp ); + + // if the user canceled - quit + if ( !ok || linkName == name ) + return ; + + // if the name is already taken - quit + if ( files() ->vfs_search( linkName ) != 0 ) { + KMessageBox::sorry( krApp, i18n( "A directory or a file with this name already exists." ) ); + return ; + } + + if ( linkName.left( 1 ) != "/" ) + linkName = files() ->vfs_workingDir() + "/" + linkName; + + if ( linkName.contains( "/" ) ) + name = files() ->vfs_getFile( name ).path( -1 ); + + if ( sym ) { + if ( symlink( name.local8Bit(), linkName.local8Bit() ) == -1 ) + KMessageBox::sorry( krApp, i18n( "Failed to create a new symlink: " ) + linkName + + i18n( " To: " ) + name ); + } else { + if ( link( name.local8Bit(), linkName.local8Bit() ) == -1 ) + KMessageBox::sorry( krApp, i18n( "Failed to create a new link: " ) + linkName + + i18n( " To: " ) + name ); + } +} + +void ListPanelFunc::view() { + QString fileName = panel->getCurrentName(); + if ( fileName.isNull() ) + return ; + + // if we're trying to view a directory, just exit + vfile * vf = files() ->vfs_search( fileName ); + if ( !vf || vf->vfile_isDir() ) + return ; + if ( !vf->vfile_isReadable() ) { + KMessageBox::sorry( 0, i18n( "No permissions to view this file." ) ); + return ; + } + // call KViewer. + KrViewer::view( files() ->vfs_getFile( fileName ) ); + // nothing more to it! +} + +void ListPanelFunc::terminal() { + QString save = getcwd( 0, 0 ); + chdir( panel->realPath().local8Bit() ); + + KProcess proc; + krConfig->setGroup( "General" ); + QString term = krConfig->readEntry( "Terminal", _Terminal ); + proc << KrServices::separateArgs( term ); + + if ( term.contains( "konsole" ) ) /* KDE 3.2 bug (konsole is killed by pressing Ctrl+C) */ + { /* Please remove the patch if the bug is corrected */ + proc << "&"; + proc.setUseShell( true ); + } + + if ( !proc.start( KProcess::DontCare ) ) + KMessageBox::sorry( krApp, i18n( "Can't open %1" ).arg(term) ); + + chdir( save.local8Bit() ); +} + +void ListPanelFunc::editFile() { + QString name = panel->getCurrentName(); + if ( name.isNull() ) + return ; + + if ( files() ->vfs_search( name ) ->vfile_isDir() ) { + KMessageBox::sorry( krApp, i18n( "You can't edit a directory" ) ); + return ; + } + + if ( !files() ->vfs_search( name ) ->vfile_isReadable() ) { + KMessageBox::sorry( 0, i18n( "No permissions to edit this file." ) ); + return ; + } + + KrViewer::edit( files() ->vfs_getFile( name ) ); +} + +void ListPanelFunc::moveFiles() { + PreserveMode pmode = PM_DEFAULT; + + QStringList fileNames; + panel->getSelectedNames( &fileNames ); + if ( fileNames.isEmpty() ) + return ; // safety + + KURL dest = panel->otherPanel->virtualPath(); + KURL virtualBaseURL; + + QString destProtocol = dest.protocol(); + if ( destProtocol == "krarc" || destProtocol == "tar" || destProtocol == "zip" ) { + KMessageBox::sorry( krApp, i18n( "Moving into archive is disabled" ) ); + return ; + } + + krConfig->setGroup( "Advanced" ); + if ( krConfig->readBoolEntry( "Confirm Move", _ConfirmMove ) ) { + bool preserveAttrs = krConfig->readBoolEntry( "PreserveAttributes", _PreserveAttributes ); + QString s; + + if( fileNames.count() == 1 ) + s = i18n("Move %1 to:").arg(fileNames.first()); + else + s = i18n("Move %n file to:", "Move %n files to:", fileNames.count()); + + // ask the user for the copy dest + virtualBaseURL = getVirtualBaseURL(); + dest = KChooseDir::getDir(s, dest, panel->virtualPath(), preserveAttrs, virtualBaseURL); + if ( dest.isEmpty() ) return ; // the user canceled + if( preserveAttrs ) + pmode = PM_PRESERVE_ATTR; + else + pmode = PM_NONE; + } + + if ( fileNames.isEmpty() ) + return ; // nothing to copy + + KURL::List* fileUrls = files() ->vfs_getFiles( &fileNames ); + + // after the delete return the cursor to the first unmarked + // file above the current item; + panel->prepareToDelete(); + + if( !virtualBaseURL.isEmpty() ) { + // keep the directory structure for virtual paths + VirtualCopyJob *vjob = new VirtualCopyJob( &fileNames, files(), dest, virtualBaseURL, pmode, KIO::CopyJob::Move, false, true ); + connect( vjob, SIGNAL( result( KIO::Job* ) ), this, SLOT( refresh() ) ); + if ( dest.equals( panel->otherPanel->virtualPath(), true ) ) + connect( vjob, SIGNAL( result( KIO::Job* ) ), panel->otherPanel->func, SLOT( refresh() ) ); + } + // if we are not moving to the other panel : + else if ( !dest.equals( panel->otherPanel->virtualPath(), true ) ) { + // you can rename only *one* file not a batch, + // so a batch dest must alwayes be a directory + if ( fileNames.count() > 1 ) dest.adjustPath(1); + KIO::Job* job = PreservingCopyJob::createCopyJob( pmode, *fileUrls, dest, KIO::CopyJob::Move, false, true ); + job->setAutoErrorHandlingEnabled( true ); + // refresh our panel when done + connect( job, SIGNAL( result( KIO::Job* ) ), this, SLOT( refresh() ) ); + // and if needed the other panel as well + if ( dest.equals( panel->otherPanel->virtualPath(), true ) ) + connect( job, SIGNAL( result( KIO::Job* ) ), panel->otherPanel->func, SLOT( refresh() ) ); + + } else { // let the other panel do the dirty job + //check if copy is supported + if ( !otherFunc() ->files() ->vfs_isWritable() ) { + KMessageBox::sorry( krApp, i18n( "You can't move files to this file system" ) ); + return ; + } + // finally.. + otherFunc() ->files() ->vfs_addFiles( fileUrls, KIO::CopyJob::Move, files(), "", pmode ); + } +} + +// called from SLOTS to begin the renaming process +void ListPanelFunc::rename() { + panel->view->renameCurrentItem(); +} + +// called by signal itemRenamed() from the view to complete the renaming process +void ListPanelFunc::rename( const QString &oldname, const QString &newname ) { + if ( oldname == newname ) + return ; // do nothing + panel->view->setNameToMakeCurrentIfAdded( newname ); + // as always - the vfs do the job + files() ->vfs_rename( oldname, newname ); +} + +void ListPanelFunc::mkdir() { + // ask the new dir name.. + bool ok = false; + QString dirName = + KInputDialog::getText( i18n( "New directory" ), i18n( "Directory's name:" ), "", &ok, krApp ); + + // if the user canceled - quit + if ( !ok || dirName.isEmpty() ) + return ; + + QStringList dirTree = QStringList::split( "/", dirName ); + + for ( QStringList::Iterator it = dirTree.begin(); it != dirTree.end(); ++it ) { + // check if the name is already taken + if ( files() ->vfs_search( *it ) ) { + // if it is the last dir to be created - quit + if ( *it == dirTree.last() ) { + KMessageBox::sorry( krApp, i18n( "A directory or a file with this name already exists." ) ); + return ; + } + // else go into this dir + else { + immediateOpenUrl( *it ); + continue; + } + } + + panel->view->setNameToMakeCurrent( *it ); + // as always - the vfs do the job + files() ->vfs_mkdir( *it ); + if ( dirTree.count() > 1 ) + immediateOpenUrl( *it ); + } // for +} + +KURL ListPanelFunc::getVirtualBaseURL() { + if( files()->vfs_getType() != vfs::VIRT || otherFunc()->files()->vfs_getType() == vfs::VIRT ) + return KURL(); + + QStringList fileNames; + panel->getSelectedNames( &fileNames ); + + KURL::List* fileUrls = files() ->vfs_getFiles( &fileNames ); + if( fileUrls->count() == 0 ) + return KURL(); + + KURL base = (*fileUrls)[ 0 ].upURL(); + + if( base.protocol() == "virt" ) // is it a virtual subfolder? + return KURL(); // --> cannot keep the directory structure + + for( unsigned i=1; i < fileUrls->count(); i++ ) { + if( base.isParentOf( (*fileUrls)[ i ] ) ) + continue; + if( base.protocol() != (*fileUrls)[ i ].protocol() ) + return KURL(); + + do { + KURL oldBase = base; + base = base.upURL(); + if( oldBase.equals( base, true ) ) + return KURL(); + if( base.isParentOf( (*fileUrls)[ i ] ) ) + break; + }while( true ); + } + return base; +} + +void ListPanelFunc::copyFiles() { + PreserveMode pmode = PM_DEFAULT; + + QStringList fileNames; + panel->getSelectedNames( &fileNames ); + if ( fileNames.isEmpty() ) + return ; // safety + + KURL dest = panel->otherPanel->virtualPath(); + KURL virtualBaseURL; + + // confirm copy + krConfig->setGroup( "Advanced" ); + if ( krConfig->readBoolEntry( "Confirm Copy", _ConfirmCopy ) ) { + bool preserveAttrs = krConfig->readBoolEntry( "PreserveAttributes", _PreserveAttributes ); + QString s; + + if( fileNames.count() == 1 ) + s = i18n("Copy %1 to:").arg(fileNames.first()); + else + s = i18n("Copy %n file to:", "Copy %n files to:", fileNames.count()); + + // ask the user for the copy dest + virtualBaseURL = getVirtualBaseURL(); + dest = KChooseDir::getDir(s, dest, panel->virtualPath(), preserveAttrs, virtualBaseURL ); + if ( dest.isEmpty() ) return ; // the user canceled + if( preserveAttrs ) + pmode = PM_PRESERVE_ATTR; + else + pmode = PM_NONE; + } + + KURL::List* fileUrls = files() ->vfs_getFiles( &fileNames ); + + if( !virtualBaseURL.isEmpty() ) { + // keep the directory structure for virtual paths + VirtualCopyJob *vjob = new VirtualCopyJob( &fileNames, files(), dest, virtualBaseURL, pmode, KIO::CopyJob::Copy, false, true ); + connect( vjob, SIGNAL( result( KIO::Job* ) ), this, SLOT( refresh() ) ); + if ( dest.equals( panel->otherPanel->virtualPath(), true ) ) + connect( vjob, SIGNAL( result( KIO::Job* ) ), panel->otherPanel->func, SLOT( refresh() ) ); + } + // if we are not copying to the other panel : + else if ( !dest.equals( panel->otherPanel->virtualPath(), true ) ) { + // you can rename only *one* file not a batch, + // so a batch dest must alwayes be a directory + if ( fileNames.count() > 1 ) dest.adjustPath(1); + KIO::Job* job = PreservingCopyJob::createCopyJob( pmode, *fileUrls, dest, KIO::CopyJob::Copy, false, true ); + job->setAutoErrorHandlingEnabled( true ); + if ( dest.equals( panel->virtualPath(), true ) || + dest.upURL().equals( panel->virtualPath(), true ) ) + // refresh our panel when done + connect( job, SIGNAL( result( KIO::Job* ) ), this, SLOT( refresh() ) ); + // let the other panel do the dirty job + } else { + //check if copy is supported + if ( !otherFunc() ->files() ->vfs_isWritable() ) { + KMessageBox::sorry( krApp, i18n( "You can't copy files to this file system" ) ); + return ; + } + // finally.. + otherFunc() ->files() ->vfs_addFiles( fileUrls, KIO::CopyJob::Copy, 0, "", pmode ); + } +} + +void ListPanelFunc::deleteFiles(bool reallyDelete) { + // check that the you have write perm + if ( !files() ->vfs_isWritable() ) { + KMessageBox::sorry( krApp, i18n( "You do not have write permission to this directory" ) ); + return ; + } + + // first get the selected file names list + QStringList fileNames; + panel->getSelectedNames( &fileNames ); + if ( fileNames.isEmpty() ) + return ; + + krConfig->setGroup( "General" ); + bool trash = krConfig->readBoolEntry( "Move To Trash", _MoveToTrash ); + // now ask the user if he want to delete: + krConfig->setGroup( "Advanced" ); + if ( krConfig->readBoolEntry( "Confirm Delete", _ConfirmDelete ) ) { + QString s, b; + + if ( !reallyDelete && trash && files() ->vfs_getType() == vfs::NORMAL ) { + s = i18n( "Do you really want to move this item to the trash?", "Do you really want to move these %n items to the trash?", fileNames.count() ); + b = i18n( "&Trash" ); + } else if( files() ->vfs_getType() == vfs::VIRT && files()->vfs_getOrigin().equals( KURL("virt:/"), true ) ) { + s = i18n( "Do you really want to delete this virtual item (physical files stay untouched)?", "Do you really want to delete these virtual items (physical files stay untouched)?", fileNames.count() ); + b = i18n( "&Delete" ); + } else if( files() ->vfs_getType() == vfs::VIRT ) { + s = i18n( "Do you really want to delete this item physically (not just removing it from the virtual items)?", "Do you really want to delete these %n items physically (not just removing them from the virtual items)?", fileNames.count() ); + b = i18n( "&Delete" ); + } else { + s = i18n( "Do you really want to delete this item?", "Do you really want to delete these %n items?", fileNames.count() ); + b = i18n( "&Delete" ); + } + + // 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, fileNames, + i18n( "Warning" ), b ) != KMessageBox::Continue ) + return ; + } + //we want to warn the user about non empty dir + // and files he don't have permission to delete + krConfig->setGroup( "Advanced" ); + bool emptyDirVerify = krConfig->readBoolEntry( "Confirm Unempty Dir", _ConfirmUnemptyDir ); + emptyDirVerify = ( ( emptyDirVerify ) && ( files() ->vfs_getType() == vfs::NORMAL ) ); + + QDir dir; + for ( QStringList::Iterator name = fileNames.begin(); name != fileNames.end(); ) { + vfile * vf = files() ->vfs_search( *name ); + + // verify non-empty dirs delete... (only for normal vfs) + if ( emptyDirVerify && vf->vfile_isDir() && !vf->vfile_isSymLink() ) { + dir.setPath( panel->virtualPath().path() + "/" + ( *name ) ); + if ( dir.entryList(QDir::All | QDir::System | QDir::Hidden ).count() > 2 ) { + switch ( KMessageBox::warningYesNoCancel( krApp, + i18n( "

Directory %1 is not empty!

Skip this one or Delete All?

" ).arg(*name), + QString::null, i18n( "&Skip" ), i18n( "&Delete All" ) ) ) { + case KMessageBox::Cancel : + return ; + case KMessageBox::No : + emptyDirVerify = false; + break; + case KMessageBox::Yes : + name = fileNames.remove( name ); + continue; + } + } + } + ++name; + } + + if ( fileNames.count() == 0 ) + return ; // nothing to delete + + // after the delete return the cursor to the first unmarked + // file above the current item; + panel->prepareToDelete(); + + // let the vfs do the job... + if (reallyDelete) { + // if reallyDelete, then make sure nothing gets moved to trash + krConfig->setGroup("General"); + krConfig->writeEntry( "Move To Trash", false ); + } + files() ->vfs_delFiles( &fileNames ); + if (reallyDelete) { + krConfig->setGroup("General"); + krConfig->writeEntry( "Move To Trash", trash); + } +} + +// this is done when you double click on a file +void ListPanelFunc::execute( QString& name ) { + if ( name == ".." ) { + dirUp(); + return ; + } + + vfile *vf = files() ->vfs_search( name ); + if ( vf == 0 ) + return ; + + KURL origin = files() ->vfs_getOrigin(); + + QString protocol = origin.isLocalFile() ? KrServices::registerdProtocol( vf->vfile_getMime() ) : ""; + + if ( protocol == "tar" || protocol == "krarc" ) { + bool encrypted; + QString type = KRarcHandler::getType( encrypted, vf->vfile_getUrl().path(), vf->vfile_getMime(), false ); + if ( !KRarcHandler::arcHandled( type ) ) // if the specified archive is disabled delete the protocol + protocol = ""; + } + + if ( vf->vfile_isDir() ) { + origin = files() ->vfs_getFile( name ); + panel->view->setNameToMakeCurrent( QString::null ); + openUrl( origin ); + } else if ( !protocol.isEmpty() ) { + KURL path = files() ->vfs_getFile( vf->vfile_getName() ); + path.setProtocol( protocol ); + openUrl( path ); + } else { + KURL url = files() ->vfs_getFile( name ); + KFileItem kfi( vf->vfile_getEntry(), url,true ); + kfi.run(); + } +} + +void ListPanelFunc::dirUp() { + openUrl( files() ->vfs_getOrigin().upURL(), files() ->vfs_getOrigin().fileName() ); +} + +void ListPanelFunc::pack() { + QStringList fileNames; + panel->getSelectedNames( &fileNames ); + if ( fileNames.isEmpty() ) + return ; // safety + + if ( fileNames.count() == 0 ) + return ; // nothing to pack + + // choose the default name + QString defaultName = panel->virtualPath().fileName(); + if ( defaultName == "" ) + defaultName = "pack"; + if ( fileNames.count() == 1 ) + defaultName = fileNames.first(); + // ask the user for archive name and packer + new PackGUI( defaultName, vfs::pathOrURL( panel->otherPanel->virtualPath(), -1 ), fileNames.count(), fileNames.first() ); + if ( PackGUI::type == QString::null ) + return ; // the user canceled + + // check for partial URLs + if( !PackGUI::destination.contains(":/") && !PackGUI::destination.startsWith("/") ){ + PackGUI::destination = panel->virtualPath().prettyURL()+"/"+PackGUI::destination; + } + + QString destDir = PackGUI::destination; + if( !destDir.endsWith( "/" ) ) + destDir += "/"; + + bool packToOtherPanel = ( destDir == panel->otherPanel->virtualPath().prettyURL(1) ); + + // on remote URL-s first pack into a temp file then copy to its right place + KURL destURL = vfs::fromPathOrURL( destDir + PackGUI::filename + "." + PackGUI::type ); + KTempFile *tempDestFile = 0; + QString arcFile; + if ( destURL.isLocalFile() ) + arcFile = destURL.path(); + else if( destURL.protocol() == "virt" ) { + KMessageBox::error( krApp, i18n( "Cannot pack files onto a virtual destination!" ) ); + return; + } + else { + tempDestFile = new KTempFile( QString::null, "." + PackGUI::type ); + tempDestFile->setAutoDelete( true ); + arcFile = tempDestFile->name(); + QFile::remove + ( arcFile ); + } + + if ( QFileInfo( arcFile ).exists() ) { + QString msg = i18n( "

The archive %1.%2 already exists. Do you want to overwrite it?

All data in the previous archive will be lost!

").arg(PackGUI::filename).arg(PackGUI::type); + if( PackGUI::type == "zip" ) { + msg = i18n( "

The archive %1.%2 already exists. Do you want to overwrite it?

Zip will replace identically named entries in the zip archive or add entries for new names.

").arg(PackGUI::filename).arg(PackGUI::type); + } + if ( KMessageBox::warningContinueCancel( krApp,msg,QString::null,i18n( "&Overwrite" )) + == KMessageBox::Cancel ) + return ; // stop operation + } + // tell the user to wait + krApp->startWaiting( i18n( "Counting files to pack" ), 0, true ); + + // get the files to be packed: + files() ->vfs_getFiles( &fileNames ); + + KIO::filesize_t totalSize = 0; + unsigned long totalDirs = 0, totalFiles = 0; + if( !calcSpace( fileNames, totalSize, totalFiles, totalDirs ) ) + return; + + // download remote URL-s if necessary + QString arcDir; + KTempDir *tempDir = 0; + + if ( files() ->vfs_getOrigin().isLocalFile() ) + arcDir = files() ->vfs_workingDir(); + else { + tempDir = new KTempDir(); + tempDir->setAutoDelete( true ); + arcDir = tempDir->name(); + KURL::List *urlList = files() ->vfs_getFiles( &fileNames ); + KIO::NetAccess::dircopy( *urlList, vfs::fromPathOrURL( arcDir ), 0 ); + delete urlList; + } + + // pack the files + // we must chdir() first because we supply *names* not URL's + QString save = getcwd( 0, 0 ); + chdir( arcDir.local8Bit() ); + KRarcHandler::pack( fileNames, PackGUI::type, arcFile, totalFiles + totalDirs, PackGUI::extraProps ); + chdir( save.local8Bit() ); + + // delete the temporary directory if created + if ( tempDir ) + delete tempDir; + + // copy from the temp file to it's right place + if ( tempDestFile ) { + KIO::NetAccess::file_move( vfs::fromPathOrURL( arcFile ), destURL ); + delete tempDestFile; + } + + if ( packToOtherPanel ) + panel->otherPanel->func->refresh(); +} + +void ListPanelFunc::testArchive() { + QString arcName = panel->getCurrentName(); + if ( arcName.isNull() ) + return ; + if ( arcName == ".." ) + return ; // safety + + KURL arcURL = files() ->vfs_getFile( arcName ); + QString url = QString::null; + + // download the file if it's on a remote filesystem + if ( !arcURL.isLocalFile() ) { + url = locateLocal( "tmp", QString( arcName ) ); + if ( !KIO::NetAccess::download( arcURL, url, 0 ) ) { + KMessageBox::sorry( krApp, i18n( "Krusader is unable to download: " ) + arcURL.fileName() ); + return ; + } + } else + url = arcURL.path( -1 ); + + QString mime = files() ->vfs_search( arcName ) ->vfile_getMime(); + bool encrypted = false; + QString type = KRarcHandler::getType( encrypted, url, mime ); + + // check we that archive is supported + if ( !KRarcHandler::arcSupported( type ) ) { + KMessageBox::sorry( krApp, i18n( "%1, unknown archive type." ).arg( arcName ) ); + return ; + } + + QString password = encrypted ? KRarcHandler::getPassword( url ) : QString::null; + + // test the archive + if ( KRarcHandler::test( url, type, password ) ) + KMessageBox::information( krApp, i18n( "%1, test passed." ).arg( arcName ) ); + else + KMessageBox::error( krApp, i18n( "%1, test failed!" ).arg( arcName ) ); + + // remove the downloaded file if necessary + if ( url != arcURL.path( -1 ) ) + QFile( url ).remove(); +} + +void ListPanelFunc::unpack() { + + QStringList fileNames; + panel->getSelectedNames( &fileNames ); + if ( fileNames.isEmpty() ) + return ; // safety + + QString s; + if(fileNames.count() == 1) + s = i18n("Unpack %1 to:").arg(fileNames[0]); + else + s = i18n("Unpack %n file to:", "Unpack %n files to:", fileNames.count()); + + // ask the user for the copy dest + KURL dest = KChooseDir::getDir(s, panel->otherPanel->virtualPath(), panel->virtualPath()); + if ( dest.isEmpty() ) return ; // the user canceled + + bool packToOtherPanel = ( dest.equals( panel->otherPanel->virtualPath(), true ) ); + + for ( unsigned int i = 0; i < fileNames.count(); ++i ) { + QString arcName = fileNames[ i ]; + if ( arcName.isNull() ) + return ; + if ( arcName == ".." ) + return ; // safety + + // download the file if it's on a remote filesystem + KURL arcURL = files() ->vfs_getFile( arcName ); + QString url = QString::null; + if ( !arcURL.isLocalFile() ) { + url = locateLocal( "tmp", QString( arcName ) ); + if ( !KIO::NetAccess::download( arcURL, url, 0 ) ) { + KMessageBox::sorry( krApp, i18n( "Krusader is unable to download: " ) + arcURL.fileName() ); + continue; + } + } else + url = arcURL.path( -1 ); + + // if the destination is in remote directory use temporary one instead + dest.adjustPath(1); + KURL originalDestURL; + KTempDir *tempDir = 0; + + if ( !dest.isLocalFile() ) { + originalDestURL = dest; + tempDir = new KTempDir(); + tempDir->setAutoDelete( true ); + dest = tempDir->name(); + } + + // determining the type + QString mime = files() ->vfs_search( arcName ) ->vfile_getMime(); + bool encrypted = false; + QString type = KRarcHandler::getType( encrypted, url, mime ); + + // check we that archive is supported + if ( !KRarcHandler::arcSupported( type ) ) { + KMessageBox::sorry( krApp, i18n( "%1, unknown archive type" ).arg( arcName ) ); + continue; + } + + QString password = encrypted ? KRarcHandler::getPassword( url ) : QString::null; + + // unpack the files + KRarcHandler::unpack( url, type, password, dest.path( -1 ) ); + + // remove the downloaded file if necessary + if ( url != arcURL.path( -1 ) ) + QFile( url ).remove(); + + // copy files to the destination directory at remote files + if ( tempDir ) { + QStringList nameList = QDir( dest.path( -1 ) ).entryList(); + KURL::List urlList; + for ( unsigned int i = 0; i != nameList.count(); i++ ) + if ( nameList[ i ] != "." && nameList[ i ] != ".." ) + urlList.append( vfs::fromPathOrURL( dest.path( 1 ) + nameList[ i ] ) ); + if ( urlList.count() > 0 ) + KIO::NetAccess::dircopy( urlList, originalDestURL, 0 ); + delete tempDir; + } + } + if ( packToOtherPanel ) + panel->otherPanel->func->refresh(); +} + +// a small ugly function, used to prevent duplication of EVERY line of +// code (maybe except 3) from createChecksum and matchChecksum +static void checksum_wrapper(ListPanel *panel, QStringList& args, bool &folders) { + KrViewItemList items; + panel->view->getSelectedKrViewItems( &items ); + if ( items.isEmpty() ) return ; // nothing to do + // determine if we need recursive mode (md5deep) + folders=false; + for ( KrViewItemList::Iterator it = items.begin(); it != items.end(); ++it ) { + if (panel->func->getVFile(*it)->vfile_isDir()) { + folders = true; + args << (*it)->name(); + } else args << (*it)->name(); + } +} + +void ListPanelFunc::createChecksum() { + QStringList args; + bool folders; + checksum_wrapper(panel, args, folders); + CreateChecksumDlg dlg(args, folders, panel->realPath()); +} + +void ListPanelFunc::matchChecksum() { + QStringList args; + bool folders; + checksum_wrapper(panel, args, folders); + QValueList checksumFiles = files()->vfs_search( + KRQuery(MatchChecksumDlg::checksumTypesFilter) + ); + MatchChecksumDlg dlg(args, folders, panel->realPath(), + (checksumFiles.size()==1 ? checksumFiles[0]->vfile_getUrl().prettyURL() : QString::null)); +} + +void ListPanelFunc::calcSpace() { + QStringList items; + panel->view->getSelectedItems( &items ); + if ( items.isEmpty() ) { + panel->view->selectAllIncludingDirs(); + panel->view->getSelectedItems( &items ); + if ( items.isEmpty() ) + return ; // nothing to do + } + + KrCalcSpaceDialog calc( krApp, panel, items, false ); + calc.exec(); + for ( QStringList::ConstIterator it = items.begin(); it != items.end(); ++it ) { + KrViewItem *viewItem = panel->view->findItemByName( *it ); + if ( viewItem ) + panel->view->updateItem(viewItem); + } + panel->slotUpdateTotals(); +} + +bool ListPanelFunc::calcSpace( const QStringList & items, KIO::filesize_t & totalSize, unsigned long & totalFiles, unsigned long & totalDirs ) { + KrCalcSpaceDialog calc( krApp, panel, items, true ); + calc.exec(); + totalSize = calc.getTotalSize(); + totalFiles = calc.getTotalFiles(); + totalDirs = calc.getTotalDirs(); + return !calc.wasCanceled(); +} + +void ListPanelFunc::FTPDisconnect() { + // you can disconnect only if connected ! + if ( files() ->vfs_getType() == vfs::FTP ) { + krFTPDiss->setEnabled( false ); + panel->view->setNameToMakeCurrent( QString::null ); + openUrl( panel->realPath() ); // open the last local URL + } +} + +void ListPanelFunc::newFTPconnection() { + KURL url = KRSpWidgets::newFTP(); + // if the user canceled - quit + if ( url.isEmpty() ) + return ; + + krFTPDiss->setEnabled( true ); + openUrl( url ); +} + +void ListPanelFunc::properties() { + QStringList names; + panel->getSelectedNames( &names ); + if ( names.isEmpty() ) + return ; // no names... + KFileItemList fi; + fi.setAutoDelete( true ); + + for ( unsigned int i = 0 ; i < names.count() ; ++i ) { + vfile* vf = files() ->vfs_search( names[ i ] ); + if ( !vf ) + continue; + KURL url = files()->vfs_getFile( names[i] ); + fi.append( new KFileItem( vf->vfile_getEntry(), url ) ); + } + + if ( fi.isEmpty() ) + return ; + + // Show the properties dialog + KPropertiesDialog *dlg = new KPropertiesDialog( fi ); + connect( dlg, SIGNAL( applied() ), SLOTS, SLOT( refresh() ) ); +} + +void ListPanelFunc::refreshActions() { + vfs::VFS_TYPE vfsType = files() ->vfs_getType(); + + // set up actions + krMultiRename->setEnabled( vfsType == vfs::NORMAL ); // batch rename + //krProperties ->setEnabled( vfsType == vfs::NORMAL || vfsType == vfs::FTP ); // file properties + krFTPDiss ->setEnabled( vfsType == vfs::FTP ); // disconnect an FTP session + krCreateCS->setEnabled( vfsType == vfs::NORMAL ); + /* + krUnpack->setEnabled(true); // unpack archive + krTest->setEnabled(true); // test archive + krSelect->setEnabled(true); // select a group by filter + krSelectAll->setEnabled(true); // select all files + krUnselect->setEnabled(true); // unselect by filter + krUnselectAll->setEnabled( true); // remove all selections + krInvert->setEnabled(true); // invert the selection + krFTPConnect->setEnabled(true); // connect to an ftp + krFTPNew->setEnabled(true); // create a new connection + krAllFiles->setEnabled(true); // show all files in list + krCustomFiles->setEnabled(true); // show a custom set of files + krBack->setEnabled(func->canGoBack()); // go back + krRoot->setEnabled(true); // go all the way up + krExecFiles->setEnabled(true); // show only executables + */ +} + +ListPanelFunc::~ListPanelFunc() { + if( !vfsP ) { + if( vfsP->vfs_canDelete() ) + delete vfsP; + else { + connect( vfsP, SIGNAL( deleteAllowed() ), vfsP, SLOT( deleteLater() ) ); + vfsP->vfs_requestDelete(); + } + } + vfsP = 0; +} + +vfs* ListPanelFunc::files() { + if ( !vfsP ) + vfsP = KrVfsHandler::getVfs( "/", panel, 0 ); + return vfsP; +} + + +void ListPanelFunc::copyToClipboard( bool move ) { + if( files()->vfs_getOrigin().equals( KURL("virt:/"), true ) ) { + if( move ) + KMessageBox::error( krApp, i18n( "Cannot cut a virtual URL collection to the clipboard!" ) ); + else + KMessageBox::error( krApp, i18n( "Cannot copy a virtual URL collection onto the clipboard!" ) ); + return; + } + + QStringList fileNames; + + panel->getSelectedNames( &fileNames ); + if ( fileNames.isEmpty() ) + return ; // safety + + KURL::List* fileUrls = files() ->vfs_getFiles( &fileNames ); + if ( fileUrls ) { + KRDrag * urlData = KRDrag::newDrag( *fileUrls, move, krApp->mainView, "krusader" ); + QApplication::clipboard() ->setData( urlData ); + + if( move && files()->vfs_getType() == vfs::VIRT ) + ( static_cast( files() ) )->vfs_removeFiles( &fileNames ); + + delete fileUrls; + } +} + +void ListPanelFunc::pasteFromClipboard() { + QClipboard * cb = QApplication::clipboard(); + QMimeSource * data = cb->data(); + KURL::List urls; + if ( KURLDrag::canDecode( data ) ) { + KURLDrag::decode( data, urls ); + bool cutSelection = KRDrag::decodeIsCutSelection( data ); + + KURL destUrl = panel->virtualPath(); + + files()->vfs_addFiles( &urls, cutSelection ? KIO::CopyJob::Move : KIO::CopyJob::Copy, otherFunc()->files(), + "", PM_DEFAULT ); + } +} + +#include "panelfunc.moc" diff --git a/krusader/Panel/panelfunc.h b/krusader/Panel/panelfunc.h new file mode 100644 index 0000000..1274e11 --- /dev/null +++ b/krusader/Panel/panelfunc.h @@ -0,0 +1,105 @@ +/*************************************************************************** + panelfunc.h + ------------------- + begin : Thu May 4 2000 + copyright : (C) 2000 by Shie Erlich & Rafi Yanai + 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 PANELFUNC_H +#define PANELFUNC_H +#include "listpanel.h" +#include "krviewitem.h" +#include +#include +#include + +class ListPanelFunc : public QObject{ +friend class ListPanel; + Q_OBJECT +public slots: + inline vfile* getVFile(KrViewItem *item) { return files()->vfs_search(item->name()); } + inline vfile* getVFile(const QString& name) { return files()->vfs_search(name); } + void execute(QString&); + void openUrl(const KURL& path, const QString& nameToMakeCurrent = QString::null); + void openUrl(const QString& path, const QString& nameToMakeCurrent = QString::null); + void immediateOpenUrl( const KURL& path); + void doOpenUrl(); + void refresh(); + void rename(const QString &oldname, const QString &newname); + +public: + ListPanelFunc(class ListPanel *parent); + ~ListPanelFunc(); + + vfs* files(); // return a pointer to the vfs + + void refreshActions(); + void redirectLink(); + void krlink(bool sym); + void goBack(); + void dirUp(); + void properties(); + void terminal(); + void editFile(); + void view(); + void rename(); + void mkdir(); + void moveFiles(); + void pack(); + void unpack(); + void testArchive(); + void copyFiles(); + void deleteFiles(bool reallyDelete=false); + void calcSpace(); // calculate the occupied space and show it in a dialog + void createChecksum(); + void matchChecksum(); + void copyToClipboard( bool move=false ); + void pasteFromClipboard(); + + // calculate the occupied space. A dialog appears, if calculation lasts more than 3 seconds + // and disappears, if the calculation is done. Returns true, if the result is ok and false + // otherwise (Cancel was pressed). + bool calcSpace(const QStringList & items,KIO::filesize_t & totalSize,unsigned long & totalFiles,unsigned long & totalDirs); + void FTPDisconnect(); + void newFTPconnection(); + inline ListPanelFunc* otherFunc(){ return panel->otherPanel->func; } + +private: + KURL getVirtualBaseURL(); + +protected: + ListPanel* panel; // our ListPanel + QValueStack urlStack; // Path stack for the "back" button + bool inRefresh; // true when we are in refresh() + vfs* vfsP; // pointer to vfs. + QTimer delayTimer; + KURL delayURL; + QString nameToMakeCurrent; +}; + +#endif diff --git a/krusader/Panel/panelpopup.cpp b/krusader/Panel/panelpopup.cpp new file mode 100644 index 0000000..deaec38 --- /dev/null +++ b/krusader/Panel/panelpopup.cpp @@ -0,0 +1,400 @@ +#include "../krusader.h" +#include "panelpopup.h" +#include "../kicons.h" +#include "../Dialogs/krsqueezedtextlabel.h" +#include "../defaults.h" +#include "../krslots.h" +#include "panelfunc.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../KViewer/kimagefilepreview.h" +#include "../KViewer/panelviewer.h" +#include "../KViewer/diskusageviewer.h" + +PanelPopup::PanelPopup( QSplitter *parent, bool left ) : QWidget( parent ), + _left( left ), _hidden(true), stack( 0 ), viewer( 0 ), pjob( 0 ), splitterSizes() { + splitter = parent; + QGridLayout * layout = new QGridLayout(this, 1, 1); + + // loading the splitter sizes + krConfig->setGroup( "Private" ); + if( left ) + splitterSizes = krConfig->readIntListEntry( "Left PanelPopup Splitter Sizes" ); + else + splitterSizes = krConfig->readIntListEntry( "Right PanelPopup Splitter Sizes" ); + + if( splitterSizes.count() < 2 ) { + splitterSizes.clear(); + splitterSizes.push_back( 100 ); + splitterSizes.push_back( 100 ); + } + + // create the label+buttons setup + dataLine = new KrSqueezedTextLabel(this); + dataLine->setText("blah blah"); + connect( dataLine, SIGNAL( clicked() ), this, SLOT( setFocus() ) ); + krConfig->setGroup( "Look&Feel" ); + dataLine->setFont( krConfig->readFontEntry( "Filelist Font", _FilelistFont ) ); + // --- hack: setup colors to be the same as an inactive panel + dataLine->setBackgroundMode( PaletteBackground ); + QPalette q( dataLine->palette() ); + q.setColor( QColorGroup::Foreground, KGlobalSettings::textColor() ); + q.setColor( QColorGroup::Background, KGlobalSettings::baseColor() ); + dataLine->setPalette( q ); + dataLine->setFrameStyle( QFrame::Box | QFrame::Raised ); + dataLine->setLineWidth( 1 ); // a nice 3D touch :-) + int sheight = QFontMetrics( dataLine->font() ).height() + 4; + dataLine->setMaximumHeight( sheight ); + + btns = new QButtonGroup(this); + btns->setExclusive(true); + btns->hide(); // it should be invisible + connect(btns, SIGNAL(clicked(int)), this, SLOT(tabSelected(int))); + + treeBtn = new QToolButton(this); + QToolTip::add(treeBtn, i18n("Tree Panel: a tree view of the local file system")); + treeBtn->setPixmap(krLoader->loadIcon( "view_tree", KIcon::Toolbar, 16 )); + treeBtn->setFixedSize(20, 20); + treeBtn->setToggleButton(true); + btns->insert(treeBtn, Tree); + + + previewBtn = new QToolButton(this); + QToolTip::add(previewBtn, i18n("Preview Panel: display a preview of the current file")); + previewBtn->setPixmap(krLoader->loadIcon( "thumbnail", KIcon::Toolbar, 16 )); + previewBtn->setFixedSize(20, 20); + previewBtn->setToggleButton(true); + btns->insert(previewBtn, Preview); + + quickBtn = new QToolButton(this); + QToolTip::add(quickBtn, i18n("Quick Panel: quick way to perform actions")); + quickBtn->setPixmap(krLoader->loadIcon( "misc", KIcon::Toolbar, 16 )); + quickBtn->setFixedSize(20, 20); + quickBtn->setToggleButton(true); + btns->insert(quickBtn, QuickPanel); + + viewerBtn = new QToolButton(this); + QToolTip::add(viewerBtn, i18n("View Panel: view the current file")); + viewerBtn->setPixmap(krLoader->loadIcon( "viewmag", KIcon::Toolbar, 16 )); + viewerBtn->setFixedSize(20, 20); + viewerBtn->setToggleButton(true); + btns->insert(viewerBtn, View); + + duBtn = new QToolButton(this); + QToolTip::add(duBtn, i18n("Disk Usage Panel: view the usage of a directory")); + duBtn->setPixmap(krLoader->loadIcon( "kr_diskusage", KIcon::Toolbar, 16 )); + duBtn->setFixedSize(20, 20); + duBtn->setToggleButton(true); + btns->insert(duBtn, DskUsage); + + layout->addWidget(dataLine,0,0); + layout->addWidget(treeBtn,0,1); + layout->addWidget(previewBtn,0,2); + layout->addWidget(quickBtn,0,3); + layout->addWidget(viewerBtn,0,4); + layout->addWidget(duBtn,0,5); + + // create a widget stack on which to put the parts + stack = new QWidgetStack( this ); + + // create the tree part ---------- + tree = new KFileTreeView( stack ); + tree->setAcceptDrops(true); + connect(tree, SIGNAL(dropped (QWidget *, QDropEvent *, KURL::List &, KURL &)), + this, SLOT(slotDroppedOnTree(QWidget *, QDropEvent *, KURL::List&, KURL& ))); + stack->addWidget( tree, Tree ); + tree->addColumn( "" ); + // add ~ + tree->addBranch( QDir::home().absPath(), i18n("Home")); + tree->setDirOnlyMode( tree->branch(i18n("Home")), true); + tree->branch(i18n("Home"))->setChildRecurse(false); + // add / + tree->addBranch( "/", i18n( "Root" ) ); + tree->setDirOnlyMode( tree->branch( i18n( "Root" ) ), true ); + tree->setShowFolderOpenPixmap(true); + tree->branch( i18n( "Root" ) ) ->setChildRecurse(false); + tree->branch( i18n( "Root" ) ) ->setOpen( true ); + tree->header() ->setHidden( true ); + connect(tree, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(treeSelection(QListViewItem*))); + // start listing the tree + tree->branch( i18n( "Root" ) ) ->root(); + tree->branch( i18n( "Home" ) ) ->root(); + + // create the quickview part ------ + viewer = new KrusaderImageFilePreview(stack); + stack->addWidget( viewer, Preview ); + + // create the panelview + + panelviewer = new PanelViewer(stack); + stack->addWidget(panelviewer, View); + connect(panelviewer, SIGNAL(openURLRequest(const KURL &)), this, SLOT(handleOpenURLRequest(const KURL &))); + + // create the disk usage view + + diskusage = new DiskUsageViewer( stack ); + diskusage->setStatusLabel( dataLine, i18n("Disk Usage: ") ); + stack->addWidget( diskusage, DskUsage ); + connect(diskusage, SIGNAL(openURLRequest(const KURL &)), this, SLOT(handleOpenURLRequest(const KURL &))); + + // create the quick-panel part ---- + + QWidget *quickPanel = new QWidget(stack); + QGridLayout *qlayout = new QGridLayout(quickPanel); + // --- quick select + QLabel *selectLabel = new QLabel(i18n("Quick Select"), quickPanel); + quickSelectCombo = new KComboBox( quickPanel ); + quickSelectCombo->setEditable( true ); + krConfig->setGroup( "Private" ); + QStrList lst; + int i = krConfig->readListEntry( "Predefined Selections", lst ); + if ( i > 0 ) + quickSelectCombo->insertStrList( lst ); + quickSelectCombo->setCurrentText( "*" ); + quickSelectCombo->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ) ); + + connect(quickSelectCombo, SIGNAL(returnPressed(const QString& )), + this, SLOT(quickSelect(const QString& ))); + + QToolButton *qselectBtn = new QToolButton(quickPanel); + qselectBtn->setPixmap(krLoader->loadIcon( "kr_selectall", KIcon::Toolbar, 16 )); + qselectBtn->setFixedSize(20, 20); + QToolTip::add( qselectBtn, i18n("apply the selection") ); + connect(qselectBtn, SIGNAL(clicked()), this, SLOT(quickSelect())); + + QToolButton *qstoreBtn = new QToolButton(quickPanel); + qstoreBtn->setPixmap(krLoader->loadIcon( "filesave", KIcon::Toolbar, 16 )); + qstoreBtn->setFixedSize(20, 20); + QToolTip::add( qstoreBtn, i18n("store the current selection") ); + connect(qstoreBtn, SIGNAL(clicked()), this, SLOT(quickSelectStore())); + + QToolButton *qsettingsBtn = new QToolButton(quickPanel); + qsettingsBtn->setPixmap(krLoader->loadIcon( "configure", KIcon::Toolbar, 16 )); + qsettingsBtn->setFixedSize(20, 20); + QToolTip::add( qsettingsBtn, i18n("select group dialog") ); + connect(qsettingsBtn, SIGNAL(clicked()), krSelect, SLOT(activate())); + + qlayout->addWidget(selectLabel,0,0); + qlayout->addWidget(quickSelectCombo,0,1); + qlayout->addWidget(qselectBtn,0,2); + qlayout->addWidget(qstoreBtn,0,3); + qlayout->addWidget(qsettingsBtn,0,4); + stack->addWidget(quickPanel, QuickPanel); + + // -------- finish the layout (General one) + layout->addMultiCellWidget(stack,1,1,0,5); + + // set the wanted widget + // ugly: are we left or right? + int id; + krConfig->setGroup("Startup"); + if (left) { + id = krConfig->readNumEntry("Left Panel Popup", _LeftPanelPopup); + } else { + id = krConfig->readNumEntry("Right Panel Popup", _RightPanelPopup); + } + btns->setButton(id); + + hide(); // for not to open the 3rd hand tool at start (selecting the last used tab) + tabSelected(id); +} + +PanelPopup::~PanelPopup() {} + +void PanelPopup::show() { + QWidget::show(); + if( _hidden ) + splitter->setSizes( splitterSizes ); + _hidden = false; + tabSelected( stack->id(stack->visibleWidget()) ); +} + + +void PanelPopup::hide() { + if( !_hidden ) + splitterSizes = splitter->sizes(); + QWidget::hide(); + _hidden = true; + if (stack->id(stack->visibleWidget()) == View) panelviewer->closeURL(); + if (stack->id(stack->visibleWidget()) == DskUsage) diskusage->closeURL(); +} + +void PanelPopup::setFocus() { + switch ( stack->id( stack->visibleWidget() ) ) { + case Preview: + if( !isHidden() ) + viewer->setFocus(); + break; + case View: + if( !isHidden() && panelviewer->part() && panelviewer->part()->widget() ) + panelviewer->part()->widget()->setFocus(); + break; + case DskUsage: + if( !isHidden() && diskusage->getWidget() && diskusage->getWidget()->visibleWidget() ) + diskusage->getWidget()->visibleWidget()->setFocus(); + break; + case Tree: + if( !isHidden() ) + tree->setFocus(); + break; + case QuickPanel: + if( !isHidden() ) + quickSelectCombo->setFocus(); + break; + } +} + +void PanelPopup::saveSizes() { + krConfig->setGroup( "Private" ); + + if( !isHidden() ) + splitterSizes = splitter->sizes(); + + if( _left ) + krConfig->writeEntry( "Left PanelPopup Splitter Sizes", splitterSizes ); + else + krConfig->writeEntry( "Right PanelPopup Splitter Sizes", splitterSizes ); +} + +void PanelPopup::handleOpenURLRequest(const KURL &url) { + if (KMimeType::findByURL(url.url())->name() == "inode/directory") ACTIVE_PANEL->func->openUrl(url); +} + + +void PanelPopup::tabSelected( int id ) { + KURL url = ""; + if ( ACTIVE_PANEL && ACTIVE_PANEL->func && ACTIVE_PANEL->func->files() && ACTIVE_PANEL->view ) { + url = ACTIVE_PANEL->func->files()->vfs_getFile( ACTIVE_PANEL->view->getCurrentItem()); + } + + stack->raiseWidget( id ); + + // if tab is tree, set something logical in the data line + switch (id) { + case Tree: + dataLine->setText( i18n("Tree:") ); + if( !isHidden() ) + tree->setFocus(); + break; + case Preview: + dataLine->setText( i18n("Preview:") ); + update(url); + break; + case QuickPanel: + dataLine->setText( i18n("Quick Select:") ); + if( !isHidden() ) + quickSelectCombo->setFocus(); + break; + case View: + dataLine->setText( i18n("View:") ); + update(url); + if( !isHidden() && panelviewer->part() && panelviewer->part()->widget() ) + panelviewer->part()->widget()->setFocus(); + break; + case DskUsage: + dataLine->setText( i18n("Disk Usage:") ); + update(url); + if( !isHidden() && diskusage->getWidget() && diskusage->getWidget()->visibleWidget() ) + diskusage->getWidget()->visibleWidget()->setFocus(); + break; + } + if (id != View) panelviewer->closeURL(); +} + +// decide which part to update, if at all +void PanelPopup::update( KURL url ) { + if ( isHidden() || url.url()=="" ) return ; // failsafe + + KFileItemList lst; + + switch ( stack->id( stack->visibleWidget() ) ) { + case Preview: + viewer->showPreview(url); + dataLine->setText( i18n("Preview: ")+url.fileName() ); + break; + case View: + panelviewer->openURL(url); + dataLine->setText( i18n("View: ")+url.fileName() ); + break; + case DskUsage: + if( url.fileName() == ".." ) + url.setFileName( "" ); + if (KMimeType::findByURL(url.url())->name() != "inode/directory") + url = url.upURL(); + dataLine->setText( i18n("Disk Usage: ")+url.fileName() ); + diskusage->openURL(url); + break; + case Tree: // nothing to do + break; + } +} + +// ------------------- tree + +void PanelPopup::treeSelection(QListViewItem*) { + emit selection(tree->currentURL()); + //emit hideMe(); +} + +// ------------------- quick panel + +void PanelPopup::quickSelect() { + SLOTS->markGroup(quickSelectCombo->currentText(), true); +} + +void PanelPopup::quickSelect(const QString &mask) { + SLOTS->markGroup(mask, true); +} + +void PanelPopup::quickSelectStore() { + krConfig->setGroup( "Private" ); + QStringList lst = krConfig->readListEntry( "Predefined Selections" ); + if ( lst.find(quickSelectCombo->currentText()) == lst.end() ) + lst.append( quickSelectCombo->currentText() ); + krConfig->writeEntry( "Predefined Selections", lst ); +} + +void PanelPopup::slotDroppedOnTree(QWidget *widget, QDropEvent *e, KURL::List &lst, KURL &) { + // KFileTreeView is buggy: when dropped, it might not give us the correct + // destination, but actually, it's parent. workaround: don't use + // the destination in the signal, but take the current item + KURL dest = tree->currentURL(); + + // ask the user what to do: copy, move or link? + QPopupMenu popup( this ); + popup.insertItem( i18n( "Copy Here" ), 1 ); + popup.insertItem( i18n( "Move Here" ), 2 ); + popup.insertItem( i18n( "Link Here" ), 3 ); + popup.insertItem( i18n( "Cancel" ), 4 ); + QPoint tmp = widget->mapToGlobal( e->pos() ); + int result = popup.exec( QCursor::pos() ); + + KIO::CopyJob *job; + switch ( result ) { + case 1 : + job = KIO::copy(lst, dest, true); + break; + case 2 : + job = KIO::move(lst, dest, true); + break; + case 3 : + job = KIO::link(lst, dest, true); + break; + case - 1 : // user pressed outside the menu + case 4: + return ; // cancel was pressed; + } +} + +#include "panelpopup.moc" diff --git a/krusader/Panel/panelpopup.h b/krusader/Panel/panelpopup.h new file mode 100644 index 0000000..3c09a0b --- /dev/null +++ b/krusader/Panel/panelpopup.h @@ -0,0 +1,73 @@ +#ifndef _PANELPOPUP_H +#define _PANELPOPUP_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class QButtonGroup; +class QLabel; +class QListViewItem; +class QSplitter; +class KFileTreeView; +class QToolButton; +class KrSqueezedTextLabel; +class KLineEdit; +class KComboBox; +class KrusaderImageFilePreview; +class PanelViewer; +class DiskUsageViewer; + +class PanelPopup: public QWidget { + Q_OBJECT + enum Parts { Tree, Preview, QuickPanel, View, DskUsage, Last=0xFF }; +public: + PanelPopup( QSplitter *splitter, bool left ); + ~PanelPopup(); + inline int currentPage() const { return stack->id(stack->visibleWidget()); } + + void saveSizes(); + +public slots: + void update(KURL url); + void show(); + void hide(); + +signals: + void selection(const KURL &url); + void hideMe(); + +protected slots: + virtual void setFocus(); + void tabSelected(int id); + void treeSelection(QListViewItem*); + void slotDroppedOnTree(QWidget *widget, QDropEvent *e, KURL::List &lst, KURL &); + void handleOpenURLRequest(const KURL &url); + void quickSelect(); + void quickSelect(const QString &); + void quickSelectStore(); + +protected: + bool _left; + bool _hidden; + QWidgetStack *stack; + KrusaderImageFilePreview *viewer; + KrSqueezedTextLabel *dataLine; + QGuardedPtr pjob; + KFileTreeView *tree; + QToolButton *treeBtn, *previewBtn, *quickBtn, *viewerBtn, *duBtn; + QButtonGroup *btns; + KLineEdit *quickFilter; + KComboBox *quickSelectCombo; + PanelViewer *panelviewer; + DiskUsageViewer *diskusage; + QValueList splitterSizes; + QSplitter *splitter; +}; + +#endif // _PANELPOPUP_H -- cgit v1.2.3