Commit 9d9cda29 authored by Michael Pyne's avatar Michael Pyne

Big huge update.

Make random play work better.  Before only the old style unused random list was
being updated when a playlist changed.  In addition, there are a lot of
improvements to the new cover support.
* You can drag-and-drop covers onto playlist items.  Right now only selected
  items are altered even if you drag onto a
  different item, so I'll have to change that.
* Clearing a cover from a track no longer removes it from every track using
  that cover.
* Replacing a track's cover works again as well.

I'm sure that both features could use more work so I guess it's back to the
grindstone for me, I just wish I had more time. :(
CCBUG: 94866

svn path=/trunk/KDE/kdemultimedia/juk/; revision=433499
parent 3fb62c28
......@@ -11,6 +11,7 @@ juk_SOURCES = \
collectionlist.cpp \
coverdialog.cpp \
coverdialogbase.ui \
covericonview.cpp \
coverinfo.cpp \
covermanager.cpp \
deletedialog.cpp \
......
......@@ -273,7 +273,7 @@ void CollectionList::contentsDropEvent(QDropEvent *e)
void CollectionList::contentsDragMoveEvent(QDragMoveEvent *e)
{
if(KURLDrag::canDecode(e) && e->source() != this)
if(canDecode(e) && e->source() != this)
e->accept(true);
else
e->accept(false);
......
......@@ -15,39 +15,21 @@
#include <klistview.h>
#include <kiconview.h>
#include <kiconviewsearchline.h>
#include <kiconloader.h>
#include <kapplication.h>
#include <kpopupmenu.h>
#include <klocale.h>
#include <qtimer.h>
#include <qtoolbutton.h>
#include "coverdialog.h"
#include "covericonview.h"
#include "covermanager.h"
#include "collectionlist.h"
namespace CoverDialogPrivate
{
class CoverIconViewItem;
};
class CoverDialogPrivate::CoverIconViewItem : public KIconViewItem
{
public:
CoverIconViewItem(coverKey id, QIconView *parent) :
KIconViewItem(parent), m_id(id)
{
CoverDataPtr data = CoverManager::coverInfo(id);
setText(QString("%1 - %2").arg(data->artist, data->album));
setPixmap(data->thumbnail());
}
coverKey id() const { return m_id; }
private:
coverKey m_id;
};
using CoverDialogPrivate::CoverIconViewItem;
using CoverUtility::CoverIconViewItem;
class AllArtistsListViewItem : public KListViewItem
{
......@@ -69,6 +51,9 @@ CoverDialog::CoverDialog(QWidget *parent) :
m_covers->setResizeMode(QIconView::Adjust);
m_covers->setGridX(140);
m_covers->setGridY(150);
m_searchLine->setIconView(m_covers);
m_clearSearch->setIconSet(SmallIconSet("locationbar_erase"));
}
CoverDialog::~CoverDialog()
......@@ -150,7 +135,7 @@ void CoverDialog::slotContextRequested(QIconViewItem *item, const QPoint &pt)
void CoverDialog::removeSelectedCover()
{
CoverIconViewItem *coverItem = static_cast<CoverIconViewItem *>(m_covers->currentItem());
CoverIconViewItem *coverItem = m_covers->currentItem();
if(!coverItem || !coverItem->isSelected()) {
kdWarning(65432) << "No item selected for removeSelectedCover.\n";
......
......@@ -8,8 +8,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>652</width>
<height>525</height>
<width>685</width>
<height>554</height>
</rect>
</property>
<property name="caption">
......@@ -63,24 +63,117 @@
<bool>false</bool>
</property>
</widget>
<widget class="KIconView">
<widget class="QLayoutWidget">
<property name="name">
<cstring>m_covers</cstring>
</property>
<property name="gridX">
<number>140</number>
</property>
<property name="gridY">
<number>150</number>
</property>
<property name="resizeMode">
<enum>Adjust</enum>
<cstring>layout3</cstring>
</property>
<vbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QLayoutWidget">
<property name="name">
<cstring>layout3</cstring>
</property>
<hbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QToolButton">
<property name="name">
<cstring>m_clearSearch</cstring>
</property>
<property name="text">
<string>Clear Search</string>
</property>
<property name="toolTip" stdset="0">
<string>Clear Search</string>
</property>
<property name="whatsThis" stdset="0">
<string>Clear the current cover search.</string>
</property>
</widget>
<widget class="KIconViewSearchLine">
<property name="name">
<cstring>m_searchLine</cstring>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>5</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</hbox>
</widget>
<widget class="CoverIconView">
<property name="name">
<cstring>m_covers</cstring>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>7</vsizetype>
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="gridX" stdset="0">
<number>140</number>
</property>
<property name="gridY" stdset="0">
<number>150</number>
</property>
</widget>
</vbox>
</widget>
</hbox>
</widget>
<customwidgets>
<customwidget>
<class>KIconViewSearchLine</class>
<header location="global">kiconviewsearchline.h</header>
<sizehint>
<width>100</width>
<height>-1</height>
</sizehint>
<container>0</container>
<sizepolicy>
<hordata>5</hordata>
<verdata>0</verdata>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<pixmap>image0</pixmap>
<slot access="public" specifier="">clear()</slot>
</customwidget>
<customwidget>
<class>CoverIconView</class>
<header location="local">covericonview.h</header>
<sizehint>
<width>100</width>
<height>100</height>
</sizehint>
<container>1</container>
<sizepolicy>
<hordata>7</hordata>
<verdata>7</verdata>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<pixmap>image0</pixmap>
<signal>contextMenuRequested(QIconViewItem *item, const QPoint &amp;pos)</signal>
<property type="Int">gridX</property>
<property type="Int">gridY</property>
</customwidget>
</customwidgets>
<images>
<image name="image0">
<data format="PNG" length="1002">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082</data>
</image>
</images>
<connections>
<connection>
<sender>m_artists</sender>
......@@ -88,6 +181,12 @@
<receiver>CoverDialogBase</receiver>
<slot>slotArtistClicked(QListViewItem*)</slot>
</connection>
<connection>
<sender>m_clearSearch</sender>
<signal>clicked()</signal>
<receiver>m_searchLine</receiver>
<slot>clear()</slot>
</connection>
<connection>
<sender>m_covers</sender>
<signal>contextMenuRequested(QIconViewItem*,const QPoint&amp;)</signal>
......@@ -100,8 +199,12 @@
<slot>slotContextRequested(QIconViewItem *, const QPoint &amp;pt)</slot>
</slots>
<layoutdefaults spacing="6" margin="11"/>
<forwards>
<forward>class QIconViewItem;</forward>
</forwards>
<includehints>
<includehint>klistview.h</includehint>
<includehint>kiconview.h</includehint>
<includehint>kiconviewsearchline.h</includehint>
<includehint>covericonview.h</includehint>
</includehints>
</UI>
/***************************************************************************
begin : Sat Jul 9 2005
copyright : (C) 2005 by Michael Pyne
email : michael.pyne@kdemail.net
***************************************************************************/
/***************************************************************************
* *
* 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 "covericonview.h"
#include "covermanager.h"
using CoverUtility::CoverIconViewItem;
CoverIconViewItem::CoverIconViewItem(coverKey id, QIconView *parent) :
KIconViewItem(parent), m_id(id)
{
CoverDataPtr data = CoverManager::coverInfo(id);
setText(QString("%1 - %2").arg(data->artist, data->album));
setPixmap(data->thumbnail());
}
CoverIconView::CoverIconView(QWidget *parent, const char *name) : KIconView(parent, name)
{
setResizeMode(Adjust);
}
CoverIconViewItem *CoverIconView::currentItem() const
{
return static_cast<CoverIconViewItem *>(KIconView::currentItem());
}
QDragObject *CoverIconView::dragObject()
{
CoverIconViewItem *item = currentItem();
if(item)
return new CoverDrag(item->id(), this);
return 0;
}
// vim: set et ts=4 sw=4:
/***************************************************************************
begin : Sat Jul 9 2005
copyright : (C) 2005 by Michael Pyne
email : michael.pyne@kdemail.net
***************************************************************************/
/***************************************************************************
* *
* 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 JUK_COVERICONVIEW_H
#define JUK_COVERICONVIEW_H
#include <kiconview.h>
#include "covermanager.h"
// The Google Fetcher dialog also has a class named CoverIconViewItem and I
// don't like the idea of naming it "CoverIVI" or something, so just namespace
// it out. I would merge them except for googlefetcher's dependence on KIO
// and such.
namespace CoverUtility
{
class CoverIconViewItem : public KIconViewItem
{
public:
CoverIconViewItem(coverKey id, QIconView *parent);
coverKey id() const { return m_id; }
private:
coverKey m_id;
};
};
using CoverUtility::CoverIconViewItem;
/**
* This class subclasses KIconView in order to provide cover drag-and-drop
* support.
*
* @author Michael Pyne <michael.pyne@kdemail.net>
*/
class CoverIconView : public KIconView
{
public:
CoverIconView(QWidget *parent, const char *name);
CoverIconViewItem *currentItem() const;
protected:
virtual QDragObject *dragObject();
};
#endif /* JUK_COVERICONVIEW_H */
// vim: set et ts=4 sw=4:
/***************************************************************************
copyright : (C) 2004 Nathan Toone
: (C) 2005 Michael Pyne <michael.pyne@kdemail.net>
email : nathan@toonetown.com
***************************************************************************/
......@@ -108,36 +109,47 @@ bool CoverInfo::hasCover()
void CoverInfo::clearCover()
{
QFile::remove(coverLocation(FullSize));
QFile::remove(coverLocation(Thumbnail));
m_hasCover = false;
m_haveCheckedForCover = false;
// Yes, we have checked, and we don't have it. ;)
m_haveCheckedForCover = true;
// We don't need to call removeCover because the CoverManager will
// automatically unlink the cover if we were the last track to use it.
CoverManager::setIdForTrack(m_file.absFilePath(), CoverManager::NoMatch);
CoverManager::removeCover(m_coverKey);
m_coverKey = CoverManager::NoMatch;
}
void CoverInfo::setCover(const QImage &image)
{
m_haveCheckedForCover = false;
if(image.isNull())
return;
if(m_hasCover)
clearCover();
m_haveCheckedForCover = true;
m_hasCover = true;
QPixmap cover;
cover.convertFromImage(image);
// If we use replaceCover we'll change the cover for every other track
// with the same coverKey, which we don't want since that case will be
// handled by Playlist. Instead just replace this track's cover.
m_coverKey = CoverManager::addCover(cover, m_file.tag()->artist(), m_file.tag()->album());
if(m_coverKey != CoverManager::NoMatch)
CoverManager::replaceCover(m_coverKey, cover);
else {
m_coverKey = CoverManager::addCover(cover, m_file.tag()->artist(), m_file.tag()->album());
if(m_coverKey != CoverManager::NoMatch)
CoverManager::setIdForTrack(m_file.absFilePath(), m_coverKey);
}
CoverManager::setIdForTrack(m_file.absFilePath(), m_coverKey);
}
void CoverInfo::setCoverId(coverKey id)
{
m_coverKey = id;
m_haveCheckedForCover = true;
// We assume this is true, this would make a good spot for an
// assertion though.
m_hasCover = true;
// Inform CoverManager of the change.
CoverManager::setIdForTrack(m_file.absFilePath(), m_coverKey);
}
QPixmap CoverInfo::pixmap(CoverSize size) const
......
......@@ -34,6 +34,9 @@ public:
void clearCover();
void setCover(const QImage &image = QImage());
// Use this to assign to a specific cover id.
void setCoverId(coverKey id);
QPixmap pixmap(CoverSize size) const;
void popup() const;
......
......@@ -22,6 +22,7 @@
#include <qdatastream.h>
#include <qdict.h>
#include <qcache.h>
#include <qmime.h>
#include <kdebug.h>
#include <kstaticdeleter.h>
......@@ -39,6 +40,7 @@ typedef QDict<coverKey> TrackLookupMap;
// gets properly destructed on shutdown.
static KStaticDeleter<CoverManagerPrivate> sd;
const char *CoverDrag::mimetype = "application/x-juk-coverid";
// Caches the QPixmaps for the covers so that the covers are not all kept in
// memory for no reason.
typedef QCache<QPixmap> CoverPixmapCache;
......@@ -235,6 +237,61 @@ coverKey CoverManagerPrivate::nextId() const
return key;
}
//
// Implementation of CoverDrag
//
CoverDrag::CoverDrag(coverKey id, QWidget *src) : QDragObject(src, "coverDrag"),
m_id(id)
{
}
const char *CoverDrag::format(int i) const
{
if(i == 0)
return mimetype;
if(i == 1)
return "image/png";
return 0;
}
QByteArray CoverDrag::encodedData(const char *mimetype) const
{
if(qstrcmp(CoverDrag::mimetype, mimetype) == 0) {
QByteArray data;
QDataStream ds(data, IO_WriteOnly);
ds << Q_UINT32(m_id);
return data;
}
else if(qstrcmp(mimetype, "image/png") == 0) {
// TODO: Implement.
;
}
return QByteArray();
}
bool CoverDrag::canDecode(const QMimeSource *e)
{
return e->provides(mimetype);
}
bool CoverDrag::decode(const QMimeSource *e, coverKey &id)
{
if(!canDecode(e))
return false;
QByteArray data = e->encodedData(mimetype);
QDataStream ds(data, IO_ReadOnly);
Q_UINT32 i;
ds >> i;
id = (coverKey) i;
return true;
}
//
// Implementation of CoverManager methods.
//
......@@ -333,6 +390,10 @@ coverKey CoverManager::addCover(const QPixmap &large, const QString &artist, con
data()->covers[id] = coverData;
// Make sure the new cover isn't inadvertently cached.
data()->pixmapCache.remove(QString("f%1").arg(coverData->path));
data()->pixmapCache.remove(QString("t%1").arg(coverData->path));
return id;
}
......@@ -351,15 +412,23 @@ bool CoverManager::removeCover(coverKey id)
if(!hasCover(id))
return false;
data()->covers.remove(id);
QDictIterator<coverKey> it(data()->tracks);
// Remove cover from cache.
CoverDataPtr coverData = coverInfo(id);
data()->pixmapCache.remove(QString("f%1").arg(coverData->path));
data()->pixmapCache.remove(QString("t%1").arg(coverData->path));
// Remove references to files that had that track ID.
QDictIterator<coverKey> it(data()->tracks);
for(; it.current(); ++it)
if(*it.current() == id)
data()->tracks.remove(it.currentKey());
// Remove covers from disk.
QFile::remove(coverData->path);
// Finally, forget that we ever knew about this cover.
data()->covers.remove(id);
return true;
}
......@@ -408,8 +477,12 @@ QValueList<coverKey> CoverManager::keys()
void CoverManager::setIdForTrack(const QString &path, coverKey id)
{
if(id == NoMatch)
if(id == NoMatch) {
data()->tracks.remove(path);
if(data()->tracks.isEmpty())
removeCover(id);
}
else
data()->tracks.insert(path, new coverKey(id));
}
......
......@@ -13,9 +13,13 @@
* *
***************************************************************************/
#ifndef JUK_COVERMANAGER_H
#define JUK_COVERMANAGER_H
#include <ksharedptr.h>
#include <qmap.h>
#include <qdragobject.h>
class CoverManagerPrivate;
class QString;
......@@ -47,6 +51,39 @@ typedef KSharedPtr<CoverData> CoverDataPtr;
typedef unsigned long coverKey; ///< Type of the id for a cover.
typedef QMap<coverKey, CoverDataPtr> CoverDataMap;
/**
* This class is used to drag covers in JuK. It adds a special mimetype that
* contains the cover ID used for this cover, and also supports an image/png
* mimetype for dragging to other applications.
*
* As of this writing the mimetype is application/x-juk-coverid
*
* @author Michael Pyne <michael.pyne@kdemail.net>
*/
class CoverDrag : public QDragObject
{
public:
CoverDrag(coverKey id, QWidget *src);
virtual const char *format(int i) const;
virtual QByteArray encodedData(const char *mimetype) const;
void setId(coverKey id) { m_id = id; }
/**
* Returns true if CoverDrag can decode the given mime source. Note that
* true is returned only if \p e contains a cover id, even though
* CoverDrag can convert it to an image.
*/
static bool canDecode(const QMimeSource *e);
static bool decode(const QMimeSource *e, coverKey &id);
static const char* mimetype;
private:
coverKey m_id;
};
/**
* This class holds all of the cover art, and manages looking it up by artist
* and/or album. This class is similar to a singleton class, but instead all
......@@ -210,4 +247,6 @@ public:
static QPixmap createThumbnail(const QPixmap &base);
};
#endif /* JUK_COVERMANAGER_H */
// vim: set et sw=4 ts=4:
......@@ -570,8 +570,6 @@ void Playlist::clearItem(PlaylistItem *item, bool emitChanged)
m_members.remove(item->file().absFilePath());
m_search.clearItem(item);
if(!m_randomList.isEmpty() && !m_visibleChanged)
m_randomList.remove(item);
m_history.remove(item);
delete item;
......@@ -664,9 +662,7 @@ void Playlist::setSearch(const PlaylistSearch &s)
if(!m_searchEnabled)
return;
// Make sure that we only play visible items.
m_randomList.clear();
TrackSequenceManager::instance()->iterator()->playlistChanged();
setItemsVisible(s.matchedItems(), true);
setItemsVisible(s.unmatchedItems(), false);
......@@ -973,14 +969,9 @@ void Playlist::removeFromDisk(const PlaylistItemList &items)
QString removePath = (*it)->file().absFilePath();
if((!shouldDelete && KIO::NetAccess::synchronousRun(KIO::trash(removePath), this)) ||
(shouldDelete && QFile::remove(removePath))) {
if(!m_randomList.isEmpty() && !m_visibleChanged)
m_randomList.remove(*it);
(shouldDelete && QFile::remove(removePath)))
{
CollectionList::instance()->clearItem((*it)->collectionItem());
// Get Orwellian and erase the song from history. :-)
m_history.remove(*it);
}
else
errorFiles.append((*it)->file().absFilePath());
......@@ -1016,15 +1007,63 @@ QDragObject *Playlist::dragObject(QWidget *parent)
return drag;
}
void Playlist::contentsDragEnterEvent(QDragEnterEvent *e)
{
KListView::contentsDragEnterEvent(e);
if(CoverDrag::canDecode(e)) {
setDropHighlighter(true);
setDropVisualizer(false);
e->accept();
return;
}
setDropHighlighter(false);
setDropVisualizer(true);
KURL::List urls;
if(!KURLDrag::decode(e, urls) || urls.isEmpty()) {
e->ignore();
return;
}
e->accept();
return;
}
bool Playlist::acceptDrag(QDropEvent *e) const
{
return CoverDrag::canDecode(e) || KURLDrag::canDecode(e);
}
bool Playlist::canDecode(QMimeSource *s)
{
KURL::List urls;
if(CoverDrag::canDecode(s))
return true;
return KURLDrag::decode(s, urls) && !urls.isEmpty();
}
void Playlist::decode(QMimeSource *s, PlaylistItem *item)
{
KURL::List urls;
coverKey id;
if(CoverDrag::decode(s, id)) {
// Apply cover to selected items.
PlaylistItemList selItems = selectedItems();
for(PlaylistItemList::Iterator it = selItems.begin(); it != selItems.end(); ++it) {
(*it)->file().coverInfo()->setCoverId(id);
(*it)->refresh();
}
return;
}
if(!KURLDrag::decode(s, urls) || urls.isEmpty())
return;
......
......@@ -422,8 +422,9 @@ protected:
virtual void decode(QMimeSource *s, PlaylistItem *item = 0);
virtual void contentsDropEvent(QDropEvent *e);
virtual void contentsMouseDoubleClickEvent(QMouseEvent *e);
virtual void contentsDragEnterEvent(QDragEnterEvent *e);
virtual void showEvent(QShowEvent *e);
virtual bool acceptDrag(QDropEvent *e) const { return KURLDrag::canDecode(e); }
virtual bool acceptDrag(QDropEvent *e) const;
virtual void viewportPaintEvent(QPaintEvent *pe);
virtual void viewportResizeEvent(QResizeEvent *re);
......@@ -649,7 +650,6 @@ private:
QValueVector<int> m_columnFixedWidths;
bool m_widthsDirty;
PlaylistItemList m_randomList;
static PlaylistItemList m_history;
PlaylistSearch m_search;
......@@ -726,9 +726,6 @@ ItemType *Playlist::createItem(const FileHandle &file, QListViewItem *after,
ItemType *i = after ? new ItemType(item, this, after) : new ItemType(item, this);
setupItem(i);
if(!m_randomList.isEmpty() && !m_visibleChanged)
m_randomList.append(i);
if(emitChanged)
dataChanged();