summaryrefslogtreecommitdiffstats
path: root/kaffeine/src/input/audiobrowser
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-10 00:59:09 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-10 00:59:09 +0000
commit7f66b9e8ba186fb14a2db598a87dfa8de7b5a47b (patch)
treeb5e07812e82f00c780d2c035dca102b8e364f447 /kaffeine/src/input/audiobrowser
downloadkaffeine-7f66b9e8ba186fb14a2db598a87dfa8de7b5a47b.tar.gz
kaffeine-7f66b9e8ba186fb14a2db598a87dfa8de7b5a47b.zip
Added old abandoned KDE3 version of Kaffeine
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kaffeine@1088031 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kaffeine/src/input/audiobrowser')
-rw-r--r--kaffeine/src/input/audiobrowser/Makefile.am28
-rw-r--r--kaffeine/src/input/audiobrowser/googlefetcher.cpp282
-rw-r--r--kaffeine/src/input/audiobrowser/googlefetcher.h91
-rw-r--r--kaffeine/src/input/audiobrowser/googlefetcherdialog.cpp254
-rw-r--r--kaffeine/src/input/audiobrowser/googlefetcherdialog.h98
-rw-r--r--kaffeine/src/input/audiobrowser/kaffeineplaylist.rc17
-rw-r--r--kaffeine/src/input/audiobrowser/playlist.cpp2365
-rw-r--r--kaffeine/src/input/audiobrowser/playlist.h336
-rw-r--r--kaffeine/src/input/audiobrowser/playlistitem.cpp268
-rw-r--r--kaffeine/src/input/audiobrowser/playlistitem.h93
-rw-r--r--kaffeine/src/input/audiobrowser/urllistview.cpp347
-rw-r--r--kaffeine/src/input/audiobrowser/urllistview.h92
12 files changed, 4271 insertions, 0 deletions
diff --git a/kaffeine/src/input/audiobrowser/Makefile.am b/kaffeine/src/input/audiobrowser/Makefile.am
new file mode 100644
index 0000000..b743ccd
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/Makefile.am
@@ -0,0 +1,28 @@
+METASOURCES = AUTO
+
+noinst_LTLIBRARIES = libkaffeineaudiobrowser.la
+
+INCLUDES = -I$(top_srcdir)/kaffeine/src/input/ \
+ -I$(top_srcdir)/kaffeine/src/ \
+ $(all_includes) \
+ -I$(top_srcdir)/kaffeine/src/player-parts/kaffeine-part
+
+libkaffeineaudiobrowser_la_SOURCES = playlist.cpp \
+ playlistitem.cpp \
+ urllistview.cpp \
+ googlefetcher.cpp \
+ googlefetcherdialog.cpp
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+
+libkaffeineaudiobrowser_la_LDFLAGS = $(KDE_RPATH) \
+ $(all_libraries) \
+ -L$(top_srcdir)/kaffeine/src/input
+
+libkaffeineaudiobrowser_la_LIBADD = $(top_builddir)/kaffeine/src/input/libkaffeineinput.la \
+ $(top_builddir)/kaffeine/src/player-parts/kaffeine-part/libkaffeinepart.la \
+ $(LIB_KHTML)
+
+# this is where the XML-GUI resource file goes
+shellrcdir = $(kde_datadir)/kaffeine
+shellrc_DATA = kaffeineplaylist.rc
diff --git a/kaffeine/src/input/audiobrowser/googlefetcher.cpp b/kaffeine/src/input/audiobrowser/googlefetcher.cpp
new file mode 100644
index 0000000..fe88d14
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/googlefetcher.cpp
@@ -0,0 +1,282 @@
+/*
+ * googlefetcher.cpp
+ *
+ * Copyright (C) 2004 Nathan Toone <nathan@toonetown.com>
+ * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <dom/html_document.h>
+#include <dom/html_misc.h>
+#include <dom/html_table.h>
+#include <dom/dom_exception.h>
+#include <dom/dom2_traversal.h>
+
+#include <khtml_part.h>
+
+#include <klocale.h>
+#include <kinputdialog.h>
+#include <kurl.h>
+#include <kio/netaccess.h>
+
+#include "googlefetcher.h"
+#include "googlefetcherdialog.h"
+
+GoogleImage::GoogleImage(QString thumbURL, QString size)
+{
+ // thumbURL is in the following format - and we can regex the imageURL
+ // images?q=tbn:hKSEWNB8aNcJ:www.styxnet.com/deyoung/styx/stygians/cp_portrait.jpg
+ m_thumbURL = thumbURL.replace("\"","");
+ m_imageURL = thumbURL.remove(QRegExp("^.*q=tbn:[^:]*:")).replace("\"","");
+ m_size = size.replace("pixels - ", "\n(") + ")";
+}
+
+
+GoogleFetcher::GoogleFetcher( QString artist, QString album, bool gallery )
+{
+ m_artist = artist;
+ m_album = album;
+ m_searchString = artist+" "+album;
+ encoding = 0;
+ galleryImage=galleryPage=0;
+ galleryMode = gallery;
+}
+
+void GoogleFetcher::slotLoadImageURLs(GoogleFetcher::ImageSize size)
+{
+ if(m_loadedQuery == m_searchString && m_loadedSize == size)
+ return;
+
+ m_imageList.clear();
+
+ KURL url("http://images.google.com/images");
+ if ( encoding )
+ url.addQueryItem("q", m_searchString,encoding);
+ else
+ url.addQueryItem("q", m_searchString);
+
+ switch (size) {
+ case XLarge:
+ url.addQueryItem("imgsz", "xlarge|xxlarge");
+ break;
+ case Large:
+ url.addQueryItem("imgsz", "large");
+ break;
+ case Medium:
+ url.addQueryItem("imgsz", "medium");
+ break;
+ case Small:
+ url.addQueryItem("imgsz", "small");
+ break;
+ case Icon:
+ url.addQueryItem("imgsz", "icon");
+ break;
+ default:
+ break;
+ }
+
+ m_loadedQuery = m_searchString;
+ m_loadedSize = size;
+
+ // We don't normally like exceptions but missing DOMException will kill
+ // JuK rather abruptly whether we like it or not so we don't really have a
+ // choice if we're going to screen-scrape Google.
+ try {
+
+ KHTMLPart part;
+
+ // Create empty document.
+
+ part.begin();
+ part.end();
+
+ DOM::Document search = part.document();
+ search.setAsync(false); // Grab the document before proceeding.
+
+ kdDebug() << "Performing Google Search: " << url << endl;
+
+ search.load(url.url()+QString("&start=%1&sa=N").arg(galleryPage*20) );
+
+ QString text = search.toString().string();
+
+ if ( !hasImageResults(text) ) {
+ kdDebug() << "Search returned no results.\n";
+ emit signalNewSearch(m_imageList);
+ return;
+ }
+
+ // Go through each of the top (table) nodes
+
+ int pos = text.find("/imgres?imgurl");
+ int tpos;
+ QString s, c;
+ while ( pos>-1 ) {
+ text = text.right( text.length()-pos-14 );
+ tpos = text.find("&h=");
+ text = text.right( text.length()-tpos-3 );
+ tpos = text.find("&w=");
+ c = "pixels - " + text.left( tpos );
+ text = text.right( text.length()-tpos-3 );
+ tpos = text.find("&sz=");
+ c = c + "x" + text.left( tpos );
+ tpos = text.find("src=");
+ text = text.right( text.length()-tpos-4 );
+ if ( (tpos=text.find("width="))==-1 )
+ break;
+ s = text.left( tpos-1 );
+ text = text.right( text.length()-tpos );
+ if ( (tpos=text.find("></a>"))==-1 )
+ break;
+ m_imageList.append(GoogleImage(s, c));
+ pos = text.find("/imgres?imgurl");
+ }
+ } // try
+ catch (DOM::DOMException &e)
+ {
+ kdError() << "Caught DOM Exception: " << e.code << endl;
+ }
+ catch (...)
+ {
+ kdError() << "Caught unknown exception.\n";
+ }
+
+ emit signalNewSearch(m_imageList);
+}
+
+QImage GoogleFetcher::galleryNext( bool &end )
+{
+ QString file;
+ QImage image;
+ m_loadedSize = All;
+ int tries = 0;
+ end = false;
+
+ while ( tries<3 ) {
+ if( m_imageList.isEmpty() ) {
+ if ( tries==0 ) {
+ encoding = 0;
+ m_loadedQuery = "";
+ ++tries;
+ displayWaitMessage();
+ }
+ else if ( tries==1 ) {
+ encoding = 4; // try iso8859-1
+ m_loadedQuery = "";
+ ++tries;
+ kdDebug() << "Trying iso8859-1" << endl;
+ displayWaitMessage();
+ }
+ else {
+ end = true;
+ return QImage();
+ }
+ }
+ else {
+ if(KIO::NetAccess::download( m_imageList[galleryImage].imageURL(), file, 0))
+ image = QImage(file);
+ else
+ image = QImage();
+ ++galleryImage;
+ if ( galleryImage==(int)m_imageList.count() ) {
+ m_imageList.clear();
+ galleryImage = 0;
+ ++galleryPage;
+ }
+ KIO::NetAccess::removeTempFile(file);
+ return image;
+ }
+ }
+ return QImage();
+}
+
+QPixmap GoogleFetcher::pixmap( bool forceFetch )
+{
+ bool chosen = false;
+ m_loadedSize = All;
+ int tries = 0;
+
+ encoding = 0;
+ displayWaitMessage();
+
+ QPixmap pixmap;
+
+ while(!chosen) {
+
+ if(m_imageList.isEmpty())
+ switch(tries) {
+ case 0:
+ encoding = 4; // try iso8859-1
+ m_loadedQuery = "";
+ ++tries;
+ kdDebug() << "Trying iso8859-1" << endl;
+ displayWaitMessage();
+ break;
+ default :
+ if ( forceFetch == true )
+ chosen = !requestNewSearchTerms(true);
+ else
+ chosen = true;
+ }
+ else {
+ GoogleFetcherDialog dialog("google", m_imageList, m_artist, m_album, 0);
+ connect(&dialog, SIGNAL(sizeChanged(GoogleFetcher::ImageSize)),
+ this, SLOT(slotLoadImageURLs(GoogleFetcher::ImageSize)));
+ connect(this, SIGNAL(signalNewSearch(GoogleImageList &)),
+ &dialog, SLOT(refreshScreen(GoogleImageList &)));
+ dialog.exec();
+ pixmap = dialog.result();
+ chosen = dialog.takeIt();
+
+ if(dialog.newSearch())
+ requestNewSearchTerms();
+ }
+ }
+ return pixmap;
+}
+
+void GoogleFetcher::displayWaitMessage()
+{
+ //KStatusBar *statusBar = static_cast<KMainWindow *>(kapp->mainWidget())->statusBar();
+ //statusBar->message(i18n("Searching for Images. Please Wait..."));
+ slotLoadImageURLs();
+ //statusBar->clear();*/
+}
+
+bool GoogleFetcher::requestNewSearchTerms(bool noResults)
+{
+ bool ok;
+ m_searchString = KInputDialog::getText(i18n("Cover Downloader"),
+ noResults ?
+ i18n("No matching images found, please enter new search terms:") :
+ i18n("Enter new search terms:"),
+ m_searchString, &ok);
+ if(ok && !m_searchString.isEmpty())
+ displayWaitMessage();
+ else
+ m_searchString = m_loadedQuery;
+
+ return ok;
+}
+
+bool GoogleFetcher::hasImageResults( QString &doc )
+{
+ if ( !doc.contains( "/imgres?imgurl" ) )
+ return false;
+
+ return true;
+}
+
+#include "googlefetcher.moc"
diff --git a/kaffeine/src/input/audiobrowser/googlefetcher.h b/kaffeine/src/input/audiobrowser/googlefetcher.h
new file mode 100644
index 0000000..7c90091
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/googlefetcher.h
@@ -0,0 +1,91 @@
+/*
+ * googlefetcher.h
+ *
+ * Copyright (C) 2004 Nathan Toone <nathan@toonetown.com>
+ * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef GOOGLEFETCHER_H
+#define GOOGLEFETCHER_H
+
+#include <kdialogbase.h>
+
+#include <qpixmap.h>
+#include <qstringlist.h>
+#include <qregexp.h>
+
+namespace DOM {
+ class HTMLDocument;
+}
+
+class KURL;
+
+class GoogleImage
+{
+public:
+ GoogleImage(QString thumbURL = QString::null, QString size = QString::null);
+
+ QString imageURL() const { return m_imageURL; }
+ QString thumbURL() const { return m_thumbURL; }
+ QString size() const { return m_size; }
+
+private:
+ QString m_imageURL;
+ QString m_thumbURL;
+ QString m_size;
+};
+
+typedef QValueList<GoogleImage> GoogleImageList;
+
+class GoogleFetcher : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum ImageSize { All, Icon, Small, Medium, Large, XLarge };
+
+ GoogleFetcher( QString artist, QString album, bool gallery=false );
+ QPixmap pixmap( bool forceFetch = false );
+ QImage galleryNext( bool &end );
+
+signals:
+ void signalNewSearch(GoogleImageList &images);
+
+private:
+ void displayWaitMessage();
+ bool requestNewSearchTerms(bool noResults = false);
+
+ // Returns true if there are results in the search, otherwise returns false.
+ bool hasImageResults( QString &doc );
+
+private slots:
+ void slotLoadImageURLs(GoogleFetcher::ImageSize size = All);
+
+private:
+ QString m_artist, m_album;
+ QString m_searchString;
+ QString m_loadedQuery;
+ ImageSize m_loadedSize;
+ GoogleImageList m_imageList;
+ uint m_selectedIndex;
+ int encoding;
+ int galleryImage;
+ int galleryPage;
+ bool galleryMode;
+};
+
+#endif /* GOOGLEFETCHER_H */
diff --git a/kaffeine/src/input/audiobrowser/googlefetcherdialog.cpp b/kaffeine/src/input/audiobrowser/googlefetcherdialog.cpp
new file mode 100644
index 0000000..bda3853
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/googlefetcherdialog.cpp
@@ -0,0 +1,254 @@
+/*
+ * googlefetcherdialog.cpp
+ *
+ * Copyright (C) 2004 Nathan Toone <nathan@toonetown.com>
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <kapplication.h>
+#include <kio/netaccess.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kcombobox.h>
+
+#include <qhbox.h>
+#include <qimage.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qeventloop.h>
+
+#include "googlefetcherdialog.h"
+
+GoogleFetcherDialog::GoogleFetcherDialog(const QString &name,
+ const GoogleImageList &imageList,
+ const QString &artist,
+ const QString &album,
+ QWidget *parent) :
+ KDialogBase(parent, name.latin1(), true, QString::null,
+ Ok | Cancel | User1 , NoDefault, true),
+ m_pixmap(QPixmap()),
+ m_imageList(imageList),
+ m_takeIt(false),
+ m_newSearch(false)
+{
+ m_artist = artist;
+ m_album = album;
+ disableResize();
+
+ QHBox *mainBox = new QHBox(this);
+ m_iconWidget = new KIconView(mainBox);
+ m_iconWidget->setResizeMode(QIconView::Adjust);
+ m_iconWidget->setSelectionMode(QIconView::Extended);
+ m_iconWidget->setSpacing(10);
+ m_iconWidget->setMode(KIconView::Execute);
+ m_iconWidget->setFixedSize(500,550);
+ m_iconWidget->arrangeItemsInGrid();
+ m_iconWidget->setItemsMovable(FALSE);
+
+ QHBox *imgSize = new QHBox(actionButton(User1)->parentWidget());
+ //QLabel *label = new QLabel(imgSize);
+ //label->setText(i18n("Image size:"));
+
+ KComboBox *combo = new KComboBox(imgSize);
+ combo->insertItem(i18n("All Sizes"));
+ combo->insertItem(i18n("Very Small"));
+ combo->insertItem(i18n("Small"));
+ combo->insertItem(i18n("Medium"));
+ combo->insertItem(i18n("Large"));
+ combo->insertItem(i18n("Very Large"));
+ combo->setCurrentItem(0);
+ connect(combo, SIGNAL(activated(int)), this, SLOT(imgSizeChanged(int)));
+ connect(m_iconWidget, SIGNAL( executed(QIconViewItem*) ), this, SLOT(slotOk()));
+
+ imgSize->adjustSize();
+ setMainWidget(mainBox);
+ setButtonText(User1, i18n("New Search"));
+}
+
+GoogleFetcherDialog::~GoogleFetcherDialog()
+{
+
+}
+
+void GoogleFetcherDialog::setLayout()
+{
+ setCaption(QString("%1 - %2 (%3)")
+ .arg(m_artist)
+ .arg(m_album)
+ .arg(m_imageList.size()));
+
+ m_iconWidget->clear();
+ for(uint i = 0; i < m_imageList.size(); i++)
+ new CoverIconViewItem(m_iconWidget, m_imageList[i]);
+
+ adjustSize();
+}
+
+void GoogleFetcherDialog::setImageList(const GoogleImageList &imageList)
+{
+ m_imageList=imageList;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// public slots
+////////////////////////////////////////////////////////////////////////////////
+
+void GoogleFetcherDialog::refreshScreen(GoogleImageList &imageList)
+{
+ setImageList(imageList);
+ setLayout();
+}
+
+int GoogleFetcherDialog::exec()
+{
+ setLayout();
+ return KDialogBase::exec();
+}
+
+void GoogleFetcherDialog::slotOk()
+{
+ uint selectedIndex = m_iconWidget->index(m_iconWidget->currentItem());
+ m_pixmap = pixmapFromURL(m_imageList[selectedIndex].imageURL());
+
+ if(m_pixmap.isNull()) {
+ KMessageBox::sorry(this,
+ i18n("The cover you have selected is unavailable. Please select another."),
+ i18n("Cover Unavailable"));
+ QPixmap blankPix;
+ blankPix.resize(80, 80);
+ blankPix.fill();
+ m_iconWidget->currentItem()->setPixmap(blankPix, true, true);
+ return;
+ }
+
+ m_takeIt = true;
+ m_newSearch = false;
+ hide();
+}
+
+void GoogleFetcherDialog::slotCancel()
+{
+ m_takeIt = true;
+ m_newSearch = false;
+ m_pixmap = QPixmap();
+ hide();
+}
+
+void GoogleFetcherDialog::slotUser1()
+{
+ m_takeIt = false;
+ m_newSearch = true;
+ m_pixmap = QPixmap();
+ hide();
+}
+
+void GoogleFetcherDialog::imgSizeChanged(int index)
+{
+ GoogleFetcher::ImageSize imageSize = GoogleFetcher::All;
+ switch (index) {
+ case 1:
+ imageSize = GoogleFetcher::Icon;
+ break;
+ case 2:
+ imageSize = GoogleFetcher::Small;
+ break;
+ case 3:
+ imageSize = GoogleFetcher::Medium;
+ break;
+ case 4:
+ imageSize=GoogleFetcher::Large;
+ break;
+ case 5:
+ imageSize=GoogleFetcher::XLarge;
+ break;
+ default:
+ break;
+ }
+ emit sizeChanged(imageSize);
+}
+
+QPixmap GoogleFetcherDialog::fetchedImage(uint index) const
+{
+ return (index > m_imageList.count()) ? QPixmap() : pixmapFromURL(m_imageList[index].imageURL());
+}
+
+QPixmap GoogleFetcherDialog::pixmapFromURL(const KURL &url) const
+{
+ QString file;
+
+ if(KIO::NetAccess::download(url, file, 0)) {
+ QPixmap pixmap = QPixmap(file);
+ KIO::NetAccess::removeTempFile(file);
+ return pixmap;
+ }
+ KIO::NetAccess::removeTempFile(file);
+ return QPixmap();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CoverIconViewItem
+////////////////////////////////////////////////////////////////////////////////
+
+CoverIconViewItem::CoverIconViewItem(QIconView *parent, const GoogleImage &image) :
+ QObject(parent), KIconViewItem(parent, parent->lastItem(), image.size()), m_job(0)
+{
+ // Set up the iconViewItem
+
+ QPixmap mainMap;
+ mainMap.resize(80, 80);
+ mainMap.fill();
+ setPixmap(mainMap, true, true);
+
+ // Start downloading the image.
+
+ m_job = KIO::get(image.thumbURL(), false, false);
+ connect(m_job, SIGNAL(result(KIO::Job *)), this, SLOT(imageResult(KIO::Job *)));
+ connect(m_job, SIGNAL(data(KIO::Job *, const QByteArray &)),
+ this, SLOT(imageData(KIO::Job *, const QByteArray &)));
+}
+
+CoverIconViewItem::~CoverIconViewItem()
+{
+ if(m_job) {
+ m_job->kill();
+
+ // Drain results issued by KIO before being deleted,
+ // and before deleting the job.
+ kapp->eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
+
+ delete m_job;
+ }
+}
+
+void CoverIconViewItem::imageData(KIO::Job *, const QByteArray &data)
+{
+ int currentSize = m_buffer.size();
+ m_buffer.resize(currentSize + data.size(), QGArray::SpeedOptim);
+ memcpy(&(m_buffer.data()[currentSize]), data.data(), data.size());
+}
+
+void CoverIconViewItem::imageResult(KIO::Job *job)
+{
+ if(job->error())
+ return;
+
+ QPixmap iconImage(m_buffer);
+ iconImage = QImage(iconImage.convertToImage()).smoothScale(80, 80);
+ setPixmap(iconImage, true, true);
+}
+
+#include "googlefetcherdialog.moc"
diff --git a/kaffeine/src/input/audiobrowser/googlefetcherdialog.h b/kaffeine/src/input/audiobrowser/googlefetcherdialog.h
new file mode 100644
index 0000000..48ec70c
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/googlefetcherdialog.h
@@ -0,0 +1,98 @@
+/*
+ * googlefetcherdialog.h
+ *
+ * Copyright (C) 2004 Nathan Toone <nathan@toonetown.com>
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef GOOGLEFETCHERDIALOG_H
+#define GOOGLEFETCHERDIALOG_H
+
+#include <kiconview.h>
+#include <kio/job.h>
+
+#include "googlefetcher.h"
+
+class KURL;
+
+class GoogleFetcherDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ GoogleFetcherDialog(const QString &name,
+ const GoogleImageList &urlList,
+ const QString &artist,
+ const QString &album,
+ QWidget *parent = 0);
+
+ virtual ~GoogleFetcherDialog();
+
+ QPixmap result() const { return m_pixmap; }
+ bool takeIt() const { return m_takeIt; }
+ bool newSearch() const { return m_newSearch; }
+
+ void setLayout();
+ void setImageList(const GoogleImageList &urlList);
+
+public slots:
+ int exec();
+ void refreshScreen(GoogleImageList &list);
+
+signals:
+ void sizeChanged(GoogleFetcher::ImageSize);
+
+protected slots:
+ void slotOk();
+ void slotCancel();
+ void slotUser1();
+ void imgSizeChanged(int index);
+
+private:
+ QPixmap fetchedImage(uint index) const;
+ QPixmap pixmapFromURL(const KURL &url) const;
+
+ QPixmap m_pixmap;
+ GoogleImageList m_imageList;
+ KIconView *m_iconWidget;
+ bool m_takeIt;
+ bool m_newSearch;
+ QString m_artist, m_album;
+};
+
+namespace KIO
+{
+ class TransferJob;
+}
+
+class CoverIconViewItem : public QObject, public KIconViewItem
+{
+ Q_OBJECT
+
+public:
+ CoverIconViewItem(QIconView *parent, const GoogleImage &image);
+ ~CoverIconViewItem();
+
+private slots:
+ void imageData(KIO::Job *job, const QByteArray &data);
+ void imageResult(KIO::Job* job);
+
+private:
+ QByteArray m_buffer;
+ QGuardedPtr<KIO::TransferJob> m_job;
+};
+
+#endif /* GOOGLEFETCHERDIALOG_H */
diff --git a/kaffeine/src/input/audiobrowser/kaffeineplaylist.rc b/kaffeine/src/input/audiobrowser/kaffeineplaylist.rc
new file mode 100644
index 0000000..a274d74
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/kaffeineplaylist.rc
@@ -0,0 +1,17 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kaffeineplaylist" version="4">
+<MenuBar>
+ <Menu name="playlist"><text>Play&amp;list</text>
+ <Action name="playlist_shuffle"/>
+ <Action name="playlist_repeat"/>
+ <Action name="playlist_autocover"/>
+ <Action name="playlist_showplayer"/>
+ <Separator/>
+ <Action name="playlist_clear"/>
+ <Action name="playlist_new"/>
+ <Action name="playlist_load"/>
+ <Action name="playlist_save_as"/>
+ <Action name="playlist_remove"/>
+ </Menu>
+</MenuBar>
+</kpartgui>
diff --git a/kaffeine/src/input/audiobrowser/playlist.cpp b/kaffeine/src/input/audiobrowser/playlist.cpp
new file mode 100644
index 0000000..480d70b
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/playlist.cpp
@@ -0,0 +1,2365 @@
+/*
+ * playlist.cpp
+ *
+ * Copyright (C) 2003-2005 Jürgen Kofler <kaffeine@gmx.net>
+ * Copyright (C) 2005-2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <krandomsequence.h>
+#include <kapplication.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+#include <kstandarddirs.h>
+#include <kmessagebox.h>
+#include <kio/netaccess.h>
+#include <kio/job.h>
+#include <kprogress.h>
+#include <kfilemetainfo.h>
+#include <klineedit.h>
+#include <kcombobox.h>
+#include <kpushbutton.h>
+#include <kdebug.h>
+#include <kurl.h>
+#include <kaccel.h>
+#include <dcopref.h>
+#include <ktoolbar.h>
+#include <kcolordialog.h>
+#include <kurlcombobox.h>
+#include <kurlcompletion.h>
+
+#include <qlabel.h>
+#include <qclipboard.h>
+#include <qdragobject.h>
+#include <qstringlist.h>
+#include <qdom.h>
+#include <qxml.h>
+#include <qregexp.h>
+#include <qheader.h>
+#include <qlayout.h>
+#include <qpixmap.h>
+#include <qvbox.h>
+#include <qlistbox.h>
+#include <qtextcodec.h>
+#include <qtooltip.h>
+#include <qinputdialog.h>
+#include <qtimer.h>
+#include <qwhatsthis.h>
+#include <qpopupmenu.h>
+
+#include "googlefetcher.h"
+#include "mrl.h"
+#include "playlistimport.h"
+#include "playlistitem.h"
+#include "playlist.h"
+#include "playlist.moc"
+
+
+
+RollTitle::RollTitle( QWidget *parent ) : QLabel( "I", parent )
+{
+ QColorGroup cg = parentWidget()->colorGroup();
+ QColor base = cg.base();
+ QColor selection = cg.highlight();
+ int r = (base.red() + selection.red()) / 2;
+ int b = (base.blue() + selection.blue()) / 2;
+ int g = (base.green() + selection.green()) / 2;
+ back = QColor(r, g, b);
+ fore = parentWidget()->colorGroup().text();
+ setPaletteBackgroundColor( back );
+ setPaletteForegroundColor( fore );
+ setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
+ title = " ##### ";
+ titleOffset = 0;
+ setTitle( title );
+ connect( &titleTimer, SIGNAL( timeout() ), this, SLOT( rollTitle() ) );
+ titleTimer.start( 50 );
+}
+
+void RollTitle::setTitle( MRL mrl )
+{
+ title = " ##### ";
+ QString s1 = mrl.artist().stripWhiteSpace();
+ QString s2 = mrl.album().stripWhiteSpace();
+ QString s3 = mrl.title().stripWhiteSpace();
+ if ( !s1.isEmpty() )
+ title+= s1+" - ";
+ if ( !s2.isEmpty() )
+ title+= s2+" - ";
+ if ( s3.isEmpty() )
+ title+= mrl.url();
+ else
+ title+= s3;
+ titleOffset = 0;
+ setTitle( title );
+}
+
+void RollTitle::setTitle( QString t )
+{
+ QLabel *lab = new QLabel( t, this );
+ lab->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
+ lab->resize( lab->sizeHint() );
+ int x = 2*lab->frameWidth();
+ titlePix = QPixmap( lab->width()-x, height()-x, -1, QPixmap::BestOptim );
+ delete lab;
+ QPainter p( &titlePix );
+ p.fillRect( 0, 0, titlePix.width(), titlePix.height(), back );
+ p.setPen( fore );
+ p.setFont( font() );
+ p.drawText( QRect(0,(titlePix.height()-QFontInfo(font()).pointSize())/2,titlePix.width(),QFontInfo(font()).pointSize()*2), Qt::AlignAuto|Qt::SingleLine, t );
+ p.end();
+}
+
+void RollTitle::rollTitle()
+{
+ int w = 2*frameWidth();
+ QPixmap pix( width()-w, height()-w, -1, QPixmap::BestOptim );
+ QPainter p1( &pix );
+ p1.fillRect( 0, 0, pix.width(), pix.height(), back );
+ p1.end();
+ int x = titlePix.width()-titleOffset;
+ bitBlt( &pix, 0, 0, &titlePix, titleOffset, 0, x, titlePix.height(), CopyROP );
+ while ( x<pix.width() ) {
+ bitBlt( &pix, x, 0, &titlePix, 0, 0, titlePix.width(), titlePix.height(), CopyROP );
+ x+= titlePix.width();
+ }
+ ++titleOffset;
+ if ( titleOffset>titlePix.width() )
+ titleOffset = 0;
+ bitBlt( this, w/2, w/2, &pix, 0, 0, width()-w, height()-w, CopyROP );
+}
+
+void RollTitle::paintEvent( QPaintEvent *pe )
+{
+ QLabel::paintEvent( pe );
+ QColorGroup cg = parentWidget()->colorGroup();
+ QColor base = cg.base();
+ QColor selection = cg.highlight();
+ int r = (base.red() + selection.red()) / 2;
+ int b = (base.blue() + selection.blue()) / 2;
+ int g = (base.green() + selection.green()) / 2;
+ back=QColor(r,g,b);
+ setPaletteBackgroundColor( back );
+ fore = parentWidget()->colorGroup().text();
+ setPaletteForegroundColor( fore );
+ setTitle( title );
+}
+
+
+
+struct CoverPopup : public QWidget
+{
+ CoverPopup(const QPixmap &image, const QPoint &p) :
+ QWidget(0, 0, WDestructiveClose | WX11BypassWM)
+ {
+ QHBoxLayout *layout = new QHBoxLayout(this);
+ QLabel *label = new QLabel(this);
+
+ layout->addWidget(label);
+ label->setFrameStyle(QFrame::Box | QFrame::Raised);
+ label->setLineWidth(1);
+ label->setPixmap(image);
+
+ setGeometry(p.x(), p.y(), label->width(), label->height());
+ show();
+ }
+ virtual void leaveEvent(QEvent *) { close(); }
+ virtual void mouseReleaseEvent(QMouseEvent *) { close(); }
+};
+
+CoverFrame::CoverFrame( QWidget *parent ) : QFrame( parent )
+{
+ imagePath = "";
+ QString path = locate("appdata", "nocover.png");
+ if ( !path )
+ path = locate("data", "kaffeine/nocover.png");
+ noCoverPix.convertFromImage( QImage(path) );
+ setPaletteBackgroundPixmap( noCoverPix );
+}
+
+CoverFrame::~CoverFrame()
+{
+}
+
+void CoverFrame::setCoverPixmap( const QString &path )
+{
+ QPixmap pix;
+ QImage img;
+
+ img = QImage( path );
+ if ( !img.isNull() ) {
+ img = img.smoothScale( 80, 80 );
+ pix.convertFromImage( img );
+ setPaletteBackgroundPixmap( pix );
+ imagePath = path;
+ }
+ else {
+ setPaletteBackgroundPixmap( noCoverPix );
+ imagePath = "";
+ }
+}
+
+void CoverFrame::popup( const QPixmap &pix ) const
+{
+ QPoint mouse = QCursor::pos();
+ QRect desktop = KApplication::desktop()->screenGeometry(mouse);
+ int x = mouse.x();
+ int y = mouse.y();
+ int height = pix.height() + 4;
+ int width = pix.width() + 4;
+
+ // Detect the right direction to pop up (always towards the center of the
+ // screen), try to pop up with the mouse pointer 10 pixels into the image in
+ // both directions. If we're too close to the screen border for this margin,
+ // show it at the screen edge, accounting for the four pixels (two on each
+ // side) for the window border.
+
+ if(x - desktop.x() < desktop.width() / 2)
+ x = (x - desktop.x() < 10) ? desktop.x() : (x - 10);
+ else
+ x = (x - desktop.x() > desktop.width() - 10) ? desktop.width() - width +desktop.x() : (x - width + 10);
+
+ if(y - desktop.y() < desktop.height() / 2)
+ y = (y - desktop.y() < 10) ? desktop.y() : (y - 10);
+ else
+ y = (y - desktop.y() > desktop.height() - 10) ? desktop.height() - height + desktop.y() : (y - height + 10);
+
+ new CoverPopup( pix, QPoint(x, y) );
+}
+
+void CoverFrame::mousePressEvent( QMouseEvent *e )
+{
+ int i;
+ QPixmap pix;
+
+ switch ( e->button() ) {
+ case LeftButton: {
+ if ( imagePath.isEmpty() )
+ break;
+ pix.convertFromImage( QImage( imagePath ) );
+ if ( !pix.isNull() )
+ popup( pix );
+ break;
+ }
+ case RightButton: {
+ QPopupMenu pop( this );
+ pop.insertItem( i18n("Choose a Cover..."), 1 );
+ pop.insertItem( i18n("Gallery..."), 2 );
+ i = pop.exec( QCursor::pos() );
+ if ( i==1 )
+ emit changeCurrentCover();
+ else if ( i==2 )
+ emit gallery();
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+
+PlayList::PlayList( QWidget* parent, QObject *objParent, const char *name ) : KaffeineInput(objParent , name),
+ m_playTime(0), m_playTimeVisible(0), m_countVisible(0), m_searchSelection(false),
+ m_metaOnLoading(true), m_sortAscending(true), m_currentEntry(NULL), m_currentRandomListEntry(-1),
+ m_endless(false), m_random(false), m_useAlternateEncoding(false), m_alternateEncoding("ISO 8859-1")
+{
+ google = NULL;
+
+ mainWidget = new QVBox( parent );
+ //mainWidget->setSizePolicy( QSizePolicy (QSizePolicy::Preferred, QSizePolicy::Preferred) );
+ hSplit = new QSplitter( mainWidget );
+ hSplit->setOpaqueResize( true );
+ panel = new QVBox( hSplit );
+ playlist = new QWidget( hSplit );
+ hSplit->moveToFirst( panel );
+ hSplit->setResizeMode( panel, QSplitter::KeepSize );
+
+ vSplit = new QSplitter( QSplitter::Vertical, panel );
+ vSplit->setOpaqueResize( true );
+ QWidget *vb = new QWidget( vSplit );
+ KToolBar *tb = new KToolBar( vb );
+ QVBoxLayout *v = new QVBoxLayout( vb, 0, 0 );
+ v->addWidget( tb );
+ tb->setIconSize( 16 );
+
+ browserComb = new KURLComboBox( KURLComboBox::Directories, true, vb );
+ browserComb->setCompletionObject( new KURLCompletion( KURLCompletion::DirCompletion ) );
+ browserComb->setAutoDeleteCompletionObject( true );
+ browserComb->setMaxItems( 10 );
+ browserComb->setFocusPolicy(QWidget::ClickFocus);
+
+
+ /* if (!m_medium)
+ m_combo->lineEdit()->setText( location->path() );
+ else
+ m_combo->lineEdit()->setText( "/" );*/
+
+ QVBoxLayout *v1 = new QVBoxLayout( 0, 3, 3 );
+ v1->addWidget( browserComb );
+ fileBrowser = new KDirOperator( KURL("/"), vb );
+ fileBrowser->setupMenu( KDirOperator::SortActions|KDirOperator::NavActions|KDirOperator::ViewActions );
+ view = new KFileIconView( fileBrowser, "view" );
+ view->setSelectionMode( KFile::Multi );
+ fileBrowser->setMode( KFile::Files );
+ fileBrowser->setView( view );
+ fileBrowser->setViewConfig( KGlobal::config(), "PlaylistFileBrowser" );
+ fileBrowser->setOnlyDoubleClickSelectsFiles( true );
+ v1->addWidget( fileBrowser );
+ v->addLayout( v1 );
+
+ KActionCollection *col = fileBrowser->actionCollection();
+ col->action( "up" )->plug( tb );
+ col->action( "back" )->plug( tb );
+ col->action( "forward" )->plug( tb );
+ col->action( "reload" )->plug( tb );
+ col->action( "home" )->plug( tb );
+
+ vSplit->moveToFirst( vb );
+ playerBox = new QVBox( vSplit );
+ playerBox->setMinimumHeight( 50 );
+ playerBox->setMinimumWidth( 200 );
+ vSplit->moveToLast( playerBox );
+
+ m_playlistDirectory = locateLocal("appdata", "playlists");
+ m_playlistDirectory.append("/");
+ KIO::NetAccess::mkdir(m_playlistDirectory, mainWidget);
+ kdDebug() << "PLAYLIST" << endl;
+
+ QGridLayout* layout = new QGridLayout( playlist, 4, 2, 3 );
+
+ m_list = new UrlListView(playlist);
+ mainWidget->setAcceptDrops(true);
+ m_list->setHScrollBarMode(KListView::AlwaysOff);
+ m_list->setItemMargin(2);
+ m_list->setMargin(0);
+ m_list->setSelectionMode(QListView::Extended);
+ m_list->addColumn("");
+ m_list->addColumn(i18n("Title"));
+ m_list->addColumn(i18n("Artist"));
+ m_list->addColumn(i18n("Album"));
+ m_list->addColumn(i18n("Track"));
+ m_list->addColumn(i18n("Length"));
+ m_list->setShowToolTips(true);
+ m_list->setColumnWidthMode(MIME_COLUMN, QListView::Manual);
+ m_list->setColumnWidthMode(TITLE_COLUMN, QListView::Manual);
+ m_list->setColumnWidthMode(ARTIST_COLUMN, QListView::Manual);
+ m_list->setColumnWidthMode(ALBUM_COLUMN, QListView::Manual);
+ m_list->setColumnWidthMode(TRACK_COLUMN, QListView::Manual);
+ m_list->setColumnWidthMode(LENGTH_COLUMN, QListView::Manual);
+ m_list->setResizeMode(QListView::NoColumn);
+ KConfig* config = kapp->config();
+ m_list->restoreLayout(config, "Playlist Layout");
+ m_list->setFullWidth(true);
+ m_list->setSorting(-1);
+ m_list->setDragEnabled(true);
+ m_list->setAcceptDrops(true);
+ m_list->setDropVisualizer(true);
+ m_list->setItemsMovable(true);
+ m_list->setItemsRenameable(true);
+ m_list->setRenameable(TITLE_COLUMN);
+ m_list->setRenameable(ARTIST_COLUMN);
+ m_list->setRenameable(ALBUM_COLUMN);
+ m_list->setRenameable(TRACK_COLUMN);
+ m_list->setAllColumnsShowFocus(true);
+ m_list->setShowSortIndicator(true);
+ layout->addMultiCellWidget(m_list, 3, 3, 0, 1);
+
+ coverFrame = new CoverFrame( playlist );
+ coverFrame->setFixedWidth( 80 );
+ coverFrame->setFixedHeight( 80 );
+ layout->addMultiCellWidget(coverFrame, 0, 2, 0, 0);
+
+ QHBoxLayout *h1 = new QHBoxLayout();
+ searchBtn = new QToolButton( playlist );
+ searchBtn->setAutoRaise( true );
+ QToolTip::add( searchBtn, i18n("Search"));
+ searchBtn->setIconSet( KGlobal::iconLoader()->loadIconSet("locationbar_erase", KIcon::Small) );
+ h1->addWidget( searchBtn );
+ QLabel* filterLabel = new QLabel(i18n("Filter") + ":", playlist);
+ h1->addWidget(filterLabel);
+ m_playlistFilter = new KLineEdit(playlist);
+ m_playlistFilter->setFocusPolicy(QWidget::ClickFocus);
+ h1->addWidget(m_playlistFilter);
+ layout->addLayout( h1, 2, 1 );
+
+ QHBoxLayout *h2 = new QHBoxLayout();
+ QLabel* playlistLabel = new QLabel(i18n("Playlist:"), playlist);
+ h2->addWidget(playlistLabel);
+ m_playlistSelector = new KComboBox( playlist );
+ m_playlistSelector->setMinimumWidth(10);
+ m_playlistSelector->setSizePolicy( QSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::Preferred) );
+ m_playlistSelector->setEditable(true);
+ m_playlistSelector->setDuplicatesEnabled(false);
+ m_playlistSelector->setFocusPolicy(QWidget::ClickFocus);
+ QToolTip::add(m_playlistSelector, i18n("Select the active playlist. To change playlist name edit it and confirm with 'Return'."));
+ h2->addWidget(m_playlistSelector);
+ layout->addLayout( h2, 1, 1 );
+
+ roller = new RollTitle( playlist );
+ layout->addWidget( roller, 0, 1 );
+
+ KAccel* accel = new KAccel(mainWidget);
+ accel->insert("Delete selected", Qt::Key_Delete, this, SLOT(slotRemoveSelected()));
+
+ m_isCurrentEntry = UserIcon("playing");
+ m_cdPixmap = KGlobal::iconLoader()->loadIcon("cdtrack", KIcon::Small);
+
+ setXMLFile("kaffeineplaylist.rc");
+ setupActions();
+
+ QStrList formats = QImageIO::outputFormats();
+ coverImageFormat = "PNG";
+ for (int i=0; i<(int)formats.count(); i++ ) {
+ if ( QString(formats.at(i))=="JPEG" ) {
+ coverImageFormat = "JPEG";
+ break;
+ }
+ }
+
+ loadConfig( KGlobal::config() );
+
+ connect(coverFrame, SIGNAL(changeCurrentCover()), this, SLOT(chooseCurrentCover()));
+ connect(coverFrame, SIGNAL(gallery()), this, SLOT(showGallery()));
+ connect(browserComb, SIGNAL(urlActivated( const KURL& )), this, SLOT(setBrowserURL( const KURL& )));
+ connect(browserComb, SIGNAL(returnPressed( const QString& )), this, SLOT(setBrowserURL( const QString& )));
+ connect(fileBrowser, SIGNAL(urlEntered( const KURL& )), this, SLOT(browserURLChanged( const KURL& )));
+ connect(fileBrowser, SIGNAL(fileSelected(const KFileItem*)), this, SLOT(fileSelected(const KFileItem*)));
+ connect(m_playlistFilter, SIGNAL(textChanged(const QString&)), this, SLOT(slotFindText(const QString&)));
+ connect( searchBtn, SIGNAL(clicked()), this, SLOT(resetSearch()) );
+ connect(m_playlistSelector, SIGNAL(returnPressed(const QString&)), this, SLOT(slotNewPlaylistName(const QString&)));
+ connect(m_playlistSelector, SIGNAL(activated(int)),this, SLOT(slotPlaylistActivated(int)));
+ connect(m_list, SIGNAL(dropped(QDropEvent*, QListViewItem*)), this, SLOT(slotDropEvent(QDropEvent*, QListViewItem*)));
+ connect(m_list, SIGNAL(aboutToMove()), this, SLOT(slotPreDropEvent()));
+ connect(m_list, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(slotPlayDirect(QListViewItem*)));
+ connect(m_list, SIGNAL(returnPressed(QListViewItem*)), this, SLOT(slotPlayDirect(QListViewItem*)));
+ connect(m_list, SIGNAL(signalCut()), this, SLOT(slotCut()));
+ connect(m_list, SIGNAL(signalCopy()), this, SLOT(slotCopy()));
+ connect(m_list, SIGNAL(signalPaste()), this, SLOT(slotPaste()));
+ connect(m_list, SIGNAL(signalSelectAll()), this, SLOT(slotSelectAll()));
+ connect(m_list, SIGNAL(signalPlayItem(QListViewItem*)), this, SLOT(slotPlayDirect(QListViewItem*)));
+ connect(m_list, SIGNAL(signalPlaylistFromSelected()), this, SLOT(slotPlaylistFromSelected()));
+ connect(m_list, SIGNAL(signalAddToQueue(MRL)), this, SLOT(slotAddToQueue(MRL)));
+ connect(m_list->header(), SIGNAL(clicked(int)), this, SLOT(slotSort(int)));
+}
+
+void PlayList::togglePanel()
+{
+ if ( panel->isHidden() )
+ panel->show();
+ else
+ panel->hide();
+}
+
+void PlayList::getTargets( QStringList &uiNames, QStringList &iconNames, QStringList &targetNames )
+{
+ uiNames.append( i18n("Play Playlist") );
+ iconNames.append( "view_text" );
+ targetNames.append( "PLAYLIST" );
+}
+
+bool PlayList::execTarget( const QString &target )
+{
+ if ( target=="PLAYLIST" ) {
+ emit showMe( this );
+ QTimer::singleShot( 100, this, SLOT(startPlaylist()) );
+ return true;
+ }
+ return false;
+}
+
+void PlayList::setFileFilter( const QString& filter )
+{
+ m_fileFilter = filter;
+ fileBrowser->setNameFilter( m_fileFilter );
+}
+
+PlayList::~PlayList()
+{
+ delete m_list;
+}
+
+void PlayList::setupActions()
+{
+ m_repeat = new KToggleAction(i18n("&Repeat"), 0 , CTRL|Key_E, this, SLOT(slotRepeat()), actionCollection(),"playlist_repeat");
+ m_repeat->setStatusText(i18n("Loop playlist"));
+ m_shuffle = new KToggleAction(i18n("Sh&uffle"), 0 , CTRL|Key_R, this, SLOT(slotShuffle()), actionCollection(),"playlist_shuffle");
+ m_shuffle->setStatusText(i18n("Play items in random order"));
+ m_autoCover = new KToggleAction(i18n("Autodownload covers"), 0 , 0, this, SLOT(slotAutoCover()), actionCollection(),"playlist_autocover");
+ m_autoCover->setStatusText(i18n("Automatic dowloading of covers"));
+ m_showPlayer = new KToggleAction(i18n("Don't switch to player window"), 0 , 0, this, SLOT(slotShowPlayer()), actionCollection(),"playlist_showplayer");
+ m_showPlayer->setStatusText(i18n("Don't switch automatically to player window"));
+ new KAction(i18n("&Clear Current Playlist"), "eraser", 0, this, SLOT(slotClearList()), actionCollection(), "playlist_clear");
+ new KAction(i18n("Ne&w Playlist"), "filenew", 0, this, SLOT(slotNewList()), actionCollection(), "playlist_new");
+ new KAction(i18n("&Import Playlist..."), "project_open", 0, this, SLOT(slotPlaylistLoad()), actionCollection(), "playlist_load");
+ new KAction(i18n("&Save Current Playlist As..."), "filesaveas", 0, this, SLOT(slotPlaylistSaveAs()), actionCollection(), "playlist_save_as");
+ new KAction(i18n("Re&move Current Playlist"), "fileclose", 0, this, SLOT(slotPlaylistRemove()), actionCollection(), "playlist_remove");
+}
+
+void PlayList::slotClearList()
+{
+ clearList();
+}
+
+void PlayList::slotRepeat()
+{
+ setEndless(m_repeat->isChecked());
+}
+
+void PlayList::slotShuffle()
+{
+ setRandom(m_shuffle->isChecked());
+}
+
+void PlayList::slotAutoCover()
+{
+ m_cover = m_autoCover->isChecked();
+}
+
+void PlayList::slotShowPlayer()
+{
+}
+
+void PlayList::slotToggleShuffle()
+{
+ m_shuffle->setChecked(!m_shuffle->isChecked());
+ slotShuffle();
+}
+
+void PlayList::slotPlaylistLoad()
+{
+ QString path = KFileDialog::getOpenFileName(":kaffeine_openPlaylist", QString("*.kaffeine|") + i18n("Kaffeine Playlists") + "\n*.*|" + i18n("All Files"), 0, i18n("Open Playlist"));
+ if (path.isEmpty() || (!path.contains(".kaffeine", false)))
+ return;
+
+ loadPlaylist(path);
+}
+
+void PlayList::slotPlaylistSaveAs()
+{
+ QString startPath = ":kaffeine_savePlaylist";
+ //if (!lastPlaylist.isEmpty()) startPath = lastPlaylist;
+ QString path = KFileDialog::getSaveFileName(startPath,
+ QString("*.kaffeine|") + i18n("Kaffeine Playlists") + "\n" +
+ QString("*.m3u|") + i18n("M3U Playlists") + "\n" +
+ QString("*.pls|") + i18n("PLS Playlists") + "\n" +
+ "*.*|" + i18n("All Files"), 0, i18n("Save Playlist"));
+
+ if ( path.isEmpty() )
+ return;
+ if ( path.right(4).lower() == ".m3u" ) {
+ exportM3UPlaylist(path);
+ } else if ( path.right(4).lower() == ".pls" ) {
+ exportPLSPlaylist(path);
+ } else if ( path.right(9).lower() == ".kaffeine" ) {
+ savePlaylist(path);
+ } else {
+ path.append(".kaffeine");
+ savePlaylist(path);
+ }
+}
+
+void PlayList::slotPlaylistRemove()
+{
+ removeCurrentPlaylist();
+}
+
+QWidget* PlayList::wantPlayerWindow()
+{
+ return playerBox;
+}
+
+QWidget* PlayList::inputMainWidget()
+{
+ return mainWidget;
+}
+
+void PlayList::loadConfig(KConfig* config)
+{
+ QValueList<int> sl;
+ bool b;
+
+ config->setGroup("Playlist");
+ b = config->readBoolEntry("Endless Mode", false);
+ m_repeat->setChecked(b);
+ setEndless(b);
+ b = config->readBoolEntry("Random Mode", false);
+ m_shuffle->setChecked(b);
+ setRandom(b);
+ b = config->readBoolEntry("AutoCover", false);
+ m_autoCover->setChecked(b);
+ m_cover = b;
+ b = config->readBoolEntry("DontShowPlayer", false);
+ m_showPlayer->setChecked(b);
+
+ sl = config->readIntListEntry("HSplitSizes");
+ if ( sl.count() )
+ hSplit->setSizes( sl );
+ else {
+ sl.append( 200 );
+ sl.append( 200 );
+ hSplit->setSizes( sl );
+ }
+ vSplit->setSizes( config->readIntListEntry("VSplitSizes") );
+ QStringList list;
+ list = config->readListEntry("Playlists");
+ if (!list.count())
+ {
+ list.append(i18n("Playlist") + "1");
+ }
+ int lastRegularPlaylist = list.count();
+ list.append(i18n("NEW"));
+ m_playlistSelector->insertStringList(list);
+ m_currentPlaylist = config->readNumEntry("Current", 0);
+ if (m_currentPlaylist > lastRegularPlaylist)
+ m_currentPlaylist = 0;
+ m_playlistSelector->setCurrentItem(m_currentPlaylist);
+ add(m_playlistDirectory + m_playlistSelector->text(m_currentPlaylist) + ".kaffeine", NULL);
+ m_nextPlaylistNumber = config->readNumEntry("Next Playlist", 2);
+ QString currentEntry = config->readEntry("Current Entry", QString());
+ if ((!currentEntry.isEmpty()) && (m_list->childCount()))
+ {
+ QListViewItem* tmp = findByURL(currentEntry);
+ if (tmp)
+ setCurrentEntry(tmp, false);
+ }
+ fileBrowser->readConfig( config, "PlaylistFileBrowser" );
+ fileBrowser->setURL( KURL(config->readEntry( "FileBrowserURL", "/" )), true );
+ browserComb->setURL( KURL(config->readEntry( "FileBrowserURL", "/" )) );
+}
+
+void PlayList::saveConfig()
+{
+ saveConfig( KGlobal::config() );
+}
+
+void PlayList::saveConfig(KConfig* config)
+{
+ saveCurrentPlaylist();
+ config->setGroup("Playlist");
+ config->writeEntry("Endless Mode", m_repeat->isChecked());
+ config->writeEntry("Random Mode", m_shuffle->isChecked());
+ config->writeEntry("AutoCover", m_autoCover->isChecked());
+ config->writeEntry("DontShowPlayer", m_showPlayer->isChecked());
+ config->writeEntry( "HSplitSizes", hSplit->sizes() );
+ config->writeEntry( "VSplitSizes", vSplit->sizes() );
+ QStringList list;
+ QString text;
+ for (uint i=0; i < m_playlistSelector->listBox()->count(); i++)
+ {
+ text = m_playlistSelector->text(i);
+ if ( text != i18n("NEW") )
+ list.append(text);
+ }
+ config->writeEntry("Playlists", list);
+ config->writeEntry("Current", m_currentPlaylist);
+ config->writeEntry("Next Playlist", m_nextPlaylistNumber);
+ config->writeEntry("Current Entry", m_currentEntryMRL.url());
+ m_list->saveLayout(config, "Playlist Layout");
+ fileBrowser->writeConfig( config, "PlaylistFileBrowser" );
+ config->writeEntry( "FileBrowserURL", fileBrowser->url().url() );
+}
+
+void PlayList::closeEvent(QCloseEvent* ce)
+{
+ kdDebug() << "Playlist: close Event" << endl;
+ ce->ignore();
+}
+
+/******************************************
+ * get the urls from playlist
+ ******************************************/
+void PlayList::startPlaylist()
+{
+ MRL mrl;
+ if ( trackNumber( 1, mrl ) )
+ emit play( mrl, this );
+}
+
+bool PlayList::currentTrack( MRL &mrl )
+{
+ mrl = getCurrent();
+ if ( !mrl.isEmpty() )
+ return true;
+ else
+ return false;
+}
+
+MRL PlayList::getCurrent()
+{
+ if (isQueueMode())
+ {
+ m_queue.clear();
+ updateStatus();
+ }
+
+ if (m_random)
+ {
+ if (m_currentRandomListEntry == -1) return MRL();
+ setCurrentEntry(m_randomList.at(m_currentRandomListEntry));
+ return m_currentEntryMRL;
+ }
+
+ if (!m_currentEntry)
+ if (m_list->childCount() > 0)
+ {
+ if (m_list->firstChild()->isVisible())
+ setCurrentEntry(m_list->firstChild());
+ else
+ {
+ if (m_list->firstChild()->itemBelow())
+ setCurrentEntry(m_list->firstChild()->itemBelow());
+ else
+ return MRL();
+ }
+ }
+ else
+ return MRL();
+
+ setCurrentEntry(m_currentEntry);
+ return m_currentEntryMRL;
+}
+
+bool PlayList::playbackFinished( MRL &mrl )
+{
+ return nextTrack( mrl );
+}
+
+bool PlayList::nextTrack( MRL &mrl )
+{
+ if (isQueueMode())
+ {
+ mrl = m_queue.first();
+ m_queue.remove(m_queue.begin());
+ updateStatus();
+ return true;
+ }
+
+ if (!m_currentEntry) {
+ mrl = getCurrent();
+ if ( !mrl.isEmpty() )
+ return true;
+ else
+ return false;
+ }
+
+ if (m_random)
+ {
+ if ((m_currentRandomListEntry+1) < (int)m_randomList.count())
+ m_currentRandomListEntry += 1;
+ else
+ {
+ if (m_endless)
+ m_currentRandomListEntry = 0;
+ else
+ return false;
+ }
+ setCurrentEntry(m_randomList.at(m_currentRandomListEntry));
+ mrl = m_currentEntryMRL;
+ return true;
+ }
+
+ QListViewItem* tmpItem;
+ tmpItem = m_currentEntry->itemBelow();
+
+ if (tmpItem)
+ {
+ setCurrentEntry(tmpItem);
+ mrl = m_currentEntryMRL;
+ return true;
+ }
+ else
+ {
+ if (m_endless)
+ {
+ setCurrentEntry(m_list->firstChild());
+ mrl = m_currentEntryMRL;
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
+bool PlayList::previousTrack( MRL &mrl )
+{
+ if (isQueueMode())
+ {
+ m_queue.clear();
+ updateStatus();
+ }
+
+ if (!m_currentEntry) {
+ mrl = getCurrent();
+ if ( !mrl.isEmpty() )
+ return true;
+ else
+ return false;
+ }
+
+ if (m_random) {
+ if (m_currentRandomListEntry > 0)
+ m_currentRandomListEntry -= 1;
+ else {
+ if (m_endless)
+ m_currentRandomListEntry = m_randomList.count()-1;
+ else
+ return false;
+ }
+ setCurrentEntry(m_randomList.at(m_currentRandomListEntry));
+ mrl = m_currentEntryMRL;
+ return true;
+ }
+
+ QListViewItem* tmpItem;
+ tmpItem = m_currentEntry->itemAbove();
+
+ if (tmpItem) {
+ setCurrentEntry(tmpItem);
+ mrl = m_currentEntryMRL;
+ return true;
+ }
+ else {
+ if (m_endless) {
+ setCurrentEntry(getLast());
+ mrl = m_currentEntryMRL;
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
+bool PlayList::trackNumber( int number, MRL &mrl )
+{
+ if (number > m_list->childCount())
+ return false;
+
+ QListViewItem * item = m_list->firstChild();
+ for (int i = 1; i < number; i++)
+ item = item->nextSibling();
+
+ setCurrentEntry(item);
+ mrl = m_currentEntryMRL;
+ return true;
+}
+
+QListViewItem* PlayList::getLast()
+{
+ return m_list->lastItem();
+}
+
+QListViewItem* PlayList::getFirst()
+{
+ return m_list->firstChild();
+}
+
+QListViewItem* PlayList::findByURL(const QString& url)
+{
+ QListViewItemIterator it(m_list);
+ while (it.current())
+ {
+ if (dynamic_cast<PlaylistItem*>(*it)->url() == url)
+ {
+ return (*it);
+ }
+ ++it;
+ }
+
+ /* fallback */
+ return getFirst();
+}
+
+/********* set current entry (with play icon) ****************/
+
+void PlayList::setCurrentEntry(QListViewItem* item, bool playIcon)
+{
+ PlaylistItem* newItem = dynamic_cast<PlaylistItem*>(item);
+ PlaylistItem* oldItem = dynamic_cast<PlaylistItem*>(m_currentEntry);
+ if (m_currentEntry)
+ {
+ oldItem->setPlaying(false);
+ m_currentEntry->setPixmap(TITLE_COLUMN, QPixmap());
+ }
+ if (playIcon)
+ {
+ newItem->setPlaying(true);
+ item->setPixmap(TITLE_COLUMN, m_isCurrentEntry);
+ }
+ m_currentEntry = item;
+ if (m_random)
+ m_currentRandomListEntry = m_randomList.find(item);
+ m_currentEntryMRL = newItem->toMRL();
+ roller->setTitle( m_currentEntryMRL );
+ m_list->setCurrentItem(m_currentEntry);
+
+ m_list->ensureVisible(10, m_list->itemPos(m_currentEntry), 10, 30);
+}
+
+QListViewItem* PlayList::insertItem(QListViewItem* after, const MRL& m)
+{
+ PlaylistItem* tmp = NULL;
+ MRL mrl(m);
+
+ m_list->setSorting(-1);
+ QListViewItemIterator it(m_list);
+ while (it.current())
+ {
+ if (dynamic_cast<PlaylistItem*>(*it)->url() == mrl.url())
+ {
+ kdDebug() << "PlayList: Source '" << mrl.url() << "' still exists. Skipped." << endl;
+ return after;
+ }
+ ++it;
+ }
+
+ if (mrl.mime().isNull())
+ {
+ KMimeType::Ptr mime = KMimeType::findByURL(mrl.kurl().path());
+ mrl.setMime(mime->name());
+ }
+
+ tmp = new PlaylistItem(m_list, dynamic_cast<KListViewItem *>(after), mrl);
+ if (!tmp) return after;
+
+ if ((mrl.mime() == "video/dvd") || (mrl.mime() == "video/vcd") || (mrl.mime() == "audio/cd"))
+ tmp->setPixmap(MIME_COLUMN, m_cdPixmap);
+ else
+ tmp->setPixmap(MIME_COLUMN, KMimeType::mimeType(mrl.mime())->pixmap(KIcon::Small));
+
+ if (tmp->length().contains(':'))
+ m_playTime += timeStringToMs(tmp->length());
+
+ if (m_searchSelection)
+ {
+ QString text = m_playlistFilter->text();
+ if ((!tmp->title().contains(text, false)) && (!tmp->url().contains(text, false))
+ && (!tmp->artist().contains(text, false)) && (!tmp->album().contains(text, false)))
+ {
+ tmp->setVisible(false);
+ }
+ }
+
+ if (tmp->isVisible())
+ {
+ if (tmp->length().contains(':'));
+ m_playTimeVisible += timeStringToMs(tmp->length());
+ m_countVisible++;
+ }
+
+ return tmp;
+}
+
+void PlayList::fileSelected( const KFileItem *item )
+{
+ if ( !item )
+ return;
+ add( QStringList( item->url().path() ), NULL );
+ QListViewItem* tmp = findByURL(item->url().path());
+ if (tmp) {
+ setCurrentEntry(tmp);
+ emit play(m_currentEntryMRL, this);
+ }
+}
+
+void PlayList::setBrowserURL( const QString &path )
+{
+ fileBrowser->setURL( KURL(path), true );
+}
+
+void PlayList::setBrowserURL( const KURL &path )
+{
+ fileBrowser->setURL( path, true );
+}
+
+void PlayList::browserURLChanged( const KURL &u )
+{
+ QString url;
+
+ if ( u.isLocalFile() )
+ url = u.path();
+ else
+ url = u.prettyURL();
+
+ QStringList urls = browserComb->urls();
+ urls.remove( url ); // do not duplicate
+ urls.prepend( url );
+ browserComb->setURLs( urls, KURLComboBox::RemoveBottom );
+}
+
+void PlayList::add(const QString& url, QListViewItem* after)
+{
+ add(QStringList(url), after);
+}
+
+
+void PlayList::add(const QStringList& urlList, QListViewItem* after)
+{
+ QListViewItem* tmp = NULL;
+ QStringList urls(urlList);
+
+ QString ext;
+ QString subtitleURL;
+ QStringList subs;
+ KURL tmpKURL;
+ bool playlist;
+ MRL mrl;
+ QValueList<MRL> mrlList;
+ QString mediadevice="";
+
+ KProgressDialog* progress = NULL;
+ progress = new KProgressDialog(mainWidget, "importprogress", QString::null, i18n("Importing media resources..."));
+ progress->progressBar()->setTotalSteps(urls.count());
+ progress->show();
+
+ kdDebug() << "PlayList: add " << urls.count() << " items to playlist" << endl;
+
+ for (uint i = 0; i < urls.count(); i++)
+ {
+ mrl = MRL(urls[i]);
+ QString url(mrl.kurl().prettyURL());
+
+ if (mrl.kurl().protocol() == "media" || url.startsWith("system:/media/"))
+ {
+ QString mediaName;
+ if (url.startsWith("system:/media/"))
+ mediaName = url.mid(14);
+ else
+ mediaName = url.mid(7);
+ int slash = mediaName.find("/");
+ QString filePath(mediaName.mid(slash));
+ if (filePath == "/")
+ filePath = "";
+ mediaName = mediaName.left(slash);
+
+ DCOPRef mediamanager("kded","mediamanager");
+ DCOPReply reply = mediamanager.call("properties(QString)",mediaName);
+ if (reply.isValid())
+ {
+ QStringList properties = reply;
+ if (properties.isEmpty()) break;
+ url = properties[6] + filePath;
+ if (filePath.isEmpty())
+ {
+ if (properties[10] == "media/audiocd")
+ {
+ mediadevice = properties[5];
+ delete progress;
+ emit signalRequestForAudioCD(mediadevice);
+ return;
+ }
+ if (properties[10] == "media/dvdvideo")
+ {
+ mediadevice = properties[5];
+ delete progress;
+ emit signalRequestForDVD(mediadevice);
+ return;
+ }
+ if ((properties[10] == "media/vcd") || (properties[10] == "media/svcd"))
+ {
+ mediadevice = properties[5];
+ delete progress;
+ emit signalRequestForVCD(mediadevice);
+ return;
+ }
+ }
+ mrl = MRL(url);
+ }
+ }
+
+ if (mrl.kurl().isLocalFile())
+ {
+ if (!QFile::exists(mrl.kurl().path()))
+ continue;
+ mrl.setTitle(mrl.kurl().fileName());
+ mrl.setURL(mrl.kurl().path());
+ }
+ else
+ {
+ mrl.setTitle(mrl.url());
+ }
+
+ //kdDebug() << "PlayList: Check url " << mrl.url() << endl;
+ /*********** determine extension and mime type ************/
+
+ ext = mrl.kurl().fileName();
+ ext = ext.remove(0 , ext.findRev('.') +1).lower();
+ // kdDebug() << "Extension: " << ext << endl;
+
+ //kdDebug() << "PlayList: Try to determine mime of: " << mrl.url() << endl;
+ KMimeType::Ptr mime = KMimeType::findByURL(mrl.kurl().path()); /* works only with path() (without protocol)
+ e.g. http://www.somafm.com/indipop.pls
+ path: /indipop.pls */
+ //kdDebug() << "Mime: " << mime->name() << endl;
+ /*** check for kaffeine/noatun/pls/asx/m3u playlist ***/
+ mrl.setMime(mime->name());
+
+ /******** some special processing for local files! *******/
+ if (mrl.kurl().isLocalFile())
+ {
+ /* playlist ? */
+ if ((mime->name() == "text/plain") || (mime->name() == "text/xml") || (mime->name() == "application/x-kaffeine")
+ || (mime->name() == "audio/x-scpls") || (mime->name() == "audio/x-mpegurl" || (mime->name() == "audio/mpegurl")
+ || (ext == "asx") || (ext == "asf") || (ext == "wvx") || (ext == "wax"))) /* windows meta files */
+ {
+ kdDebug() << "PlayList: Check for kaffeine/noatun/m3u/pls/asx playlist\n";
+
+ mrlList.clear();
+ playlist = false;
+ QFile file(mrl.url());
+ file.open(IO_ReadOnly);
+
+ QTextStream stream(&file);
+ QString firstLine = stream.readLine();
+ QString secondLine = stream.readLine();
+ file.close();
+
+ if (secondLine.contains("kaffeine", false))
+ {
+ kdDebug() << "PlayList: Try loading kaffeine playlist\n";
+ playlist = PlaylistImport::kaffeine(mrl.url(), mrlList);
+ if (!playlist)
+ continue;
+ }
+ if (secondLine.contains("noatun", false))
+ {
+ kdDebug() << "PlayList: Try loading noatun playlist\n";
+ playlist = PlaylistImport::noatun(mrl.url(), mrlList);
+ }
+ if (firstLine.contains("asx", false))
+ {
+ kdDebug() << "PlayList: Try loading asx playlist\n";
+ playlist = PlaylistImport::asx(mrl.url(), mrlList);
+ }
+ if ( (firstLine.contains("[playlist]", false)) || (ext == "pls") )
+ {
+ kdDebug() << "PlayList: Try loading pls playlist\n";
+ playlist = PlaylistImport::pls(mrl.url(), mrlList);
+ }
+ if (ext == "m3u") //identify by extension
+ {
+ kdDebug() << "PlayList: Try loading m3u playlist\n";
+ playlist = PlaylistImport::m3u(mrl.url(), mrlList);
+ }
+ if (playlist)
+ {
+ QValueList<MRL>::ConstIterator end(mrlList.end());
+ for (QValueList<MRL>::ConstIterator it = mrlList.begin(); it != end; ++it)
+ after = insertItem(after, *it);
+ continue;
+ }
+
+ }
+
+ /* check for ram playlist */
+ if ( (ext == "ra") || (ext == "rm") || (ext == "ram") || (ext == "lsc") || (ext == "pl") )
+ {
+ mrlList.clear();
+ kdDebug() << "PlayList: Try loading ram playlist\n";
+ if (PlaylistImport::ram(mrl, mrlList, mainWidget->parentWidget()))
+ {
+ QValueList<MRL>::ConstIterator end(mrlList.end());
+ for (QValueList<MRL>::ConstIterator it = mrlList.begin(); it != end; ++it)
+ after = insertItem(after, *it);
+ continue;
+ }
+ }
+
+ /**** a directory ? ****/
+ if (mime->name() == "inode/directory")
+ {
+ kdDebug() << "PlayList: Add Directory: " << mrl.url() << endl;
+
+ QDir d(mrl.url());
+ uint x;
+
+ /* subdirs */
+ QStringList entryList = d.entryList(QDir::Dirs, QDir::Name);
+ for (x = 0; x < entryList.count(); x++)
+ {
+ if (entryList[x][0] != '.')
+ {
+ urls.append(mrl.url() + "/" + entryList[x]);
+ }
+ }
+
+ /* Media files */
+ /* Exclude subtitles because they are examined twice : */
+ /* Once for movie and once per subtitle - very annoying*/
+ QString fileFilter = m_fileFilter;
+ fileFilter.remove("*.srt",false);
+ fileFilter.remove("*.ssa",false);
+ fileFilter.remove("*.txt",false);
+ fileFilter.remove("*.asc",false);
+ fileFilter.remove("*.smi",false);
+ fileFilter.remove("*.sub",false);
+ entryList = d.entryList(fileFilter, QDir::Files, QDir::Name );
+ for (x = 0; x < entryList.count(); x++)
+ {
+ urls.append(mrl.url() + "/" + entryList[x]);
+ }
+
+ progress->progressBar()->setTotalSteps(urls.count());
+ continue; /* dont add directory to playlist */
+ }
+
+ /*** append subtitle files to the movie ***/
+ if ((ext == "srt") || (ext == "ssa") || (ext == "txt") ||
+ (ext == "asc") || (ext == "smi") || (ext == "sub"))
+ {
+ QStringList movies;
+ QString movieURL;
+ QListViewItemIterator it(m_list);
+ while (it.current())
+ {
+ if (dynamic_cast<PlaylistItem*>(*it)->mime().contains("video"))
+ movies << dynamic_cast<PlaylistItem*>(*it)->url();
+ ++it;
+ }
+ if (movies.count() == 1)
+ movieURL = movies[0];
+ else if (movies.count() >= 2)
+ {
+ MovieChooser *mc = new MovieChooser(movies, mrl.url(), mainWidget);
+ if(mc->exec() == QDialog::Accepted)
+ movieURL = mc->getSelection();
+ delete mc;
+ }
+ it = m_list;
+ while (it.current())
+ {
+ if (dynamic_cast<PlaylistItem*>(*it)->url() == movieURL)
+ {
+ kdDebug() << "PlayList: adding subtitle to movie " << dynamic_cast<PlaylistItem*>(*it)->url() << endl;
+ (dynamic_cast<PlaylistItem*>(*it))->addSubtitle(mrl.url());
+ break;
+ }
+ ++it;
+ }
+ continue;
+ }
+
+ /*** get meta tags ****/
+ if (m_metaOnLoading)
+ getMetaInfo(mrl, mime->name());
+
+ /* Get all suported subs in movie dir, clear out
+ * those starting with a different name than the movie,
+ * prompt the user to select a sub
+ */
+ if (mime->name().contains("video"))
+ {
+ kdDebug() << "PlayList: Check for subtitle files" << endl;
+ subtitleURL = QString::null;
+ QDir *d = new QDir(mrl.url().section('/',0,-2));
+ QString filename = mrl.url().section('/',-1,-1);
+ subs = QStringList();
+ //Do a case insensitive search for subs
+ QStringList dirListing = d->entryList(QDir::Files|QDir::NoSymLinks); //cache directory listing
+ bool matches = false;
+ QStringList::Iterator end(dirListing.end());
+ for(QStringList::Iterator it = dirListing.begin(); it != end; ++it )
+ {
+ if(startsWith(*it, filename.section('.',0,-2), false)) //If filenames (without extensions) match
+ {
+ if( endsWith(*it, ".srt", false) || endsWith(*it, ".ssa", false) ||
+ endsWith(*it, ".txt", false) || endsWith(*it, ".smi", false) ||
+ endsWith(*it, ".asc", false) || endsWith(*it, ".sub", false) )
+ matches = true;
+
+ if(matches) {
+ subs.append(*it); //This is a subtitle for our movie
+ }
+ matches = false;
+ }
+ }
+
+ if((subs.count() > 1)) {
+ subs.prepend(i18n("(no subtitles)"));
+ subs.append(i18n("Other subtitle..."));
+ subtitleURL = QString::null;
+ SubtitleChooser *sc = new SubtitleChooser(subs, filename, mainWidget);
+
+ THERE: if(sc->exec() == QDialog::Accepted)
+ {
+ if((sc->getSelection() != i18n("(no subtitles)")) && (sc->getSelection() != i18n("Other subtitle...")))
+ subtitleURL = d->path()+"/"+sc->getSelection();
+ if((sc->getSelection() == i18n("Other subtitle...")))
+ {
+ subtitleURL = KFileDialog::getOpenURL(d->path(), i18n("*.smi *.srt *.sub *.txt *.ssa *.asc|Subtitle Files\n*.*|All Files"), 0, i18n("Select Subtitle File")).path();
+ if(subtitleURL.isEmpty())
+ {
+ subtitleURL = QString::null;
+ goto THERE;
+ }
+ else //The user has selected another sub, so add this to the list
+ {
+ subs.clear();
+ subs.append(subtitleURL);
+ }
+ }
+ }
+ delete sc;
+ subs.remove(i18n("(no subtitles)"));
+ subs.remove(i18n("Other subtitle..."));
+ }
+
+ //Add the full path to the subtitle name
+ for (unsigned int i = 0; i < subs.size(); i++ )
+ if(!subs[i].startsWith(d->path()))
+ subs[i] = d->path()+"/"+subs[i];
+
+ mrl.setSubtitleFiles(subs);
+ if ( subs.count()==1 )
+ subtitleURL = subs[0]; // Use this one.
+ if (!subtitleURL.isNull())
+ {
+ kdDebug() << "PlayList: Use subtitle file: " << subtitleURL << " for: " << mrl.url() << endl;
+ mrl.setCurrentSubtitle(subs.findIndex(subtitleURL));
+ }
+ }
+ } /* if localFile() */
+
+ tmp = insertItem(after, mrl);
+ if (tmp)
+ after = tmp;
+
+ if ( progress->wasCancelled() )
+ break;
+ progress->progressBar()->setProgress(i+1);
+ progress->setLabel(QString::number(i+1) + " / " + QString::number(progress->progressBar()->totalSteps()) + " " + i18n("Files"));
+ KApplication::kApplication()->processEvents();
+ }
+
+ delete progress;
+ if (m_random) createRandomList();
+ updateStatus();
+}
+
+void PlayList::add(const QValueList<MRL>& mrlList, QListViewItem* after)
+{
+ QValueList<MRL>::ConstIterator end(mrlList.end());
+ for (QValueList<MRL>::ConstIterator it = mrlList.begin(); it != end; ++it)
+ after = insertItem(after, *it);
+ updateStatus();
+ if (m_random) createRandomList();
+}
+
+void PlayList::slotPlayDirect(QListViewItem* item)
+{
+ if (!item) return;
+
+ setCurrentEntry(item);
+ emit play(m_currentEntryMRL, this);
+}
+
+void PlayList::setEndless(bool e)
+{
+ m_endless = e;
+}
+
+void PlayList::setRandom(bool r)
+{
+ m_random = r;
+ if (m_random) createRandomList();
+}
+
+void PlayList::createRandomList()
+{
+ kdDebug() << "PlayList: Create a random playlist" << endl;
+ m_randomList.clear();
+ m_currentRandomListEntry = 0;
+
+ QListViewItem* tmpItem = NULL;
+ tmpItem = m_list->firstChild();
+ if ( (tmpItem) && (!tmpItem->isVisible()) )
+ tmpItem = tmpItem->itemBelow();
+
+ while (tmpItem)
+ {
+ m_randomList.append(tmpItem);
+ tmpItem = tmpItem->itemBelow();
+ }
+
+ if (!(m_randomList.count() > 0))
+ {
+ m_currentRandomListEntry = -1;
+ return;
+ }
+
+ KRandomSequence r(KApplication::random());
+ r.randomize(&m_randomList);
+}
+
+void PlayList::clearList()
+{
+ m_list->clear();
+ m_randomList.clear();
+ m_playTime = 0;
+ m_playTimeVisible = 0;
+ m_countVisible = 0;
+ if (m_searchSelection)
+ {
+ m_playlistFilter->clear();
+ m_searchSelection = false;
+ }
+ updateStatus();
+ m_currentEntry = NULL;
+ m_currentRandomListEntry = -1;
+}
+
+void PlayList::slotDropEvent(QDropEvent* dev, QListViewItem* after)
+{
+ QStringList urls ,newurls;
+
+ m_list->setSorting(-1);
+ if (QUriDrag::decodeLocalFiles(dev, urls))
+ {
+ if (urls.count())
+ {
+ for (uint i=0; i < urls.count() ;i++)
+ {
+ //KURL url(QUriDrag::unicodeUriToUri(urls[i]));
+ //newurls << url.path(-1);
+ //kdDebug() << "PlayList: Dropped " << url.path() << endl;
+ newurls << urls[i];
+ kdDebug() << "PlayList: Dropped " << urls[i] << endl;
+ }
+ add(newurls, after);
+ }
+ else
+ {
+ QUriDrag::decodeToUnicodeUris(dev, urls);
+ if (urls.count())
+ add(urls, after);
+ }
+ }
+ else
+ if (strcmp(dev->format(), "text/x-moz-url") == 0) /* for mozilla drops */
+ {
+ QByteArray data = dev->encodedData("text/plain");
+ QString md(data);
+ add(md, after);
+ }
+}
+
+void PlayList::slotPreDropEvent()
+{
+ m_list->setSorting(-1);
+}
+
+void PlayList::slotSetAlternateColor( const QColor& col )
+{
+ m_list->setAlternateBackground( col );
+ m_altCol = col;
+ m_list->triggerUpdate();
+}
+
+void PlayList::useAlternateEncoding(bool useEncoding)
+{
+ m_useAlternateEncoding = useEncoding;
+}
+
+void PlayList::setAlternateEncoding(const QString& encoding)
+{
+ m_alternateEncoding = encoding;
+}
+
+
+void PlayList::getMetaInfo(MRL& mrl, const QString& mimeName)
+{
+ KFileMetaInfo* metaInfo = NULL;
+ KFileMetaInfoGroup metaGroup;
+ uint m, n;
+
+ metaInfo = new KFileMetaInfo(mrl.url(), mimeName);
+ QStringList groups = metaInfo->groups();
+ QStringList keys;
+ QString title;
+ QString artist;
+ QString album;
+
+ QTextCodec *altCodec;
+ QTextCodec *CodecUtf8;
+
+ altCodec = QTextCodec::codecForName(m_alternateEncoding.ascii());
+ CodecUtf8 = QTextCodec::codecForName("UTF-8");
+ //kdDebug() << "playlist: locale " << Codec->name << " index: " << m_alternateEncoding << endl;
+
+ for (m = 0; m < groups.count(); m++)
+ {
+ //kdDebug() << "Metainfo-Group: " << groups[m] << endl;
+ metaGroup = metaInfo->group(groups[m]);
+ keys = metaGroup.keys();
+ for (n = 0; n < keys.count(); n++)
+ {
+ //kdDebug() << "Metainfo-Key: " << keys[n] << endl;
+ if (keys[n] == "Length")
+ {
+ mrl.setLength(QTime().addSecs(metaGroup.item(keys[n]).value().toUInt()));
+ }
+
+ if (keys[n] == "Title")
+ {
+ title = metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace();
+ if ((!title.isEmpty()) && (title.contains(QRegExp("\\w")) > 2) && (title.left(5).lower() != "track"))
+ {
+ if ((m_useAlternateEncoding) && (CodecUtf8->heuristicContentMatch(title.ascii(), title.length()) < 0))
+ {
+ mrl.setTitle(altCodec->toUnicode(title.ascii()));
+ //kdDebug() << "playlist: Convert, locale name: " << altCodec->name() << title << endl;
+ }
+ else
+ {
+ mrl.setTitle(title);
+ //kdDebug() << "playlist: non Convert, locale name: " << CodecUtf8->name() << title << endl;
+ }
+ }
+ }
+
+ if (keys[n] == "Artist")
+ {
+ artist = (metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace());
+ if (!artist.isEmpty())
+ {
+ if ((m_useAlternateEncoding) && (CodecUtf8->heuristicContentMatch(artist.ascii(),artist.length()) < 0 ))
+ {
+ mrl.setArtist(altCodec->toUnicode(artist.ascii()));
+ }
+ else
+ {
+ mrl.setArtist(artist);
+ }
+ }
+ }
+
+ if (keys[n] == "Album")
+ {
+ album = (metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace());
+ if (!album.isEmpty())
+ {
+ if ((m_useAlternateEncoding) && (CodecUtf8->heuristicContentMatch(album.ascii(),album.length()) < 0 ))
+ {
+ mrl.setAlbum(altCodec->toUnicode(album.ascii()));
+ }
+ else
+ {
+ mrl.setAlbum(album);
+ }
+ }
+ }
+
+ if (keys[n] == "Tracknumber")
+ mrl.setTrack(metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace());
+ if (keys[n] == "Date")
+ mrl.setYear(metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace());
+ if (keys[n] == "Genre")
+ mrl.setGenre(metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace());
+ }
+ }
+
+ delete metaInfo;
+}
+
+void PlayList::mergeMeta(const MRL& mrl)
+{
+ if (!m_currentEntry) return;
+ PlaylistItem* tmp = dynamic_cast<PlaylistItem*>(m_currentEntry);
+ bool addTime = (tmp->length() == QString("00:00:00"));
+ if ((tmp) && (tmp->url() == mrl.url()))
+ {
+ tmp->setTitle(mrl.title());
+ tmp->setArtist(mrl.artist());
+ tmp->setAlbum(mrl.album());
+ tmp->setTrack(mrl.track());
+ tmp->setYear(mrl.year());
+ tmp->setGenre(mrl.genre());
+ tmp->setLength(mrl.length().toString("h:mm:ss"));
+ tmp->setCurrentSubtitle(mrl.currentSubtitle());
+ tmp->setSubtitles(mrl.subtitleFiles());
+ }
+ if (addTime)
+ {
+ if (tmp->length().contains(':'));
+ {
+ m_playTime += timeStringToMs(tmp->length());
+ if (tmp->isVisible())
+ m_playTimeVisible += timeStringToMs(tmp->length());
+
+ updateStatus();
+ }
+ }
+
+ roller->setTitle( mrl );
+ setCover( mrl.artist().stripWhiteSpace(), mrl.album().stripWhiteSpace() );
+}
+
+GalleryDialog::GalleryDialog( QWidget *parent, GoogleFetcher *goog )
+ : KDialogBase( parent, QString(i18n("Gallery")).latin1(), true, QString::null, Ok, NoDefault, true )
+{
+ google = goog;
+ hbox = new QHBox(this);
+ imageFrame = new QFrame( hbox );
+ imageFrame->setFixedSize(500,500);
+ setMainWidget(hbox);
+ connect( &next, SIGNAL(timeout()), this, SLOT(slotNext()) );
+ next.start(1000,true);
+}
+
+void GalleryDialog::slotNext()
+{
+ QPixmap pix;
+ bool end;
+
+ actionButton(Ok)->setEnabled(false);
+loop:
+ QImage img = google->galleryNext( end );
+ if ( end ) {
+ slotOk();
+ return;
+ }
+ if ( !img.isNull() ) {
+ if ( img.width()>img.height() )
+ imageFrame->setFixedSize(500, 500*img.height()/img.width());
+ else
+ imageFrame->setFixedSize(500*img.width()/img.height(), 500);
+ img = img.smoothScale(imageFrame->width(),imageFrame->height());
+ pix.convertFromImage( img );
+ imageFrame->setPaletteBackgroundPixmap( pix );
+ }
+ else
+ goto loop;
+
+ actionButton(Ok)->setEnabled(true);
+ next.start(5000,true);
+}
+
+void GalleryDialog::slotOk()
+{
+ if ( next.isActive() )
+ next.stop();
+ hide();
+}
+
+void PlayList::showGallery()
+{
+ if ( google )
+ return;
+ QString s = getCurrent().artist().stripWhiteSpace();
+ if ( s.isEmpty() )
+ return;
+ google = new GoogleFetcher( s, "", true );
+ GalleryDialog dlg( 0, google );
+ dlg.exec();
+ delete google;
+ google = NULL;
+}
+
+void PlayList::setCover( QString s1, QString s2, bool forceFetch )
+{
+ if ( s1.isEmpty() || s2.isEmpty() ) {
+ coverFrame->setCoverPixmap( "" );
+ return;
+ }
+ QString s = locateLocal("appdata", "");
+ QImage img;
+ QPixmap pix;
+ QString fname = s1+"_"+s2;
+ fname = fname.replace( QChar( '/' ), "_" );
+ fname = fname.upper();
+ fname = s+"covers/"+fname;
+ if ( !forceFetch && QFile( fname ).exists() )
+ coverFrame->setCoverPixmap( fname );
+ else {
+ if ( !forceFetch )
+ coverFrame->setCoverPixmap( "" );
+ if ( google )
+ return;
+ if ( m_cover || forceFetch ) {
+ google = new GoogleFetcher( s1, s2 );
+ pix = google->pixmap( forceFetch );
+ delete google;
+ google = NULL;
+ }
+ if ( !QDir( s+"covers" ).exists() )
+ QDir().mkdir( s+"covers" );
+ if ( !pix.isNull() ) {
+ img = pix.convertToImage();
+ img.save( fname, coverImageFormat.latin1() );
+ MRL mrl = getCurrent();
+ if ( s1==mrl.artist().stripWhiteSpace() && s2==mrl.album().stripWhiteSpace() )
+ coverFrame->setCoverPixmap( fname );
+ }
+ else if ( !forceFetch && m_cover ) {
+ QString path = locate("appdata", "nocover.png");
+ if ( !path )
+ path = locate("data", "kaffeine/nocover.png");
+ KIO::file_copy( KURL::fromPathOrURL( path ), KURL::fromPathOrURL( fname ), -1, true );
+ }
+ }
+}
+
+void PlayList::chooseCurrentCover()
+{
+ MRL mrl = getCurrent();
+ setCover( mrl.artist().stripWhiteSpace(), mrl.album().stripWhiteSpace(), true );
+}
+
+/************ sort playlist ******************/
+
+void PlayList::slotSort(int section)
+{
+ m_list->setSorting(section, m_sortAscending);
+ m_list->sort();
+ m_sortAscending = !m_sortAscending;
+}
+
+
+/*** remove items ***/
+
+void PlayList::slotRemoveSelected()
+{
+ QPtrList<QListViewItem> selected;
+
+ if (m_currentEntry)
+ if (m_currentEntry->isSelected())
+ {
+ m_currentEntry = NULL;
+ m_currentRandomListEntry = -1;
+ }
+
+ selected = m_list->selectedItems();
+ PlaylistItem* item = NULL;
+
+ for(uint i = 0; i<selected.count(); i++)
+ {
+ // kdDebug() << "Remove " << selected.at(i)->text(TITLE_COLUMN) << "\n";
+ item = dynamic_cast<PlaylistItem *>(selected.at(i));
+ if (item->length().contains(':'))
+ {
+ m_playTime -= timeStringToMs(item->length());
+ m_playTimeVisible -= timeStringToMs(item->length());
+ }
+
+ m_countVisible--;
+ delete selected.at(i);
+ }
+
+ if (m_random) createRandomList();
+ updateStatus();
+}
+
+void PlayList::updateStatus()
+{
+ QString status;
+ if (isQueueMode())
+ {
+ QTime total;
+ QValueList<MRL>::ConstIterator end(m_queue.end());
+ for (QValueList<MRL>::ConstIterator it = m_queue.begin(); it != end; ++it)
+ total = total.addSecs(QTime().secsTo((*it).length()));
+ status = i18n("Queue: %1 Entries, Playtime: %2").arg(m_queue.count()).arg(total.toString("h:mm:ss"));
+ }
+ else
+ {
+ //status = i18n("Entries: %1, Playtime: %2 (Total: %3, %4)").arg(QString::number(m_countVisible)).arg(msToTimeString(m_playTimeVisible)).arg(QString::number(m_list->childCount())).arg(msToTimeString(m_playTime));
+
+
+ status = i18n("Entries: %1, Playtime: %2").arg(QString::number(m_countVisible)).arg(msToTimeString(m_playTimeVisible));
+ }
+ emit statusBarMessage(status);
+}
+
+void PlayList::slotNewList()
+{
+ m_list->setSorting(-1);
+ saveCurrentPlaylist();
+ m_playlistSelector->insertItem(i18n("Playlist") + QString::number(m_nextPlaylistNumber), 0);
+ m_nextPlaylistNumber++;
+ m_playlistSelector->setCurrentItem(0);
+ m_currentPlaylist = 0;
+ clearList();
+}
+
+void PlayList::setPlaylist(const QString& name, bool clear)
+{
+ saveCurrentPlaylist();
+ if (clear)
+ clearList();
+ int index = 0;
+ if (m_playlistSelector->listBox()->findItem(name))
+ index = m_playlistSelector->listBox()->index(m_playlistSelector->listBox()->findItem(name));
+ else
+ m_playlistSelector->insertItem(name, 0);
+ m_playlistSelector->setCurrentItem(index);
+ m_currentPlaylist = index;
+}
+
+void PlayList::nextPlaylist()
+{
+ int nextPlaylist = m_playlistSelector->currentItem();
+ QString pl = NULL;
+ do
+ {
+ nextPlaylist++;
+ if (nextPlaylist == m_playlistSelector->count())
+ nextPlaylist = 0;
+ pl = m_playlistSelector->text(nextPlaylist);
+ }
+ while (nextPlaylist != m_playlistSelector->currentItem());
+
+ saveCurrentPlaylist();
+ clearList();
+ m_playlistSelector->setCurrentItem(nextPlaylist);
+ m_currentPlaylist = nextPlaylist;
+ add(m_playlistDirectory + pl + ".kaffeine", NULL);
+ if (mainWidget->parentWidget())
+ mainWidget->parentWidget()->setFocus();
+}
+
+void PlayList::slotPlaylistActivated(int index)
+{
+ kdDebug() << "PlayList: Switch to playlist: " << m_playlistSelector->text(index) << endl;
+ QString pl = m_playlistSelector->text(index);
+
+ saveCurrentPlaylist();
+ clearList();
+ m_currentPlaylist = index;
+ add(m_playlistDirectory + pl + ".kaffeine", NULL);
+ if (mainWidget->parentWidget())
+ mainWidget->parentWidget()->setFocus();
+ /* if (!isQueueMode())
+ {
+ getCurrent();
+ emit signalPlay(m_currentEntryMRL);
+ } */
+}
+
+void PlayList::slotNewPlaylistName(const QString& text)
+{
+ if ((text.isEmpty()) || (text == m_playlistSelector->text(m_currentPlaylist)))
+ return;
+ if (m_playlistSelector->listBox()->findItem(text))
+ {
+ kdDebug() << "PlayList: Name still exists!" << endl;
+ return;
+ }
+ QString oldPl = m_playlistDirectory + m_playlistSelector->text(m_currentPlaylist) + ".kaffeine";
+ kdDebug() << "Playlist: removing file: " << oldPl << endl;
+ if (!KIO::NetAccess::del(oldPl, mainWidget))
+ kdError() << "Playlist: " << KIO::NetAccess::lastErrorString() << endl;
+
+ kdDebug() << "PlayList: Set playlist name to: " << text << endl;
+ m_playlistSelector->changeItem(text, m_currentPlaylist);
+ saveCurrentPlaylist();
+ if (mainWidget->parentWidget())
+ mainWidget->parentWidget()->setFocus();
+}
+
+QString PlayList::queryCurrentPlaylist()
+{
+ QString pl = m_playlistSelector->text(m_currentPlaylist);
+ return (m_playlistDirectory + pl + ".kaffeine");
+}
+
+void PlayList::saveCurrentPlaylist()
+{
+ QString pl = m_playlistSelector->text(m_currentPlaylist);
+ savePlaylist(m_playlistDirectory + pl + ".kaffeine");
+}
+
+void PlayList::removeCurrentPlaylist()
+{
+ int code = KMessageBox::warningContinueCancel(0, i18n("Remove '%1' from list and from disk?").arg(m_playlistSelector->text(m_currentPlaylist)),QString::null,KStdGuiItem::del());
+ if (code == KMessageBox::Continue)
+ {
+ QString pl = m_playlistDirectory + m_playlistSelector->text(m_currentPlaylist) + ".kaffeine";
+ if (!KIO::NetAccess::del(pl, mainWidget))
+ kdError() << "Playlist: " << KIO::NetAccess::lastErrorString() << endl;
+
+ m_playlistSelector->removeItem(m_currentPlaylist);
+ m_currentPlaylist = m_playlistSelector->currentItem();
+ clearList();
+ add(m_playlistDirectory + m_playlistSelector->text(m_currentPlaylist) + ".kaffeine", NULL);
+ }
+}
+
+void PlayList::loadPlaylist(const QString& pl)
+{
+ saveCurrentPlaylist();
+ QString plName = KURL(pl).fileName();
+ plName = plName.remove(".kaffeine", false);
+ if (m_playlistSelector->listBox()->findItem(plName))
+ {
+ QString plNewName = NULL;
+ while (true)
+ {
+ bool ok;
+ plNewName = QInputDialog::getText(i18n("Playlist Name Already Exists"),
+ i18n("Enter different playlist name:"), QLineEdit::Normal, plName, &ok);
+ if ((ok) && (!plNewName.isEmpty()))
+ {
+ if (m_playlistSelector->listBox()->findItem(plNewName))
+ continue;
+ else
+ break;
+ }
+ else
+ {
+ kdDebug() << "Playlist: Import aborted, playlist not added" << endl;
+ return;
+ }
+ }
+ plName = plNewName;
+ }
+ m_playlistSelector->insertItem(plName, 0);
+ m_playlistSelector->setCurrentItem(0);
+ m_currentPlaylist = 0;
+ clearList();
+ add(pl, NULL);
+}
+
+/******************************************
+ * save xml playlist
+ ******************************************/
+
+void PlayList::savePlaylist(const QString& pl)
+{
+ QDomDocument doc("playlist");
+ doc.setContent(QString("<!DOCTYPE XMLPlaylist>"));
+ QDomElement root = doc.createElement("playlist");
+ root.setAttribute("client", "kaffeine");
+ doc.appendChild(root);
+
+ QDomElement entry;
+ PlaylistItem * tmp = NULL;
+
+ QListViewItemIterator it(m_list);
+ while (it.current())
+ {
+ tmp = dynamic_cast<PlaylistItem *>(it.current());
+
+ entry = doc.createElement("entry");
+
+ entry.setAttribute("title", tmp->title());
+ entry.setAttribute("artist", tmp->artist());
+ entry.setAttribute("album", tmp->album());
+ entry.setAttribute("track", tmp->track());
+ entry.setAttribute("year", tmp->year());
+ entry.setAttribute("genre", tmp->genre());
+ entry.setAttribute("url", tmp->url());
+ entry.setAttribute("mime", tmp->mime());
+ entry.setAttribute("length", tmp->length());
+
+ if(!(tmp->subtitles().isEmpty()))
+ {
+ QString subList;
+ for(unsigned int i=0; i<tmp->subtitles().count(); i++)
+ subList += tmp->subtitles()[i] + "&";
+
+ entry.setAttribute("subs", subList);
+ }
+ entry.setAttribute("currentSub", QString::number(tmp->currentSubtitle()));
+ root.appendChild(entry);
+
+ ++it;
+ }
+
+ QFile file(pl);
+ if (!file.open(IO_WriteOnly)) return;
+ QTextStream stream(&file);
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+
+ stream << doc.toString();
+
+ file.close();
+ m_list->setCleared(false);
+}
+
+/**********************/
+
+void PlayList::exportM3UPlaylist(const QString& pl)
+{
+ PlaylistItem * tmp = NULL;
+
+ QListViewItemIterator it(m_list);
+
+ int length = -1;
+ QString m3uList = "#EXTM3U\n";
+
+ while (it.current())
+ {
+ tmp = dynamic_cast<PlaylistItem *>(it.current());
+
+ length = timeStringToMs(tmp->length()) / 1000;
+ if ( length == 0 )
+ length = -1;
+
+ m3uList.append("#EXTINF:" + QString::number(length) + "," + tmp->title());
+ if (tmp->artist().isEmpty() )
+ m3uList.append("\n");
+ else
+ m3uList.append(" - " + tmp->artist() + "\n");
+ m3uList.append(tmp->url() + "\n");
+ ++it;
+ }
+
+ QFile file(pl);
+ if (!file.open(IO_WriteOnly)) return;
+ QTextStream stream(&file);
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+
+ stream << m3uList;
+
+ file.close();
+}
+
+void PlayList::exportPLSPlaylist(const QString& pl)
+{
+ PlaylistItem * tmp = NULL;
+
+ QListViewItemIterator it(m_list);
+
+ int counter = 0;
+ int length = -1;
+
+ QString plsList = "[playlist]\n";
+
+ while (it.current())
+ {
+ tmp = dynamic_cast<PlaylistItem *>(it.current());
+ ++counter;
+
+ length = timeStringToMs(tmp->length()) / 1000;
+
+ if ( length == 0 ) {
+ length = -1;
+ }
+
+ plsList.append("File" + QString::number(counter) + "=" + tmp->url() + "\n");
+ plsList.append("Title" + QString::number(counter) + "=" + tmp->title());
+ if (tmp->artist().isEmpty() )
+ plsList.append("\n");
+ else
+ plsList.append(" - " + tmp->artist() + "\n");
+ plsList.append("Length" + QString::number(counter) + "=" + QString::number(length) + "\n");
+ ++it;
+
+ }
+
+ plsList.append("NumberOfEntries=" + QString::number(counter) + "\n");
+ plsList.append("Version=2");
+
+ QFile file(pl);
+ if (!file.open(IO_WriteOnly)) return;
+ QTextStream stream(&file);
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+
+ stream << plsList;
+
+ file.close();
+}
+
+void PlayList::resetSearch()
+{
+ m_playlistFilter->clear();
+ slotFindText( "" );
+}
+
+void PlayList::slotFindText(const QString& text)
+{
+ if (text == i18n("Filter")) return;
+
+ QListViewItemIterator it(m_list);
+ m_playTimeVisible = 0;
+ m_countVisible = 0;
+ PlaylistItem* tmp = NULL;
+ while ( it.current() )
+ {
+ tmp = dynamic_cast<PlaylistItem *>(it.current());
+ if (text.isEmpty() || tmp->title().contains(text, false) || tmp->url().contains(text, false)
+ || tmp->artist().contains(text, false) || tmp->album().contains(text, false) )
+ {
+ tmp->setVisible(true);
+ if (tmp->length().contains(':'))
+ m_playTimeVisible += timeStringToMs(tmp->length());
+
+ m_countVisible++;
+ }
+ else
+ {
+ tmp->setVisible(false);
+ if (tmp == m_currentEntry)
+ {
+ tmp->setPixmap(TITLE_COLUMN, QPixmap());
+ m_currentEntry = NULL;
+ m_currentRandomListEntry = -1;
+ }
+ }
+ ++it;
+ }
+
+ if (text.isEmpty())
+ m_searchSelection = false;
+ else
+ m_searchSelection = true;
+
+ if (m_random) createRandomList();
+ updateStatus();
+}
+
+
+/***************** cut/copy/paste *************************/
+
+void PlayList::slotCut()
+{
+ slotCopy();
+ slotRemoveSelected();
+}
+
+void PlayList::slotPaste()
+{
+ QPtrList<QListViewItem> selected;
+ selected = m_list->selectedItems();
+ QListViewItem* lastSelected = NULL;
+ if (selected.count())
+ lastSelected = selected.at(selected.count() - 1);
+ else
+ lastSelected = m_list->lastItem();
+
+ QStrList list;
+
+ if (QUriDrag::decode(QApplication::clipboard()->data(), list))
+ {
+ QStringList urls;
+ for (QStrListIterator it(list); *it; ++it)
+ urls.append(QUriDrag::uriToUnicodeUri(*it));
+ add(urls, lastSelected);
+ return;
+ }
+ /** try to decode as text **/
+ QString text;
+ if (QTextDrag::decode(QApplication::clipboard()->data(), text))
+ {
+ add(text, lastSelected);
+ }
+}
+
+void PlayList::slotCopy()
+{
+ QPtrList<QListViewItem> selected;
+ selected = m_list->selectedItems();
+
+ QStrList urlList;
+
+ for (uint i=0; i<selected.count(); i++)
+ {
+ urlList.append(QUriDrag::unicodeUriToUri(dynamic_cast<PlaylistItem *>(selected.at(i))->url()));
+ }
+
+ QApplication::clipboard()->setData(new QUriDrag(urlList));
+}
+
+void PlayList::slotSelectAll()
+{
+ QListViewItemIterator it(m_list);
+ while (it.current())
+ {
+ if ((*it)->isVisible())
+ m_list->setSelected(*it, true);
+ ++it;
+ }
+}
+
+void PlayList::slotPlaylistFromSelected()
+{
+ QPtrList<QListViewItem> selected;
+ selected = m_list->selectedItems();
+
+ QValueList<MRL> mrlList;
+
+ for (uint i=0; i<selected.count(); i++)
+ {
+ mrlList.append(dynamic_cast<PlaylistItem *>(selected.at(i))->toMRL());
+ }
+
+ if (mrlList.count())
+ {
+ slotNewList();
+ add(mrlList, NULL);
+ }
+}
+
+void PlayList::slotAddToQueue(MRL mrl)
+{
+ m_queue.append(mrl);
+ updateStatus();
+}
+
+/**** helper ****/
+
+QString PlayList::msToTimeString(int msec)
+{
+ /*
+ QTime t;
+ t = t.addMSecs(msec);
+ return t.toString("h:mm:ss");
+ */
+ /* can be >24h */
+ int hours;
+ int min;
+ int sec;
+ int my_msec=msec;
+ QString tmp;
+ QString t;
+
+ msec = msec/1000; //sec
+ hours = msec/3600;
+ my_msec -= hours*3600*1000;
+ t = t.setNum(hours);
+ t.append(":");
+
+ msec = msec - (hours*3600);
+ min = msec / 60;
+ my_msec -= min*60*1000;
+ tmp = tmp.setNum(min);
+ tmp = tmp.rightJustify(2, '0');
+ t.append(tmp);
+ t.append(":");
+
+ sec = msec - (min*60);
+ my_msec -= sec*1000;
+ if(my_msec > 500)
+ sec++;
+ tmp = tmp.setNum(sec);
+ tmp = tmp.rightJustify(2, '0');
+ t.append(tmp);
+
+ return t;
+}
+
+int PlayList::timeStringToMs(const QString& timeString)
+{
+ int sec = 0;
+ QStringList tokens = QStringList::split(':',timeString);
+
+ bool ok = false;
+ sec += tokens[0].toInt(&ok)*3600; //hours
+ if (!ok)
+ return 0;
+ sec += tokens[1].toInt(&ok)*60; //minutes
+ if (!ok)
+ return 0;
+ sec += tokens[2].toInt(&ok); //secs
+
+ if (ok)
+ return sec*1000; //return millisecs
+ else
+ return 0;
+}
+
+bool PlayList::endsWith(QString s1, QString s2, bool caseSensitive )
+{
+ if ( s1.isNull() || s2.isNull() )
+ return false;
+ int startPos = s1.length() - s2.length();
+
+ for (unsigned int i = 0; i < s2.length(); i++ )
+ {
+ if(caseSensitive)
+ {
+ if ( s1[startPos + i] != s2[i] )
+ return false;
+ }
+ else
+ {
+ if ( s1[startPos + i].lower() != s2[i].lower() )
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool PlayList::startsWith(QString s1, QString s2, bool caseSensitive )
+{
+ if ( s1.isNull() || s2.isNull() )
+ return false;
+
+ if(s2.length() > s1.length())
+ return false;
+
+ for (unsigned int i = 0; i < s2.length(); i++ )
+ {
+ if(caseSensitive)
+ {
+ if ( s1[i] != s2[i] )
+ return false;
+ }
+ else
+ {
+ if ( s1[i].lower() != s2[i].lower() )
+ return false;
+ }
+ }
+
+ return true;
+}
+
+SubtitleChooser::SubtitleChooser(QStringList values, QString filename,QWidget *parent, const char * name) :
+ KDialogBase(parent,name,true,i18n("Select Subtitle"), Ok|Cancel, Ok, true)
+{
+ QVBox *page = makeVBoxMainWidget();
+ QLabel *label = new QLabel(page);
+ label->setText("<qt>" + i18n("Media file:") + " <b>" + filename + "</b></qt>");
+ table = new QListBox(page);
+ this->setMinimumSize(300,200);
+
+ table->setFocus();
+ table->insertStringList(values);
+ table->setSelected(0, true);
+}
+
+SubtitleChooser::~SubtitleChooser(){}
+
+QString SubtitleChooser::getSelection()
+{
+ return table->selectedItem()->text();
+}
+
+MovieChooser::MovieChooser(QStringList values, QString filename,QWidget *parent, const char * name) :
+ KDialogBase(parent,name,true,i18n("Select Movie"), Ok|Cancel, Ok, true)
+{
+ QVBox *page = makeVBoxMainWidget();
+ QLabel *label = new QLabel(page);
+ label->setText("<qt> " + i18n("Subtitle file:") + " <b>" + filename + "</b></qt>");
+ table = new QListBox(page);
+ this->setMinimumSize(450,200);
+
+ table->setFocus();
+ table->insertStringList(values);
+ table->setSelected(0, true);
+}
+
+MovieChooser::~MovieChooser(){}
+
+QString MovieChooser::getSelection()
+{
+ return table->selectedItem()->text();
+}
diff --git a/kaffeine/src/input/audiobrowser/playlist.h b/kaffeine/src/input/audiobrowser/playlist.h
new file mode 100644
index 0000000..41df120
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/playlist.h
@@ -0,0 +1,336 @@
+/*
+ * playlist.h
+ *
+ * Copyright (C) 2003-2005 Jürgen Kofler <kaffeine@gmx.net>
+ * Copyright (C) 2005-2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef PLAYLIST_H
+#define PLAYLIST_H
+
+#include <kdialogbase.h>
+#include <kdiroperator.h>
+#include <kfileiconview.h>
+#include <kaction.h>
+#include <kstdaction.h>
+
+#include <qwidget.h>
+#include <qptrlist.h>
+#include <qvbox.h>
+#include <qsplitter.h>
+#include <qpainter.h>
+#include <qtoolbutton.h>
+
+#include "urllistview.h"
+#include "kaffeineinput.h"
+
+class UrlListView;
+class MRL;
+class KURL;
+class QListViewItem;
+class QString;
+class QLabel;
+class QColor;
+class QDropEvent;
+class QPixmap;
+class KLineEdit;
+class KComboBox;
+class KURLComboBox;
+class KConfig;
+class KPushButton;
+class GoogleFetcher;
+
+
+
+class GalleryDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ GalleryDialog( QWidget *parent, GoogleFetcher *goog );
+protected slots:
+ void slotOk();
+ void slotNext();
+private:
+ QFrame *imageFrame;
+ GoogleFetcher *google;
+ QTimer next;
+ QHBox *hbox;
+};
+
+
+
+class RollTitle : public QLabel
+{
+ Q_OBJECT
+
+public:
+ RollTitle( QWidget *parent );
+ void setTitle( MRL mrl );
+
+private:
+ void setTitle( QString t );
+ QTimer titleTimer;
+ QPixmap titlePix;
+ QColor back, fore;
+ int titleOffset;
+ QString title;
+
+protected:
+ void paintEvent ( QPaintEvent * );
+
+private slots:
+ void rollTitle();
+};
+
+
+
+class CoverFrame : public QFrame
+{
+ Q_OBJECT
+
+public:
+ CoverFrame( QWidget *parent );
+ ~CoverFrame();
+ void setCoverPixmap( const QString &path );
+
+protected:
+ void mousePressEvent( QMouseEvent *e );
+
+private:
+ void popup( const QPixmap &pix ) const;
+ QString imagePath;
+ QPixmap noCoverPix;
+
+signals:
+ void changeCurrentCover();
+ void gallery();
+};
+
+
+
+class PlayList : public KaffeineInput
+{
+ Q_OBJECT
+
+public:
+ PlayList(QWidget *parent, QObject *objParent, const char *name=0);
+ ~PlayList();
+
+ // Reimplemented from KaffeineInput
+public:
+ QWidget *wantPlayerWindow();
+ QWidget *inputMainWidget();
+ void mergeMeta(const MRL&);
+ bool nextTrack( MRL& );
+ bool previousTrack( MRL& );
+ bool currentTrack( MRL& );
+ bool trackNumber( int, MRL& );
+ bool playbackFinished( MRL& );
+ void getTargets( QStringList &uiNames, QStringList &iconNames, QStringList &targetNames );
+ void togglePanel();
+ bool execTarget( const QString& );
+ void saveConfig();
+ bool showPlayer() {return !m_showPlayer->isChecked();}
+ //***************************************
+
+public:
+ MRL getCurrent(); /* get current playlist entry */
+ MRL getNext();
+ MRL getEntryWithNumber(int number);
+ void setCurrentEntry(QListViewItem*, bool playIcon = true);
+
+ QListViewItem* getLast();
+ QListViewItem* getFirst();
+ QListViewItem* findByURL(const QString&);
+
+ /* insert a KURL(list) after a specific item */
+ void add(const QString& url, QListViewItem* after);
+ void add(const QStringList& urls, QListViewItem* after);
+ void add(const QValueList<MRL>&, QListViewItem* after);
+
+ bool isQueueMode() { return m_queue.count(); }
+
+ void setPlaylist(const QString& name, bool clear = false);
+ void nextPlaylist();
+ void removeCurrentPlaylist();
+ void saveCurrentPlaylist();
+ QString queryCurrentPlaylist();
+ void loadConfig(KConfig*);
+ void saveConfig(KConfig*);
+ void clearList();
+
+ void setEndless(bool);
+ void setRandom(bool);
+
+ void useAlternateEncoding(bool);
+ void setAlternateEncoding(const QString&);
+
+ void setFileFilter(const QString& filter);
+ void savePlaylist(const QString&);
+ void loadPlaylist(const QString&);
+
+ void exportM3UPlaylist(const QString&);
+ void exportPLSPlaylist(const QString&);
+
+ const bool getReadMetaOnLoading() const { return m_metaOnLoading; }
+
+ QVBox *mainWidget;
+ QVBox *playerBox;
+
+public slots:
+ void slotToggleShuffle();
+
+protected:
+ void closeEvent(QCloseEvent*);
+
+private slots:
+ void slotNewList();
+ void slotSetReadMetaOnLoading(bool read) { m_metaOnLoading = read; }
+ void slotSetAlternateColor(const QColor&);
+ void slotPlayDirect(QListViewItem* item); /* doubleclick */
+ void slotDropEvent(QDropEvent*, QListViewItem*);
+ void slotPreDropEvent();
+ void slotCut();
+ void slotPaste();
+ void slotCopy();
+ void slotSelectAll();
+ void slotPlaylistFromSelected();
+ void slotAddToQueue(MRL);
+ void slotRemoveSelected();
+ void slotFindText(const QString&);
+ void slotSort(int);
+ void slotPlaylistActivated(int);
+ void slotNewPlaylistName(const QString&);
+ void slotRepeat();
+ void slotShuffle();
+ void slotAutoCover();
+ void slotShowPlayer();
+ void slotPlaylistLoad();
+ void slotPlaylistSaveAs();
+ void slotPlaylistRemove();
+ void setCover( QString s1, QString s2, bool forceFetch=false );
+ void chooseCurrentCover();
+ void showGallery();
+ void startPlaylist();
+ void fileSelected( const KFileItem* );
+ void setBrowserURL( const QString& );
+ void setBrowserURL( const KURL& );
+ void browserURLChanged( const KURL& );
+ void slotClearList();
+ void resetSearch();
+
+private:
+ QListViewItem* insertItem(QListViewItem* after, const MRL&);
+ void updateStatus();
+ void createRandomList();
+ void getMetaInfo(MRL& mrl, const QString& mimeName);
+ void setupActions();
+ /* helpers */
+ static QString msToTimeString(int);
+ static int timeStringToMs(const QString&);
+ static bool endsWith(QString, QString, bool);
+ static bool startsWith(QString, QString, bool);
+
+private:
+ QColor m_altCol;
+ KComboBox* m_playlistSelector;
+ QToolButton *searchBtn;
+ KLineEdit* m_playlistFilter;
+ int m_nextPlaylistNumber;
+ QString m_playlistDirectory;
+ int m_currentPlaylist;
+ KURLComboBox *browserComb;
+
+ QSplitter *hSplit, *vSplit;
+ QVBox *panel;
+ QWidget *playlist;
+ KDirOperator *fileBrowser;
+ KFileIconView *view;
+ CoverFrame *coverFrame;
+ GoogleFetcher *google;
+ QString coverImageFormat;
+ RollTitle *roller;
+
+ KToggleAction *m_repeat, *m_shuffle, *m_autoCover, *m_showPlayer;
+
+ QValueList<MRL> m_queue;
+
+ uint m_playTime;
+ uint m_playTimeVisible;
+ uint m_countVisible;
+
+ bool m_searchSelection;
+ bool m_metaOnLoading;
+ bool m_sortAscending;
+
+ UrlListView* m_list;
+ QListViewItem* m_currentEntry;
+ MRL m_currentEntryMRL;
+
+ QString m_fileFilter;
+ QString m_metaInfoString;
+ QString m_lastPlaylist;
+
+ QPtrList<QListViewItem> m_randomList;
+ int m_currentRandomListEntry;
+
+ QPixmap m_isCurrentEntry;
+ QPixmap m_cdPixmap;
+
+ bool m_endless;
+ bool m_random;
+ bool m_cover;
+
+ bool m_useAlternateEncoding;
+ QString m_alternateEncoding;
+
+signals:
+ void signalRequestForAudioCD(const QString&);
+ void signalRequestForDVD(const QString&);
+ void signalRequestForVCD(const QString&);
+};
+
+class QListBox;
+class QStringList;
+
+class SubtitleChooser : public KDialogBase
+{
+ Q_OBJECT
+public:
+ SubtitleChooser(QStringList, QString, QWidget *parent=0, const char *name = 0);
+ virtual ~SubtitleChooser();
+
+ QString getSelection();
+
+private:
+ QListBox *table;
+};
+
+class MovieChooser : public KDialogBase
+{
+ Q_OBJECT
+public:
+ MovieChooser(QStringList, QString, QWidget *parent=0, const char *name = 0);
+ virtual ~MovieChooser();
+
+ QString getSelection();
+
+private:
+ QListBox *table;
+};
+
+#endif /* PLAYLIST_H */
diff --git a/kaffeine/src/input/audiobrowser/playlistitem.cpp b/kaffeine/src/input/audiobrowser/playlistitem.cpp
new file mode 100644
index 0000000..3b5fc05
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/playlistitem.cpp
@@ -0,0 +1,268 @@
+/*
+ * playlistitem.cpp - a self-displayable item for kaffeine's playlist
+ *
+ * Copyright (C) 2004-2005 Giorgos Gousios
+ * Copyright (C) 2004-2005 Jürgen Kofler <kaffeine@gmx.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.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <qstringlist.h>
+
+#include <kdebug.h>
+
+#include "mrl.h"
+#include "playlistitem.h"
+
+PlaylistItem::PlaylistItem(KListView *list, KListViewItem *after, const QString& url, const QString& mime, const QString& title,
+ const QString& length, const QString& artist, const QString& album, const QString& year, const QString& genre,
+ const QString& track, const QStringList& subtitles, int currentSubtitle) :
+ KListViewItem(list, after, mime, title, artist, album, track, length),
+ m_url(url), m_year(year), m_genre(genre), m_subtitles(subtitles), m_currentSubtitle(currentSubtitle), isCurrent(false)
+{}
+
+PlaylistItem::PlaylistItem(KListView* list, KListViewItem* after, const MRL& mrl) :
+ KListViewItem(list, after, mrl.mime(), mrl.title(), mrl.artist(), mrl.album(),
+ mrl.track(), mrl.length().toString("h:mm:ss")), m_url(mrl.url()),
+ m_year(mrl.year()), m_genre(mrl.genre()),
+ m_subtitles(mrl.subtitleFiles()), m_currentSubtitle(mrl.currentSubtitle()), isCurrent(false)
+{}
+
+PlaylistItem::~PlaylistItem() {}
+
+MRL PlaylistItem::toMRL() const
+{
+ return MRL(url(), title(), stringToTime(length()), mime(), artist(), album(), track(), year(), genre(), QString::null, subtitles(), currentSubtitle());
+}
+
+const QString& PlaylistItem::url() const
+{
+ return m_url;
+}
+
+QString PlaylistItem::mime() const
+{
+ return this->text(MIME_COLUMN);
+}
+
+QString PlaylistItem::title() const
+{
+ return this->text(TITLE_COLUMN);
+}
+
+QString PlaylistItem::artist() const
+{
+ return this->text(ARTIST_COLUMN);
+}
+
+QString PlaylistItem::album() const
+{
+ return this->text(ALBUM_COLUMN);
+}
+
+QString PlaylistItem::track() const
+{
+ return this->text(TRACK_COLUMN);
+}
+
+QString PlaylistItem::year() const
+{
+ return m_year;
+}
+
+QString PlaylistItem::genre() const
+{
+ return m_genre;
+}
+
+QString PlaylistItem::length() const
+{
+ return this->text(LENGTH_COLUMN);
+}
+
+const QStringList& PlaylistItem::subtitles() const
+{
+ return m_subtitles;
+}
+
+int PlaylistItem::currentSubtitle() const
+{
+ return m_currentSubtitle;
+}
+
+void PlaylistItem::setUrl(const QString& url)
+{
+ m_url = url;
+}
+
+void PlaylistItem::setMime(const QString& mime)
+{
+ this->setText(MIME_COLUMN, mime);
+}
+
+void PlaylistItem::setTitle(const QString& title)
+{
+ this->setText(TITLE_COLUMN, title);
+}
+
+void PlaylistItem::setArtist(const QString& artist)
+{
+ this->setText(ARTIST_COLUMN, artist);
+}
+
+void PlaylistItem::setAlbum(const QString& album)
+{
+ this->setText(ALBUM_COLUMN, album);
+}
+
+void PlaylistItem::setTrack(const QString& track)
+{
+ this->setText(TRACK_COLUMN, track);
+}
+
+void PlaylistItem::setYear(const QString& year)
+{
+ m_year = year;
+}
+
+void PlaylistItem::setGenre(const QString& genre)
+{
+ m_genre = genre;
+}
+
+void PlaylistItem::setLength(const QString& length)
+{
+ this->setText(LENGTH_COLUMN, length);
+}
+
+void PlaylistItem::setSubtitles(const QStringList& subs)
+{
+ m_subtitles = subs;
+}
+
+void PlaylistItem::addSubtitle(const QString& sub)
+{
+ /* This will add subtitle & set it to the current one */
+ for (uint i=0; i < m_subtitles.count(); i++) {
+ if (m_subtitles[i] == sub) {
+ m_currentSubtitle = i;
+ return;
+ }
+ }
+ m_subtitles.append(sub);
+ m_currentSubtitle = m_subtitles.count()-1;
+}
+
+void PlaylistItem::setCurrentSubtitle(int sub)
+{
+ m_currentSubtitle = sub;
+}
+
+QTime PlaylistItem::stringToTime(const QString& timeString)
+{
+ int sec = 0;
+ bool ok = false;
+ QStringList tokens = QStringList::split(':',timeString);
+
+ sec += tokens[0].toInt(&ok)*3600; //hours
+ sec += tokens[1].toInt(&ok)*60; //minutes
+ sec += tokens[2].toInt(&ok); //secs
+
+ if (ok)
+ return QTime().addSecs(sec);
+ else
+ return QTime();
+}
+
+int PlaylistItem::compare(QListViewItem *i, int col, bool ascending ) const
+{
+ PlaylistItem* p = dynamic_cast<PlaylistItem*>(i);
+ if (!p)
+ return QListViewItem::compare(i, col, ascending);
+
+ //if both strings are empty, sort by filename
+ if (text(col).isEmpty() && i->text(col).isEmpty())
+ return -url().compare(p->url());
+
+ bool ok;
+ int track1, track2 = 0;
+ track1 = track().toInt(&ok);
+ if (ok)
+ track2 = p->track().toInt(&ok);
+
+ if (col == TRACK_COLUMN)
+ {
+ if (ok)
+ return (track2 - track1);
+ else
+ return QListViewItem::compare(i, col, ascending);
+ }
+ else
+ {
+ int result = QListViewItem::compare(i, col, ascending);
+
+ //if artists are equal, compare albums
+ if ((col == ARTIST_COLUMN) && (result == 0))
+ {
+ result = QListViewItem::compare(i, ALBUM_COLUMN, ascending);
+ if (!ascending)
+ result = -result;
+ }
+
+ //if strings are equal, sort by track number or filename
+ if (result == 0)
+ {
+ int diff;
+ if (ok)
+ diff = track1 - track2;
+ else
+ diff = url().compare(p->url());
+
+ if (ascending)
+ return diff;
+ else
+ return -diff;
+ }
+ else
+ return result;
+ }
+}
+
+void PlaylistItem::setPlaying(bool playing)
+{
+ isCurrent = playing;
+}
+
+void PlaylistItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align)
+{
+ if (isCurrent)
+ {
+ QColorGroup colorGroup = cg;
+
+ QColor base = colorGroup.base();
+ QColor selection = colorGroup.highlight();
+
+ int r = (base.red() + selection.red()) / 2;
+ int b = (base.blue() + selection.blue()) / 2;
+ int g = (base.green() + selection.green()) / 2;
+
+ QColor c(r, g, b);
+
+ colorGroup.setColor(QColorGroup::Base, c);
+ QListViewItem::paintCell(p, colorGroup, column, width, align);
+ }
+ else
+ return KListViewItem::paintCell(p, cg, column, width, align);
+}
diff --git a/kaffeine/src/input/audiobrowser/playlistitem.h b/kaffeine/src/input/audiobrowser/playlistitem.h
new file mode 100644
index 0000000..9b1b9f5
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/playlistitem.h
@@ -0,0 +1,93 @@
+/*
+ * playlistitem.h - a self-displayable item for kaffeine's playlist
+ *
+ * Copyright (C) 2004-2005 Giorgos Gousios
+ * Copyright (C) 2004-2005 Jürgen Kofler <kaffeine@gmx.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.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef PLAYLISTITEM_H
+#define PLAYLISTITEM_H
+
+#include <klistview.h>
+
+#define MIME_COLUMN 0
+#define TITLE_COLUMN 1
+#define ARTIST_COLUMN 2
+#define ALBUM_COLUMN 3
+#define TRACK_COLUMN 4
+#define LENGTH_COLUMN 5
+
+class QTime;
+class QString;
+class QStringList;
+class MRL;
+
+class PlaylistItem : public KListViewItem
+{
+
+public:
+ PlaylistItem(KListView *list, KListViewItem *after, const QString& url, const QString& mime, const QString& title,
+ const QString& length = QString::null, const QString& artist = QString::null, const QString& album = QString::null,
+ const QString& track = QString::null, const QString& year = QString::null, const QString& genre = QString::null,
+ const QStringList& subtitles = QStringList(), int currentSubtitle = -1);
+ PlaylistItem(KListView* list, KListViewItem* after, const MRL&);
+ virtual ~PlaylistItem();
+
+ MRL toMRL() const;
+
+ const QString& url() const;
+ QString mime() const;
+ QString title() const;
+ QString artist() const;
+ QString album() const;
+ QString track() const;
+ QString year() const;
+ QString genre() const;
+ QString length() const;
+ const QStringList& subtitles() const;
+ int currentSubtitle() const;
+
+ void setUrl(const QString&);
+ void setMime(const QString&);
+ void setTitle(const QString&);
+ void setArtist(const QString&);
+ void setAlbum(const QString&);
+ void setTrack(const QString&);
+ void setYear(const QString&);
+ void setGenre(const QString&);
+ void setLength(const QString&);
+ void setSubtitles(const QStringList&);
+ void addSubtitle(const QString&);
+ void setCurrentSubtitle(int);
+
+ //reimplement to fix track order
+ int compare( QListViewItem *i, int col, bool ascending ) const;
+
+ void setPlaying(bool playing);
+ virtual void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align);
+
+private:
+ static QTime stringToTime(const QString&);
+ QString m_url;
+ QString m_year;
+ QString m_genre;
+ QStringList m_subtitles;
+ int m_currentSubtitle;
+ bool isCurrent;
+};
+
+#endif /* PLAYLISTITEM_H */
diff --git a/kaffeine/src/input/audiobrowser/urllistview.cpp b/kaffeine/src/input/audiobrowser/urllistview.cpp
new file mode 100644
index 0000000..49cfc3c
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/urllistview.cpp
@@ -0,0 +1,347 @@
+/*
+ * urllistview.cpp
+ *
+ * Copyright (C) 2003-2005 Jürgen Kofler <kaffeine@gmx.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.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kurl.h>
+#include <kglobalsettings.h>
+#include <kfiledialog.h>
+#include <kpopupmenu.h>
+
+#include <qfontmetrics.h>
+#include <qdragobject.h>
+
+#include "mrl.h"
+#include "playlistitem.h"
+#include "urllistview.h"
+#include "urllistview.moc"
+
+
+UrlListView::UrlListView(QWidget *parent, const char *name ) : KListView(parent,name),
+ m_listCleared(true), m_itemOfContextMenu(NULL)
+{
+ m_contextMenu = new KPopupMenu(this);
+ m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("player_play", KIcon::Small), i18n("Play"), this, SLOT(slotPlayItem()));
+ m_contextMenu->insertItem(i18n("Play Next/Add to Queue"), this, SLOT(slotPlayNext()));
+ m_contextMenu->insertSeparator();
+
+ m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("editcut", KIcon::Small), i18n("C&ut"), this, SIGNAL(signalCut()), CTRL+Key_X);
+ m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("editcopy", KIcon::Small), i18n("&Copy"), this, SIGNAL(signalCopy()), CTRL+Key_C);
+ m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("editpaste", KIcon::Small), i18n("&Paste"), this, SIGNAL(signalPaste()), CTRL+Key_V);
+ m_contextMenu->insertItem(i18n("Select &All"), this, SIGNAL(signalSelectAll()), CTRL+Key_A);
+ m_contextMenu->insertItem(i18n("Create Playlist From Selected"), this, SIGNAL(signalPlaylistFromSelected()));
+ m_contextMenu->insertSeparator();
+ m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("indent", KIcon::Small), i18n("Add Sub&title..."), this, SLOT(slotAddSubtitle()),QKeySequence(),100 );
+ m_contextMenu->insertSeparator();
+ m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("edit", KIcon::Small), i18n("&Edit Title"), this, SLOT(slotEditTitle()));
+ m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("info", KIcon::Small), i18n("&Info"), this, SLOT(slotShowInfo()));
+
+/* width of the "length"-column */
+ QFontMetrics met(KGlobalSettings::generalFont());
+ int w1 = met.width(i18n("Length"));
+ int w2 = met.width("5:55:55") + 2;
+
+ m_column5Width = w1 > w2 ? w1 : w2;
+ m_column5Width += 30;
+
+/* width of the "track"-column */
+ w1 = met.width(i18n("Track"));
+ w2 = met.width("9999") + 2;
+
+ m_column4Track = w1 > w2 ? w1 : w2;
+ m_column4Track += 36;
+
+ connect(this, SIGNAL(contextMenuRequested(QListViewItem*, const QPoint&, int)),
+ this, SLOT(slotShowContextMenu(QListViewItem*, const QPoint&, int)));
+ connect(this, SIGNAL(currentChanged(QListViewItem*)),
+ this, SLOT(slotCurrentChanged(QListViewItem*)));
+ connect(this, SIGNAL(clicked( QListViewItem*, const QPoint&, int )),
+ this, SLOT(slotClicked( QListViewItem*, const QPoint&, int )));
+}
+
+UrlListView::~UrlListView()
+{
+}
+
+bool UrlListView::acceptDrag(QDropEvent* event) const
+{
+ return QUriDrag::canDecode(event) || QTextDrag::canDecode(event) || KListView::acceptDrag(event);
+}
+
+QDragObject* UrlListView::dragObject()
+{
+ // get selected items
+ QPtrList<QListViewItem> selected;
+ QStrList urlList;
+
+ selected = selectedItems();
+ for (uint i = 0; i<selected.count(); i++)
+ {
+ urlList.append(dynamic_cast<PlaylistItem*>(selected.at(i))->url().ascii());
+ }
+
+ return new QUriDrag(urlList, viewport());
+}
+
+void UrlListView::resizeEvent(QResizeEvent* rev)
+{
+ int width = contentsRect().width() - m_column5Width - m_column4Track - 69;
+ setColumnWidth(0, 20); /* mime */
+ setColumnWidth(1, ((width * 5 / 12) + 50)); /* title */
+ setColumnWidth(2, (width * 3 / 12)); /* artist */
+ setColumnWidth(3, (width * 4 / 12)); /* album */
+ setColumnWidth(4, m_column4Track); /* track */
+ setColumnWidth(5, m_column5Width); /* width of "length" column */
+
+ KListView::resizeEvent(rev);
+}
+
+void UrlListView::clear()
+{
+ m_listCleared = true;
+ m_itemOfContextMenu = NULL;
+ setSorting(-1);
+ KListView::clear();
+}
+
+void UrlListView::setCleared(bool cl)
+{
+ m_listCleared = cl;
+}
+
+bool UrlListView::getCleared() const /* was playlist cleared ? */
+{
+ return m_listCleared;
+}
+
+/********** context menu **********/
+
+void UrlListView::slotShowContextMenu(QListViewItem* item, const QPoint& pos, int)
+{
+ if (!item)
+ {
+ m_itemOfContextMenu = NULL;
+ disableSubEntry();
+ }
+ else
+ {
+ m_itemOfContextMenu = dynamic_cast<PlaylistItem *>(item);
+ if (m_itemOfContextMenu->mime().contains("video"))
+ enableSubEntry();
+ else
+ disableSubEntry();
+ }
+
+ m_contextMenu->popup(pos);
+}
+
+void UrlListView::slotPlayItem()
+{
+ if (m_itemOfContextMenu)
+ emit signalPlayItem(m_itemOfContextMenu);
+}
+
+void UrlListView::slotPlayNext()
+{
+ if (m_itemOfContextMenu)
+ emit signalAddToQueue(m_itemOfContextMenu->toMRL());
+}
+
+void UrlListView::slotEditTitle()
+{
+ if (m_itemOfContextMenu)
+ {
+ m_itemOfContextMenu->setRenameEnabled(1, true);
+ m_itemOfContextMenu->startRename(1);
+ m_itemOfContextMenu->setRenameEnabled(1, false);
+ }
+}
+
+//Pretty print item info
+void UrlListView::slotShowInfo()
+{
+ if (!m_itemOfContextMenu)
+ return;
+
+ QString num;
+ num = num.setNum(childCount());
+ QString info = "<qt><table width=\"90%\">";
+ info = info + "<tr><td colspan=\"2\"><center><b>" + m_itemOfContextMenu->title() + "</b></center></td></tr>";
+ info = info + "<tr><td><b>" + i18n("URL")+ ":</b></td><td>" + m_itemOfContextMenu->url() + "</td></tr>";
+ info = info + "<tr><td><b>" + i18n("Artist") + ":</b></td><td>" + m_itemOfContextMenu->artist() + "</td></td>";
+ info = info + "<tr><td><b>" + i18n("Album") + ":</b></td><td>" + m_itemOfContextMenu->album() + "</td></td>";
+ info = info + "<tr><td><b>" + i18n("Track") + ":</b></td><td>" + m_itemOfContextMenu->track() + "</td></td>";
+ info = info + "<tr><td><b>" + i18n("Year") + ":</b></td><td>" + m_itemOfContextMenu->year() + "</td></td>";
+ info = info + "<tr><td><b>" + i18n("Genre") + ":</b></td><td>" + m_itemOfContextMenu->genre() + "</td></td>";
+ info = info + "<tr><td><b>" + i18n("Length") + ":</b></td><td>" + m_itemOfContextMenu->length() + "</td></tr>";
+ if(!m_itemOfContextMenu->subtitles().isEmpty())
+ {
+ info = info + "<tr><td><b>" + i18n("Subtitles") + ":</b></td><td>";
+
+ for(uint i = 0; i < m_itemOfContextMenu->subtitles().count(); i++ )
+ {
+ info = info + ""+m_itemOfContextMenu->subtitles()[i];
+ if(m_itemOfContextMenu->currentSubtitle() == (int)i)
+ info = info + "<small> ("+i18n("in use")+")</small>";
+ info = info + "<br>";
+ }
+ info = info + "</ul></td></tr></table></qt>";
+ }
+
+ KMessageBox::information(this, info);
+}
+
+void UrlListView::slotClicked(QListViewItem*, const QPoint&, int)
+{
+ /*if ( (item) && (col == 3) )
+ {
+ m_itemOfContextMenu = dynamic_cast<PlaylistItem *>(item);
+ if (!m_itemOfContextMenu) return;
+ slotShowInfo();
+ } */
+}
+
+#include <qdom.h>
+#include <kio/job.h>
+
+void UrlListView::slotAddSubtitle()
+{
+ /*QDomDocument reqdoc;
+
+ QDomElement methodCall = reqdoc.createElement( "methodCall" );
+ QDomElement methodName = reqdoc.createElement( "methodName" );
+ QDomText methodNameValue = reqdoc.createTextNode( "LogIn" );
+ methodName.appendChild( methodNameValue );
+ methodCall.appendChild( methodName );
+ reqdoc.appendChild( methodCall );
+
+ QDomElement params = reqdoc.createElement( "params" );
+
+ QDomElement param1 = reqdoc.createElement( "param" );
+ QDomElement value1 = reqdoc.createElement( "value" );
+ QDomElement type1 = reqdoc.createElement( "string" );
+ QDomText param1Value = reqdoc.createTextNode( "" );
+ type1.appendChild( param1Value );
+ value1.appendChild( type1 );
+ param1.appendChild( value1 );
+ params.appendChild( param1 );
+
+ QDomElement param2 = reqdoc.createElement( "param" );
+ QDomElement value2 = reqdoc.createElement( "value" );
+ QDomElement type2 = reqdoc.createElement( "string" );
+ QDomText param2Value = reqdoc.createTextNode( "" );
+ type2.appendChild( param2Value );
+ value2.appendChild( type2 );
+ param2.appendChild( value2 );
+ params.appendChild( param2 );
+
+ QDomElement param3 = reqdoc.createElement( "param" );
+ QDomElement value3 = reqdoc.createElement( "value" );
+ QDomElement type3 = reqdoc.createElement( "string" );
+ QDomText param3Value = reqdoc.createTextNode( "en" );
+ type3.appendChild( param3Value );
+ value3.appendChild( type3 );
+ param3.appendChild( value3 );
+ params.appendChild( param3 );
+
+ methodCall.appendChild( params );
+
+ const QString xmlRequest = "<?xml version=\"1.0\"?>\n" + reqdoc.toString();
+
+ QByteArray postData;
+ QDataStream stream( postData, IO_WriteOnly );
+ stream.writeRawBytes( xmlRequest.utf8(), xmlRequest.utf8().length() );
+
+ openSubJobBuf = QByteArray();
+
+ openSubJob = KIO::http_post( "http://test.opensubtitles.org/xml-rpc", postData, false );
+ openSubJob->addMetaData( "content-type", "Content-Type: text/xml" );
+
+ connect( openSubJob, SIGNAL(result(KIO::Job*)), this, SLOT(openSubResult(KIO::Job*)) );
+ connect( openSubJob, SIGNAL(data(KIO::Job*,const QByteArray&) ), this, SLOT(openSubData(KIO::Job*,
+ const QByteArray&)) );
+
+ kdDebug() << "\n\n" << xmlRequest << "\n\n" << endl;*/
+
+
+ if (!m_itemOfContextMenu)
+ return;
+
+ QString openURL = m_itemOfContextMenu->url();
+ QString subtitleURL = KFileDialog::getOpenURL(openURL,
+ i18n("*.smi *.srt *.sub *.txt *.ssa *.asc|Subtitle Files\n*.*|All Files"),
+ 0, i18n("Select Subtitle File")).path();
+ if(!(subtitleURL.isEmpty()) && !(m_itemOfContextMenu->subtitles().contains(subtitleURL)) && QFile::exists(subtitleURL))
+ {
+ m_itemOfContextMenu->addSubtitle(subtitleURL);
+ emit signalPlayItem(m_itemOfContextMenu);
+ }
+
+}
+
+void UrlListView::openSubResult( KIO::Job* job )
+{
+ if ( openSubJob!=job )
+ return;
+ if ( job->error() ) {
+ kdDebug() << "OpenSubtiltes error : " << job->error() << endl;
+ return;
+ }
+
+ QDomDocument document;
+ if ( !document.setContent( openSubJobBuf ) ) {
+ kdDebug() << "Couldn't read similar artists response" << endl;
+ return;
+ }
+ kdDebug() << "\n\n" << document.toString() << "\n\n" << endl;
+ openSubJob = 0;
+}
+
+void UrlListView::openSubData( KIO::Job* job, const QByteArray& data )
+{
+ if ( openSubJob != job )
+ return;
+
+ unsigned int bufsize = openSubJobBuf.size();
+ openSubJobBuf.resize( bufsize + data.size() );
+ memcpy( openSubJobBuf.data()+bufsize, data.data(), data.size() );
+}
+
+
+void UrlListView::slotCurrentChanged(QListViewItem * item)
+{
+ if(item == 0) //All items deleted
+ m_itemOfContextMenu = NULL;
+ else
+ m_itemOfContextMenu = dynamic_cast<PlaylistItem *>(item);
+}
+
+void UrlListView::enableSubEntry()
+{
+ m_contextMenu->setItemEnabled(100, true);
+}
+
+void UrlListView::disableSubEntry()
+{
+ m_contextMenu->setItemEnabled(100, false);
+}
diff --git a/kaffeine/src/input/audiobrowser/urllistview.h b/kaffeine/src/input/audiobrowser/urllistview.h
new file mode 100644
index 0000000..964b743
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/urllistview.h
@@ -0,0 +1,92 @@
+/*
+ * urllistview.h
+ *
+ * Copyright (C) 2003-2005 Jürgen Kofler <kaffeine@gmx.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.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef URLLISTVIEW_H
+#define URLLISTVIEW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <klistview.h>
+
+class KPopupMenu;
+class QWidget;
+class QDragObject;
+class PlaylistItem;
+class MRL;
+class KIO::Job;
+
+class UrlListView : public KListView
+{
+ Q_OBJECT
+public:
+ UrlListView(QWidget *parent=0, const char *name=0);
+ ~UrlListView();
+
+ void setCleared(bool);
+ bool getCleared() const; /* was the playlist cleared or should we save it? */
+
+public slots:
+ virtual void clear(); /* reimplement slot */
+
+signals:
+ void signalPlayItem(QListViewItem* ); /* play selected in context menu */
+ void signalCut();
+ void signalCopy();
+ void signalPaste();
+ void signalSelectAll();
+ void signalAddToQueue(MRL);
+ void signalPlaylistFromSelected();
+
+private slots:
+ void slotShowContextMenu(QListViewItem*, const QPoint&, int);
+ void slotCurrentChanged(QListViewItem *);
+ void slotAddSubtitle();
+ void slotShowInfo();
+ void slotEditTitle();
+ void slotPlayItem();
+ void slotClicked(QListViewItem*, const QPoint&, int);
+ void slotPlayNext();
+ void openSubResult( KIO::Job* );
+ void openSubData( KIO::Job*, const QByteArray& );
+
+protected:
+ virtual bool acceptDrag(QDropEvent* event) const;
+ virtual void resizeEvent(QResizeEvent*);
+ virtual QDragObject* dragObject();
+
+private:
+ void enableSubEntry();
+ void disableSubEntry();
+
+private:
+ bool m_listCleared;
+ int m_column5Width; /* width of the fifth column */
+ int m_column4Track; /* width of the fourth column */
+
+ PlaylistItem* m_itemOfContextMenu;
+ KPopupMenu* m_contextMenu;
+ KIO::Job *openSubJob;
+ QByteArray openSubJobBuf;
+
+};
+
+#endif /* URLLISTVIEW_H */