/**
 * Copyright (C) 2006 by Koos Vriezen <koos.vriezen@gmail.com>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License version 2 as published by the Free Software Foundation.
 *
 *  This library 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
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this library; see the file COPYING.LIB.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
 *  Boston, MA 02110-1301, USA.
 **/

#include <stdio.h>

#include <config.h>
// include files for TQt
#include <tqapplication.h>
#include <tqclipboard.h>
#include <tqpopupmenu.h>
#include <tqdrawutil.h>
#include <tqpainter.h>
#include <tqiconset.h>
#include <tqpixmap.h>
#include <tqheader.h>
#include <tqstyle.h>
#include <tqtimer.h>

#include <kiconloader.h>
#include <kfinddialog.h>
#include <kurldrag.h>
#include <tdeaction.h>
#include <tdelocale.h>
#include <kdebug.h>

#include "playlistview.h"
#include "kmplayerview.h"
#include "kmplayercontrolpanel.h"

using namespace KMPlayer;

//-------------------------------------------------------------------------

namespace KMPlayer {

    KDE_NO_EXPORT bool isDragValid (TQDropEvent * de) {
        if (KURLDrag::canDecode (de))
            return true;
        if (TQTextDrag::canDecode (de)) {
            TQString text;
            if (TQTextDrag::decode (de, text) && KURL (text).isValid ())
                return true;
        }
        return false;
    }
}

//-----------------------------------------------------------------------------

KDE_NO_CDTOR_EXPORT PlayListItem::PlayListItem (TQListViewItem *p, const NodePtr & e, PlayListView * lv) : TQListViewItem (p), node (e), listview (lv) {}

KDE_NO_CDTOR_EXPORT PlayListItem::PlayListItem (TQListViewItem *p, const AttributePtr & a, PlayListView * lv) : TQListViewItem (p), m_attr (a), listview (lv) {}

KDE_NO_CDTOR_EXPORT
PlayListItem::PlayListItem (PlayListView *v, const NodePtr &e, TQListViewItem *b)
  : TQListViewItem (v, b), node (e), listview (v) {}

KDE_NO_CDTOR_EXPORT void PlayListItem::paintCell (TQPainter * p, const TQColorGroup & cg, int column, int width, int align) {
    if (node && node->state == Node::state_began) {
        TQColorGroup mycg (cg);
        mycg.setColor (TQColorGroup::Foreground, listview->activeColor ());
        mycg.setColor (TQColorGroup::Text, listview->activeColor ());
        TQListViewItem::paintCell (p, mycg, column, width, align);
    } else
        TQListViewItem::paintCell (p, cg, column, width, align);
}

KDE_NO_CDTOR_EXPORT void PlayListItem::paintBranches (TQPainter * p, const TQColorGroup &, int w, int, int h) {
    p->fillRect (0, 0, w, h, listview->paletteBackgroundColor());
}

//-----------------------------------------------------------------------------

KDE_NO_CDTOR_EXPORT
RootPlayListItem::RootPlayListItem (int _id, PlayListView *v, const NodePtr & e, TQListViewItem * before, int flgs)
  : PlayListItem (v, e, before),
    id (_id),
    flags (flgs),
    show_all_nodes (false),
    have_dark_nodes (false) {}

KDE_NO_CDTOR_EXPORT void RootPlayListItem::paintCell (TQPainter * p, const TQColorGroup & cg, int column, int width, int align) {
    TQColorGroup mycg (cg);
    mycg.setColor (TQColorGroup::Base, listview->topLevelWidget()->paletteBackgroundColor());
    mycg.setColor (TQColorGroup::Highlight, mycg.base ());
    mycg.setColor (TQColorGroup::Text, listview->topLevelWidget()->paletteForegroundColor());
    mycg.setColor (TQColorGroup::HighlightedText, mycg.text ());
    TQListViewItem::paintCell (p, mycg, column, width, align);
    qDrawShadeRect (p, 0, 0, width -1, height () -1, mycg, !isOpen ());
}

//-----------------------------------------------------------------------------

