summaryrefslogtreecommitdiffstats
path: root/src/kmplayerplaylist.h
blob: 3371e70b87679d806d2977a0903af8e7f2762f58 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
/* This file is part of the KDE project
 *
 * Copyright (C) 2004 Koos Vriezen <[email protected]>
 *
 * 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 <config.h>
#include <sys/time.h>

#include <tqstring.h>

#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<T> keeps its own copy of the shared SharedData<T> as a weak refence.
 * \sa: self()
 */
template <class T>
class KMPLAYER_EXPORT Item {
    friend class SharedPtr<T>;
    friend class WeakPtr<T>;
public:
    typedef SharedPtr <T> SharedType;
    typedef WeakPtr <T> WeakType;

    virtual ~Item () {}

    SharedType self () const { return m_self; }
protected:
    Item ();
    WeakType m_self;
private:
    Item (const Item <T> &); // forbidden copy constructor
};

/**
 * Because of the m_self member of Item<T>, it's not allowed to assign a
 * Item<T>* directly to SharedPtr<Item<T>>. Item<T>* will then reside in
 * two independent SharedData<Item<T>> objects.
 * So specialize constructor and assignment operators to fetch the 
 * SharedData<Item<T>> from the Item<T>* instead of creating a new one
 */
#define ITEM_AS_POINTER(CLASS)                                         \
 template <> inline SharedPtr<CLASS>::SharedPtr (CLASS * t)            \
 : data (t ? t->m_self.data : 0L) {                                    \
    if (data)                                                          \
        data->addRef ();                                               \
 }                                                                     \
                                                                       \
 template <>                                                           \
 inline SharedPtr<CLASS> & SharedPtr<CLASS>::operator = (CLASS * t) {  \
    if (t) {                                                           \
        operator = (t->m_self);                                        \
    } else if (data) {                                                 \
        data->release ();                                              \
        data = 0L;                                                     \
    }                                                                  \
    return *this;                                                      \
 }                                                                     \
                                                                       \
 template <> inline WeakPtr<CLASS>::WeakPtr (CLASS * t)                \
 : data (t ? t->m_self.data : 0L) {                                    \
    if (data)                                                          \
        data->addWeakRef ();                                           \
 }                                                                     \
                                                                       \
 template <>                                                           \
 inline WeakPtr<CLASS> & WeakPtr<CLASS>::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<T> nodes
 */
template <class T>
class KMPLAYER_EXPORT List : public Item <List <T> > {
public:
    List () {}
    List (typename Item<T>::SharedType f, typename Item<T>::SharedType l) 
        : m_first (f), m_last (l) {}
    ~List () { clear (); }

    typename Item<T>::SharedType first () const { return m_first; }
    typename Item<T>::SharedType last () const { return m_last; }
    void append (typename Item<T>::SharedType c);
    void insertBefore(typename Item<T>::SharedType c, typename Item<T>::SharedType b);
    void remove (typename Item<T>::SharedType c);
    void clear ();
    unsigned int length () const;
    typename Item<T>::SharedType item (int i) const;
protected:
    typename Item<T>::SharedType m_first;
    typename Item<T>::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 T>
class KMPLAYER_EXPORT ListNodeBase : public Item <T> {
    friend class List<T>;
public:
    virtual ~ListNodeBase () {}

    typename Item<T>::SharedType nextSibling () const { return m_next; }
    typename Item<T>::SharedType previousSibling () const { return m_prev; }
protected:
    ListNodeBase () {}
    typename Item<T>::SharedType m_next;
    typename Item<T>::WeakType m_prev;
};

/*
 * ListNode for class T storage
 */
template <class T>
class ListNode : public ListNodeBase <ListNode <T> > {
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 T>
class KMPLAYER_EXPORT TreeNode : public ListNodeBase <T> {
public:
    virtual ~TreeNode () {}

    virtual void appendChild (typename Item<T>::SharedType c);
    virtual void removeChild (typename Item<T>::SharedType c);

