Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit 6e329eaa authored by Scott Wheeler's avatar Scott Wheeler

Rework the painting optimization junk. Rather than attempting to compress the

paint events, which never really worked properly, this hides the widget temporarily
which tricks the listview into adding items much more quickly.

This significantly speeds up start time, time for loading new items and avoids the
nasty bug where sometimes the list of items would be blank until it was clicked on.

BUG:87247

svn path=/trunk/kdemultimedia/juk/; revision=391481
parent 358efff0
......@@ -36,7 +36,6 @@ juk_SOURCES = \
mediafiles.cpp \
musicbrainzquery.cpp \
nowplaying.cpp \
painteater.cpp \
playermanager.cpp \
playlist.cpp \
playlistbox.cpp \
......
......@@ -86,9 +86,6 @@ void CollectionList::initialize(PlaylistCollection *collection)
PlaylistItem *CollectionList::createItem(const FileHandle &file, QListViewItem *, bool)
{
if(m_itemsDict.find(file.absFilePath()))
return 0;
PlaylistItem *item = new CollectionListItem(file);
if(!item->isValid()) {
......
......@@ -127,6 +127,8 @@ protected:
void addWatched(const QString &file) { m_dirWatch->addFile(file); }
void removeWatched(const QString &file) { m_dirWatch->removeFile(file); }
virtual bool hasItem(const QString &file) const { return m_itemsDict.find(file); }
signals:
void signalCollectionChanged();
......
/***************************************************************************
copyright : (C) 2004 by Scott Wheeler
email : wheeler@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. *
* *
***************************************************************************/
#include "painteater.h"
#include "playlist.h"
PaintEater::PaintEater(Playlist *list) :
QObject(list),
m_list(list),
m_allowOne(false),
m_previousHeight(0)
{
// We want to catch paint events for both the contents and the frame of
// our listview.
list->installEventFilter(this);
list->viewport()->installEventFilter(this);
}
bool PaintEater::eventFilter(QObject *o, QEvent *e)
{
if(e->type() == QEvent::Paint) {
// There are two cases where we want to let our viewport repaint
// itself -- if the actual contents have changed as indicated by
// m_allowOne being true, or if the height has changed indicating
// that we've either scrolled or resized the widget.
if(o == m_list->viewport()) {
if(m_allowOne) {
m_allowOne = false;
return false;
}
int newHeight = static_cast<QPaintEvent *>(e)->rect().top();
if(m_previousHeight != newHeight) {
m_previousHeight = newHeight;
return false;
}
}
else
m_allowOne = true;
if(m_list->count() < 20)
m_list->slotWeightDirty();
return true;
}
return false;
}
/***************************************************************************
copyright : (C) 2004 by Scott Wheeler
email : wheeler@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. *
* *
***************************************************************************/
#ifndef PAINTEATER_H
#define PAINTEATER_H
#include <qobject.h>
class Playlist;
/**
* This small class will block paint events on a Playlist until it passes out
* of scope. This is a bit of a hack to get around the fact that while
* Playlists are loading items painting takes much more time than loading the
* PlaylistItems.
*/
class PaintEater : public QObject
{
public:
PaintEater(Playlist *list);
protected:
virtual bool eventFilter(QObject *o, QEvent *e);
private:
Playlist *m_list;
bool m_allowOne;
int m_previousHeight;
};
#endif
......@@ -36,6 +36,7 @@
#include <qtooltip.h>
#include <qwidgetstack.h>
#include <qfile.h>
#include <qhbox.h>
#include <id3v1genres.h>
......@@ -55,7 +56,6 @@
#include "juk.h"
#include "tag.h"
#include "k3bexporter.h"
#include "painteater.h"
#include "upcomingplaylist.h"
#include "deletedialog.h"
#include "googlefetcher.h"
......@@ -323,7 +323,8 @@ Playlist::Playlist(PlaylistCollection *collection, const QString &name,
m_lastSelected(0),
m_playlistName(name),
m_rmbMenu(0),
m_toolTip(0)
m_toolTip(0),
m_blockDataChanged(false)
{
setup();
collection->setupPlaylist(this, iconName);
......@@ -345,7 +346,8 @@ Playlist::Playlist(PlaylistCollection *collection, const PlaylistItemList &items
m_lastSelected(0),
m_playlistName(name),
m_rmbMenu(0),
m_toolTip(0)
m_toolTip(0),
m_blockDataChanged(false)
{
setup();
collection->setupPlaylist(this, iconName);
......@@ -368,7 +370,8 @@ Playlist::Playlist(PlaylistCollection *collection, const QFileInfo &playlistFile
m_lastSelected(0),
m_fileName(playlistFile.absFilePath()),
m_rmbMenu(0),
m_toolTip(0)
m_toolTip(0),
m_blockDataChanged(false)
{
setup();
loadFile(m_fileName, playlistFile);
......@@ -389,7 +392,8 @@ Playlist::Playlist(PlaylistCollection *collection, bool delaySetup) :
m_searchEnabled(true),
m_lastSelected(0),
m_rmbMenu(0),
m_toolTip(0)
m_toolTip(0),
m_blockDataChanged(false)
{
setup();
......@@ -574,9 +578,13 @@ void Playlist::clearItem(PlaylistItem *item, bool emitChanged)
void Playlist::clearItems(const PlaylistItemList &items)
{
m_blockDataChanged = true;
for(PlaylistItemList::ConstIterator it = items.begin(); it != items.end(); ++it)
clearItem(*it, false);
m_blockDataChanged = false;
dataChanged();
}
......@@ -760,7 +768,9 @@ void Playlist::slotRenameFile()
emit signalEnableDirWatch(false);
m_blockDataChanged = true;
renamer.rename(items);
m_blockDataChanged = false;
dataChanged();
emit signalEnableDirWatch(true);
......@@ -818,9 +828,11 @@ void Playlist::slotGuessTagInfo(TagGuesser::Type type)
KApplication::setOverrideCursor(Qt::waitCursor);
PlaylistItemList items = selectedItems();
setCanDeletePlaylist(false);
m_blockDataChanged = true;
for(PlaylistItemList::Iterator it = items.begin(); it != items.end(); ++it) {
(*it)->guessTagInfo(type);
processEvents();
}
......@@ -830,6 +842,8 @@ void Playlist::slotGuessTagInfo(TagGuesser::Type type)
if(type == TagGuesser::FileName)
TagTransactionManager::instance()->commit();
m_blockDataChanged = false;
dataChanged();
setCanDeletePlaylist(true);
KApplication::restoreOverrideCursor();
......@@ -886,6 +900,13 @@ void Playlist::slotColumnResizeModeChanged()
SharedSettings::instance()->sync();
}
void Playlist::dataChanged()
{
if(m_blockDataChanged)
return;
PlaylistInterface::dataChanged();
}
////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////
......@@ -899,6 +920,9 @@ void Playlist::removeFromDisk(const PlaylistItemList &items)
files.append((*it)->file().absFilePath());
DeleteDialog dialog(this);
m_blockDataChanged = true;
if(dialog.confirmDeleteList(files)) {
bool shouldDelete = dialog.shouldDelete();
QStringList errorFiles;
......@@ -929,6 +953,9 @@ void Playlist::removeFromDisk(const PlaylistItemList &items)
KMessageBox::errorList(this, errorMsg, errorFiles);
}
}
m_blockDataChanged = false;
dataChanged();
}
}
......@@ -1042,6 +1069,8 @@ void Playlist::contentsDropEvent(QDropEvent *e)
else if(vp.y() < item->itemPos() + item->height() / 2)
item = static_cast<PlaylistItem *>(item->itemAbove());
m_blockDataChanged = true;
if(e->source() == this) {
// Since we're trying to arrange things manually, turn off sorting.
......@@ -1068,6 +1097,8 @@ void Playlist::contentsDropEvent(QDropEvent *e)
else
decode(e, item);
m_blockDataChanged = false;
dataChanged();
emit signalPlaylistItemsDropped(this);
KListView::contentsDropEvent(e);
......@@ -1107,9 +1138,14 @@ void Playlist::read(QDataStream &s)
s >> files;
QListViewItem *after = 0;
m_blockDataChanged = true;
for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it)
after = createItem(FileHandle(*it), after, false);
m_blockDataChanged = false;
dataChanged();
m_collection->setupPlaylist(this, "midi");
}
......@@ -1175,10 +1211,17 @@ void Playlist::addFiles(const QStringList &files, bool importPlaylists,
KApplication::setOverrideCursor(Qt::waitCursor);
PaintEater pe(this);
m_blockDataChanged = true;
for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it)
after = addFile(*it, importPlaylists, after);
FileHandleList queue;
const QStringList::ConstIterator filesEnd = files.end();
for(QStringList::ConstIterator it = files.begin(); it != filesEnd; ++it)
addFile(*it, queue, importPlaylists, &after);
addFileHelper(queue, importPlaylists, &after, true);
m_blockDataChanged = false;
slotWeightDirty();
dataChanged();
......@@ -1482,6 +1525,8 @@ void Playlist::loadFile(const QString &fileName, const QFileInfo &fileInfo)
m_disableColumnWidthUpdates = true;
m_blockDataChanged = true;
while(!stream.atEnd()) {
QString itemName = stream.readLine().stripWhiteSpace();
......@@ -1500,6 +1545,8 @@ void Playlist::loadFile(const QString &fileName, const QFileInfo &fileInfo)
}
}
m_blockDataChanged = false;
file.close();
dataChanged();
......@@ -1593,36 +1640,46 @@ void Playlist::calculateColumnWeights()
m_weightDirty.clear();
}
PlaylistItem *Playlist::addFile(const QString &file, bool importPlaylists,
PlaylistItem *after)
void Playlist::addFile(const QString &file, FileHandleList &files, bool importPlaylists,
PlaylistItem **after)
{
if(processEvents())
m_collection->dataChanged();
if(hasItem(file) && !m_allowDuplicates)
return;
processEvents();
addFileHelper(files, importPlaylists, after);
// Our biggest thing that we're fighting during startup is too many stats
// of files. Make sure that we don't do one here if it's not needed.
FileHandle cached = Cache::instance()->value(file);
if(!cached.isNull())
return createItem(cached, after, false);
const QFileInfo fileInfo = QDir::cleanDirPath(file);
if(!cached.isNull()) {
cached.tag();
files.append(cached);
return;
}
const QFileInfo fileInfo = QDir::cleanDirPath(file);
if(!fileInfo.exists())
return after;
return;
if(fileInfo.isFile() && fileInfo.isReadable()) {
if(MediaFiles::isMediaFile(file))
return createItem(FileHandle(fileInfo, fileInfo.absFilePath()), after, false);
if(importPlaylists && MediaFiles::isPlaylistFile(file) &&
!m_collection->containsPlaylistFile(fileInfo.absFilePath()))
{
new Playlist(m_collection, fileInfo);
return after;
if(MediaFiles::isMediaFile(file)) {
FileHandle f(fileInfo, fileInfo.absFilePath());
f.tag();
files.append(f);
}
}
if(importPlaylists && MediaFiles::isPlaylistFile(file) &&
!m_collection->containsPlaylistFile(fileInfo.absFilePath()))
{
new Playlist(m_collection, fileInfo);
return;
}
if(fileInfo.isDir()) {
// Resorting to the POSIX API because QDir::listEntries() stats every
......@@ -1634,21 +1691,54 @@ PlaylistItem *Playlist::addFile(const QString &file, bool importPlaylists,
struct dirent *dirEntry;
for(dirEntry = ::readdir(dir); dirEntry; dirEntry = ::readdir(dir)) {
if(strcmp(dirEntry->d_name, ".") != 0 && strcmp(dirEntry->d_name, "..") != 0)
after = addFile(fileInfo.filePath() + QDir::separator() +
QFile::decodeName(dirEntry->d_name), importPlaylists, after);
if(strcmp(dirEntry->d_name, ".") != 0 && strcmp(dirEntry->d_name, "..") != 0) {
addFile(fileInfo.filePath() + QDir::separator() + QFile::decodeName(dirEntry->d_name),
files, importPlaylists, after);
}
}
::closedir(dir);
}
else
{
else {
kdWarning(65432) << "Unable to open directory "
<< fileInfo.filePath()
<< ", make sure it is readable.\n";
}
}
}
return after;
void Playlist::addFileHelper(FileHandleList &files, bool loadPlaylists,
PlaylistItem **after, bool ignoreTimer)
{
static QTime time = QTime::currentTime();
// Process new items every 10 seconds, when we've loaded 1000 items, or when
// it's been requested in the API.
if(ignoreTimer || time.elapsed() > 10000 ||
(files.count() >= 1000 && time.elapsed() > 1000))
{
time.restart();
const bool focus = hasFocus();
const bool visible = isVisible() && files.count() > 20;
kdDebug(65432) << k_funcinfo << name() << " - " << files.count() << " - " << visible << endl;
if(visible)
m_collection->raiseDistraction();
const FileHandleList::ConstIterator filesEnd = files.end();
for(FileHandleList::ConstIterator it = files.begin(); it != filesEnd; ++it)
*after = createItem(*it, *after, loadPlaylists);
files.clear();
if(visible)
m_collection->lowerDistraction();
if(focus)
setFocus();
processEvents();
}
}
////////////////////////////////////////////////////////////////////////////////
......@@ -2103,7 +2193,7 @@ bool processEvents()
{
static QTime time = QTime::currentTime();
if(time.elapsed() > 200) {
if(time.elapsed() > 100) {
time.restart();
kapp->processEvents();
return true;
......
......@@ -401,6 +401,8 @@ public slots:
void slotColumnResizeModeChanged();
virtual void dataChanged();
protected:
/**
* Remove \a items from the playlist and disk. This will ignore items that
......@@ -425,6 +427,8 @@ protected:
virtual void insertItem(QListViewItem *item);
virtual void takeItem(QListViewItem *item);
virtual bool hasItem(const QString &file) const { return m_members.contains(file); }
void addColumn(const QString &label);
/**
......@@ -530,7 +534,10 @@ private:
*/
void calculateColumnWeights();
PlaylistItem *addFile(const QString &file, bool importPlaylists, PlaylistItem *after);
void addFile(const QString &file, FileHandleList &files, bool importPlaylists,
PlaylistItem **after);
void addFileHelper(FileHandleList &files, bool importPlaylists,
PlaylistItem **after, bool ignoreTimer = false);
void redisplaySearch() { setSearch(m_search); }
......@@ -671,6 +678,8 @@ private:
static int m_leftColumn;
static UpcomingPlaylist *m_upcomingPlaylist;
static QMap<int, PlaylistItem *> m_backMenuItems;
bool m_blockDataChanged;
};
bool processEvents();
......
......@@ -41,6 +41,7 @@
#include <kfiledialog.h>
#include <qwidgetstack.h>
#include <qhbox.h>
#define widget (kapp->mainWidget())
......@@ -59,7 +60,9 @@ PlaylistCollection::PlaylistCollection(QWidgetStack *playlistStack) :
m_playing(false),
m_showMorePlaylist(0),
m_belowShowMorePlaylist(0),
m_dynamicPlaylist(0)
m_dynamicPlaylist(0),
m_belowDistraction(0),
m_distraction(0)
{
m_actionHandler = new ActionHandler(this);
PlayerManager::instance()->setPlaylistInterface(this);
......@@ -542,6 +545,9 @@ QObject *PlaylistCollection::object() const
Playlist *PlaylistCollection::currentPlaylist() const
{
if(m_belowDistraction)
return m_belowDistraction;
if(m_upcomingPlaylist)
return m_upcomingPlaylist;
......@@ -571,6 +577,32 @@ void PlaylistCollection::raise(Playlist *playlist)
dataChanged();
}
void PlaylistCollection::raiseDistraction()
{
if(m_belowDistraction)
return;
m_belowDistraction = currentPlaylist();
if(!m_distraction) {
m_distraction = new QHBox(m_playlistStack);
m_playlistStack->addWidget(m_distraction);
}
m_playlistStack->raiseWidget(m_distraction);
}
void PlaylistCollection::lowerDistraction()
{
if(!m_distraction)
return;
if(m_belowDistraction)
m_playlistStack->raiseWidget(m_belowDistraction);
m_belowDistraction = 0;
}
////////////////////////////////////////////////////////////////////////////////
// protected methods
////////////////////////////////////////////////////////////////////////////////
......
......@@ -147,6 +147,14 @@ public:
*/
virtual void raise(Playlist *playlist);
/**
* This is used to put up a temporary widget over the top of the playlist
* stack. This is part of a trick to significantly speed up painting by
* hiding the playlist to which items are being added.
*/
void raiseDistraction();
void lowerDistraction();
class ActionHandler;
protected:
......@@ -188,6 +196,9 @@ private:
QGuardedPtr<SearchPlaylist> m_showMorePlaylist;
QGuardedPtr<Playlist> m_belowShowMorePlaylist;
QGuardedPtr<DynamicPlaylist> m_dynamicPlaylist;
QGuardedPtr<Playlist> m_belowDistraction;
QWidget *m_distraction;
};
/**
......
......@@ -113,7 +113,7 @@ public:
virtual void updateData()
{
if(m_parent && m_parent->m_currentPlaylist)
if(m_parent && m_parent->m_currentPlaylist && m_parent->isVisible())
m_parent->slotSetItems(m_parent->m_currentPlaylist->selectedItems());
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment