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