    bool hasChildNodes () const { return m_first_child != 0L; }
    typename Item<T>::SharedType parentNode () const { return m_parent; }
    typename Item<T>::SharedType firstChild () const { return m_first_child; }
    typename Item<T>::SharedType lastChild () const { return m_last_child; }

protected:
    TreeNode () {}
    typename Item<T>::WeakType m_parent;
    typename Item<T>::SharedType m_first_child;
    typename Item<T>::WeakType m_last_child;
};

/**
 * Attribute having a name/value pair for use with Elements
 */
class KMPLAYER_EXPORT Attribute : public ListNodeBase <Attribute> {
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 <Event> {
public:
    KDE_NO_CDTOR_EXPORT Event (unsigned int event_id) : m_event_id (event_id) {}
    KDE_NO_CDTOR_EXPORT virtual ~Event () {}
    KDE_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<Node>::SharedType NodePtr;
typedef Item<Node>::WeakType NodePtrW;
typedef Item<Attribute>::SharedType AttributePtr;
typedef Item<Attribute>::WeakType AttributePtrW;
typedef Item<Event>::SharedType EventPtr;
typedef List<Node> NodeList;                 // eg. for Node's children
typedef Item<NodeList>::SharedType NodeListPtr;
typedef Item<NodeList>::WeakType NodeListPtrW;
ITEM_AS_POINTER(KMPlayer::NodeList)
typedef List<Attribute> AttributeList;       // eg. for Element's attributes
typedef Item<AttributeList>::SharedType AttributeListPtr;
ITEM_AS_POINTER(KMPlayer::AttributeList)
typedef ListNode<NodePtrW> NodeRefItem;      // Node for ref Nodes
ITEM_AS_POINTER(KMPlayer::NodeRefItem)
//typedef ListNode<NodePtr> NodeStoreItem;   // list stores Nodes
typedef NodeRefItem::SharedType NodeRefItemPtr;
typedef NodeRefItem::WeakType NodeRefItemPtrW;
typedef List<NodeRefItem> NodeRefList;       // ref nodes, eg. event listeners
typedef Item<NodeRefList>::SharedType NodeRefListPtr;
typedef Item<NodeRefList>::WeakType NodeRefListPtrW;
ITEM_AS_POINTER(KMPlayer::NodeRefList)
typedef Item<Surface>::SharedType SurfacePtr;
typedef Item<Surface>::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 <Connection> 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 <Node> {
    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 ();
    KDE_NO_EXPORT bool isDocument () const { return m_doc == m_self; }

    KDE_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);
    KDE_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 &para, 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 <class T>
inline KDE_NO_EXPORT T * convertNode (NodePtr e) {
    return static_cast <T *> (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:
    KDE_NO_EXPORT virtual void remoteReady (TQByteArray &) {}
    bool downloading () const;
private:
    RemoteObjectPrivate *d;
};

class KMPLAYER_NO_EXPORT Surface : public TreeNode <Surface> {
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 <TimerInfo> {
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 <TimerInfo>::SharedType TimerInfoPtr;
typedef Item <TimerInfo>::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 <Postpone> PostponePtr;
typedef WeakPtr <Postpone> 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);
    KDE_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 <TimerInfo> 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 '<foo>some text</foo>'
 */
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 '<![CDATA[some text]]>'
 */
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 ());
    KDE_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"));
    KDE_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 <class T>
inline Item<T>::Item () : m_self (static_cast <T*> (this), true) {}

template <class T> inline void List<T>::append(typename Item<T>::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 <class T> inline void List<T>::insertBefore(typename Item<T>::SharedType c, typename Item<T>::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 <class T> inline void List<T>::remove(typename Item<T>::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 <class T> inline unsigned int List<T>::length () const {
    unsigned int count = 0;
    for (typename Item<T>::SharedType t = m_first; t; t = t->nextSibling ())
        count++;
    return count;
}

template <class T> inline void List<T>::clear () {
    m_first = m_last = 0L;
}

template <class T>
inline typename Item<T>::SharedType List<T>::item (int i) const {
    for (typename Item<T>::SharedType t = m_first; t; t = t->nextSibling(), --i)
        if (i == 0)
            return t;
    return typename Item<T>::SharedType ();
}

template <class T>
inline void TreeNode<T>::appendChild (typename Item<T>::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<T>::m_self;
}

template <class T>
inline void TreeNode<T>::removeChild (typename Item<T>::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 KDE_NO_EXPORT NodeListPtr Node::childNodes () const {
    return new NodeList (m_first_child, m_last_child);
}

}  // KMPlayer namespace

#endif //_KMPLAYER_PLAYLIST_H_