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     KIconView::focusOutEvent( ev );
00473 }
00474 
00475 void KonqIconViewWidget::slotItemRenamed(QIconViewItem *item, const QString &name)
00476 {
00477     kdDebug(1203) << "KonqIconViewWidget::slotItemRenamed" << endl;
00478     KFileIVI *viewItem = static_cast<KFileIVI *>(item);
00479     KFileItem *fileItem = viewItem->item();
00480 
00481     // The correct behavior is to show the old name until the rename has successfully
00482     // completed. Unfortunately, KIconView forces us to allow the text to be changed
00483     // before we try the rename, so set it back to the pre-rename state.
00484     viewItem->setText( fileItem->text() );
00485     kdDebug(1203)<<" fileItem->text() ;"<<fileItem->text()<<endl;
00486     // Don't do anything if the user renamed to a blank name.
00487     if( !name.isEmpty() )
00488     {
00489         // Actually attempt the rename. If it succeeds, KDirLister will update the name.
00490         KURL oldurl( fileItem->url() );
00491         KURL newurl( url() );
00492         newurl.setPath( url().path(1) + KIO::encodeFileName( name ) );
00493         kdDebug(1203)<<" newurl :"<<newurl.url()<<endl;
00494         // We use url()+name so that it also works if the name is a relative path (#51176)
00495         KonqOperations::rename( this, oldurl, newurl );
00496     }
00497 }
00498 
00499 void KonqIconViewWidget::slotIconChanged( int group )
00500 {
00501     if (group != KIcon::Desktop)
00502         return;
00503 
00504     int size = m_size;
00505     if ( m_size == 0 )
00506       m_size = -1; // little trick to force grid change in setIcons
00507     setIcons( size ); // force re-determining all icons
00508     readAnimatedIconsConfig();
00509 }
00510 
00511 void KonqIconViewWidget::readAnimatedIconsConfig()
00512 {
00513     KConfigGroup cfgGroup( KGlobal::config(), "DesktopIcons" );
00514     d->doAnimations = cfgGroup.readBoolEntry( "Animated", true /*default*/ );
00515     d->gridXspacing = cfgGroup.readNumEntry( "GridXSpacing", 50);
00516 }
00517 
00518 void KonqIconViewWidget::slotOnItem( QIconViewItem *_item )
00519 {
00520     KFileIVI* item = static_cast<KFileIVI *>( _item );
00521     // Reset icon of previous item
00522     if( d->pActiveItem != 0L && d->pActiveItem != item )
00523     {
00524         if ( d->m_movie && d->pActiveItem->isAnimated() )
00525         {
00526             d->m_movie->pause(); // we'll see below what we do with it
00527             d->pActiveItem->setAnimated( false );
00528             d->pActiveItem->refreshIcon( true );
00529         }
00530         else {
00531             d->pActiveItem->setActive( false );
00532         }
00533         d->pActiveItem = 0L;
00534         d->pFileTipTimer->stop();
00535         d->pFileTip->setItem( 0L );
00536     }
00537 
00538     // Stop sound
00539     if (d->pSoundPlayer != 0 && item != d->pSoundItem)
00540     {
00541         d->pSoundPlayer->stop();
00542 
00543         d->pSoundItem = 0;
00544         if (d->pSoundTimer && d->pSoundTimer->isActive())
00545             d->pSoundTimer->stop();
00546     }
00547 
00548     if ( !m_bMousePressed )
00549     {
00550         if( item != d->pActiveItem )
00551         {
00552             d->pActiveItem = item;
00553             if ( topLevelWidget() == kapp->activeWindow() )
00554                 d->pFileTipTimer->start( 400, true );
00555 
00556             if ( d->doAnimations && d->pActiveItem && d->pActiveItem->hasAnimation() )
00557             {
00558                 //kdDebug(1203) << "Playing animation for: " << d->pActiveItem->mouseOverAnimation() << endl;
00559                 // Check if cached movie can be used
00560 #if 0 // Qt-mng bug, reusing the movie doesn't work currently.
00561                 if ( d->m_movie && d->movieFileName == d->pActiveItem->mouseOverAnimation() )
00562                 {
00563                     d->pActiveItem->setAnimated( true );
00564                     if (d->m_movieBlocked) {
00565                         kdDebug(1203) << "onitem, but blocked" << endl;
00566                         d->m_movie->pause();
00567                     }
00568                     else {
00569                         kdDebug(1203) << "we go ahead.." << endl;
00570                         d->m_movieBlocked++;
00571                         QTimer::singleShot(300, this, SLOT(slotReenableAnimation()));
00572                         d->m_movie->restart();
00573                         d->m_movie->unpause();
00574                     }
00575                 }
00576                 else
00577 #endif
00578                 {
00579                     QMovie movie = KGlobal::iconLoader()->loadMovie( d->pActiveItem->mouseOverAnimation(), KIcon::Desktop, d->pActiveItem->iconSize() );
00580                     if ( !movie.isNull() )
00581                     {
00582                         delete d->m_movie;
00583                         d->m_movie = new QMovie( movie ); // shallow copy, don't worry
00584                         // Fix alpha-channel - currently only if no background pixmap,
00585                         // the bg pixmap case requires to uncomment the code at qmovie.cpp:404
00586                         const QPixmap* pm = backgroundPixmap();
00587                         bool hasPixmap = pm && !pm->isNull();
00588                         if ( !hasPixmap ) {
00589                             pm = viewport()->backgroundPixmap();
00590                             hasPixmap = pm && !pm->isNull();
00591                         }
00592                         if (!hasPixmap && backgroundMode() != NoBackground)
00593                            d->m_movie->setBackgroundColor( viewport()->backgroundColor() );
00594                         d->m_movie->connectUpdate( this, SLOT( slotMovieUpdate(const QRect &) ) );
00595                         d->m_movie->connectStatus( this, SLOT( slotMovieStatus(int) ) );
00596                         d->movieFileName = d->pActiveItem->mouseOverAnimation();
00597                         d->pActiveItem->setAnimated( true );
00598                     }
00599                     else
00600                     {
00601                         d->pActiveItem->setAnimated( false );
00602                         if (d->m_movie)
00603                             d->m_movie->pause();
00604                         // No movie available, remember it
00605                         d->pActiveItem->setMouseOverAnimation( QString::null );
00606                     }
00607                 }
00608             } // animations
00609             // Only do the normal "mouseover" effect if no animation is in use
00610             if (d->pActiveItem && !d->pActiveItem->isAnimated())
00611             {
00612                 d->pActiveItem->setActive( true );
00613             }
00614         }
00615         else // No change in current item
00616         {
00617             // No effect. If we want to underline on hover, we should
00618             // force the IVI to repaint here, though!
00619             d->pActiveItem = 0L;
00620             d->pFileTipTimer->stop();
00621             d->pFileTip->setItem( 0L );
00622         }
00623     } // bMousePressed
00624     else
00625     {
00626         // All features disabled during mouse clicking, e.g. rectangular
00627         // selection
00628         d->pActiveItem = 0L;
00629         d->pFileTipTimer->stop();
00630         d->pFileTip->setItem( 0L );
00631     }
00632 
00633     // ## shouldn't this be disabled during rectangular selection too ?
00634     if (d->bSoundPreviews && d->pSoundPlayer &&
00635         d->pSoundPlayer->mimeTypes().contains(
00636             item->item()->mimetype())
00637         && KGlobalSettings::showFilePreview(item->item()->url())
00638         && topLevelWidget() == kapp->activeWindow())
00639     {
00640         d->pSoundItem = item;
00641         d->bSoundItemClicked = false;
00642         if (!d->pSoundTimer)
00643         {
00644             d->pSoundTimer = new QTimer(this);
00645             connect(d->pSoundTimer, SIGNAL(timeout()), SLOT(slotStartSoundPreview()));
00646         }
00647         if (d->pSoundTimer->isActive())
00648             d->pSoundTimer->stop();
00649         d->pSoundTimer->start(500, true);
00650     }
00651     else
00652     {
00653         if (d->pSoundPlayer)
00654             d->pSoundPlayer->stop();
00655         d->pSoundItem = 0;
00656         if (d->pSoundTimer && d->pSoundTimer->isActive())
00657             d->pSoundTimer->stop();
00658     }
00659 }
00660 
00661 void KonqIconViewWidget::slotOnViewport()
00662 {
00663     d->pFileTipTimer->stop();
00664     d->pFileTip->setItem( 0L );
00665 
00666     if (d->pSoundPlayer)
00667       d->pSoundPlayer->stop();
00668     d->pSoundItem = 0;
00669     if (d->pSoundTimer && d->pSoundTimer->isActive())
00670       d->pSoundTimer->stop();
00671 
00672     if (d->pActiveItem == 0L)
00673         return;
00674 
00675     if ( d->doAnimations && d->m_movie && d->pActiveItem->isAnimated() )
00676     {
00677         d->pActiveItem->setAnimated( false );
00678 #if 0
00679         // Aborting before the end of the animation ?
00680         if (d->m_movie->running()) {
00681             d->m_movie->pause();
00682             d->m_movieBlocked++;
00683             kdDebug(1203) << "on viewport, blocking" << endl;
00684             QTimer::singleShot(300, this, SLOT(slotReenableAnimation()));
00685         }
00686 #endif
00687         d->pActiveItem->refreshIcon( true );
00688         Q_ASSERT( d->pActiveItem->state() == KIcon::DefaultState );
00689         //delete d->m_movie;
00690         //d->m_movie = 0L;
00691         // TODO a timer to delete the movie after some time if unused?
00692     }
00693     else
00694     {
00695         d->pActiveItem->setActive( false );
00696     }
00697     d->pActiveItem = 0L;
00698 }
00699 
00700 void KonqIconViewWidget::slotStartSoundPreview()
00701 {
00702   if (!d->pSoundItem || d->bSoundItemClicked)
00703     return;
00704 
00705   d->pSoundPlayer->play(d->pSoundItem->item()->url().url());
00706 }
00707 
00708 
00709 void KonqIconViewWidget::slotPreview(const KFileItem *item, const QPixmap &pix)
00710 {
00711     // ### slow. Idea: move KonqKfmIconView's m_itemDict into this class
00712     for (QIconViewItem *it = firstItem(); it; it = it->nextItem())
00713     {
00714         KFileIVI* current = static_cast<KFileIVI *>(it);
00715         if (current->item() == item)
00716         {
00717             if (item->overlays() & KIcon::HiddenOverlay) {
00718                 QPixmap p(pix);
00719 
00720                 KIconEffect::semiTransparent(p);
00721                 current->setThumbnailPixmap(p);
00722             } else {
00723                 current->setThumbnailPixmap(pix);
00724             }
00725             break;
00726         }
00727     }
00728 }
00729 
00730 void KonqIconViewWidget::slotPreviewResult()
00731 {
00732     d->pPreviewJob = 0;
00733     emit imagePreviewFinished();
00734 }
00735 
00736 void KonqIconViewWidget::slotStartTooltip()
00737 {
00738     if ( d->pActiveItem )
00739         d->pFileTip->setItem( d->pActiveItem );
00740 }
00741 
00742 void KonqIconViewWidget::slotToolTipPreview(const KFileItem* item, const QPixmap &pix)
00743 {
00744     d->pFileTip->gotPreview( item, pix );
00745 }
00746 
00747 void KonqIconViewWidget::slotToolTipPreviewResult()
00748 {
00749     d->pFileTip->gotPreviewResult();
00750 }
00751 
00752 void KonqIconViewWidget::slotMovieUpdate( const QRect& rect )
00753 {
00754     //kdDebug(1203) << "KonqIconViewWidget::slotMovieUpdate " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << endl;
00755     Q_ASSERT( d );
00756     Q_ASSERT( d->m_movie );
00757     // seems stopAnimation triggers one last update
00758     if ( d->pActiveItem && d->m_movie && d->pActiveItem->isAnimated() ) {
00759         const QPixmap &frame = d->m_movie->framePixmap();
00760         // This can happen if the icon was scaled to the desired size, so KIconLoader
00761         // will happily return a movie with different dimensions than the icon
00762         int iconSize=d->pActiveItem->iconSize();
00763         if (iconSize==0) iconSize = KGlobal::iconLoader()->currentSize( KIcon::Desktop );
00764         if ( frame.width() != iconSize || frame.height() != iconSize ) {
00765             d->pActiveItem->setAnimated( false );
00766             d->m_movie->pause();
00767             // No movie available, remember it
00768             d->pActiveItem->setMouseOverAnimation( QString::null );
00769             d->pActiveItem->setActive( true );
00770             return;
00771         }
00772         d->pActiveItem->setPixmapDirect( frame, false, false /*no redraw*/ );
00773         QRect pixRect = d->pActiveItem->pixmapRect(false);
00774         repaintContents( pixRect.x() + rect.x(), pixRect.y() + rect.y(), rect.width(), rect.height(), false );
00775     }
00776 }
00777 
00778 void KonqIconViewWidget::slotMovieStatus( int status )
00779 {
00780     if ( status < 0 ) {
00781         // Error playing the MNG -> forget about it and do normal iconeffect
00782         if ( d->pActiveItem && d->pActiveItem->isAnimated() ) {
00783             d->pActiveItem->setAnimated( false );
00784             d->pActiveItem->setMouseOverAnimation( QString::null );
00785             d->pActiveItem->setActive( true );
00786         }
00787     }
00788 }
00789 
00790 void KonqIconViewWidget::slotReenableAnimation()
00791 {
00792     if (!--d->m_movieBlocked) {
00793         if ( d->pActiveItem && d->m_movie && d->m_movie->paused()) {
00794             kdDebug(1203) << "reenabled animation" << endl;
00795             d->m_movie->restart();
00796             d->m_movie->unpause();
00797         }
00798     }
00799 }
00800 
00801 void KonqIconViewWidget::clear()
00802 {
00803     d->pFileTipTimer->stop();
00804     d->pFileTip->setItem( 0L );
00805     stopImagePreview(); // Just in case
00806     KIconView::clear();
00807     d->pActiveItem = 0L;
00808 }
00809 
00810 void KonqIconViewWidget::takeItem( QIconViewItem *item )
00811 {
00812     if ( d->pActiveItem == static_cast<KFileIVI *>(item) )
00813     {
00814         d->pFileTipTimer->stop();
00815         d->pFileTip->setItem( 0L );
00816         d->pActiveItem = 0L;
00817     }
00818 
00819     if ( d->pPreviewJob )
00820       d->pPreviewJob->removeItem( static_cast<KFileIVI *>(item)->item() );
00821 
00822     KIconView::takeItem( item );
00823 }
00824 
00825 // Currently unused - remove in KDE 4.0
00826 void KonqIconViewWidget::setThumbnailPixmap( KFileIVI * item, const QPixmap & pixmap )
00827 {
00828     if ( item )
00829     {
00830         if ( d->pActiveItem == item )
00831         {
00832             d->pFileTipTimer->stop();
00833             d->pFileTip->setItem( 0L );
00834             d->pActiveItem = 0L;
00835         }
00836         item->setThumbnailPixmap( pixmap );
00837         if ( m_bSetGridX &&  item->width() > gridX() )
00838         {
00839           setGridX( item->width() );
00840           if (autoArrange())
00841             arrangeItemsInGrid();
00842         }
00843     }
00844 }
00845 
00846 bool KonqIconViewWidget::initConfig( bool bInit )
00847 {
00848     bool fontChanged = false;
00849     m_pSettings = KonqFMSettings::settings();
00850 
00851     // Color settings
00852     QColor normalTextColor       = m_pSettings->normalTextColor();
00853     setItemColor( normalTextColor );
00854 
00855     if (m_bDesktop)
00856     {
00857       QColor itemTextBg = m_pSettings->itemTextBackground();
00858       if ( itemTextBg.isValid() )
00859           setItemTextBackground( itemTextBg );
00860       else
00861           setItemTextBackground( NoBrush );
00862     }
00863 
00864 
00865     d->pFileTip->setOptions(m_pSettings->showFileTips() && QToolTip::isGloballyEnabled(),
00866                             m_pSettings->showPreviewsInFileTips(),
00867                             m_pSettings->numFileTips());
00868 
00869     // Font settings
00870     QFont font( m_pSettings->standardFont() );
00871     if (!m_bDesktop)
00872         font.setUnderline( m_pSettings->underlineLink() );
00873 
00874     if ( font != KonqIconViewWidget::font() )
00875     {
00876         setFont( font );
00877         if (!bInit)
00878         {
00879             // QIconView doesn't do it by default... but if the font is made much
00880             // bigger, we really need to give more space between the icons
00881             fontChanged = true;
00882         }
00883     }
00884 
00885     setIconTextHeight( m_bDesktop ? 2 : m_pSettings->iconTextHeight() );
00886 
00887     // Update icons if settings for preview icon size have changed
00888     if ( d->bBoostPreview != boostPreview() )
00889         setIcons(m_size);
00890     else if (!bInit)
00891         updateContents();
00892     return fontChanged;
00893 }
00894 
00895 bool KonqIconViewWidget::boostPreview() const
00896 {
00897     if ( m_bDesktop ) {
00898         int size = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
00899         int mini = spacing() + QMAX( 0, largestPreviewIconSize( size ) - size );
00900         if ( d->desktopGridSpacing.x() < mini ||
00901              d->desktopGridSpacing.y() < mini )
00902             return false;
00903     }
00904 
00905     KConfigGroup group( KGlobal::config(), "PreviewSettings" );
00906     return group.readBoolEntry( "BoostSize", false );
00907 }
00908 
00909 void KonqIconViewWidget::disableSoundPreviews()
00910 {
00911     d->bSoundPreviews = false;
00912 
00913     if (d->pSoundPlayer)
00914       d->pSoundPlayer->stop();
00915     d->pSoundItem = 0;
00916     if (d->pSoundTimer && d->pSoundTimer->isActive())
00917       d->pSoundTimer->stop();
00918 }
00919 
00920 void KonqIconViewWidget::setIcons( int size, const QStringList& stopImagePreviewFor )
00921 {
00922     // size has changed?
00923     bool sizeChanged = (m_size != size);
00924     int oldGridX = gridX();
00925     m_size = size;
00926     
00927     // boost preview option has changed?
00928     bool boost = boostPreview();
00929     bool previewSizeChanged = ( d->bBoostPreview != boost );
00930     d->bBoostPreview = boost;
00931     
00932     if ( sizeChanged || previewSizeChanged )
00933     {
00934         int realSize = size ? size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
00935         setSpacing( ( realSize > KIcon::SizeSmall ) ? 5 : 0 );
00936     }
00937 
00938     if ( sizeChanged || previewSizeChanged || !stopImagePreviewFor.isEmpty() )
00939     {
00940         calculateGridX();
00941     }
00942     bool stopAll = !stopImagePreviewFor.isEmpty() && stopImagePreviewFor.first() == "*";
00943 
00944     // Disable repaints that can be triggered by ivi->setIcon(). Since icons are
00945     // resized in-place, if the icon size is increasing it can happens that the right
00946     // or bottom icons exceed the size of the viewport.. here we prevent the repaint
00947     // event that will be triggered in that case.
00948     bool prevUpdatesState = viewport()->isUpdatesEnabled();
00949     viewport()->setUpdatesEnabled( false );
00950 
00951     // Do this even if size didn't change, since this is used by refreshMimeTypes...
00952     for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
00953         KFileIVI * ivi = static_cast<KFileIVI *>( it );
00954         // Set a normal icon for files that are not thumbnails, and for files
00955         // that are thumbnails but for which it should be stopped
00956         if ( !ivi->isThumbnail() ||
00957              sizeChanged ||
00958              previewSizeChanged ||
00959              stopAll ||
00960              mimeTypeMatch( ivi->item()->mimetype(), stopImagePreviewFor ) )
00961         {
00962             ivi->setIcon( size, ivi->state(), true, false );
00963         }
00964         else
00965             ivi->invalidateThumb( ivi->state(), true );
00966     }
00967 
00968     // Restore viewport update to previous state
00969     viewport()->setUpdatesEnabled( prevUpdatesState );
00970 
00971     if ( ( sizeChanged || previewSizeChanged || oldGridX != gridX() ||
00972          !stopImagePreviewFor.isEmpty() ) && autoArrange() )
00973         arrangeItemsInGrid( true ); // take new grid into account and repaint
00974     else
00975         viewport()->update(); //Repaint later..
00976 }
00977 
00978 bool KonqIconViewWidget::mimeTypeMatch( const QString& mimeType, const QStringList& mimeList ) const
00979 {
00980     for (QStringList::ConstIterator mt = mimeList.begin(); mt != mimeList.end(); ++mt)
00981     {
00982         if ( mimeType == *mt )
00983             return true;
00984         // Support for *mt == "image/*"
00985         QString tmp( mimeType );
00986         if ( (*mt).endsWith("*") && tmp.replace(QRegExp("/.*"), "/*") == (*mt) )
00987             return true;
00988     }
00989     return false;
00990 }
00991 
00992 void KonqIconViewWidget::setItemTextPos( ItemTextPos pos )
00993 {
00994     if ( m_bSetGridX )
00995     {
00996         calculateGridX();
00997         if ( itemTextPos() != pos )
00998         {
00999             if ( pos == QIconView::Right )
01000                 setGridX( gridX() + 100 );
01001             else
01002                 setGridX( gridX() - 100 );
01003         }
01004     }
01005 
01006     KIconView::setItemTextPos( pos );
01007 }
01008 
01009 void KonqIconViewWidget::gridValues( int* x, int* y, int* dx, int* dy,
01010                                      int* nx, int* ny )
01011 {
01012     int previewSize = previewIconSize( m_size );
01013     int iconSize = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
01014 
01015     // Grid size
01016     *dx = QMAX( iconSize + d->desktopGridSpacing.x(),
01017                    previewSize + spacing() );
01018     int textHeight = QMIN( iconTextHeight(), 2 ) * fontMetrics().height();
01019     *dy = textHeight + 2 +
01020         QMAX( iconSize + d->desktopGridSpacing.y(), previewSize );
01021 
01022     // Icon Area
01023     int x1, x2, y1, y2;
01024     int yOffset = QMAX( 0, *dy - ( previewSize + textHeight ) );
01025     if ( m_IconRect.isValid() ) {
01026         *x = x1 = m_IconRect.left(); x2 = m_IconRect.right();
01027         y1 = m_IconRect.top(); y2 = m_IconRect.bottom();
01028     }
01029     else {
01030         *x = x1 = 0; x2 = viewport()->width();
01031         y1 = 0; y2 = viewport()->height();
01032     }
01033     *y = y1 -= yOffset / 2;
01034     y2 -= yOffset / 2;
01035 
01036     *nx = (x2 - x1) / *dx;
01037     *ny = (y2 - y1) / *dy;
01038     // TODO: Check that items->count() <= nx * ny
01039 
01040     // Let have exactly nx columns and ny rows
01041     *dx = (x2 - x1) / *nx;
01042     *dy = (y2 - y1) / *ny;
01043     kdDebug(1203) << "dx = " << *dx << ", dy = " << *dy << "\n";
01044 }
01045 
01046 void KonqIconViewWidget::calculateGridX()
01047 {
01048     if ( m_bSetGridX )
01049         setGridX( gridXValue() );
01050 }
01051 
01052 int KonqIconViewWidget::gridXValue() const
01053 {
01054     int sz = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
01055     bool horizontal = (itemTextPos() == QIconView::Right);
01056     int newGridX = sz + (!m_bSetGridX ? d->gridXspacing : 50) + ( horizontal ? 100 : 0);
01057     newGridX = QMAX( newGridX, (horizontal ? 2 : 1) * previewIconSize( sz ) + 13 );
01058     //kdDebug(1203) << "gridXValue: " << newGridX << " sz=" << sz << endl;
01059     return newGridX;
01060 }
01061 
01062 void KonqIconViewWidget::refreshMimeTypes()
01063 {
01064     updatePreviewMimeTypes();
01065     for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
01066         (static_cast<KFileIVI *>( it ))->item()->refreshMimeType();
01067     setIcons( m_size );
01068 }
01069 
01070 void KonqIconViewWidget::setURL( const KURL &kurl )
01071 {
01072     stopImagePreview();
01073     m_url = kurl;
01074 
01075     d->pFileTip->setPreview( KGlobalSettings::showFilePreview(m_url) );
01076 
01077     if ( m_url.isLocalFile() )
01078         m_dotDirectoryPath = m_url.path(1).append( ".directory" );
01079     else
01080         m_dotDirectoryPath = QString::null;
01081 }
01082 
01083 void KonqIconViewWidget::startImagePreview( const QStringList &, bool force )
01084 {
01085     stopImagePreview(); // just in case
01086 
01087     // Check config
01088     if ( !KGlobalSettings::showFilePreview( url() ) ) {
01089         kdDebug(1203) << "Previews disabled for protocol " << url().protocol() << endl;
01090         emit imagePreviewFinished();
01091         return;
01092     }
01093 
01094     if ((d->bSoundPreviews = d->previewSettings.contains( "audio/" )) &&
01095         !d->pSoundPlayer)
01096     {
01097       KLibFactory *factory = KLibLoader::self()->factory("konq_sound");
01098       if (factory)
01099         d->pSoundPlayer = static_cast<KonqSoundPlayer *>(
01100           factory->create(this, 0, "KonqSoundPlayer"));
01101       d->bSoundPreviews = (d->pSoundPlayer != 0L);
01102     }
01103 
01104     KFileItemList items;
01105     for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
01106         if ( force || !static_cast<KFileIVI *>( it )->hasValidThumbnail() )
01107             items.append( static_cast<KFileIVI *>( it )->item() );
01108 
01109     bool onlyAudio = true;
01110     for ( QStringList::ConstIterator it = d->previewSettings.begin(); it != d->previewSettings.end(); ++it ) {
01111         if ( (*it).startsWith( "audio/" ) )
01112             d->bSoundPreviews = true;
01113         else
01114             onlyAudio = false;
01115     }
01116 
01117     if ( items.isEmpty() || onlyAudio ) {
01118         emit imagePreviewFinished();
01119         return; // don't start the preview job if not really necessary
01120     }
01121 
01122     int iconSize = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
01123     int size;
01124 
01125     d->bBoostPreview = boostPreview();
01126     size = previewIconSize( iconSize );
01127 
01128     if ( !d->bBoostPreview )
01129          iconSize /= 2;
01130 
01131     d->pPreviewJob = KIO::filePreview( items, size, size, iconSize,
01132         m_pSettings->textPreviewIconTransparency(), true /* scale */,
01133         true /* save */, &(d->previewSettings) );
01134     connect( d->pPreviewJob, SIGNAL( gotPreview( const KFileItem *, const QPixmap & ) ),
01135              this, SLOT( slotPreview( const KFileItem *, const QPixmap & ) ) );
01136     connect( d->pPreviewJob, SIGNAL( result( KIO::Job * ) ),
01137              this, SLOT( slotPreviewResult() ) );
01138 }
01139 
01140 void KonqIconViewWidget::stopImagePreview()
01141 {
01142     if (d->pPreviewJob)
01143     {
01144         d->pPreviewJob->kill();
01145         d->pPreviewJob = 0;
01146         // Now that previews are updated in-place, calling
01147         // arrangeItemsInGrid() here is not needed anymore
01148     }
01149 }
01150 
01151 bool KonqIconViewWidget::isPreviewRunning() const
01152 {
01153     return d->pPreviewJob;
01154 }
01155 
01156 KFileItemList KonqIconViewWidget::selectedFileItems()
01157 {
01158     KFileItemList lstItems;
01159 
01160     QIconViewItem *it = firstItem();
01161     for (; it; it = it->nextItem() )
01162         if ( it->isSelected() ) {
01163             KFileItem *fItem = (static_cast<KFileIVI *>(it))->item();
01164             lstItems.append( fItem );
01165         }
01166     return lstItems;
01167 }
01168 
01169 void KonqIconViewWidget::slotDropped( QDropEvent *ev, const QValueList<QIconDragItem> & )
01170 {
01171     // Drop on background
01172     KonqOperations::doDrop( m_rootItem /* may be 0L */, url(), ev, this );
01173 }
01174 
01175 void KonqIconViewWidget::slotAboutToCreate(const QPoint &, const QValueList<KIO::CopyInfo> &)
01176 {
01177    // Do nothing :-)
01178 }
01179 
01180 void KonqIconViewWidget::drawBackground( QPainter *p, const QRect &r )
01181 {
01182     drawBackground(p, r, r.topLeft());
01183 }
01184 
01185 void KonqIconViewWidget::drawBackground( QPainter *p, const QRect &r , const QPoint &pt)
01186 {
01187     const QPixmap *pm  = backgroundPixmap();
01188     bool hasPixmap = pm && !pm->isNull();
01189     if ( !hasPixmap ) {
01190         pm = viewport()->backgroundPixmap();
01191         hasPixmap = pm && !pm->isNull();
01192     }
01193 
01194     QRect rtgt(r);
01195     rtgt.moveTopLeft(pt);
01196     if (!hasPixmap && backgroundMode() != NoBackground) {
01197         p->fillRect(rtgt, viewport()->backgroundColor());
01198         return;
01199     }
01200 
01201     if (hasPixmap) {
01202         int ax = (r.x() + contentsX() + leftMargin()) % pm->width();
01203         int ay = (r.y() + contentsY() + topMargin()) % pm->height();
01204         p->drawTiledPixmap(rtgt, *pm, QPoint(ax, ay));
01205     }
01206 }
01207 
01208 QDragObject * KonqIconViewWidget::dragObject()
01209 {
01210     if ( !currentItem() )
01211         return 0;
01212 
01213     return konqDragObject( viewport() );
01214 }
01215 
01216 KonqIconDrag * KonqIconViewWidget::konqDragObject( QWidget * dragSource )
01217 {
01218     //kdDebug(1203) << "KonqIconViewWidget::konqDragObject" << endl;
01219 
01220     QPoint offset(-10,-10);
01221     KonqIconDrag * drag = new KonqIconDrag( dragSource );
01222     QIconViewItem *primaryItem = currentItem();
01223     // Append all items to the drag object
01224     for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
01225         if ( it->isSelected() ) {
01226           if (!primaryItem)
01227              primaryItem = it;
01228           KURL url = (static_cast<KFileIVI *>(it))->item()->url();
01229           QString itemURL = KURLDrag::urlToString(url);
01230           kdDebug(1203) << "itemURL=" << itemURL << endl;
01231           QIconDragItem id;
01232           id.setData( QCString(itemURL.latin1()) );
01233           drag->append( id,
01234                         QRect( it->pixmapRect(false).topLeft() - m_mousePos - offset,
01235                                it->pixmapRect().size() ),
01236                         QRect( it->textRect(false).topLeft() - m_mousePos - offset,
01237                                it->textRect().size() ),
01238                         itemURL );
01239         }
01240     }
01241 
01242     if (primaryItem)
01243     {
01244        // Set pixmap, with the correct offset
01245        drag->setPixmap( *primaryItem->pixmap(), m_mousePos - primaryItem->pixmapRect(false).topLeft() + offset );
01246     }
01247 
01248     return drag;
01249 }
01250 
01251 void KonqIconViewWidget::contentsDragEnterEvent( QDragEnterEvent *e )
01252 {
01253     if ( e->provides( "text/uri-list" ) )
01254     {
01255         QByteArray payload = e->encodedData( "text/uri-list" );
01256         if ( !payload.size() )
01257             kdError() << "Empty data !" << endl;
01258         // Cache the URLs, since we need them every time we move over a file
01259         // (see KFileIVI)
01260         bool ok = KURLDrag::decode( e, m_lstDragURLs );
01261         if( !ok )
01262             kdError() << "Couldn't decode urls dragged !" << endl;
01263     }
01264     KIconView::contentsDragEnterEvent( e );
01265     emit dragEntered();
01266 }
01267 
01268 void KonqIconViewWidget::contentsDragLeaveEvent( QDragLeaveEvent *e )
01269 {
01270     QIconView::contentsDragLeaveEvent(e);
01271     emit dragLeft();
01272 }
01273 
01274 
01275 void KonqIconViewWidget::setItemColor( const QColor &c )
01276 {
01277     iColor = c;
01278 }
01279 
01280 QColor KonqIconViewWidget::itemColor() const
01281 {
01282     return iColor;
01283 }
01284 
01285 void KonqIconViewWidget::disableIcons( const KURL::List & lst )
01286 {
01287   for ( QIconViewItem *kit = firstItem(); kit; kit = kit->nextItem() )
01288   {
01289       bool bFound = false;
01290       // Wow. This is ugly. Matching two lists together....
01291       // Some sorting to optimise this would be a good idea ?
01292       for (KURL::List::ConstIterator it = lst.begin(); !bFound && it != lst.end(); ++it)
01293       {
01294           if ( static_cast<KFileIVI *>( kit )->item()->url() == *it )
01295           {
01296               bFound = true;
01297               // maybe remove "it" from lst here ?
01298           }
01299       }
01300       static_cast<KFileIVI *>( kit )->setDisabled( bFound );
01301   }
01302 }
01303 
01304 void KonqIconViewWidget::slotSelectionChanged()
01305 {
01306     // This code is very related to ListViewBrowserExtension::updateActions
01307     int canCopy = 0;
01308     int canDel = 0;
01309     bool bInTrash = false;
01310     int iCount = 0;
01311 
01312     for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
01313     {
01314         if ( it->isSelected() )
01315         {
01316             iCount++;
01317             canCopy++;
01318 
01319             KURL url = ( static_cast<KFileIVI *>( it ) )->item()->url();
01320             if ( url.directory(false) == KGlobalSettings::trashPath() )
01321                 bInTrash = true;
01322             if ( KProtocolInfo::supportsDeleting( url ) )
01323                 canDel++;
01324         }
01325     }
01326 
01327     emit enableAction( "cut", canDel > 0 );
01328     emit enableAction( "copy", canCopy > 0 );
01329     emit enableAction( "trash", canDel > 0 && !bInTrash && m_url.isLocalFile() );
01330     emit enableAction( "del", canDel > 0 );
01331     emit enableAction( "properties", iCount > 0 && KPropertiesDialog::canDisplay( selectedFileItems() ) );
01332     emit enableAction( "editMimeType", ( iCount == 1 ) );
01333     emit enableAction( "rename", ( iCount == 1 ) && !bInTrash );
01334 }
01335 
01336 void KonqIconViewWidget::renameCurrentItem()
01337 {
01338     if ( currentItem() )
01339         currentItem()->rename();
01340 }
01341 
01342 void KonqIconViewWidget::renameSelectedItem()
01343 {
01344     kdDebug(1203) << " -- KonqIconViewWidget::renameSelectedItem() -- " << endl;
01345     QIconViewItem * item = 0L;
01346     QIconViewItem *it = firstItem();
01347     for (; it; it = it->nextItem() )
01348         if ( it->isSelected() && !item )
01349         {
01350             item = it;
01351             break;
01352         }
01353     if (!item)
01354     {
01355         Q_ASSERT(item);
01356         return;
01357     }
01358     item->rename();
01359 }
01360 
01361 void KonqIconViewWidget::cutSelection()
01362 {
01363     kdDebug(1203) << " -- KonqIconViewWidget::cutSelection() -- " << endl;
01364     KonqIconDrag * obj = konqDragObject( /* no parent ! */ );
01365     obj->setMoveSelection( true );
01366     QApplication::clipboard()->setData( obj );
01367 }
01368 
01369 void KonqIconViewWidget::copySelection()
01370 {
01371     kdDebug(1203) << " -- KonqIconViewWidget::copySelection() -- " << endl;
01372     KonqIconDrag * obj = konqDragObject( /* no parent ! */ );
01373     QApplication::clipboard()->setData( obj );
01374 }
01375 
01376 void KonqIconViewWidget::pasteSelection()
01377 {
01378     paste( url() );
01379 }
01380 
01381 void KonqIconViewWidget::paste( const KURL &url )
01382 {
01383     KonqOperations::doPaste( this, url );
01384 }
01385 
01386 KURL::List KonqIconViewWidget::selectedUrls()
01387 {
01388     KURL::List lstURLs;
01389 
01390     for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
01391         if ( it->isSelected() )
01392             lstURLs.append( (static_cast<KFileIVI *>( it ))->item()->url() );
01393     return lstURLs;
01394 }
01395 
01396 QRect KonqIconViewWidget::iconArea() const
01397 {
01398     return m_IconRect;
01399 }
01400 
01401 void KonqIconViewWidget::setIconArea(const QRect &rect)
01402 {
01403     m_IconRect = rect;
01404 }
01405 
01406 int KonqIconViewWidget::lineupMode() const
01407 {
01408     return m_LineupMode;
01409 }
01410 
01411 void KonqIconViewWidget::setLineupMode(int mode)
01412 {
01413     m_LineupMode = mode;
01414 }
01415 
01416 bool KonqIconViewWidget::sortDirectoriesFirst() const
01417 {
01418   return m_bSortDirsFirst;
01419 }
01420 
01421 void KonqIconViewWidget::setSortDirectoriesFirst( bool b )
01422 {
01423   m_bSortDirsFirst = b;
01424 }
01425 
01426 void KonqIconViewWidget::contentsMouseMoveEvent( QMouseEvent *e )
01427 {
01428     if ( (d->pSoundPlayer && d->pSoundPlayer->isPlaying()) || (d->pSoundTimer && d->pSoundTimer->isActive()))
01429     {
01430         // The following call is SO expensive (the ::widgetAt call eats up to 80%
01431         // of the mouse move cpucycles!), so it's mandatory to place that function 
01432         // under strict checks, such as d->pSoundPlayer->isPlaying()
01433         if ( QApplication::widgetAt( QCursor::pos() ) != topLevelWidget() )
01434         {
01435             if (d->pSoundPlayer)
01436                 d->pSoundPlayer->stop();
01437             d->pSoundItem = 0;
01438             if (d->pSoundTimer && d->pSoundTimer->isActive())
01439                 d->pSoundTimer->stop();
01440         }
01441     }
01442     d->renameItem= false;
01443     QIconView::contentsMouseMoveEvent( e );
01444 }
01445 
01446 void KonqIconViewWidget::contentsDropEvent( QDropEvent * ev )
01447 {
01448   QIconViewItem *i = findItem( ev->pos() );
01449   // Short-circuit QIconView if Ctrl is pressed, so that it's possible
01450   // to drop a file into its own parent widget to copy it.
01451   if ( !i && (ev->action() == QDropEvent::Copy || ev->action() == QDropEvent::Link)
01452           && ev->source() && ev->source() == viewport())
01453   {
01454     // First we need to call QIconView though, to clear the drag shape
01455     bool bMovable = itemsMovable();
01456     setItemsMovable(false); // hack ? call it what you want :-)
01457     KIconView::contentsDropEvent( ev );
01458     setItemsMovable(bMovable);
01459 
01460     QValueList<QIconDragItem> lst;
01461     slotDropped(ev, lst);
01462   }
01463   else
01464   {
01465     KIconView::contentsDropEvent( ev );
01466     emit dropped(); // What is this for ? (David)
01467   }
01468   // Don't do this here, it's too early !
01469   // slotSaveIconPositions();
01470   // If we want to save after the new file gets listed, though,
01471   // we could reimplement contentsDropEvent in KDIconView and set m_bNeedSave. Bah.
01472 
01473   // This signal is sent last because we need to ensure it is
01474   // taken in account when all the slots triggered by the dropped() signal
01475   // are executed. This way we know that the Drag and Drop is truely finished
01476   emit dragFinished();
01477 }
01478 
01479 void KonqIconViewWidget::doubleClickTimeout()
01480 {
01481     d->renameItem= true;
01482     mousePressChangeValue();
01483     if ( d->releaseMouseEvent )
01484     {
01485         QMouseEvent e( QEvent::MouseButtonPress,d->mousePos , 1, d->mouseState);
01486         QIconViewItem* item = findItem( e.pos() );
01487         KURL url;
01488         if ( item )
01489         {
01490             url= ( static_cast<KFileIVI *>( item ) )->item()->url();
01491             bool brenameTrash =false;
01492             if ( url.isLocalFile() && (url.directory(false) == KGlobalSettings::trashPath() || url.path(1).startsWith(KGlobalSettings::trashPath())))
01493                 brenameTrash = true;
01494 
01495             if ( url.isLocalFile() && !brenameTrash && d->renameItem && m_pSettings->renameIconDirectly() && e.button() == LeftButton && item->textRect( false ).contains(e.pos()))
01496             {
01497                 if( d->pActivateDoubleClick->isActive () )
01498                     d->pActivateDoubleClick->stop();
01499                 item->rename();
01500                 m_bMousePressed = false;
01501             }
01502         }
01503     }
01504     else
01505     {
01506         QMouseEvent e( QEvent::MouseMove,d->mousePos , 1, d->mouseState);
01507         KIconView::contentsMousePressEvent( &e );
01508     }
01509     if( d->pActivateDoubleClick->isActive() )
01510         d->pActivateDoubleClick->stop();
01511 
01512     d->releaseMouseEvent = false;
01513     d->renameItem= false;
01514 }
01515 
01516 void KonqIconViewWidget::wheelEvent(QWheelEvent* e)
01517 {
01518     if (e->state() == ControlButton)
01519     {
01520         if (e->delta() >= 0)
01521         {
01522             emit incIconSize();
01523         }
01524         else
01525         {
01526             emit decIconSize();
01527         }
01528         e->accept();
01529         return;
01530     }
01531 
01532     KIconView::wheelEvent(e);
01533 }
01534 
01535 void KonqIconViewWidget::mousePressChangeValue()
01536 {
01537   //kdDebug(1203) << "KonqIconViewWidget::contentsMousePressEvent" << endl;
01538   m_bMousePressed = true;
01539   if (d->pSoundPlayer)
01540     d->pSoundPlayer->stop();
01541   d->bSoundItemClicked = true;
01542   d->firstClick = false;
01543 }
01544 
01545 void KonqIconViewWidget::contentsMousePressEvent( QMouseEvent *e )
01546 {
01547     if(d->pActivateDoubleClick && d->pActivateDoubleClick->isActive ())
01548         d->pActivateDoubleClick->stop();
01549      QIconViewItem* item = findItem( e->pos() );
01550      m_mousePos = e->pos();
01551      KURL url;
01552      if ( item )
01553      {
01554          url = ( static_cast<KFileIVI *>( item ) )->item()->url();
01555          bool brenameTrash =false;
01556          if ( url.isLocalFile() && (url.directory(false) == KGlobalSettings::trashPath() || url.path(1).startsWith(KGlobalSettings::trashPath())))
01557              brenameTrash = true;
01558          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))
01559          {
01560              d->firstClick = true;
01561              d->mousePos = e->pos();
01562              d->mouseState = e->state();
01563              if (!d->pActivateDoubleClick)
01564              {
01565                  d->pActivateDoubleClick = new QTimer(this);
01566                  connect(d->pActivateDoubleClick, SIGNAL(timeout()), this, SLOT(doubleClickTimeout()));
01567              }
01568              if( d->pActivateDoubleClick->isActive () )
01569                  d->pActivateDoubleClick->stop();
01570              else
01571                  d->pActivateDoubleClick->start(QApplication::doubleClickInterval());
01572              d->releaseMouseEvent = false;
01573              return;
01574          }
01575          else
01576              d->renameItem= false;
01577      }
01578      else
01579          d->renameItem= false;
01580     mousePressChangeValue();
01581     if(d->pActivateDoubleClick && d->pActivateDoubleClick->isActive())
01582         d->pActivateDoubleClick->stop();
01583     KIconView::contentsMousePressEvent( e );
01584 
01585 }
01586 
01587 void KonqIconViewWidget::contentsMouseReleaseEvent( QMouseEvent *e )
01588 {
01589     KIconView::contentsMouseReleaseEvent( e );
01590     if(d->releaseMouseEvent && d->pActivateDoubleClick && d->pActivateDoubleClick->isActive ())
01591         d->pActivateDoubleClick->stop();
01592     slotSelectionChanged();
01593     d->releaseMouseEvent = true;
01594     m_bMousePressed = false;
01595 }
01596 
01597 void KonqIconViewWidget::slotSaveIconPositions()
01598 {
01599   // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
01600   // This code is currently not used but left in for compatibility reasons.
01601   // It can be removed in KDE 4.0
01602   // Saving of desktop icon positions is now done in KDIconView::saveIconPositions()
01603   // in kdebase/kdesktop/kdiconview.cc
01604   // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
01605 
01606   if ( m_dotDirectoryPath.isEmpty() )
01607     return;
01608   if ( !m_bDesktop )
01609     return; // Currently not available in Konqueror
01610   kdDebug(1214) << "KonqIconViewWidget::slotSaveIconPositions" << endl;
01611   KSimpleConfig dotDirectory( m_dotDirectoryPath );
01612   QIconViewItem *it = firstItem();
01613   if ( !it )
01614     return; // No more icons. Maybe we're closing and they've been removed already
01615   while ( it )
01616   {
01617     KFileIVI *ivi = static_cast<KFileIVI *>( it );
01618     KFileItem *item = ivi->item();
01619 
01620     dotDirectory.setGroup( QString( m_iconPositionGroupPrefix ).append( item->url().fileName() ) );
01621     kdDebug(1214) << "KonqIconViewWidget::slotSaveIconPositions " << item->url().fileName() << " " << it->x() << " " << it->y() << endl;
01622     dotDirectory.writeEntry( QString( "X %1" ).arg( width() ), it->x() );
01623     dotDirectory.writeEntry( QString( "Y %1" ).arg( height() ), it->y() );
01624     dotDirectory.writeEntry( "Exists", true );
01625 
01626     it = it->nextItem();
01627   }
01628 
01629   QStringList groups = dotDirectory.groupList();
01630   QStringList::ConstIterator gIt = groups.begin();
01631   QStringList::ConstIterator gEnd = groups.end();
01632   for (; gIt != gEnd; ++gIt )
01633     if ( (*gIt).left( m_iconPositionGroupPrefix.length() ) == m_iconPositionGroupPrefix )
01634     {
01635       dotDirectory.setGroup( *gIt );
01636       if ( dotDirectory.hasKey( "Exists" ) )
01637         dotDirectory.deleteEntry( "Exists", false );
01638       else
01639       {
01640         kdDebug(1214) << "KonqIconViewWidget::slotSaveIconPositions deleting group " << *gIt << endl;
01641         dotDirectory.deleteGroup( *gIt );
01642       }
01643     }
01644 
01645   dotDirectory.sync();
01646 
01647   // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
01648   // This code is currently not used but left in for compatibility reasons.
01649   // It can be removed in KDE 4.0
01650   // Saving of desktop icon positions is now done in KDIconView::saveIconPositions()
01651   // in kdebase/kdesktop/kdiconview.cc
01652   // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
01653 }
01654 
01655 // Adapted version of QIconView::insertInGrid, that works relative to
01656 // m_IconRect, instead of the entire viewport.
01657 
01658 void KonqIconViewWidget::insertInGrid(QIconViewItem *item)
01659 {
01660     if (0L == item)
01661         return;
01662 
01663     if (!m_IconRect.isValid())
01664     {
01665         QIconView::insertInGrid(item);
01666         return;
01667     }
01668 
01669     QRegion r(m_IconRect);
01670     QIconViewItem *i = firstItem();
01671     int y = -1;
01672     for (; i; i = i->nextItem() )
01673     {
01674         r = r.subtract(i->rect());
01675         y = QMAX(y, i->y() + i->height());
01676     }
01677 
01678     QMemArray<QRect> rects = r.rects();
01679     QMemArray<QRect>::Iterator it = rects.begin();
01680     bool foundPlace = FALSE;
01681     for (; it != rects.end(); ++it)
01682     {
01683         QRect rect = *it;
01684         if (rect.width() >= item->width() && rect.height() >= item->height())
01685         {
01686             int sx = 0, sy = 0;
01687             if (rect.width() >= item->width() + spacing())
01688                 sx = spacing();
01689             if (rect.height() >= item->height() + spacing())
01690                 sy = spacing();
01691             item->move(rect.x() + sx, rect.y() + sy);
01692             foundPlace = true;
01693             break;
01694         }
01695     }
01696 
01697     if (!foundPlace)
01698         item->move(m_IconRect.topLeft());
01699 
01700     //item->dirty = false;
01701     return;
01702 }
01703 
01704 
01705 /*
01706  * The algorithm used for lineing up the icons could be called
01707  * "beating flat the icon field". Imagine the icon field to be some height
01708  * field on a regular grid, with the height being the number of icons in
01709  * each grid element. Now imagine slamming on the field with a shovel or
01710  * some other flat surface. The high peaks will be flattened and spread out
01711  * over their adjacent areas. This is basically what the algorithm tries to
01712  * simulate.
01713  *
01714  * First, the icons are binned to a grid of the desired size. If all bins
01715  * are containing at most one icon, we're done, of course. We just have to
01716  * move all icons to the center of each grid element.
01717  * For each bin which has more than one icon in it, we calculate 4
01718  * "friction coefficients", one for each cardinal direction. The friction
01719  * coefficient of a direction is the number of icons adjacent in that
01720  * direction. The idea is that this number is somewhat a measure in which
01721  * direction the icons should flow: icons flow in the direction of lowest
01722  * friction coefficient. We move a maximum of one icon per bin and loop over
01723  * all bins. This procedure is repeated some maximum number of times or until
01724  * no icons are moved anymore.
01725  *
01726  * I don't know if this algorithm is good or bad, I don't even know if it will
01727  * work all the time. It seems a correct thing to do, however, and it seems to
01728  * work particularly well. In any case, the number of runs is limited so there
01729  * can be no races.
01730  */
01731 
01732 void KonqIconViewWidget::lineupIcons()
01733 {
01734     if ( !firstItem() ) {
01735         kdDebug(1203) << "No icons at all ?\n";
01736         return;
01737     }
01738 
01739     // Make a list of items
01740     QValueList<QIconViewItem*> items;
01741     for ( QIconViewItem* item = firstItem(); item; item = item->nextItem() )
01742         items.append(item);
01743 
01744     int iconSize = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
01745 
01746     // Create a grid of (ny x nx) bins.
01747     int x0, y0, dx, dy, nx, ny;
01748     gridValues( &x0, &y0, &dx, &dy, &nx, &ny );
01749     typedef QValueList<QIconViewItem*> Bin;
01750     Bin* bins[nx][ny];
01751     int i;
01752     int j;
01753     for ( i = 0; i < nx ; i++ ) {
01754         for ( j = 0; j < ny; j++ )
01755             bins[i][j] = 0L;
01756     }
01757 
01758     // Insert items into grid
01759     int textHeight = QMIN( iconTextHeight(), 2 ) * fontMetrics().height();
01760     QValueList<QIconViewItem*>::Iterator it;
01761     for ( it = items.begin(); it != items.end(); it++ ) {
01762         QIconViewItem* item = *it;
01763         int x = item->x() + item->width() / 2 - x0;
01764         int y = item->pixmapRect( false ).bottom() - iconSize / 2
01765                 - ( dy - ( iconSize + textHeight ) ) / 2 - y0;
01766         int posX = QMIN( nx-1, QMAX( 0, x / dx ) );
01767         int posY = QMIN( ny-1, QMAX( 0, y / dy ) );
01768 
01769         if ( !bins[posX][posY] )
01770             bins[posX][posY] = new Bin;
01771         bins[posX][posY]->prepend( item );
01772     }
01773 
01774     // The shuffle code
01775     int n, k;
01776     const int infinity = 10000;
01777     int nmoves = 1;
01778     for ( n = 0; n < 30 && nmoves > 0; n++ ) {
01779         nmoves = 0;
01780         for ( i = 0; i < nx; i++ ) {
01781             for ( j = 0; j < ny; j++ ) {
01782                 if ( !bins[i][j] || ( bins[i][j]->count() <= 1 ) )
01783                     continue;
01784 
01785                 // Calculate the 4 "friction coefficients".
01786                 int tf = 0, bf = 0, lf = 0, rf = 0;
01787                 for ( k = j-1; k >= 0 && bins[i][k] && bins[i][k]->count(); k-- )
01788                     tf += bins[i][k]->count();
01789                 if ( k == -1 )
01790                     tf += infinity;
01791 
01792                 for ( k = j+1; k < ny && bins[i][k] && bins[i][k]->count(); k++ )
01793                     bf += bins[i][k]->count();
01794                 if ( k == ny )
01795                     bf += infinity;
01796 
01797                 for ( k = i-1; k >= 0 && bins[k][j] && bins[k][j]->count(); k-- )
01798                     lf += bins[k][j]->count();
01799                 if ( k == -1 )
01800                     lf += infinity;
01801 
01802                 for ( k = i+1; k < nx && bins[k][j] && bins[k][j]->count(); k++ )
01803                     rf += bins[k][j]->count();
01804                 if ( k == nx )
01805                     rf += infinity;
01806 
01807                 // If we are stuck between walls, continue
01808                 if ( tf >= infinity && bf >= infinity &&
01809                      lf >= infinity && rf >= infinity )
01810                     continue;
01811 
01812                 // Is there a preferred lineup direction?
01813                 if ( m_LineupMode == LineupHorizontal ) {
01814                     tf += infinity;
01815                     bf += infinity;
01816                 }
01817                 else if ( m_LineupMode == LineupVertical ) {
01818                     lf += infinity;
01819                     rf += infinity;
01820                 }
01821 
01822                 // Move one item in the direction of the least friction
01823                 QIconViewItem* movedItem;
01824                 Bin* items = bins[i][j];
01825 
01826                 int mini = QMIN( QMIN( tf, bf ), QMIN( lf, rf ) );
01827                 if ( tf == mini ) {
01828                     // move top item in (i,j) to (i,j-1)
01829                     Bin::iterator it = items->begin();
01830                     movedItem = *it;
01831                     for ( ++it; it != items->end(); ++it ) {
01832                         if ( (*it)->y() < movedItem->y() )
01833                             movedItem = *it;
01834                     }
01835                     items->remove( movedItem );
01836                     if ( !bins[i][j-1] )
01837                         bins[i][j-1] = new Bin;
01838                     bins[i][j-1]->prepend( movedItem );
01839                 }
01840                 else if ( bf ==mini ) {
01841                     // move bottom item in (i,j) to (i,j+1)
01842                     Bin::iterator it = items->begin();
01843                     movedItem = *it;
01844                     for ( ++it; it != items->end(); ++it ) {
01845                         if ( (*it)->y() > movedItem->y() )
01846                             movedItem = *it;
01847                     }
01848                     items->remove( movedItem );
01849                     if ( !bins[i][j+1] )
01850                         bins[i][j+1] = new Bin;
01851                     bins[i][j+1]->prepend( movedItem );
01852                 }
01853                 else if ( lf == mini )
01854                 {
01855                     // move left item in (i,j) to (i-1,j)
01856                     Bin::iterator it = items->begin();
01857                     movedItem = *it;
01858                     for ( ++it; it != items->end(); ++it ) {
01859                         if ( (*it)->x() < movedItem->x() )
01860                             movedItem = *it;
01861                     }
01862                     items->remove( movedItem );
01863                     if ( !bins[i-1][j] )
01864                         bins[i-1][j] = new Bin;
01865                     bins[i-1][j]->prepend( movedItem );
01866                 }
01867                 else {
01868                     // move right item in (i,j) to (i+1,j)
01869                     Bin::iterator it = items->begin();
01870                     movedItem = *it;
01871                     for ( ++it; it != items->end(); ++it ) {
01872                         if ( (*it)->x() > movedItem->x() )
01873                             movedItem = *it;
01874                     }
01875                     items->remove( movedItem );
01876                     if ( !bins[i+1][j] )
01877                         bins[i+1][j] = new Bin;
01878                     bins[i+1][j]->prepend( movedItem );
01879                 }
01880                 nmoves++;
01881             }
01882         }
01883     }
01884 
01885     // Perform the actual moving
01886     QRegion repaintRegion;
01887     QValueList<QIconViewItem*> movedItems;
01888 
01889     for ( i = 0; i < nx; i++ ) {
01890         for ( j = 0; j < ny; j++ ) {
01891             Bin* bin = bins[i][j];
01892             if ( !bin )
01893                 continue;
01894             if ( !bin->isEmpty() ) {
01895                 QIconViewItem* item = bin->first();
01896                 int newX = x0 + i*dx + ( dx - item->width() ) / 2;
01897                 int newY = y0 + j*dy + dy - ( item->pixmapRect().bottom() + textHeight + 2 );
01898                 if ( item->x() != newX || item->y() != newY ) {
01899                     QRect oldRect = item->rect();
01900                     movedItems.prepend( item );
01901                     item->move( newX, newY );
01902                     if ( item->rect() != oldRect )
01903                         repaintRegion = repaintRegion.unite( oldRect );
01904                 }
01905             }
01906             delete bin;
01907             bins[i][j] = 0L;
01908         }
01909     }
01910 
01911     // repaint
01912     int itemWidth = dx - 2 * spacing();
01913     if ( maxItemWidth() != itemWidth ) {
01914         setMaxItemWidth( itemWidth );
01915         setFont( font() );  // Force calcRect()
01916         updateContents();
01917     }
01918     else {
01919         // Repaint only repaintRegion...
01920         QMemArray<QRect> rects = repaintRegion.rects();
01921         for ( uint l = 0; l < rects.count(); l++ ) {
01922             kdDebug( 1203 ) << "Repainting (" << rects[l].x() << ","
01923                             << rects[l].y() << ")\n";
01924             repaintContents( rects[l], false );
01925         }
01926         // Repaint icons that were moved
01927         while ( !movedItems.isEmpty() ) {
01928             repaintItem( movedItems.first() );
01929             movedItems.remove( movedItems.first() );
01930         }
01931     }
01932 }
01933 
01934 void KonqIconViewWidget::lineupIcons( QIconView::Arrangement arrangement )
01935 {
01936     int x0, y0, dx, dy, nxmax, nymax;
01937     gridValues( &x0, &y0, &dx, &dy, &nxmax, &nymax );
01938     int textHeight = QMIN( iconTextHeight(), 2 ) * fontMetrics().height();
01939 
01940     QRegion repaintRegion;
01941     QValueList<QIconViewItem*> movedItems;
01942     int nx = 0, ny = 0;
01943 
01944     QIconViewItem* item;
01945     for ( item = firstItem(); item; item = item->nextItem() ) {
01946         int newX = x0 + nx * dx + ( dx - item->width() ) / 2;
01947         int newY = y0 + ny * dy + dy - ( item->pixmapRect().bottom() + textHeight + 2 );
01948         if ( item->x() != newX || item->y() != newY ) {
01949             QRect oldRect = item->rect();
01950             movedItems.prepend( item );
01951             item->move( newX, newY );
01952             if ( item->rect() != oldRect )
01953                 repaintRegion = repaintRegion.unite( oldRect );
01954         }
01955         if ( arrangement == QIconView::LeftToRight ) {
01956             nx++;
01957             if ( nx >= nxmax ) {
01958                 ny++;
01959                 nx = 0;
01960             }
01961         }
01962         else {
01963             ny++;
01964             if ( ny >= nymax ) {
01965                 nx++;
01966                 ny = 0;
01967             }
01968         }
01969     }
01970 
01971     // Repaint only repaintRegion...
01972     QMemArray<QRect> rects = repaintRegion.rects();
01973     for ( uint l = 0; l < rects.count(); l++ ) {
01974         kdDebug( 1203 ) << "Repainting (" << rects[l].x() << ","
01975                         << rects[l].y() << ")\n";
01976         repaintContents( rects[l], false );
01977     }
01978     // Repaint icons that were moved
01979     while ( !movedItems.isEmpty() ) {
01980         repaintItem( movedItems.first() );
01981         movedItems.remove( movedItems.first() );
01982     }
01983 }
01984 
01985 int KonqIconViewWidget::largestPreviewIconSize( int size ) const
01986 {
01987     int iconSize = size ? size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
01988 
01989     if (iconSize < 28)
01990         return 48;
01991     if (iconSize < 40)
01992         return 64;
01993     if (iconSize < 60)
01994         return 96;
01995     if (iconSize < 120)
01996         return 128;
01997 
01998     return 192;
01999 }
02000 
02001 int KonqIconViewWidget::previewIconSize( int size ) const
02002 {
02003     int iconSize = size ? size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
02004 
02005     if (!d->bBoostPreview)
02006         return iconSize;
02007 
02008     return largestPreviewIconSize( iconSize );
02009 }
02010 
02011 void KonqIconViewWidget::visualActivate(QIconViewItem * item)
02012 {
02013     // Rect of the QIconViewItem.
02014     QRect irect = item->rect();
02015 
02016     // Rect of the QIconViewItem's pixmap area.
02017     QRect rect = item->pixmapRect();
02018 
02019     // Adjust to correct position. If this isn't done, the fact that the
02020     // text may be wider than the pixmap puts us off-centre.
02021     rect.moveBy(irect.x(), irect.y());
02022 
02023     // Adjust for scrolling (David)
02024     rect.moveBy( -contentsX(), -contentsY() );
02025 
02026     KIconEffect::visualActivate(viewport(), rect);
02027 }
02028 
02029 void KonqIconViewWidget::backgroundPixmapChange( const QPixmap & )
02030 {
02031     viewport()->update();
02032 }
02033 
02034 void KonqIconViewWidget::setPreviewSettings( const QStringList& settings )
02035 {
02036     d->previewSettings = settings;
02037     updatePreviewMimeTypes();
02038     
02039     int size = m_size;
02040     m_size = -1; // little trick to force grid change in setIcons
02041     setIcons( size ); // force re-determining all icons
02042 }
02043 
02044 const QStringList& KonqIconViewWidget::previewSettings()
02045 {
02046     return d->previewSettings;
02047 }
02048 
02049 void KonqIconViewWidget::setNewURL( const QString& url )
02050 {
02051     KURL u;
02052     if ( url.startsWith( "/" ) )
02053         u.setPath( url );
02054     else
02055         u = url;
02056     setURL( u );
02057 }
02058 
02059 void KonqIconViewWidget::setCaseInsensitiveSort( bool b )
02060 {
02061     d->bCaseInsensitive = b;
02062 }
02063 
02064 bool KonqIconViewWidget::caseInsensitiveSort() const
02065 {
02066     return d->bCaseInsensitive;
02067 }
02068 
02069 bool KonqIconViewWidget::canPreview( KFileItem* item )
02070 {
02071     if ( !KGlobalSettings::showFilePreview( url() ) )
02072         return false;
02073 
02074     if ( d->pPreviewMimeTypes == 0L )
02075         updatePreviewMimeTypes();
02076 
02077     return mimeTypeMatch( item->mimetype(), *( d->pPreviewMimeTypes ) );
02078 }
02079 
02080 void KonqIconViewWidget::updatePreviewMimeTypes()
02081 {
02082     if ( d->pPreviewMimeTypes == 0L )
02083         d->pPreviewMimeTypes = new QStringList;
02084     else
02085         d->pPreviewMimeTypes->clear();
02086 
02087     // Load the list of plugins to determine which mimetypes are supported
02088     KTrader::OfferList plugins = KTrader::self()->query("ThumbCreator");
02089     KTrader::OfferList::ConstIterator it;
02090 
02091     for ( it = plugins.begin(); it != plugins.end(); ++it ) {
02092         if ( d->previewSettings.contains((*it)->desktopEntryName()) ) {
02093             QStringList mimeTypes = (*it)->property("MimeTypes").toStringList();
02094             for (QStringList::ConstIterator mt = mimeTypes.begin(); mt != mimeTypes.end(); ++mt)
02095                 d->pPreviewMimeTypes->append(*mt);
02096         }
02097     }
02098 }
02099 
02100 #include "konq_iconviewwidget.moc"
02101 
02102 /* vim: set et sw=4 ts=8 softtabstop=4: */
KDE Logo
This file is part of the documentation for libkonq Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Sep 25 20:35:00 2004 by doxygen 1.3.8-20040913 written by Dimitri van Heesch, © 1997-2003