/***************************************************************************
    copyright            : (C) 2004 by Scott Wheeler
    email                : wheeler@kde.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <kurl.h>

#include <config.h>
#include <tqobjectlist.h>

#include <sys/types.h>
#include <dirent.h>

#include "collectionlist.h"
#include "playlistcollection.h"
#include "actioncollection.h"
#include "advancedsearchdialog.h"
#include "coverinfo.h"
#include "searchplaylist.h"
#include "folderplaylist.h"
#include "historyplaylist.h"
#include "upcomingplaylist.h"
#include "directorylist.h"
#include "mediafiles.h"
#include "playermanager.h"
#include "tracksequencemanager.h"

#include <kiconloader.h>
#include <tdeactionclasses.h>
#include <tdeapplication.h>
#include <kinputdialog.h>
#include <tdemessagebox.h>
#include <tdefiledialog.h>

#include <tqwidgetstack.h>
#include <tqhbox.h>

#define widget (kapp->mainWidget())

using namespace ActionCollection;

////////////////////////////////////////////////////////////////////////////////
// static methods
////////////////////////////////////////////////////////////////////////////////

PlaylistCollection *PlaylistCollection::m_instance = 0;

////////////////////////////////////////////////////////////////////////////////
// public methods
////////////////////////////////////////////////////////////////////////////////

PlaylistCollection::PlaylistCollection(TQWidgetStack *playlistStack) :
    m_playlistStack(playlistStack),
    m_historyPlaylist(0),
    m_upcomingPlaylist(0),
    m_importPlaylists(true),
    m_searchEnabled(true),
    m_playing(false),
    m_showMorePlaylist(0),
    m_belowShowMorePlaylist(0),
    m_dynamicPlaylist(0),
    m_belowDistraction(0),
    m_distraction(0)
{
    m_instance = this;

    m_actionHandler = new ActionHandler(this);
    PlayerManager::instance()->setPlaylistInterface(this);

    // KDirLister's auto error handling seems to crash JuK during startup in
    // readConfig().

    m_dirLister.setAutoErrorHandlingEnabled(false, playlistStack);
    readConfig();
}

PlaylistCollection::~PlaylistCollection()
{
    saveConfig();
    delete m_actionHandler;
    PlayerManager::instance()->setPlaylistInterface(0);
    Playlist::setShuttingDown();
}

TQString PlaylistCollection::name() const
{
    return currentPlaylist()->name();
}

FileHandle PlaylistCollection::currentFile() const
{
    return currentPlaylist()->currentFile();
}

int PlaylistCollection::count() const
{
    return currentPlaylist()->count();
}

int PlaylistCollection::time() const
{
    return currentPlaylist()->time();
}

void PlaylistCollection::playFirst()
{
    m_playing = true;
    currentPlaylist()->playFirst();
    currentChanged();
}

void PlaylistCollection::playNextAlbum()
{
    m_playing = true;
    currentPlaylist()->playNextAlbum();
    currentChanged();
}

void PlaylistCollection::playPrevious()
{
    m_playing = true;
    currentPlaylist()->playPrevious();
    currentChanged();
}

void PlaylistCollection::playNext()
{
    m_playing = true;
    currentPlaylist()->playNext();
    currentChanged();
}

void PlaylistCollection::stop()
{
    m_playing = false;
    currentPlaylist()->stop();
    dataChanged();
}

bool PlaylistCollection::playing() const
{
    return m_playing;
}

TQStringList PlaylistCollection::playlists() const
{
    TQStringList l;

    TQObjectList *childList = m_playlistStack->queryList("Playlist");
    TQObject *obj;
    for(obj = childList->first(); obj; obj = childList->next()) {
        Playlist *p = static_cast<Playlist *>(TQT_TQWIDGET(obj));
        l.append(p->name());
    }

    delete childList;
    return l;
}

void PlaylistCollection::createPlaylist(const TQString &name)
{
    raise(new Playlist(this, name));
}

void PlaylistCollection::createDynamicPlaylist(const PlaylistList &playlists)
{
    if(m_dynamicPlaylist)
        m_dynamicPlaylist->setPlaylists(playlists);
    else
        m_dynamicPlaylist =
            new DynamicPlaylist(playlists, this, i18n("Dynamic List"), "audio-midi", false, true);

    PlaylistCollection::raise(m_dynamicPlaylist);
}

void PlaylistCollection::showMore(const TQString &artist, const TQString &album)
{

    PlaylistList playlists;
    PlaylistSearch::ComponentList components;

    if(currentPlaylist() != CollectionList::instance() &&
       currentPlaylist() != m_showMorePlaylist)
    {
        playlists.append(currentPlaylist());
    }

    playlists.append(CollectionList::instance());

    { // Just setting off the artist stuff in its own block.
        ColumnList columns;
        columns.append(PlaylistItem::ArtistColumn);
        PlaylistSearch::Component c(artist, false, columns,
                                    PlaylistSearch::Component::Exact);
        components.append(c);
    }

    if(!album.isNull()) {
        ColumnList columns;
        columns.append(PlaylistItem::AlbumColumn);
        PlaylistSearch::Component c(album, false, columns,
                                    PlaylistSearch::Component::Exact);
        components.append(c);
    }

    PlaylistSearch search(playlists, components, PlaylistSearch::MatchAll);

    if(m_showMorePlaylist)
        m_showMorePlaylist->setPlaylistSearch(search);
    else
        m_showMorePlaylist = new SearchPlaylist(this, search, i18n("Now Playing"), false, true);

    // The call to raise() below will end up clearing m_belowShowMorePlaylist,
    // so cache the value we want it to have now.
    Playlist *belowShowMore = visiblePlaylist();

    PlaylistCollection::setupPlaylist(m_showMorePlaylist, TQString());
    PlaylistCollection::raise(m_showMorePlaylist);

    m_belowShowMorePlaylist = belowShowMore;
}

void PlaylistCollection::removeTrack(const TQString &playlist, const TQStringList &files)
{
    Playlist *p = playlistByName(playlist);
    PlaylistItemList itemList;
    if(!p)
        return;

    TQStringList::ConstIterator it;
    for(it = files.begin(); it != files.end(); ++it) {
        CollectionListItem *item = CollectionList::instance()->lookup(*it);

        if(item) {
            PlaylistItem *playlistItem = item->itemForPlaylist(p);
            if(playlistItem)
                itemList.append(playlistItem);
        }
    }

    p->clearItems(itemList);
}

TQString PlaylistCollection::playlist() const
{
    return visiblePlaylist() ? visiblePlaylist()->name() : TQString();
}

TQString PlaylistCollection::playingPlaylist() const
{
    return currentPlaylist() && m_playing ? currentPlaylist()->name() : TQString();
}

void PlaylistCollection::setPlaylist(const TQString &playlist)
{
    Playlist *p = playlistByName(playlist);
    if(p)
        raise(p);
}

TQStringList PlaylistCollection::playlistTracks(const TQString &playlist) const
{
    Playlist *p = playlistByName(playlist);

    if(p)
        return p->files();
    return TQStringList();
}

TQString PlaylistCollection::trackProperty(const TQString &file, const TQString &property) const
{
    CollectionList *l = CollectionList::instance();
    CollectionListItem *item = l->lookup(file);

    return item ? item->file().property(property) : TQString();
}

TQPixmap PlaylistCollection::trackCover(const TQString &file, const TQString &size) const
{
    if(size.lower() != "small" && size.lower() != "large")
        return TQPixmap();

    CollectionList *l = CollectionList::instance();
    CollectionListItem *item = l->lookup(file);

    if(!item)
        return TQPixmap();

    if(size.lower() == "small")
        return item->file().coverInfo()->pixmap(CoverInfo::Thumbnail);
    else
        return item->file().coverInfo()->pixmap(CoverInfo::FullSize);
}

void PlaylistCollection::open(const TQStringList &l)
{
    TQStringList files = l;

    if(files.isEmpty())
        files = MediaFiles::openDialog(widget);

    if(files.isEmpty())
        return;

    bool justPlaylists = true;

    for(TQStringList::ConstIterator it = l.begin(); it != l.end() && justPlaylists; ++it)
        justPlaylists = !MediaFiles::isPlaylistFile(*it);

    if(visiblePlaylist() == CollectionList::instance() || justPlaylists ||
       KMessageBox::questionYesNo(
           widget,
           i18n("Do you want to add these items to the current list or to the collection list?"),
           TQString(),
           KGuiItem(i18n("Current")),
           KGuiItem(i18n("Collection"))) == KMessageBox::No)
    {
        CollectionList::instance()->addFiles(files);
    }
    else
        visiblePlaylist()->addFiles(files);

    dataChanged();
}

void PlaylistCollection::open(const TQString &playlist, const TQStringList &files)
{
    Playlist *p = playlistByName(playlist);

    if(p)
        p->addFiles(files);
}

void PlaylistCollection::addFolder()
{
    kdDebug(65432) << k_funcinfo << endl;
    DirectoryList l(m_folderList, m_importPlaylists, widget, "directoryList");
    DirectoryList::Result result = l.exec();

    if(result.status == TQDialog::Accepted) {

        m_dirLister.blockSignals(true);

        const bool reload = m_importPlaylists != result.addPlaylists;
        m_importPlaylists = result.addPlaylists;

        for(TQStringList::Iterator it = result.addedDirs.begin();
            it != result.addedDirs.end(); it++)
        {
            m_dirLister.openURL(*it, true);
            m_folderList.append(*it);
        }

        for(TQStringList::Iterator it = result.removedDirs.begin();
            it !=  result.removedDirs.end(); it++)
        {
            m_dirLister.stop(*it);
            m_folderList.remove(*it);
        }

        if(reload)
            open(m_folderList);
        else if(!result.addedDirs.isEmpty())
            open(result.addedDirs);

        saveConfig();

        m_dirLister.blockSignals(false);
    }
}

void PlaylistCollection::rename()
{
    TQString old = visiblePlaylist()->name();
    TQString name = playlistNameDialog(i18n("Rename"), old, false);

    m_playlistNames.remove(old);

    if(name.isNull())
        return;

    visiblePlaylist()->setName(name);
}

void PlaylistCollection::duplicate()
{
    TQString name = playlistNameDialog(i18n("Duplicate"), visiblePlaylist()->name());
    if(name.isNull())
        return;
    raise(new Playlist(this, visiblePlaylist()->items(), name));
}

void PlaylistCollection::save()
{
    visiblePlaylist()->save();
}

void PlaylistCollection::saveAs()
{
    visiblePlaylist()->saveAs();
}

void PlaylistCollection::reload()
{
    if(visiblePlaylist() == CollectionList::instance())
        CollectionList::instance()->addFiles(m_folderList);
    else
        visiblePlaylist()->slotReload();

}

void PlaylistCollection::editSearch()
{
    SearchPlaylist *p = dynamic_cast<SearchPlaylist *>(visiblePlaylist());

    if(!p)
        return;

    AdvancedSearchDialog::Result r =
        AdvancedSearchDialog(p->name(), p->playlistSearch(), widget).exec();

    if(r.result == AdvancedSearchDialog::Accepted) {
        p->setPlaylistSearch(r.search);
        p->setName(r.playlistName);
    }
}

void PlaylistCollection::removeItems()
{
    visiblePlaylist()->slotRemoveSelectedItems();
}

void PlaylistCollection::refreshItems()
{
    visiblePlaylist()->slotRefresh();
}

void PlaylistCollection::renameItems()
{
    visiblePlaylist()->slotRenameFile();
}

void PlaylistCollection::addCovers(bool fromFile)
{
    visiblePlaylist()->slotAddCover(fromFile);
    dataChanged();
}

void PlaylistCollection::removeCovers()
{
    visiblePlaylist()->slotRemoveCover();
    dataChanged();
}

void PlaylistCollection::viewCovers()
{
    visiblePlaylist()->slotViewCover();
}

void PlaylistCollection::showCoverManager()
{
    visiblePlaylist()->slotShowCoverManager();
}

PlaylistItemList PlaylistCollection::selectedItems()
{
    return visiblePlaylist()->selectedItems();
}

void PlaylistCollection::scanFolders()
{
    CollectionList::instance()->addFiles(m_folderList);

    if(CollectionList::instance()->count() == 0)
        addFolder();
}

void PlaylistCollection::createPlaylist()
{
    TQString name = playlistNameDialog();
    if(!name.isNull())
        raise(new Playlist(this, name));
}

void PlaylistCollection::createSearchPlaylist()
{
    TQString name = uniquePlaylistName(i18n("Search Playlist"));

    AdvancedSearchDialog::Result r =
        AdvancedSearchDialog(name, PlaylistSearch(), widget).exec();

    if(r.result == AdvancedSearchDialog::Accepted)
        raise(new SearchPlaylist(this, r.search, r.playlistName));
}

void PlaylistCollection::createFolderPlaylist()
{
    TQString folder = KFileDialog::getExistingDirectory();

    if(folder.isEmpty())
        return;

    TQString name = uniquePlaylistName(folder.mid(folder.findRev('/') + 1));
    name = playlistNameDialog(i18n("Create Folder Playlist"), name);

    if(!name.isNull())
        raise(new FolderPlaylist(this, folder, name));
}

void PlaylistCollection::guessTagFromFile()
{
    visiblePlaylist()->slotGuessTagInfo(TagGuesser::FileName);
}

void PlaylistCollection::guessTagFromInternet()
{
    visiblePlaylist()->slotGuessTagInfo(TagGuesser::MusicBrainz);
}

void PlaylistCollection::setSearchEnabled(bool enable)
{
    if(enable == m_searchEnabled)
        return;

    m_searchEnabled = enable;

    visiblePlaylist()->setSearchEnabled(enable);
}

HistoryPlaylist *PlaylistCollection::historyPlaylist() const
{
    return m_historyPlaylist;
}

void PlaylistCollection::setHistoryPlaylistEnabled(bool enable)
{
    if((enable && m_historyPlaylist) || (!enable && !m_historyPlaylist))
        return;

    if(enable) {
        action<TDEToggleAction>("showHistory")->setChecked(true);
        m_historyPlaylist = new HistoryPlaylist(this);
        m_historyPlaylist->setName(i18n("History"));
        setupPlaylist(m_historyPlaylist, "history");
    }
    else {
        delete m_historyPlaylist;
        m_historyPlaylist = 0;
    }
}

UpcomingPlaylist *PlaylistCollection::upcomingPlaylist() const
{
    return m_upcomingPlaylist;
}

void PlaylistCollection::setUpcomingPlaylistEnabled(bool enable)
{
    if((enable && m_upcomingPlaylist) || (!enable && !m_upcomingPlaylist))
        return;

    if(enable) {
        action<TDEToggleAction>("showUpcoming")->setChecked(true);
        if(!m_upcomingPlaylist)
            m_upcomingPlaylist = new UpcomingPlaylist(this);

        setupPlaylist(m_upcomingPlaylist, "today");
    }
    else {
        action<TDEToggleAction>("showUpcoming")->setChecked(false);
        bool raiseCollection = m_playlistStack->visibleWidget() == m_upcomingPlaylist;
        delete m_upcomingPlaylist;
        m_upcomingPlaylist = 0;

        if(raiseCollection) {
            kapp->processEvents(); // Seems to stop a crash, weird.
            raise(CollectionList::instance());
        }
    }
}

TQObject *PlaylistCollection::object() const
{
    return m_actionHandler;
}

Playlist *PlaylistCollection::currentPlaylist() const
{
    if(m_belowDistraction)
        return m_belowDistraction;

    if(m_upcomingPlaylist && m_upcomingPlaylist->active())
        return m_upcomingPlaylist;

    if(Playlist::playingItem())
        return Playlist::playingItem()->playlist();
    else
        return visiblePlaylist();
}

Playlist *PlaylistCollection::visiblePlaylist() const
{
    return static_cast<Playlist *>(m_playlistStack->visibleWidget());
}

void PlaylistCollection::raise(Playlist *playlist)
{
    if(m_showMorePlaylist && currentPlaylist() == m_showMorePlaylist)
        m_showMorePlaylist->lower(playlist);
    if(m_dynamicPlaylist && currentPlaylist() == m_dynamicPlaylist)
        m_dynamicPlaylist->lower(playlist);

    TrackSequenceManager::instance()->setCurrentPlaylist(playlist);
    playlist->applySharedSettings();
    playlist->setSearchEnabled(m_searchEnabled);
    m_playlistStack->raiseWidget(playlist);
    clearShowMore(false);
    dataChanged();
}

void PlaylistCollection::raiseDistraction()
{
    if(m_belowDistraction)
        return;

    m_belowDistraction = currentPlaylist();

    if(!m_distraction) {
        m_distraction = new TQHBox(m_playlistStack);
        m_playlistStack->addWidget(m_distraction);
    }

    m_playlistStack->raiseWidget(m_distraction);
}

void PlaylistCollection::lowerDistraction()
{
    if(!m_distraction)
        return;

    if(m_belowDistraction)
        m_playlistStack->raiseWidget(m_belowDistraction);

    m_belowDistraction = 0;
}

////////////////////////////////////////////////////////////////////////////////
// protected methods
////////////////////////////////////////////////////////////////////////////////

TQWidgetStack *PlaylistCollection::playlistStack() const
{
    return m_playlistStack;
}

void PlaylistCollection::setupPlaylist(Playlist *playlist, const TQString &)
{
    if(!playlist->fileName().isNull())
        m_playlistFiles.insert(playlist->fileName());

    if(!playlist->name().isNull())
        m_playlistNames.insert(playlist->name());

    TQObject::connect(playlist, TQT_SIGNAL(selectionChanged()),
                     object(), TQT_SIGNAL(signalSelectedItemsChanged()));
}

bool PlaylistCollection::importPlaylists() const
{
    return m_importPlaylists;
}

bool PlaylistCollection::containsPlaylistFile(const TQString &file) const
{
    return m_playlistFiles.contains(file);
}

bool PlaylistCollection::showMoreActive() const
{
    return visiblePlaylist() == m_showMorePlaylist;
}

void PlaylistCollection::clearShowMore(bool raisePlaylist)
{
    if(!m_showMorePlaylist)
        return;

    if(raisePlaylist) {
        if(m_belowShowMorePlaylist)
            raise(m_belowShowMorePlaylist);
        else
            raise(CollectionList::instance());
    }

    m_belowShowMorePlaylist = 0;
}

void PlaylistCollection::enableDirWatch(bool enable)
{
    TQObject *collection = TQT_TQOBJECT(CollectionList::instance());

    m_dirLister.disconnect(object());
    if(enable) {
        TQObject::connect(&m_dirLister, TQT_SIGNAL(newItems(const KFileItemList &)),
                object(), TQT_SLOT(slotNewItems(const KFileItemList &)));
        TQObject::connect(&m_dirLister, TQT_SIGNAL(refreshItems(const KFileItemList &)),
                collection, TQT_SLOT(slotRefreshItems(const KFileItemList &)));
        TQObject::connect(&m_dirLister, TQT_SIGNAL(deleteItem(KFileItem *)),
                collection, TQT_SLOT(slotDeleteItem(KFileItem *)));
    }
}

TQString PlaylistCollection::playlistNameDialog(const TQString &caption,
                                               const TQString &suggest,
                                               bool forceUnique) const
{
    bool ok;

    TQString name = KInputDialog::getText(
        caption,
        i18n("Please enter a name for this playlist:"),
        forceUnique ? uniquePlaylistName(suggest) : suggest,
        &ok);

    return ok ? uniquePlaylistName(name) : TQString();
}


TQString PlaylistCollection::uniquePlaylistName(const TQString &suggest) const
{
    if(suggest.isEmpty())
        return uniquePlaylistName();

    if(!m_playlistNames.contains(suggest))
        return suggest;

    TQString base = suggest;
    base.remove(TQRegExp("\\s\\([0-9]+\\)$"));

    int count = 1;
    TQString s = TQString("%1 (%2)").arg(base).arg(count);

    while(m_playlistNames.contains(s)) {
        count++;
        s = TQString("%1 (%2)").arg(base).arg(count);
    }

    return s;
}

void PlaylistCollection::addNameToDict(const TQString &name)
{
    m_playlistNames.insert(name);
}

void PlaylistCollection::addFileToDict(const TQString &file)
{
    m_playlistFiles.insert(file);
}

void PlaylistCollection::removeNameFromDict(const TQString &name)
{
    m_playlistNames.remove(name);
}

void PlaylistCollection::removeFileFromDict(const TQString &file)
{
    m_playlistFiles.remove(file);
}

void PlaylistCollection::dirChanged(const TQString &path)
{
    CollectionList::instance()->addFiles(path);
}

Playlist *PlaylistCollection::playlistByName(const TQString &name) const
{
    TQObjectList *l = m_playlistStack->queryList("Playlist");
    Playlist *list = 0;
    TQObject *obj;

    for(obj = l->first(); obj; obj = l->next()) {
        Playlist *p = static_cast<Playlist*>(TQT_TQWIDGET(obj));
        if(p->name() == name) {
            list = p;
            break;
        }
    }

    delete l;
    return list;
}

void PlaylistCollection::newItems(const KFileItemList &list) const
{
    CollectionList::instance()->slotNewItems(list);
}

////////////////////////////////////////////////////////////////////////////////
// private methods
////////////////////////////////////////////////////////////////////////////////

void PlaylistCollection::readConfig()
{
    TDEConfigGroup config(TDEGlobal::config(), "Playlists");

    m_importPlaylists  = config.readBoolEntry("ImportPlaylists", true);
    m_folderList       = config.readPathListEntry("DirectoryList");

    for(TQStringList::ConstIterator it = m_folderList.begin(); it != m_folderList.end(); ++it)
        m_dirLister.openURL(*it, true);
}

void PlaylistCollection::saveConfig()
{
    TDEConfigGroup config(TDEGlobal::config(), "Playlists");
    config.writeEntry("ImportPlaylists", m_importPlaylists);
    config.writeEntry("showUpcoming", action<TDEToggleAction>("showUpcoming")->isChecked());
    config.writePathEntry("DirectoryList", m_folderList);
}

////////////////////////////////////////////////////////////////////////////////
// ActionHanlder implementation
////////////////////////////////////////////////////////////////////////////////

PlaylistCollection::ActionHandler::ActionHandler(PlaylistCollection *collection) :
    TQObject(0, "ActionHandler"),
    m_collection(collection)
{
    TDEActionMenu *menu;

    // "New" menu

    menu = new TDEActionMenu(i18n("&New"), "document-new", actions(), "file_new");

    menu->insert(createAction(i18n("&Empty Playlist..."), TQT_SLOT(slotCreatePlaylist()),
                              "newPlaylist", "window-new", "CTRL+n"));
    menu->insert(createAction(i18n("&Search Playlist..."), TQT_SLOT(slotCreateSearchPlaylist()),
                              "newSearchPlaylist", "edit-find", "CTRL+f"));
    menu->insert(createAction(i18n("Playlist From &Folder..."), TQT_SLOT(slotCreateFolderPlaylist()),
                              "newDirectoryPlaylist", "document-open", "CTRL+d"));

    // Guess tag info menu

#if HAVE_MUSICBRAINZ
    menu = new TDEActionMenu(i18n("&Guess Tag Information"), TQString(), actions(), "guessTag");
    menu->setIconSet(SmallIconSet("wizard"));

    menu->insert(createAction(i18n("From &File Name"), TQT_SLOT(slotGuessTagFromFile()),
                              "guessTagFile", "fileimport", "CTRL+g"));
    menu->insert(createAction(i18n("From &Internet"), TQT_SLOT(slotGuessTagFromInternet()),
                              "guessTagInternet", "connect_established", "CTRL+i"));
#else
    createAction(i18n("Guess Tag Information From &File Name"), TQT_SLOT(slotGuessTagFromFile()),
                 "guessTag", "fileimport", "CTRL+f");
#endif


    createAction(i18n("Play First Track"),TQT_SLOT(slotPlayFirst()),     "playFirst");
    createAction(i18n("Play Next Album"), TQT_SLOT(slotPlayNextAlbum()), "forwardAlbum", "next");

    createAction(i18n("Open..."),         TQT_SLOT(slotOpen()),         "file_open", "document-open", "CTRL+o");
    createAction(i18n("Add &Folder..."),  TQT_SLOT(slotAddFolder()),    "openDirectory", "document-open");
    createAction(i18n("&Rename..."),      TQT_SLOT(slotRename()),       "renamePlaylist", "lineedit");
    createAction(i18n("D&uplicate..."),   TQT_SLOT(slotDuplicate()),    "duplicatePlaylist", "edit-copy");
    createAction(i18n("Save"),            TQT_SLOT(slotSave()),         "file_save", "document-save", "CTRL+s");
    createAction(i18n("Save As..."),      TQT_SLOT(slotSaveAs()),       "file_save_as", "document-save-as");
    createAction(i18n("R&emove"),         TQT_SLOT(slotRemove()),       "deleteItemPlaylist", "edittrash");
    createAction(i18n("Reload"),          TQT_SLOT(slotReload()),       "reloadPlaylist", "reload");
    createAction(i18n("Edit Search..."),  TQT_SLOT(slotEditSearch()),   "editSearch", "edit-clear");

    createAction(i18n("&Delete"),         TQT_SLOT(slotRemoveItems()),  "removeItem", "edit-delete");
    createAction(i18n("Refresh"),         TQT_SLOT(slotRefreshItems()), "refresh", "reload");
    createAction(i18n("&Rename File"),    TQT_SLOT(slotRenameItems()),  "renameFile", "document-save-as", "CTRL+r");

    menu = new TDEActionMenu(i18n("Cover Manager"), TQString(), actions(), "coverManager");
    menu->setIconSet(SmallIconSet("image-x-generic"));
    menu->insert(createAction(i18n("&View Cover"),
        TQT_SLOT(slotViewCovers()), "viewCover", "viewmag"));
    menu->insert(createAction(i18n("Get Cover From &File..."),
        TQT_SLOT(slotAddLocalCover()), "addCover", "fileimport", "CTRL+SHIFT+f"));

    // Do not rename googleCover for backward compatibility
    menu->insert(createAction(i18n("Get Cover From &Internet..."),
        TQT_SLOT(slotAddInternetCover()), "googleCover", "connect_established", "CTRL+SHIFT+g"));
    menu->insert(createAction(i18n("&Delete Cover"),
        TQT_SLOT(slotRemoveCovers()), "removeCover", "edit-delete"));
    menu->insert(createAction(i18n("Show Cover &Manager"),
        TQT_SLOT(slotShowCoverManager()), "showCoverManager"));

    TDEToggleAction *historyAction =
        new TDEToggleAction(i18n("Show &History"), "history",  0, actions(), "showHistory");
    historyAction->setCheckedState(i18n("Hide &History"));

    TDEToggleAction *upcomingAction =
        new TDEToggleAction(i18n("Show &Play Queue"), "today", 0, actions(), "showUpcoming");
    upcomingAction->setCheckedState(i18n("Hide &Play Queue"));

    connect(action<TDEToggleAction>("showHistory"), TQT_SIGNAL(toggled(bool)),
            this, TQT_SLOT(slotSetHistoryPlaylistEnabled(bool)));
    connect(action<TDEToggleAction>("showUpcoming"), TQT_SIGNAL(toggled(bool)),
            this, TQT_SLOT(slotSetUpcomingPlaylistEnabled(bool)));
}

TDEAction *PlaylistCollection::ActionHandler::createAction(const TQString &text,
                                                         const char *slot,
                                                         const char *name,
                                                         const TQString &icon,
                                                         const TDEShortcut &shortcut)
{
    if(icon.isNull())
        return new TDEAction(text, shortcut, this, slot, actions(), name);
    else
        return new TDEAction(text, icon, shortcut, this, slot, actions(), name);
}

#undef widget
#include "playlistcollection.moc"
