/* This file is part of the KDE project * * Copyright (C) 2004 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 as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * 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. * * until boost gets common, a more or less compatable one .. */ #ifndef _KMPLAYER_PLAYLIST_H_ #define _KMPLAYER_PLAYLIST_H_ #include #include #include #include "kmplayer_def.h" #include "kmplayertypes.h" #include "kmplayershared.h" typedef struct _cairo_surface cairo_surface_t; class TQTextStream; namespace KMPlayer { class Document; class Node; class Mrl; class Surface; class ElementPrivate; class RemoteObjectPrivate; class Visitor; /* * Base class for objects that will be used as SharedPtr/WeakPtr pointers. * Item keeps its own copy of the shared SharedData as a weak refence. * \sa: self() */ template class KMPLAYER_EXPORT Item { friend class SharedPtr; friend class WeakPtr; public: typedef SharedPtr SharedType; typedef WeakPtr WeakType; virtual ~Item () {} SharedType self () const { return m_self; } protected: Item (); WeakType m_self; private: Item (const Item &); // forbidden copy constructor }; /** * Because of the m_self member of Item, it's not allowed to assign a * Item* directly to SharedPtr>. Item* will then reside in * two independent SharedData> objects. * So specialize constructor and assignment operators to fetch the * SharedData> from the Item* instead of creating a new one */ #define ITEM_AS_POINTER(CLASS) \ template <> inline SharedPtr::SharedPtr (CLASS * t) \ : data (t ? t->m_self.data : 0L) { \ if (data) \ data->addRef (); \ } \ \ template <> \ inline SharedPtr & SharedPtr::operator = (CLASS * t) { \ if (t) { \ operator = (t->m_self); \ } else if (data) { \ data->release (); \ data = 0L; \ } \ return *this; \ } \ \ template <> inline WeakPtr::WeakPtr (CLASS * t) \ : data (t ? t->m_self.data : 0L) { \ if (data) \ data->addWeakRef (); \ } \ \ template <> \ inline WeakPtr & WeakPtr::operator = (CLASS * t) { \ if (t) { \ operator = (t->m_self); \ } else if (data) { \ data->releaseWeak (); \ data = 0L; \ } \ return *this; \ } /* * A shareable double linked list of ListNodeBase nodes */ template class KMPLAYER_EXPORT List : public Item > { public: List () {} List (typename Item::SharedType f, typename Item::SharedType l) : m_first (f), m_last (l) {} ~List () { clear (); } typename Item::SharedType first () const { return m_first; } typename Item::SharedType last () const { return m_last; } void append (typename Item::SharedType c); void insertBefore(typename Item::SharedType c, typename Item::SharedType b); void remove (typename Item::SharedType c); void clear (); unsigned int length () const; typename Item::SharedType item (int i) const; protected: typename Item::SharedType m_first; typename Item::WeakType m_last; }; /* * Base class for double linked list nodes of SharedPtr/WeakPtr objects. * The linkage is a shared nextSibling and a weak previousSibling. */ template class KMPLAYER_EXPORT ListNodeBase : public Item { friend class List; public: virtual ~ListNodeBase () {} typename Item::SharedType nextSibling () const { return m_next; } typename Item::SharedType previousSibling () const { return m_prev; } protected: ListNodeBase () {} typename Item::SharedType m_next; typename Item::WeakType m_prev; }; /* * ListNode for class T storage */ template class ListNode : public ListNodeBase > { public: ListNode (T d) : data (d) {} T data; }; /* * Base class for double linked tree nodes having parent/siblings/children. * The linkage is a shared firstChild and weak parentNode. */ template class KMPLAYER_EXPORT TreeNode : public ListNodeBase { public: virtual ~TreeNode () {} virtual void appendChild (typename Item::SharedType c); virtual void removeChild (typename Item::SharedType c); bool hasChildNodes () const { return m_first_child != 0L; } typename Item::SharedType parentNode () const { return m_parent; } typename Item::SharedType firstChild () const { return m_first_child; } typename Item::SharedType lastChild () const { return m_last_child; } protected: TreeNode () {} typename Item::WeakType m_parent; typename Item::SharedType m_first_child; typename Item::WeakType m_last_child; }; /** * Attribute having a name/value pair for use with Elements */ class KMPLAYER_EXPORT Attribute : public ListNodeBase { public: KDE_NO_CDTOR_EXPORT Attribute () {} Attribute (const TrieString & n, const TQString & v); KDE_NO_CDTOR_EXPORT ~Attribute () {} TrieString name () const { return m_name; } TQString value () const { return m_value; } void setName (const TrieString &); void setValue (const TQString &); protected: TrieString m_name; TQString m_value; }; ITEM_AS_POINTER(KMPlayer::Attribute) /** * Object should scale according the passed Fit value in SizedEvent */ enum Fit { fit_fill, // fill complete area, no aspect preservation fit_hidden, // keep aspect and don't scale, cut off what doesn't fit fit_meet, // keep aspect and scale so that the smallest size just fits fit_slice, // keep aspect and scale so that the largest size just fits fit_scroll // keep aspect and don't scale, add scollbars if needed }; /* * A generic event type */ class KMPLAYER_EXPORT Event : public Item { public: KDE_NO_CDTOR_EXPORT Event (unsigned int event_id) : m_event_id (event_id) {} KDE_NO_CDTOR_EXPORT virtual ~Event () {} TDE_NO_EXPORT unsigned int id () const { return m_event_id; } protected: unsigned int m_event_id; }; ITEM_AS_POINTER(KMPlayer::Event) extern const unsigned int event_pointer_clicked; extern const unsigned int event_pointer_moved; extern const unsigned int event_inbounds; extern const unsigned int event_outbounds; extern const unsigned int event_sized; extern const unsigned int event_postponed; extern const unsigned int event_timer; extern const unsigned int mediatype_attached; // convenient types typedef Item::SharedType NodePtr; typedef Item::WeakType NodePtrW; typedef Item::SharedType AttributePtr; typedef Item::WeakType AttributePtrW; typedef Item::SharedType EventPtr; typedef List NodeList; // eg. for Node's children typedef Item::SharedType NodeListPtr; typedef Item::WeakType NodeListPtrW; ITEM_AS_POINTER(KMPlayer::NodeList) typedef List AttributeList; // eg. for Element's attributes typedef Item::SharedType AttributeListPtr; ITEM_AS_POINTER(KMPlayer::AttributeList) typedef ListNode NodeRefItem; // Node for ref Nodes ITEM_AS_POINTER(KMPlayer::NodeRefItem) //typedef ListNode NodeStoreItem; // list stores Nodes typedef NodeRefItem::SharedType NodeRefItemPtr; typedef NodeRefItem::WeakType NodeRefItemPtrW; typedef List NodeRefList; // ref nodes, eg. event listeners typedef Item::SharedType NodeRefListPtr; typedef Item::WeakType NodeRefListPtrW; ITEM_AS_POINTER(KMPlayer::NodeRefList) typedef Item::SharedType SurfacePtr; typedef Item::WeakType SurfacePtrW; /* * Weak ref of the listeners list from signaler and the listener node */ class KMPLAYER_EXPORT Connection { friend class Node; public: KDE_NO_CDTOR_EXPORT ~Connection () { disconnect (); } void disconnect (); NodePtrW connectee; // the one that will, when ever, trigger the event private: Connection (NodeRefListPtr ls, NodePtr node, NodePtr invoker); NodeRefListPtrW listeners; NodeRefItemPtrW listen_item; }; typedef SharedPtr ConnectionPtr; /* * Base class for XML nodes. Provides a w3c's DOM like API * * Most severe traps with using SharedPtr/WeakPtr for tree nodes: * - pointer ends up in two independent shared objects (hopefully with * template specialization for constructor for T* and assignment of T* should * be enough of defences ..) * - Node added two times (added ASSERT in appendChild/insertBefore) * - Node is destroyed before being stored in a SharedPtr with kmplayer usage * of each object having a WeakPtr to itself (eg. be extremely careful with * using m_self in the constructor, no SharedPtr storage yet) * * Livetime of an element is |-->state_activated<-->state_began<-->state_finished-->state_deactivated-->| In scope begin event end event Out scope */ class KMPLAYER_EXPORT Node : public TreeNode { friend class DocumentBuilder; public: enum State { state_init, state_deferred, state_activated, state_began, state_finished, state_deactivated }; enum PlayType { play_type_none, play_type_unknown, play_type_info, play_type_image, play_type_audio, play_type_video }; virtual ~Node (); Document * document (); virtual Mrl * mrl (); virtual NodePtr childFromTag (const TQString & tag); void characterData (const TQString & s); TQString innerText () const; TQString innerXML () const; TQString outerXML () const; virtual const char * nodeName () const; virtual TQString nodeValue () const; virtual void setNodeName (const TQString &) {} /** * If this is a derived Mrl object and has a SRC attribute */ virtual PlayType playType (); bool isPlayable () { return playType () > play_type_none; } virtual bool isElementNode () { return false; } /** * If this node should be visible to the user */ virtual bool expose () const; /** * If this node should be visible to the user */ bool isEditable () const { return editable; } /** * If this node purpose is for storing runtime data only, * ie. node doesn't exist in the original document */ bool auxiliaryNode () const { return auxiliary_node; } void setAuxiliaryNode (bool b) { auxiliary_node = b; } /** * Add node as listener for a certain event_id. * Return a NULL ptr if event_id is not supported. * \sa: Connection::disconnect() */ ConnectionPtr connectTo (NodePtr node, unsigned int event_id); /* * Event send to this node, return true if handled */ virtual bool handleEvent (EventPtr event); /* * Dispatch Event to all listeners of event->id() */ void propagateEvent (EventPtr event); /** * Alternative to event handling is the Visitor pattern */ virtual void accept (Visitor *); /* * Returns a listener list for event_id, or a null ptr if not supported. */ virtual NodeRefListPtr listeners (unsigned int event_id); /** * Adds node to call 'handleEvent()' for all events that gets * delivered to this node, ignored by default */ virtual SurfacePtr getSurface (NodePtr node); /** * Activates element, sets state to state_activated. Will call activate() on * firstChild or call deactivate(). */ virtual void activate (); /** * if state is between state_activated and state_deactivated */ bool active () const { return state >= state_deferred && state < state_deactivated; } /** * if state is between state_activated and state_finished */ bool unfinished () const { return state > state_deferred && state < state_finished; } /** * Defers an activated, so possible playlists items can be added. */ virtual void defer (); /** * Puts a deferred element in activated again, calls activate() again */ virtual void undefer (); /** * Sets state to state_begin when active */ virtual void begin (); /** * Sets state to state_finish when >= state_activated. * Notifies parent with a childDone call. */ virtual void finish (); /** * Stops element, sets state to state_deactivated. Calls deactivate() on * activated/deferred children. May call childDone() when active() and not * finished yet. */ virtual void deactivate (); /** * Resets element, calls deactivate() if state is state_activated and sets * state to state_init. */ virtual void reset (); /** * Notification from child that it has began. */ virtual void childBegan (NodePtr child); /** * Notification from child that it's finished. Will call deactivate() on * child if it state is state_finished. Call activate() on nexSibling * or deactivate() if there is none. */ virtual void childDone (NodePtr child); virtual void clear (); void clearChildren (); void appendChild (NodePtr c); void insertBefore (NodePtr c, NodePtr b); void removeChild (NodePtr c); void replaceChild (NodePtr _new, NodePtr old); /* * Get rid of whitespace only text nodes */ void normalize (); TDE_NO_EXPORT bool isDocument () const { return m_doc == m_self; } TDE_NO_EXPORT NodeListPtr childNodes () const; void setState (State nstate); /* * Open tag is found by parser, attributes are set */ virtual void opened (); /* * Close tag is found by parser, children are appended */ virtual void closed (); protected: Node (NodePtr & d, short _id=0); NodePtr m_doc; public: State state; short id; private: bool auxiliary_node; protected: bool editable; }; ITEM_AS_POINTER(KMPlayer::Node) const short id_node_document = 1; const short id_node_text = 5; const short id_node_cdata = 6; const short id_node_group_node = 25; const short id_node_playlist_document = 26; const short id_node_playlist_item = 27; const short id_node_param = 28; const short id_node_html_object = 29; const short id_node_html_embed = 30; /* * Element node, XML node that can have attributes */ class KMPLAYER_EXPORT Element : public Node { public: ~Element (); void setAttributes (AttributeListPtr attrs); void setAttribute (const TrieString & name, const TQString & value); TQString getAttribute (const TrieString & name); TDE_NO_EXPORT AttributeListPtr attributes () const { return m_attributes; } virtual void init (); virtual void reset (); virtual void clear (); virtual bool isElementNode () { return true; } /** * Params are like attributes, but meant to be set dynamically. Caller may * pass a modification id, that it can use to restore the old value. * Param will be auto removed on deactivate */ void setParam (const TrieString ¶, const TQString &val, int * mod_id=0L); TQString param (const TrieString & para); void resetParam (const TrieString & para, int mod_id); /** * Called from (re)setParam for specialized interpretation of params **/ virtual void parseParam (const TrieString &, const TQString &) {} protected: Element (NodePtr & d, short id=0); AttributeListPtr m_attributes; private: ElementPrivate * d; }; /** * Node that references another node */ class RefNode : public Node { public: RefNode (NodePtr & d, NodePtr ref); virtual const char * nodeName () const { return tag_name.ascii (); } NodePtr refNode () const { return ref_node; } void setRefNode (const NodePtr ref); protected: NodePtrW ref_node; TQString tag_name; }; template inline TDE_NO_EXPORT T * convertNode (NodePtr e) { return static_cast (e.ptr ()); } /** * Element representing a playable link, like URL to a movie or playlist. */ class KMPLAYER_EXPORT Mrl : public Element { protected: Mrl (NodePtr & d, short id=0); NodePtr childFromTag (const TQString & tag); void parseParam (const TrieString &, const TQString &); unsigned int cached_ismrl_version; PlayType cached_play_type; public: ~Mrl (); PlayType playType (); /* * The original node (or this) having the URL, needed for playlist expansion */ virtual Mrl * linkNode (); virtual Mrl * mrl (); virtual void endOfFile (); TQString absolutePath (); /* * Reimplement to callback with requestPlayURL if isPlayable() */ virtual void activate (); virtual void begin (); /** * By default support one event handler (eg. SMIL or RP child document) */ virtual SurfacePtr getSurface (NodePtr node); virtual bool handleEvent (EventPtr event); /** * If this Mrl is top node of external document, opener has the * location in SCR. Typically that's the parent of this node. */ NodePtrW opener; //if this node is top node of external document, TQString src; TQString pretty_name; TQString mimetype; Single width; Single height; float aspect; int repeat; enum { SingleMode = 0, WindowMode } view_mode; bool resolved; bool bookmarkable; }; /** * Document listener interface */ class KMPLAYER_EXPORT PlayListNotify { public: virtual ~PlayListNotify () {} /** * Ask for playing a video/audio mrl by backend players * If returning false, the element will be set to finished */ virtual bool requestPlayURL (NodePtr mrl) = 0; /** * Called by an unresolved Mrl, check if this node points to a playlist */ virtual bool resolveURL (NodePtr mrl) = 0; /** * Element has activated or deactivated notification */ virtual void stateElementChanged (Node * element, Node::State old_state, Node::State new_state) = 0; /** * Set element to which to send GUI events and return a surface for drawing */ virtual SurfacePtr getSurface (NodePtr node) = 0; /** * Request to show msg for informing the user */ virtual void setInfoMessage (const TQString & msg) = 0; /** * Ask for connection bitrates settings */ virtual void bitRates (int & preferred, int & maximal) = 0; /** * Sets next call to Document::timer() or -1 to cancel a previous call */ virtual void setTimeout (int ms) = 0; }; /** * Base class for cached network data */ class KMPLAYER_NO_EXPORT RemoteObject { friend class RemoteObjectPrivate; public: RemoteObject (); virtual ~RemoteObject (); bool wget (const TQString & url); void killWGet (); void clear (); TQString mimetype (); protected: TDE_NO_EXPORT virtual void remoteReady (TQByteArray &) {} bool downloading () const; private: RemoteObjectPrivate *d; }; class KMPLAYER_NO_EXPORT Surface : public TreeNode { public: Surface (NodePtr node, const SRect & rect); ~Surface(); virtual SurfacePtr createSurface (NodePtr owner, const SRect & rect) = 0; virtual IRect toScreen (Single x, Single y, Single w, Single h) = 0; virtual void resize (const SRect & rect) = 0; virtual void repaint () = 0; virtual void repaint (const SRect &rect) = 0; virtual void video () = 0; void remove (); // remove from parent, mark ancestors dirty void markDirty (); // mark this and ancestors dirty NodePtrW node; SRect bounds; // bounds in in parent coord. float xscale, yscale; // internal scaling unsigned int background_color; // rgba background color bool dirty; // a decendant is removed #ifdef HAVE_CAIRO cairo_surface_t *surface; #endif }; ITEM_AS_POINTER(KMPlayer::Surface) /** * To have a somewhat synchronized time base, node having timers should use * this. Idea is that if a node still waiting for network data, it can hold * this time line. */ class KMPLAYER_NO_EXPORT TimerInfo : public ListNodeBase { public: TimerInfo (NodePtr n, unsigned id, struct timeval & now, int ms); KDE_NO_CDTOR_EXPORT ~TimerInfo () {} NodePtrW node; unsigned event_id; struct timeval timeout; int milli_sec; }; ITEM_AS_POINTER(KMPlayer::TimerInfo) typedef Item ::SharedType TimerInfoPtr; typedef Item ::WeakType TimerInfoPtrW; /** * Event signaling a timer event */ class KMPLAYER_NO_EXPORT TimerEvent : public Event { public: TimerEvent (TimerInfoPtr tinfo); TimerInfoPtrW timer_info; bool interval; // set to 'true' in 'Node::handleEvent()' to make it repeat }; /** * Event signaling postponed or proceeded */ class KMPLAYER_NO_EXPORT PostponedEvent : public Event { public: PostponedEvent (bool postponed); bool is_postponed; // postponed or proceeded }; /** * Postpone object representing a postponed document * During its livetime, no TimerEvent's happen */ class KMPLAYER_NO_EXPORT Postpone { friend class Document; struct timeval postponed_time; NodePtrW m_doc; Postpone (NodePtr doc); public: ~Postpone (); }; typedef SharedPtr PostponePtr; typedef WeakPtr PostponePtrW; /** * The root of the DOM tree */ class KMPLAYER_EXPORT Document : public Mrl { friend class Postpone; public: Document (const TQString &, PlayListNotify * notify = 0L); ~Document (); NodePtr getElementById (const TQString & id); NodePtr getElementById (NodePtr start, const TQString & id, bool inter_doc); /** All nodes have shared pointers to Document, * so explicitly dispose it (calls clear and set m_doc to 0L) * */ void dispose (); virtual NodePtr childFromTag (const TQString & tag); TDE_NO_EXPORT const char * nodeName () const { return "document"; } virtual void activate (); virtual void defer (); virtual void undefer (); virtual void reset (); /** * Ask for TimerEvent for Node n in ms milli-seconds. * Returns weak ref to TimerInfo ptr, which is an item in the timers list */ TimerInfoPtrW setTimeout (NodePtr n, int ms, unsigned id=0); void cancelTimer (TimerInfoPtr ti); void timeOfDay (struct timeval &); PostponePtr postpone (); /** * Called by PlayListNotify, creates TimerEvent on first item in timers. * Returns true if to repeat this same timeout FIXME. */ bool timer (); /** * Document has list of postponed listeners, eg. for running (gif)movies */ virtual NodeRefListPtr listeners (unsigned int event_id); /** * Reimplement, so it will call PlayListNotify::getSurface() */ virtual SurfacePtr getSurface (NodePtr node); List timers; //FIXME: make as connections PlayListNotify * notify_listener; unsigned int m_tree_version; unsigned int last_event_time; private: void proceed (const struct timeval & postponed_time); PostponePtrW postpone_ref; PostponePtr postpone_lock; NodeRefListPtr m_PostponedListeners; int cur_timeout; struct timeval first_event_time; bool intimer; }; /** * Represents XML text, like "some text" in 'some text' */ class KMPLAYER_EXPORT TextNode : public Node { public: TextNode (NodePtr & d, const TQString & s, short _id = id_node_text); KDE_NO_CDTOR_EXPORT ~TextNode () {} void appendText (const TQString & s); void setText (const TQString & txt) { text = txt; } const char * nodeName () const { return "#text"; } TQString nodeValue () const; bool expose () const; protected: TQString text; }; /** * Represents cdata sections, like "some text" in '' */ class KMPLAYER_EXPORT CData : public TextNode { public: CData (NodePtr & d, const TQString & s); KDE_NO_CDTOR_EXPORT ~CData () {} const char * nodeName () const { return "#cdata"; } }; /** * Unrecognized tag by parent element or just some auxiliary node */ class KMPLAYER_EXPORT DarkNode : public Element { public: DarkNode (NodePtr & d, const TQString & n, short id=0); KDE_NO_CDTOR_EXPORT ~DarkNode () {} const char * nodeName () const { return name.ascii (); } NodePtr childFromTag (const TQString & tag); virtual bool expose () const; protected: TQString name; }; namespace SMIL { class RegionBase; class Region; class Layout; class Transition; class MediaType; class ImageMediaType; class TextMediaType; class RefMediaType; class AVMediaType; class Brush; class TimedMrl; class Anchor; class Area; } namespace RP { class Imfl; class Crossfade; class Fadein; class Fadeout; class Fill; class Wipe; class ViewChange; class Animate; } class KMPLAYER_NO_EXPORT Visitor { public: KDE_NO_CDTOR_EXPORT Visitor () {} KDE_NO_CDTOR_EXPORT virtual ~Visitor () {} virtual void visit (Node *) {} virtual void visit (SMIL::Region *); virtual void visit (SMIL::Layout *); virtual void visit (SMIL::Transition *); virtual void visit (SMIL::TimedMrl *); virtual void visit (SMIL::MediaType *); virtual void visit (SMIL::ImageMediaType *); virtual void visit (SMIL::TextMediaType *); virtual void visit (SMIL::RefMediaType *); virtual void visit (SMIL::AVMediaType *); virtual void visit (SMIL::Brush *); virtual void visit (SMIL::Anchor *); virtual void visit (SMIL::Area *); virtual void visit (RP::Imfl *) {} virtual void visit (RP::Crossfade *) {} virtual void visit (RP::Fadein *) {} virtual void visit (RP::Fadeout *) {} virtual void visit (RP::Fill *) {} virtual void visit (RP::Wipe *) {} virtual void visit (RP::ViewChange *) {} virtual void visit (RP::Animate *) {} }; //----------------------------------------------------------------------------- /** * just some url, can get a SMIL, RSS, or ASX childtree */ class KMPLAYER_EXPORT GenericURL : public Mrl { public: GenericURL(NodePtr &d, const TQString &s, const TQString &n=TQString ()); TDE_NO_EXPORT const char * nodeName () const { return "url"; } void closed (); }; /** * Non url mrl */ class KMPLAYER_EXPORT GenericMrl : public Mrl { public: KDE_NO_CDTOR_EXPORT GenericMrl (NodePtr & d) : Mrl (d), node_name ("mrl") {} GenericMrl(NodePtr &d, const TQString &s, const TQString & name=TQString (), const TQString &tag=TQString ("mrl")); TDE_NO_EXPORT const char * nodeName () const { return node_name.ascii (); } void closed (); bool expose () const; TQString node_name; }; KMPLAYER_EXPORT void readXML (NodePtr root, TQTextStream & in, const TQString & firstline, bool set_opener=true); KMPLAYER_EXPORT Node * fromXMLDocumentTag (NodePtr & d, const TQString & tag); template inline Item::Item () : m_self (static_cast (this), true) {} template inline void List::append(typename Item::SharedType c) { if (!m_first) { m_first = m_last = c; } else { m_last->m_next = c; c->m_prev = m_last; m_last = c; } } template inline void List::insertBefore(typename Item::SharedType c, typename Item::SharedType b) { if (!b) { append (c); } else { if (b->m_prev) { b->m_prev->m_next = c; c->m_prev = b->m_prev; } else { c->m_prev = 0L; m_first = c; } b->m_prev = c; c->m_next = b; } } template inline void List::remove(typename Item::SharedType c) { if (c->m_prev) { c->m_prev->m_next = c->m_next; } else m_first = c->m_next; if (c->m_next) { c->m_next->m_prev = c->m_prev; c->m_next = 0L; } else m_last = c->m_prev; c->m_prev = 0L; } template inline unsigned int List::length () const { unsigned int count = 0; for (typename Item::SharedType t = m_first; t; t = t->nextSibling ()) count++; return count; } template inline void List::clear () { m_first = m_last = 0L; } template inline typename Item::SharedType List::item (int i) const { for (typename Item::SharedType t = m_first; t; t = t->nextSibling(), --i) if (i == 0) return t; return typename Item::SharedType (); } template inline void TreeNode::appendChild (typename Item::SharedType c) { if (!m_first_child) { m_first_child = m_last_child = c; } else { m_last_child->m_next = c; c->m_prev = m_last_child; m_last_child = c; } c->m_parent = Item::m_self; } template inline void TreeNode::removeChild (typename Item::SharedType c) { if (c->m_prev) { c->m_prev->m_next = c->m_next; } else m_first_child = c->m_next; if (c->m_next) { c->m_next->m_prev = c->m_prev; c->m_next = 0L; } else m_last_child = c->m_prev; c->m_prev = 0L; c->m_parent = 0L; } inline TDE_NO_EXPORT NodeListPtr Node::childNodes () const { return new NodeList (m_first_child, m_last_child); } } // KMPlayer namespace #endif //_KMPLAYER_PLAYLIST_H_