You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1010 lines
22 KiB
1010 lines
22 KiB
/**
|
|
* Copyright (c) 2000-2004 Charles Samuels <charles@kde.org>
|
|
* 2000-2001 Neil Stevens <neil@qualityassistant.com>
|
|
*
|
|
* Copyright (c) from the patches of:
|
|
* 2001 Klas Kalass <klas.kalass@gmx.de>
|
|
* 2001 Anno v. Heimburg <doktor.dos@gmx.de>
|
|
**/
|
|
|
|
|
|
// Abandon All Hope, Ye Who Enter Here
|
|
|
|
#include <tqdragobject.h>
|
|
#include <tqheader.h>
|
|
#include <tqlayout.h>
|
|
#include <tqmap.h>
|
|
#include <tqregexp.h>
|
|
#include <tqtextstream.h>
|
|
#include <tqpainter.h>
|
|
|
|
#include <tdeaction.h>
|
|
#include <kdebug.h>
|
|
#include <tdefiledialog.h>
|
|
#include <tdefileitem.h>
|
|
#include <tdeio/job.h>
|
|
#include <tdeio/netaccess.h>
|
|
#include <tdelocale.h>
|
|
#include <tdemenubar.h>
|
|
#include <ksimpleconfig.h>
|
|
#include <kstandarddirs.h>
|
|
#include <kstdaction.h>
|
|
#include <kedittoolbar.h>
|
|
#include <kurldrag.h>
|
|
#include <tdemessagebox.h>
|
|
|
|
#include <noatun/app.h>
|
|
#include <noatun/player.h>
|
|
#include <noatun/playlistsaver.h>
|
|
|
|
#include "playlist.h"
|
|
#include "view.h"
|
|
#include "find.h"
|
|
|
|
#define SPL SplitPlaylist::SPL()
|
|
|
|
SafeListViewItem::SafeListViewItem(TQListView *parent, TQListViewItem *after, const KURL &text)
|
|
: TQCheckListItem(parent,0, TQCheckListItem::CheckBox), PlaylistItemData(), removed(false)
|
|
{
|
|
addRef();
|
|
setUrl(text);
|
|
|
|
static_cast<TDEListView*>(TQT_TQWIDGET(parent))->moveItem(this, 0, after);
|
|
setOn(true);
|
|
|
|
// is this really needed, it makes the listview too wide for me :(
|
|
// setText(0,text.filename());
|
|
|
|
// if (!isDownloaded()) setText(1, "0%");
|
|
|
|
// mProperties.setAutoDelete(true);
|
|
|
|
if (!streamable() && enqueue(url()))
|
|
setUrl(KURL(localFilename()));
|
|
|
|
PlaylistItemData::added();
|
|
}
|
|
|
|
SafeListViewItem::SafeListViewItem(TQListView *parent, TQListViewItem *after, const TQMap<TQString,TQString> &props)
|
|
: TQCheckListItem(parent, 0, TQCheckListItem::CheckBox), removed(false)
|
|
{
|
|
addRef();
|
|
|
|
setOn(true);
|
|
|
|
// A version of setProperty that assumes a key is unique,
|
|
// and doesn't call modified for every new key.
|
|
// Ugly, but this function is a very hot path on playlist loading
|
|
for (TQMap<TQString,TQString>::ConstIterator i=props.begin(); i!=props.end(); ++i )
|
|
{
|
|
TQString n = i.key();
|
|
TQString val = i.data();
|
|
|
|
if (n=="enabled")
|
|
{
|
|
setOn(val!="false" && val!="0");
|
|
}
|
|
else
|
|
{
|
|
Property p={n,val};
|
|
mProperties += p;
|
|
}
|
|
}
|
|
|
|
static_cast<TDEListView*>(TQT_TQWIDGET(parent))->moveItem(this, 0, after);
|
|
modified();
|
|
|
|
if (!streamable() && enqueue(url()))
|
|
{
|
|
KURL u;
|
|
u.setPath(localFilename());
|
|
|
|
setUrl(u);
|
|
}
|
|
PlaylistItemData::added();
|
|
}
|
|
|
|
SafeListViewItem::~SafeListViewItem()
|
|
{
|
|
remove();
|
|
}
|
|
|
|
TQString SafeListViewItem::file() const
|
|
{
|
|
return localFilename();
|
|
}
|
|
|
|
static void pad(TQString &str)
|
|
{
|
|
int len=str.length();
|
|
int at = 0;
|
|
int blocklen=0;
|
|
|
|
static const int paddingsize=12;
|
|
|
|
// not static for reason
|
|
const TQChar chars[paddingsize] =
|
|
{
|
|
TQChar('0'), TQChar('0'), TQChar('0'), TQChar('0'),
|
|
TQChar('0'), TQChar('0'), TQChar('0'), TQChar('0'),
|
|
TQChar('0'), TQChar('0'), TQChar('0'), TQChar('0')
|
|
};
|
|
|
|
for (int i=0; i < len; i++)
|
|
{
|
|
if (str[i].isNumber())
|
|
{
|
|
if (!blocklen)
|
|
at = i;
|
|
blocklen++;
|
|
}
|
|
else if (blocklen)
|
|
{
|
|
int pads=paddingsize;
|
|
pads -= blocklen;
|
|
str.insert(at, chars, pads);
|
|
i += pads;
|
|
blocklen = 0;
|
|
}
|
|
}
|
|
if (blocklen)
|
|
{
|
|
int pads=paddingsize;
|
|
pads -= blocklen;
|
|
str.insert(at, chars, pads);
|
|
}
|
|
}
|
|
|
|
int SafeListViewItem::compare(TQListViewItem * i, int col, bool) const
|
|
{
|
|
TQString text1 = text(col);
|
|
TQString text2 = i->text(col);
|
|
|
|
pad(text1);
|
|
pad(text2);
|
|
return text1.compare(text2);
|
|
}
|
|
|
|
TQString SafeListViewItem::property(const TQString &n, const TQString &def) const
|
|
{
|
|
for (TQValueList<Property>::ConstIterator i=mProperties.begin(); i != mProperties.end(); ++i)
|
|
{
|
|
if ((*i).key==n)
|
|
return (*i).value;
|
|
}
|
|
if (n=="enabled")
|
|
{
|
|
if (isOn()) return "true";
|
|
else return "false";
|
|
}
|
|
return def;
|
|
}
|
|
|
|
void SafeListViewItem::setProperty(const TQString &n, const TQString &val)
|
|
{
|
|
if (n=="enabled")
|
|
{
|
|
setOn(val!="false" && val!="0");
|
|
}
|
|
else
|
|
{
|
|
if ( property(n,"") == val )
|
|
{
|
|
// kdDebug(66666) << "SafeListViewItem::setProperty(), property unchanged!" << endl;
|
|
return;
|
|
}
|
|
|
|
clearProperty(n);
|
|
Property p={n,val};
|
|
mProperties += p;
|
|
}
|
|
modified();
|
|
}
|
|
|
|
void SafeListViewItem::clearProperty(const TQString &n)
|
|
{
|
|
if (n=="enabled")
|
|
{
|
|
setOn(true);
|
|
modified();
|
|
return;
|
|
}
|
|
|
|
for (TQValueList<Property>::Iterator i=mProperties.begin(); i != mProperties.end(); ++i)
|
|
{
|
|
if ((*i).key==n)
|
|
{
|
|
mProperties.remove(i);
|
|
modified();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
TQStringList SafeListViewItem::properties() const
|
|
{
|
|
TQStringList list;
|
|
for (TQValueList<Property>::ConstIterator i=mProperties.begin(); i != mProperties.end(); ++i)
|
|
list += (*i).key;
|
|
list += "enabled";
|
|
return list;
|
|
}
|
|
|
|
bool SafeListViewItem::isProperty(const TQString &n) const
|
|
{
|
|
for (TQValueList<Property>::ConstIterator i=mProperties.begin(); i != mProperties.end(); ++i)
|
|
{
|
|
if ((*i).key==n)
|
|
return true;
|
|
}
|
|
return n=="enabled";
|
|
}
|
|
|
|
void SafeListViewItem::downloaded(int percent)
|
|
{
|
|
if (!removed)
|
|
setText(1, TQString::number(percent)+'%');
|
|
}
|
|
|
|
void SafeListViewItem::downloadTimeout()
|
|
{
|
|
if (!removed)
|
|
setText(1, "-");
|
|
}
|
|
|
|
void SafeListViewItem::downloadFinished()
|
|
{
|
|
if (!removed)
|
|
setText(1, "");
|
|
}
|
|
|
|
void SafeListViewItem::modified()
|
|
{
|
|
bool widthChangeNeeded = false;
|
|
|
|
if (text(0)!=title())
|
|
{
|
|
setText(0, title());
|
|
widthChangeNeeded = true;
|
|
}
|
|
|
|
if (isDownloaded() && length()!=-1 && text(1)!=lengthString())
|
|
{
|
|
setText(1, lengthString());
|
|
widthChangeNeeded = true;
|
|
}
|
|
|
|
if (widthChangeNeeded)
|
|
widthChanged(-1);
|
|
|
|
PlaylistItemData::modified();
|
|
}
|
|
|
|
void SafeListViewItem::stateChange(bool s)
|
|
{
|
|
// if you uncheck this, uncheck thet others that
|
|
// are selected too
|
|
|
|
TQPtrList<TQListViewItem> list=SPL->view->listView()->selectedItems();
|
|
|
|
// but not if I'm not selected
|
|
if (list.containsRef(this))
|
|
for (TQListViewItem *i=list.first(); i != 0; i=list.next())
|
|
static_cast<TQCheckListItem*>(i)->setOn(s);
|
|
else
|
|
TQCheckListItem::stateChange(s);
|
|
}
|
|
|
|
void SafeListViewItem::paintCell(TQPainter *p, const TQColorGroup &cg, int column, int width, int align)
|
|
{
|
|
TQCheckListItem::paintCell(p, cg, column, width, align);
|
|
|
|
if (SPL->current() == this)
|
|
{
|
|
p->save();
|
|
p->setRasterOp(XorROP);
|
|
p->fillRect(0, 0, width, height(), TQColor(255,255,255));
|
|
|
|
p->restore();
|
|
}
|
|
}
|
|
|
|
void SafeListViewItem::remove()
|
|
{
|
|
removed=true;
|
|
if (napp->player()->current()==this && !itemAbove() && !itemBelow())
|
|
{
|
|
napp->player()->stop();
|
|
SPL->setCurrent(0);
|
|
}
|
|
else if (napp->player()->current()==this)
|
|
{
|
|
// SPL->setCurrent(0);
|
|
// napp->player()->playCurrent();
|
|
|
|
if (napp->player()->isPlaying() && !SPL->exiting())
|
|
napp->player()->forward();
|
|
else
|
|
SPL->setCurrent(0);
|
|
}
|
|
|
|
if (listView())
|
|
{
|
|
if (SPL->currentItem==this) // just optimizing for least unreadably
|
|
SPL->setCurrent(static_cast<SafeListViewItem*>(itemBelow()));
|
|
|
|
listView()->takeItem(this);
|
|
}
|
|
else if (SPL->currentItem==this)
|
|
{
|
|
SPL->setCurrent(0);
|
|
}
|
|
|
|
dequeue();
|
|
PlaylistItemData::removed();
|
|
}
|
|
|
|
List::List(View *parent)
|
|
: TDEListView(parent), recursiveAddAfter(0), listJob(0)
|
|
{
|
|
addColumn(i18n("File"));
|
|
addColumn(i18n("Time"));
|
|
setAcceptDrops(true);
|
|
setSorting(-1);
|
|
setDropVisualizer(true);
|
|
setDragEnabled(true);
|
|
setItemsMovable(true);
|
|
setSelectionMode(TQListView::Extended);
|
|
connect(TQT_TQOBJECT(this), TQT_SIGNAL(dropped(TQDropEvent*, TQListViewItem*)), TQT_SLOT(dropEvent(TQDropEvent*, TQListViewItem*)));
|
|
connect(TQT_TQOBJECT(this), TQT_SIGNAL(moved()), TQT_SLOT(move()));
|
|
connect(TQT_TQOBJECT(this), TQT_SIGNAL(aboutToMove()), parent, TQT_SLOT(setNoSorting()));
|
|
connect(TQT_TQOBJECT(this), TQT_SIGNAL(deleteCurrentItem()), parent, TQT_SLOT(deleteSelected()));
|
|
}
|
|
|
|
List::~List()
|
|
{
|
|
}
|
|
|
|
void List::move()
|
|
{
|
|
emit modified();
|
|
}
|
|
|
|
bool List::acceptDrag(TQDropEvent *event) const
|
|
{
|
|
return KURLDrag::canDecode(event) || TDEListView::acceptDrag(event);
|
|
}
|
|
|
|
void List::dropEvent(TQDropEvent *event, TQListViewItem *after)
|
|
{
|
|
static_cast<View*>(TQT_TQWIDGET(parent()))->setNoSorting();
|
|
KURL::List textlist;
|
|
if (!KURLDrag::decode(event, textlist)) return;
|
|
event->acceptAction();
|
|
|
|
for (KURL::List::Iterator i=textlist.begin(); i != textlist.end(); ++i)
|
|
{
|
|
after= addFile(*i, false, after);
|
|
}
|
|
|
|
emit modified();
|
|
}
|
|
|
|
void List::keyPressEvent(TQKeyEvent *e)
|
|
{
|
|
if (e->key()==Key_Enter || e->key()==Key_Return)
|
|
{
|
|
if (currentItem())
|
|
{
|
|
emit TDEListView::executed(currentItem());
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (e->key()==Key_Delete)
|
|
{
|
|
if (currentItem())
|
|
{
|
|
emit deleteCurrentItem();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
TDEListView::keyPressEvent(e);
|
|
|
|
|
|
}
|
|
|
|
/**
|
|
* use this only once!!!
|
|
**/
|
|
class NoatunSaver : public PlaylistSaver
|
|
{
|
|
List *mList;
|
|
SafeListViewItem *after, *mFirst;
|
|
public:
|
|
NoatunSaver(List *l, TQListViewItem *after=0)
|
|
: mList(l)
|
|
{
|
|
this->after = static_cast<SafeListViewItem*>(after);
|
|
mFirst = 0;
|
|
}
|
|
|
|
TQListViewItem *getAfter() { return after; }
|
|
TQListViewItem *getFirst() { return mFirst; }
|
|
|
|
protected:
|
|
virtual void readItem(const TQMap<TQString,TQString> &properties)
|
|
{
|
|
after = new SafeListViewItem(mList, after, properties);
|
|
if (mFirst==0)
|
|
mFirst = after;
|
|
}
|
|
|
|
virtual PlaylistItem writeItem()
|
|
{
|
|
if (!after)
|
|
{
|
|
after=static_cast<SafeListViewItem*>(mList->firstChild());
|
|
}
|
|
else
|
|
{
|
|
after=static_cast<SafeListViewItem*>(static_cast<SafeListViewItem*>(after)->nextSibling());
|
|
}
|
|
return PlaylistItem(after);
|
|
}
|
|
};
|
|
|
|
|
|
bool View::saveToURL(const KURL &url)
|
|
{
|
|
NoatunSaver saver(list);
|
|
if(saver.save(url))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
KMessageBox::error( this, i18n("Could not write to %1.").arg(url.prettyURL()) );
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void View::exportTo(const KURL &url)
|
|
{
|
|
TQString local(napp->tempSaveName(url.path()));
|
|
TQFile saver(local);
|
|
saver.open(IO_ReadWrite | IO_Truncate);
|
|
TQTextStream t(&saver);
|
|
// navigate the list
|
|
for (SafeListViewItem *i=static_cast<SafeListViewItem*>(listView()->firstChild());
|
|
i != 0; i=static_cast<SafeListViewItem*>(i->itemBelow()))
|
|
{
|
|
KURL u=i->url();
|
|
if (u.isLocalFile())
|
|
t<< u.path() << '\n';
|
|
else
|
|
t << u.url() << '\n';
|
|
}
|
|
saver.close();
|
|
|
|
TDEIO::NetAccess::upload(local, url, this);
|
|
|
|
saver.remove();
|
|
}
|
|
|
|
TQListViewItem *List::openGlobal(const KURL &u, TQListViewItem *after)
|
|
{
|
|
clear();
|
|
NoatunSaver saver(this, after);
|
|
saver.metalist(u);
|
|
|
|
return saver.getAfter();
|
|
}
|
|
|
|
// for m3u files
|
|
TQListViewItem *List::importGlobal(const KURL &u, TQListViewItem *after)
|
|
{
|
|
NoatunSaver saver(this, after);
|
|
if (!saver.metalist(u))
|
|
{
|
|
after=new SafeListViewItem(this, after, u);
|
|
// SPL->listItemSelected(after);
|
|
return after;
|
|
}
|
|
|
|
// return the first item added from this playlist
|
|
// that way noatun can start playing the first item
|
|
if (saver.getFirst())
|
|
return saver.getFirst();
|
|
|
|
// failsafe in case nothing was added, getFirst() may return 0
|
|
return saver.getAfter();
|
|
}
|
|
|
|
TQListViewItem *List::addFile(const KURL& url, bool play, TQListViewItem *after)
|
|
{
|
|
// when a new item is added, we don't want to sort anymore
|
|
SPL->view->setNoSorting();
|
|
|
|
if (
|
|
url.path().right(4).lower()==".m3u"
|
|
|| url.path().right(4).lower()==".pls"
|
|
|| url.protocol().lower()=="http"
|
|
)
|
|
{
|
|
// a playlist is requested
|
|
TQListViewItem *i = importGlobal(url, after);
|
|
if (play)
|
|
SPL->listItemSelected(i);
|
|
return i;
|
|
}
|
|
else
|
|
{
|
|
if (!after) after=lastItem();
|
|
KFileItem fileItem(KFileItem::Unknown,KFileItem::Unknown,url);
|
|
if (fileItem.isDir())
|
|
{
|
|
addDirectoryRecursive(url, after);
|
|
return after; // don't (and can't) know better!?
|
|
}
|
|
else
|
|
{
|
|
TQListViewItem *i = new SafeListViewItem(this, after, url);
|
|
if (play)
|
|
SPL->listItemSelected(i);
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
|
|
// starts a new listJob if there is no active but work to do
|
|
void List::addNextPendingDirectory()
|
|
{
|
|
KURL::List::Iterator pendingIt= pendingAddDirectories.begin();
|
|
if (!listJob && (pendingIt!= pendingAddDirectories.end()))
|
|
{
|
|
currentJobURL= *pendingIt;
|
|
listJob= TDEIO::listRecursive(currentJobURL, false,false);
|
|
connect(
|
|
listJob, TQT_SIGNAL(entries(TDEIO::Job*, const TDEIO::UDSEntryList&)),
|
|
TQT_SLOT(slotEntries(TDEIO::Job*, const TDEIO::UDSEntryList&))
|
|
);
|
|
connect(
|
|
listJob, TQT_SIGNAL(result(TDEIO::Job *)),
|
|
TQT_SLOT(slotResult(TDEIO::Job *))
|
|
);
|
|
connect(
|
|
listJob, TQT_SIGNAL(redirection(TDEIO::Job *, const KURL &)),
|
|
TQT_SLOT(slotRedirection(TDEIO::Job *, const KURL &))
|
|
);
|
|
pendingAddDirectories.remove(pendingIt);
|
|
}
|
|
}
|
|
|
|
void List::addDirectoryRecursive(const KURL &dir, TQListViewItem *after)
|
|
{
|
|
if (!after) after=lastItem();
|
|
recursiveAddAfter= after;
|
|
pendingAddDirectories.append(dir);
|
|
addNextPendingDirectory();
|
|
}
|
|
|
|
void List::slotResult(TDEIO::Job *job)
|
|
{
|
|
listJob= 0;
|
|
if (job && job->error())
|
|
job->showErrorDialog();
|
|
addNextPendingDirectory();
|
|
}
|
|
|
|
void List::slotEntries(TDEIO::Job *, const TDEIO::UDSEntryList &entries)
|
|
{
|
|
TQMap<TQString,KURL> __list; // temp list to sort entries
|
|
|
|
TDEIO::UDSEntryListConstIterator it = entries.begin();
|
|
TDEIO::UDSEntryListConstIterator end = entries.end();
|
|
|
|
for (; it != end; ++it)
|
|
{
|
|
KFileItem file(*it, currentJobURL, false /* no mimetype detection */, true);
|
|
// "prudhomm:
|
|
// insert the path + url in the map to sort automatically by path
|
|
// note also that you use audiocd to rip your CDs then it will be sorted the right way
|
|
// now it is an easy fix to have a nice sort BUT it is not the best
|
|
// we should sort based on the tracknumber"
|
|
// - copied over from old kdirlister hack <hans_meine@gmx.de>
|
|
if (!file.isDir())
|
|
__list.insert(file.url().path(), file.url());
|
|
}
|
|
TQMap<TQString,KURL>::Iterator __it;
|
|
for( __it = __list.begin(); __it != __list.end(); ++__it )
|
|
{
|
|
recursiveAddAfter= addFile(__it.data(), false, recursiveAddAfter);
|
|
}
|
|
}
|
|
|
|
void List::slotRedirection(TDEIO::Job *, const KURL & url)
|
|
{
|
|
currentJobURL= url;
|
|
}
|
|
|
|
/////////////////////////////////
|
|
|
|
View::View(SplitPlaylist *)
|
|
: TDEMainWindow(0, "NoatunSplitplaylistView")
|
|
{
|
|
list=new List(this);
|
|
setCentralWidget(list);
|
|
connect(list, TQT_SIGNAL(modified(void)), TQT_TQOBJECT(this), TQT_SLOT(setModified(void)) );
|
|
// connect the click on the header with sorting
|
|
connect(list->header(),TQT_SIGNAL(clicked(int)),this,TQT_SLOT(headerClicked(int)) );
|
|
|
|
mOpen=new TDEAction(i18n("Add &Files..."), "queue", 0, TQT_TQOBJECT(this), TQT_SLOT(addFiles()), actionCollection(), "add_files");
|
|
(void) new TDEAction(i18n("Add Fol&ders..."), "folder", 0, TQT_TQOBJECT(this), TQT_SLOT(addDirectory()), actionCollection(), "add_dir");
|
|
mDelete=new TDEAction(i18n("Delete"), "edit-delete", Key_Delete, TQT_TQOBJECT(this), TQT_SLOT(deleteSelected()), actionCollection(), "delete");
|
|
|
|
mClose=KStdAction::close(TQT_TQOBJECT(this), TQT_SLOT(close()), actionCollection());
|
|
mFind=KStdAction::find(TQT_TQOBJECT(this), TQT_SLOT(find()), actionCollection());
|
|
|
|
(void) KStdAction::configureToolbars(TQT_TQOBJECT(this), TQT_SLOT(configureToolBars()), actionCollection());
|
|
mOpenNew=KStdAction::openNew(TQT_TQOBJECT(this), TQT_SLOT(openNew()), actionCollection());
|
|
mOpenpl=KStdAction::open(TQT_TQOBJECT(this), TQT_SLOT(open()), actionCollection());
|
|
mSave=KStdAction::save(TQT_TQOBJECT(this), TQT_SLOT(save()), actionCollection());
|
|
mSaveAs=KStdAction::saveAs(TQT_TQOBJECT(this), TQT_SLOT(saveAs()), actionCollection());
|
|
|
|
(void) new TDEAction(i18n("Shuffle"), "misc", 0, TQT_TQOBJECT(SPL), TQT_SLOT( randomize() ), actionCollection(), "shuffle");
|
|
(void) new TDEAction(i18n("Clear"), "edit-clear", 0, TQT_TQOBJECT(list), TQT_SLOT( clear() ), actionCollection(), "clear");
|
|
|
|
createGUI("splui.rc");
|
|
|
|
mFinder = new Finder(this);
|
|
|
|
applyMainWindowSettings(TDEGlobal::config(), "SPL Window");
|
|
list->setFocus();
|
|
}
|
|
|
|
void View::find()
|
|
{
|
|
mFinder->show();
|
|
connect(mFinder, TQT_SIGNAL(search(Finder*)), TQT_SLOT(findIt(Finder*)));
|
|
}
|
|
|
|
static bool testWord(TQListViewItem *i, const TQString &finder)
|
|
{
|
|
PlaylistItemData *item=static_cast<SafeListViewItem*>(i);
|
|
if (item->title().find(finder, 0, false) >=0)
|
|
return true;
|
|
if (item->file().find(finder, 0, false) >=0)
|
|
return true;
|
|
if (item->url().path().find(finder.local8Bit().data(), 0, false) >=0)
|
|
return true;
|
|
if (item->lengthString().find(finder, 0, false) >=0)
|
|
return true;
|
|
if (item->mimetype().find(finder.local8Bit().data(), 0, false) >=0)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
static bool testWord(TQListViewItem *i, const TQRegExp &finder)
|
|
{
|
|
PlaylistItemData *item=static_cast<SafeListViewItem*>(i);
|
|
if (item->title().find(finder) >=0)
|
|
return true;
|
|
if (item->file().find(finder) >=0)
|
|
return true;
|
|
if (item->url().path().find(finder) >=0)
|
|
return true;
|
|
if (item->lengthString().find(finder) >=0)
|
|
return true;
|
|
if (item->mimetype().find(finder) >=0)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void View::findIt(Finder *f)
|
|
{
|
|
TQListViewItem *search=list->currentItem();
|
|
|
|
if (list->currentItem())
|
|
{
|
|
if (f->isForward())
|
|
search=list->currentItem()->itemBelow();
|
|
else
|
|
search=list->currentItem()->itemAbove();
|
|
}
|
|
else
|
|
{
|
|
if (f->isForward())
|
|
search=list->firstChild();
|
|
else
|
|
search=list->lastChild();
|
|
}
|
|
|
|
|
|
while (search)
|
|
{
|
|
if (f->regexp())
|
|
{
|
|
if (testWord(search, TQRegExp(f->string(), false)))
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (testWord(search, f->string()))
|
|
break;
|
|
}
|
|
|
|
if (f->isForward())
|
|
search=search->itemBelow();
|
|
else
|
|
search=search->itemAbove();
|
|
|
|
if (!search)
|
|
{
|
|
if (f->isForward())
|
|
{
|
|
if (KMessageBox::questionYesNo(this, i18n("End of playlist reached. Continue searching from beginning?"),TQString(),KStdGuiItem::cont(),KStdGuiItem::cancel()) == KMessageBox::Yes)
|
|
search=list->firstChild();
|
|
}
|
|
else
|
|
{
|
|
if (KMessageBox::questionYesNo(this, i18n("Beginning of playlist reached. Continue searching from end?"),TQString(),KStdGuiItem::cont(),KStdGuiItem::cancel()) == KMessageBox::Yes)
|
|
search=list->lastChild();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (search)
|
|
{
|
|
{ // select none
|
|
TQPtrList<TQListViewItem> sel=list->selectedItems();
|
|
for (TQListViewItem *i=sel.first(); i!=0; i=sel.next())
|
|
list->setSelected(i, false);
|
|
}
|
|
list->setSelected(search, true);
|
|
list->setCurrentItem(search);
|
|
list->ensureItemVisible(search);
|
|
}
|
|
}
|
|
|
|
View::~View()
|
|
{
|
|
napp->player()->stop();
|
|
hide();
|
|
saveState();
|
|
delete list;
|
|
}
|
|
|
|
void View::init()
|
|
{
|
|
// see if we are importing an old-style list
|
|
bool importing= ! TQFile(napp->dirs()->saveLocation("data", "noatun/") + "splitplaylist.xml").exists();
|
|
|
|
if (importing)
|
|
{
|
|
KURL internalURL;
|
|
internalURL.setPath(napp->dirs()->saveLocation("data", "noatun/") + "splitplaylistdata");
|
|
NoatunSaver saver(list, 0);
|
|
saver.load(internalURL, PlaylistSaver::M3U);
|
|
}
|
|
else
|
|
{
|
|
KURL internalURL;
|
|
internalURL.setPath(napp->dirs()->saveLocation("data", "noatun/") + "splitplaylist.xml");
|
|
list->openGlobal(internalURL);
|
|
}
|
|
|
|
TDEConfig &config = *TDEGlobal::config();
|
|
config.setGroup("splitplaylist");
|
|
|
|
// this has to come after openGlobal, since openGlobal emits modified()
|
|
setModified(config.readBoolEntry("modified", false));
|
|
TQString path = config.readPathEntry("file");
|
|
// don't call setPath with an empty path, that would make the url "valid"
|
|
if ( !path.isEmpty() )
|
|
mPlaylistFile.setPath(path);
|
|
|
|
SPL->reset();
|
|
int saved = config.readNumEntry("current", 0);
|
|
|
|
PlaylistItem item=SPL->getFirst();
|
|
for(int i = 0 ; i < saved ; i++)
|
|
{
|
|
item=SPL->getAfter(item);
|
|
}
|
|
if (item)
|
|
SPL->setCurrent(item);
|
|
}
|
|
|
|
void View::save()
|
|
{
|
|
if(mPlaylistFile.isEmpty() || !mPlaylistFile.isValid())
|
|
{
|
|
saveAs();
|
|
return;
|
|
}
|
|
|
|
if(saveToURL(mPlaylistFile))
|
|
setModified(false);
|
|
}
|
|
|
|
void View::saveAs()
|
|
{
|
|
KURL u=KFileDialog::getSaveURL(0, "*.xml splitplaylistdata *.pls *.m3u\n*", this, i18n("Save Playlist"));
|
|
if(!u.isValid())
|
|
return;
|
|
mPlaylistFile = u;
|
|
save();
|
|
}
|
|
|
|
void View::open()
|
|
{
|
|
KURL u=KFileDialog::getOpenURL(0, "*.xml splitplaylistdata *.pls *.m3u\n*", this, i18n("Open Playlist"));
|
|
if(!u.isValid())
|
|
return;
|
|
mPlaylistFile = u;
|
|
list->openGlobal(u);
|
|
setModified(false);
|
|
}
|
|
|
|
void View::openNew()
|
|
{
|
|
mPlaylistFile = "";
|
|
listView()->clear();
|
|
}
|
|
|
|
void List::clear()
|
|
{
|
|
SPL->setCurrent(0);
|
|
|
|
TQListView::clear();
|
|
}
|
|
|
|
void View::deleteSelected()
|
|
{
|
|
TQPtrList<TQListViewItem> items(list->selectedItems());
|
|
|
|
bool stopped=false;
|
|
// noatun shouldn't play files for now
|
|
TQListViewItem *afterLast=0;
|
|
|
|
for (TQPtrListIterator<TQListViewItem> it(items); it.current(); ++it)
|
|
{
|
|
SafeListViewItem *i = static_cast<SafeListViewItem*>(*it);
|
|
if (!stopped && SPL->current() == i)
|
|
{
|
|
napp->player()->stop();
|
|
SPL->setCurrent(0);
|
|
stopped = true;
|
|
}
|
|
i->remove();
|
|
|
|
afterLast = i->itemBelow();
|
|
}
|
|
|
|
if (stopped)
|
|
SPL->setCurrent(static_cast<SafeListViewItem*>(afterLast));
|
|
|
|
setModified(true);
|
|
}
|
|
|
|
void View::addFiles()
|
|
{
|
|
KURL::List files=KFileDialog::getOpenURLs(":mediadir", napp->mimeTypes(), this, i18n("Select File to Play"));
|
|
|
|
TQListViewItem *last = list->lastItem();
|
|
for(KURL::List::Iterator it=files.begin(); it!=files.end(); ++it)
|
|
last = addFile(KURL(*it), false);
|
|
|
|
setModified(true);
|
|
}
|
|
|
|
void View::addDirectory()
|
|
{
|
|
TQString file=KFileDialog::getExistingDirectory(0, this, i18n("Select Folder"));
|
|
|
|
if (!file) return;
|
|
KURL url;
|
|
url.setPath(file);
|
|
list->addDirectoryRecursive(url);
|
|
|
|
setModified(true);
|
|
}
|
|
|
|
void View::closeEvent(TQCloseEvent*)
|
|
{
|
|
hide();
|
|
}
|
|
|
|
void View::showEvent(TQShowEvent *)
|
|
{
|
|
emit shown();
|
|
}
|
|
|
|
void View::hideEvent(TQHideEvent *)
|
|
{
|
|
emit hidden();
|
|
}
|
|
|
|
void View::setModified(bool b)
|
|
{
|
|
modified = b;
|
|
setCaption(i18n("Playlist"), modified);
|
|
}
|
|
|
|
void View::setModified(void)
|
|
{
|
|
setModified(true);
|
|
}
|
|
|
|
void View::saveState(void)
|
|
{
|
|
TDEConfig &config = *TDEGlobal::config();
|
|
config.setGroup("splitplaylist");
|
|
|
|
config.writeEntry("modified", modified);
|
|
config.writePathEntry("file", mPlaylistFile.path());
|
|
saveToURL(napp->dirs()->saveLocation("data", "noatun/") + "splitplaylist.xml");
|
|
|
|
unsigned int i;
|
|
PlaylistItem item=SPL->getFirst();
|
|
for(i = 0; item && item != SPL->current(); )
|
|
item=SPL->getAfter(item), i++;
|
|
|
|
config.writeEntry("current", i);
|
|
saveMainWindowSettings(TDEGlobal::config(), "SPL Window");
|
|
|
|
config.sync();
|
|
}
|
|
|
|
void View::configureToolBars()
|
|
{
|
|
saveMainWindowSettings(TDEGlobal::config(), "SPL Window");
|
|
KEditToolbar dlg(actionCollection(), "splui.rc");
|
|
connect(&dlg, TQT_SIGNAL(newToolbarConfig()), TQT_SLOT(newToolBarConfig()));
|
|
dlg.exec();
|
|
}
|
|
|
|
void View::newToolBarConfig()
|
|
{
|
|
createGUI("splui.rc");
|
|
applyMainWindowSettings(TDEGlobal::config(), "SPL Window");
|
|
}
|
|
|
|
// turns the sorting on or off
|
|
void View::setSorting(bool on, int column)
|
|
{
|
|
if (on)
|
|
{
|
|
list->setSorting(column,true);
|
|
list->setShowSortIndicator(true);
|
|
}
|
|
else
|
|
{
|
|
list->setShowSortIndicator(false);
|
|
list->setSorting(-1);
|
|
}
|
|
}
|
|
|
|
void View::headerClicked(int column)
|
|
{
|
|
// this is to avoid that if we already have it sorted,
|
|
// we sort it again ascendingly this way, clicking on
|
|
// the header a second time will correctly toggle
|
|
// ascending/descending sort
|
|
if (list->showSortIndicator())
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
setSorting(true,column);
|
|
}
|
|
}
|
|
|
|
#include "view.moc"
|
|
|