Index: playlist/Playlist.cpp
===================================================================
--- playlist/Playlist.cpp	(revision 41169)
+++ playlist/Playlist.cpp	(working copy)
@@ -456,8 +456,11 @@
 		} else {
 			if (_IsQuery(type))
 				AppendQueryToPlaylist(ref, &subPlaylist);
-			else
-				AppendToPlaylistRecursive(ref, &subPlaylist);
+			else {
+				if ( !ExtraMediaExists(this, ref) ) {
+					AppendToPlaylistRecursive(ref, &subPlaylist);
+				}
+			}
 
 			// At least sort this subsection of the playlist
 			// if the whole playlist is not sorted anymore.
@@ -510,7 +513,11 @@
 		BString mimeString = _MIMEString(&ref);
 		if (_IsMediaFile(mimeString)) {
 			PlaylistItem* item = new (std::nothrow) FilePlaylistItem(ref);
-			if (item != NULL && !playlist->AddItem(item))
+			if (!ExtraMediaExists(playlist, ref)) {
+				_BindExtraMedia(item);
+				if (item != NULL && !playlist->AddItem(item))
+					delete item;
+			} else
 				delete item;
 		} else
 			printf("MIME Type = %s\n", mimeString.String());
@@ -584,10 +591,43 @@
 }
 
 
+/*static*/ bool
+Playlist::ExtraMediaExists(Playlist* playlist, const entry_ref& ref)
+{
+	BString exceptExtension = _GetExceptExtension(BPath(&ref).Path());
+	
+	for (int32 i = 0; i < playlist->CountItems(); i++) {
+		FilePlaylistItem* compare = dynamic_cast<FilePlaylistItem*>(playlist->ItemAt(i));
+		if (compare == NULL)
+			continue;
+		if (compare->Ref() != ref
+				&& _GetExceptExtension(BPath(&compare->Ref()).Path()) == exceptExtension )
+			return true;
+	}
+	return false;
+}
+
+
 // #pragma mark - private
 
 
 /*static*/ bool
+Playlist::_IsImageFile(const BString& mimeString)
+{
+	BMimeType superType;
+	BMimeType fileType(mimeString.String());
+
+	if (fileType.GetSupertype(&superType) != B_OK)
+		return false;
+
+	if (superType == "image")
+		return true;
+
+	return false;
+}
+
+
+/*static*/ bool
 Playlist::_IsMediaFile(const BString& mimeString)
 {
 	BMimeType superType;
@@ -668,6 +708,62 @@
 }
 
 
+// _BindExtraMedia() searches additional videos and audios
+// and addes them as extra medias.
+/*static*/ void
+Playlist::_BindExtraMedia(PlaylistItem* item)
+{
+	FilePlaylistItem* fileItem = dynamic_cast<FilePlaylistItem*>(item);
+	if (!item)
+		return;
+	
+	// If the media file is foo.mp3, _BindExtraMedia() searches foo.avi.
+	BPath mediaFilePath(&fileItem->Ref());
+	BString mediaFilePathString = mediaFilePath.Path();
+	BPath dirPath;
+	mediaFilePath.GetParent(&dirPath);
+	BDirectory dir(dirPath.Path());
+	if (dir.InitCheck() != B_OK)
+		return;
+	
+	BEntry entry;
+	BString entryPathString;
+	while (dir.GetNextEntry(&entry, true) == B_OK) {
+		if (!entry.IsFile())
+			continue;
+		entryPathString = BPath(&entry).Path();
+		if (entryPathString != mediaFilePathString
+				&& _GetExceptExtension(entryPathString) == _GetExceptExtension(mediaFilePathString)) {
+			_BindExtraMedia(fileItem, entry);
+		}
+	}
+}
+
+
+/*static*/ void
+Playlist::_BindExtraMedia(FilePlaylistItem* fileItem, const BEntry& entry)
+{
+	entry_ref ref;
+	entry.GetRef(&ref);
+	BString mimeString = _MIMEString(&ref);
+	if (_IsMediaFile(mimeString)) {
+		fileItem->AddRef(ref);
+	} else if (_IsImageFile(mimeString)) {
+		fileItem->AddImageRef(ref);
+	}
+}
+
+
+/*static*/ BString
+Playlist::_GetExceptExtension(const BString& path)
+{
+	int32 periodPos = path.FindLast('.');
+	if (periodPos <= path.FindLast('/'))
+		return path;
+	return BString(path.String(), periodPos);
+}
+
+
 // #pragma mark - notifications
 
 