KDE_NO_CDTOR_EXPORT PlayListView::PlayListView (TQWidget * parent, View * view, TDEActionCollection * ac)
 : TDEListView (parent, "kde_kmplayer_playlist"),
   m_view (view),
   m_find_dialog (0L),
   m_active_color (30, 0, 255),
   last_id (0),
   last_drag_tree_id (0),
   m_ignore_expanded (false) {
    addColumn (TQString ());
    header()->hide ();
    //setRootIsDecorated (true);
    setSorting (-1);
    setAcceptDrops (true);
    setDropVisualizer (true);
    setItemsRenameable (true);
    setItemMargin (2);
    setPaletteBackgroundColor (TQColor (0, 0, 0));
    setPaletteForegroundColor (TQColor (0xB2, 0xB2, 0xB2));
    m_itemmenu = new TQPopupMenu (this);
    folder_pix = TDEGlobal::iconLoader ()->loadIcon (TQString ("folder"), TDEIcon::Small);
    auxiliary_pix = TDEGlobal::iconLoader ()->loadIcon (TQString ("folder_grey"), TDEIcon::Small);
    video_pix = TDEGlobal::iconLoader ()->loadIcon (TQString ("video-x-generic"), TDEIcon::Small);
    info_pix = TDEGlobal::iconLoader ()->loadIcon (TQString ("messagebox_info"), TDEIcon::Small);
    img_pix = TDEGlobal::iconLoader ()->loadIcon (TQString ("colorize"), TDEIcon::Small);
    unknown_pix = TDEGlobal::iconLoader ()->loadIcon (TQString ("unknown"), TDEIcon::Small);
    menu_pix = TDEGlobal::iconLoader ()->loadIcon (TQString ("player_playlist"), TDEIcon::Small);
    config_pix = TDEGlobal::iconLoader ()->loadIcon (TQString ("configure"), TDEIcon::Small);
    url_pix = TDEGlobal::iconLoader ()->loadIcon (TQString ("www"), TDEIcon::Small);
    m_find = KStdAction::find (TQT_TQOBJECT(this), TQT_SLOT (slotFind ()), ac, "find");
    m_find_next = KStdAction::findNext (TQT_TQOBJECT(this), TQT_SLOT(slotFindNext()), ac, "next");
    m_find_next->setEnabled (false);
    connect (this, TQT_SIGNAL (contextMenuRequested (TQListViewItem *, const TQPoint &, int)), this, TQT_SLOT (contextMenuItem (TQListViewItem *, const TQPoint &, int)));
    connect (this, TQT_SIGNAL (expanded (TQListViewItem *)),
             this, TQT_SLOT (itemExpanded (TQListViewItem *)));
    connect (this, TQT_SIGNAL (dropped (TQDropEvent *, TQListViewItem *)),
             this, TQT_SLOT (itemDropped (TQDropEvent *, TQListViewItem *)));
    connect (this, TQT_SIGNAL (itemRenamed (TQListViewItem *)),
             this, TQT_SLOT (itemIsRenamed (TQListViewItem *)));
    connect (this, TQT_SIGNAL (selectionChanged (TQListViewItem *)),
             this, TQT_SLOT (itemIsSelected (TQListViewItem *)));
}

KDE_NO_CDTOR_EXPORT PlayListView::~PlayListView () {
}

int PlayListView::addTree (NodePtr root, const TQString & source, const TQString & icon, int flags) {
    //kdDebug () << "addTree " << source << " " << root->mrl()->src << endl;
    RootPlayListItem * ritem = new RootPlayListItem (++last_id, this, root, lastChild(), flags);
    ritem->source = source;
    ritem->icon = icon;
    ritem->setPixmap (0, !ritem->icon.isEmpty ()
            ? TDEGlobal::iconLoader ()->loadIcon (ritem->icon, TDEIcon::Small)
            : url_pix);
    updateTree (ritem, 0L, false);
    return last_id;
}

