summaryrefslogtreecommitdiffstats
path: root/libkonq/konq_iconviewwidget.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libkonq/konq_iconviewwidget.cc')
-rw-r--r--libkonq/konq_iconviewwidget.cc1927
1 files changed, 1927 insertions, 0 deletions
diff --git a/libkonq/konq_iconviewwidget.cc b/libkonq/konq_iconviewwidget.cc
new file mode 100644
index 000000000..99d92ebde
--- /dev/null
+++ b/libkonq/konq_iconviewwidget.cc
@@ -0,0 +1,1927 @@
+/* This file is part of the KDE projects
+ Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
+ Copyright (C) 2000 - 2005 David Faure <faure@kde.org>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#include "konq_iconviewwidget.h"
+#include "konq_operations.h"
+#include "konq_undo.h"
+#include "konq_sound.h"
+#include "konq_filetip.h"
+
+#include <qclipboard.h>
+#include <qlayout.h>
+#include <qtimer.h>
+#include <qpainter.h>
+#include <qtooltip.h>
+#include <qlabel.h>
+#include <qmovie.h>
+#include <qregexp.h>
+#include <qcursor.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kio/previewjob.h>
+#include <kfileivi.h>
+#include <konq_settings.h>
+#include <konq_drag.h>
+#include <kglobalsettings.h>
+#include <kpropertiesdialog.h>
+#include <kipc.h>
+#include <kicontheme.h>
+#include <kiconeffect.h>
+#include <kurldrag.h>
+#include <kstandarddirs.h>
+#include <kprotocolinfo.h>
+#include <ktrader.h>
+
+#include <assert.h>
+#include <unistd.h>
+#include <klocale.h>
+
+
+struct KonqIconViewWidgetPrivate
+{
+ KonqIconViewWidgetPrivate() {
+ pActiveItem = 0;
+ bSoundPreviews = false;
+ pSoundItem = 0;
+ bSoundItemClicked = false;
+ pSoundPlayer = 0;
+ pSoundTimer = 0;
+ pPreviewJob = 0;
+ bAllowSetWallpaper = false;
+
+ doAnimations = true;
+ m_movie = 0L;
+ m_movieBlocked = 0;
+ pFileTip = 0;
+ pActivateDoubleClick = 0L;
+ bCaseInsensitive = true;
+ pPreviewMimeTypes = 0L;
+ bProgramsURLdrag = false;
+ }
+ ~KonqIconViewWidgetPrivate() {
+ delete pSoundPlayer;
+ delete pSoundTimer;
+ delete m_movie;
+ delete pFileTip;
+ delete pActivateDoubleClick;
+ delete pPreviewMimeTypes;
+ //delete pPreviewJob; done by stopImagePreview
+ }
+ KFileIVI *pActiveItem;
+ // Sound preview
+ KFileIVI *pSoundItem;
+ KonqSoundPlayer *pSoundPlayer;
+ QTimer *pSoundTimer;
+ bool bSoundPreviews;
+ bool bSoundItemClicked;
+ bool bAllowSetWallpaper;
+ bool bCaseInsensitive;
+ bool bBoostPreview;
+
+ // Animated icons support
+ bool doAnimations;
+ QMovie* m_movie;
+ int m_movieBlocked;
+ QString movieFileName;
+
+ KIO::PreviewJob *pPreviewJob;
+ KonqFileTip* pFileTip;
+ QStringList previewSettings;
+ bool renameItem;
+ bool firstClick;
+ bool releaseMouseEvent;
+ QPoint mousePos;
+ int mouseState;
+ QTimer *pActivateDoubleClick;
+ QStringList* pPreviewMimeTypes;
+ bool bProgramsURLdrag;
+};
+
+KonqIconViewWidget::KonqIconViewWidget( QWidget * parent, const char * name, WFlags f, bool kdesktop )
+ : KIconView( parent, name, f ),
+ m_rootItem( 0L ), m_size( 0 ) /* default is DesktopIcon size */,
+ m_bDesktop( kdesktop ),
+ m_bSetGridX( !kdesktop ) /* No line breaking on the desktop */
+{
+ d = new KonqIconViewWidgetPrivate;
+ connect( this, SIGNAL( dropped( QDropEvent *, const QValueList<QIconDragItem> & ) ),
+ this, SLOT( slotDropped( QDropEvent*, const QValueList<QIconDragItem> & ) ) );
+
+ connect( this, SIGNAL( selectionChanged() ),
+ this, SLOT( slotSelectionChanged() ) );
+
+ kapp->addKipcEventMask( KIPC::IconChanged );
+ connect( kapp, SIGNAL(iconChanged(int)), SLOT(slotIconChanged(int)) );
+ connect( this, SIGNAL(onItem(QIconViewItem *)), SLOT(slotOnItem(QIconViewItem *)) );
+ connect( this, SIGNAL(onViewport()), SLOT(slotOnViewport()) );
+ connect( this, SIGNAL(itemRenamed(QIconViewItem *, const QString &)), SLOT(slotItemRenamed(QIconViewItem *, const QString &)) );
+
+ m_pSettings = KonqFMSettings::settings(); // already needed in setItemTextPos(), calculateGridX()
+ d->bBoostPreview = boostPreview();
+
+ // hardcoded settings
+ setSelectionMode( QIconView::Extended );
+ setItemTextPos( QIconView::Bottom );
+ d->releaseMouseEvent = false;
+ d->pFileTip = new KonqFileTip(this);
+ d->firstClick = false;
+ calculateGridX();
+ setAutoArrange( true );
+ setSorting( true, sortDirection() );
+ readAnimatedIconsConfig();
+ m_bSortDirsFirst = true;
+ m_bMousePressed = false;
+ m_LineupMode = LineupBoth;
+ // emit our signals
+ slotSelectionChanged();
+ m_iconPositionGroupPrefix = QString::fromLatin1( "IconPosition::" );
+ KonqUndoManager::incRef();
+}
+
+KonqIconViewWidget::~KonqIconViewWidget()
+{
+ stopImagePreview();
+ KonqUndoManager::decRef();
+ delete d;
+}
+
+bool KonqIconViewWidget::maySetWallpaper()
+{
+ return d->bAllowSetWallpaper;
+}
+
+void KonqIconViewWidget::setMaySetWallpaper(bool b)
+{
+ d->bAllowSetWallpaper = b;
+}
+
+void KonqIconViewWidget::focusOutEvent( QFocusEvent * ev )
+{
+ // We can't possibly have the mouse pressed and still lose focus.
+ // Well, we can, but when we regain focus we should assume the mouse is
+ // not down anymore or the slotOnItem code will break with highlighting!
+ m_bMousePressed = false;
+
+ // This will ensure that tooltips don't pop up and the mouseover icon
+ // effect will go away if the mouse goes out of the view without
+ // first moving into an empty portion of the view
+ // Fixes part of #86968, and #85204
+ // Matt Newell 2004-09-24
+ slotOnViewport();
+
+ KIconView::focusOutEvent( ev );
+}
+
+void KonqIconViewWidget::slotItemRenamed(QIconViewItem *item, const QString &name)
+{
+ kdDebug(1203) << "KonqIconViewWidget::slotItemRenamed" << endl;
+ KFileIVI *viewItem = static_cast<KFileIVI *>(item);
+ KFileItem *fileItem = viewItem->item();
+
+ // The correct behavior is to show the old name until the rename has successfully
+ // completed. Unfortunately, KIconView forces us to allow the text to be changed
+ // before we try the rename, so set it back to the pre-rename state.
+ viewItem->setText( fileItem->text() );
+ kdDebug(1203)<<" fileItem->text() ;"<<fileItem->text()<<endl;
+ // Don't do anything if the user renamed to a blank name.
+ if( !name.isEmpty() )
+ {
+ // Actually attempt the rename. If it succeeds, KDirLister will update the name.
+ KURL oldurl( fileItem->url() );
+ KURL newurl( oldurl );
+ newurl.setPath( newurl.directory(false) + KIO::encodeFileName( name ) );
+ kdDebug(1203)<<" newurl :"<<newurl<<endl;
+ // We use url()+name so that it also works if the name is a relative path (#51176)
+ KonqOperations::rename( this, oldurl, newurl );
+ }
+}
+
+void KonqIconViewWidget::slotIconChanged( int group )
+{
+ if (group != KIcon::Desktop)
+ return;
+
+ int size = m_size;
+ if ( m_size == 0 )
+ m_size = -1; // little trick to force grid change in setIcons
+ setIcons( size ); // force re-determining all icons
+ readAnimatedIconsConfig();
+}
+
+void KonqIconViewWidget::readAnimatedIconsConfig()
+{
+ KConfigGroup cfgGroup( KGlobal::config(), "DesktopIcons" );
+ d->doAnimations = cfgGroup.readBoolEntry( "Animated", true /*default*/ );
+}
+
+void KonqIconViewWidget::slotOnItem( QIconViewItem *_item )
+{
+ KFileIVI* item = static_cast<KFileIVI *>( _item );
+ // Reset icon of previous item
+ if( d->pActiveItem != 0L && d->pActiveItem != item )
+ {
+ if ( d->m_movie && d->pActiveItem->isAnimated() )
+ {
+ d->m_movie->pause(); // we'll see below what we do with it
+ d->pActiveItem->setAnimated( false );
+ d->pActiveItem->refreshIcon( true );
+ }
+ else {
+ d->pActiveItem->setActive( false );
+ }
+ d->pActiveItem = 0L;
+ d->pFileTip->setItem( 0L );
+ }
+
+ // Stop sound
+ if (d->pSoundPlayer != 0 && item != d->pSoundItem)
+ {
+ d->pSoundPlayer->stop();
+
+ d->pSoundItem = 0;
+ if (d->pSoundTimer && d->pSoundTimer->isActive())
+ d->pSoundTimer->stop();
+ }
+
+ if ( !m_bMousePressed )
+ {
+ if( item != d->pActiveItem )
+ {
+ d->pActiveItem = item;
+ d->pFileTip->setItem( d->pActiveItem->item(),
+ item->rect(),
+ item->pixmap() );
+
+ if ( d->doAnimations && d->pActiveItem && d->pActiveItem->hasAnimation() )
+ {
+ //kdDebug(1203) << "Playing animation for: " << d->pActiveItem->mouseOverAnimation() << endl;
+ // Check if cached movie can be used
+#if 0 // Qt-mng bug, reusing the movie doesn't work currently.
+ if ( d->m_movie && d->movieFileName == d->pActiveItem->mouseOverAnimation() )
+ {
+ d->pActiveItem->setAnimated( true );
+ if (d->m_movieBlocked) {
+ kdDebug(1203) << "onitem, but blocked" << endl;
+ d->m_movie->pause();
+ }
+ else {
+ kdDebug(1203) << "we go ahead.." << endl;
+ d->m_movieBlocked++;
+ QTimer::singleShot(300, this, SLOT(slotReenableAnimation()));
+ d->m_movie->restart();
+ d->m_movie->unpause();
+ }
+ }
+ else
+#endif
+ {
+ QMovie movie = KGlobal::iconLoader()->loadMovie( d->pActiveItem->mouseOverAnimation(), KIcon::Desktop, d->pActiveItem->iconSize() );
+ if ( !movie.isNull() )
+ {
+ delete d->m_movie;
+ d->m_movie = new QMovie( movie ); // shallow copy, don't worry
+ // Fix alpha-channel - currently only if no background pixmap,
+ // the bg pixmap case requires to uncomment the code at qmovie.cpp:404
+ const QPixmap* pm = backgroundPixmap();
+ bool hasPixmap = pm && !pm->isNull();
+ if ( !hasPixmap ) {
+ pm = viewport()->backgroundPixmap();
+ hasPixmap = pm && !pm->isNull();
+ }
+ if (!hasPixmap && backgroundMode() != NoBackground)
+ d->m_movie->setBackgroundColor( viewport()->backgroundColor() );
+ d->m_movie->connectUpdate( this, SLOT( slotMovieUpdate(const QRect &) ) );
+ d->m_movie->connectStatus( this, SLOT( slotMovieStatus(int) ) );
+ d->movieFileName = d->pActiveItem->mouseOverAnimation();
+ d->pActiveItem->setAnimated( true );
+ }
+ else
+ {
+ d->pActiveItem->setAnimated( false );
+ if (d->m_movie)
+ d->m_movie->pause();
+ // No movie available, remember it
+ d->pActiveItem->setMouseOverAnimation( QString::null );
+ }
+ }
+ } // animations
+ // Only do the normal "mouseover" effect if no animation is in use
+ if (d->pActiveItem && !d->pActiveItem->isAnimated())
+ {
+ d->pActiveItem->setActive( true );
+ }
+ }
+ else // No change in current item
+ {
+ // No effect. If we want to underline on hover, we should
+ // force the IVI to repaint here, though!
+ d->pActiveItem = 0L;
+ d->pFileTip->setItem( 0L );
+ }
+ } // bMousePressed
+ else
+ {
+ // All features disabled during mouse clicking, e.g. rectangular
+ // selection
+ d->pActiveItem = 0L;
+ d->pFileTip->setItem( 0L );
+ }
+
+ // ## shouldn't this be disabled during rectangular selection too ?
+ if (d->bSoundPreviews && d->pSoundPlayer &&
+ d->pSoundPlayer->mimeTypes().contains(
+ item->item()->mimetype())
+ && KGlobalSettings::showFilePreview(item->item()->url())
+ && topLevelWidget() == kapp->activeWindow())
+ {
+ d->pSoundItem = item;
+ d->bSoundItemClicked = false;
+ if (!d->pSoundTimer)
+ {
+ d->pSoundTimer = new QTimer(this);
+ connect(d->pSoundTimer, SIGNAL(timeout()), SLOT(slotStartSoundPreview()));
+ }
+ if (d->pSoundTimer->isActive())
+ d->pSoundTimer->stop();
+ d->pSoundTimer->start(500, true);
+ }
+ else
+ {
+ if (d->pSoundPlayer)
+ d->pSoundPlayer->stop();
+ d->pSoundItem = 0;
+ if (d->pSoundTimer && d->pSoundTimer->isActive())
+ d->pSoundTimer->stop();
+ }
+}
+
+void KonqIconViewWidget::slotOnViewport()
+{
+ d->pFileTip->setItem( 0L );
+
+ if (d->pSoundPlayer)
+ d->pSoundPlayer->stop();
+ d->pSoundItem = 0;
+ if (d->pSoundTimer && d->pSoundTimer->isActive())
+ d->pSoundTimer->stop();
+
+ if (d->pActiveItem == 0L)
+ return;
+
+ if ( d->doAnimations && d->m_movie && d->pActiveItem->isAnimated() )
+ {
+ d->pActiveItem->setAnimated( false );
+#if 0
+ // Aborting before the end of the animation ?
+ if (d->m_movie->running()) {
+ d->m_movie->pause();
+ d->m_movieBlocked++;
+ kdDebug(1203) << "on viewport, blocking" << endl;
+ QTimer::singleShot(300, this, SLOT(slotReenableAnimation()));
+ }
+#endif
+ d->pActiveItem->refreshIcon( true );
+ Q_ASSERT( d->pActiveItem->state() == KIcon::DefaultState );
+ //delete d->m_movie;
+ //d->m_movie = 0L;
+ // TODO a timer to delete the movie after some time if unused?
+ }
+ else
+ {
+ d->pActiveItem->setActive( false );
+ }
+ d->pActiveItem = 0L;
+}
+
+void KonqIconViewWidget::slotStartSoundPreview()
+{
+ if (!d->pSoundItem || d->bSoundItemClicked)
+ return;
+
+ d->pSoundPlayer->play(d->pSoundItem->item()->url().url());
+}
+
+
+void KonqIconViewWidget::slotPreview(const KFileItem *item, const QPixmap &pix)
+{
+ // ### slow. Idea: move KonqKfmIconView's m_itemDict into this class
+ for (QIconViewItem *it = firstItem(); it; it = it->nextItem())
+ {
+ KFileIVI* current = static_cast<KFileIVI *>(it);
+ if (current->item() == item)
+ {
+ if (item->overlays() & KIcon::HiddenOverlay) {
+ QPixmap p(pix);
+
+ KIconEffect::semiTransparent(p);
+ current->setThumbnailPixmap(p);
+ } else {
+ current->setThumbnailPixmap(pix);
+ }
+ break;
+ }
+ }
+}
+
+void KonqIconViewWidget::slotPreviewResult()
+{
+ d->pPreviewJob = 0;
+ emit imagePreviewFinished();
+}
+
+void KonqIconViewWidget::slotToolTipPreview(const KFileItem* , const QPixmap &)
+{
+// unused - remove for KDE4
+}
+
+void KonqIconViewWidget::slotToolTipPreviewResult()
+{
+// unused - remove for KDE4
+}
+
+void KonqIconViewWidget::slotMovieUpdate( const QRect& rect )
+{
+ //kdDebug(1203) << "KonqIconViewWidget::slotMovieUpdate " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << endl;
+ Q_ASSERT( d );
+ Q_ASSERT( d->m_movie );
+ // seems stopAnimation triggers one last update
+ if ( d->pActiveItem && d->m_movie && d->pActiveItem->isAnimated() ) {
+ const QPixmap &frame = d->m_movie->framePixmap();
+ // This can happen if the icon was scaled to the desired size, so KIconLoader
+ // will happily return a movie with different dimensions than the icon
+ int iconSize=d->pActiveItem->iconSize();
+ if (iconSize==0) iconSize = KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+ if ( frame.width() != iconSize || frame.height() != iconSize ) {
+ d->pActiveItem->setAnimated( false );
+ d->m_movie->pause();
+ // No movie available, remember it
+ d->pActiveItem->setMouseOverAnimation( QString::null );
+ d->pActiveItem->setActive( true );
+ return;
+ }
+ d->pActiveItem->setPixmapDirect( frame, false, false /*no redraw*/ );
+ QRect pixRect = d->pActiveItem->pixmapRect(false);
+ repaintContents( pixRect.x() + rect.x(), pixRect.y() + rect.y(), rect.width(), rect.height(), false );
+ }
+}
+
+void KonqIconViewWidget::slotMovieStatus( int status )
+{
+ if ( status < 0 ) {
+ // Error playing the MNG -> forget about it and do normal iconeffect
+ if ( d->pActiveItem && d->pActiveItem->isAnimated() ) {
+ d->pActiveItem->setAnimated( false );
+ d->pActiveItem->setMouseOverAnimation( QString::null );
+ d->pActiveItem->setActive( true );
+ }
+ }
+}
+
+void KonqIconViewWidget::slotReenableAnimation()
+{
+ if (!--d->m_movieBlocked) {
+ if ( d->pActiveItem && d->m_movie && d->m_movie->paused()) {
+ kdDebug(1203) << "reenabled animation" << endl;
+ d->m_movie->restart();
+ d->m_movie->unpause();
+ }
+ }
+}
+
+void KonqIconViewWidget::clear()
+{
+ d->pFileTip->setItem( 0L );
+ stopImagePreview(); // Just in case
+ KIconView::clear();
+ d->pActiveItem = 0L;
+}
+
+void KonqIconViewWidget::takeItem( QIconViewItem *item )
+{
+ if ( d->pActiveItem == static_cast<KFileIVI *>(item) )
+ {
+ d->pFileTip->setItem( 0L );
+ d->pActiveItem = 0L;
+ }
+
+ if ( d->pPreviewJob )
+ d->pPreviewJob->removeItem( static_cast<KFileIVI *>(item)->item() );
+
+ KIconView::takeItem( item );
+}
+
+// Currently unused - remove in KDE 4.0
+void KonqIconViewWidget::setThumbnailPixmap( KFileIVI * item, const QPixmap & pixmap )
+{
+ if ( item )
+ {
+ if ( d->pActiveItem == item )
+ {
+ d->pFileTip->setItem( 0L );
+ d->pActiveItem = 0L;
+ }
+ item->setThumbnailPixmap( pixmap );
+ if ( m_bSetGridX && item->width() > gridX() )
+ {
+ setGridX( item->width() );
+ if (autoArrange())
+ arrangeItemsInGrid();
+ }
+ }
+}
+
+bool KonqIconViewWidget::initConfig( bool bInit )
+{
+ bool fontChanged = false;
+
+ // Color settings
+ QColor normalTextColor = m_pSettings->normalTextColor();
+ setItemColor( normalTextColor );
+
+ if (m_bDesktop)
+ {
+ QColor itemTextBg = m_pSettings->itemTextBackground();
+ if ( itemTextBg.isValid() )
+ setItemTextBackground( itemTextBg );
+ else
+ setItemTextBackground( NoBrush );
+ }
+
+ bool on = m_pSettings->showFileTips() && QToolTip::isGloballyEnabled();
+ d->pFileTip->setOptions(on,
+ m_pSettings->showPreviewsInFileTips(),
+ m_pSettings->numFileTips());
+
+ // if the user wants our own tooltip, don't show the one from Qts ListView
+ setShowToolTips(!on);
+
+ // Font settings
+ QFont font( m_pSettings->standardFont() );
+ if (!m_bDesktop)
+ font.setUnderline( m_pSettings->underlineLink() );
+
+ if ( font != KonqIconViewWidget::font() )
+ {
+ setFont( font );
+ if (!bInit)
+ {
+ // QIconView doesn't do it by default... but if the font is made much
+ // bigger, we really need to give more space between the icons
+ fontChanged = true;
+ }
+ }
+
+ setIconTextHeight( m_pSettings->iconTextHeight() );
+
+ if ( (itemTextPos() == QIconView::Right) && (maxItemWidth() != gridXValue()) )
+ {
+ int size = m_size;
+ m_size = -1; // little trick to force grid change in setIcons
+ setIcons( size ); // force re-determining all icons
+ }
+ else if ( d->bBoostPreview != boostPreview() ) // Update icons if settings for preview icon size have changed
+ setIcons(m_size);
+ else if (!bInit)
+ updateContents();
+ return fontChanged;
+}
+
+bool KonqIconViewWidget::boostPreview() const
+{
+ if ( m_bDesktop ) return false;
+
+ KConfigGroup group( KGlobal::config(), "PreviewSettings" );
+ return group.readBoolEntry( "BoostSize", false );
+}
+
+void KonqIconViewWidget::disableSoundPreviews()
+{
+ d->bSoundPreviews = false;
+
+ if (d->pSoundPlayer)
+ d->pSoundPlayer->stop();
+ d->pSoundItem = 0;
+ if (d->pSoundTimer && d->pSoundTimer->isActive())
+ d->pSoundTimer->stop();
+}
+
+void KonqIconViewWidget::setIcons( int size, const QStringList& stopImagePreviewFor )
+{
+ // size has changed?
+ bool sizeChanged = (m_size != size);
+ int oldGridX = gridX();
+ m_size = size;
+
+ // boost preview option has changed?
+ bool boost = boostPreview();
+ bool previewSizeChanged = ( d->bBoostPreview != boost );
+ d->bBoostPreview = boost;
+
+ if ( sizeChanged || previewSizeChanged )
+ {
+ int realSize = size ? size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+ // choose spacing depending on font, but min 5 (due to KFileIVI move limit)
+ setSpacing( ( m_bDesktop || ( realSize > KIcon::SizeSmall ) ) ?
+ QMAX( 5, QFontMetrics(font()).width('n') ) : 0 );
+ }
+
+ if ( sizeChanged || previewSizeChanged || !stopImagePreviewFor.isEmpty() )
+ {
+ calculateGridX();
+ }
+ bool stopAll = !stopImagePreviewFor.isEmpty() && stopImagePreviewFor.first() == "*";
+
+ // Disable repaints that can be triggered by ivi->setIcon(). Since icons are
+ // resized in-place, if the icon size is increasing it can happens that the right
+ // or bottom icons exceed the size of the viewport.. here we prevent the repaint
+ // event that will be triggered in that case.
+ bool prevUpdatesState = viewport()->isUpdatesEnabled();
+ viewport()->setUpdatesEnabled( false );
+
+ // Do this even if size didn't change, since this is used by refreshMimeTypes...
+ for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
+ KFileIVI * ivi = static_cast<KFileIVI *>( it );
+ // Set a normal icon for files that are not thumbnails, and for files
+ // that are thumbnails but for which it should be stopped
+ if ( !ivi->isThumbnail() ||
+ sizeChanged ||
+ previewSizeChanged ||
+ stopAll ||
+ mimeTypeMatch( ivi->item()->mimetype(), stopImagePreviewFor ) )
+ {
+ ivi->setIcon( size, ivi->state(), true, false );
+ }
+ else
+ ivi->invalidateThumb( ivi->state(), true );
+ }
+
+ // Restore viewport update to previous state
+ viewport()->setUpdatesEnabled( prevUpdatesState );
+
+ if ( ( sizeChanged || previewSizeChanged || oldGridX != gridX() ||
+ !stopImagePreviewFor.isEmpty() ) && autoArrange() )
+ arrangeItemsInGrid( true ); // take new grid into account and repaint
+ else
+ viewport()->update(); //Repaint later..
+}
+
+bool KonqIconViewWidget::mimeTypeMatch( const QString& mimeType, const QStringList& mimeList ) const
+{
+ // Code duplication from KIO::PreviewJob
+ KMimeType::Ptr mime = KMimeType::mimeType( mimeType );
+ for (QStringList::ConstIterator mt = mimeList.begin(); mt != mimeList.end(); ++mt)
+ {
+ if ( mime->is( *mt ) )
+ return true;
+ // Support for *mt == "image/*"
+ QString tmp( mimeType );
+ if ( (*mt).endsWith("*") && tmp.replace(QRegExp("/.*"), "/*") == (*mt) )
+ return true;
+ if ( (*mt) == "text/plain" )
+ {
+ QVariant textProperty = mime->property( "X-KDE-text" );
+ if ( textProperty.type() == QVariant::Bool && textProperty.toBool() )
+ return true;
+ }
+ }
+ return false;
+}
+
+void KonqIconViewWidget::setItemTextPos( ItemTextPos pos )
+{
+ // can't call gridXValue() because this already would need the new itemTextPos()
+ int sz = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+
+ if ( m_bSetGridX )
+ if ( pos == QIconView::Bottom )
+ setGridX( QMAX( sz + 50, previewIconSize( sz ) + 13 ) );
+ else
+ {
+ setMaxItemWidth( QMAX( sz, previewIconSize( sz ) ) + m_pSettings->iconTextWidth() );
+ setGridX( -1 );
+ }
+
+ KIconView::setItemTextPos( pos );
+}
+
+void KonqIconViewWidget::gridValues( int* x, int* y, int* dx, int* dy,
+ int* nx, int* ny )
+{
+ int previewSize = previewIconSize( m_size );
+ int iconSize = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+
+ // Grid size
+ // as KFileIVI limits to move an icon to x >= 5, y >= 5, we define a grid cell as:
+ // spacing() must be >= 5 (currently set to 5 in setIcons())
+ // horizontal: left spacing() + <width>
+ // vertical : top spacing(), <height>, bottom spacing()
+ // The doubled space in y-direction gives a better visual separation and makes it clearer
+ // to which item the text belongs
+ *dx = spacing() + QMAX( QMAX( iconSize, previewSize ), m_pSettings->iconTextWidth() );
+ int textHeight = iconTextHeight() * fontMetrics().height();
+ *dy = spacing() + QMAX( iconSize, previewSize ) + 2 + textHeight + spacing();
+
+ // Icon Area
+ int w, h;
+ if ( m_IconRect.isValid() ) { // w and h must be != 0, otherwise we would get a div by zero
+ *x = m_IconRect.left(); w = m_IconRect.width();
+ *y = m_IconRect.top(); h = m_IconRect.height();
+ }
+ else {
+ *x = 0; w = viewport()->width();
+ *y = 0; h = viewport()->height();
+ }
+
+ // bug:110775 avoid div by zero (happens e.g. when iconTextHeight or iconTextWidth are very large)
+ if ( *dx > w )
+ *dx = w;
+
+ if ( *dy > h )
+ *dy = h;
+
+ *nx = w / *dx;
+ *ny = h / *dy;
+ // TODO: Check that items->count() <= nx * ny
+
+ // Let have exactly nx columns and ny rows
+ if(*nx && *ny) {
+ *dx = w / *nx;
+ *dy = h / *ny;
+ }
+ kdDebug(1203) << "x=" << *x << " y=" << *y << " spacing=" << spacing() << " iconSize=" << iconSize
+ << " w=" << w << " h=" << h
+ << " nx=" << *nx << " ny=" << *ny
+ << " dx=" << *dx << " dy=" << *dy << endl;
+}
+
+void KonqIconViewWidget::calculateGridX()
+{
+ if ( m_bSetGridX )
+ if ( itemTextPos() == QIconView::Bottom )
+ setGridX( gridXValue() );
+ else
+ {
+ setMaxItemWidth( gridXValue() );
+ setGridX( -1 );
+ }
+}
+
+int KonqIconViewWidget::gridXValue() const
+{
+ // this method is only used in konqi as filemanager (not desktop)
+ int sz = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+ int newGridX;
+
+ if ( itemTextPos() == QIconView::Bottom )
+ newGridX = QMAX( sz + 50, previewIconSize( sz ) + 13 );
+ else
+ newGridX = QMAX( sz, previewIconSize( sz ) ) + m_pSettings->iconTextWidth();
+
+ //kdDebug(1203) << "gridXValue: " << newGridX << " sz=" << sz << endl;
+ return newGridX;
+}
+
+void KonqIconViewWidget::refreshMimeTypes()
+{
+ updatePreviewMimeTypes();
+ for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
+ (static_cast<KFileIVI *>( it ))->item()->refreshMimeType();
+ setIcons( m_size );
+}
+
+void KonqIconViewWidget::setURL( const KURL &kurl )
+{
+ stopImagePreview();
+ m_url = kurl;
+
+ d->pFileTip->setPreview( KGlobalSettings::showFilePreview(m_url) );
+
+ if ( m_url.isLocalFile() )
+ m_dotDirectoryPath = m_url.path(1).append( ".directory" );
+ else
+ m_dotDirectoryPath = QString::null;
+}
+
+void KonqIconViewWidget::startImagePreview( const QStringList &, bool force )
+{
+ stopImagePreview(); // just in case
+
+ // Check config
+ if ( !KGlobalSettings::showFilePreview( url() ) ) {
+ kdDebug(1203) << "Previews disabled for protocol " << url().protocol() << endl;
+ emit imagePreviewFinished();
+ return;
+ }
+
+ if ((d->bSoundPreviews = d->previewSettings.contains( "audio/" )) &&
+ !d->pSoundPlayer)
+ {
+ KLibFactory *factory = KLibLoader::self()->factory("konq_sound");
+ if (factory)
+ d->pSoundPlayer = static_cast<KonqSoundPlayer *>(
+ factory->create(this, 0, "KonqSoundPlayer"));
+ d->bSoundPreviews = (d->pSoundPlayer != 0L);
+ }
+
+ KFileItemList items;
+ for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
+ if ( force || !static_cast<KFileIVI *>( it )->hasValidThumbnail() )
+ items.append( static_cast<KFileIVI *>( it )->item() );
+
+ bool onlyAudio = true;
+ for ( QStringList::ConstIterator it = d->previewSettings.begin(); it != d->previewSettings.end(); ++it ) {
+ if ( (*it).startsWith( "audio/" ) )
+ d->bSoundPreviews = true;
+ else
+ onlyAudio = false;
+ }
+
+ if ( items.isEmpty() || onlyAudio ) {
+ emit imagePreviewFinished();
+ return; // don't start the preview job if not really necessary
+ }
+
+ int iconSize = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+ int size;
+
+ d->bBoostPreview = boostPreview();
+ size = previewIconSize( iconSize );
+
+ if ( !d->bBoostPreview )
+ iconSize /= 2;
+
+ d->pPreviewJob = KIO::filePreview( items, size, size, iconSize,
+ m_pSettings->textPreviewIconTransparency(), true /* scale */,
+ true /* save */, &(d->previewSettings) );
+ connect( d->pPreviewJob, SIGNAL( gotPreview( const KFileItem *, const QPixmap & ) ),
+ this, SLOT( slotPreview( const KFileItem *, const QPixmap & ) ) );
+ connect( d->pPreviewJob, SIGNAL( result( KIO::Job * ) ),
+ this, SLOT( slotPreviewResult() ) );
+}
+
+void KonqIconViewWidget::stopImagePreview()
+{
+ if (d->pPreviewJob)
+ {
+ d->pPreviewJob->kill();
+ d->pPreviewJob = 0;
+ // Now that previews are updated in-place, calling
+ // arrangeItemsInGrid() here is not needed anymore
+ }
+}
+
+bool KonqIconViewWidget::isPreviewRunning() const
+{
+ return d->pPreviewJob;
+}
+
+KFileItemList KonqIconViewWidget::selectedFileItems()
+{
+ KFileItemList lstItems;
+
+ QIconViewItem *it = firstItem();
+ for (; it; it = it->nextItem() )
+ if ( it->isSelected() ) {
+ KFileItem *fItem = (static_cast<KFileIVI *>(it))->item();
+ lstItems.append( fItem );
+ }
+ return lstItems;
+}
+
+void KonqIconViewWidget::slotDropped( QDropEvent *ev, const QValueList<QIconDragItem> & )
+{
+ // Drop on background
+ KURL dirURL = url();
+ if ( m_rootItem ) {
+ bool dummy;
+ dirURL = m_rootItem->mostLocalURL(dummy);
+ }
+ KonqOperations::doDrop( m_rootItem /* may be 0L */, dirURL, ev, this );
+}
+
+void KonqIconViewWidget::slotAboutToCreate(const QPoint &, const QValueList<KIO::CopyInfo> &)
+{
+ // Do nothing :-)
+}
+
+void KonqIconViewWidget::drawBackground( QPainter *p, const QRect &r )
+{
+ drawBackground(p, r, r.topLeft());
+}
+
+void KonqIconViewWidget::drawBackground( QPainter *p, const QRect &r , const QPoint &pt)
+{
+ const QPixmap *pm = backgroundPixmap();
+ bool hasPixmap = pm && !pm->isNull();
+ if ( !hasPixmap ) {
+ pm = viewport()->backgroundPixmap();
+ hasPixmap = pm && !pm->isNull();
+ }
+
+ QRect rtgt(r);
+ rtgt.moveTopLeft(pt);
+ if (!hasPixmap && backgroundMode() != NoBackground) {
+ p->fillRect(rtgt, viewport()->backgroundColor());
+ return;
+ }
+
+ if (hasPixmap) {
+ int ax = (r.x() + contentsX() + leftMargin()) % pm->width();
+ int ay = (r.y() + contentsY() + topMargin()) % pm->height();
+ p->drawTiledPixmap(rtgt, *pm, QPoint(ax, ay));
+ }
+}
+
+QDragObject * KonqIconViewWidget::dragObject()
+{
+ if ( !currentItem() )
+ return 0;
+
+ return konqDragObject( viewport() );
+}
+
+KonqIconDrag * KonqIconViewWidget::konqDragObject( QWidget * dragSource )
+{
+ //kdDebug(1203) << "KonqIconViewWidget::konqDragObject" << endl;
+
+ KonqIconDrag2 * drag = new KonqIconDrag2( dragSource );
+ QIconViewItem *primaryItem = currentItem();
+ // Append all items to the drag object
+ for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
+ if ( it->isSelected() ) {
+ if (!primaryItem)
+ primaryItem = it;
+ KFileItem* fileItem = (static_cast<KFileIVI *>(it))->item();
+ KURL url = fileItem->url();
+ bool dummy;
+ KURL mostLocalURL = fileItem->mostLocalURL(dummy);
+ QString itemURL = KURLDrag::urlToString(url);
+ kdDebug(1203) << "itemURL=" << itemURL << endl;
+ QIconDragItem id;
+ id.setData( QCString(itemURL.latin1()) );
+ drag->append( id,
+ QRect( it->pixmapRect(false).topLeft() - m_mousePos,
+ it->pixmapRect().size() ),
+ QRect( it->textRect(false).topLeft() - m_mousePos,
+ it->textRect().size() ),
+ itemURL, mostLocalURL );
+ }
+ }
+
+ if (primaryItem)
+ drag->setPixmap( *primaryItem->pixmap(), m_mousePos - primaryItem->pixmapRect(false).topLeft() );
+
+ return drag;
+}
+
+void KonqIconViewWidget::contentsDragEnterEvent( QDragEnterEvent *e )
+{
+ if ( e->provides( "text/uri-list" ) )
+ {
+ QByteArray payload = e->encodedData( "text/uri-list" );
+ if ( !payload.size() )
+ kdError() << "Empty data !" << endl;
+ // Cache the URLs, since we need them every time we move over a file
+ // (see KFileIVI)
+ bool ok = KURLDrag::decode( e, m_lstDragURLs );
+ if( !ok )
+ kdError() << "Couldn't decode urls dragged !" << endl;
+ }
+
+ KURL::List uriList;
+ if ( KURLDrag::decode(e, uriList) )
+ {
+ if ( uriList.first().protocol() == "programs" )
+ {
+ e->ignore();
+ emit dragEntered( false );
+ d->bProgramsURLdrag = true;
+ return;
+ }
+ }
+
+ KIconView::contentsDragEnterEvent( e );
+ emit dragEntered( true /*accepted*/ );
+}
+
+void KonqIconViewWidget::contentsDragMoveEvent( QDragMoveEvent *e )
+{
+ if ( d->bProgramsURLdrag ) {
+ emit dragMove( false );
+ e->ignore();
+ cancelPendingHeldSignal();
+ return;
+ }
+
+ QIconViewItem *item = findItem( e->pos() );
+ if ( e->source() != viewport() &&
+ !item && m_rootItem && !m_rootItem->isWritable() ) {
+ emit dragMove( false );
+ e->ignore();
+ cancelPendingHeldSignal();
+ return;
+ }
+ emit dragMove( true );
+ KIconView::contentsDragMoveEvent( e );
+}
+
+void KonqIconViewWidget::contentsDragLeaveEvent( QDragLeaveEvent *e )
+{
+ d->bProgramsURLdrag = false;
+ KIconView::contentsDragLeaveEvent(e);
+ emit dragLeft();
+}
+
+
+void KonqIconViewWidget::setItemColor( const QColor &c )
+{
+ iColor = c;
+}
+
+QColor KonqIconViewWidget::itemColor() const
+{
+ return iColor;
+}
+
+void KonqIconViewWidget::disableIcons( const KURL::List & lst )
+{
+ for ( QIconViewItem *kit = firstItem(); kit; kit = kit->nextItem() )
+ {
+ bool bFound = false;
+ // Wow. This is ugly. Matching two lists together....
+ // Some sorting to optimise this would be a good idea ?
+ for (KURL::List::ConstIterator it = lst.begin(); !bFound && it != lst.end(); ++it)
+ {
+ if ( static_cast<KFileIVI *>( kit )->item()->url() == *it )
+ {
+ bFound = true;
+ // maybe remove "it" from lst here ?
+ }
+ }
+ static_cast<KFileIVI *>( kit )->setDisabled( bFound );
+ }
+}
+
+void KonqIconViewWidget::slotSelectionChanged()
+{
+ // This code is very related to ListViewBrowserExtension::updateActions
+ int canCopy = 0;
+ int canDel = 0;
+ int canTrash = 0;
+ bool bInTrash = false;
+ int iCount = 0;
+
+ for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
+ {
+ if ( it->isSelected() )
+ {
+ iCount++;
+ canCopy++;
+
+ KFileItem *item = ( static_cast<KFileIVI *>( it ) )->item();
+ KURL url = item->url();
+ QString local_path = item->localPath();
+
+ if ( url.directory(false) == KGlobalSettings::trashPath() )
+ bInTrash = true;
+ if ( KProtocolInfo::supportsDeleting( url ) )
+ canDel++;
+ if ( !local_path.isEmpty() )
+ canTrash++;
+ }
+ }
+
+ emit enableAction( "cut", canDel > 0 );
+ emit enableAction( "copy", canCopy > 0 );
+ emit enableAction( "trash", canDel > 0 && !bInTrash && canTrash==canDel );
+ emit enableAction( "del", canDel > 0 );
+ emit enableAction( "properties", iCount > 0 && KPropertiesDialog::canDisplay( selectedFileItems() ) );
+ emit enableAction( "editMimeType", ( iCount == 1 ) );
+ emit enableAction( "rename", ( iCount == 1) && !bInTrash );
+}
+
+void KonqIconViewWidget::renameCurrentItem()
+{
+ if ( currentItem() )
+ currentItem()->rename();
+}
+
+void KonqIconViewWidget::renameSelectedItem()
+{
+ kdDebug(1203) << " -- KonqIconViewWidget::renameSelectedItem() -- " << endl;
+ QIconViewItem * item = 0L;
+ QIconViewItem *it = firstItem();
+ for (; it; it = it->nextItem() )
+ if ( it->isSelected() && !item )
+ {
+ item = it;
+ break;
+ }
+ if (!item)
+ {
+ Q_ASSERT(item);
+ return;
+ }
+ item->rename();
+}
+
+void KonqIconViewWidget::cutSelection()
+{
+ kdDebug(1203) << " -- KonqIconViewWidget::cutSelection() -- " << endl;
+ KonqIconDrag * obj = konqDragObject( /* no parent ! */ );
+ obj->setMoveSelection( true );
+ QApplication::clipboard()->setData( obj );
+}
+
+void KonqIconViewWidget::copySelection()
+{
+ kdDebug(1203) << " -- KonqIconViewWidget::copySelection() -- " << endl;
+ KonqIconDrag * obj = konqDragObject( /* no parent ! */ );
+ QApplication::clipboard()->setData( obj );
+}
+
+void KonqIconViewWidget::pasteSelection()
+{
+ paste( url() );
+}
+
+void KonqIconViewWidget::paste( const KURL &url )
+{
+ KonqOperations::doPaste( this, url );
+}
+
+KURL::List KonqIconViewWidget::selectedUrls()
+{
+ return selectedUrls( UserVisibleUrls );
+}
+
+KURL::List KonqIconViewWidget::selectedUrls( UrlFlags flags ) const
+{
+ KURL::List lstURLs;
+ bool dummy;
+ for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
+ if ( it->isSelected() ) {
+ KFileItem* item = (static_cast<KFileIVI *>( it ))->item();
+ lstURLs.append( flags == MostLocalUrls ? item->mostLocalURL( dummy ) : item->url() );
+ }
+ return lstURLs;
+}
+
+QRect KonqIconViewWidget::iconArea() const
+{
+ return m_IconRect;
+}
+
+void KonqIconViewWidget::setIconArea(const QRect &rect)
+{
+ m_IconRect = rect;
+}
+
+int KonqIconViewWidget::lineupMode() const
+{
+ return m_LineupMode;
+}
+
+void KonqIconViewWidget::setLineupMode(int mode)
+{
+ m_LineupMode = mode;
+}
+
+bool KonqIconViewWidget::sortDirectoriesFirst() const
+{
+ return m_bSortDirsFirst;
+}
+
+void KonqIconViewWidget::setSortDirectoriesFirst( bool b )
+{
+ m_bSortDirsFirst = b;
+}
+
+void KonqIconViewWidget::contentsMouseMoveEvent( QMouseEvent *e )
+{
+ if ( (d->pSoundPlayer && d->pSoundPlayer->isPlaying()) || (d->pSoundTimer && d->pSoundTimer->isActive()))
+ {
+ // The following call is SO expensive (the ::widgetAt call eats up to 80%
+ // of the mouse move cpucycles!), so it's mandatory to place that function
+ // under strict checks, such as d->pSoundPlayer->isPlaying()
+ if ( QApplication::widgetAt( QCursor::pos() ) != topLevelWidget() )
+ {
+ if (d->pSoundPlayer)
+ d->pSoundPlayer->stop();
+ d->pSoundItem = 0;
+ if (d->pSoundTimer && d->pSoundTimer->isActive())
+ d->pSoundTimer->stop();
+ }
+ }
+ d->renameItem= false;
+ KIconView::contentsMouseMoveEvent( e );
+}
+
+void KonqIconViewWidget::contentsDropEvent( QDropEvent * ev )
+{
+ QIconViewItem *i = findItem( ev->pos() );
+
+ if ( ev->source() != viewport() &&
+ !i && m_rootItem && !m_rootItem->isWritable() ) {
+ ev->accept( false );
+ return;
+ }
+
+ // Short-circuit QIconView if Ctrl is pressed, so that it's possible
+ // to drop a file into its own parent widget to copy it.
+ if ( !i && (ev->action() == QDropEvent::Copy || ev->action() == QDropEvent::Link)
+ && ev->source() && ev->source() == viewport())
+ {
+ // First we need to call QIconView though, to clear the drag shape
+ bool bMovable = itemsMovable();
+ setItemsMovable(false); // hack ? call it what you want :-)
+ KIconView::contentsDropEvent( ev );
+ setItemsMovable(bMovable);
+
+ QValueList<QIconDragItem> lst;
+ slotDropped(ev, lst);
+ }
+ else
+ {
+ KIconView::contentsDropEvent( ev );
+ emit dropped(); // What is this for ? (David) KDE4: remove
+ }
+ // Don't do this here, it's too early !
+ // slotSaveIconPositions();
+ // If we want to save after the new file gets listed, though,
+ // we could reimplement contentsDropEvent in KDIconView and set m_bNeedSave. Bah.
+
+ // This signal is sent last because we need to ensure it is
+ // taken in account when all the slots triggered by the dropped() signal
+ // are executed. This way we know that the Drag and Drop is truely finished
+ emit dragFinished();
+}
+
+void KonqIconViewWidget::doubleClickTimeout()
+{
+ d->renameItem= true;
+ mousePressChangeValue();
+ if ( d->releaseMouseEvent )
+ {
+ QMouseEvent e( QEvent::MouseButtonPress,d->mousePos , 1, d->mouseState);
+ QIconViewItem* item = findItem( e.pos() );
+ KURL url;
+ if ( item )
+ {
+ url= ( static_cast<KFileIVI *>( item ) )->item()->url();
+ bool brenameTrash =false;
+ if ( url.isLocalFile() && (url.directory(false) == KGlobalSettings::trashPath() || url.path(1).startsWith(KGlobalSettings::trashPath())))
+ brenameTrash = true;
+
+ if ( url.isLocalFile() && !brenameTrash && d->renameItem && m_pSettings->renameIconDirectly() && e.button() == LeftButton && item->textRect( false ).contains(e.pos()))
+ {
+ if( d->pActivateDoubleClick->isActive () )
+ d->pActivateDoubleClick->stop();
+ item->rename();
+ m_bMousePressed = false;
+ }
+ }
+ }
+ else
+ {
+ QMouseEvent e( QEvent::MouseMove,d->mousePos , 1, d->mouseState);
+ KIconView::contentsMousePressEvent( &e );
+ }
+ if( d->pActivateDoubleClick->isActive() )
+ d->pActivateDoubleClick->stop();
+
+ d->releaseMouseEvent = false;
+ d->renameItem= false;
+}
+
+void KonqIconViewWidget::wheelEvent(QWheelEvent* e)
+{
+ // when scrolling with mousewheel, stop possible pending filetip
+ d->pFileTip->setItem( 0 );
+
+ if (e->state() == ControlButton)
+ {
+ if (e->delta() >= 0)
+ {
+ emit incIconSize();
+ }
+ else
+ {
+ emit decIconSize();
+ }
+ e->accept();
+ return;
+ }
+
+ KIconView::wheelEvent(e);
+}
+
+void KonqIconViewWidget::leaveEvent( QEvent *e )
+{
+ // when leaving the widget, stop possible pending filetip and icon effect
+ slotOnViewport();
+
+ KIconView::leaveEvent(e);
+}
+
+void KonqIconViewWidget::mousePressChangeValue()
+{
+ //kdDebug(1203) << "KonqIconViewWidget::contentsMousePressEvent" << endl;
+ m_bMousePressed = true;
+ if (d->pSoundPlayer)
+ d->pSoundPlayer->stop();
+ d->bSoundItemClicked = true;
+ d->firstClick = false;
+
+ // Once we click on the item, we don't want a tooltip
+ // Fixes part of #86968
+ d->pFileTip->setItem( 0 );
+}
+
+void KonqIconViewWidget::contentsMousePressEvent( QMouseEvent *e )
+{
+ if(d->pActivateDoubleClick && d->pActivateDoubleClick->isActive ())
+ d->pActivateDoubleClick->stop();
+ QIconViewItem* item = findItem( e->pos() );
+ m_mousePos = e->pos();
+ KURL url;
+ if ( item )
+ {
+ url = ( static_cast<KFileIVI *>( item ) )->item()->url();
+ bool brenameTrash =false;
+ if ( url.isLocalFile() && (url.directory(false) == KGlobalSettings::trashPath() || url.path(1).startsWith(KGlobalSettings::trashPath())))
+ brenameTrash = true;
+ if ( !brenameTrash && !KGlobalSettings::singleClick() && m_pSettings->renameIconDirectly() && e->button() == LeftButton && item->textRect( false ).contains(e->pos())&& !d->firstClick && url.isLocalFile() && (!url.protocol().find("device", 0, false)==0))
+ {
+ d->firstClick = true;
+ d->mousePos = e->pos();
+ d->mouseState = e->state();
+ if (!d->pActivateDoubleClick)
+ {
+ d->pActivateDoubleClick = new QTimer(this);
+ connect(d->pActivateDoubleClick, SIGNAL(timeout()), this, SLOT(doubleClickTimeout()));
+ }
+ if( d->pActivateDoubleClick->isActive () )
+ d->pActivateDoubleClick->stop();
+ else
+ d->pActivateDoubleClick->start(QApplication::doubleClickInterval());
+ d->releaseMouseEvent = false;
+ return;
+ }
+ else
+ d->renameItem= false;
+ }
+ else
+ d->renameItem= false;
+ mousePressChangeValue();
+ if(d->pActivateDoubleClick && d->pActivateDoubleClick->isActive())
+ d->pActivateDoubleClick->stop();
+ KIconView::contentsMousePressEvent( e );
+
+}
+
+void KonqIconViewWidget::contentsMouseReleaseEvent( QMouseEvent *e )
+{
+ KIconView::contentsMouseReleaseEvent( e );
+ if(d->releaseMouseEvent && d->pActivateDoubleClick && d->pActivateDoubleClick->isActive ())
+ d->pActivateDoubleClick->stop();
+ slotSelectionChanged();
+ d->releaseMouseEvent = true;
+ m_bMousePressed = false;
+}
+
+void KonqIconViewWidget::slotSaveIconPositions()
+{
+ // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ // This code is currently not used but left in for compatibility reasons.
+ // It can be removed in KDE 4.0
+ // Saving of desktop icon positions is now done in KDIconView::saveIconPositions()
+ // in kdebase/kdesktop/kdiconview.cc
+ // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+
+ if ( m_dotDirectoryPath.isEmpty() )
+ return;
+ if ( !m_bDesktop )
+ return; // Currently not available in Konqueror
+ kdDebug(1214) << "KonqIconViewWidget::slotSaveIconPositions" << endl;
+ KSimpleConfig dotDirectory( m_dotDirectoryPath );
+ QIconViewItem *it = firstItem();
+ if ( !it )
+ return; // No more icons. Maybe we're closing and they've been removed already
+ while ( it )
+ {
+ KFileIVI *ivi = static_cast<KFileIVI *>( it );
+ KFileItem *item = ivi->item();
+
+ dotDirectory.setGroup( QString( m_iconPositionGroupPrefix ).append( item->url().fileName() ) );
+ kdDebug(1214) << "KonqIconViewWidget::slotSaveIconPositions " << item->url().fileName() << " " << it->x() << " " << it->y() << endl;
+ dotDirectory.writeEntry( QString( "X %1" ).arg( width() ), it->x() );
+ dotDirectory.writeEntry( QString( "Y %1" ).arg( height() ), it->y() );
+ dotDirectory.writeEntry( "Exists", true );
+
+ it = it->nextItem();
+ }
+
+ QStringList groups = dotDirectory.groupList();
+ QStringList::ConstIterator gIt = groups.begin();
+ QStringList::ConstIterator gEnd = groups.end();
+ for (; gIt != gEnd; ++gIt )
+ if ( (*gIt).left( m_iconPositionGroupPrefix.length() ) == m_iconPositionGroupPrefix )
+ {
+ dotDirectory.setGroup( *gIt );
+ if ( dotDirectory.hasKey( "Exists" ) )
+ dotDirectory.deleteEntry( "Exists", false );
+ else
+ {
+ kdDebug(1214) << "KonqIconViewWidget::slotSaveIconPositions deleting group " << *gIt << endl;
+ dotDirectory.deleteGroup( *gIt );
+ }
+ }
+
+ dotDirectory.sync();
+
+ // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ // This code is currently not used but left in for compatibility reasons.
+ // It can be removed in KDE 4.0
+ // Saving of desktop icon positions is now done in KDIconView::saveIconPositions()
+ // in kdebase/kdesktop/kdiconview.cc
+ // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+}
+
+// Adapted version of QIconView::insertInGrid, that works relative to
+// m_IconRect, instead of the entire viewport.
+
+void KonqIconViewWidget::insertInGrid(QIconViewItem *item)
+{
+ if (0L == item)
+ return;
+
+ if (!m_IconRect.isValid())
+ {
+ KIconView::insertInGrid(item);
+ return;
+ }
+
+ QRegion r(m_IconRect);
+ QIconViewItem *i = firstItem();
+ int y = -1;
+ for (; i; i = i->nextItem() )
+ {
+ r = r.subtract(i->rect());
+ y = QMAX(y, i->y() + i->height());
+ }
+
+ QMemArray<QRect> rects = r.rects();
+ QMemArray<QRect>::Iterator it = rects.begin();
+ bool foundPlace = FALSE;
+ for (; it != rects.end(); ++it)
+ {
+ QRect rect = *it;
+ if (rect.width() >= item->width() && rect.height() >= item->height())
+ {
+ int sx = 0, sy = 0;
+ if (rect.width() >= item->width() + spacing())
+ sx = spacing();
+ if (rect.height() >= item->height() + spacing())
+ sy = spacing();
+ item->move(rect.x() + sx, rect.y() + sy);
+ foundPlace = true;
+ break;
+ }
+ }
+
+ if (!foundPlace)
+ item->move(m_IconRect.topLeft());
+
+ //item->dirty = false;
+ return;
+}
+
+
+/*
+ * The algorithm used for lineing up the icons could be called
+ * "beating flat the icon field". Imagine the icon field to be some height
+ * field on a regular grid, with the height being the number of icons in
+ * each grid element. Now imagine slamming on the field with a shovel or
+ * some other flat surface. The high peaks will be flattened and spread out
+ * over their adjacent areas. This is basically what the algorithm tries to
+ * simulate.
+ *
+ * First, the icons are binned to a grid of the desired size. If all bins
+ * are containing at most one icon, we're done, of course. We just have to
+ * move all icons to the center of each grid element.
+ * For each bin which has more than one icon in it, we calculate 4
+ * "friction coefficients", one for each cardinal direction. The friction
+ * coefficient of a direction is the number of icons adjacent in that
+ * direction. The idea is that this number is somewhat a measure in which
+ * direction the icons should flow: icons flow in the direction of lowest
+ * friction coefficient. We move a maximum of one icon per bin and loop over
+ * all bins. This procedure is repeated some maximum number of times or until
+ * no icons are moved anymore.
+ *
+ * I don't know if this algorithm is good or bad, I don't even know if it will
+ * work all the time. It seems a correct thing to do, however, and it seems to
+ * work particularly well. In any case, the number of runs is limited so there
+ * can be no races.
+ */
+
+void KonqIconViewWidget::lineupIcons()
+{
+ // even if there are no items yet, calculate the maxItemWidth to have the correct
+ // item rect when we insert new items
+
+ // Create a grid of (ny x nx) bins.
+ int x0, y0, dx, dy, nx, ny;
+ gridValues( &x0, &y0, &dx, &dy, &nx, &ny );
+
+ int itemWidth = dx - spacing();
+ bool newItemWidth = false;
+ if ( maxItemWidth() != itemWidth ) {
+ newItemWidth = true;
+ setMaxItemWidth( itemWidth );
+ setFont( font() ); // Force calcRect()
+ }
+
+ if ( !firstItem() ) {
+ kdDebug(1203) << "No icons at all ?\n";
+ return;
+ }
+
+ int iconSize = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+
+ typedef QValueList<QIconViewItem*> Bin;
+ Bin*** bins = new Bin**[nx];
+ int i;
+ int j;
+ for ( i = 0; i < nx ; i++ ) {
+ bins[i] = new Bin*[ny];
+ for ( j = 0; j < ny; j++ )
+ bins[i][j] = 0L;
+ }
+
+ // Insert items into grid
+ int textHeight = iconTextHeight() * fontMetrics().height();
+
+ for ( QIconViewItem* item = firstItem(); item; item = item->nextItem() ) {
+ int x = item->x() + item->width() / 2 - x0;
+ int y = item->pixmapRect( false ).bottom() - iconSize / 2
+ - ( dy - ( iconSize + textHeight ) ) / 2 - y0;
+ int posX = QMIN( nx-1, QMAX( 0, x / dx ) );
+ int posY = QMIN( ny-1, QMAX( 0, y / dy ) );
+
+ if ( !bins[posX][posY] )
+ bins[posX][posY] = new Bin;
+ bins[posX][posY]->prepend( item );
+ }
+
+ // The shuffle code
+ int n, k;
+ const int infinity = 10000;
+ int nmoves = 1;
+ for ( n = 0; n < 30 && nmoves > 0; n++ ) {
+ nmoves = 0;
+ for ( i = 0; i < nx; i++ ) {
+ for ( j = 0; j < ny; j++ ) {
+ if ( !bins[i][j] || ( bins[i][j]->count() <= 1 ) )
+ continue;
+
+ // Calculate the 4 "friction coefficients".
+ int tf = 0, bf = 0, lf = 0, rf = 0;
+ for ( k = j-1; k >= 0 && bins[i][k] && bins[i][k]->count(); k-- )
+ tf += bins[i][k]->count();
+ if ( k == -1 )
+ tf += infinity;
+
+ for ( k = j+1; k < ny && bins[i][k] && bins[i][k]->count(); k++ )
+ bf += bins[i][k]->count();
+ if ( k == ny )
+ bf += infinity;
+
+ for ( k = i-1; k >= 0 && bins[k][j] && bins[k][j]->count(); k-- )
+ lf += bins[k][j]->count();
+ if ( k == -1 )
+ lf += infinity;
+
+ for ( k = i+1; k < nx && bins[k][j] && bins[k][j]->count(); k++ )
+ rf += bins[k][j]->count();
+ if ( k == nx )
+ rf += infinity;
+
+ // If we are stuck between walls, continue
+ if ( tf >= infinity && bf >= infinity &&
+ lf >= infinity && rf >= infinity )
+ continue;
+
+ // Is there a preferred lineup direction?
+ if ( m_LineupMode == LineupHorizontal ) {
+ tf += infinity;
+ bf += infinity;
+ }
+ else if ( m_LineupMode == LineupVertical ) {
+ lf += infinity;
+ rf += infinity;
+ }
+
+ // Move one item in the direction of the least friction
+ QIconViewItem* movedItem;
+ Bin* items = bins[i][j];
+
+ int mini = QMIN( QMIN( tf, bf ), QMIN( lf, rf ) );
+ if ( tf == mini ) {
+ // move top item in (i,j) to (i,j-1)
+ Bin::iterator it = items->begin();
+ movedItem = *it;
+ for ( ++it; it != items->end(); ++it ) {
+ if ( (*it)->y() < movedItem->y() )
+ movedItem = *it;
+ }
+ items->remove( movedItem );
+ if ( !bins[i][j-1] )
+ bins[i][j-1] = new Bin;
+ bins[i][j-1]->prepend( movedItem );
+ }
+ else if ( bf ==mini ) {
+ // move bottom item in (i,j) to (i,j+1)
+ Bin::iterator it = items->begin();
+ movedItem = *it;
+ for ( ++it; it != items->end(); ++it ) {
+ if ( (*it)->y() > movedItem->y() )
+ movedItem = *it;
+ }
+ items->remove( movedItem );
+ if ( !bins[i][j+1] )
+ bins[i][j+1] = new Bin;
+ bins[i][j+1]->prepend( movedItem );
+ }
+ else if ( lf == mini )
+ {
+ // move left item in (i,j) to (i-1,j)
+ Bin::iterator it = items->begin();
+ movedItem = *it;
+ for ( ++it; it != items->end(); ++it ) {
+ if ( (*it)->x() < movedItem->x() )
+ movedItem = *it;
+ }
+ items->remove( movedItem );
+ if ( !bins[i-1][j] )
+ bins[i-1][j] = new Bin;
+ bins[i-1][j]->prepend( movedItem );
+ }
+ else {
+ // move right item in (i,j) to (i+1,j)
+ Bin::iterator it = items->begin();
+ movedItem = *it;
+ for ( ++it; it != items->end(); ++it ) {
+ if ( (*it)->x() > movedItem->x() )
+ movedItem = *it;
+ }
+ items->remove( movedItem );
+ if ( !bins[i+1][j] )
+ bins[i+1][j] = new Bin;
+ bins[i+1][j]->prepend( movedItem );
+ }
+ nmoves++;
+ }
+ }
+ }
+
+ // Perform the actual moving
+ QRegion repaintRegion;
+ QValueList<QIconViewItem*> movedItems;
+
+ for ( i = 0; i < nx; i++ ) {
+ for ( j = 0; j < ny; j++ ) {
+ Bin* bin = bins[i][j];
+ if ( !bin )
+ continue;
+ if ( !bin->isEmpty() ) {
+ QIconViewItem* item = bin->first();
+ int newX = x0 + i*dx + spacing() +
+ QMAX(0, ( (dx-spacing()) - item->width() ) / 2); // pixmap can be larger as iconsize
+ // align all icons vertically to their text
+ int newY = y0 + j*dy + dy - spacing() - ( item->pixmapRect().bottom() + 2 + textHeight );
+ if ( item->x() != newX || item->y() != newY ) {
+ QRect oldRect = item->rect();
+ movedItems.prepend( item );
+ item->move( newX, newY );
+ if ( item->rect() != oldRect )
+ repaintRegion = repaintRegion.unite( oldRect );
+ }
+ }
+ delete bin;
+ bins[i][j] = 0L;
+ }
+ }
+
+ // repaint
+ if ( newItemWidth )
+ updateContents();
+ else {
+ // Repaint only repaintRegion...
+ QMemArray<QRect> rects = repaintRegion.rects();
+ for ( uint l = 0; l < rects.count(); l++ ) {
+ kdDebug( 1203 ) << "Repainting (" << rects[l].x() << ","
+ << rects[l].y() << ")\n";
+ repaintContents( rects[l], false );
+ }
+ // Repaint icons that were moved
+ while ( !movedItems.isEmpty() ) {
+ repaintItem( movedItems.first() );
+ movedItems.remove( movedItems.first() );
+ }
+ }
+
+ for ( i = 0; i < nx ; i++ ) {
+ delete [] bins[i];
+ }
+ delete [] bins;
+}
+
+void KonqIconViewWidget::lineupIcons( QIconView::Arrangement arrangement )
+{
+ int x0, y0, dx, dy, nxmax, nymax;
+ gridValues( &x0, &y0, &dx, &dy, &nxmax, &nymax );
+ int textHeight = iconTextHeight() * fontMetrics().height();
+
+ QRegion repaintRegion;
+ QValueList<QIconViewItem*> movedItems;
+ int nx = 0, ny = 0;
+
+ QIconViewItem* item;
+ for ( item = firstItem(); item; item = item->nextItem() ) {
+ int newX = x0 + nx*dx + spacing() +
+ QMAX(0, ( (dx-spacing()) - item->width() ) / 2); // icon can be larger as defined
+ // align all icons vertically to their text
+ int newY = y0 + ny*dy + dy - spacing() - ( item->pixmapRect().bottom() + 2 + textHeight );
+ if ( item->x() != newX || item->y() != newY ) {
+ QRect oldRect = item->rect();
+ movedItems.prepend( item );
+ item->move( newX, newY );
+ if ( item->rect() != oldRect )
+ repaintRegion = repaintRegion.unite( oldRect );
+ }
+ if ( arrangement == QIconView::LeftToRight ) {
+ nx++;
+ if ( nx >= nxmax ) {
+ ny++;
+ nx = 0;
+ }
+ }
+ else {
+ ny++;
+ if ( ny >= nymax ) {
+ nx++;
+ ny = 0;
+ }
+ }
+ }
+
+ // Repaint only repaintRegion...
+ QMemArray<QRect> rects = repaintRegion.rects();
+ for ( uint l = 0; l < rects.count(); l++ ) {
+ kdDebug( 1203 ) << "Repainting (" << rects[l].x() << ","
+ << rects[l].y() << ")\n";
+ repaintContents( rects[l], false );
+ }
+ // Repaint icons that were moved
+ while ( !movedItems.isEmpty() ) {
+ repaintItem( movedItems.first() );
+ movedItems.remove( movedItems.first() );
+ }
+}
+
+int KonqIconViewWidget::largestPreviewIconSize( int size ) const
+{
+ int iconSize = size ? size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+
+ if (iconSize < 28)
+ return 48;
+ if (iconSize < 40)
+ return 64;
+ if (iconSize < 60)
+ return 96;
+ if (iconSize < 120)
+ return 128;
+
+ return 192;
+}
+
+int KonqIconViewWidget::previewIconSize( int size ) const
+{
+ int iconSize = size ? size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
+
+ if (!d->bBoostPreview)
+ return iconSize;
+
+ return largestPreviewIconSize( iconSize );
+}
+
+void KonqIconViewWidget::visualActivate(QIconViewItem * item)
+{
+ // Rect of the QIconViewItem.
+ QRect irect = item->rect();
+
+ // Rect of the QIconViewItem's pixmap area.
+ QRect rect = item->pixmapRect();
+
+ // Adjust to correct position. If this isn't done, the fact that the
+ // text may be wider than the pixmap puts us off-centre.
+ rect.moveBy(irect.x(), irect.y());
+
+ // Adjust for scrolling (David)
+ rect.moveBy( -contentsX(), -contentsY() );
+
+ KIconEffect::visualActivate(viewport(), rect);
+}
+
+void KonqIconViewWidget::backgroundPixmapChange( const QPixmap & )
+{
+ viewport()->update();
+}
+
+void KonqIconViewWidget::setPreviewSettings( const QStringList& settings )
+{
+ d->previewSettings = settings;
+ updatePreviewMimeTypes();
+
+ int size = m_size;
+ m_size = -1; // little trick to force grid change in setIcons
+ setIcons( size ); // force re-determining all icons
+}
+
+const QStringList& KonqIconViewWidget::previewSettings()
+{
+ return d->previewSettings;
+}
+
+void KonqIconViewWidget::setNewURL( const QString& url )
+{
+ KURL u;
+ if ( url.startsWith( "/" ) )
+ u.setPath( url );
+ else
+ u = url;
+ setURL( u );
+}
+
+void KonqIconViewWidget::setCaseInsensitiveSort( bool b )
+{
+ d->bCaseInsensitive = b;
+}
+
+bool KonqIconViewWidget::caseInsensitiveSort() const
+{
+ return d->bCaseInsensitive;
+}
+
+bool KonqIconViewWidget::canPreview( KFileItem* item )
+{
+ if ( !KGlobalSettings::showFilePreview( url() ) )
+ return false;
+
+ if ( d->pPreviewMimeTypes == 0L )
+ updatePreviewMimeTypes();
+
+ return mimeTypeMatch( item->mimetype(), *( d->pPreviewMimeTypes ) );
+}
+
+void KonqIconViewWidget::updatePreviewMimeTypes()
+{
+ if ( d->pPreviewMimeTypes == 0L )
+ d->pPreviewMimeTypes = new QStringList;
+ else
+ d->pPreviewMimeTypes->clear();
+
+ // Load the list of plugins to determine which mimetypes are supported
+ KTrader::OfferList plugins = KTrader::self()->query("ThumbCreator");
+ KTrader::OfferList::ConstIterator it;
+
+ for ( it = plugins.begin(); it != plugins.end(); ++it ) {
+ if ( d->previewSettings.contains((*it)->desktopEntryName()) ) {
+ QStringList mimeTypes = (*it)->property("MimeTypes").toStringList();
+ for (QStringList::ConstIterator mt = mimeTypes.begin(); mt != mimeTypes.end(); ++mt)
+ d->pPreviewMimeTypes->append(*mt);
+ }
+ }
+}
+
+#include "konq_iconviewwidget.moc"
+
+/* vim: set et sw=4 ts=8 softtabstop=4: */