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