KDE_NO_EXPORT PlayListItem * PlayListView::populate
(NodePtr e, NodePtr focus, RootPlayListItem *root, PlayListItem * pitem, PlayListItem ** curitem) {
    root->have_dark_nodes |= !e->expose ();
    if (pitem && !root->show_all_nodes && !e->expose ()) {
        for (NodePtr c = e->lastChild (); c; c = c->previousSibling ())
            populate (c, focus, root, pitem, curitem);
        return pitem;
    }
    PlayListItem * item = pitem ? new PlayListItem (pitem, e, this) : root;
    Mrl * mrl = e->mrl ();
    TQString text (e->nodeName());
    if (mrl && !root->show_all_nodes) {
        if (mrl->pretty_name.isEmpty ()) {
            if (!mrl->src.isEmpty())
                text = KURL(mrl->src).prettyURL (0, KURL::StripFileProtocol);
            else if (e->isDocument ())
                text = e->hasChildNodes () ? i18n ("unnamed") : i18n ("none");
        } else
            text = mrl->pretty_name;
    } else if (e->id == id_node_text)
        text = e->nodeValue ();
    item->setText(0, text);
    if (focus == e)
        *curitem = item;
    if (e->active ())
        ensureItemVisible (item);
    for (NodePtr c = e->lastChild (); c; c = c->previousSibling ())
        populate (c, focus, root, item, curitem);
    if (e->isElementNode ()) {
        AttributePtr a = convertNode<Element> (e)->attributes ()->first ();
        if (a) {
            root->have_dark_nodes = true;
            if (root->show_all_nodes) {
                PlayListItem * as = new PlayListItem (item, e, this);
                as->setText (0, i18n ("[attributes]"));
                as->setPixmap (0, menu_pix);
                for (; a; a = a->nextSibling ()) {
                    PlayListItem * ai = new PlayListItem (as, a, this);
                    ai->setText (0, TQString ("%1=%2").arg (
                                a->name ().toString ()).arg (a->value ()));
                    ai->setPixmap (0, config_pix);
                }
            }
        }
    }
    if (item != root) {
        Node::PlayType pt = e->playType ();
        TQPixmap * pix;
        switch (pt) {
            case Node::play_type_image:
                pix = &img_pix;
                break;
            case Node::play_type_info:
                pix = &info_pix;
                break;
            default:
                if (pt > Node::play_type_none)
                    pix = &video_pix;
                else 
                    pix = item->firstChild ()
                        ? e->auxiliaryNode ()
                          ? &auxiliary_pix : &folder_pix
                          : &unknown_pix;
        }
        item->setPixmap (0, *pix);
        if (root->flags & PlayListView::AllowDrag)
            item->setDragEnabled (true);
    }
    return item;
}

void PlayListView::updateTree (int id, NodePtr root, NodePtr active,
        bool select, bool open) {
    // TODO, if root is same as rootitems->node and treeversion is the same
    // and show all nodes is unchanged then only update the cells
    TQWidget * w = focusWidget ();
    if (w && w != this)
        w->clearFocus ();
    //setSelected (firstChild (), true);
    RootPlayListItem * ritem = static_cast <RootPlayListItem *> (firstChild ());
    RootPlayListItem * before = 0L;
    for (; ritem; ritem =static_cast<RootPlayListItem*>(ritem->nextSibling())) {
        if (ritem->id == id) {
            if (!root)
                root = ritem->node;
            break;  // found based on id
        }
        if (id == -1) { // wildcard id
            for (NodePtr n = root; n; n = n->parentNode ())
                if (n == ritem->node) {
                    root = n;
                    break;
                }
            if (root == ritem->node) {
                id = ritem->id;
                break;  // found based on matching (ancestor) node
            }
        }
        if (ritem->id < id)
            before = ritem;
    }
    if (!root) {
        delete ritem;
        return;
    }
    if (!ritem) {
        ritem =new RootPlayListItem(id, this, root, before,AllowDrops|TreeEdit);
        ritem->setPixmap (0, url_pix);
    } else
        ritem->node = root;
    m_find_next->setEnabled (!!m_current_find_elm);
    bool need_timer = !tree_update;
    tree_update = new TreeUpdate (ritem, active, select, open, tree_update);
    if (need_timer)
        TQTimer::singleShot (0, this, TQT_SLOT (updateTrees ()));
}

KDE_NO_EXPORT void PlayListView::updateTrees () {
    for (; tree_update; tree_update = tree_update->next) {
        updateTree (tree_update->root_item, tree_update->node, tree_update->select);
        if (tree_update->open) // FIXME for non-root nodes lazy loading
            setOpen (tree_update->root_item, true);
    }
}