Index: playlist/Playlist.h
===================================================================
--- playlist/Playlist.h	(revision 41169)
+++ playlist/Playlist.h	(working copy)
@@ -25,6 +25,7 @@
 #include <List.h>
 #include <Locker.h>
 
+#include "FilePlaylistItem.h"
 #include "PlaylistItem.h"
 
 class BDataIO;
@@ -113,17 +114,23 @@
 
 			void				NotifyImportFailed();
 
+	static	bool				ExtraMediaExists(Playlist* playlist, const entry_ref& ref);
+
 private:
 								Playlist(const Playlist& other);
 			Playlist&			operator=(const Playlist& other);
 									// unimplemented
 
+	static	bool 				_IsImageFile(const BString& mimeString);
 	static	bool 				_IsMediaFile(const BString& mimeString);
 	static	bool				_IsTextPlaylist(const BString& mimeString);
 	static	bool				_IsBinaryPlaylist(const BString& mimeString);
 	static	bool				_IsPlaylist(const BString& mimeString);
 	static	bool				_IsQuery(const BString& mimeString);
 	static	BString				_MIMEString(const entry_ref* ref);
+	static	void				_BindExtraMedia(PlaylistItem* item);
+	static	void				_BindExtraMedia(FilePlaylistItem* fileItem, const BEntry& entry);
+	static	BString				_GetExceptExtension(const BString& path);
 
 			void				_NotifyItemAdded(PlaylistItem*,
 									int32 index) const;
Index: playlist/ImportPLItemsCommand.cpp
===================================================================
--- playlist/ImportPLItemsCommand.cpp	(revision 41169)
+++ playlist/ImportPLItemsCommand.cpp	(working copy)
@@ -57,14 +57,20 @@
 	memset(fNewItems, 0, fNewCount * sizeof(PlaylistItem*));
 
 	// init new entries
