3
// Copyright (C) 2000, 2001 Neil Stevens <multivac@fcmail.com>
5
// Permission is hereby granted, free of charge, to any person obtaining a copy
6
// of this software and associated documentation files (the "Software"), to deal
7
// in the Software without restriction, including without limitation the rights
8
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
// copies of the Software, and to permit persons to whom the Software is
10
// furnished to do so, subject to the following conditions:
12
// The above copyright notice and this permission notice shall be included in
13
// all copies or substantial portions of the Software.
15
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
// THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
// Except as contained in this notice, the name(s) of the author(s) shall not be
23
// used in advertising or otherwise to promote the sale, use or other dealings
24
// in this Software without prior written authorization from the author(s).
37
#include <kio/global.h>
39
#include <kio/netaccess.h>
41
#include <kmessagebox.h>
42
#include <krandomsequence.h>
43
#include <ktempfile.h>
45
#include <qtextstream.h>
49
#include "noatunapp.h"
53
* class MCPItem is closely coupled with class MCP. It makes sure that,
54
* at all times, every PlaylistItem maintains a one-to-one relationship
55
* with a QDomElement from MCP.
57
* Additionally, it makes sure that the QDomElement is kept updated with
58
* the PlaylistItem information.
60
class MCPItem : public PlaylistItem
64
* Create a new item, and create an element for it
66
MCPItem(QDomDocument, const KURL & = 0, bool = true);
69
* Create an item for an existing element, as from a playlist file
75
inline QDomElement element(void) const {return node;};
76
static inline KURL getURL(const QString &path);
79
virtual void modified(void);
82
void setPointer(void);
89
MCPItem::MCPItem(QDomElement n)
90
: PlaylistItem(getURL(n.attribute("path")), n.attribute("download") == "true")
93
setProperty("title", node.attribute("title"), false);
94
setProperty("artist", node.attribute("artist"), false);
95
setProperty("album", node.attribute("album"), false);
96
setProperty("date", node.attribute("date"), false);
97
setProperty("comment", node.attribute("comment"), false);
98
mLength = node.attribute("length").toInt();
99
// Keep compatible, despite new ms system
100
if(mLength != -1) mLength *= 1000;
104
MCPItem::MCPItem(QDomDocument d, const KURL &url, bool download)
105
: PlaylistItem(url, download)
107
node = d.createElement("item");
114
node.removeAttribute("MCPItem");
117
void MCPItem::modified(void)
120
static_cast<MCP *>(napp->playlist())->itemModified(this);
123
void MCPItem::setPointer(void)
125
node.setAttribute("MCPItem", QString::number((long)this));
128
void MCPItem::update(void)
130
node.setAttribute("title", property("title"));
131
node.setAttribute("artist", property("artist"));
132
node.setAttribute("album", property("album"));
133
node.setAttribute("date", property("date"));
134
node.setAttribute("comment", property("comment"));
135
node.setAttribute("path", mUrl.path());
136
node.setAttribute("download", mDownloaded ? "true" : "false");
137
// Keep compatible, despite new ms system
138
int length = mLength;
139
if(length != -1) length /= 1000;
140
node.setAttribute("length", QString::number(length));
143
KURL MCPItem::getURL(const QString &path)
146
if (result.isMalformed() || result.protocol() == "file")
148
result.setProtocol("file");
149
result.setPath(path);
154
inline MCPItem *getItemForElement(QDomElement element)
156
return (MCPItem *)element.attribute("MCPItem").toLong();
163
MCP::MCP(QObject *parent, const char *name)
164
: Playlist(parent, name)
169
shuffleUnused.setAutoDelete(false);
170
connect(this, SIGNAL(current(PlaylistItem *)), this, SLOT(setVolume(PlaylistItem *)));
172
// I just checked. napp->player() should exist at this point.
173
connect(napp->player(), SIGNAL(volumeChanged(int)), this, SLOT(getVolume(int)));
178
// Only You can help prevent memory leaks
182
void MCP::reset(void)
190
cur = doc.documentElement().namedItem("item").toElement();
191
emit current(getItemForElement(cur));
195
void MCP::clear(void)
201
void MCP::clearInternal(void)
203
QDomElement element = doc.documentElement().namedItem("item").toElement();
205
while(!element.isNull())
207
MCPItem *item = getItemForElement(element);
209
element = element.nextSibling().toElement();
213
doc.setContent(QString("<!DOCTYPE NoatunPlaylist><playlist/>"));
216
napp->player()->stop();
219
shuffleUnused.clear();
222
const MCPItem *MCP::AtBottom = (MCPItem *)-1;
224
MCPItem *MCP::addFileG(const KURL &_url, bool _play, MCPItem *_afterThis)
226
MCPItem *item = new MCPItem(doc, _url);
228
if(_afterThis == AtBottom)
229
doc.documentElement().appendChild(item->element());
231
moveAfter(item, _afterThis);
233
if(_play) play(item);
237
shuffleUnused.append(item);
238
KRandomSequence rand;
239
rand.randomize(&shuffleUnused);
245
void MCP::addFile(const KURL &_url, bool _play)
247
(void)addFileG(_url, _play);
250
PlaylistItem *MCP::addFile(const KURL &_url, PlaylistItem *_afterThis)
252
return addFileG(_url, false, static_cast<MCPItem *>(_afterThis));
255
PlaylistItem *MCP::next(void)
259
PlaylistItem *item = shuffleUnused.take();
263
item = shuffleUnused.take();
267
cur = static_cast<MCPItem *>(item)->element();
275
QDomElement element = cur.nextSibling().toElement();
283
emit current(getItemForElement(cur));
284
return getItemForElement(cur);
289
PlaylistItem *MCP::current(void)
291
return getItemForElement(cur);
294
PlaylistItem *MCP::previous(void)
299
QDomElement element = cur.previousSibling().toElement();
307
emit current(getItemForElement(cur));
308
return getItemForElement(cur);
312
PlaylistItem *MCP::getFirst(void) const
314
return getItemForElement(doc.documentElement().namedItem("item").toElement());
317
PlaylistItem *MCP::getAfter(const PlaylistItem *_item) const
319
const MCPItem *item = static_cast<const MCPItem *>(_item);
320
QDomElement element = item->element();
321
element = element.nextSibling().toElement();
322
return getItemForElement(element);
325
PlaylistItem *MCP::getBefore(const PlaylistItem *_item) const
327
const MCPItem *item = static_cast<const MCPItem *>(_item);
328
QDomElement element = item->element();
329
element = element.previousSibling().toElement();
330
return getItemForElement(element);
333
bool MCP::listVisible(void) const
335
return !static_cast<QWidget *>(parent())->isHidden();
338
void MCP::setShuffle(bool b)
343
shuffleUnused.clear();
345
QDomElement element = doc.documentElement().namedItem("item").toElement();
346
while(!element.isNull())
348
shuffleUnused.append(getItemForElement(element));
349
element = element.nextSibling().toElement();
351
KRandomSequence rand;
352
rand.randomize(&shuffleUnused);
356
void MCP::setApplyVolume(bool b)
359
if(!cur.isNull()) setVolume(getItemForElement(cur));
362
void MCP::moveAfter(PlaylistItem *_item, PlaylistItem *_moveAfter)
364
MCPItem *item = static_cast<MCPItem *>(_item);
365
QDomElement element = item->element();
367
MCPItem *moveAfter = static_cast<MCPItem *>(_moveAfter);
370
QDomElement after = moveAfter->element();
371
after.parentNode().insertAfter(element, after);
372
emit moved(_item, _moveAfter);
376
QDomNode parent = doc.documentElement();
377
parent.insertBefore(element, parent.firstChild());
378
emit moved(_item, 0);
382
void MCP::play(PlaylistItem *_item)
384
MCPItem *item = static_cast<MCPItem *>(_item);
385
QDomElement element = item->element();
392
void MCP::itemModified(PlaylistItem *item)
397
void MCP::showList(void)
399
if(!listVisible()) static_cast<QWidget *>(parent())->show();
403
void MCP::hideList(void)
405
if(listVisible()) static_cast<QWidget *>(parent())->hide();
409
void MCP::toggleList(void)
411
QWidget *widget = static_cast<QWidget *>(parent());
412
if(widget->isHidden())
424
void MCP::remove(PlaylistItem *_item)
426
MCPItem *item = static_cast<MCPItem *>(_item);
427
QDomElement element = item->element();
431
shuffleUnused.removeRef(item);
436
if(cur.nextSibling().isNull())
437
napp->player()->stop();
443
element.parentNode().removeChild(element);
449
static inline void MCPError(QObject *obj, QString err)
451
KMessageBox::error(static_cast<QWidget *>(obj), err);
454
void MCP::load(const KURL &url, bool errorFree)
457
if(!KIO::NetAccess::download(url, dest))
460
MCPError(this, i18n("Failed to load %1.").arg(url.prettyURL()));
465
file.open(IO_ReadOnly);
466
QTextStream stream(&file);
467
QString data = stream.read();
470
if(!newDoc.setContent(data))
472
MCPError(this, i18n("%1 is not a valid Noatun playlist.").arg(url.prettyURL()));
477
doc.setContent(data);
478
QDomElement element = doc.documentElement().namedItem("item").toElement();
479
while(!element.isNull())
481
(void)new MCPItem(element);
482
element = element.nextSibling().toElement();
487
KIO::NetAccess::removeTempFile(dest);
491
void MCP::save(const KURL &url)
496
MCPError(this, i18n("Failed to save to %1.").arg(url.prettyURL()));
500
saver.textStream() << doc.toString();
504
MCPError(this, i18n("Failed to save to %1.").arg(url.prettyURL()));
511
PlaylistItem *MCP::importWindowsPlaylist(const KURL &url, PlaylistItem *_item)
513
MCPItem *item = static_cast<MCPItem *>(_item);
516
if(!KIO::NetAccess::download(url, dest))
518
MCPError(this, i18n("Failed to load %1.").arg(url.prettyURL()));
523
file.open(IO_ReadOnly);
524
QTextStream stream(&file);
525
QString data = stream.readLine();
526
while(!data.isNull())
528
// happy Moose feature
529
if(KURL::isRelativeURL(data)) data = url.path(1) + data;
530
item = addFileG( MCPItem::getURL(data), false, item);
531
data = stream.readLine();
533
KIO::NetAccess::removeTempFile(dest);
539
PlaylistItem *MCP::importPlaylist(const KURL &url, PlaylistItem *_item)
541
MCPItem *item = static_cast<MCPItem *>(_item);
544
if(!KIO::NetAccess::download(url, dest))
546
MCPError(this, i18n("Failed to load %1.").arg(url.prettyURL()));
551
file.open(IO_ReadOnly);
552
QTextStream stream(&file);
553
QString data = stream.read();
556
list.setContent(data);
558
QDomElement cur = list.documentElement().namedItem("item").toElement();
562
QDomElement element = doc.createElement("item");
563
QDomNamedNodeMap attrs = cur.attributes();
565
for(unsigned i = 0; i < attrs.length(); i++)
567
QDomAttr attr = attrs.item(i).toAttr();
568
element.setAttribute( attr.name(), attr.value() );
571
MCPItem *item = new MCPItem(element);
572
moveAfter(item, _item);
576
cur = cur.nextSibling().toElement();
579
KIO::NetAccess::removeTempFile(dest);
585
PlaylistItem *MCP::addDirectory(const KURL &_url, PlaylistItem *_item)
587
listLastAdded = _item;
590
KIO::ListJob *job = KIO::listRecursive(_url, false);
591
connect(job, SIGNAL(result(KIO::Job *)), this, SLOT(listFinished(KIO::Job *)));
592
connect(job, SIGNAL(entries(KIO::Job *, const KIO::UDSEntryList &)), this, SLOT(listEntries(KIO::Job *, const KIO::UDSEntryList &)));
594
while(!listDone) napp->processEvents();
596
return listLastAdded;
599
void MCP::listFinished(KIO::Job *)
604
void MCP::listEntries(KIO::Job *job, const KIO::UDSEntryList &list)
606
for(KIO::UDSEntryListConstIterator i = list.begin(); i != list.end(); ++i)
608
QValueList<KIO::UDSAtom>::ConstIterator j;
609
for(j = (*i).begin(); (*j).m_uds != KIO::UDS_FILE_TYPE && j != (*i).end(); ++j);
611
if( j != (*i).end() && S_ISREG((*j).m_long) )
613
for(j = (*i).begin(); (*j).m_uds != KIO::UDS_NAME && j != (*i).end(); ++j);
616
KURL url = static_cast<KIO::ListJob *>(job)->url();
617
url.addPath((*j).m_str);
618
listLastAdded = addFile(url, listLastAdded);
624
void MCP::setVolume(PlaylistItem *_item)
626
if(!applyVolume) return;
628
MCPItem *item = static_cast<MCPItem *>(_item);
629
QDomElement node = item->element();
630
if(node.hasAttribute("volume"))
631
napp->player()->setVolume(node.attribute("volume").toInt());
633
getVolume(napp->player()->volume());
636
void MCP::getVolume(int _volume)
638
cur.setAttribute("volume", QString::number(_volume));