void PlayListView::updateTree (RootPlayListItem * ritem, NodePtr active, bool select) {
    bool set_open = ritem->id == 0 || (ritem ? ritem->isOpen () : false);
    m_ignore_expanded = true;
    PlayListItem * curitem = 0L;
    while (ritem->firstChild ())
        delete ritem->firstChild ();
    if (!ritem->node)
        return;
    populate (ritem->node, active, ritem, 0L, &curitem);
    if (set_open && ritem->firstChild () && !ritem->isOpen ())
        setOpen (ritem, true);
    if (curitem && select) {
        setSelected (curitem, true);
        ensureItemVisible (curitem);
    }
    if (!ritem->have_dark_nodes && ritem->show_all_nodes && !m_view->editMode())
        toggleShowAllNodes (); // redo, because the user can't change it anymore
    m_ignore_expanded = false;
}

void PlayListView::selectItem (const TQString & txt) {
    TQListViewItem * item = selectedItem ();
    if (item && item->text (0) == txt)
        return;
    item = findItem (txt, 0);
    if (item) {
        setSelected (item, true);
        ensureItemVisible (item);
    }
}

KDE_NO_EXPORT TQDragObject * PlayListView::dragObject () {
    PlayListItem * item = static_cast <PlayListItem *> (selectedItem ());
    if (item && item->node) {
        TQString txt = item->node->isPlayable ()
            ? item->node->mrl ()->src : item->node->outerXML ();
        TQTextDrag * drag = new TQTextDrag (txt, this);
        last_drag_tree_id = rootItem (item)->id;
        m_last_drag = item->node;
        drag->setPixmap (*item->pixmap (0));
        if (!item->node->isPlayable ())
            drag->setSubtype ("xml");
        return drag;
    }
    return 0;
}

KDE_NO_EXPORT void PlayListView::setFont (const TQFont & fnt) {
    setTreeStepSize (TQFontMetrics (fnt).boundingRect ('m').width ());
    TDEListView::setFont (fnt);
}

KDE_NO_EXPORT void PlayListView::contextMenuItem (TQListViewItem * vi, const TQPoint & p, int) {
    if (vi) {
        PlayListItem * item = static_cast <PlayListItem *> (vi);
        if (item->node || item->m_attr) {
            RootPlayListItem * ritem = rootItem (vi);
            if (m_itemmenu->count () > 0) {
                m_find->unplug (m_itemmenu);
                m_find_next->unplug (m_itemmenu);
                m_itemmenu->clear ();
            }
            m_itemmenu->insertItem (TDEGlobal::iconLoader ()->loadIconSet
                    (TQString ("edit-copy"), TDEIcon::Small, 0, true),
                    i18n ("&Copy to Clipboard"),
                    this, TQT_SLOT (copyToClipboard ()), 0, 0);
            if (item->m_attr ||
                    (item->node && (item->node->isPlayable () ||
                                    item->node->isDocument ()) &&
                     item->node->mrl ()->bookmarkable))
                m_itemmenu->insertItem (TDEGlobal::iconLoader ()->loadIconSet
                        (TQString ("bookmark_add"), TDEIcon::Small, 0, true),
                        i18n ("&Add Bookmark"),
                        this, TQT_SLOT (addBookMark ()), 0, 1);
            if (ritem->have_dark_nodes) {
                m_itemmenu->insertItem (i18n ("&Show all"),
                        this, TQT_SLOT (toggleShowAllNodes ()), 0, 2);
                m_itemmenu->setItemChecked (2, ritem->show_all_nodes);
            }
            m_itemmenu->insertSeparator ();
            m_find->plug (m_itemmenu);
            m_find_next->plug (m_itemmenu);
            emit prepareMenu (item, m_itemmenu);
            m_itemmenu->exec (p);
        }
    } else
        m_view->controlPanel ()->popupMenu ()->exec (p);
}

void PlayListView::itemExpanded (TQListViewItem * item) {
    if (!m_ignore_expanded && item->childCount () == 1) {
        PlayListItem * child_item = static_cast<PlayListItem*>(item->firstChild ());
        child_item->setOpen (rootItem (item)->show_all_nodes ||
                (child_item->node && child_item->node->expose ()));
    }
}

RootPlayListItem * PlayListView::rootItem (TQListViewItem * item) const {
    if (!item)
        return 0L;
    while (item->parent ())
        item = item->parent ();
    return static_cast <RootPlayListItem *> (item);
}

