libkonq Library API Documentation

konq_iconviewwidget.cc

00001 /* This file is part of the KDE projects
00002    Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
00003    Copyright (C) 2000, 2001, 2002 David Faure <david@mandrakesoft.com>
00004 
00005    This program is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     General Public License for more details.
00014 
00015    You should have received a copy of the GNU General Public License
00016    along with this program; see the file COPYING.  If not, write to
00017    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018    Boston, MA 02111-1307, USA.
00019 */
00020 #include "konq_iconviewwidget.h"
00021 #include "konq_undo.h"
00022 #include "konq_sound.h"
00023 
00024 #include <qclipboard.h>
00025 #include <qlayout.h>
00026 #include <qtimer.h>
00027 #include <qpainter.h>
00028 #include <qtooltip.h>
00029 #include <qlabel.h>
00030 #include <qmovie.h>
00031 #include <qregexp.h>
00032 #include <qcursor.h>
00033 
00034 #include <kapplication.h>
00035 #include <kdebug.h>
00036 #include <kio/previewjob.h>
00037 #include <kfileivi.h>
00038 #include <konq_settings.h>
00039 #include <konq_drag.h>
00040 #include <konq_operations.h>
00041 #include <kglobalsettings.h>
00042 #include <kpropertiesdialog.h>
00043 #include <kipc.h>
00044 #include <kicontheme.h>
00045 #include <kiconeffect.h>
00046 #include <kurldrag.h>
00047 #include <kstandarddirs.h>
00048 #include <kprotocolinfo.h>
00049 #include <ktrader.h>
00050 
00051 #include <assert.h>
00052 #include <unistd.h>
00053 
00054 class KFileTip: public QFrame
00055 {
00056 public:
00057     KFileTip( KonqIconViewWidget* parent ) : QFrame( 0, 0, WStyle_Customize | WStyle_NoBorder | WStyle_Tool | WStyle_StaysOnTop | WX11BypassWM ),
00058 
00059           m_corner( 0 ),
00060           m_filter( false ),
00061           m_view( parent ),
00062           m_item( 0 ),
00063           m_previewJob( 0 ),
00064           m_ivi( 0 )
00065     {
00066         m_iconLabel = new QLabel(this);
00067         m_textLabel = new QLabel(this);
00068         m_textLabel->setAlignment(Qt::AlignAuto | Qt::AlignTop);
00069 
00070         QGridLayout* layout = new QGridLayout(this, 1, 2, 8, 0);
00071         layout->addWidget(m_iconLabel, 0, 0);
00072         layout->addWidget(m_textLabel, 0, 1);
00073         layout->setResizeMode(QLayout::Fixed);
00074 
00075         setPalette( QToolTip::palette() );
00076         setMargin( 1 );
00077         setFrameStyle( QFrame::Plain | QFrame::Box );
00078 
00079         hide();
00080     }
00081     ~KFileTip();
00082 
00083     void setPreview(bool on)
00084     {
00085         m_preview = on;
00086         if(on)
00087             m_iconLabel->show();
00088         else
00089             m_iconLabel->hide();
00090     }
00091 
00092     void setOptions( bool on, bool preview, int num)
00093     {
00094         m_num = num;
00095         setPreview(preview);
00096         m_on = on;
00097     }
00098 
00099     void setItem( KFileIVI *ivi );
00100 
00101     virtual bool eventFilter( QObject *, QEvent *e );
00102 
00103     void gotPreview( const KFileItem*, const QPixmap& );
00104     void gotPreviewResult();
00105 
00106 protected:
00107     virtual void drawContents( QPainter *p );
00108     virtual void timerEvent( QTimerEvent * );
00109     virtual void resizeEvent( QResizeEvent * );
00110 
00111 private:
00112     void setFilter( bool enable );
00113 
00114     void reposition();
00115 
00116     QLabel*    m_iconLabel;
00117     QLabel*    m_textLabel;
00118     int        m_num;
00119     bool       m_on;
00120     bool       m_preview;
00121     QPixmap    m_corners[4];
00122     int        m_corner;
00123     bool       m_filter;
00124     KonqIconViewWidget*       m_view;
00125     KFileItem* m_item;
00126     KIO::PreviewJob* m_previewJob;
00127     KFileIVI*  m_ivi;
00128 };
00129 
00130 KFileTip::~KFileTip()
00131 {
00132    if ( m_previewJob ) {
00133         m_previewJob->kill();
00134         m_previewJob = 0;
00135     }
00136 }
00137 
00138 void KFileTip::setItem( KFileIVI *ivi )
00139 {
00140     if (!m_on) return;
00141     if (m_ivi == ivi) return;
00142 
00143     if ( m_previewJob ) {
00144         m_previewJob->kill();
00145         m_previewJob = 0;
00146     }
00147 
00148     m_ivi = ivi;
00149     m_item = ivi ? ivi->item() : 0;
00150 
00151     QString text = ivi ? ivi->item()->getToolTipText( m_num ) : QString::null;
00152     if ( !text.isEmpty() ) {
00153         hide();
00154         m_textLabel -> setText( text );
00155 
00156         killTimers();
00157         setFilter( true );
00158 
00159         if (m_preview) {
00160             m_iconLabel -> setPixmap(*(ivi->pixmap()));
00161             KFileItemList oneItem;
00162             oneItem.append( ivi->item() );
00163 
00164             m_previewJob = KIO::filePreview( oneItem, 256, 256, 64, 70, true, true, 0);
00165             connect( m_previewJob, SIGNAL( gotPreview( const KFileItem *, const QPixmap & ) ),
00166                     m_view, SLOT( slotToolTipPreview( const KFileItem *, const QPixmap & ) ) );
00167             connect( m_previewJob, SIGNAL( result( KIO::Job * ) ),
00168                     m_view, SLOT( slotToolTipPreviewResult() ) );
00169         }
00170 
00171         startTimer( 300 );
00172     }
00173     else {
00174         killTimers();
00175         if ( isVisible() ) {
00176             setFilter( false );
00177             hide();
00178         }
00179     }
00180 }
00181 
00182 void KFileTip::reposition()
00183 {
00184     if (!m_ivi) return;
00185 
00186     QRect rect = m_ivi->rect();
00187     QPoint off = m_view->viewport()->mapToGlobal( m_view->contentsToViewport( rect.topRight() ) );
00188     rect.moveTopRight( off );
00189 
00190     QPoint pos = rect.center();
00191     // m_corner:
00192     // 0: upperleft
00193     // 1: upperright
00194     // 2: lowerleft
00195     // 3: lowerright
00196     // 4+: none
00197     m_corner = 0;
00198     // should the tooltip be shown to the left or to the right of the ivi ?
00199     QRect desk = KGlobalSettings::desktopGeometry(rect.center());
00200     if (rect.center().x() + width() > desk.right())
00201     {
00202         // to the left
00203         if (pos.x() - width() < 0) {
00204             pos.setX(0);
00205             m_corner = 4;
00206         } else {
00207             pos.setX( pos.x() - width() );
00208             m_corner = 1;
00209         }
00210     }
00211     // should the tooltip be shown above or below the ivi ?
00212     if (rect.bottom() + height() > desk.bottom())
00213     {
00214         // above
00215         pos.setY( rect.top() - height() );
00216         m_corner += 2;
00217     }
00218     else pos.setY( rect.bottom() + 1 );
00219 
00220     move( pos );
00221     update();
00222 }
00223 
00224 void KFileTip::gotPreview( const KFileItem* item, const QPixmap& pixmap )
00225 {
00226     m_previewJob = 0;
00227     if (item != m_item) return;
00228 
00229     m_iconLabel -> setPixmap(pixmap);
00230 }
00231 
00232 void KFileTip::gotPreviewResult()
00233 {
00234     m_previewJob = 0;
00235 }
00236 
00237 void KFileTip::drawContents( QPainter *p )
00238 {
00239     static const char * const names[] = {
00240         "arrow_topleft",
00241         "arrow_topright",
00242         "arrow_bottomleft",
00243         "arrow_bottomright"
00244     };
00245 
00246     if (m_corner >= 4) {  // 4 is empty, so don't draw anything
00247         QFrame::drawContents( p );
00248         return;
00249     }
00250 
00251     if ( m_corners[m_corner].isNull())
00252         m_corners[m_corner].load( locate( "data", QString::fromLatin1( "konqueror/pics/%1.png" ).arg( names[m_corner] ) ) );
00253 
00254     QPixmap &pix = m_corners[m_corner];
00255 
00256     switch ( m_corner )
00257     {
00258         case 0:
00259             p->drawPixmap( 3, 3, pix );
00260             break;
00261         case 1:
00262             p->drawPixmap( width() - pix.width() - 3, 3, pix );
00263             break;
00264         case 2:
00265             p->drawPixmap( 3, height() - pix.height() - 3, pix );
00266             break;
00267         case 3:
00268             p->drawPixmap( width() - pix.width() - 3, height() - pix.height() - 3, pix );
00269             break;
00270     }
00271 
00272     QFrame::drawContents( p );
00273 }
00274 
00275 void KFileTip::setFilter( bool enable )
00276 {
00277     if ( enable == m_filter ) return;
00278 
00279     if ( enable ) {
00280         kapp->installEventFilter( this );
00281         QApplication::setGlobalMouseTracking( true );
00282     }
00283     else {
00284         QApplication::setGlobalMouseTracking( false );
00285         kapp->removeEventFilter( this );
00286     }
00287     m_filter = enable;
00288 }
00289 
00290 void KFileTip::timerEvent( QTimerEvent * )
00291 {
00292     killTimers();
00293     if ( !isVisible() ) {
00294         startTimer( 15000 );
00295         reposition();
00296         show();
00297     }
00298     else {
00299         setFilter( false );
00300         hide();
00301     }
00302 }
00303 
00304 void KFileTip::resizeEvent( QResizeEvent* event )
00305 {
00306     QFrame::resizeEvent(event);
00307     reposition();
00308 }
00309 
00310 bool KFileTip::eventFilter( QObject *, QEvent *e )
00311 {
00312     switch ( e->type() )
00313     {
00314         case QEvent::Leave:
00315         case QEvent::MouseButtonPress:
00316         case QEvent::MouseButtonRelease:
00317         case QEvent::KeyPress:
00318         case QEvent::KeyRelease:
00319         case QEvent::FocusIn:
00320         case QEvent::FocusOut:
00321         case QEvent::Wheel:
00322             killTimers();
00323             setFilter( false );
00324             hide();
00325         default: break;
00326     }
00327 
00328     return false;
00329 }
00330 
00331 struct KonqIconViewWidgetPrivate
00332 {
00333     KonqIconViewWidgetPrivate() {
00334         pActiveItem = 0;
00335         bSoundPreviews = false;
00336         pSoundItem = 0;
00337         bSoundItemClicked = false;
00338         pSoundPlayer = 0;
00339         pSoundTimer = 0;
00340         pPreviewJob = 0;
00341         bAllowSetWallpaper = false;
00342     gridXspacing = 50;
00343 
00344         doAnimations = true;
00345         m_movie = 0L;
00346         m_movieBlocked = 0;
00347         pFileTip = 0;
00348         pFileTipTimer = 0;
00349         pActivateDoubleClick = 0L;
00350         bCaseInsensitive = true;
00351         pPreviewMimeTypes = 0L;
00352     }
00353     ~KonqIconViewWidgetPrivate() {
00354         delete pSoundPlayer;
00355         delete pSoundTimer;
00356         delete m_movie;
00357         delete pFileTip;
00358         delete pFileTipTimer;
00359         delete pActivateDoubleClick;
00360         delete pPreviewMimeTypes;
00361         //delete pPreviewJob; done by stopImagePreview
00362     }
00363     KFileIVI *pActiveItem;
00364     // Sound preview
00365     KFileIVI *pSoundItem;
00366     KonqSoundPlayer *pSoundPlayer;
00367     QTimer *pSoundTimer;
00368     bool bSoundPreviews;
00369     bool bSoundItemClicked;
00370     bool bAllowSetWallpaper;
00371     bool bCaseInsensitive;
00372     bool bBoostPreview;
00373     QPoint desktopGridSpacing;
00374     int gridXspacing;
00375 
00376     // Animated icons support
00377     bool doAnimations;
00378     QMovie* m_movie;
00379     int m_movieBlocked;
00380     QString movieFileName;
00381 
00382     KIO::PreviewJob *pPreviewJob;
00383     KFileTip* pFileTip;
00384     QTimer *pFileTipTimer;
00385     QStringList previewSettings;
00386     bool renameItem;
00387     bool firstClick;
00388     bool releaseMouseEvent;
00389     QPoint mousePos;
00390     int mouseState;
00391     QTimer *pActivateDoubleClick;
00392     QStringList* pPreviewMimeTypes;
00393 };
00394 
00395 KonqIconViewWidget::KonqIconViewWidget( QWidget * parent, const char * name, WFlags f, bool kdesktop )
00396     : KIconView( parent, name, f ),
00397       m_rootItem( 0L ), m_size( 0 ) /* default is DesktopIcon size */,
00398       m_bDesktop( kdesktop ),
00399       m_bSetGridX( !kdesktop ) /* No line breaking on the desktop */
00400 {
00401     d = new KonqIconViewWidgetPrivate;
00402     connect( this, SIGNAL( dropped( QDropEvent *, const QValueList<QIconDragItem> & ) ),
00403              this, SLOT( slotDropped( QDropEvent*, const QValueList<QIconDragItem> & ) ) );
00404 
00405     connect( this, SIGNAL( selectionChanged() ),
00406              this, SLOT( slotSelectionChanged() ) );
00407 
00408     kapp->addKipcEventMask( KIPC::IconChanged );
00409     connect( kapp, SIGNAL(iconChanged(int)), SLOT(slotIconChanged(int)) );
00410     connect( this, SIGNAL(onItem(QIconViewItem *)), SLOT(slotOnItem(QIconViewItem *)) );
00411     connect( this, SIGNAL(onViewport()), SLOT(slotOnViewport()) );
00412     connect( this, SIGNAL(itemRenamed(QIconViewItem *, const QString &)), SLOT(slotItemRenamed(QIconViewItem *, const QString &)) );
00413 
00414     if ( m_bDesktop ) {
00415         KConfigGroup group( KGlobal::config(), "DesktopIcons" );
00416         QPoint defaultSize;
00417         d->desktopGridSpacing = group.readPointEntry( "DesktopGridSpacing", &defaultSize );
00418         if ( d->desktopGridSpacing.isNull() ) {
00419             d->desktopGridSpacing = QPoint( 55, 15 );
00420             // read GridXSpacing (for compatibility with old settings)
00421             int compat = group.readNumEntry( "GridXSpacing", 0 );
00422             if ( compat > 0 )
00423                 d->desktopGridSpacing.setX( compat );
00424         }
00425     }
00426     d->bBoostPreview = boostPreview();
00427 
00428     // hardcoded settings
00429     setSelectionMode( QIconView::Extended );
00430     setItemTextPos( QIconView::Bottom );
00431     d->releaseMouseEvent = false;
00432     d->pFileTip = new KFileTip(this);
00433     d->pFileTipTimer = new QTimer( this );
00434     connect( d->pFileTipTimer, SIGNAL(timeout()), SLOT(slotStartTooltip()) );
00435     d->firstClick = false;
00436     calculateGridX();
00437     setAutoArrange( true );
00438     setSorting( true, sortDirection() );
00439     readAnimatedIconsConfig();
00440     m_bSortDirsFirst = true;
00441     m_bMousePressed = false;
00442     m_LineupMode = LineupBoth;
00443     // emit our signals
00444     slotSelectionChanged();
00445     m_iconPositionGroupPrefix = QString::fromLatin1( "IconPosition::" );
00446     KonqUndoManager::incRef();
00447 }
00448 
00449 KonqIconViewWidget::~KonqIconViewWidget()
00450 {
00451     stopImagePreview();
00452     KonqUndoManager::decRef();
00453     delete d;
00454 }
00455 
00456 bool KonqIconViewWidget::maySetWallpaper()
00457 {
00458     return d->bAllowSetWallpaper;
00459 }
00460 
00461 void KonqIconViewWidget::setMaySetWallpaper(bool b)
00462 {
00463     d->bAllowSetWallpaper = b;
00464 }
00465 
00466 void KonqIconViewWidget::focusOutEvent( QFocusEvent * ev )
00467 {
00468     // We can't possibly have the mouse pressed and still lose focus.
00469     // Well, we can, but when we regain focus we should assume the mouse is
00470     // not down anymore or the slotOnItem code will break with highlighting!
00471     m_bMousePressed = false;
00472     
00473     // This will ensure that tooltips don't pop up and the mouseover icon
00474     // effect will go away if the mouse goes out of the view without
00475     // first moving into an empty portion of the view
00476     // Fixes part of #86968, and #85204
00477     // Matt Newell 2004-09-24
00478     slotOnViewport();
00479     
00480     KIconView::focusOutEvent( ev );
00481 }
00482 
00483 void KonqIconViewWidget::slotItemRenamed(QIconViewItem *item, const QString &name)
00484 {
00485     kdDebug(1203) << "KonqIconViewWidget::slotItemRenamed" << endl;
00486     KFileIVI *viewItem = static_cast<KFileIVI *>(item);
00487     KFileItem *fileItem = viewItem->item();
00488 
00489     // The correct behavior is to show the old name until the rename has successfully
00490     // completed. Unfortunately, KIconView forces us to allow the text to be changed
00491     // before we try the rename, so set it back to the pre-rename state.
00492     viewItem->setText( fileItem->text() );
00493     kdDebug(1203)<<" fileItem->text() ;"<<fileItem->text()<<endl;
00494     // Don't do anything if the user renamed to a blank name.
00495     if( !name.isEmpty() )
00496     {
00497         // Actually attempt the rename. If it succeeds, KDirLister will update the name.
00498         KURL oldurl( fileItem->url() );
00499         KURL newurl( url() );
00500         newurl.setPath( url().path(1) + KIO::encodeFileName( name ) );
00501         kdDebug(1203)<<" newurl :"<<newurl.url()<<endl;
00502         // We use url()+name so that it also works if the name is a relative path (#51176)
00503         KonqOperations::rename( this, oldurl, newurl );
00504     }
00505 }
00506 
00507 void KonqIconViewWidget::slotIconChanged( int group )
00508 {
00509     if (group != KIcon::Desktop)
00510         return;
00511 
00512     int size = m_size;
00513     if ( m_size == 0 )
00514       m_size = -1; // little trick to force grid change in setIcons
00515     setIcons( size ); // force re-determining all icons
00516     readAnimatedIconsConfig();
00517 }
00518 
00519 void KonqIconViewWidget::readAnimatedIconsConfig()
00520 {
00521     KConfigGroup cfgGroup( KGlobal::config(), "DesktopIcons" );
00522     d->doAnimations = cfgGroup.readBoolEntry( "Animated", true /*default*/ );
00523     d->gridXspacing = cfgGroup.readNumEntry( "GridXSpacing", 50);
00524 }
00525 
00526 void KonqIconViewWidget::slotOnItem( QIconViewItem *_item )
00527 {
00528     KFileIVI* item = static_cast<KFileIVI *>( _item );
00529     // Reset icon of previous item
00530     if( d->pActiveItem != 0L && d->pActiveItem != item )
00531     {
00532         if ( d->m_movie && d->pActiveItem->isAnimated() )
00533         {
00534             d->m_movie->pause(); // we'll see below what we do with it
00535             d->pActiveItem->setAnimated( false );
00536             d->pActiveItem->refreshIcon( true );
00537         }
00538         else {
00539             d->pActiveItem->setActive( false );
00540         }
00541         d->pActiveItem = 0L;
00542         d->pFileTipTimer->stop();
00543         d->pFileTip->setItem( 0L );
00544     }
00545 
00546     // Stop sound
00547     if (d->pSoundPlayer != 0 && item != d->pSoundItem)
00548     {
00549         d->pSoundPlayer->stop();
00550 
00551         d->pSoundItem = 0;
00552         if (d->pSoundTimer && d->pSoundTimer->isActive())
00553             d->pSoundTimer->stop();
00554     }
00555 
00556     if ( !m_bMousePressed )
00557     {
00558         if( item != d->pActiveItem )
00559         {
00560             d->pActiveItem = item;
00561             if ( topLevelWidget() == kapp->activeWindow() )
00562                 d->pFileTipTimer->start( 400, true );
00563 
00564             if ( d->doAnimations && d->pActiveItem && d->pActiveItem->hasAnimation() )
00565             {
00566                 //kdDebug(1203) << "Playing animation for: " << d->pActiveItem->mouseOverAnimation() << endl;
00567                 // Check if cached movie can be used
00568 #if 0 // Qt-mng bug, reusing the movie doesn't work currently.
00569                 if ( d->m_movie && d->movieFileName == d->pActiveItem->mouseOverAnimation() )
00570                 {
00571                     d->pActiveItem->setAnimated( true );
00572                     if (d->m_movieBlocked) {
00573                         kdDebug(1203) << "onitem, but blocked" << endl;
00574                         d->m_movie->pause();
00575                     }
00576                     else {
00577                         kdDebug(1203) << "we go ahead.." << endl;
00578                         d->m_movieBlocked++;
00579                         QTimer::singleShot(300, this, SLOT(slotReenableAnimation()));
00580                         d->m_movie->restart();
00581                         d->m_movie->unpause();
00582                     }
00583                 }
00584                 else
00585 #endif
00586                 {
00587                     QMovie movie = KGlobal::iconLoader()->loadMovie( d->pActiveItem->mouseOverAnimation(), KIcon::Desktop, d->pActiveItem->iconSize() );
00588                     if ( !movie.isNull() )
00589                     {
00590                         delete d->m_movie;
00591                         d->m_movie = new QMovie( movie ); // shallow copy, don't worry
00592                         // Fix alpha-channel - currently only if no background pixmap,
00593                         // the bg pixmap case requires to uncomment the code at qmovie.cpp:404
00594                         const QPixmap* pm = backgroundPixmap();
00595                         bool hasPixmap = pm && !pm->isNull();
00596                         if ( !hasPixmap ) {
00597                             pm = viewport()->backgroundPixmap();
00598                             hasPixmap = pm && !pm->isNull();
00599                         }
00600                         if (!hasPixmap && backgroundMode() != NoBackground)
00601                            d->m_movie->setBackgroundColor( viewport()->backgroundColor() );
00602                         d->m_movie->connectUpdate( this, SLOT( slotMovieUpdate(const QRect &) ) );
00603                         d->m_movie->connectStatus( this, SLOT( slotMovieStatus(int) ) );
00604                         d->movieFileName = d->pActiveItem->mouseOverAnimation();
00605                         d->pActiveItem->setAnimated( true );
00606                     }
00607                     else
00608                     {
00609                         d->pActiveItem->setAnimated( false );
00610                         if (d->m_movie)
00611                             d->m_movie->pause();
00612                         // No movie available, remember it
00613                         d->pActiveItem->setMouseOverAnimation( QString::null );
00614                     }
00615                 }
00616             } // animations
00617             // Only do the normal "mouseover" effect if no animation is in use
00618             if (d->pActiveItem && !d->pActiveItem->isAnimated())
00619             {
00620                 d->pActiveItem->setActive( true );
00621             }
00622         }
00623         else // No change in current item
00624         {
00625             // No effect. If we want to underline on hover, we should
00626             // force the IVI to repaint here, though!
00627             d->pActiveItem = 0L;
00628             d->pFileTipTimer->stop();
00629             d->pFileTip->setItem( 0L );
00630         }
00631     } // bMousePressed
00632     else
00633     {
00634         // All features disabled during mouse clicking, e.g. rectangular
00635         // selection
00636         d->pActiveItem = 0L;
00637         d->pFileTipTimer->stop();
00638         d->pFileTip->setItem( 0L );
00639     }
00640 
00641     // ## shouldn't this be disabled during rectangular selection too ?
00642     if (d->bSoundPreviews && d->pSoundPlayer &&
00643         d->pSoundPlayer->mimeTypes().contains(
00644             item->item()->mimetype())
00645         && KGlobalSettings::showFilePreview(item->item()->url())
00646         && topLevelWidget() == kapp->activeWindow())
00647     {
00648         d->pSoundItem = item;
00649         d->bSoundItemClicked = false;
00650         if (!d->pSoundTimer)
00651         {
00652             d->pSoundTimer = new QTimer(this);
00653             connect(d->pSoundTimer, SIGNAL(timeout()), SLOT(slotStartSoundPreview()));
00654         }
00655         if (d->pSoundTimer->isActive())
00656             d->pSoundTimer->stop();
00657         d->pSoundTimer->start(500, true);
00658     }
00659     else
00660     {
00661         if (d->pSoundPlayer)
00662             d->pSoundPlayer->stop();
00663         d->pSoundItem = 0;
00664         if (d->pSoundTimer && d->pSoundTimer->isActive())
00665             d->pSoundTimer->stop();
00666     }
00667 }
00668 
00669 void KonqIconViewWidget::slotOnViewport()
00670 {
00671     d->pFileTipTimer->stop();
00672     d->pFileTip->setItem( 0L );
00673 
00674     if (d->pSoundPlayer)
00675       d->pSoundPlayer->stop();
00676     d->pSoundItem = 0;
00677     if (d->pSoundTimer && d->pSoundTimer->isActive())
00678       d->pSoundTimer->stop();
00679 
00680     if (d->pActiveItem == 0L)
00681         return;
00682 
00683     if ( d->doAnimations && d->m_movie && d->pActiveItem->isAnimated() )
00684     {
00685         d->pActiveItem->setAnimated( false );
00686 #if 0
00687         // Aborting before the end of the animation ?
00688         if (d->m_movie->running()) {
00689             d->m_movie->pause();
00690             d->m_movieBlocked++;
00691             kdDebug(1203) << "on viewport, blocking" << endl;
00692             QTimer::singleShot(300, this, SLOT(slotReenableAnimation()));
00693         }
00694 #endif
00695         d->pActiveItem->refreshIcon( true );
00696         Q_ASSERT( d->pActiveItem->state() == KIcon::DefaultState );
00697         //delete d->m_movie;
00698         //d->m_movie = 0L;
00699         // TODO a timer to delete the movie after some time if unused?
00700     }
00701     else
00702     {
00703         d->pActiveItem->setActive( false );
00704     }
00705     d->pActiveItem = 0L;
00706 }
00707 
00708 void KonqIconViewWidget::slotStartSoundPreview()
00709 {
00710   if (!d->pSoundItem || d->bSoundItemClicked)
00711     return;
00712 
00713   d->pSoundPlayer->play(d->pSoundItem->item()->url().url());
00714 }
00715 
00716 
00717 void KonqIconViewWidget::slotPreview(const KFileItem *item, const QPixmap &pix)
00718 {
00719     // ### slow. Idea: move KonqKfmIconView's m_itemDict into this class
00720     for (QIconViewItem *it = firstItem(); it; it = it->nextItem())
00721     {
00722         KFileIVI* current = static_cast<KFileIVI *>(it);
00723         if (current->item() == item)
00724         {
00725             if (item->overlays() & KIcon::HiddenOverlay) {
00726                 QPixmap p(pix);
00727 
00728                 KIconEffect::semiTransparent(p);
00729                 current->setThumbnailPixmap(p);
00730             } else {
00731                 current->setThumbnailPixmap(pix);
00732             }
00733             break;
00734         }
00735     }
00736 }
00737 
00738 void KonqIconViewWidget::slotPreviewResult()
00739 {
00740     d->pPreviewJob = 0;
00741     emit imagePreviewFinished();
00742 }
00743 
00744 void KonqIconViewWidget::slotStartTooltip()
00745 {
00746     if ( d->pActiveItem )
00747         d->pFileTip->setItem( d->pActiveItem );
00748 }
00749 
00750 void KonqIconViewWidget::slotToolTipPreview(const KFileItem* item, const QPixmap &pix)
00751 {
00752     d->pFileTip->gotPreview( item, pix );
00753 }
00754 
00755 void KonqIconViewWidget::slotToolTipPreviewResult()
00756 {
00757     d->pFileTip->gotPreviewResult();
00758 }
00759 
00760 void KonqIconViewWidget::slotMovieUpdate( const QRect& rect )
00761 {
00762     //kdDebug(1203) << "KonqIconViewWidget::slotMovieUpdate " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << endl;
00763     Q_ASSERT( d );
00764     Q_ASSERT( d->m_movie );
00765     // seems stopAnimation triggers one last update
00766     if ( d->pActiveItem && d->m_movie && d->pActiveItem->isAnimated() ) {
00767         const QPixmap &frame = d->m_movie->framePixmap();
00768         // This can happen if the icon was scaled to the desired size, so KIconLoader
00769         // will happily return a movie with different dimensions than the icon
00770         int iconSize=d->pActiveItem->iconSize();
00771         if (iconSize==0) iconSize = KGlobal::iconLoader()->currentSize( KIcon::Desktop );
00772         if ( frame.width() != iconSize || frame.height() != iconSize ) {
00773             d->pActiveItem->setAnimated( false );
00774             d->m_movie->pause();
00775             // No movie available, remember it
00776             d->pActiveItem->setMouseOverAnimation( QString::null );
00777             d->pActiveItem->setActive( true );
00778             return;
00779         }
00780         d->pActiveItem->setPixmapDirect( frame, false, false /*no redraw*/ );
00781         QRect pixRect = d->pActiveItem->pixmapRect(false);
00782         repaintContents( pixRect.x() + rect.x(), pixRect.y() + rect.y(), rect.width(), rect.height(), false );
00783     }
00784 }
00785 
00786 void KonqIconViewWidget::slotMovieStatus( int status )
00787 {
00788     if ( status < 0 ) {
00789         // Error playing the MNG -> forget about it and do normal iconeffect
00790         if ( d->pActiveItem && d->pActiveItem->isAnimated() ) {
00791             d->pActiveItem->setAnimated( false );
00792             d->pActiveItem->setMouseOverAnimation( QString::null );
00793             d->pActiveItem->setActive( true );
00794         }
00795     }
00796 }
00797 
00798 void KonqIconViewWidget::slotReenableAnimation()
00799 {
00800     if (!--d->m_movieBlocked) {
00801         if ( d->pActiveItem && d->m_movie && d->m_movie->paused()) {
00802             kdDebug(1203) << "reenabled animation" << endl;
00803             d->m_movie->restart();
00804             d->m_movie->unpause();
00805         }
00806     }
00807 }
00808 
00809 void KonqIconViewWidget::clear()
00810 {
00811     d->pFileTipTimer->stop();
00812     d->pFileTip->setItem( 0L );
00813     stopImagePreview(); // Just in case
00814     KIconView::clear();
00815     d->pActiveItem = 0L;
00816 }
00817 
00818 void KonqIconViewWidget::takeItem( QIconViewItem *item )
00819 {
00820     if ( d->pActiveItem == static_cast<KFileIVI *>(item) )
00821     {
00822         d->pFileTipTimer->stop();
00823         d->pFileTip->setItem( 0L );
00824         d->pActiveItem = 0L;
00825     }
00826 
00827     if ( d->pPreviewJob )
00828       d->pPreviewJob->removeItem( static_cast<KFileIVI *>(item)->item() );
00829 
00830     KIconView::takeItem( item );
00831 }
00832 
00833 // Currently unused - remove in KDE 4.0
00834 void KonqIconViewWidget::setThumbnailPixmap( KFileIVI * item, const QPixmap & pixmap )
00835 {
00836     if ( item )
00837     {
00838         if ( d->pActiveItem == item )
00839         {
00840             d->pFileTipTimer->stop();
00841             d->pFileTip->setItem( 0L );
00842             d->pActiveItem = 0L;
00843         }
00844         item->setThumbnailPixmap( pixmap );
00845         if ( m_bSetGridX &&  item->width() > gridX() )
00846         {
00847           setGridX( item->width() );
00848           if (autoArrange())
00849             arrangeItemsInGrid();
00850         }
00851     }
00852 }
00853 
00854 bool KonqIconViewWidget::initConfig( bool bInit )
00855 {
00856     bool fontChanged = false;
00857     m_pSettings = KonqFMSettings::settings();
00858 
00859     // Color settings
00860     QColor normalTextColor       = m_pSettings->normalTextColor();
00861     setItemColor( normalTextColor );
00862 
00863     if (m_bDesktop)
00864     {
00865       QColor itemTextBg = m_pSettings->itemTextBackground();
00866       if ( itemTextBg.isValid() )
00867           setItemTextBackground( itemTextBg );
00868       else
00869           setItemTextBackground( NoBrush );
00870     }
00871 
00872 
00873     d->pFileTip->setOptions(m_pSettings->showFileTips() && QToolTip::isGloballyEnabled(),
00874                             m_pSettings->showPreviewsInFileTips(),
00875                             m_pSettings->numFileTips());
00876 
00877     // Font settings
00878     QFont font( m_pSettings->standardFont() );
00879     if (!m_bDesktop)
00880         font.setUnderline( m_pSettings->underlineLink() );
00881 
00882     if ( font != KonqIconViewWidget::font() )
00883     {
00884         setFont( font );
00885         if (!bInit)
00886         {
00887             // QIconView doesn't do it by default... but if the font is made much
00888             // bigger, we really need to give more space between the icons
00889             fontChanged = true;
00890         }
00891     }
00892 
00893     setIconTextHeight( m_bDesktop ? 2 : m_pSettings->iconTextHeight() );
00894 
00895     // Update icons if settings for preview icon size have changed
00896     if ( d->bBoostPreview != boostPreview() )
00897         setIcons(m_size);
00898     else if (!bInit)
00899         updateContents();
00900     return fontChanged;
00901 }
00902 
00903 bool KonqIconViewWidget::boostPreview() const
00904 {
00905     if ( m_bDesktop ) {
00906         int size = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
00907         int mini = spacing() + QMAX( 0, largestPreviewIconSize( size ) - size );
00908         if ( d->desktopGridSpacing.x() < mini ||
00909              d->desktopGridSpacing.y() < mini )
00910             return false;
00911     }
00912 
00913     KConfigGroup group( KGlobal::config(), "PreviewSettings" );
00914     return group.readBoolEntry( "BoostSize", false );
00915 }
00916 
00917 void KonqIconViewWidget::disableSoundPreviews()
00918 {
00919     d->bSoundPreviews = false;
00920 
00921     if (d->pSoundPlayer)
00922       d->pSoundPlayer->stop();
00923     d->pSoundItem = 0;
00924     if (d->pSoundTimer && d->pSoundTimer->isActive())
00925       d->pSoundTimer->stop();
00926 }
00927 
00928 void KonqIconViewWidget::setIcons( int size, const QStringList& stopImagePreviewFor )
00929 {
00930     // size has changed?
00931     bool sizeChanged = (m_size != size);
00932     int oldGridX = gridX();
00933     m_size = size;
00934     
00935     // boost preview option has changed?
00936     bool boost = boostPreview();
00937     bool previewSizeChanged = ( d->bBoostPreview != boost );
00938     d->bBoostPreview = boost;
00939     
00940     if ( sizeChanged || previewSizeChanged )
00941     {
00942         int realSize = size ? size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
00943         setSpacing( ( realSize > KIcon::SizeSmall ) ? 5 : 0 );
00944     }
00945 
00946     if ( sizeChanged || previewSizeChanged || !stopImagePreviewFor.isEmpty() )
00947     {
00948         calculateGridX();
00949     }
00950     bool stopAll = !stopImagePreviewFor.isEmpty() && stopImagePreviewFor.first() == "*";
00951 
00952     // Disable repaints that can be triggered by ivi->setIcon(). Since icons are
00953     // resized in-place, if the icon size is increasing it can happens that the right
00954     // or bottom icons exceed the size of the viewport.. here we prevent the repaint
00955     // event that will be triggered in that case.
00956     bool prevUpdatesState = viewport()->isUpdatesEnabled();
00957     viewport()->setUpdatesEnabled( false );
00958 
00959     // Do this even if size didn't change, since this is used by refreshMimeTypes...
00960     for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
00961         KFileIVI * ivi = static_cast<KFileIVI *>( it );
00962         // Set a normal icon for files that are not thumbnails, and for files
00963         // that are thumbnails but for which it should be stopped
00964         if ( !ivi->isThumbnail() ||
00965              sizeChanged ||
00966              previewSizeChanged ||
00967              stopAll ||
00968              mimeTypeMatch( ivi->item()->mimetype(), stopImagePreviewFor ) )
00969         {
00970             ivi->setIcon( size, ivi->state(), true, false );
00971         }
00972         else
00973             ivi->invalidateThumb( ivi->state(), true );
00974     }
00975 
00976     // Restore viewport update to previous state
00977     viewport()->setUpdatesEnabled( prevUpdatesState );
00978 
00979     if ( ( sizeChanged || previewSizeChanged || oldGridX != gridX() ||
00980          !stopImagePreviewFor.isEmpty() ) && autoArrange() )
00981         arrangeItemsInGrid( true ); // take new grid into account and repaint
00982     else
00983         viewport()->update(); //Repaint later..
00984 }
00985 
00986 bool KonqIconViewWidget::mimeTypeMatch( const QString& mimeType, const QStringList& mimeList ) const
00987 {
00988     for (QStringList::ConstIterator mt = mimeList.begin(); mt != mimeList.end(); ++mt)
00989     {
00990         if ( mimeType == *mt )
00991             return true;
00992         // Support for *mt == "image/*"
00993         QString tmp( mimeType );
00994         if ( (*mt).endsWith("*") && tmp.replace(QRegExp("/.*"), "/*") == (*mt) )
00995             return true;
00996     }
00997     return false;
00998 }
00999 
01000 void KonqIconViewWidget::setItemTextPos( ItemTextPos pos )
01001 {
01002     if ( m_bSetGridX )
01003     {
01004         calculateGridX();
01005         if ( itemTextPos() != pos )
01006         {
01007             if ( pos == QIconView::Right )
01008                 setGridX( gridX() + 100 );
01009             else
01010                 setGridX( gridX() - 100 );
01011         }
01012     }
01013 
01014     KIconView::setItemTextPos( pos );
01015 }
01016 
01017 void KonqIconViewWidget::gridValues( int* x, int* y, int* dx, int* dy,
01018                                      int* nx, int* ny )
01019 {
01020     int previewSize = previewIconSize( m_size );
01021     int iconSize = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
01022 
01023     // Grid size
01024     *dx = QMAX( iconSize + d->desktopGridSpacing.x(),
01025                    previewSize + spacing() );
01026     int textHeight = QMIN( iconTextHeight(), 2 ) * fontMetrics().height();
01027     *dy = textHeight + 2 +
01028         QMAX( iconSize + d->desktopGridSpacing.y(), previewSize );
01029 
01030     // Icon Area
01031     int x1, x2, y1, y2;
01032     int yOffset = QMAX( 0, *dy - ( previewSize + textHeight ) );
01033     if ( m_IconRect.isValid() ) {
01034         *x = x1 = m_IconRect.left(); x2 = m_IconRect.right();
01035         y1 = m_IconRect.top(); y2 = m_IconRect.bottom();
01036     }
01037     else {
01038         *x = x1 = 0; x2 = viewport()->width();
01039         y1 = 0; y2 = viewport()->height();
01040     }
01041     *y = y1 -= yOffset / 2;
01042     y2 -= yOffset / 2;
01043 
01044     *nx = (x2 - x1) / *dx;
01045     *ny = (y2 - y1) / *dy;
01046     // TODO: Check that items->count() <= nx * ny
01047 
01048     // Let have exactly nx columns and ny rows
01049     *dx = (x2 - x1) / *nx;
01050     *dy = (y2 - y1) / *ny;
01051     kdDebug(1203) << "dx = " << *dx << ", dy = " << *dy << "\n";
01052 }
01053 
01054 void KonqIconViewWidget::calculateGridX()
01055 {
01056     if ( m_bSetGridX )
01057         setGridX( gridXValue() );
01058 }
01059 
01060 int KonqIconViewWidget::gridXValue() const
01061 {
01062     int sz = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
01063     bool horizontal = (itemTextPos() == QIconView::Right);
01064     int newGridX = sz + (!m_bSetGridX ? d->gridXspacing : 50) + ( horizontal ? 100 : 0);
01065     newGridX = QMAX( newGridX, (horizontal ? 2 : 1) * previewIconSize( sz ) + 13 );
01066     //kdDebug(1203) << "gridXValue: " << newGridX << " sz=" << sz << endl;
01067     return newGridX;
01068 }
01069 
01070 void KonqIconViewWidget::refreshMimeTypes()
01071 {
01072     updatePreviewMimeTypes();
01073     for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
01074         (static_cast<KFileIVI *>( it ))->item()->refreshMimeType();
01075     setIcons( m_size );
01076 }
01077 
01078 void KonqIconViewWidget::setURL( const KURL &kurl )
01079 {
01080     stopImagePreview();
01081     m_url = kurl;
01082 
01083     d->pFileTip->setPreview( KGlobalSettings::showFilePreview(m_url) );
01084 
01085     if ( m_url.isLocalFile() )
01086         m_dotDirectoryPath = m_url.path(1).append( ".directory" );
01087     else
01088         m_dotDirectoryPath = QString::null;
01089 }
01090 
01091 void KonqIconViewWidget::startImagePreview( const QStringList &, bool force )
01092 {
01093     stopImagePreview(); // just in case
01094 
01095     // Check config
01096     if ( !KGlobalSettings::showFilePreview( url() ) ) {
01097         kdDebug(1203) << "Previews disabled for protocol " << url().protocol() << endl;
01098         emit imagePreviewFinished();
01099         return;
01100     }
01101 
01102     if ((d->bSoundPreviews = d->previewSettings.contains( "audio/" )) &&
01103         !d->pSoundPlayer)
01104     {
01105       KLibFactory *factory = KLibLoader::self()->factory("konq_sound");
01106       if (factory)
01107         d->pSoundPlayer = static_cast<KonqSoundPlayer *>(
01108           factory->create(this, 0, "KonqSoundPlayer"));
01109       d->bSoundPreviews = (d->pSoundPlayer != 0L);
01110     }
01111 
01112     KFileItemList items;
01113     for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
01114         if ( force || !static_cast<KFileIVI *>( it )->hasValidThumbnail() )
01115             items.append( static_cast<KFileIVI *>( it )->item() );
01116 
01117     bool onlyAudio = true;
01118     for ( QStringList::ConstIterator it = d->previewSettings.begin(); it != d->previewSettings.end(); ++it ) {
01119         if ( (*it).startsWith( "audio/" ) )
01120             d->bSoundPreviews = true;
01121         else
01122             onlyAudio = false;
01123     }
01124 
01125     if ( items.isEmpty() || onlyAudio ) {
01126         emit imagePreviewFinished();
01127         return; // don't start the preview job if not really necessary
01128     }
01129 
01130     int iconSize = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
01131     int size;
01132 
01133     d->bBoostPreview = boostPreview();
01134     size = previewIconSize( iconSize );
01135 
01136     if ( !d->bBoostPreview )
01137          iconSize /= 2;
01138 
01139     d->pPreviewJob = KIO::filePreview( items, size, size, iconSize,
01140         m_pSettings->textPreviewIconTransparency(), true /* scale */,
01141         true /* save */, &(d->previewSettings) );
01142     connect( d->pPreviewJob, SIGNAL( gotPreview( const KFileItem *, const QPixmap & ) ),
01143              this, SLOT( slotPreview( const KFileItem *, const QPixmap & ) ) );
01144     connect( d->pPreviewJob, SIGNAL( result( KIO::Job * ) ),
01145              this, SLOT( slotPreviewResult() ) );
01146 }
01147 
01148 void KonqIconViewWidget::stopImagePreview()
01149 {
01150     if (d->pPreviewJob)
01151     {
01152         d->pPreviewJob->kill();
01153         d->pPreviewJob = 0;
01154         // Now that previews are updated in-place, calling
01155         // arrangeItemsInGrid() here is not needed anymore
01156     }
01157 }
01158 
01159 bool KonqIconViewWidget::isPreviewRunning() const
01160 {
01161     return d->pPreviewJob;
01162 }
01163 
01164 KFileItemList KonqIconViewWidget::selectedFileItems()
01165 {
01166     KFileItemList lstItems;
01167 
01168     QIconViewItem *it = firstItem();
01169     for (; it; it = it->nextItem() )
01170         if ( it->isSelected() ) {
01171             KFileItem *fItem = (static_cast<KFileIVI *>(it))->item();
01172             lstItems.append( fItem );
01173         }
01174     return lstItems;
01175 }
01176 
01177 void KonqIconViewWidget::slotDropped( QDropEvent *ev, const QValueList<QIconDragItem> & )
01178 {
01179     // Drop on background
01180     KonqOperations::doDrop( m_rootItem /* may be 0L */, url(), ev, this );
01181 }
01182 
01183 void KonqIconViewWidget::slotAboutToCreate(const QPoint &, const QValueList<KIO::CopyInfo> &)
01184 {
01185    // Do nothing :-)
01186 }
01187 
01188 void KonqIconViewWidget::drawBackground( QPainter *p, const QRect &r )
01189 {
01190     drawBackground(p, r, r.topLeft());
01191 }
01192 
01193 void KonqIconViewWidget::drawBackground( QPainter *p, const QRect &r , const QPoint &pt)
01194 {
01195     const QPixmap *pm  = backgroundPixmap();
01196     bool hasPixmap = pm && !pm->isNull();
01197     if ( !hasPixmap ) {
01198         pm = viewport()->backgroundPixmap();
01199         hasPixmap = pm && !pm->isNull();
01200     }
01201 
01202     QRect rtgt(r);
01203     rtgt.moveTopLeft(pt);
01204     if (!hasPixmap && backgroundMode() != NoBackground) {
01205         p->fillRect(rtgt, viewport()->backgroundColor());
01206         return;
01207     }
01208 
01209     if (hasPixmap) {
01210         int ax = (r.x() + contentsX() + leftMargin()) % pm->width();
01211         int ay = (r.y() + contentsY() + topMargin()) % pm->height();
01212         p->drawTiledPixmap(rtgt, *pm, QPoint(ax, ay));
01213     }
01214 }
01215 
01216 QDragObject * KonqIconViewWidget::dragObject()
01217 {
01218     if ( !currentItem() )
01219         return 0;
01220 
01221     return konqDragObject( viewport() );
01222 }
01223 
01224 KonqIconDrag * KonqIconViewWidget::konqDragObject( QWidget * dragSource )
01225 {
01226     //kdDebug(1203) << "KonqIconViewWidget::konqDragObject" << endl;
01227 
01228     QPoint offset(-10,-10);
01229     KonqIconDrag * drag = new KonqIconDrag( dragSource );
01230     QIconViewItem *primaryItem = currentItem();
01231     // Append all items to the drag object
01232     for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
01233         if ( it->isSelected() ) {
01234           if (!primaryItem)
01235              primaryItem = it;
01236           KURL url = (static_cast<KFileIVI *>(it))->item()->url();
01237           QString itemURL = KURLDrag::urlToString(url);
01238           kdDebug(1203) << "itemURL=" << itemURL << endl;
01239           QIconDragItem id;
01240           id.setData( QCString(itemURL.latin1()) );
01241           drag->append( id,
01242                         QRect( it->pixmapRect(false).topLeft() - m_mousePos - offset,
01243                                it->pixmapRect().size() ),
01244                         QRect( it->textRect(false).topLeft() - m_mousePos - offset,
01245                                it->textRect().size() ),
01246                         itemURL );
01247         }
01248     }
01249 
01250     if (primaryItem)
01251     {
01252        // Set pixmap, with the correct offset
01253        drag->setPixmap( *primaryItem->pixmap(), m_mousePos - primaryItem->pixmapRect(false).topLeft() + offset );
01254     }
01255 
01256     return drag;
01257 }
01258 
01259 void KonqIconViewWidget::contentsDragEnterEvent( QDragEnterEvent *e )
01260 {
01261     if ( e->provides( "text/uri-list" ) )
01262     {
01263         QByteArray payload = e->encodedData( "text/uri-list" );
01264         if ( !payload.size() )
01265             kdError() << "Empty data !" << endl;
01266         // Cache the URLs, since we need them every time we move over a file
01267         // (see KFileIVI)
01268         bool ok = KURLDrag::decode( e, m_lstDragURLs );
01269         if( !ok )
01270             kdError() << "Couldn't decode urls dragged !" << endl;
01271     }
01272     KIconView::contentsDragEnterEvent( e );
01273     emit dragEntered();
01274 }
01275 
01276 void KonqIconViewWidget::contentsDragLeaveEvent( QDragLeaveEvent *e )
01277 {
01278     QIconView::contentsDragLeaveEvent(e);
01279     emit dragLeft();
01280 }
01281 
01282 
01283 void KonqIconViewWidget::setItemColor( const QColor &c )
01284 {
01285     iColor = c;
01286 }
01287 
01288 QColor KonqIconViewWidget::itemColor() const
01289 {
01290     return iColor;
01291 }
01292 
01293 void KonqIconViewWidget::disableIcons( const KURL::List & lst )
01294 {
01295   for ( QIconViewItem *kit = firstItem(); kit; kit = kit->nextItem() )
01296   {
01297       bool bFound = false;
01298       // Wow. This is ugly. Matching two lists together....
01299       // Some sorting to optimise this would be a good idea ?
01300       for (KURL::List::ConstIterator it = lst.begin(); !bFound && it != lst.end(); ++it)
01301       {
01302           if ( static_cast<KFileIVI *>( kit )->item()->url() == *it )
01303           {
01304               bFound = true;
01305               // maybe remove "it" from lst here ?
01306           }
01307       }
01308       static_cast<KFileIVI *>( kit )->setDisabled( bFound );
01309   }
01310 }
01311 
01312 void KonqIconViewWidget::slotSelectionChanged()
01313 {
01314     // This code is very related to ListViewBrowserExtension::updateActions
01315     int canCopy = 0;
01316     int canDel = 0;
01317     bool bInTrash = false;
01318     int iCount = 0;
01319 
01320     for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
01321     {
01322         if ( it->isSelected() )
01323         {
01324             iCount++;
01325             canCopy++;
01326 
01327             KURL url = ( static_cast<KFileIVI *>( it ) )->item()->url();
01328             if ( url.directory(false) == KGlobalSettings::trashPath() )
01329                 bInTrash = true;
01330             if ( KProtocolInfo::supportsDeleting( url ) )
01331                 canDel++;
01332         }
01333     }
01334 
01335     emit enableAction( "cut", canDel > 0 );
01336     emit enableAction( "copy", canCopy > 0 );
01337     emit enableAction( "trash", canDel > 0 && !bInTrash && m_url.isLocalFile() );
01338     emit enableAction( "del", canDel > 0 );
01339     emit enableAction( "properties", iCount > 0 && KPropertiesDialog::canDisplay( selectedFileItems() ) );
01340     emit enableAction( "editMimeType", ( iCount == 1 ) );
01341     emit enableAction( "rename", ( iCount == 1 ) && !bInTrash );
01342 }
01343 
01344 void KonqIconViewWidget::renameCurrentItem()
01345 {
01346     if ( currentItem() )
01347         currentItem()->rename();
01348 }
01349 
01350 void KonqIconViewWidget::renameSelectedItem()
01351 {
01352     kdDebug(1203) << " -- KonqIconViewWidget::renameSelectedItem() -- " << endl;
01353     QIconViewItem * item = 0L;
01354     QIconViewItem *it = firstItem();
01355     for (; it; it = it->nextItem() )
01356         if ( it->isSelected() && !item )
01357         {
01358             item = it;
01359             break;
01360         }
01361     if (!item)
01362     {
01363         Q_ASSERT(item);
01364         return;
01365     }
01366     item->rename();
01367 }
01368 
01369 void KonqIconViewWidget::cutSelection()
01370 {
01371     kdDebug(1203) << " -- KonqIconViewWidget::cutSelection() -- " << endl;
01372     KonqIconDrag * obj = konqDragObject( /* no parent ! */ );
01373     obj->setMoveSelection( true );
01374     QApplication::clipboard()->setData( obj );
01375 }
01376 
01377 void KonqIconViewWidget::copySelection()
01378 {
01379     kdDebug(1203) << " -- KonqIconViewWidget::copySelection() -- " << endl;
01380     KonqIconDrag * obj = konqDragObject( /* no parent ! */ );
01381     QApplication::clipboard()->setData( obj );
01382 }
01383 
01384 void KonqIconViewWidget::pasteSelection()
01385 {
01386     paste( url() );
01387 }
01388 
01389 void KonqIconViewWidget::paste( const KURL &url )
01390 {
01391     KonqOperations::doPaste( this, url );
01392 }
01393 
01394 KURL::List KonqIconViewWidget::selectedUrls()
01395 {
01396     KURL::List lstURLs;
01397 
01398     for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
01399         if ( it->isSelected() )
01400             lstURLs.append( (static_cast<KFileIVI *>( it ))->item()->url() );
01401     return lstURLs;
01402 }
01403 
01404 QRect KonqIconViewWidget::iconArea() const
01405 {
01406     return m_IconRect;
01407 }
01408 
01409 void KonqIconViewWidget::setIconArea(const QRect &rect)
01410 {
01411     m_IconRect = rect;
01412 }
01413 
01414 int KonqIconViewWidget::lineupMode() const
01415 {
01416     return m_LineupMode;
01417 }
01418 
01419 void KonqIconViewWidget::setLineupMode(int mode)
01420 {
01421     m_LineupMode = mode;
01422 }
01423 
01424 bool KonqIconViewWidget::sortDirectoriesFirst() const
01425 {
01426   return m_bSortDirsFirst;
01427 }
01428 
01429 void KonqIconViewWidget::setSortDirectoriesFirst( bool b )
01430 {
01431   m_bSortDirsFirst = b;
01432 }
01433 
01434 void KonqIconViewWidget::contentsMouseMoveEvent( QMouseEvent *e )
01435 {
01436     if ( (d->pSoundPlayer && d->pSoundPlayer->isPlaying()) || (d->pSoundTimer && d->pSoundTimer->isActive()))
01437     {
01438         // The following call is SO expensive (the ::widgetAt call eats up to 80%
01439         // of the mouse move cpucycles!), so it's mandatory to place that function 
01440         // under strict checks, such as d->pSoundPlayer->isPlaying()
01441         if ( QApplication::widgetAt( QCursor::pos() ) != topLevelWidget() )
01442         {
01443             if (d->pSoundPlayer)
01444                 d->pSoundPlayer->stop();
01445             d->pSoundItem = 0;
01446             if (d->pSoundTimer && d->pSoundTimer->isActive())
01447                 d->pSoundTimer->stop();
01448         }
01449     }
01450     d->renameItem= false;
01451     QIconView::contentsMouseMoveEvent( e );
01452 }
01453 
01454 void KonqIconViewWidget::contentsDropEvent( QDropEvent * ev )
01455 {
01456   QIconViewItem *i = findItem( ev->pos() );
01457   // Short-circuit QIconView if Ctrl is pressed, so that it's possible
01458   // to drop a file into its own parent widget to copy it.
01459   if ( !i && (ev->action() == QDropEvent::Copy || ev->action() == QDropEvent::Link)
01460           && ev->source() && ev->source() == viewport())
01461   {
01462     // First we need to call QIconView though, to clear the drag shape
01463     bool bMovable = itemsMovable();
01464     setItemsMovable(false); // hack ? call it what you want :-)
01465     KIconView::contentsDropEvent( ev );
01466     setItemsMovable(bMovable);
01467 
01468     QValueList<QIconDragItem> lst;
01469     slotDropped(ev, lst);
01470   }
01471   else
01472   {
01473     KIconView::contentsDropEvent( ev );
01474     emit dropped(); // What is this for ? (David)
01475   }
01476   // Don't do this here, it's too early !
01477   // slotSaveIconPositions();
01478   // If we want to save after the new file gets listed, though,
01479   // we could reimplement contentsDropEvent in KDIconView and set m_bNeedSave. Bah.
01480 
01481   // This signal is sent last because we need to ensure it is
01482   // taken in account when all the slots triggered by the dropped() signal
01483   // are executed. This way we know that the Drag and Drop is truely finished
01484   emit dragFinished();
01485 }
01486 
01487 void KonqIconViewWidget::doubleClickTimeout()
01488 {
01489     d->renameItem= true;
01490     mousePressChangeValue();
01491     if ( d->releaseMouseEvent )
01492     {
01493         QMouseEvent e( QEvent::MouseButtonPress,d->mousePos , 1, d->mouseState);
01494         QIconViewItem* item = findItem( e.pos() );
01495         KURL url;
01496         if ( item )
01497         {
01498             url= ( static_cast<KFileIVI *>( item ) )->item()->url();
01499             bool brenameTrash =false;
01500             if ( url.isLocalFile() && (url.directory(false) == KGlobalSettings::trashPath() || url.path(1).startsWith(KGlobalSettings::trashPath())))
01501                 brenameTrash = true;
01502 
01503             if ( url.isLocalFile() && !brenameTrash && d->renameItem && m_pSettings->renameIconDirectly() && e.button() == LeftButton && item->textRect( false ).contains(e.pos()))
01504             {
01505                 if( d->pActivateDoubleClick->isActive () )
01506                     d->pActivateDoubleClick->stop();
01507                 item->rename();
01508                 m_bMousePressed = false;
01509             }
01510         }
01511     }
01512     else
01513     {
01514         QMouseEvent e( QEvent::MouseMove,d->mousePos , 1, d->mouseState);
01515         KIconView::contentsMousePressEvent( &e );
01516     }
01517     if( d->pActivateDoubleClick->isActive() )
01518         d->pActivateDoubleClick->stop();
01519 
01520     d->releaseMouseEvent = false;
01521     d->renameItem= false;
01522 }
01523 
01524 void KonqIconViewWidget::wheelEvent(QWheelEvent* e)
01525 {
01526     if (e->state() == ControlButton)
01527     {
01528         if (e->delta() >= 0)
01529         {
01530             emit incIconSize();
01531         }
01532         else
01533         {
01534             emit decIconSize();
01535         }
01536         e->accept();
01537         return;
01538     }
01539 
01540     KIconView::wheelEvent(e);
01541 }
01542 
01543 void KonqIconViewWidget::mousePressChangeValue()
01544 {
01545   //kdDebug(1203) << "KonqIconViewWidget::contentsMousePressEvent" << endl;
01546   m_bMousePressed = true;
01547   if (d->pSoundPlayer)
01548     d->pSoundPlayer->stop();
01549   d->bSoundItemClicked = true;
01550   d->firstClick = false;
01551   
01552   // Once we click on the item, we don't want a tooltip
01553   // Fixes part of #86968
01554   d->pFileTip->setItem( 0 );
01555 }
01556 
01557 void KonqIconViewWidget::contentsMousePressEvent( QMouseEvent *e )
01558 {
01559     if(d->pActivateDoubleClick && d->pActivateDoubleClick->isActive ())
01560         d->pActivateDoubleClick->stop();
01561      QIconViewItem* item = findItem( e->pos() );
01562      m_mousePos = e->pos();
01563      KURL url;
01564      if ( item )
01565      {
01566          url = ( static_cast<KFileIVI *>( item ) )->item()->url();
01567          bool brenameTrash =false;
01568          if ( url.isLocalFile() && (url.directory(false) == KGlobalSettings::trashPath() || url.path(1).startsWith(KGlobalSettings::trashPath())))
01569              brenameTrash = true;
01570          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))
01571          {
01572              d->firstClick = true;
01573              d->mousePos = e->pos();
01574              d->mouseState = e->state();
01575              if (!d->pActivateDoubleClick)
01576              {
01577                  d->pActivateDoubleClick = new QTimer(this);
01578                  connect(d->pActivateDoubleClick, SIGNAL(timeout()), this, SLOT(doubleClickTimeout()));
01579              }
01580              if( d->pActivateDoubleClick->isActive () )
01581                  d->pActivateDoubleClick->stop();
01582              else
01583                  d->pActivateDoubleClick->start(QApplication::doubleClickInterval());
01584              d->releaseMouseEvent = false;
01585              return;
01586          }
01587          else
01588              d->renameItem= false;
01589      }
01590      else
01591          d->renameItem= false;
01592     mousePressChangeValue();
01593     if(d->pActivateDoubleClick && d->pActivateDoubleClick->isActive())
01594         d->pActivateDoubleClick->stop();
01595     KIconView::contentsMousePressEvent( e );
01596 
01597 }
01598 
01599 void KonqIconViewWidget::contentsMouseReleaseEvent( QMouseEvent *e )
01600 {
01601     KIconView::contentsMouseReleaseEvent( e );
01602     if(d->releaseMouseEvent && d->pActivateDoubleClick && d->pActivateDoubleClick->isActive ())
01603         d->pActivateDoubleClick->stop();
01604     slotSelectionChanged();
01605     d->releaseMouseEvent = true;
01606     m_bMousePressed = false;
01607 }
01608 
01609 void KonqIconViewWidget::slotSaveIconPositions()
01610 {
01611   // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
01612   // This code is currently not used but left in for compatibility reasons.
01613   // It can be removed in KDE 4.0
01614   // Saving of desktop icon positions is now done in KDIconView::saveIconPositions()
01615   // in kdebase/kdesktop/kdiconview.cc
01616   // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
01617 
01618   if ( m_dotDirectoryPath.isEmpty() )
01619     return;
01620   if ( !m_bDesktop )
01621     return; // Currently not available in Konqueror
01622   kdDebug(1214) << "KonqIconViewWidget::slotSaveIconPositions" << endl;
01623   KSimpleConfig dotDirectory( m_dotDirectoryPath );
01624   QIconViewItem *it = firstItem();
01625   if ( !it )
01626     return; // No more icons. Maybe we're closing and they've been removed already
01627   while ( it )
01628   {
01629     KFileIVI *ivi = static_cast<KFileIVI *>( it );
01630     KFileItem *item = ivi->item();
01631 
01632     dotDirectory.setGroup( QString( m_iconPositionGroupPrefix ).append( item->url().fileName() ) );
01633     kdDebug(1214) << "KonqIconViewWidget::slotSaveIconPositions " << item->url().fileName() << " " << it->x() << " " << it->y() << endl;
01634     dotDirectory.writeEntry( QString( "X %1" ).arg( width() ), it->x() );
01635     dotDirectory.writeEntry( QString( "Y %1" ).arg( height() ), it->y() );
01636     dotDirectory.writeEntry( "Exists", true );
01637 
01638     it = it->nextItem();
01639   }
01640 
01641   QStringList groups = dotDirectory.groupList();
01642   QStringList::ConstIterator gIt = groups.begin();
01643   QStringList::ConstIterator gEnd = groups.end();
01644   for (; gIt != gEnd; ++gIt )
01645     if ( (*gIt).left( m_iconPositionGroupPrefix.length() ) == m_iconPositionGroupPrefix )
01646     {
01647       dotDirectory.setGroup( *gIt );
01648       if ( dotDirectory.hasKey( "Exists" ) )
01649         dotDirectory.deleteEntry( "Exists", false );
01650       else
01651       {
01652         kdDebug(1214) << "KonqIconViewWidget::slotSaveIconPositions deleting group " << *gIt << endl;
01653         dotDirectory.deleteGroup( *gIt );
01654       }
01655     }
01656 
01657   dotDirectory.sync();
01658 
01659   // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
01660   // This code is currently not used but left in for compatibility reasons.
01661   // It can be removed in KDE 4.0
01662   // Saving of desktop icon positions is now done in KDIconView::saveIconPositions()
01663   // in kdebase/kdesktop/kdiconview.cc
01664   // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
01665 }
01666 
01667 // Adapted version of QIconView::insertInGrid, that works relative to
01668 // m_IconRect, instead of the entire viewport.
01669 
01670 void KonqIconViewWidget::insertInGrid(QIconViewItem *item)
01671 {
01672     if (0L == item)
01673         return;
01674 
01675     if (!m_IconRect.isValid())
01676     {
01677         QIconView::insertInGrid(item);
01678         return;
01679     }
01680 
01681     QRegion r(m_IconRect);
01682     QIconViewItem *i = firstItem();
01683     int y = -1;
01684     for (; i; i = i->nextItem() )
01685     {
01686         r = r.subtract(i->rect());
01687         y = QMAX(y, i->y() + i->height());
01688     }
01689 
01690     QMemArray<QRect> rects = r.rects();
01691     QMemArray<QRect>::Iterator it = rects.begin();
01692     bool foundPlace = FALSE;
01693     for (; it != rects.end(); ++it)
01694     {
01695         QRect rect = *it;
01696         if (rect.width() >= item->width() && rect.height() >= item->height())
01697         {
01698             int sx = 0, sy = 0;
01699             if (rect.width() >= item->width() + spacing())
01700                 sx = spacing();
01701             if (rect.height() >= item->height() + spacing())
01702                 sy = spacing();
01703             item->move(rect.x() + sx, rect.y() + sy);
01704             foundPlace = true;
01705             break;
01706         }
01707     }
01708 
01709     if (!foundPlace)
01710         item->move(m_IconRect.topLeft());
01711 
01712     //item->dirty = false;
01713     return;
01714 }
01715 
01716 
01717 /*
01718  * The algorithm used for lineing up the icons could be called
01719  * "beating flat the icon field". Imagine the icon field to be some height
01720  * field on a regular grid, with the height being the number of icons in
01721  * each grid element. Now imagine slamming on the field with a shovel or
01722  * some other flat surface. The high peaks will be flattened and spread out
01723  * over their adjacent areas. This is basically what the algorithm tries to
01724  * simulate.
01725  *
01726  * First, the icons are binned to a grid of the desired size. If all bins
01727  * are containing at most one icon, we're done, of course. We just have to
01728  * move all icons to the center of each grid element.
01729  * For each bin which has more than one icon in it, we calculate 4
01730  * "friction coefficients", one for each cardinal direction. The friction
01731  * coefficient of a direction is the number of icons adjacent in that
01732  * direction. The idea is that this number is somewhat a measure in which
01733  * direction the icons should flow: icons flow in the direction of lowest
01734  * friction coefficient. We move a maximum of one icon per bin and loop over
01735  * all bins. This procedure is repeated some maximum number of times or until
01736  * no icons are moved anymore.
01737  *
01738  * I don't know if this algorithm is good or bad, I don't even know if it will
01739  * work all the time. It seems a correct thing to do, however, and it seems to
01740  * work particularly well. In any case, the number of runs is limited so there
01741  * can be no races.
01742  */
01743 
01744 void KonqIconViewWidget::lineupIcons()
01745 {
01746     if ( !firstItem() ) {
01747         kdDebug(1203) << "No icons at all ?\n";
01748         return;
01749     }
01750 
01751     // Make a list of items
01752     QValueList<QIconViewItem*> items;
01753     for ( QIconViewItem* item = firstItem(); item; item = item->nextItem() )
01754         items.append(item);
01755 
01756     int iconSize = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
01757 
01758     // Create a grid of (ny x nx) bins.
01759     int x0, y0, dx, dy, nx, ny;
01760     gridValues( &x0, &y0, &dx, &dy, &nx, &ny );
01761     typedef QValueList<QIconViewItem*> Bin;
01762     Bin* bins[nx][ny];
01763     int i;
01764     int j;
01765     for ( i = 0; i < nx ; i++ ) {
01766         for ( j = 0; j < ny; j++ )
01767             bins[i][j] = 0L;
01768     }
01769 
01770     // Insert items into grid
01771     int textHeight = QMIN( iconTextHeight(), 2 ) * fontMetrics().height();
01772     QValueList<QIconViewItem*>::Iterator it;
01773     for ( it = items.begin(); it != items.end(); it++ ) {
01774         QIconViewItem* item = *it;
01775         int x = item->x() + item->width() / 2 - x0;
01776         int y = item->pixmapRect( false ).bottom() - iconSize / 2
01777                 - ( dy - ( iconSize + textHeight ) ) / 2 - y0;
01778         int posX = QMIN( nx-1, QMAX( 0, x / dx ) );
01779         int posY = QMIN( ny-1, QMAX( 0, y / dy ) );
01780 
01781         if ( !bins[posX][posY] )
01782             bins[posX][posY] = new Bin;
01783         bins[posX][posY]->prepend( item );
01784     }
01785 
01786     // The shuffle code
01787     int n, k;
01788     const int infinity = 10000;
01789     int nmoves = 1;
01790     for ( n = 0; n < 30 && nmoves > 0; n++ ) {
01791         nmoves = 0;
01792         for ( i = 0; i < nx; i++ ) {
01793             for ( j = 0; j < ny; j++ ) {
01794                 if ( !bins[i][j] || ( bins[i][j]->count() <= 1 ) )
01795                     continue;
01796 
01797                 // Calculate the 4 "friction coefficients".
01798                 int tf = 0, bf = 0, lf = 0, rf = 0;
01799                 for ( k = j-1; k >= 0 && bins[i][k] && bins[i][k]->count(); k-- )
01800                     tf += bins[i][k]->count();
01801                 if ( k == -1 )
01802                     tf += infinity;
01803 
01804                 for ( k = j+1; k < ny && bins[i][k] && bins[i][k]->count(); k++ )
01805                     bf += bins[i][k]->count();
01806                 if ( k == ny )
01807                     bf += infinity;
01808 
01809                 for ( k = i-1; k >= 0 && bins[k][j] && bins[k][j]->count(); k-- )
01810                     lf += bins[k][j]->count();
01811                 if ( k == -1 )
01812                     lf += infinity;
01813 
01814                 for ( k = i+1; k < nx && bins[k][j] && bins[k][j]->count(); k++ )
01815                     rf += bins[k][j]->count();
01816                 if ( k == nx )
01817                     rf += infinity;
01818 
01819                 // If we are stuck between walls, continue
01820                 if ( tf >= infinity && bf >= infinity &&
01821                      lf >= infinity && rf >= infinity )
01822                     continue;
01823 
01824                 // Is there a preferred lineup direction?
01825                 if ( m_LineupMode == LineupHorizontal ) {
01826                     tf += infinity;
01827                     bf += infinity;
01828                 }
01829                 else if ( m_LineupMode == LineupVertical ) {
01830                     lf += infinity;
01831                     rf += infinity;
01832                 }
01833 
01834                 // Move one item in the direction of the least friction
01835                 QIconViewItem* movedItem;
01836                 Bin* items = bins[i][j];
01837 
01838                 int mini = QMIN( QMIN( tf, bf ), QMIN( lf, rf ) );
01839                 if ( tf == mini ) {
01840                     // move top item in (i,j) to (i,j-1)
01841                     Bin::iterator it = items->begin();
01842                     movedItem = *it;
01843                     for ( ++it; it != items->end(); ++it ) {
01844                         if ( (*it)->y() < movedItem->y() )
01845                             movedItem = *it;
01846                     }
01847                     items->remove( movedItem );
01848                     if ( !bins[i][j-1] )
01849                         bins[i][j-1] = new Bin;
01850                     bins[i][j-1]->prepend( movedItem );
01851                 }
01852                 else if ( bf ==mini ) {
01853                     // move bottom item in (i,j) to (i,j+1)
01854                     Bin::iterator it = items->begin();
01855                     movedItem = *it;
01856                     for ( ++it; it != items->end(); ++it ) {
01857                         if ( (*it)->y() > movedItem->y() )
01858                             movedItem = *it;
01859                     }
01860                     items->remove( movedItem );
01861                     if ( !bins[i][j+1] )
01862                         bins[i][j+1] = new Bin;
01863                     bins[i][j+1]->prepend( movedItem );
01864                 }
01865                 else if ( lf == mini )
01866                 {
01867                     // move left item in (i,j) to (i-1,j)
01868                     Bin::iterator it = items->begin();
01869                     movedItem = *it;
01870                     for ( ++it; it != items->end(); ++it ) {
01871                         if ( (*it)->x() < movedItem->x() )
01872                             movedItem = *it;
01873                     }
01874                     items->remove( movedItem );
01875                     if ( !bins[i-1][j] )
01876                         bins[i-1][j] = new Bin;
01877                     bins[i-1][j]->prepend( movedItem );
01878                 }
01879                 else {
01880                     // move right item in (i,j) to (i+1,j)
01881                     Bin::iterator it = items->begin();
01882                     movedItem = *it;
01883                     for ( ++it; it != items->end(); ++it ) {
01884                         if ( (*it)->x() > movedItem->x() )
01885                             movedItem = *it;
01886                     }
01887                     items->remove( movedItem );
01888                     if ( !bins[i+1][j] )
01889                         bins[i+1][j] = new Bin;
01890                     bins[i+1][j]->prepend( movedItem );
01891                 }
01892                 nmoves++;
01893             }
01894         }
01895     }
01896 
01897     // Perform the actual moving
01898     QRegion repaintRegion;
01899     QValueList<QIconViewItem*> movedItems;
01900 
01901     for ( i = 0; i < nx; i++ ) {
01902         for ( j = 0; j < ny; j++ ) {
01903             Bin* bin = bins[i][j];
01904             if ( !bin )
01905                 continue;
01906             if ( !bin->isEmpty() ) {
01907                 QIconViewItem* item = bin->first();
01908                 int newX = x0 + i*dx + ( dx - item->width() ) / 2;
01909                 int newY = y0 + j*dy + dy - ( item->pixmapRect().bottom() + textHeight + 2 );
01910                 if ( item->x() != newX || item->y() != newY ) {
01911                     QRect oldRect = item->rect();
01912                     movedItems.prepend( item );
01913                     item->move( newX, newY );
01914                     if ( item->rect() != oldRect )
01915                         repaintRegion = repaintRegion.unite( oldRect );
01916                 }
01917             }
01918             delete bin;
01919             bins[i][j] = 0L;
01920         }
01921     }
01922 
01923     // repaint
01924     int itemWidth = dx - 2 * spacing();
01925     if ( maxItemWidth() != itemWidth ) {
01926         setMaxItemWidth( itemWidth );
01927         setFont( font() );  // Force calcRect()
01928         updateContents();
01929     }
01930     else {
01931         // Repaint only repaintRegion...
01932         QMemArray<QRect> rects = repaintRegion.rects();
01933         for ( uint l = 0; l < rects.count(); l++ ) {
01934             kdDebug( 1203 ) << "Repainting (" << rects[l].x() << ","
01935                             << rects[l].y() << ")\n";
01936             repaintContents( rects[l], false );
01937         }
01938         // Repaint icons that were moved
01939         while ( !movedItems.isEmpty() ) {
01940             repaintItem( movedItems.first() );
01941             movedItems.remove( movedItems.first() );
01942         }
01943     }
01944 }
01945 
01946 void KonqIconViewWidget::lineupIcons( QIconView::Arrangement arrangement )
01947 {
01948     int x0, y0, dx, dy, nxmax, nymax;
01949     gridValues( &x0, &y0, &dx, &dy, &nxmax, &nymax );
01950     int textHeight = QMIN( iconTextHeight(), 2 ) * fontMetrics().height();
01951 
01952     QRegion repaintRegion;
01953     QValueList<QIconViewItem*> movedItems;
01954     int nx = 0, ny = 0;
01955 
01956     QIconViewItem* item;
01957     for ( item = firstItem(); item; item = item->nextItem() ) {
01958         int newX = x0 + nx * dx + ( dx - item->width() ) / 2;
01959         int newY = y0 + ny * dy + dy - ( item->pixmapRect().bottom() + textHeight + 2 );
01960         if ( item->x() != newX || item->y() != newY ) {
01961             QRect oldRect = item->rect();
01962             movedItems.prepend( item );
01963             item->move( newX, newY );
01964             if ( item->rect() != oldRect )
01965                 repaintRegion = repaintRegion.unite( oldRect );
01966         }
01967         if ( arrangement == QIconView::LeftToRight ) {
01968             nx++;
01969             if ( nx >= nxmax ) {
01970                 ny++;
01971                 nx = 0;
01972             }
01973         }
01974         else {
01975             ny++;
01976             if ( ny >= nymax ) {
01977                 nx++;
01978                 ny = 0;
01979             }
01980         }
01981     }
01982 
01983     // Repaint only repaintRegion...
01984     QMemArray<QRect> rects = repaintRegion.rects();
01985     for ( uint l = 0; l < rects.count(); l++ ) {
01986         kdDebug( 1203 ) << "Repainting (" << rects[l].x() << ","
01987                         << rects[l].y() << ")\n";
01988         repaintContents( rects[l], false );
01989     }
01990     // Repaint icons that were moved
01991     while ( !movedItems.isEmpty() ) {
01992         repaintItem( movedItems.first() );
01993         movedItems.remove( movedItems.first() );
01994     }
01995 }
01996 
01997 int KonqIconViewWidget::largestPreviewIconSize( int size ) const
01998 {
01999     int iconSize = size ? size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
02000 
02001     if (iconSize < 28)
02002         return 48;
02003     if (iconSize < 40)
02004         return 64;
02005     if (iconSize < 60)
02006         return 96;
02007     if (iconSize < 120)
02008         return 128;
02009 
02010     return 192;
02011 }
02012 
02013 int KonqIconViewWidget::previewIconSize( int size ) const
02014 {
02015     int iconSize = size ? size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
02016 
02017     if (!d->bBoostPreview)
02018         return iconSize;
02019 
02020     return largestPreviewIconSize( iconSize );
02021 }
02022 
02023 void KonqIconViewWidget::visualActivate(QIconViewItem * item)
02024 {
02025     // Rect of the QIconViewItem.
02026     QRect irect = item->rect();
02027 
02028     // Rect of the QIconViewItem's pixmap area.
02029     QRect rect = item->pixmapRect();
02030 
02031     // Adjust to correct position. If this isn't done, the fact that the
02032     // text may be wider than the pixmap puts us off-centre.
02033     rect.moveBy(irect.x(), irect.y());
02034 
02035     // Adjust for scrolling (David)
02036     rect.moveBy( -contentsX(), -contentsY() );
02037 
02038     KIconEffect::visualActivate(viewport(), rect);
02039 }
02040 
02041 void KonqIconViewWidget::backgroundPixmapChange( const QPixmap & )
02042 {
02043     viewport()->update();
02044 }
02045 
02046 void KonqIconViewWidget::setPreviewSettings( const QStringList& settings )
02047 {
02048     d->previewSettings = settings;
02049     updatePreviewMimeTypes();
02050     
02051     int size = m_size;
02052     m_size = -1; // little trick to force grid change in setIcons
02053     setIcons( size ); // force re-determining all icons
02054 }
02055 
02056 const QStringList& KonqIconViewWidget::previewSettings()
02057 {
02058     return d->previewSettings;
02059 }
02060 
02061 void KonqIconViewWidget::setNewURL( const QString& url )
02062 {
02063     KURL u;
02064     if ( url.startsWith( "/" ) )
02065         u.setPath( url );
02066     else
02067         u = url;
02068     setURL( u );
02069 }
02070 
02071 void KonqIconViewWidget::setCaseInsensitiveSort( bool b )
02072 {
02073     d->bCaseInsensitive = b;
02074 }
02075 
02076 bool KonqIconViewWidget::caseInsensitiveSort() const
02077 {
02078     return d->bCaseInsensitive;
02079 }
02080 
02081 bool KonqIconViewWidget::canPreview( KFileItem* item )
02082 {
02083     if ( !KGlobalSettings::showFilePreview( url() ) )
02084         return false;
02085 
02086     if ( d->pPreviewMimeTypes == 0L )
02087         updatePreviewMimeTypes();
02088 
02089     return mimeTypeMatch( item->mimetype(), *( d->pPreviewMimeTypes ) );
02090 }
02091 
02092 void KonqIconViewWidget::updatePreviewMimeTypes()
02093 {
02094     if ( d->pPreviewMimeTypes == 0L )
02095         d->pPreviewMimeTypes = new QStringList;
02096     else
02097         d->pPreviewMimeTypes->clear();
02098 
02099     // Load the list of plugins to determine which mimetypes are supported
02100     KTrader::OfferList plugins = KTrader::self()->query("ThumbCreator");
02101     KTrader::OfferList::ConstIterator it;
02102 
02103     for ( it = plugins.begin(); it != plugins.end(); ++it ) {
02104         if ( d->previewSettings.contains((*it)->desktopEntryName()) ) {
02105             QStringList mimeTypes = (*it)->property("MimeTypes").toStringList();
02106             for (QStringList::ConstIterator mt = mimeTypes.begin(); mt != mimeTypes.end(); ++mt)
02107                 d->pPreviewMimeTypes->append(*mt);
02108         }
02109     }
02110 }
02111 
02112 #include "konq_iconviewwidget.moc"
02113 
02114 /* vim: set et sw=4 ts=8 softtabstop=4: */
KDE Logo
This file is part of the documentation for libkonq Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Aug 20 13:39:03 2006 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003