kfileivi.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 1999, 2000, 2001, 2002 David Faure <faure@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017    Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "kfileivi.h"
00021 #include "kivdirectoryoverlay.h"
00022 #include "konq_iconviewwidget.h"
00023 #include "konq_operations.h"
00024 #include "konq_settings.h"
00025 
00026 #include <qpainter.h>
00027 
00028 #include <kurldrag.h>
00029 #include <kiconeffect.h>
00030 #include <kfileitem.h>
00031 #include <kdebug.h>
00032 #include <krun.h>
00033 
00034 #undef Bool
00035 
00039 struct KFileIVI::Private
00040 {
00041     QIconSet icons; // Icon states (cached to prevent re-applying icon effects
00042             // every time)
00043     QPixmap  thumb; // Raw unprocessed thumbnail
00044     QString m_animatedIcon; // Name of animation
00045     bool m_animated;        // Animation currently running ?
00046     KIVDirectoryOverlay* m_directoryOverlay;
00047     QPixmap m_overlay;
00048     QString m_overlayName;
00049 };
00050 
00051 KFileIVI::KFileIVI( KonqIconViewWidget *iconview, KFileItem* fileitem, int size )
00052     : KIconViewItem( iconview, fileitem->text() ),
00053     m_size( size ), m_state( KIcon::DefaultState ),
00054     m_bDisabled( false ), m_bThumbnail( false ), m_fileitem( fileitem )
00055 {
00056     d = new KFileIVI::Private;
00057 
00058     updatePixmapSize();
00059     setPixmap( m_fileitem->pixmap( m_size, m_state ) );
00060     setDropEnabled( S_ISDIR( m_fileitem->mode() ) );
00061 
00062     // Cache entry for the icon effects
00063     d->icons.reset( *pixmap(), QIconSet::Large );
00064     d->m_animated = false;
00065 
00066     // iconName() requires the mimetype to be known
00067     if ( fileitem->isMimeTypeKnown() )
00068     {
00069         QString icon = fileitem->iconName();
00070         if ( !icon.isEmpty() )
00071             setMouseOverAnimation( icon );
00072         else
00073             setMouseOverAnimation( "unknown" );
00074     }
00075     d->m_directoryOverlay = 0;
00076 }
00077 
00078 KFileIVI::~KFileIVI()
00079 {
00080     delete d->m_directoryOverlay;
00081     delete d;
00082 }
00083 
00084 void KFileIVI::invalidateThumb( int state, bool redraw )
00085 {
00086     QIconSet::Mode mode;
00087     switch( state )
00088     {
00089     case KIcon::DisabledState:
00090         mode = QIconSet::Disabled;
00091         break;
00092     case KIcon::ActiveState:
00093         mode = QIconSet::Active;
00094         break;
00095     case KIcon::DefaultState:
00096     default:
00097         mode = QIconSet::Normal;
00098         break;
00099     }
00100     d->icons = QIconSet();
00101     d->icons.setPixmap( KGlobal::iconLoader()->iconEffect()->
00102             apply( d->thumb, KIcon::Desktop, state ),
00103             QIconSet::Large, mode );
00104     m_state = state;
00105 
00106     QIconViewItem::setPixmap( d->icons.pixmap( QIconSet::Large, mode ),
00107                   false, redraw );
00108 }
00109 
00110 void KFileIVI::setIcon( int size, int state, bool recalc, bool redraw )
00111 {
00112     m_size = size;
00113     m_bThumbnail = false;
00114     if ( m_bDisabled )
00115       m_state = KIcon::DisabledState;
00116     else
00117       m_state = state;
00118 
00119     if ( d->m_overlayName.isNull() )
00120         d->m_overlay = QPixmap();
00121     else {
00122         int halfSize;
00123         if (m_size == 0) {
00124             halfSize = IconSize(KIcon::Desktop) / 2;
00125         } else {
00126             halfSize = m_size / 2;
00127         }
00128         d->m_overlay = DesktopIcon(d->m_overlayName, halfSize);
00129     }
00130 
00131     setPixmapDirect(m_fileitem->pixmap( m_size, m_state ) , recalc, redraw );
00132 }
00133 
00134 void KFileIVI::setOverlay( const QString& iconName )
00135 {
00136     d->m_overlayName = iconName;
00137 
00138     refreshIcon(true);
00139 }
00140 
00141 KIVDirectoryOverlay* KFileIVI::setShowDirectoryOverlay( bool show )
00142 {
00143     if ( !m_fileitem->isDir() || m_fileitem->iconName() != "folder" )
00144         return 0;
00145 
00146     if (show) {
00147         if (!d->m_directoryOverlay)
00148             d->m_directoryOverlay = new KIVDirectoryOverlay(this);
00149         return d->m_directoryOverlay;
00150     } else {
00151         delete d->m_directoryOverlay;
00152         d->m_directoryOverlay = 0;
00153         setOverlay(QString());
00154         return 0;
00155     }
00156 }
00157 
00158 bool KFileIVI::showDirectoryOverlay(  )
00159 {
00160     return (bool)d->m_directoryOverlay;
00161 }
00162 
00163 void KFileIVI::setPixmapDirect( const QPixmap& pixmap, bool recalc, bool redraw )
00164 {
00165     QIconSet::Mode mode;
00166     switch( m_state )
00167     {
00168     case KIcon::DisabledState:
00169         mode = QIconSet::Disabled;
00170         break;
00171     case KIcon::ActiveState:
00172         mode = QIconSet::Active;
00173         break;
00174     case KIcon::DefaultState:
00175     default:
00176         mode = QIconSet::Normal;
00177         break;
00178     }
00179 
00180     // We cannot just reset() the iconset here, because setIcon can be
00181     // called with any state and not just normal state. So we just
00182     // create a dummy empty iconset as base object.
00183     d->icons = QIconSet();
00184     d->icons.setPixmap( pixmap, QIconSet::Large, mode );
00185 
00186     updatePixmapSize();
00187     QIconViewItem::setPixmap( d->icons.pixmap( QIconSet::Large, mode ),
00188                   recalc, redraw );
00189 }
00190 
00191 void KFileIVI::setDisabled( bool disabled )
00192 {
00193     if ( m_bDisabled != disabled )
00194     {
00195         m_bDisabled = disabled;
00196         bool active = ( m_state == KIcon::ActiveState );
00197         setEffect( m_bDisabled ? KIcon::DisabledState : 
00198                    ( active ? KIcon::ActiveState : KIcon::DefaultState ) );
00199     }
00200 }
00201 
00202 void KFileIVI::setThumbnailPixmap( const QPixmap & pixmap )
00203 {
00204     m_bThumbnail = true;
00205     d->thumb = pixmap;
00206     // QIconSet::reset() doesn't seem to clear the other generated pixmaps,
00207     // so we just create a blank QIconSet here
00208     d->icons = QIconSet();
00209     d->icons.setPixmap( KGlobal::iconLoader()->iconEffect()->
00210             apply( pixmap, KIcon::Desktop, KIcon::DefaultState ),
00211             QIconSet::Large, QIconSet::Normal );
00212 
00213     m_state = KIcon::DefaultState;
00214 
00215     // Recalc when setting this pixmap!
00216     updatePixmapSize();
00217     QIconViewItem::setPixmap( d->icons.pixmap( QIconSet::Large,
00218                   QIconSet::Normal ), true );
00219 }
00220 
00221 void KFileIVI::setActive( bool active )
00222 {
00223     if ( active )
00224         setEffect( KIcon::ActiveState );
00225     else
00226         setEffect( m_bDisabled ? KIcon::DisabledState : KIcon::DefaultState );
00227 }
00228 
00229 void KFileIVI::setEffect( int state )
00230 {
00231     QIconSet::Mode mode;
00232     switch( state )
00233     {
00234     case KIcon::DisabledState:
00235         mode = QIconSet::Disabled;
00236         break;
00237     case KIcon::ActiveState:
00238         mode = QIconSet::Active;
00239         break;
00240     case KIcon::DefaultState:
00241     default:
00242         mode = QIconSet::Normal;
00243         break;
00244     }
00245     // Do not update if the fingerprint is identical (prevents flicker)!
00246 
00247     KIconEffect *effect = KGlobal::iconLoader()->iconEffect();
00248 
00249     bool haveEffect = effect->hasEffect( KIcon::Desktop, m_state ) !=
00250                       effect->hasEffect( KIcon::Desktop, state );
00251 
00252                 //kdDebug(1203) << "desktop;defaultstate=" <<
00253                 //      effect->fingerprint(KIcon::Desktop, KIcon::DefaultState) <<
00254                 //      endl;
00255                 //kdDebug(1203) << "desktop;activestate=" <<
00256                 //      effect->fingerprint(KIcon::Desktop, KIcon::ActiveState) <<
00257                 //      endl;
00258 
00259     if( haveEffect &&
00260         effect->fingerprint( KIcon::Desktop, m_state ) !=
00261     effect->fingerprint( KIcon::Desktop, state ) )
00262     {
00263     // Effects on are not applied until they are first accessed to
00264     // save memory. Do this now when needed
00265     if( m_bThumbnail )
00266     {
00267         if( d->icons.isGenerated( QIconSet::Large, mode ) )
00268         d->icons.setPixmap( effect->apply( d->thumb, KIcon::Desktop, state ),
00269                     QIconSet::Large, mode );
00270     }
00271     else
00272     {
00273         if( d->icons.isGenerated( QIconSet::Large, mode ) )
00274         d->icons.setPixmap( m_fileitem->pixmap( m_size, state ),
00275                     QIconSet::Large, mode );
00276     }
00277     QIconViewItem::setPixmap( d->icons.pixmap( QIconSet::Large, mode ) );
00278     }
00279     m_state = state;
00280 }
00281 
00282 void KFileIVI::refreshIcon( bool redraw )
00283 {
00284     if (!isThumbnail())
00285         setIcon( m_size, m_state, true, redraw );
00286 }
00287 
00288 void KFileIVI::invalidateThumbnail()
00289 {
00290     d->thumb = QPixmap();
00291 }
00292 
00293 bool KFileIVI::isThumbnailInvalid() const
00294 {
00295     return d->thumb.isNull();
00296 }
00297 
00298 bool KFileIVI::acceptDrop( const QMimeSource *mime ) const
00299 {
00300     if ( mime->provides( "text/uri-list" ) ) // We're dragging URLs
00301     {
00302         if ( m_fileitem->acceptsDrops() ) // Directory, executables, ...
00303             return true;
00304 
00305         // Use cache
00306         KURL::List uris = ( static_cast<KonqIconViewWidget*>(iconView()) )->dragURLs();
00307 
00308         // Check if we want to drop something on itself
00309         // (Nothing will happen, but it's a convenient way to move icons)
00310         KURL::List::Iterator it = uris.begin();
00311         for ( ; it != uris.end() ; it++ )
00312         {
00313             if ( m_fileitem->url().equals( *it, true /*ignore trailing slashes*/ ) )
00314                 return true;
00315         }
00316     }
00317     return QIconViewItem::acceptDrop( mime );
00318 }
00319 
00320 void KFileIVI::setKey( const QString &key )
00321 {
00322     QString theKey = key;
00323 
00324     QVariant sortDirProp = iconView()->property( "sortDirectoriesFirst" );
00325 
00326     bool isdir = ( S_ISDIR( m_fileitem->mode() ) && ( !sortDirProp.isValid() || ( sortDirProp.type() == QVariant::Bool && sortDirProp.toBool() ) ) );
00327 
00328     // The order is: .dir (0), dir (1), .file (2), file (3)
00329     int sortChar = isdir ? 1 : 3;
00330     if ( m_fileitem->text()[0] == '.' )
00331         --sortChar;
00332 
00333     if ( !iconView()->sortDirection() ) // reverse sorting
00334         sortChar = 3 - sortChar;
00335 
00336     theKey.prepend( QChar( sortChar + '0' ) );
00337 
00338     QIconViewItem::setKey( theKey );
00339 }
00340 
00341 void KFileIVI::dropped( QDropEvent *e, const QValueList<QIconDragItem> & )
00342 {
00343     KonqOperations::doDrop( item(), item()->url(), e, iconView() );
00344 }
00345 
00346 void KFileIVI::returnPressed()
00347 {
00348     if ( static_cast<KonqIconViewWidget*>(iconView())->isDesktop() ) {
00349         KURL url = m_fileitem->url();
00350         // When clicking on a link to e.g. $HOME from the desktop, we want to open $HOME
00351         // Symlink resolution must only happen on the desktop though (#63014)
00352         if ( m_fileitem->isLink() && url.isLocalFile() )
00353             url = KURL( url, m_fileitem->linkDest() );
00354 
00355         (void) new KRun( url, m_fileitem->mode(), m_fileitem->isLocalFile() );
00356     } else {
00357         m_fileitem->run();
00358     }
00359 }
00360 
00361 
00362 void KFileIVI::paintItem( QPainter *p, const QColorGroup &c )
00363 {
00364     QColorGroup cg = updateColors(c);
00365     paintFontUpdate( p );
00366 
00367     //*** TEMPORARY CODE - MUST BE MADE CONFIGURABLE FIRST - Martijn
00368     // SET UNDERLINE ON HOVER ONLY
00369     /*if ( ( ( KonqIconViewWidget* ) iconView() )->m_pActiveItem == this )
00370     {
00371         QFont f( p->font() );
00372         f.setUnderline( TRUE );
00373         p->setFont( f );
00374     }*/
00375 
00376     KIconViewItem::paintItem( p, cg );
00377     paintOverlay(p);
00378 
00379 }
00380 
00381 void KFileIVI::paintOverlay( QPainter *p ) const
00382 {
00383     if ( !d->m_overlay.isNull() ) {
00384         QRect rect = pixmapRect(true);
00385         p->drawPixmap(x() + rect.x() , y() + pixmapRect().height() - d->m_overlay.height(), d->m_overlay);
00386     }
00387 }
00388 
00389 void KFileIVI::paintFontUpdate( QPainter *p ) const
00390 {
00391     if ( m_fileitem->isLink() )
00392     {
00393         QFont f( p->font() );
00394         f.setItalic( TRUE );
00395         p->setFont( f );
00396     }
00397 }
00398 
00399 QColorGroup KFileIVI::updateColors( const QColorGroup &c ) const
00400 {
00401     QColorGroup cg( c );
00402     cg.setColor( QColorGroup::Text, static_cast<KonqIconViewWidget*>(iconView())->itemColor() );
00403     return cg;
00404 }
00405 
00406 bool KFileIVI::move( int x, int y )
00407 {
00408     if ( static_cast<KonqIconViewWidget*>(iconView())->isDesktop() ) {
00409     if ( x < 5 )
00410         x = 5;
00411     if ( x > iconView()->viewport()->width() - ( width() + 5 ) )
00412         x = iconView()->viewport()->width() - ( width() + 5 );
00413     if ( y < 5 )
00414         y = 5;
00415     if ( y > iconView()->viewport()->height() - ( height() + 5 ) )
00416         y = iconView()->viewport()->height() - ( height() + 5 );
00417     }
00418     return QIconViewItem::move( x, y );
00419 }
00420 
00421 bool KFileIVI::hasAnimation() const
00422 {
00423     return !d->m_animatedIcon.isEmpty() && !m_bThumbnail;
00424 }
00425 
00426 void KFileIVI::setMouseOverAnimation( const QString& movieFileName )
00427 {
00428     if ( !movieFileName.isEmpty() )
00429     {
00430         //kdDebug(1203) << "KIconViewItem::setMouseOverAnimation " << movieFileName << endl;
00431         d->m_animatedIcon = movieFileName;
00432     }
00433 }
00434 
00435 QString KFileIVI::mouseOverAnimation() const
00436 {
00437     return d->m_animatedIcon;
00438 }
00439 
00440 bool KFileIVI::isAnimated() const
00441 {
00442     return d->m_animated;
00443 }
00444 
00445 void KFileIVI::setAnimated( bool a )
00446 {
00447     d->m_animated = a;
00448 }
00449 
00450 int KFileIVI::compare( QIconViewItem *i ) const
00451 {
00452     KonqIconViewWidget* view = static_cast<KonqIconViewWidget*>(iconView());
00453     if ( view->caseInsensitiveSort() )
00454         return key().localeAwareCompare( i->key() );
00455     else
00456         return view->m_pSettings->caseSensitiveCompare( key(), i->key() );
00457 }
00458 
00459 void KFileIVI::updatePixmapSize()
00460 {
00461     int size = m_size ? m_size :
00462         KGlobal::iconLoader()->currentSize( KIcon::Desktop );
00463 
00464     KonqIconViewWidget* view = static_cast<KonqIconViewWidget*>( iconView() );
00465 
00466     if ( view && view->canPreview( item() ) ) { 
00467         int previewSize = view->previewIconSize( size );
00468         setPixmapSize( QSize( previewSize, previewSize ) );
00469     }
00470     else {
00471         QSize pixSize = QSize( size, size );
00472         if ( pixSize != pixmapSize() )
00473             setPixmapSize( pixSize );
00474     }
00475 }
00476 
00477 /* vim: set noet sw=4 ts=8 softtabstop=4: */
KDE Home | KDE Accessibility Home | Description of Access Keys