RootPlayListItem * PlayListView::rootItem (int id) const {
    RootPlayListItem * ri = static_cast <RootPlayListItem *> (firstChild ());
    for (; ri; ri = static_cast <RootPlayListItem *> (ri->nextSibling ())) {
        if (ri->id == id)
            return ri;
    }
    return 0L;
}

void PlayListView::copyToClipboard () {
    PlayListItem * item = currentPlayListItem ();
    TQString text = item->text (0);
    if (item->node) {
        Mrl * mrl = item->node->mrl ();
        if (mrl && !mrl->src.isEmpty ())
            text = mrl->src;
    }
    TQApplication::clipboard()->setText (text);
}

void PlayListView::addBookMark () {
    PlayListItem * item = currentPlayListItem ();
    if (item->node) {
        Mrl * mrl = item->node->mrl ();
        KURL url (mrl ? mrl->src : TQString (item->node->nodeName ()));
        emit addBookMark (mrl->pretty_name.isEmpty () ? url.prettyURL () : mrl->pretty_name, url.url ());
    }
}

void PlayListView::toggleShowAllNodes () {
    PlayListItem * cur_item = currentPlayListItem ();
    if (cur_item) {
        RootPlayListItem * ritem = rootItem (cur_item);
        showAllNodes (rootItem (cur_item), !ritem->show_all_nodes);
    }
}

KDE_NO_EXPORT void PlayListView::showAllNodes(RootPlayListItem *ri, bool show) {
    if (ri && ri->show_all_nodes != show) {
        PlayListItem * cur_item = currentPlayListItem ();
        ri->show_all_nodes = show;
        updateTree (ri->id, ri->node, cur_item->node, true, false);
        if (m_current_find_elm &&
                ri->node->document() == m_current_find_elm->document() &&
                !ri->show_all_nodes) {
            if (!m_current_find_elm->expose ())
                m_current_find_elm = 0L;
            m_current_find_attr = 0L;
        }
    }
}

KDE_NO_EXPORT bool PlayListView::acceptDrag (TQDropEvent * de) const {
    TQListViewItem * item = itemAt (contentsToViewport (de->pos ()));
    if (item && (de->source () == this || isDragValid (de))) {
        RootPlayListItem * ritem = rootItem (item);
        return ritem->flags & AllowDrops;
    }
    return false;
}

KDE_NO_EXPORT void PlayListView::itemDropped (TQDropEvent * de, TQListViewItem *after) {
    if (!after) { // could still be a descendent
        after = itemAt (contentsToViewport (de->pos ()));
        if (after)
            after = after->parent ();
    }
    if (after) {
        RootPlayListItem * ritem = rootItem (after);
        if (ritem->id > 0)
            return;
        NodePtr n = static_cast <PlayListItem *> (after)->node;
        bool valid = n && (!n->isDocument () || n->hasChildNodes ());
        KURL::List sl;
        if (KURLDrag::canDecode (de)) {
            KURLDrag::decode (de, sl);
        } else if (TQTextDrag::canDecode (de)) {
            TQString text;
            TQTextDrag::decode (de, text);
            sl.push_back (KURL (text));
        }
        if (valid && sl.size () > 0) {
            bool as_child = n->isDocument () || n->hasChildNodes ();
            NodePtr d = n->document ();
            for (int i = sl.size (); i > 0; i--) {
                Node * ni = new KMPlayer::GenericURL (d, sl[i-1].url ());
                if (as_child)
                    n->insertBefore (ni, n->firstChild ());
                else
                    n->parentNode ()->insertBefore (ni, n->nextSibling ());
            }
            PlayListItem * citem = currentPlayListItem ();
            NodePtr cn;
            if (citem)
                cn = citem->node;
            updateTree (ritem, cn, true);
        }
    } else
        m_view->dropEvent (de);
}

