/** * Copyright (C) 2006 by Koos Vriezen * * 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 #include // include files for TQt #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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->tqtopLevelWidget()->paletteBackgroundColor()); mycg.setColor (TQColorGroup::Highlight, mycg.base ()); mycg.setColor (TQColorGroup::Text, listview->tqtopLevelWidget()->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 * tqparent, View * view, KActionCollection * ac) : KListView (tqparent, "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 = KGlobal::iconLoader ()->loadIcon (TQString ("folder"), KIcon::Small); auxiliary_pix = KGlobal::iconLoader ()->loadIcon (TQString ("folder_grey"), KIcon::Small); video_pix = KGlobal::iconLoader ()->loadIcon (TQString ("video"), KIcon::Small); info_pix = KGlobal::iconLoader ()->loadIcon (TQString ("messagebox_info"), KIcon::Small); img_pix = KGlobal::iconLoader ()->loadIcon (TQString ("colorize"), KIcon::Small); unknown_pix = KGlobal::iconLoader ()->loadIcon (TQString ("unknown"), KIcon::Small); menu_pix = KGlobal::iconLoader ()->loadIcon (TQString ("player_playlist"), KIcon::Small); config_pix = KGlobal::iconLoader ()->loadIcon (TQString ("configure"), KIcon::Small); url_pix = KGlobal::iconLoader ()->loadIcon (TQString ("www"), KIcon::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 () ? KGlobal::iconLoader ()->loadIcon (ritem->icon, KIcon::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 (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 = tqfocusWidget (); if (w && w != this) w->clearFocus (); //setSelected (firstChild (), true); RootPlayListItem * ritem = static_cast (firstChild ()); RootPlayListItem * before = 0L; for (; ritem; ritem =static_cast(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 (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 ()); KListView::setFont (fnt); } KDE_NO_EXPORT void PlayListView::contextMenuItem (TQListViewItem * vi, const TQPoint & p, int) { if (vi) { PlayListItem * item = static_cast (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 (KGlobal::iconLoader ()->loadIconSet (TQString ("editcopy"), KIcon::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 (KGlobal::iconLoader ()->loadIconSet (TQString ("bookmark_add"), KIcon::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(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->tqparent ()) item = item->tqparent (); return static_cast (item); } RootPlayListItem * PlayListView::rootItem (int id) const { RootPlayListItem * ri = static_cast (firstChild ()); for (; ri; ri = static_cast (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::tqclipboard()->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->tqparent (); } if (after) { RootPlayListItem * ritem = rootItem (after); if (ritem->id > 0) return; NodePtr n = static_cast (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 (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 (item->tqparent ()); 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 (qitem); if (rootItem (qitem)->show_all_nodes && item && item->m_attr) { PlayListItem * pi = static_cast (qitem->tqparent ()); if (pi && pi->node && pi->node->isEditable ()) KListView::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); KListView::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" ) < (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 () <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(currentItem()->tqparent()); 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 (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 (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"