+	int32 added = 0;
 	for (int32 i = 0; i < fNewCount; i++) {
-		fNewItems[i] = temp.ItemAtFast(i)->Clone();
-		if (fNewItems[i] == NULL) {
-			// indicate bad object init
-			_CleanUp(fNewItems, fNewCount, true);
-			return;
+		FilePlaylistItem* fileItem = dynamic_cast<FilePlaylistItem*>(temp.ItemAtFast(i));
+		if (fileItem && !Playlist::ExtraMediaExists(playlist, fileItem->Ref())) {
+			fNewItems[added] = temp.ItemAtFast(i)->Clone();
+			if (fNewItems[added] == NULL) {
+				// indicate bad object init
+				_CleanUp(fNewItems, fNewCount, true);
+				return;
+			}
+			added++;
 		}
 	}
+	fNewCount = added;
 
 	fPlaylingIndex = fPlaylist->CurrentItemIndex();
 
Index: playlist/FilePlaylistItem.cpp
===================================================================
--- playlist/FilePlaylistItem.cpp	(revision 41169)
+++ playlist/FilePlaylistItem.cpp	(working copy)
@@ -14,40 +14,49 @@
 #include <FindDirectory.h>
 #include <MediaFile.h>
 #include <Path.h>
+#include <TranslationUtils.h>
 
 #include "MediaFileTrackSupplier.h"
 #include "SubTitlesSRT.h"
 
-
 static const char* kPathKey = "path";
 
-
 FilePlaylistItem::FilePlaylistItem(const entry_ref& ref)
-	:
-	fRef(ref),
-	fNameInTrash("")
 {
+	fRefs.push_back(ref);
+	fNamesInTrash.push_back("");
 }
 
 
 FilePlaylistItem::FilePlaylistItem(const FilePlaylistItem& other)
 	:
-	fRef(other.fRef),
-	fNameInTrash(other.fNameInTrash)
+	fRefs(other.fRefs),
+	fNamesInTrash(other.fNamesInTrash),
+	fImageRefs(other.fImageRefs),
+	fImageNamesInTrash(other.fImageNamesInTrash)
 {
 }
 
 
 FilePlaylistItem::FilePlaylistItem(const BMessage* archive)
-	:
-	fRef(),
-	fNameInTrash("")
 {
 	const char* path;
-	if (archive != NULL && archive->FindString(kPathKey, &path) == B_OK) {
-		if (get_ref_for_path(path, &fRef) != B_OK)
-			fRef = entry_ref();
+	entry_ref	ref;
+	if (archive != NULL) {
+		int32 i = 0;
+		while (archive->FindString(kPathKey, i, &path) == B_OK) {
+			if (get_ref_for_path(path, &ref) == B_OK) {
+				fRefs.push_back(ref);
+			}
+			i++;
+		}
 	}
+	if (fRefs.empty()) {
+		fRefs.push_back(entry_ref());
+	}
+	for (vector<entry_ref>::size_type i = 0; i < fRefs.size(); i++) {
+		fNamesInTrash.push_back("");
+	}
 }
 
 
@@ -82,11 +91,16 @@
 	status_t ret = BArchivable::Archive(into, deep);
 	if (ret != B_OK)
 		return ret;
-	BPath path(&fRef);
-	ret = path.InitCheck();
-	if (ret == B_OK)
+	for (vector<entry_ref>::size_type i = 0; i < fRefs.size(); i++) {
+		BPath path(&fRefs[i]);
+		ret = path.InitCheck();
+		if (ret != B_OK)
+			return ret;
 		ret = into->AddString(kPathKey, path.Path());
-	return ret;
+		if (ret != B_OK)
+			return ret;
+	}
+	return B_OK;
 }
 
 
@@ -97,7 +111,7 @@
 	switch (attribute) {
 		case ATTR_STRING_NAME:
 		{
-			BEntry entry(&fRef, false);
+			BEntry entry(&fRefs[0], false);
 			return entry.Rename(string.String(), false);
 		}
 	
@@ -135,7 +149,7 @@
 	BString& string) const
 {
 	if (attribute == ATTR_STRING_NAME) {
-		string = fRef.name;
+		string = fRefs[0].name;
 		return B_OK;
 	}
 
@@ -194,7 +208,7 @@
 BString
 FilePlaylistItem::LocationURI() const
 {
-	BPath path(&fRef);
+	BPath path(&fRefs[0]);
 	BString locationURI("file://");
 	locationURI << path.Path();
 	return locationURI;
@@ -204,7 +218,7 @@
 status_t
 FilePlaylistItem::GetIcon(BBitmap* bitmap, icon_size iconSize) const
 {
-	BNode node(&fRef);
+	BNode node(&fRefs[0]);
 	BNodeInfo info(&node);
 	return info.GetTrackerIcon(bitmap, iconSize);
 }
@@ -213,150 +227,82 @@
 status_t
 FilePlaylistItem::MoveIntoTrash()
 {
-	if (fNameInTrash.Length() != 0) {
+	if (fNamesInTrash[0].Length() != 0) {
 		// Already in the trash!
 		return B_ERROR;
 	}
 
-	char trashPath[B_PATH_NAME_LENGTH];
-	status_t err = find_directory(B_TRASH_DIRECTORY, fRef.device,
-		true /*create it*/, trashPath, B_PATH_NAME_LENGTH);
-	if (err != B_OK) {
-		fprintf(stderr, "failed to find Trash: %s\n", strerror(err));
+	status_t err;
+	err = _MoveIntoTrash(&fRefs, &fNamesInTrash);
+	if (err != B_OK)
 		return err;
-	}
+	
+	if (fImageRefs.empty())
+		return B_OK;
 
-	BEntry entry(&fRef);
-	err = entry.InitCheck();
-	if (err != B_OK) {
-		fprintf(stderr, "failed to init BEntry for %s: %s\n",
-			fRef.name, strerror(err));
+	err = _MoveIntoTrash(&fImageRefs, &fImageNamesInTrash);
+	if (err != B_OK)
 		return err;
-	}
-	BDirectory trashDir(trashPath);
-	if (err != B_OK) {
-		fprintf(stderr, "failed to init BDirectory for %s: %s\n",
-			trashPath, strerror(err));
-		return err;
-	}
 
-	// Find a unique name for the entry in the trash
-	fNameInTrash = fRef.name;
-	int32 uniqueNameIndex = 1;
-	while (true) {
-		BEntry test(&trashDir, fNameInTrash.String());
-		if (!test.Exists())
-			break;
-		fNameInTrash = fRef.name;
-		fNameInTrash << ' ' << uniqueNameIndex;
-		uniqueNameIndex++;
-	}
-
-	// Remember the original path
-	BPath originalPath;
-	entry.GetPath(&originalPath);
-
-	// Finally, move the entry into the trash
-	err = entry.MoveTo(&trashDir, fNameInTrash.String());
-	if (err != B_OK) {
-		fprintf(stderr, "failed to move entry into trash %s: %s\n",
-			trashPath, strerror(err));
-		return err;
-	}
-
-	// Allow Tracker to restore this entry
-	BNode node(&entry);
-	BString originalPathString(originalPath.Path());
-	node.WriteAttrString("_trk/original_path", &originalPathString);
-
-	return err;
+	return B_OK;
 }
 
 
-
 status_t
 FilePlaylistItem::RestoreFromTrash()
 {
-	if (fNameInTrash.Length() <= 0) {
+	if (fNamesInTrash[0].Length() <= 0) {
 		// Not in the trash!
 		return B_ERROR;
 	}
 
-	char trashPath[B_PATH_NAME_LENGTH];
-	status_t err = find_directory(B_TRASH_DIRECTORY, fRef.device,
-		false /*create it*/, trashPath, B_PATH_NAME_LENGTH);
-	if (err != B_OK) {
-		fprintf(stderr, "failed to find Trash: %s\n", strerror(err));
+	status_t err;
+	err = _RestoreFromTrash(&fRefs, &fNamesInTrash);
+	if (err != B_OK)
 		return err;
-	}
-	// construct the entry to the file in the trash
-// TODO: BEntry(const BDirectory* directory, const char* path) is broken!
-//	BEntry entry(trashPath, fNamesInTrash[i].String());
-BPath path(trashPath, fNameInTrash.String());
-BEntry entry(path.Path());
-	err = entry.InitCheck();
-	if (err != B_OK) {
-		fprintf(stderr, "failed to init BEntry for %s: %s\n",
-			fNameInTrash.String(), strerror(err));
-		return err;
-	}
-//entry.GetPath(&path);
-//printf("moving '%s'\n", path.Path());
+	
+	if (fImageRefs.empty())
+		return B_OK;
 
-	// construct the folder of the original entry_ref
-	node_ref nodeRef;
-	nodeRef.device = fRef.device;
-	nodeRef.node = fRef.directory;
-	BDirectory originalDir(&nodeRef);
-	err = originalDir.InitCheck();
-	if (err != B_OK) {
-		fprintf(stderr, "failed to init original BDirectory for "
-			"%s: %s\n", fRef.name, strerror(err));
+	err = _RestoreFromTrash(&fImageRefs, &fImageNamesInTrash);
+	if (err != B_OK)
 		return err;
-	}
 
-//path.SetTo(&originalDir, fItems[i].name);
-//printf("as '%s'\n", path.Path());
-
-	// Reset the name here, the user may have already moved the entry
-	// out of the trash via Tracker for example.
-	fNameInTrash = "";
-
-	// Finally, move the entry back into the original folder
-	err = entry.MoveTo(&originalDir, fRef.name);
-	if (err != B_OK) {
-		fprintf(stderr, "failed to restore entry from trash "
-			"%s: %s\n", fRef.name, strerror(err));
-		return err;
-	}
-
-	// Remove the attribute that helps Tracker restore the entry.
-	BNode node(&entry);
-	node.RemoveAttr("_trk/original_path");
-
-	return err;
+	return B_OK;
 }
 
 
 // #pragma mark -
 
-
 TrackSupplier*
 FilePlaylistItem::CreateTrackSupplier() const
 {
-	BMediaFile* mediaFile = new(std::nothrow) BMediaFile(&fRef);
-	if (mediaFile == NULL)
-		return NULL;
 	MediaFileTrackSupplier* supplier
-		= new(std::nothrow) MediaFileTrackSupplier(mediaFile);
-	if (supplier == NULL) {
-		delete mediaFile;
+		= new(std::nothrow) MediaFileTrackSupplier();
+	if (supplier == NULL)
 		return NULL;
+
+	for (vector<entry_ref>::size_type i = 0; i < fRefs.size(); i++) {
+		BMediaFile* mediaFile = new(std::nothrow) BMediaFile(&fRefs[i]);
+		if (mediaFile == NULL) {
+			delete supplier;
+			return NULL;
+		}
+		if (supplier->AddMediaFile(mediaFile) != B_OK)
+			delete mediaFile;
 	}
 
+	for (vector<entry_ref>::size_type i = 0; i < fImageRefs.size(); i++) {
+		BBitmap* bitmap = BTranslationUtils::GetBitmap(&fImageRefs[i]);
+		if (bitmap == NULL)
+			continue;
+		if (supplier->AddBitmap(bitmap) != B_OK)
+			delete bitmap;
+	}
+
 	// Search for subtitle files in the same folder
 	// TODO: Error checking
-	BEntry entry(&fRef, true);
+	BEntry entry(&fRefs[0], true);
 
 	char originalName[B_FILE_NAME_LENGTH];
 	entry.GetName(originalName);
@@ -411,10 +357,40 @@
 
 
 status_t
+FilePlaylistItem::AddRef(const entry_ref& ref)
+{
+	fRefs.push_back(ref);
+	fNamesInTrash.push_back("");
+	return B_OK;
+}
+
+
+status_t
+FilePlaylistItem::AddImageRef(const entry_ref& ref)
+{
+	fImageRefs.push_back(ref);
+	fImageNamesInTrash.push_back("");
+	return B_OK;
+}
+
+
+const entry_ref&
+FilePlaylistItem::ImageRef() const
+{
+	static entry_ref ref;
+
+	if (fImageRefs.empty())
+		return ref;
+	
+	return fImageRefs[0];
+}
+
+
+status_t
 FilePlaylistItem::_SetAttribute(const char* attrName, type_code type,
 	const void* data, size_t size)
 {
-	BEntry entry(&fRef, true);
+	BEntry entry(&fRefs[0], true);
 	BNode node(&entry);
 	if (node.InitCheck() != B_OK)
 		return node.InitCheck();
@@ -433,7 +409,7 @@
 FilePlaylistItem::_GetAttribute(const char* attrName, type_code type,
 	void* data, size_t size)
 {
-	BEntry entry(&fRef, true);
+	BEntry entry(&fRefs[0], true);
 	BNode node(&entry);
 	if (node.InitCheck() != B_OK)
 		return node.InitCheck();
@@ -447,3 +423,128 @@
 	return B_OK;
 }
 
+
+status_t
+FilePlaylistItem::_MoveIntoTrash(vector<entry_ref>* refs,
+	vector<BString>* namesInTrash)
+{
+	char trashPath[B_PATH_NAME_LENGTH];
+	status_t err = find_directory(B_TRASH_DIRECTORY, (*refs)[0].device,
+		true /*create it*/, trashPath, B_PATH_NAME_LENGTH);
+	if (err != B_OK) {
+		fprintf(stderr, "failed to find Trash: %s\n", strerror(err));
+		return err;
+	}
+
+	BDirectory trashDir(trashPath);
+	if (err != B_OK) {
+		fprintf(stderr, "failed to init BDirectory for %s: %s\n",
+			trashPath, strerror(err));
+		return err;
+	}
+
+	for (vector<entry_ref>::size_type i = 0; i < refs->size(); i++) {
+		BEntry entry(&(*refs)[i]);
+		err = entry.InitCheck();
+		if (err != B_OK) {
+			fprintf(stderr, "failed to init BEntry for %s: %s\n",
+				(*refs)[i].name, strerror(err));
+			return err;
+		}
+	
+		// Find a unique name for the entry in the trash
+		(*namesInTrash)[i] = (*refs)[i].name;
+		int32 uniqueNameIndex = 1;
+		while (true) {
+			BEntry test(&trashDir, (*namesInTrash)[i].String());
+			if (!test.Exists())
+				break;
+			(*namesInTrash)[i] = (*refs)[i].name;
+			(*namesInTrash)[i] << ' ' << uniqueNameIndex;
+			uniqueNameIndex++;
+		}
+	
+		// Remember the original path
+		BPath originalPath;
+		entry.GetPath(&originalPath);
+	
+		// Finally, move the entry into the trash
+		err = entry.MoveTo(&trashDir, (*namesInTrash)[i].String());
+		if (err != B_OK) {
+			fprintf(stderr, "failed to move entry into trash %s: %s\n",
+				trashPath, strerror(err));
+			return err;
+		}
+	
+		// Allow Tracker to restore this entry
+		BNode node(&entry);
+		BString originalPathString(originalPath.Path());
+		node.WriteAttrString("_trk/original_path", &originalPathString);
+	}
+
+	return B_OK;
+}
+
+
+status_t
+FilePlaylistItem::_RestoreFromTrash(vector<entry_ref>* refs,
+	vector<BString>* namesInTrash)
+{
+	char trashPath[B_PATH_NAME_LENGTH];
+	status_t err = find_directory(B_TRASH_DIRECTORY, (*refs)[0].device,
+		false /*create it*/, trashPath, B_PATH_NAME_LENGTH);
+	if (err != B_OK) {
+		fprintf(stderr, "failed to find Trash: %s\n", strerror(err));
+		return err;
+	}
+	
+	for (vector<entry_ref>::size_type i = 0; i < refs->size(); i++) {
+		// construct the entry to the file in the trash
+		// TODO: BEntry(const BDirectory* directory, const char* path) is broken!
+		//	BEntry entry(trashPath, (*namesInTrash)[i].String());
+		BPath path(trashPath, (*namesInTrash)[i].String());
+		BEntry entry(path.Path());
+		err = entry.InitCheck();
+		if (err != B_OK) {
+			fprintf(stderr, "failed to init BEntry for %s: %s\n",
+				(*namesInTrash)[i].String(), strerror(err));
+			return err;
+		}
+		//entry.GetPath(&path);
+		//printf("moving '%s'\n", path.Path());
+	
+		// construct the folder of the original entry_ref
+		node_ref nodeRef;
+		nodeRef.device = (*refs)[i].device;
+		nodeRef.node = (*refs)[i].directory;
+		BDirectory originalDir(&nodeRef);
+		err = originalDir.InitCheck();
+		if (err != B_OK) {
+			fprintf(stderr, "failed to init original BDirectory for "
+				"%s: %s\n", (*refs)[i].name, strerror(err));
+			return err;
+		}
+	
+		//path.SetTo(&originalDir, fItems[i].name);
+		//printf("as '%s'\n", path.Path());
+	
+		// Reset the name here, the user may have already moved the entry
+		// out of the trash via Tracker for example.
+		(*namesInTrash)[i] = "";
+	
+		// Finally, move the entry back into the original folder
+		err = entry.MoveTo(&originalDir, (*refs)[i].name);
+		if (err != B_OK) {
+			fprintf(stderr, "failed to restore entry from trash "
+				"%s: %s\n", (*refs)[i].name, strerror(err));
+			return err;
+		}
+	
+		// Remove the attribute that helps Tracker restore the entry.
+		BNode node(&entry);
+		node.RemoveAttr("_trk/original_path");
+	}
+
+	return B_OK;
+}
+
Index: playlist/FilePlaylistItem.h
===================================================================
--- playlist/FilePlaylistItem.h	(revision 41169)
+++ playlist/FilePlaylistItem.h	(working copy)
@@ -9,6 +9,8 @@
 
 #include <Entry.h>
 
+#include <vector>
+
 class FilePlaylistItem : public PlaylistItem {
 public:
 								FilePlaylistItem(const entry_ref& ref);
@@ -50,8 +52,12 @@
 	// playback
 	virtual	TrackSupplier*		CreateTrackSupplier() const;
 
-			const entry_ref&	Ref() const { return fRef; }
+			status_t			AddRef(const entry_ref& ref);
+			const entry_ref&	Ref() const { return fRefs[0]; }
 
+			status_t			AddImageRef(const entry_ref& ref);
+			const entry_ref&	ImageRef() const;
+
 private:
 			status_t			_SetAttribute(const char* attrName,
 									type_code type, const void* data,
@@ -59,10 +65,18 @@
 			status_t			_GetAttribute(const char* attrName,
 									type_code type, void* data,
 									size_t size);
+			status_t			_MoveIntoTrash(vector<entry_ref>* refs,
+									vector<BString>* namesInTrash);
+			status_t			_RestoreFromTrash(vector<entry_ref>* refs,
+									vector<BString>* namesInTrash);
 
 private:
-			entry_ref			fRef;
-			BString				fNameInTrash;
+	// always fRefs.size() == fNamesInTrash.size()
+			vector<entry_ref>	fRefs;
+			vector<BString>		fNamesInTrash;
+	// always fImageRefs.size() == fImageNamesInTrash.size()
+			vector<entry_ref>	fImageRefs;
+			vector<BString>		fImageNamesInTrash;
 };
 
 #endif // FILE_PLAYLIST_ITEM_H
Index: supplier/MediaFileTrackSupplier.cpp
===================================================================
--- supplier/MediaFileTrackSupplier.cpp	(revision 41169)
+++ supplier/MediaFileTrackSupplier.cpp	(working copy)
@@ -17,58 +17,23 @@
 
 #include "MediaTrackAudioSupplier.h"
 #include "MediaTrackVideoSupplier.h"
+#include "ImageTrackVideoSupplier.h"
 
 
-MediaFileTrackSupplier::MediaFileTrackSupplier(BMediaFile* mediaFile)
+MediaFileTrackSupplier::MediaFileTrackSupplier()
 	:
-	TrackSupplier(),
-	fMediaFile(mediaFile)
+	TrackSupplier()
 {
-	if (fMediaFile->InitCheck() != B_OK)
-		return;
-	int trackCount = fMediaFile->CountTracks();
-	if (trackCount <= 0)
-		return;
-
-	for (int i = 0; i < trackCount; i++) {
-		BMediaTrack* track = fMediaFile->TrackAt(i);
-		media_format format;
-		status_t status = track->EncodedFormat(&format);
-		if (status != B_OK) {
-			fprintf(stderr, "MediaFileTrackSupplier: EncodedFormat failed for "
-				"track index %d, error: %s\n", i, strerror(status));
-			fMediaFile->ReleaseTrack(track);
-			continue;
-		}
-
-		if (track->Duration() <= 0) {
-			fprintf(stderr, "MediaFileTrackSupplier: warning! track index %d "
-				"has no duration\n", i);
-		}
-
-		if (format.IsAudio()) {
-			if (!fAudioTracks.AddItem(track)) {
-				fMediaFile->ReleaseTrack(track);
-				return;
-			}
-		} else if (format.IsVideo()) {
-			if (!fVideoTracks.AddItem(track)) {
-				fMediaFile->ReleaseTrack(track);
-				return;
-			}
-		} else {
-			printf("MediaFileTrackSupplier: track index %d has unknown "
-				"type\n", i);
-			fMediaFile->ReleaseTrack(track);
-		}
-	}
 }
 
 
 MediaFileTrackSupplier::~MediaFileTrackSupplier()
 {
-	delete fMediaFile;
+	for (vector<BMediaFile*>::size_type i = fMediaFiles.size() - 1; static_cast<int32>(i) >= 0; i--)
+		delete fMediaFiles[i];
 		// BMediaFile destructor will call ReleaseAllTracks()
+	for (vector<BBitmap*>::size_type i = fBitmaps.size() - 1; static_cast<int32>(i) >= 0; i--)
+		delete fBitmaps[i];
  	for (int32 i = fSubTitleTracks.CountItems() - 1; i >= 0; i--)
  		delete reinterpret_cast<SubTitles*>(fSubTitleTracks.ItemAtFast(i));
  }
@@ -77,21 +42,30 @@
 status_t
 MediaFileTrackSupplier::InitCheck()
 {
-	return fMediaFile->InitCheck();
+	if (fMediaFiles.empty())
+		return B_ERROR;
+	
+	return fMediaFiles[0]->InitCheck();
 }
 
 
 status_t
 MediaFileTrackSupplier::GetFileFormatInfo(media_file_format* fileFormat)
 {
-	return fMediaFile->GetFileFormatInfo(fileFormat);
+	if (fMediaFiles.empty())
+		return B_ERROR;
+
+	return fMediaFiles[0]->GetFileFormatInfo(fileFormat);
 }
 
 
 status_t
 MediaFileTrackSupplier::GetCopyright(BString* copyright)
 {
-	*copyright = fMediaFile->Copyright();
+	if (fMediaFiles.empty())
+		return B_ERROR;
+
+	*copyright = fMediaFiles[0]->Copyright();
 	return B_OK;
 }
 
@@ -99,7 +73,10 @@
 status_t
 MediaFileTrackSupplier::GetMetaData(BMessage* metaData)
 {
-	return fMediaFile->GetMetaData(metaData);
+	if (fMediaFiles.empty())
+		return B_ERROR;
+
+	return fMediaFiles[0]->GetMetaData(metaData);
 }
 
 
@@ -113,7 +90,7 @@
 int32
 MediaFileTrackSupplier::CountVideoTracks()
 {
-	return fVideoTracks.CountItems();
+	return fVideoTracks.CountItems() + fBitmaps.size();
 }
 
 
@@ -160,18 +137,24 @@
 VideoTrackSupplier*
 MediaFileTrackSupplier::CreateVideoTrackForIndex(int32 index)
 {
-	BMediaTrack* track = (BMediaTrack*)fVideoTracks.ItemAt(index);
-	if (track == NULL)
-		return NULL;
+	VideoTrackSupplier* supplier;
+	status_t initStatus;
 
-	status_t initStatus;
-	MediaTrackVideoSupplier* supplier
-		= new(std::nothrow) MediaTrackVideoSupplier(track, index, initStatus);
+	if (fVideoTracks.CountItems() <= index
+			&& index < fVideoTracks.CountItems() + static_cast<int32>(fBitmaps.size())) {
+		supplier = new(std::nothrow) ImageTrackVideoSupplier(fBitmaps[index-fVideoTracks.CountItems()], index, initStatus);
+	} else {
+		BMediaTrack* track = (BMediaTrack*)fVideoTracks.ItemAt(index);
+		if (track == NULL)
+			return NULL;
+	
+		supplier = new(std::nothrow) MediaTrackVideoSupplier(track, index, initStatus);
+	}
+
 	if (initStatus != B_OK) {
 		delete supplier;
 		return NULL;
 	}
-
 	return supplier;
 }
 
@@ -189,3 +172,62 @@
 	return fSubTitleTracks.AddItem(subTitles);
 }
 
+
+status_t
+MediaFileTrackSupplier::AddMediaFile(BMediaFile* mediaFile)
+{
+	if (mediaFile->InitCheck() != B_OK)
+		return B_ERROR;
+	int trackCount = mediaFile->CountTracks();
+	if (trackCount <= 0)
+		return B_ERROR;
+
+	status_t	funcStatus = B_ERROR;
+	for (int i = 0; i < trackCount; i++) {
+		BMediaTrack* track = mediaFile->TrackAt(i);
+		media_format format;
+		status_t status = track->EncodedFormat(&format);
+		if (status != B_OK) {
+			fprintf(stderr, "MediaFileTrackSupplier: EncodedFormat failed for "
+				"track index %d, error: %s\n", i, strerror(status));
+			mediaFile->ReleaseTrack(track);
+			continue;
+		}
+
+		if (track->Duration() <= 0) {
+			fprintf(stderr, "MediaFileTrackSupplier: warning! track index %d "
+				"has no duration\n", i);
+		}
+
+		if (format.IsAudio()) {
+			if (fAudioTracks.AddItem(track)) {
+				funcStatus = B_OK;
+			} else {
+				mediaFile->ReleaseTrack(track);
+			}
+		} else if (format.IsVideo()) {
+			if (fVideoTracks.AddItem(track)) {
+				funcStatus = B_OK;
+			} else {
+				mediaFile->ReleaseTrack(track);
+			}
+		} else {
+			printf("MediaFileTrackSupplier: track index %d has unknown "
+				"type\n", i);
+			mediaFile->ReleaseTrack(track);
+		}
+	}
+	if (funcStatus == B_OK)
+		fMediaFiles.push_back(mediaFile);
+	return funcStatus;
+}
+
+
+status_t
+MediaFileTrackSupplier::AddBitmap(BBitmap* bitmap)
+{
+	fBitmaps.push_back(bitmap);
+	return B_OK;
+}
+
+
Index: supplier/MediaFileTrackSupplier.h
===================================================================
--- supplier/MediaFileTrackSupplier.h	(revision 41169)
+++ supplier/MediaFileTrackSupplier.h	(working copy)
@@ -6,17 +6,19 @@
 #define MEDIA_FILE_TRACK_SUPPLIER_H
 
 
+#include <Bitmap.h>
 #include <List.h>
 
 #include "TrackSupplier.h"
 
+#include <vector>
 
 class BMediaFile;
 
 
 class MediaFileTrackSupplier : public TrackSupplier {
 public:
-								MediaFileTrackSupplier(BMediaFile* mediaFile);
+								MediaFileTrackSupplier();
 	virtual						~MediaFileTrackSupplier();
 
 	virtual	status_t			InitCheck();
@@ -41,8 +43,13 @@
 
 			bool				AddSubTitles(SubTitles* subTitles);
 
+			status_t			AddMediaFile(BMediaFile* mediaFile);
+
+			status_t			AddBitmap(BBitmap* bitmap);
+
 private:
-			BMediaFile*			fMediaFile;
+			vector<BMediaFile*>	fMediaFiles;
+			vector<BBitmap*>	fBitmaps;
 			BList				fAudioTracks;
 			BList				fVideoTracks;
 			BList				fSubTitleTracks;
Index: Jamfile
===================================================================
--- Jamfile	(revision 41169)
+++ Jamfile	(working copy)
@@ -77,6 +77,7 @@
 
 	# supplier
 	AudioTrackSupplier.cpp
+	ImageTrackVideoSupplier.cpp
 	MediaFileTrackSupplier.cpp
 	MediaTrackAudioSupplier.cpp
 	MediaTrackVideoSupplier.cpp