KDE_NO_EXPORT void PlayListView::itemIsRenamed (TQListViewItem * qitem) {
    PlayListItem * item = static_cast <PlayListItem *> (qitem);
    if (item->node) {
        RootPlayListItem * ri = rootItem (qitem);
        if (!ri->show_all_nodes && item->node->isEditable ()) {
            item->node->setNodeName (item->text (0));
            if (item->node->mrl ()->pretty_name.isEmpty ())
                item->setText (0, KURL (item->node->mrl ()->src).prettyURL (0, KURL::StripFileProtocol));
        } else // restore damage ..
            updateTree (ri, item->node, true);
    } else if (item->m_attr) {
        TQString txt = item->text (0);
        int pos = txt.find (TQChar ('='));
        if (pos > -1) {
            item->m_attr->setName (txt.left (pos));
            item->m_attr->setValue (txt.mid (pos + 1));
        } else {
            item->m_attr->setName (txt);
            item->m_attr->setValue (TQString (""));
        }
        PlayListItem * pi = static_cast <PlayListItem *> (item->parent ());
        if (pi && pi->node)
            pi->node->document ()->m_tree_version++;
    }
}

KDE_NO_EXPORT void PlayListView::itemIsSelected (TQListViewItem * qitem) {
    RootPlayListItem * ri = rootItem (qitem);
    setItemsRenameable (ri && (ri->flags & TreeEdit) && ri != qitem);
}

KDE_NO_EXPORT void PlayListView::rename (TQListViewItem * qitem, int c) {
    PlayListItem * item = static_cast <PlayListItem *> (qitem);
    if (rootItem (qitem)->show_all_nodes && item && item->m_attr) {
        PlayListItem * pi = static_cast <PlayListItem *> (qitem->parent ());
        if (pi && pi->node && pi->node->isEditable ())
            TDEListView::rename (item, c);
    } else if (item && item->node && item->node->isEditable ()) {
        if (!rootItem (qitem)->show_all_nodes &&
                item->node->isPlayable () &&
                item->node->mrl ()->pretty_name.isEmpty ())
            // populate() has crippled src, restore for editing 
            item->setText (0, item->node->mrl ()->src);
        TDEListView::rename (item, c);
    }
}

KDE_NO_EXPORT void PlayListView::editCurrent () {
    TQListViewItem * qitem = selectedItem ();
    if (qitem) {
        RootPlayListItem * ri = rootItem (qitem);
        if (ri && (ri->flags & TreeEdit) && ri != qitem)
            rename (qitem, 0);
    }
}

KDE_NO_EXPORT void PlayListView::slotFind () {
    m_current_find_elm = 0L;
    if (!m_find_dialog) {
        m_find_dialog = new KFindDialog (false, this, "kde_kmplayer_find", KFindDialog::CaseSensitive);
        m_find_dialog->setHasSelection (false);
        connect(m_find_dialog, TQT_SIGNAL(okClicked ()), this, TQT_SLOT(slotFindOk ()));
    } else
        m_find_dialog->setPattern (TQString ());
    m_find_dialog->show ();
}

static TQListViewItem * findNodeInTree (NodePtr n, TQListViewItem * item) {
    //kdDebug () << "item:" << item->text (0) << " n:" << (n ? n->nodeName () : "null" )  <<endl;
    PlayListItem * pi = static_cast <PlayListItem *> (item);
    if (!n || !pi->node)
        return 0L;
    if (n == pi->node)
        return item;
    for (TQListViewItem * ci = item->firstChild(); ci; ci = ci->nextSibling ()) {
        //kdDebug () << "ci:" << ci->text (0) << " n:" << n->nodeName () <<endl;
        TQListViewItem * vi = findNodeInTree (n, ci);
        if (vi)
            return vi;
    }
    return 0L;
    
}

KDE_NO_EXPORT void PlayListView::slotFindOk () {
    if (!m_find_dialog)
        return;
    m_find_dialog->hide ();
    long opt = m_find_dialog->options ();
    current_find_tree_id = 0;
    if (opt & KFindDialog::FromCursor && currentItem ()) {
        PlayListItem * lvi = currentPlayListItem ();
        if (lvi && lvi->node) {
             m_current_find_elm = lvi->node;
             current_find_tree_id = rootItem (lvi)->id;
        } else if (lvi && lvi->m_attr) {
            PlayListItem*pi=static_cast<PlayListItem*>(currentItem()->parent());
            if (pi) {
                m_current_find_attr = lvi->m_attr;
                m_current_find_elm = pi->node;
            }
        }
    } else if (!(opt & KFindDialog::FindIncremental))
        m_current_find_elm = 0L;
    if (!m_current_find_elm) {
        PlayListItem * lvi = static_cast <PlayListItem *> (firstChild ());
        if (lvi)
            m_current_find_elm = lvi->node;
    }
    if (m_current_find_elm)
        slotFindNext ();
}

