|
|
|
/* This file is part of the KDE projects
|
|
|
|
Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
|
|
|
|
Copyright (C) 2000 - 2005 David Faure <faure@kde.org>
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; see the file COPYING. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
#include "konq_iconviewwidget.h"
|
|
|
|
#include "konq_operations.h"
|
|
|
|
#include "konq_undo.h"
|
|
|
|
#include "konq_sound.h"
|
|
|
|
#include "konq_filetip.h"
|
|
|
|
|
|
|
|
#include <qclipboard.h>
|
|
|
|
#include <qlayout.h>
|
|
|
|
#include <qtimer.h>
|
|
|
|
#include <qpainter.h>
|
|
|
|
#include <qtooltip.h>
|
|
|
|
#include <qlabel.h>
|
|
|
|
#include <qmovie.h>
|
|
|
|
#include <qregexp.h>
|
|
|
|
#include <qcursor.h>
|
|
|
|
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kio/previewjob.h>
|
|
|
|
#include <kfileivi.h>
|
|
|
|
#include <konq_settings.h>
|
|
|
|
#include <konq_drag.h>
|
|
|
|
#include <kglobalsettings.h>
|
|
|
|
#include <kpropertiesdialog.h>
|
|
|
|
#include <kipc.h>
|
|
|
|
#include <kicontheme.h>
|
|
|
|
#include <kiconeffect.h>
|
|
|
|
#include <kurldrag.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <kprotocolinfo.h>
|
|
|
|
#include <ktrader.h>
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
|
|
|
|
|
|
|
|
struct KonqIconViewWidgetPrivate
|
|
|
|
{
|
|
|
|
KonqIconViewWidgetPrivate() {
|
|
|
|
pActiveItem = 0;
|
|
|
|
bSoundPreviews = false;
|
|
|
|
pSoundItem = 0;
|
|
|
|
bSoundItemClicked = false;
|
|
|
|
pSoundPlayer = 0;
|
|
|
|
pSoundTimer = 0;
|
|
|
|
pPreviewJob = 0;
|
|
|
|
bAllowSetWallpaper = false;
|
|
|
|
|
|
|
|
doAnimations = true;
|
|
|
|
m_movie = 0L;
|
|
|
|
m_movieBlocked = 0;
|
|
|
|
pFileTip = 0;
|
|
|
|
pActivateDoubleClick = 0L;
|
|
|
|
bCaseInsensitive = true;
|
|
|
|
pPreviewMimeTypes = 0L;
|
|
|
|
bProgramsURLdrag = false;
|
|
|
|
}
|
|
|
|
~KonqIconViewWidgetPrivate() {
|
|
|
|
delete pSoundPlayer;
|
|
|
|
delete pSoundTimer;
|
|
|
|
delete m_movie;
|
|
|
|
delete pFileTip;
|
|
|
|
delete pActivateDoubleClick;
|
|
|
|
delete pPreviewMimeTypes;
|
|
|
|
//delete pPreviewJob; done by stopImagePreview
|
|
|
|
}
|
|
|
|
KFileIVI *pActiveItem;
|
|
|
|
// Sound preview
|
|
|
|
KFileIVI *pSoundItem;
|
|
|
|
KonqSoundPlayer *pSoundPlayer;
|
|
|
|
QTimer *pSoundTimer;
|
|
|
|
bool bSoundPreviews;
|
|
|
|
bool bSoundItemClicked;
|
|
|
|
bool bAllowSetWallpaper;
|
|
|
|
bool bCaseInsensitive;
|
|
|
|
bool bBoostPreview;
|
|
|
|
|
|
|
|
// Animated icons support
|
|
|
|
bool doAnimations;
|
|
|
|
QMovie* m_movie;
|
|
|
|
int m_movieBlocked;
|
|
|
|
QString movieFileName;
|
|
|
|
|
|
|
|
KIO::PreviewJob *pPreviewJob;
|
|
|
|
KonqFileTip* pFileTip;
|
|
|
|
QStringList previewSettings;
|
|
|
|
bool renameItem;
|
|
|
|
bool firstClick;
|
|
|
|
bool releaseMouseEvent;
|
|
|
|
QPoint mousePos;
|
|
|
|
int mouseState;
|
|
|
|
QTimer *pActivateDoubleClick;
|
|
|
|
QStringList* pPreviewMimeTypes;
|
|
|
|
bool bProgramsURLdrag;
|
|
|
|
};
|
|
|
|
|
|
|
|
KonqIconViewWidget::KonqIconViewWidget( QWidget * parent, const char * name, WFlags f, bool kdesktop )
|
|
|
|
: KIconView( parent, name, f ),
|
|
|
|
m_rootItem( 0L ), m_size( 0 ) /* default is DesktopIcon size */,
|
|
|
|
m_bDesktop( kdesktop ),
|
|
|
|
m_bSetGridX( !kdesktop ) /* No line breaking on the desktop */
|
|
|
|
{
|
|
|
|
d = new KonqIconViewWidgetPrivate;
|
|
|
|
connect( this, SIGNAL( dropped( QDropEvent *, const QValueList<QIconDragItem> & ) ),
|
|
|
|
this, SLOT( slotDropped( QDropEvent*, const QValueList<QIconDragItem> & ) ) );
|
|
|
|
|
|
|
|
connect( this, SIGNAL( selectionChanged() ),
|
|
|
|
this, SLOT( slotSelectionChanged() ) );
|
|
|
|
|
|
|
|
kapp->addKipcEventMask( KIPC::IconChanged );
|
|
|
|
connect( kapp, SIGNAL(iconChanged(int)), SLOT(slotIconChanged(int)) );
|
|
|
|
connect( this, SIGNAL(onItem(QIconViewItem *)), SLOT(slotOnItem(QIconViewItem *)) );
|
|
|
|
connect( this, SIGNAL(onViewport()), SLOT(slotOnViewport()) );
|
|
|
|
connect( this, SIGNAL(itemRenamed(QIconViewItem *, const QString &)), SLOT(slotItemRenamed(QIconViewItem *, const QString &)) );
|
|
|
|
|
|
|
|
m_pSettings = KonqFMSettings::settings(); // already needed in setItemTextPos(), calculateGridX()
|
|
|
|
d->bBoostPreview = boostPreview();
|
|
|
|
|
|
|
|
// hardcoded settings
|
|
|
|
setSelectionMode( QIconView::Extended );
|
|
|
|
setItemTextPos( QIconView::Bottom );
|
|
|
|
d->releaseMouseEvent = false;
|
|
|
|
d->pFileTip = new KonqFileTip(this);
|
|
|
|
d->firstClick = false;
|
|
|
|
calculateGridX();
|
|
|
|
setAutoArrange( true );
|
|
|
|
setSorting( true, sortDirection() );
|
|
|
|
readAnimatedIconsConfig();
|
|
|
|
m_bSortDirsFirst = true;
|
|
|
|
m_bMousePressed = false;
|
|
|
|
m_LineupMode = LineupBoth;
|
|
|
|
// emit our signals
|
|
|
|
slotSelectionChanged();
|
|
|
|
m_iconPositionGroupPrefix = QString::fromLatin1( "IconPosition::" );
|
|
|
|
KonqUndoManager::incRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
KonqIconViewWidget::~KonqIconViewWidget()
|
|
|
|
{
|
|
|
|
stopImagePreview();
|
|
|
|
KonqUndoManager::decRef();
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KonqIconViewWidget::maySetWallpaper()
|
|
|
|
{
|
|
|
|
return d->bAllowSetWallpaper;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::setMaySetWallpaper(bool b)
|
|
|
|
{
|
|
|
|
d->bAllowSetWallpaper = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::focusOutEvent( QFocusEvent * ev )
|
|
|
|
{
|
|
|
|
// We can't possibly have the mouse pressed and still lose focus.
|
|
|
|
// Well, we can, but when we regain focus we should assume the mouse is
|
|
|
|
// not down anymore or the slotOnItem code will break with highlighting!
|
|
|
|
m_bMousePressed = false;
|
|
|
|
|
|
|
|
// This will ensure that tooltips don't pop up and the mouseover icon
|
|
|
|
// effect will go away if the mouse goes out of the view without
|
|
|
|
// first moving into an empty portion of the view
|
|
|
|
// Fixes part of #86968, and #85204
|
|
|
|
// Matt Newell 2004-09-24
|
|
|
|
slotOnViewport();
|
|
|
|
|
|
|
|
KIconView::focusOutEvent( ev );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::slotItemRenamed(QIconViewItem *item, const QString &name)
|
|
|
|
{
|
|
|
|
kdDebug(1203) << "KonqIconViewWidget::slotItemRenamed" << endl;
|
|
|
|
KFileIVI *viewItem = static_cast<KFileIVI *>(item);
|
|
|
|
KFileItem *fileItem = viewItem->item();
|
|
|
|
|
|
|
|
// The correct behavior is to show the old name until the rename has successfully
|
|
|
|
// completed. Unfortunately, KIconView forces us to allow the text to be changed
|
|
|
|
// before we try the rename, so set it back to the pre-rename state.
|
|
|
|
viewItem->setText( fileItem->text() );
|
|
|
|
kdDebug(1203)<<" fileItem->text() ;"<<fileItem->text()<<endl;
|
|
|
|
// Don't do anything if the user renamed to a blank name.
|
|
|
|
if( !name.isEmpty() )
|
|
|
|
{
|
|
|
|
// Actually attempt the rename. If it succeeds, KDirLister will update the name.
|
|
|
|
KURL oldurl( fileItem->url() );
|
|
|
|
KURL newurl( oldurl );
|
|
|
|
newurl.setPath( newurl.directory(false) + KIO::encodeFileName( name ) );
|
|
|
|
kdDebug(1203)<<" newurl :"<<newurl<<endl;
|
|
|
|
// We use url()+name so that it also works if the name is a relative path (#51176)
|
|
|
|
KonqOperations::rename( this, oldurl, newurl );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::slotIconChanged( int group )
|
|
|
|
{
|
|
|
|
if (group != KIcon::Desktop)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int size = m_size;
|
|
|
|
if ( m_size == 0 )
|
|
|
|
m_size = -1; // little trick to force grid change in setIcons
|
|
|
|
setIcons( size ); // force re-determining all icons
|
|
|
|
readAnimatedIconsConfig();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::readAnimatedIconsConfig()
|
|
|
|
{
|
|
|
|
KConfigGroup cfgGroup( KGlobal::config(), "DesktopIcons" );
|
|
|
|
d->doAnimations = cfgGroup.readBoolEntry( "Animated", true /*default*/ );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::slotOnItem( QIconViewItem *_item )
|
|
|
|
{
|
|
|
|
KFileIVI* item = static_cast<KFileIVI *>( _item );
|
|
|
|
// Reset icon of previous item
|
|
|
|
if( d->pActiveItem != 0L && d->pActiveItem != item )
|
|
|
|
{
|
|
|
|
if ( d->m_movie && d->pActiveItem->isAnimated() )
|
|
|
|
{
|
|
|
|
d->m_movie->pause(); // we'll see below what we do with it
|
|
|
|
d->pActiveItem->setAnimated( false );
|
|
|
|
d->pActiveItem->refreshIcon( true );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
d->pActiveItem->setActive( false );
|
|
|
|
}
|
|
|
|
d->pActiveItem = 0L;
|
|
|
|
d->pFileTip->setItem( 0L );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop sound
|
|
|
|
if (d->pSoundPlayer != 0 && item != d->pSoundItem)
|
|
|
|
{
|
|
|
|
d->pSoundPlayer->stop();
|
|
|
|
|
|
|
|
d->pSoundItem = 0;
|
|
|
|
if (d->pSoundTimer && d->pSoundTimer->isActive())
|
|
|
|
d->pSoundTimer->stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !m_bMousePressed )
|
|
|
|
{
|
|
|
|
if( item != d->pActiveItem )
|
|
|
|
{
|
|
|
|
d->pActiveItem = item;
|
|
|
|
d->pFileTip->setItem( d->pActiveItem->item(),
|
|
|
|
item->rect(),
|
|
|
|
item->pixmap() );
|
|
|
|
|
|
|
|
if ( d->doAnimations && d->pActiveItem && d->pActiveItem->hasAnimation() )
|
|
|
|
{
|
|
|
|
//kdDebug(1203) << "Playing animation for: " << d->pActiveItem->mouseOverAnimation() << endl;
|
|
|
|
// Check if cached movie can be used
|
|
|
|
#if 0 // Qt-mng bug, reusing the movie doesn't work currently.
|
|
|
|
if ( d->m_movie && d->movieFileName == d->pActiveItem->mouseOverAnimation() )
|
|
|
|
{
|
|
|
|
d->pActiveItem->setAnimated( true );
|
|
|
|
if (d->m_movieBlocked) {
|
|
|
|
kdDebug(1203) << "onitem, but blocked" << endl;
|
|
|
|
d->m_movie->pause();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
kdDebug(1203) << "we go ahead.." << endl;
|
|
|
|
d->m_movieBlocked++;
|
|
|
|
QTimer::singleShot(300, this, SLOT(slotReenableAnimation()));
|
|
|
|
d->m_movie->restart();
|
|
|
|
d->m_movie->unpause();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
QMovie movie = KGlobal::iconLoader()->loadMovie( d->pActiveItem->mouseOverAnimation(), KIcon::Desktop, d->pActiveItem->iconSize() );
|
|
|
|
if ( !movie.isNull() )
|
|
|
|
{
|
|
|
|
delete d->m_movie;
|
|
|
|
d->m_movie = new QMovie( movie ); // shallow copy, don't worry
|
|
|
|
// Fix alpha-channel - currently only if no background pixmap,
|
|
|
|
// the bg pixmap case requires to uncomment the code at qmovie.cpp:404
|
|
|
|
const QPixmap* pm = backgroundPixmap();
|
|
|
|
bool hasPixmap = pm && !pm->isNull();
|
|
|
|
if ( !hasPixmap ) {
|
|
|
|
pm = viewport()->backgroundPixmap();
|
|
|
|
hasPixmap = pm && !pm->isNull();
|
|
|
|
}
|
|
|
|
if (!hasPixmap && backgroundMode() != NoBackground)
|
|
|
|
d->m_movie->setBackgroundColor( viewport()->backgroundColor() );
|
|
|
|
d->m_movie->connectUpdate( this, SLOT( slotMovieUpdate(const QRect &) ) );
|
|
|
|
d->m_movie->connectStatus( this, SLOT( slotMovieStatus(int) ) );
|
|
|
|
d->movieFileName = d->pActiveItem->mouseOverAnimation();
|
|
|
|
d->pActiveItem->setAnimated( true );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d->pActiveItem->setAnimated( false );
|
|
|
|
if (d->m_movie)
|
|
|
|
d->m_movie->pause();
|
|
|
|
// No movie available, remember it
|
|
|
|
d->pActiveItem->setMouseOverAnimation( QString::null );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // animations
|
|
|
|
// Only do the normal "mouseover" effect if no animation is in use
|
|
|
|
if (d->pActiveItem && !d->pActiveItem->isAnimated())
|
|
|
|
{
|
|
|
|
d->pActiveItem->setActive( true );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else // No change in current item
|
|
|
|
{
|
|
|
|
// No effect. If we want to underline on hover, we should
|
|
|
|
// force the IVI to repaint here, though!
|
|
|
|
d->pActiveItem = 0L;
|
|
|
|
d->pFileTip->setItem( 0L );
|
|
|
|
}
|
|
|
|
} // bMousePressed
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// All features disabled during mouse clicking, e.g. rectangular
|
|
|
|
// selection
|
|
|
|
d->pActiveItem = 0L;
|
|
|
|
d->pFileTip->setItem( 0L );
|
|
|
|
}
|
|
|
|
|
|
|
|
// ## shouldn't this be disabled during rectangular selection too ?
|
|
|
|
if (d->bSoundPreviews && d->pSoundPlayer &&
|
|
|
|
d->pSoundPlayer->mimeTypes().contains(
|
|
|
|
item->item()->mimetype())
|
|
|
|
&& KGlobalSettings::showFilePreview(item->item()->url())
|
|
|
|
&& topLevelWidget() == kapp->activeWindow())
|
|
|
|
{
|
|
|
|
d->pSoundItem = item;
|
|
|
|
d->bSoundItemClicked = false;
|
|
|
|
if (!d->pSoundTimer)
|
|
|
|
{
|
|
|
|
d->pSoundTimer = new QTimer(this);
|
|
|
|
connect(d->pSoundTimer, SIGNAL(timeout()), SLOT(slotStartSoundPreview()));
|
|
|
|
}
|
|
|
|
if (d->pSoundTimer->isActive())
|
|
|
|
d->pSoundTimer->stop();
|
|
|
|
d->pSoundTimer->start(500, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (d->pSoundPlayer)
|
|
|
|
d->pSoundPlayer->stop();
|
|
|
|
d->pSoundItem = 0;
|
|
|
|
if (d->pSoundTimer && d->pSoundTimer->isActive())
|
|
|
|
d->pSoundTimer->stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::slotOnViewport()
|
|
|
|
{
|
|
|
|
d->pFileTip->setItem( 0L );
|
|
|
|
|
|
|
|
if (d->pSoundPlayer)
|
|
|
|
d->pSoundPlayer->stop();
|
|
|
|
d->pSoundItem = 0;
|
|
|
|
if (d->pSoundTimer && d->pSoundTimer->isActive())
|
|
|
|
d->pSoundTimer->stop();
|
|
|
|
|
|
|
|
if (d->pActiveItem == 0L)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( d->doAnimations && d->m_movie && d->pActiveItem->isAnimated() )
|
|
|
|
{
|
|
|
|
d->pActiveItem->setAnimated( false );
|
|
|
|
#if 0
|
|
|
|
// Aborting before the end of the animation ?
|
|
|
|
if (d->m_movie->running()) {
|
|
|
|
d->m_movie->pause();
|
|
|
|
d->m_movieBlocked++;
|
|
|
|
kdDebug(1203) << "on viewport, blocking" << endl;
|
|
|
|
QTimer::singleShot(300, this, SLOT(slotReenableAnimation()));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
d->pActiveItem->refreshIcon( true );
|
|
|
|
Q_ASSERT( d->pActiveItem->state() == KIcon::DefaultState );
|
|
|
|
//delete d->m_movie;
|
|
|
|
//d->m_movie = 0L;
|
|
|
|
// TODO a timer to delete the movie after some time if unused?
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d->pActiveItem->setActive( false );
|
|
|
|
}
|
|
|
|
d->pActiveItem = 0L;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::slotStartSoundPreview()
|
|
|
|
{
|
|
|
|
if (!d->pSoundItem || d->bSoundItemClicked)
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->pSoundPlayer->play(d->pSoundItem->item()->url().url());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KonqIconViewWidget::slotPreview(const KFileItem *item, const QPixmap &pix)
|
|
|
|
{
|
|
|
|
// ### slow. Idea: move KonqKfmIconView's m_itemDict into this class
|
|
|
|
for (QIconViewItem *it = firstItem(); it; it = it->nextItem())
|
|
|
|
{
|
|
|
|
KFileIVI* current = static_cast<KFileIVI *>(it);
|
|
|
|
if (current->item() == item)
|
|
|
|
{
|
|
|
|
if (item->overlays() & KIcon::HiddenOverlay) {
|
|
|
|
QPixmap p(pix);
|
|
|
|
|
|
|
|
KIconEffect::semiTransparent(p);
|
|
|
|
current->setThumbnailPixmap(p);
|
|
|
|
} else {
|
|
|
|
current->setThumbnailPixmap(pix);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::slotPreviewResult()
|
|
|
|
{
|
|
|
|
d->pPreviewJob = 0;
|
|
|
|
emit imagePreviewFinished();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::slotToolTipPreview(const KFileItem* , const QPixmap &)
|
|
|
|
{
|
|
|
|
// unused - remove for KDE4
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::slotToolTipPreviewResult()
|
|
|
|
{
|
|
|
|
// unused - remove for KDE4
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::slotMovieUpdate( const QRect& rect )
|
|
|
|
{
|
|
|
|
//kdDebug(1203) << "KonqIconViewWidget::slotMovieUpdate " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << endl;
|
|
|
|
Q_ASSERT( d );
|
|
|
|
Q_ASSERT( d->m_movie );
|
|
|
|
// seems stopAnimation triggers one last update
|
|
|
|
if ( d->pActiveItem && d->m_movie && d->pActiveItem->isAnimated() ) {
|
|
|
|
const QPixmap &frame = d->m_movie->framePixmap();
|
|
|
|
// This can happen if the icon was scaled to the desired size, so KIconLoader
|
|
|
|
// will happily return a movie with different dimensions than the icon
|
|
|
|
int iconSize=d->pActiveItem->iconSize();
|
|
|
|
if (iconSize==0) iconSize = KGlobal::iconLoader()->currentSize( KIcon::Desktop );
|
|
|
|
if ( frame.width() != iconSize || frame.height() != iconSize ) {
|
|
|
|
d->pActiveItem->setAnimated( false );
|
|
|
|
d->m_movie->pause();
|
|
|
|
// No movie available, remember it
|
|
|
|
d->pActiveItem->setMouseOverAnimation( QString::null );
|
|
|
|
d->pActiveItem->setActive( true );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
d->pActiveItem->setPixmapDirect( frame, false, false /*no redraw*/ );
|
|
|
|
QRect pixRect = d->pActiveItem->pixmapRect(false);
|
|
|
|
repaintContents( pixRect.x() + rect.x(), pixRect.y() + rect.y(), rect.width(), rect.height(), false );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::slotMovieStatus( int status )
|
|
|
|
{
|
|
|
|
if ( status < 0 ) {
|
|
|
|
// Error playing the MNG -> forget about it and do normal iconeffect
|
|
|
|
if ( d->pActiveItem && d->pActiveItem->isAnimated() ) {
|
|
|
|
d->pActiveItem->setAnimated( false );
|
|
|
|
d->pActiveItem->setMouseOverAnimation( QString::null );
|
|
|
|
d->pActiveItem->setActive( true );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::slotReenableAnimation()
|
|
|
|
{
|
|
|
|
if (!--d->m_movieBlocked) {
|
|
|
|
if ( d->pActiveItem && d->m_movie && d->m_movie->paused()) {
|
|
|
|
kdDebug(1203) << "reenabled animation" << endl;
|
|
|
|
d->m_movie->restart();
|
|
|
|
d->m_movie->unpause();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::clear()
|
|
|
|
{
|
|
|
|
d->pFileTip->setItem( 0L );
|
|
|
|
stopImagePreview(); // Just in case
|
|
|
|
KIconView::clear();
|
|
|
|
d->pActiveItem = 0L;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::takeItem( QIconViewItem *item )
|
|
|
|
{
|
|
|
|
if ( d->pActiveItem == static_cast<KFileIVI *>(item) )
|
|
|
|
{
|
|
|
|
d->pFileTip->setItem( 0L );
|
|
|
|
d->pActiveItem = 0L;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( d->pPreviewJob )
|
|
|
|
d->pPreviewJob->removeItem( static_cast<KFileIVI *>(item)->item() );
|
|
|
|
|
|
|
|
KIconView::takeItem( item );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Currently unused - remove in KDE 4.0
|
|
|
|
void KonqIconViewWidget::setThumbnailPixmap( KFileIVI * item, const QPixmap & pixmap )
|
|
|
|
{
|
|
|
|
if ( item )
|
|
|
|
{
|
|
|
|
if ( d->pActiveItem == item )
|
|
|
|
{
|
|
|
|
d->pFileTip->setItem( 0L );
|
|
|
|
d->pActiveItem = 0L;
|
|
|
|
}
|
|
|
|
item->setThumbnailPixmap( pixmap );
|
|
|
|
if ( m_bSetGridX && item->width() > gridX() )
|
|
|
|
{
|
|
|
|
setGridX( item->width() );
|
|
|
|
if (autoArrange())
|
|
|
|
arrangeItemsInGrid();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KonqIconViewWidget::initConfig( bool bInit )
|
|
|
|
{
|
|
|
|
bool fontChanged = false;
|
|
|
|
|
|
|
|
// Color settings
|
|
|
|
QColor normalTextColor = m_pSettings->normalTextColor();
|
|
|
|
setItemColor( normalTextColor );
|
|
|
|
|
|
|
|
if (m_bDesktop)
|
|
|
|
{
|
|
|
|
QColor itemTextBg = m_pSettings->itemTextBackground();
|
|
|
|
if ( itemTextBg.isValid() )
|
|
|
|
setItemTextBackground( itemTextBg );
|
|
|
|
else
|
|
|
|
setItemTextBackground( NoBrush );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool on = m_pSettings->showFileTips() && QToolTip::isGloballyEnabled();
|
|
|
|
d->pFileTip->setOptions(on,
|
|
|
|
m_pSettings->showPreviewsInFileTips(),
|
|
|
|
m_pSettings->numFileTips());
|
|
|
|
|
|
|
|
// if the user wants our own tooltip, don't show the one from Qts ListView
|
|
|
|
setShowToolTips(!on);
|
|
|
|
|
|
|
|
// Font settings
|
|
|
|
QFont font( m_pSettings->standardFont() );
|
|
|
|
if (!m_bDesktop)
|
|
|
|
font.setUnderline( m_pSettings->underlineLink() );
|
|
|
|
|
|
|
|
if ( font != KonqIconViewWidget::font() )
|
|
|
|
{
|
|
|
|
setFont( font );
|
|
|
|
if (!bInit)
|
|
|
|
{
|
|
|
|
// QIconView doesn't do it by default... but if the font is made much
|
|
|
|
// bigger, we really need to give more space between the icons
|
|
|
|
fontChanged = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setIconTextHeight( m_pSettings->iconTextHeight() );
|
|
|
|
|
|
|
|
if ( (itemTextPos() == QIconView::Right) && (maxItemWidth() != gridXValue()) )
|
|
|
|
{
|
|
|
|
int size = m_size;
|
|
|
|
m_size = -1; // little trick to force grid change in setIcons
|
|
|
|
setIcons( size ); // force re-determining all icons
|
|
|
|
}
|
|
|
|
else if ( d->bBoostPreview != boostPreview() ) // Update icons if settings for preview icon size have changed
|
|
|
|
setIcons(m_size);
|
|
|
|
else if (!bInit)
|
|
|
|
updateContents();
|
|
|
|
return fontChanged;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KonqIconViewWidget::boostPreview() const
|
|
|
|
{
|
|
|
|
if ( m_bDesktop ) return false;
|
|
|
|
|
|
|
|
KConfigGroup group( KGlobal::config(), "PreviewSettings" );
|
|
|
|
return group.readBoolEntry( "BoostSize", false );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::disableSoundPreviews()
|
|
|
|
{
|
|
|
|
d->bSoundPreviews = false;
|
|
|
|
|
|
|
|
if (d->pSoundPlayer)
|
|
|
|
d->pSoundPlayer->stop();
|
|
|
|
d->pSoundItem = 0;
|
|
|
|
if (d->pSoundTimer && d->pSoundTimer->isActive())
|
|
|
|
d->pSoundTimer->stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::setIcons( int size, const QStringList& stopImagePreviewFor )
|
|
|
|
{
|
|
|
|
// size has changed?
|
|
|
|
bool sizeChanged = (m_size != size);
|
|
|
|
int oldGridX = gridX();
|
|
|
|
m_size = size;
|
|
|
|
|
|
|
|
// boost preview option has changed?
|
|
|
|
bool boost = boostPreview();
|
|
|
|
bool previewSizeChanged = ( d->bBoostPreview != boost );
|
|
|
|
d->bBoostPreview = boost;
|
|
|
|
|
|
|
|
if ( sizeChanged || previewSizeChanged )
|
|
|
|
{
|
|
|
|
int realSize = size ? size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
|
|
|
|
// choose spacing depending on font, but min 5 (due to KFileIVI move limit)
|
|
|
|
setSpacing( ( m_bDesktop || ( realSize > KIcon::SizeSmall ) ) ?
|
|
|
|
QMAX( 5, QFontMetrics(font()).width('n') ) : 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( sizeChanged || previewSizeChanged || !stopImagePreviewFor.isEmpty() )
|
|
|
|
{
|
|
|
|
calculateGridX();
|
|
|
|
}
|
|
|
|
bool stopAll = !stopImagePreviewFor.isEmpty() && stopImagePreviewFor.first() == "*";
|
|
|
|
|
|
|
|
// Disable repaints that can be triggered by ivi->setIcon(). Since icons are
|
|
|
|
// resized in-place, if the icon size is increasing it can happens that the right
|
|
|
|
// or bottom icons exceed the size of the viewport.. here we prevent the repaint
|
|
|
|
// event that will be triggered in that case.
|
|
|
|
bool prevUpdatesState = viewport()->isUpdatesEnabled();
|
|
|
|
viewport()->setUpdatesEnabled( false );
|
|
|
|
|
|
|
|
// Do this even if size didn't change, since this is used by refreshMimeTypes...
|
|
|
|
for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
|
|
|
|
KFileIVI * ivi = static_cast<KFileIVI *>( it );
|
|
|
|
// Set a normal icon for files that are not thumbnails, and for files
|
|
|
|
// that are thumbnails but for which it should be stopped
|
|
|
|
if ( !ivi->isThumbnail() ||
|
|
|
|
sizeChanged ||
|
|
|
|
previewSizeChanged ||
|
|
|
|
stopAll ||
|
|
|
|
mimeTypeMatch( ivi->item()->mimetype(), stopImagePreviewFor ) )
|
|
|
|
{
|
|
|
|
ivi->setIcon( size, ivi->state(), true, false );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ivi->invalidateThumb( ivi->state(), true );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Restore viewport update to previous state
|
|
|
|
viewport()->setUpdatesEnabled( prevUpdatesState );
|
|
|
|
|
|
|
|
if ( ( sizeChanged || previewSizeChanged || oldGridX != gridX() ||
|
|
|
|
!stopImagePreviewFor.isEmpty() ) && autoArrange() )
|
|
|
|
arrangeItemsInGrid( true ); // take new grid into account and repaint
|
|
|
|
else
|
|
|
|
viewport()->update(); //Repaint later..
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KonqIconViewWidget::mimeTypeMatch( const QString& mimeType, const QStringList& mimeList ) const
|
|
|
|
{
|
|
|
|
// Code duplication from KIO::PreviewJob
|
|
|
|
KMimeType::Ptr mime = KMimeType::mimeType( mimeType );
|
|
|
|
for (QStringList::ConstIterator mt = mimeList.begin(); mt != mimeList.end(); ++mt)
|
|
|
|
{
|
|
|
|
if ( mime->is( *mt ) )
|
|
|
|
return true;
|
|
|
|
// Support for *mt == "image/*"
|
|
|
|
QString tmp( mimeType );
|
|
|
|
if ( (*mt).endsWith("*") && tmp.replace(QRegExp("/.*"), "/*") == (*mt) )
|
|
|
|
return true;
|
|
|
|
if ( (*mt) == "text/plain" )
|
|
|
|
{
|
|
|
|
QVariant textProperty = mime->property( "X-KDE-text" );
|
|
|
|
if ( textProperty.type() == QVariant::Bool && textProperty.toBool() )
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::setItemTextPos( ItemTextPos pos )
|
|
|
|
{
|
|
|
|
// can't call gridXValue() because this already would need the new itemTextPos()
|
|
|
|
int sz = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
|
|
|
|
|
|
|
|
if ( m_bSetGridX )
|
|
|
|
if ( pos == QIconView::Bottom )
|
|
|
|
setGridX( QMAX( sz + 50, previewIconSize( sz ) + 13 ) );
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setMaxItemWidth( QMAX( sz, previewIconSize( sz ) ) + m_pSettings->iconTextWidth() );
|
|
|
|
setGridX( -1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
KIconView::setItemTextPos( pos );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::gridValues( int* x, int* y, int* dx, int* dy,
|
|
|
|
int* nx, int* ny )
|
|
|
|
{
|
|
|
|
int previewSize = previewIconSize( m_size );
|
|
|
|
int iconSize = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
|
|
|
|
|
|
|
|
// Grid size
|
|
|
|
// as KFileIVI limits to move an icon to x >= 5, y >= 5, we define a grid cell as:
|
|
|
|
// spacing() must be >= 5 (currently set to 5 in setIcons())
|
|
|
|
// horizontal: left spacing() + <width>
|
|
|
|
// vertical : top spacing(), <height>, bottom spacing()
|
|
|
|
// The doubled space in y-direction gives a better visual separation and makes it clearer
|
|
|
|
// to which item the text belongs
|
|
|
|
*dx = spacing() + QMAX( QMAX( iconSize, previewSize ), m_pSettings->iconTextWidth() );
|
|
|
|
int textHeight = iconTextHeight() * fontMetrics().height();
|
|
|
|
*dy = spacing() + QMAX( iconSize, previewSize ) + 2 + textHeight + spacing();
|
|
|
|
|
|
|
|
// Icon Area
|
|
|
|
int w, h;
|
|
|
|
if ( m_IconRect.isValid() ) { // w and h must be != 0, otherwise we would get a div by zero
|
|
|
|
*x = m_IconRect.left(); w = m_IconRect.width();
|
|
|
|
*y = m_IconRect.top(); h = m_IconRect.height();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*x = 0; w = viewport()->width();
|
|
|
|
*y = 0; h = viewport()->height();
|
|
|
|
}
|
|
|
|
|
|
|
|
// bug:110775 avoid div by zero (happens e.g. when iconTextHeight or iconTextWidth are very large)
|
|
|
|
if ( *dx > w )
|
|
|
|
*dx = w;
|
|
|
|
|
|
|
|
if ( *dy > h )
|
|
|
|
*dy = h;
|
|
|
|
|
|
|
|
*nx = w / *dx;
|
|
|
|
*ny = h / *dy;
|
|
|
|
// TODO: Check that items->count() <= nx * ny
|
|
|
|
|
|
|
|
// Let have exactly nx columns and ny rows
|
|
|
|
if(*nx && *ny) {
|
|
|
|
*dx = w / *nx;
|
|
|
|
*dy = h / *ny;
|
|
|
|
}
|
|
|
|
kdDebug(1203) << "x=" << *x << " y=" << *y << " spacing=" << spacing() << " iconSize=" << iconSize
|
|
|
|
<< " w=" << w << " h=" << h
|
|
|
|
<< " nx=" << *nx << " ny=" << *ny
|
|
|
|
<< " dx=" << *dx << " dy=" << *dy << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::calculateGridX()
|
|
|
|
{
|
|
|
|
if ( m_bSetGridX )
|
|
|
|
if ( itemTextPos() == QIconView::Bottom )
|
|
|
|
setGridX( gridXValue() );
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setMaxItemWidth( gridXValue() );
|
|
|
|
setGridX( -1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int KonqIconViewWidget::gridXValue() const
|
|
|
|
{
|
|
|
|
// this method is only used in konqi as filemanager (not desktop)
|
|
|
|
int sz = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
|
|
|
|
int newGridX;
|
|
|
|
|
|
|
|
if ( itemTextPos() == QIconView::Bottom )
|
|
|
|
newGridX = QMAX( sz + 50, previewIconSize( sz ) + 13 );
|
|
|
|
else
|
|
|
|
newGridX = QMAX( sz, previewIconSize( sz ) ) + m_pSettings->iconTextWidth();
|
|
|
|
|
|
|
|
//kdDebug(1203) << "gridXValue: " << newGridX << " sz=" << sz << endl;
|
|
|
|
return newGridX;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::refreshMimeTypes()
|
|
|
|
{
|
|
|
|
updatePreviewMimeTypes();
|
|
|
|
for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
|
|
|
|
(static_cast<KFileIVI *>( it ))->item()->refreshMimeType();
|
|
|
|
setIcons( m_size );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::setURL( const KURL &kurl )
|
|
|
|
{
|
|
|
|
stopImagePreview();
|
|
|
|
m_url = kurl;
|
|
|
|
|
|
|
|
d->pFileTip->setPreview( KGlobalSettings::showFilePreview(m_url) );
|
|
|
|
|
|
|
|
if ( m_url.isLocalFile() )
|
|
|
|
m_dotDirectoryPath = m_url.path(1).append( ".directory" );
|
|
|
|
else
|
|
|
|
m_dotDirectoryPath = QString::null;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::startImagePreview( const QStringList &, bool force )
|
|
|
|
{
|
|
|
|
stopImagePreview(); // just in case
|
|
|
|
|
|
|
|
// Check config
|
|
|
|
if ( !KGlobalSettings::showFilePreview( url() ) ) {
|
|
|
|
kdDebug(1203) << "Previews disabled for protocol " << url().protocol() << endl;
|
|
|
|
emit imagePreviewFinished();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((d->bSoundPreviews = d->previewSettings.contains( "audio/" )) &&
|
|
|
|
!d->pSoundPlayer)
|
|
|
|
{
|
|
|
|
KLibFactory *factory = KLibLoader::self()->factory("konq_sound");
|
|
|
|
if (factory)
|
|
|
|
d->pSoundPlayer = static_cast<KonqSoundPlayer *>(
|
|
|
|
factory->create(this, 0, "KonqSoundPlayer"));
|
|
|
|
d->bSoundPreviews = (d->pSoundPlayer != 0L);
|
|
|
|
}
|
|
|
|
|
|
|
|
KFileItemList items;
|
|
|
|
for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
|
|
|
|
if ( force || !static_cast<KFileIVI *>( it )->hasValidThumbnail() )
|
|
|
|
items.append( static_cast<KFileIVI *>( it )->item() );
|
|
|
|
|
|
|
|
bool onlyAudio = true;
|
|
|
|
for ( QStringList::ConstIterator it = d->previewSettings.begin(); it != d->previewSettings.end(); ++it ) {
|
|
|
|
if ( (*it).startsWith( "audio/" ) )
|
|
|
|
d->bSoundPreviews = true;
|
|
|
|
else
|
|
|
|
onlyAudio = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( items.isEmpty() || onlyAudio ) {
|
|
|
|
emit imagePreviewFinished();
|
|
|
|
return; // don't start the preview job if not really necessary
|
|
|
|
}
|
|
|
|
|
|
|
|
int iconSize = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
|
|
|
|
int size;
|
|
|
|
|
|
|
|
d->bBoostPreview = boostPreview();
|
|
|
|
size = previewIconSize( iconSize );
|
|
|
|
|
|
|
|
if ( !d->bBoostPreview )
|
|
|
|
iconSize /= 2;
|
|
|
|
|
|
|
|
d->pPreviewJob = KIO::filePreview( items, size, size, iconSize,
|
|
|
|
m_pSettings->textPreviewIconTransparency(), true /* scale */,
|
|
|
|
true /* save */, &(d->previewSettings) );
|
|
|
|
connect( d->pPreviewJob, SIGNAL( gotPreview( const KFileItem *, const QPixmap & ) ),
|
|
|
|
this, SLOT( slotPreview( const KFileItem *, const QPixmap & ) ) );
|
|
|
|
connect( d->pPreviewJob, SIGNAL( result( KIO::Job * ) ),
|
|
|
|
this, SLOT( slotPreviewResult() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::stopImagePreview()
|
|
|
|
{
|
|
|
|
if (d->pPreviewJob)
|
|
|
|
{
|
|
|
|
d->pPreviewJob->kill();
|
|
|
|
d->pPreviewJob = 0;
|
|
|
|
// Now that previews are updated in-place, calling
|
|
|
|
// arrangeItemsInGrid() here is not needed anymore
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KonqIconViewWidget::isPreviewRunning() const
|
|
|
|
{
|
|
|
|
return d->pPreviewJob;
|
|
|
|
}
|
|
|
|
|
|
|
|
KFileItemList KonqIconViewWidget::selectedFileItems()
|
|
|
|
{
|
|
|
|
KFileItemList lstItems;
|
|
|
|
|
|
|
|
QIconViewItem *it = firstItem();
|
|
|
|
for (; it; it = it->nextItem() )
|
|
|
|
if ( it->isSelected() ) {
|
|
|
|
KFileItem *fItem = (static_cast<KFileIVI *>(it))->item();
|
|
|
|
lstItems.append( fItem );
|
|
|
|
}
|
|
|
|
return lstItems;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::slotDropped( QDropEvent *ev, const QValueList<QIconDragItem> & )
|
|
|
|
{
|
|
|
|
// Drop on background
|
|
|
|
KURL dirURL = url();
|
|
|
|
if ( m_rootItem ) {
|
|
|
|
bool dummy;
|
|
|
|
dirURL = m_rootItem->mostLocalURL(dummy);
|
|
|
|
}
|
|
|
|
KonqOperations::doDrop( m_rootItem /* may be 0L */, dirURL, ev, this );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::slotAboutToCreate(const QPoint &, const QValueList<KIO::CopyInfo> &)
|
|
|
|
{
|
|
|
|
// Do nothing :-)
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::drawBackground( QPainter *p, const QRect &r )
|
|
|
|
{
|
|
|
|
drawBackground(p, r, r.topLeft());
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::drawBackground( QPainter *p, const QRect &r , const QPoint &pt)
|
|
|
|
{
|
|
|
|
const QPixmap *pm = backgroundPixmap();
|
|
|
|
bool hasPixmap = pm && !pm->isNull();
|
|
|
|
if ( !hasPixmap ) {
|
|
|
|
pm = viewport()->backgroundPixmap();
|
|
|
|
hasPixmap = pm && !pm->isNull();
|
|
|
|
}
|
|
|
|
|
|
|
|
QRect rtgt(r);
|
|
|
|
rtgt.moveTopLeft(pt);
|
|
|
|
if (!hasPixmap && backgroundMode() != NoBackground) {
|
|
|
|
p->fillRect(rtgt, viewport()->backgroundColor());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hasPixmap) {
|
|
|
|
int ax = (r.x() + contentsX() + leftMargin()) % pm->width();
|
|
|
|
int ay = (r.y() + contentsY() + topMargin()) % pm->height();
|
|
|
|
p->drawTiledPixmap(rtgt, *pm, QPoint(ax, ay));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QDragObject * KonqIconViewWidget::dragObject()
|
|
|
|
{
|
|
|
|
if ( !currentItem() )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return konqDragObject( viewport() );
|
|
|
|
}
|
|
|
|
|
|
|
|
KonqIconDrag * KonqIconViewWidget::konqDragObject( QWidget * dragSource )
|
|
|
|
{
|
|
|
|
//kdDebug(1203) << "KonqIconViewWidget::konqDragObject" << endl;
|
|
|
|
|
|
|
|
KonqIconDrag2 * drag = new KonqIconDrag2( dragSource );
|
|
|
|
QIconViewItem *primaryItem = currentItem();
|
|
|
|
// Append all items to the drag object
|
|
|
|
for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() ) {
|
|
|
|
if ( it->isSelected() ) {
|
|
|
|
if (!primaryItem)
|
|
|
|
primaryItem = it;
|
|
|
|
KFileItem* fileItem = (static_cast<KFileIVI *>(it))->item();
|
|
|
|
KURL url = fileItem->url();
|
|
|
|
bool dummy;
|
|
|
|
KURL mostLocalURL = fileItem->mostLocalURL(dummy);
|
|
|
|
QString itemURL = KURLDrag::urlToString(url);
|
|
|
|
kdDebug(1203) << "itemURL=" << itemURL << endl;
|
|
|
|
QIconDragItem id;
|
|
|
|
id.setData( QCString(itemURL.latin1()) );
|
|
|
|
drag->append( id,
|
|
|
|
QRect( it->pixmapRect(false).topLeft() - m_mousePos,
|
|
|
|
it->pixmapRect().size() ),
|
|
|
|
QRect( it->textRect(false).topLeft() - m_mousePos,
|
|
|
|
it->textRect().size() ),
|
|
|
|
itemURL, mostLocalURL );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (primaryItem)
|
|
|
|
drag->setPixmap( *primaryItem->pixmap(), m_mousePos - primaryItem->pixmapRect(false).topLeft() );
|
|
|
|
|
|
|
|
return drag;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::contentsDragEnterEvent( QDragEnterEvent *e )
|
|
|
|
{
|
|
|
|
if ( e->provides( "text/uri-list" ) )
|
|
|
|
{
|
|
|
|
QByteArray payload = e->encodedData( "text/uri-list" );
|
|
|
|
if ( !payload.size() )
|
|
|
|
kdError() << "Empty data !" << endl;
|
|
|
|
// Cache the URLs, since we need them every time we move over a file
|
|
|
|
// (see KFileIVI)
|
|
|
|
bool ok = KURLDrag::decode( e, m_lstDragURLs );
|
|
|
|
if( !ok )
|
|
|
|
kdError() << "Couldn't decode urls dragged !" << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
KURL::List uriList;
|
|
|
|
if ( KURLDrag::decode(e, uriList) )
|
|
|
|
{
|
|
|
|
if ( uriList.first().protocol() == "programs" )
|
|
|
|
{
|
|
|
|
e->ignore();
|
|
|
|
emit dragEntered( false );
|
|
|
|
d->bProgramsURLdrag = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KIconView::contentsDragEnterEvent( e );
|
|
|
|
emit dragEntered( true /*accepted*/ );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::contentsDragMoveEvent( QDragMoveEvent *e )
|
|
|
|
{
|
|
|
|
if ( d->bProgramsURLdrag ) {
|
|
|
|
emit dragMove( false );
|
|
|
|
e->ignore();
|
|
|
|
cancelPendingHeldSignal();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QIconViewItem *item = findItem( e->pos() );
|
|
|
|
if ( e->source() != viewport() &&
|
|
|
|
!item && m_rootItem && !m_rootItem->isWritable() ) {
|
|
|
|
emit dragMove( false );
|
|
|
|
e->ignore();
|
|
|
|
cancelPendingHeldSignal();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
emit dragMove( true );
|
|
|
|
KIconView::contentsDragMoveEvent( e );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::contentsDragLeaveEvent( QDragLeaveEvent *e )
|
|
|
|
{
|
|
|
|
d->bProgramsURLdrag = false;
|
|
|
|
KIconView::contentsDragLeaveEvent(e);
|
|
|
|
emit dragLeft();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KonqIconViewWidget::setItemColor( const QColor &c )
|
|
|
|
{
|
|
|
|
iColor = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
QColor KonqIconViewWidget::itemColor() const
|
|
|
|
{
|
|
|
|
return iColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::disableIcons( const KURL::List & lst )
|
|
|
|
{
|
|
|
|
for ( QIconViewItem *kit = firstItem(); kit; kit = kit->nextItem() )
|
|
|
|
{
|
|
|
|
bool bFound = false;
|
|
|
|
// Wow. This is ugly. Matching two lists together....
|
|
|
|
// Some sorting to optimise this would be a good idea ?
|
|
|
|
for (KURL::List::ConstIterator it = lst.begin(); !bFound && it != lst.end(); ++it)
|
|
|
|
{
|
|
|
|
if ( static_cast<KFileIVI *>( kit )->item()->url() == *it )
|
|
|
|
{
|
|
|
|
bFound = true;
|
|
|
|
// maybe remove "it" from lst here ?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static_cast<KFileIVI *>( kit )->setDisabled( bFound );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::slotSelectionChanged()
|
|
|
|
{
|
|
|
|
// This code is very related to ListViewBrowserExtension::updateActions
|
|
|
|
int canCopy = 0;
|
|
|
|
int canDel = 0;
|
|
|
|
int canTrash = 0;
|
|
|
|
bool bInTrash = false;
|
|
|
|
int iCount = 0;
|
|
|
|
|
|
|
|
for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
|
|
|
|
{
|
|
|
|
if ( it->isSelected() )
|
|
|
|
{
|
|
|
|
iCount++;
|
|
|
|
canCopy++;
|
|
|
|
|
|
|
|
KFileItem *item = ( static_cast<KFileIVI *>( it ) )->item();
|
|
|
|
KURL url = item->url();
|
|
|
|
QString local_path = item->localPath();
|
|
|
|
|
|
|
|
if ( url.directory(false) == KGlobalSettings::trashPath() )
|
|
|
|
bInTrash = true;
|
|
|
|
if ( KProtocolInfo::supportsDeleting( url ) )
|
|
|
|
canDel++;
|
|
|
|
if ( !local_path.isEmpty() )
|
|
|
|
canTrash++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
emit enableAction( "cut", canDel > 0 );
|
|
|
|
emit enableAction( "copy", canCopy > 0 );
|
|
|
|
emit enableAction( "trash", canDel > 0 && !bInTrash && canTrash==canDel );
|
|
|
|
emit enableAction( "del", canDel > 0 );
|
|
|
|
emit enableAction( "properties", iCount > 0 && KPropertiesDialog::canDisplay( selectedFileItems() ) );
|
|
|
|
emit enableAction( "editMimeType", ( iCount == 1 ) );
|
|
|
|
emit enableAction( "rename", ( iCount == 1) && !bInTrash );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::renameCurrentItem()
|
|
|
|
{
|
|
|
|
if ( currentItem() )
|
|
|
|
currentItem()->rename();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::renameSelectedItem()
|
|
|
|
{
|
|
|
|
kdDebug(1203) << " -- KonqIconViewWidget::renameSelectedItem() -- " << endl;
|
|
|
|
QIconViewItem * item = 0L;
|
|
|
|
QIconViewItem *it = firstItem();
|
|
|
|
for (; it; it = it->nextItem() )
|
|
|
|
if ( it->isSelected() && !item )
|
|
|
|
{
|
|
|
|
item = it;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!item)
|
|
|
|
{
|
|
|
|
Q_ASSERT(item);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
item->rename();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::cutSelection()
|
|
|
|
{
|
|
|
|
kdDebug(1203) << " -- KonqIconViewWidget::cutSelection() -- " << endl;
|
|
|
|
KonqIconDrag * obj = konqDragObject( /* no parent ! */ );
|
|
|
|
obj->setMoveSelection( true );
|
|
|
|
QApplication::clipboard()->setData( obj );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::copySelection()
|
|
|
|
{
|
|
|
|
kdDebug(1203) << " -- KonqIconViewWidget::copySelection() -- " << endl;
|
|
|
|
KonqIconDrag * obj = konqDragObject( /* no parent ! */ );
|
|
|
|
QApplication::clipboard()->setData( obj );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::pasteSelection()
|
|
|
|
{
|
|
|
|
paste( url() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::paste( const KURL &url )
|
|
|
|
{
|
|
|
|
KonqOperations::doPaste( this, url );
|
|
|
|
}
|
|
|
|
|
|
|
|
KURL::List KonqIconViewWidget::selectedUrls()
|
|
|
|
{
|
|
|
|
return selectedUrls( UserVisibleUrls );
|
|
|
|
}
|
|
|
|
|
|
|
|
KURL::List KonqIconViewWidget::selectedUrls( UrlFlags flags ) const
|
|
|
|
{
|
|
|
|
KURL::List lstURLs;
|
|
|
|
bool dummy;
|
|
|
|
for ( QIconViewItem *it = firstItem(); it; it = it->nextItem() )
|
|
|
|
if ( it->isSelected() ) {
|
|
|
|
KFileItem* item = (static_cast<KFileIVI *>( it ))->item();
|
|
|
|
lstURLs.append( flags == MostLocalUrls ? item->mostLocalURL( dummy ) : item->url() );
|
|
|
|
}
|
|
|
|
return lstURLs;
|
|
|
|
}
|
|
|
|
|
|
|
|
QRect KonqIconViewWidget::iconArea() const
|
|
|
|
{
|
|
|
|
return m_IconRect;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::setIconArea(const QRect &rect)
|
|
|
|
{
|
|
|
|
m_IconRect = rect;
|
|
|
|
}
|
|
|
|
|
|
|
|
int KonqIconViewWidget::lineupMode() const
|
|
|
|
{
|
|
|
|
return m_LineupMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::setLineupMode(int mode)
|
|
|
|
{
|
|
|
|
m_LineupMode = mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KonqIconViewWidget::sortDirectoriesFirst() const
|
|
|
|
{
|
|
|
|
return m_bSortDirsFirst;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::setSortDirectoriesFirst( bool b )
|
|
|
|
{
|
|
|
|
m_bSortDirsFirst = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::contentsMouseMoveEvent( QMouseEvent *e )
|
|
|
|
{
|
|
|
|
if ( (d->pSoundPlayer && d->pSoundPlayer->isPlaying()) || (d->pSoundTimer && d->pSoundTimer->isActive()))
|
|
|
|
{
|
|
|
|
// The following call is SO expensive (the ::widgetAt call eats up to 80%
|
|
|
|
// of the mouse move cpucycles!), so it's mandatory to place that function
|
|
|
|
// under strict checks, such as d->pSoundPlayer->isPlaying()
|
|
|
|
if ( QApplication::widgetAt( QCursor::pos() ) != topLevelWidget() )
|
|
|
|
{
|
|
|
|
if (d->pSoundPlayer)
|
|
|
|
d->pSoundPlayer->stop();
|
|
|
|
d->pSoundItem = 0;
|
|
|
|
if (d->pSoundTimer && d->pSoundTimer->isActive())
|
|
|
|
d->pSoundTimer->stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
d->renameItem= false;
|
|
|
|
KIconView::contentsMouseMoveEvent( e );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::contentsDropEvent( QDropEvent * ev )
|
|
|
|
{
|
|
|
|
QIconViewItem *i = findItem( ev->pos() );
|
|
|
|
|
|
|
|
if ( ev->source() != viewport() &&
|
|
|
|
!i && m_rootItem && !m_rootItem->isWritable() ) {
|
|
|
|
ev->accept( false );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Short-circuit QIconView if Ctrl is pressed, so that it's possible
|
|
|
|
// to drop a file into its own parent widget to copy it.
|
|
|
|
if ( !i && (ev->action() == QDropEvent::Copy || ev->action() == QDropEvent::Link)
|
|
|
|
&& ev->source() && ev->source() == viewport())
|
|
|
|
{
|
|
|
|
// First we need to call QIconView though, to clear the drag shape
|
|
|
|
bool bMovable = itemsMovable();
|
|
|
|
setItemsMovable(false); // hack ? call it what you want :-)
|
|
|
|
KIconView::contentsDropEvent( ev );
|
|
|
|
setItemsMovable(bMovable);
|
|
|
|
|
|
|
|
QValueList<QIconDragItem> lst;
|
|
|
|
slotDropped(ev, lst);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
KIconView::contentsDropEvent( ev );
|
|
|
|
emit dropped(); // What is this for ? (David) KDE4: remove
|
|
|
|
}
|
|
|
|
// Don't do this here, it's too early !
|
|
|
|
// slotSaveIconPositions();
|
|
|
|
// If we want to save after the new file gets listed, though,
|
|
|
|
// we could reimplement contentsDropEvent in KDIconView and set m_bNeedSave. Bah.
|
|
|
|
|
|
|
|
// This signal is sent last because we need to ensure it is
|
|
|
|
// taken in account when all the slots triggered by the dropped() signal
|
|
|
|
// are executed. This way we know that the Drag and Drop is truely finished
|
|
|
|
emit dragFinished();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::doubleClickTimeout()
|
|
|
|
{
|
|
|
|
d->renameItem= true;
|
|
|
|
mousePressChangeValue();
|
|
|
|
if ( d->releaseMouseEvent )
|
|
|
|
{
|
|
|
|
QMouseEvent e( QEvent::MouseButtonPress,d->mousePos , 1, d->mouseState);
|
|
|
|
QIconViewItem* item = findItem( e.pos() );
|
|
|
|
KURL url;
|
|
|
|
if ( item )
|
|
|
|
{
|
|
|
|
url= ( static_cast<KFileIVI *>( item ) )->item()->url();
|
|
|
|
bool brenameTrash =false;
|
|
|
|
if ( url.isLocalFile() && (url.directory(false) == KGlobalSettings::trashPath() || url.path(1).startsWith(KGlobalSettings::trashPath())))
|
|
|
|
brenameTrash = true;
|
|
|
|
|
|
|
|
if ( url.isLocalFile() && !brenameTrash && d->renameItem && m_pSettings->renameIconDirectly() && e.button() == LeftButton && item->textRect( false ).contains(e.pos()))
|
|
|
|
{
|
|
|
|
if( d->pActivateDoubleClick->isActive () )
|
|
|
|
d->pActivateDoubleClick->stop();
|
|
|
|
item->rename();
|
|
|
|
m_bMousePressed = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QMouseEvent e( QEvent::MouseMove,d->mousePos , 1, d->mouseState);
|
|
|
|
KIconView::contentsMousePressEvent( &e );
|
|
|
|
}
|
|
|
|
if( d->pActivateDoubleClick->isActive() )
|
|
|
|
d->pActivateDoubleClick->stop();
|
|
|
|
|
|
|
|
d->releaseMouseEvent = false;
|
|
|
|
d->renameItem= false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::wheelEvent(QWheelEvent* e)
|
|
|
|
{
|
|
|
|
// when scrolling with mousewheel, stop possible pending filetip
|
|
|
|
d->pFileTip->setItem( 0 );
|
|
|
|
|
|
|
|
if (e->state() == ControlButton)
|
|
|
|
{
|
|
|
|
if (e->delta() >= 0)
|
|
|
|
{
|
|
|
|
emit incIconSize();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
emit decIconSize();
|
|
|
|
}
|
|
|
|
e->accept();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
KIconView::wheelEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::leaveEvent( QEvent *e )
|
|
|
|
{
|
|
|
|
// when leaving the widget, stop possible pending filetip and icon effect
|
|
|
|
slotOnViewport();
|
|
|
|
|
|
|
|
KIconView::leaveEvent(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::mousePressChangeValue()
|
|
|
|
{
|
|
|
|
//kdDebug(1203) << "KonqIconViewWidget::contentsMousePressEvent" << endl;
|
|
|
|
m_bMousePressed = true;
|
|
|
|
if (d->pSoundPlayer)
|
|
|
|
d->pSoundPlayer->stop();
|
|
|
|
d->bSoundItemClicked = true;
|
|
|
|
d->firstClick = false;
|
|
|
|
|
|
|
|
// Once we click on the item, we don't want a tooltip
|
|
|
|
// Fixes part of #86968
|
|
|
|
d->pFileTip->setItem( 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::contentsMousePressEvent( QMouseEvent *e )
|
|
|
|
{
|
|
|
|
if(d->pActivateDoubleClick && d->pActivateDoubleClick->isActive ())
|
|
|
|
d->pActivateDoubleClick->stop();
|
|
|
|
QIconViewItem* item = findItem( e->pos() );
|
|
|
|
m_mousePos = e->pos();
|
|
|
|
KURL url;
|
|
|
|
if ( item )
|
|
|
|
{
|
|
|
|
url = ( static_cast<KFileIVI *>( item ) )->item()->url();
|
|
|
|
bool brenameTrash =false;
|
|
|
|
if ( url.isLocalFile() && (url.directory(false) == KGlobalSettings::trashPath() || url.path(1).startsWith(KGlobalSettings::trashPath())))
|
|
|
|
brenameTrash = true;
|
|
|
|
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))
|
|
|
|
{
|
|
|
|
d->firstClick = true;
|
|
|
|
d->mousePos = e->pos();
|
|
|
|
d->mouseState = e->state();
|
|
|
|
if (!d->pActivateDoubleClick)
|
|
|
|
{
|
|
|
|
d->pActivateDoubleClick = new QTimer(this);
|
|
|
|
connect(d->pActivateDoubleClick, SIGNAL(timeout()), this, SLOT(doubleClickTimeout()));
|
|
|
|
}
|
|
|
|
if( d->pActivateDoubleClick->isActive () )
|
|
|
|
d->pActivateDoubleClick->stop();
|
|
|
|
else
|
|
|
|
d->pActivateDoubleClick->start(QApplication::doubleClickInterval());
|
|
|
|
d->releaseMouseEvent = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
d->renameItem= false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
d->renameItem= false;
|
|
|
|
mousePressChangeValue();
|
|
|
|
if(d->pActivateDoubleClick && d->pActivateDoubleClick->isActive())
|
|
|
|
d->pActivateDoubleClick->stop();
|
|
|
|
KIconView::contentsMousePressEvent( e );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::contentsMouseReleaseEvent( QMouseEvent *e )
|
|
|
|
{
|
|
|
|
KIconView::contentsMouseReleaseEvent( e );
|
|
|
|
if(d->releaseMouseEvent && d->pActivateDoubleClick && d->pActivateDoubleClick->isActive ())
|
|
|
|
d->pActivateDoubleClick->stop();
|
|
|
|
slotSelectionChanged();
|
|
|
|
d->releaseMouseEvent = true;
|
|
|
|
m_bMousePressed = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::slotSaveIconPositions()
|
|
|
|
{
|
|
|
|
// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
|
|
|
// This code is currently not used but left in for compatibility reasons.
|
|
|
|
// It can be removed in KDE 4.0
|
|
|
|
// Saving of desktop icon positions is now done in KDIconView::saveIconPositions()
|
|
|
|
// in kdebase/kdesktop/kdiconview.cc
|
|
|
|
// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
|
|
|
|
|
|
|
if ( m_dotDirectoryPath.isEmpty() )
|
|
|
|
return;
|
|
|
|
if ( !m_bDesktop )
|
|
|
|
return; // Currently not available in Konqueror
|
|
|
|
kdDebug(1214) << "KonqIconViewWidget::slotSaveIconPositions" << endl;
|
|
|
|
KSimpleConfig dotDirectory( m_dotDirectoryPath );
|
|
|
|
QIconViewItem *it = firstItem();
|
|
|
|
if ( !it )
|
|
|
|
return; // No more icons. Maybe we're closing and they've been removed already
|
|
|
|
while ( it )
|
|
|
|
{
|
|
|
|
KFileIVI *ivi = static_cast<KFileIVI *>( it );
|
|
|
|
KFileItem *item = ivi->item();
|
|
|
|
|
|
|
|
dotDirectory.setGroup( QString( m_iconPositionGroupPrefix ).append( item->url().fileName() ) );
|
|
|
|
kdDebug(1214) << "KonqIconViewWidget::slotSaveIconPositions " << item->url().fileName() << " " << it->x() << " " << it->y() << endl;
|
|
|
|
dotDirectory.writeEntry( QString( "X %1" ).arg( width() ), it->x() );
|
|
|
|
dotDirectory.writeEntry( QString( "Y %1" ).arg( height() ), it->y() );
|
|
|
|
dotDirectory.writeEntry( "Exists", true );
|
|
|
|
|
|
|
|
it = it->nextItem();
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList groups = dotDirectory.groupList();
|
|
|
|
QStringList::ConstIterator gIt = groups.begin();
|
|
|
|
QStringList::ConstIterator gEnd = groups.end();
|
|
|
|
for (; gIt != gEnd; ++gIt )
|
|
|
|
if ( (*gIt).left( m_iconPositionGroupPrefix.length() ) == m_iconPositionGroupPrefix )
|
|
|
|
{
|
|
|
|
dotDirectory.setGroup( *gIt );
|
|
|
|
if ( dotDirectory.hasKey( "Exists" ) )
|
|
|
|
dotDirectory.deleteEntry( "Exists", false );
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdDebug(1214) << "KonqIconViewWidget::slotSaveIconPositions deleting group " << *gIt << endl;
|
|
|
|
dotDirectory.deleteGroup( *gIt );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dotDirectory.sync();
|
|
|
|
|
|
|
|
// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
|
|
|
// This code is currently not used but left in for compatibility reasons.
|
|
|
|
// It can be removed in KDE 4.0
|
|
|
|
// Saving of desktop icon positions is now done in KDIconView::saveIconPositions()
|
|
|
|
// in kdebase/kdesktop/kdiconview.cc
|
|
|
|
// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
|
|
|
}
|
|
|
|
|
|
|
|
// Adapted version of QIconView::insertInGrid, that works relative to
|
|
|
|
// m_IconRect, instead of the entire viewport.
|
|
|
|
|
|
|
|
void KonqIconViewWidget::insertInGrid(QIconViewItem *item)
|
|
|
|
{
|
|
|
|
if (0L == item)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!m_IconRect.isValid())
|
|
|
|
{
|
|
|
|
KIconView::insertInGrid(item);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QRegion r(m_IconRect);
|
|
|
|
QIconViewItem *i = firstItem();
|
|
|
|
int y = -1;
|
|
|
|
for (; i; i = i->nextItem() )
|
|
|
|
{
|
|
|
|
r = r.subtract(i->rect());
|
|
|
|
y = QMAX(y, i->y() + i->height());
|
|
|
|
}
|
|
|
|
|
|
|
|
QMemArray<QRect> rects = r.rects();
|
|
|
|
QMemArray<QRect>::Iterator it = rects.begin();
|
|
|
|
bool foundPlace = FALSE;
|
|
|
|
for (; it != rects.end(); ++it)
|
|
|
|
{
|
|
|
|
QRect rect = *it;
|
|
|
|
if (rect.width() >= item->width() && rect.height() >= item->height())
|
|
|
|
{
|
|
|
|
int sx = 0, sy = 0;
|
|
|
|
if (rect.width() >= item->width() + spacing())
|
|
|
|
sx = spacing();
|
|
|
|
if (rect.height() >= item->height() + spacing())
|
|
|
|
sy = spacing();
|
|
|
|
item->move(rect.x() + sx, rect.y() + sy);
|
|
|
|
foundPlace = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!foundPlace)
|
|
|
|
item->move(m_IconRect.topLeft());
|
|
|
|
|
|
|
|
//item->dirty = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The algorithm used for lineing up the icons could be called
|
|
|
|
* "beating flat the icon field". Imagine the icon field to be some height
|
|
|
|
* field on a regular grid, with the height being the number of icons in
|
|
|
|
* each grid element. Now imagine slamming on the field with a shovel or
|
|
|
|
* some other flat surface. The high peaks will be flattened and spread out
|
|
|
|
* over their adjacent areas. This is basically what the algorithm tries to
|
|
|
|
* simulate.
|
|
|
|
*
|
|
|
|
* First, the icons are binned to a grid of the desired size. If all bins
|
|
|
|
* are containing at most one icon, we're done, of course. We just have to
|
|
|
|
* move all icons to the center of each grid element.
|
|
|
|
* For each bin which has more than one icon in it, we calculate 4
|
|
|
|
* "friction coefficients", one for each cardinal direction. The friction
|
|
|
|
* coefficient of a direction is the number of icons adjacent in that
|
|
|
|
* direction. The idea is that this number is somewhat a measure in which
|
|
|
|
* direction the icons should flow: icons flow in the direction of lowest
|
|
|
|
* friction coefficient. We move a maximum of one icon per bin and loop over
|
|
|
|
* all bins. This procedure is repeated some maximum number of times or until
|
|
|
|
* no icons are moved anymore.
|
|
|
|
*
|
|
|
|
* I don't know if this algorithm is good or bad, I don't even know if it will
|
|
|
|
* work all the time. It seems a correct thing to do, however, and it seems to
|
|
|
|
* work particularly well. In any case, the number of runs is limited so there
|
|
|
|
* can be no races.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void KonqIconViewWidget::lineupIcons()
|
|
|
|
{
|
|
|
|
// even if there are no items yet, calculate the maxItemWidth to have the correct
|
|
|
|
// item rect when we insert new items
|
|
|
|
|
|
|
|
// Create a grid of (ny x nx) bins.
|
|
|
|
int x0, y0, dx, dy, nx, ny;
|
|
|
|
gridValues( &x0, &y0, &dx, &dy, &nx, &ny );
|
|
|
|
|
|
|
|
int itemWidth = dx - spacing();
|
|
|
|
bool newItemWidth = false;
|
|
|
|
if ( maxItemWidth() != itemWidth ) {
|
|
|
|
newItemWidth = true;
|
|
|
|
setMaxItemWidth( itemWidth );
|
|
|
|
setFont( font() ); // Force calcRect()
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !firstItem() ) {
|
|
|
|
kdDebug(1203) << "No icons at all ?\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int iconSize = m_size ? m_size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
|
|
|
|
|
|
|
|
typedef QValueList<QIconViewItem*> Bin;
|
|
|
|
Bin*** bins = new Bin**[nx];
|
|
|
|
int i;
|
|
|
|
int j;
|
|
|
|
for ( i = 0; i < nx ; i++ ) {
|
|
|
|
bins[i] = new Bin*[ny];
|
|
|
|
for ( j = 0; j < ny; j++ )
|
|
|
|
bins[i][j] = 0L;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert items into grid
|
|
|
|
int textHeight = iconTextHeight() * fontMetrics().height();
|
|
|
|
|
|
|
|
for ( QIconViewItem* item = firstItem(); item; item = item->nextItem() ) {
|
|
|
|
int x = item->x() + item->width() / 2 - x0;
|
|
|
|
int y = item->pixmapRect( false ).bottom() - iconSize / 2
|
|
|
|
- ( dy - ( iconSize + textHeight ) ) / 2 - y0;
|
|
|
|
int posX = QMIN( nx-1, QMAX( 0, x / dx ) );
|
|
|
|
int posY = QMIN( ny-1, QMAX( 0, y / dy ) );
|
|
|
|
|
|
|
|
if ( !bins[posX][posY] )
|
|
|
|
bins[posX][posY] = new Bin;
|
|
|
|
bins[posX][posY]->prepend( item );
|
|
|
|
}
|
|
|
|
|
|
|
|
// The shuffle code
|
|
|
|
int n, k;
|
|
|
|
const int infinity = 10000;
|
|
|
|
int nmoves = 1;
|
|
|
|
for ( n = 0; n < 30 && nmoves > 0; n++ ) {
|
|
|
|
nmoves = 0;
|
|
|
|
for ( i = 0; i < nx; i++ ) {
|
|
|
|
for ( j = 0; j < ny; j++ ) {
|
|
|
|
if ( !bins[i][j] || ( bins[i][j]->count() <= 1 ) )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Calculate the 4 "friction coefficients".
|
|
|
|
int tf = 0, bf = 0, lf = 0, rf = 0;
|
|
|
|
for ( k = j-1; k >= 0 && bins[i][k] && bins[i][k]->count(); k-- )
|
|
|
|
tf += bins[i][k]->count();
|
|
|
|
if ( k == -1 )
|
|
|
|
tf += infinity;
|
|
|
|
|
|
|
|
for ( k = j+1; k < ny && bins[i][k] && bins[i][k]->count(); k++ )
|
|
|
|
bf += bins[i][k]->count();
|
|
|
|
if ( k == ny )
|
|
|
|
bf += infinity;
|
|
|
|
|
|
|
|
for ( k = i-1; k >= 0 && bins[k][j] && bins[k][j]->count(); k-- )
|
|
|
|
lf += bins[k][j]->count();
|
|
|
|
if ( k == -1 )
|
|
|
|
lf += infinity;
|
|
|
|
|
|
|
|
for ( k = i+1; k < nx && bins[k][j] && bins[k][j]->count(); k++ )
|
|
|
|
rf += bins[k][j]->count();
|
|
|
|
if ( k == nx )
|
|
|
|
rf += infinity;
|
|
|
|
|
|
|
|
// If we are stuck between walls, continue
|
|
|
|
if ( tf >= infinity && bf >= infinity &&
|
|
|
|
lf >= infinity && rf >= infinity )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Is there a preferred lineup direction?
|
|
|
|
if ( m_LineupMode == LineupHorizontal ) {
|
|
|
|
tf += infinity;
|
|
|
|
bf += infinity;
|
|
|
|
}
|
|
|
|
else if ( m_LineupMode == LineupVertical ) {
|
|
|
|
lf += infinity;
|
|
|
|
rf += infinity;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move one item in the direction of the least friction
|
|
|
|
QIconViewItem* movedItem;
|
|
|
|
Bin* items = bins[i][j];
|
|
|
|
|
|
|
|
int mini = QMIN( QMIN( tf, bf ), QMIN( lf, rf ) );
|
|
|
|
if ( tf == mini ) {
|
|
|
|
// move top item in (i,j) to (i,j-1)
|
|
|
|
Bin::iterator it = items->begin();
|
|
|
|
movedItem = *it;
|
|
|
|
for ( ++it; it != items->end(); ++it ) {
|
|
|
|
if ( (*it)->y() < movedItem->y() )
|
|
|
|
movedItem = *it;
|
|
|
|
}
|
|
|
|
items->remove( movedItem );
|
|
|
|
if ( !bins[i][j-1] )
|
|
|
|
bins[i][j-1] = new Bin;
|
|
|
|
bins[i][j-1]->prepend( movedItem );
|
|
|
|
}
|
|
|
|
else if ( bf ==mini ) {
|
|
|
|
// move bottom item in (i,j) to (i,j+1)
|
|
|
|
Bin::iterator it = items->begin();
|
|
|
|
movedItem = *it;
|
|
|
|
for ( ++it; it != items->end(); ++it ) {
|
|
|
|
if ( (*it)->y() > movedItem->y() )
|
|
|
|
movedItem = *it;
|
|
|
|
}
|
|
|
|
items->remove( movedItem );
|
|
|
|
if ( !bins[i][j+1] )
|
|
|
|
bins[i][j+1] = new Bin;
|
|
|
|
bins[i][j+1]->prepend( movedItem );
|
|
|
|
}
|
|
|
|
else if ( lf == mini )
|
|
|
|
{
|
|
|
|
// move left item in (i,j) to (i-1,j)
|
|
|
|
Bin::iterator it = items->begin();
|
|
|
|
movedItem = *it;
|
|
|
|
for ( ++it; it != items->end(); ++it ) {
|
|
|
|
if ( (*it)->x() < movedItem->x() )
|
|
|
|
movedItem = *it;
|
|
|
|
}
|
|
|
|
items->remove( movedItem );
|
|
|
|
if ( !bins[i-1][j] )
|
|
|
|
bins[i-1][j] = new Bin;
|
|
|
|
bins[i-1][j]->prepend( movedItem );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// move right item in (i,j) to (i+1,j)
|
|
|
|
Bin::iterator it = items->begin();
|
|
|
|
movedItem = *it;
|
|
|
|
for ( ++it; it != items->end(); ++it ) {
|
|
|
|
if ( (*it)->x() > movedItem->x() )
|
|
|
|
movedItem = *it;
|
|
|
|
}
|
|
|
|
items->remove( movedItem );
|
|
|
|
if ( !bins[i+1][j] )
|
|
|
|
bins[i+1][j] = new Bin;
|
|
|
|
bins[i+1][j]->prepend( movedItem );
|
|
|
|
}
|
|
|
|
nmoves++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Perform the actual moving
|
|
|
|
QRegion repaintRegion;
|
|
|
|
QValueList<QIconViewItem*> movedItems;
|
|
|
|
|
|
|
|
for ( i = 0; i < nx; i++ ) {
|
|
|
|
for ( j = 0; j < ny; j++ ) {
|
|
|
|
Bin* bin = bins[i][j];
|
|
|
|
if ( !bin )
|
|
|
|
continue;
|
|
|
|
if ( !bin->isEmpty() ) {
|
|
|
|
QIconViewItem* item = bin->first();
|
|
|
|
int newX = x0 + i*dx + spacing() +
|
|
|
|
QMAX(0, ( (dx-spacing()) - item->width() ) / 2); // pixmap can be larger as iconsize
|
|
|
|
// align all icons vertically to their text
|
|
|
|
int newY = y0 + j*dy + dy - spacing() - ( item->pixmapRect().bottom() + 2 + textHeight );
|
|
|
|
if ( item->x() != newX || item->y() != newY ) {
|
|
|
|
QRect oldRect = item->rect();
|
|
|
|
movedItems.prepend( item );
|
|
|
|
item->move( newX, newY );
|
|
|
|
if ( item->rect() != oldRect )
|
|
|
|
repaintRegion = repaintRegion.unite( oldRect );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delete bin;
|
|
|
|
bins[i][j] = 0L;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// repaint
|
|
|
|
if ( newItemWidth )
|
|
|
|
updateContents();
|
|
|
|
else {
|
|
|
|
// Repaint only repaintRegion...
|
|
|
|
QMemArray<QRect> rects = repaintRegion.rects();
|
|
|
|
for ( uint l = 0; l < rects.count(); l++ ) {
|
|
|
|
kdDebug( 1203 ) << "Repainting (" << rects[l].x() << ","
|
|
|
|
<< rects[l].y() << ")\n";
|
|
|
|
repaintContents( rects[l], false );
|
|
|
|
}
|
|
|
|
// Repaint icons that were moved
|
|
|
|
while ( !movedItems.isEmpty() ) {
|
|
|
|
repaintItem( movedItems.first() );
|
|
|
|
movedItems.remove( movedItems.first() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( i = 0; i < nx ; i++ ) {
|
|
|
|
delete [] bins[i];
|
|
|
|
}
|
|
|
|
delete [] bins;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::lineupIcons( QIconView::Arrangement arrangement )
|
|
|
|
{
|
|
|
|
int x0, y0, dx, dy, nxmax, nymax;
|
|
|
|
gridValues( &x0, &y0, &dx, &dy, &nxmax, &nymax );
|
|
|
|
int textHeight = iconTextHeight() * fontMetrics().height();
|
|
|
|
|
|
|
|
QRegion repaintRegion;
|
|
|
|
QValueList<QIconViewItem*> movedItems;
|
|
|
|
int nx = 0, ny = 0;
|
|
|
|
|
|
|
|
QIconViewItem* item;
|
|
|
|
for ( item = firstItem(); item; item = item->nextItem() ) {
|
|
|
|
int newX = x0 + nx*dx + spacing() +
|
|
|
|
QMAX(0, ( (dx-spacing()) - item->width() ) / 2); // icon can be larger as defined
|
|
|
|
// align all icons vertically to their text
|
|
|
|
int newY = y0 + ny*dy + dy - spacing() - ( item->pixmapRect().bottom() + 2 + textHeight );
|
|
|
|
if ( item->x() != newX || item->y() != newY ) {
|
|
|
|
QRect oldRect = item->rect();
|
|
|
|
movedItems.prepend( item );
|
|
|
|
item->move( newX, newY );
|
|
|
|
if ( item->rect() != oldRect )
|
|
|
|
repaintRegion = repaintRegion.unite( oldRect );
|
|
|
|
}
|
|
|
|
if ( arrangement == QIconView::LeftToRight ) {
|
|
|
|
nx++;
|
|
|
|
if ( nx >= nxmax ) {
|
|
|
|
ny++;
|
|
|
|
nx = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ny++;
|
|
|
|
if ( ny >= nymax ) {
|
|
|
|
nx++;
|
|
|
|
ny = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Repaint only repaintRegion...
|
|
|
|
QMemArray<QRect> rects = repaintRegion.rects();
|
|
|
|
for ( uint l = 0; l < rects.count(); l++ ) {
|
|
|
|
kdDebug( 1203 ) << "Repainting (" << rects[l].x() << ","
|
|
|
|
<< rects[l].y() << ")\n";
|
|
|
|
repaintContents( rects[l], false );
|
|
|
|
}
|
|
|
|
// Repaint icons that were moved
|
|
|
|
while ( !movedItems.isEmpty() ) {
|
|
|
|
repaintItem( movedItems.first() );
|
|
|
|
movedItems.remove( movedItems.first() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int KonqIconViewWidget::largestPreviewIconSize( int size ) const
|
|
|
|
{
|
|
|
|
int iconSize = size ? size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
|
|
|
|
|
|
|
|
if (iconSize < 28)
|
|
|
|
return 48;
|
|
|
|
if (iconSize < 40)
|
|
|
|
return 64;
|
|
|
|
if (iconSize < 60)
|
|
|
|
return 96;
|
|
|
|
if (iconSize < 120)
|
|
|
|
return 128;
|
|
|
|
|
|
|
|
return 192;
|
|
|
|
}
|
|
|
|
|
|
|
|
int KonqIconViewWidget::previewIconSize( int size ) const
|
|
|
|
{
|
|
|
|
int iconSize = size ? size : KGlobal::iconLoader()->currentSize( KIcon::Desktop );
|
|
|
|
|
|
|
|
if (!d->bBoostPreview)
|
|
|
|
return iconSize;
|
|
|
|
|
|
|
|
return largestPreviewIconSize( iconSize );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::visualActivate(QIconViewItem * item)
|
|
|
|
{
|
|
|
|
// Rect of the QIconViewItem.
|
|
|
|
QRect irect = item->rect();
|
|
|
|
|
|
|
|
// Rect of the QIconViewItem's pixmap area.
|
|
|
|
QRect rect = item->pixmapRect();
|
|
|
|
|
|
|
|
// Adjust to correct position. If this isn't done, the fact that the
|
|
|
|
// text may be wider than the pixmap puts us off-centre.
|
|
|
|
rect.moveBy(irect.x(), irect.y());
|
|
|
|
|
|
|
|
// Adjust for scrolling (David)
|
|
|
|
rect.moveBy( -contentsX(), -contentsY() );
|
|
|
|
|
|
|
|
KIconEffect::visualActivate(viewport(), rect, item->pixmap());
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::backgroundPixmapChange( const QPixmap & )
|
|
|
|
{
|
|
|
|
viewport()->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::setPreviewSettings( const QStringList& settings )
|
|
|
|
{
|
|
|
|
d->previewSettings = settings;
|
|
|
|
updatePreviewMimeTypes();
|
|
|
|
|
|
|
|
int size = m_size;
|
|
|
|
m_size = -1; // little trick to force grid change in setIcons
|
|
|
|
setIcons( size ); // force re-determining all icons
|
|
|
|
}
|
|
|
|
|
|
|
|
const QStringList& KonqIconViewWidget::previewSettings()
|
|
|
|
{
|
|
|
|
return d->previewSettings;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::setNewURL( const QString& url )
|
|
|
|
{
|
|
|
|
KURL u;
|
|
|
|
if ( url.startsWith( "/" ) )
|
|
|
|
u.setPath( url );
|
|
|
|
else
|
|
|
|
u = url;
|
|
|
|
setURL( u );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::setCaseInsensitiveSort( bool b )
|
|
|
|
{
|
|
|
|
d->bCaseInsensitive = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KonqIconViewWidget::caseInsensitiveSort() const
|
|
|
|
{
|
|
|
|
return d->bCaseInsensitive;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KonqIconViewWidget::canPreview( KFileItem* item )
|
|
|
|
{
|
|
|
|
if ( !KGlobalSettings::showFilePreview( url() ) )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if ( d->pPreviewMimeTypes == 0L )
|
|
|
|
updatePreviewMimeTypes();
|
|
|
|
|
|
|
|
return mimeTypeMatch( item->mimetype(), *( d->pPreviewMimeTypes ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KonqIconViewWidget::updatePreviewMimeTypes()
|
|
|
|
{
|
|
|
|
if ( d->pPreviewMimeTypes == 0L )
|
|
|
|
d->pPreviewMimeTypes = new QStringList;
|
|
|
|
else
|
|
|
|
d->pPreviewMimeTypes->clear();
|
|
|
|
|
|
|
|
// Load the list of plugins to determine which mimetypes are supported
|
|
|
|
KTrader::OfferList plugins = KTrader::self()->query("ThumbCreator");
|
|
|
|
KTrader::OfferList::ConstIterator it;
|
|
|
|
|
|
|
|
for ( it = plugins.begin(); it != plugins.end(); ++it ) {
|
|
|
|
if ( d->previewSettings.contains((*it)->desktopEntryName()) ) {
|
|
|
|
QStringList mimeTypes = (*it)->property("MimeTypes").toStringList();
|
|
|
|
for (QStringList::ConstIterator mt = mimeTypes.begin(); mt != mimeTypes.end(); ++mt)
|
|
|
|
d->pPreviewMimeTypes->append(*mt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "konq_iconviewwidget.moc"
|
|
|
|
|
|
|
|
/* vim: set et sw=4 ts=8 softtabstop=4: */
|