/* A bit tricky, but between the find's PlayListItems might be gone, so
 * try to match on the generated tree following the source's document tree
 */
KDE_NO_EXPORT void PlayListView::slotFindNext () {
    if (!m_find_dialog)
        return;
    TQString str = m_find_dialog->pattern();
    if (!m_current_find_elm || str.isEmpty ())
        return;
    long opt = m_find_dialog->options ();
    TQRegExp regexp;
    if (opt & KFindDialog::RegularExpression)
        regexp = str;
    bool cs = (opt & KFindDialog::CaseSensitive);
    bool found = false;
    NodePtr node, n = m_current_find_elm;
    RootPlayListItem * ri = rootItem (current_find_tree_id);
    while (!found && n) {
        if (ri->show_all_nodes || n->expose ()) {
            bool elm = n->isElementNode ();
            TQString val = n->nodeName ();
            if (elm && !ri->show_all_nodes) {
                Mrl * mrl = n->mrl ();
                if (mrl) {
                    if (mrl->pretty_name.isEmpty ()) {
                        if (!mrl->src.isEmpty())
                            val = KURL(mrl->src).prettyURL();
                    } else
                        val = mrl->pretty_name;
                }
            } else if (!elm)
                val = n->nodeValue ();
            if (((opt & KFindDialog::RegularExpression) &&
                    val.find (regexp, 0) > -1) ||
                    (!(opt & KFindDialog::RegularExpression) &&
                     val.find (str, 0, cs) > -1)) {
                node = n;
                m_current_find_attr = 0L;
                found = true;
            } else if (elm && ri->show_all_nodes) {
                for (AttributePtr a = convertNode <Element> (n)->attributes ()->first (); a; a = a->nextSibling ()) {
                    TQString attr = a->name ().toString ();
                    if (((opt & KFindDialog::RegularExpression) &&
                                (attr.find (regexp, 0) || a->value ().find (regexp, 0) > -1)) ||
                                (!(opt & KFindDialog::RegularExpression) &&
                                 (attr.find (str, 0, cs) > -1 || a->value ().find (str, 0, cs) > -1))) {
                        node = n;
                        m_current_find_attr = a;
                        found = true;
                        break;
                    }
                }
            }
        }
        if (n) { //set pointer to next
            if (opt & KFindDialog::FindBackwards) {
                if (n->lastChild ()) {
                    n = n->lastChild ();
                } else if (n->previousSibling ()) {
                    n = n->previousSibling ();
                } else {
                    for (n = n->parentNode (); n; n = n->parentNode ())
                        if (n->previousSibling ()) {
                            n = n->previousSibling ();
                            break;
                        }
                    while (!n && current_find_tree_id > 0) {
                        ri = rootItem (--current_find_tree_id);
                        if (ri)
                            n = ri->node;
                    }
                }
            } else {
                if (n->firstChild ()) {
                    n = n->firstChild ();
                } else if (n->nextSibling ()) {
                    n = n->nextSibling ();
                } else {
                    for (n = n->parentNode (); n; n = n->parentNode ())
                        if (n->nextSibling ()) {
                            n = n->nextSibling ();
                            break;
                        }
                    while (!n) {
                        ri = rootItem (++current_find_tree_id);
                        if (!ri)
                            break;
                        n = ri->node;
                    }
                }
            }
        }
    }
    m_current_find_elm = n;
    kdDebug () << " search for " << str << "=" << (node ? node->nodeName () : "not found") << " next:" << (n ? n->nodeName () : " not found") << endl;
    if (found) {
        TQListViewItem * fc = findNodeInTree (node, ri);
        if (!fc) {
            m_current_find_elm = 0L;
            kdDebug () << "node not found in tree tree:" << ri->id << endl;
        } else {
            setSelected (fc, true);
            if (m_current_find_attr && fc->firstChild () && fc->firstChild ()->firstChild ())
                ensureItemVisible (fc->firstChild ()->firstChild ());
            ensureItemVisible (fc);
        }
    }
    m_find_next->setEnabled (!!m_current_find_elm);
}

#include "playlistview.moc"