summaryrefslogtreecommitdiffstats
path: root/khtml/xml/dom_nodeimpl.h
blob: 275452d69e8f2ade3be3b5a728bac5153d437c60 (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
/*
 * This file is part of the DOM implementation for KDE.
 *
 * Copyright (C) 1999 Lars Knoll ([email protected])
 *           (C) 1999 Antti Koivisto ([email protected])
 *           (C) 2001 Dirk Mueller ([email protected])
 *           (C) 2003 Apple Computer, Inc.
 *
 * 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 Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 */
#ifndef _DOM_NodeImpl_h_
#define _DOM_NodeImpl_h_

#include "dom/dom_misc.h"
#include "dom/dom_string.h"
#include "dom/dom_node.h"
#include "misc/helper.h"
#include "misc/shared.h"

// The namespace used for XHTML elements
#define XHTML_NAMESPACE "http://www.w3.org/1999/xhtml"

class TQPainter;
template <class type> class TQPtrList;
template <class type> class TQValueList;
class KHTMLView;
class TQRect;
class TQMouseEvent;
class TQKeyEvent;
class TQTextStream;

namespace khtml {
    class RenderStyle;
    class RenderObject;
    class RenderArena;
}

namespace DOM {

class NodeListImpl;
class NamedNodeMapImpl;
class DocumentImpl;
class CSSStyleDeclarationImpl;
class RegisteredEventListener;
class EventImpl;

struct RegisteredListenerList {
    RegisteredListenerList() : listeners(0)
    {}

    ~RegisteredListenerList();

    void addEventListener(int id, EventListener *listener, const bool useCapture);
    void removeEventListener(int id, EventListener *listener, bool useCapture);

    void setHTMLEventListener(int id, EventListener *listener);
    EventListener *getHTMLEventListener(int id);

    bool hasEventListener(int id);
    void clear();

    //### KDE4: should disappear
    bool stillContainsListener(const RegisteredEventListener& listener);

    TQValueList<RegisteredEventListener>* listeners;//The actual listener list - may be 0
private:
    bool isHTMLEventListener(EventListener* listener);
};


// this class implements nodes, which can have a parent but no children:
#define NodeImpl_IdNSMask    0xffff0000
#define NodeImpl_IdLocalMask 0x0000ffff

const TQ_UINT16 defaultNamespace = 0;
const TQ_UINT16 xhtmlNamespace = 1;
const TQ_UINT16 emptyNamespace = 2;
const TQ_UINT16 anyNamespace = 0xffff;
const TQ_UINT16 anyLocalName = 0xffff;

inline TQ_UINT16 localNamePart(TQ_UINT32 id) { return id & NodeImpl_IdLocalMask; }
inline TQ_UINT16 namespacePart(TQ_UINT32 id) { return (((unsigned int)id) & NodeImpl_IdNSMask) >> 16; }
inline TQ_UINT32 makeId(TQ_UINT16 n, TQ_UINT16 l) { return (n << 16) | l; }

const TQ_UINT32 anyQName = makeId(anyNamespace, anyLocalName);

class NodeImpl : public khtml::TreeShared<NodeImpl>
{
    friend class DocumentImpl;
public:
    NodeImpl(DocumentImpl *doc);
    virtual ~NodeImpl();

    // DOM methods & attributes for Node
    virtual DOMString nodeName() const;
    virtual DOMString nodeValue() const;
    virtual void setNodeValue( const DOMString &_nodeValue, int &exceptioncode );
    virtual unsigned short nodeType() const;
    NodeImpl *parentNode() const { return m_parent; }
    NodeImpl *previousSibling() const { return m_previous; }
    NodeImpl *nextSibling() const { return m_next; }
    virtual NodeListImpl *childNodes();
    virtual NodeImpl *firstChild() const;
    virtual NodeImpl *lastChild() const;
    // insertBefore, replaceChild and appendChild also close newChild
    // unlike the speed optimized addChild (which is used by the parser)
    virtual NodeImpl *insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode );
    
    /* These two methods may delete the old node, so make sure to reference it if you need it */
    virtual void replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode );
    virtual void removeChild ( NodeImpl *oldChild, int &exceptioncode );
    virtual NodeImpl *appendChild ( NodeImpl *newChild, int &exceptioncode );
    virtual bool hasChildNodes (  ) const;
    virtual NodeImpl *cloneNode ( bool deep ) = 0;
    virtual DOMString localName() const;
    virtual DOMString prefix() const;
    virtual DOMString namespaceURI() const;
    virtual void setPrefix(const DOMString &_prefix, int &exceptioncode );
    void normalize ();

    // Other methods (not part of DOM)
    virtual bool isElementNode() const { return false; }
    virtual bool isHTMLElement() const { return false; }
    virtual bool isAttributeNode() const { return false; }
    virtual bool isTextNode() const { return false; }
    virtual bool isDocumentNode() const { return false; }
    virtual bool isXMLElementNode() const { return false; }
    virtual bool isGenericFormElement() const { return false; }
    virtual bool containsOnlyWhitespace() const { return false; }
    virtual bool contentEditable() const;

    // helper functions not being part of the DOM
    // Attention: they assume that the caller did the consistency checking!
    void setPreviousSibling(NodeImpl *previous) { m_previous = previous; }
    void setNextSibling(NodeImpl *next) { m_next = next; }

    virtual void setFirstChild(NodeImpl *child);
    virtual void setLastChild(NodeImpl *child);

    // used by the parser. Doesn't do as many error checkings as
    // appendChild(), and returns the node into which will be parsed next.
    virtual NodeImpl *addChild(NodeImpl *newChild);

    typedef TQ_UINT32 Id;
    // id() is used to easily and exactly identify a node. It
    // is optimized for quick comparison and low memory consumption.
    // its value depends on the owner document of the node and is
    // categorized in the following way:
    // 1..ID_LAST_TAG: the node inherits HTMLElementImpl and is
    //                 part of the HTML namespace.
    //                 The HTML namespace is either the global
    //                 one (no namespace) or the XHTML namespace
    //                 depending on the owner document's doctype
    // ID_LAST_TAG+1..0xffff: non-HTML elements in the global namespace
    // others       non-HTML elements in a namespace.
    //                 the upper 16 bit identify the namespace
    //                 the lower 16 bit identify the local part of the
    //                 qualified element name.
    virtual Id id() const { return 0; }

    // These are the DOM 3 Core answer to innerText/setInnerText, and are used
    // quite a bit since Mozilla doesn't do innerText. They do, however, behave slightly 
    // differently. The default implementation is for ELEMENT_NODE, ATTRIBUTE_NODE, 
    // ENTITY_NODE, ENTITY_REFERENCE_NODE, DOCUMENT_FRAGMENT_NODE. 
    virtual DOMStringImpl* textContent() const;
    virtual void           setTextContent( const DOMString &text, int& exceptioncode ) = 0;

    enum IdType {
        AttributeId,
        ElementId,
        NamespaceId
    };

    enum MouseEventType {
        MousePress,
        MouseRelease,
        MouseClick,
        MouseDblClick,
        MouseMove
    };

    struct MouseEvent
    {
        MouseEvent( int _button, MouseEventType _type,
                    const DOMString &_url = DOMString(), const DOMString& _target = DOMString(),
                    NodeImpl *_innerNode = 0, NodeImpl *_innerNonSharedNode = 0)
            {
                button = _button; type = _type;
                url = _url; target = _target;
                innerNode = _innerNode;
		innerNonSharedNode = _innerNonSharedNode;
            }

        int button;
        MouseEventType type;
        DOMString url; // url under mouse or empty
        DOMString target;
        Node innerNode;
	Node innerNonSharedNode;
    };

    // for LINK and STYLE
    virtual void sheetLoaded() {}

    bool hasID() const      { return m_hasId; }
    bool hasClass() const   { return m_hasClass; }
    bool active() const     { return m_active; }
    bool focused() const    { return m_focused; }
    bool hovered() const    { return m_hovered; }
    bool attached() const   { return m_attached; }
    bool closed() const     { return m_closed; }
    bool changed() const    { return m_changed; }
    bool hasChangedChild() const { return m_hasChangedChild; }
    bool hasAnchor() const { return m_hasAnchor; }
    bool inDocument() const { return m_inDocument; }
    bool implicitNode() const { return m_implicit; }
    bool htmlCompat() const { return m_htmlCompat; }
    void setHasID(bool b=true) { m_hasId = b; }
    void setHasClass(bool b=true) { m_hasClass = b; }
    void setHasChangedChild( bool b = true ) { m_hasChangedChild = b; }
    void setInDocument(bool b=true) { m_inDocument = b; }
    void setHTMLCompat(bool b) { m_htmlCompat = b; }
    virtual void setFocus(bool b=true) { m_focused = b; }
    virtual void setActive(bool b=true) { m_active = b; }
    virtual void setHovered(bool b=true) { m_hovered = b; }
    virtual void setChanged(bool b=true);

    // for descending restyle when ID or CLASS changes
    bool changedAscendentAttribute() const { return m_changedAscendentAttribute; }
    void setChangedAscendentAttribute(bool b) { m_changedAscendentAttribute = b; }

    // for style selection performance: whether the element matches several CSS Classes
    bool hasClassList() const { return m_hasClassList; }
    void setHasClassList(bool b) { m_hasClassList = b; }

    unsigned short tabIndex() const { return m_tabIndex; }
    void setTabIndex(unsigned short _tabIndex) { m_tabIndex = _tabIndex; }

    virtual bool isFocusable() const { return false; }
    virtual bool isMouseFocusable() const { return isFocusable(); }
    virtual bool isTabFocusable() const { return isFocusable(); }

    virtual bool isInline() const;

    virtual void getCaret(int offset, bool override, int &_x, int &_y, int &width, int &height);
    virtual TQRect getRect() const;

    enum StyleChange { NoChange, NoInherit, Inherit, Detach, Force };
    virtual void recalcStyle( StyleChange = NoChange ) {}
    static StyleChange diff( khtml::RenderStyle *s1, khtml::RenderStyle *s2 );
    static bool pseudoDiff( khtml::RenderStyle *s1, khtml::RenderStyle *s2, unsigned int pid);

    unsigned long nodeIndex() const;
    // Returns the document that this node is associated with. This is guaranteed to always be non-null, as opposed to
    // DOM's ownerDocument() which is null for Document nodes (and sometimes DocumentType nodes).
    DocumentImpl* getDocument() const { return m_document.get(); }

    void addEventListener(int id, EventListener *listener, const bool useCapture);
    void removeEventListener(int id, EventListener *listener, bool useCapture);
    void setHTMLEventListener(int id, EventListener *listener);
    EventListener *getHTMLEventListener(int id);

    void dispatchEvent(EventImpl *evt, int &exceptioncode, bool tempEvent = false);
    void dispatchGenericEvent( EventImpl *evt, int &exceptioncode);
    // return true if event not prevented
    bool dispatchHTMLEvent(int _id, bool canBubbleArg, bool cancelableArg);
    void dispatchWindowEvent(int _id, bool canBubbleArg, bool cancelableArg);
    void dispatchMouseEvent(TQMouseEvent *e, int overrideId = 0, int overrideDetail = 0);
    void dispatchUIEvent(int _id, int detail = 0);
    void dispatchSubtreeModifiedEvent();
    // return true if defaultPrevented (i.e. event should be swallowed)
    // this matches the logic in KHTMLView.
    bool dispatchKeyEvent(TQKeyEvent *key, bool keypress);

    void handleLocalEvents(EventImpl *evt, bool useCapture);

    /**
     * Perform the default action for an event e.g. submitting a form
     */
    virtual void defaultEventHandler(EventImpl *evt);

    virtual bool isReadOnly();
    virtual bool childTypeAllowed( unsigned short /*type*/ ) { return false; }
    virtual unsigned long childNodeCount();
    virtual NodeImpl *childNode(unsigned long index);

    /**
     * Does a pre-order traversal of the tree to find the node next node after this one. This uses the same order that
     * the tags appear in the source file.
     *
     * @param stayWithin If not null, the traversal will stop once the specified node is reached. This can be used to
     * restrict traversal to a particular sub-tree.
     *
     * @return The next node, in document order
     *
     * see traversePreviousNode()
     */
    NodeImpl *traverseNextNode(NodeImpl *stayWithin = 0) const;

    /**
     * Does a reverse pre-order traversal to find the node that comes before the current one in document order
     *
     * see traverseNextNode()
     */
    NodeImpl *traversePreviousNode() const;

    DocumentImpl *docPtr() const { return m_document.get(); }

    khtml::RenderObject *renderer() const { return m_render; }
    khtml::RenderObject *nextRenderer();
    khtml::RenderObject *previousRenderer();
    void setRenderer(khtml::RenderObject* renderer) { m_render = renderer; }

    void checkSetPrefix(const DOMString &_prefix, int &exceptioncode);
    void checkAddChild(NodeImpl *newChild, int &exceptioncode);
    bool isAncestor( NodeImpl *other );
    virtual bool childAllowed( NodeImpl *newChild );

    /**
     * Returns the minimum caret offset that is allowed for this node.
     *
     * This default implementation always returns 0. Textual child nodes
     * may return other values.
     */
    virtual long minOffset() const;
    /**
     * Returns the maximum caret offset that is allowed for this node.
     *
     * This default implementation always returns the node count.
     * Textual child nodes return the character count instead.
     */
    virtual long maxOffset() const;

    // -----------------------------------------------------------------------------
    // Integration with rendering tree

    /**
     * Attaches this node to the rendering tree. This calculates the style to be applied to the node and creates an
     * appropriate RenderObject which will be inserted into the tree (except when the style has display: none). This
     * makes the node visible in the KHTMLView.
     */
    virtual void attach();

    /**
     * Detaches the node from the rendering tree, making it invisible in the rendered view. This method will remove
     * the node's rendering object from the rendering tree and delete it.
     */
    virtual void detach();

    /**
     * Notifies the node that no more children will be added during parsing.
     * After a node has been closed all changes must go through the DOM interface.
     */
    virtual void close();

    virtual void structureChanged() {};
    virtual void backwardsStructureChanged() {};

    void createRendererIfNeeded();
    virtual khtml::RenderStyle *styleForRenderer(khtml::RenderObject *parent);
    virtual bool rendererIsNeeded(khtml::RenderStyle *);
    virtual khtml::RenderObject *createRenderer(khtml::RenderArena *, khtml::RenderStyle *);

    // -----------------------------------------------------------------------------
    // Methods for maintaining the state of the element between history navigation

    /**
     * Indicates whether or not this type of node maintains its state. If so, the state of the node will be stored when
     * the user goes to a different page using the state() method, and restored using the restoreState() method if the
     * user returns (e.g. using the back button). This is used to ensure that user-changeable elements such as form
     * controls maintain their contents when the user returns to a previous page in the history.
     */
    virtual bool maintainsState();

    /**
     * Returns the state of this node represented as a string. This string will be passed to restoreState() if the user
     * returns to the page.
     *
     * @return State information about the node represented as a string
     */
    virtual TQString state();

    /**
     * Sets the state of the element based on a string previosuly returned by state(). This is used to initialize form
     * controls with their old values when the user returns to the page in their history.
     *
     * @param state A string representation of the node's previously-stored state
     */
    virtual void restoreState(const TQString &state);

    // -----------------------------------------------------------------------------
    // Notification of document stucture changes

    /**
     * Notifies the node that it has been inserted into the document. This is called during document parsing, and also
     * when a node is added through the DOM methods insertBefore(), appendChild() or replaceChild(). Note that this only
     * happens when the node becomes part of the document tree, i.e. only when the document is actually an ancestor of
     * the node. The call happens _after_ the node has been added to the tree.
     *
     * This is similar to the DOMNodeInsertedIntoDocument DOM event, but does not require the overhead of event
     * dispatching.
     */
    virtual void insertedIntoDocument();

    /**
     * Notifies the node that it is no longer part of the document tree, i.e. when the document is no longer an ancestor
     * node.
     *
     * This is similar to the DOMNodeRemovedFromDocument DOM event, but does not require the overhead of event
     * dispatching, and is called _after_ the node is removed from the tree.
     */
    virtual void removedFromDocument();

    /**
     * Notifies the node that its list of children have changed (either by adding or removing child nodes), or a child
     * node that is of the type CDATA_SECTION_NODE, TEXT_NODE or COMMENT_NODE has changed its value.
     */
    virtual void childrenChanged();

    virtual DOMString toString() const = 0;
    /**
     * Sometimes we need to get the string between two points on the DOM graph.  Use this function to do this.
     * For example, when the user copies some selected text to the clipboard as html.
     * @param selectionStart Where to start the selection.  If selectionStart != this, it is assumed we are after the start point
     * @param selectionEnd   Where to end the selection.  If selectionEnd != this, it is assumed we are before the end point (unless found is true)
     * @param startOffset    Number of characters into the text in selectionStart that the start of the selection is.
     * @param endOffset      Number of characters into the text in selectionEnd that the end of the selection is.
     * @param found          When this is set to true, don't print anymore but closing tags.
     * @return An html formatted string for this node and its children between the selectionStart and selectionEnd.
     */
    virtual DOMString selectionToString(NodeImpl * selectionStart, 
                                        NodeImpl * selectionEnd, 
                                        int startOffset, 
                                        int endOffset, 
                                        bool &found) const 
    { Q_UNUSED(selectionStart);
      Q_UNUSED(selectionEnd);
      Q_UNUSED(startOffset);
      Q_UNUSED(endOffset);
      Q_UNUSED(found);
      return toString(); 
    }

private: // members
    khtml::DocPtr<DocumentImpl> m_document;
    NodeImpl *m_previous;
    NodeImpl *m_next;
protected:
    khtml::RenderObject *m_render;
    RegisteredListenerList m_regdListeners;

    unsigned short m_tabIndex : 15;
    bool m_hasTabIndex  : 1;

    bool m_hasId : 1;
    bool m_attached : 1;
    bool m_closed : 1;
    bool m_changed : 1;
    bool m_hasChangedChild : 1;
    bool m_changedAscendentAttribute : 1;
    bool m_inDocument : 1;
    bool m_hasAnchor : 1;
    bool m_specified : 1; // used in AttrImpl. Accessor functions there

    bool m_hovered : 1;
    bool m_focused : 1;
    bool m_active : 1;
    bool m_implicit : 1; // implicitely generated by the parser
    bool m_htmlCompat : 1; // true if element was created in HTML compat mode
    bool m_hasClassList : 1;
    bool m_hasClass : 1;   // true if element has a class property, as relevant to CSS
};

// this is the full Node Implementation with parents and children.
class NodeBaseImpl : public NodeImpl
{
public:
    NodeBaseImpl(DocumentImpl *doc)
        : NodeImpl(doc), _first(0), _last(0) {}
    virtual ~NodeBaseImpl();

    // DOM methods overridden from  parent classes
    virtual NodeImpl *firstChild() const;
    virtual NodeImpl *lastChild() const;
    virtual NodeImpl *insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode );
    virtual void replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode );
    virtual void removeChild ( NodeImpl *oldChild, int &exceptioncode );
    virtual NodeImpl *appendChild ( NodeImpl *newChild, int &exceptioncode );
    virtual bool hasChildNodes (  ) const;

    virtual void setTextContent( const DOMString &text, int& exceptioncode );

    // Other methods (not part of DOM)
    void removeChildren();
    void cloneChildNodes(NodeImpl *clone);

    virtual void setFirstChild(NodeImpl *child);
    virtual void setLastChild(NodeImpl *child);
    virtual NodeImpl *addChild(NodeImpl *newChild);
    virtual void attach();
    virtual void detach();


    bool getUpperLeftCorner(int &xPos, int &yPos) const;
    bool getLowerRightCorner(int &xPos, int &yPos) const;

    virtual void setFocus(bool=true);
    virtual void setActive(bool=true);
    virtual void setHovered(bool=true);
    virtual unsigned long childNodeCount();
    virtual NodeImpl *childNode(unsigned long index);

protected:
    NodeImpl *_first;
    NodeImpl *_last;

    // helper functions for inserting children:

    // ### this should vanish. do it in dom/ !
    // check for same source document:
    bool checkSameDocument( NodeImpl *newchild, int &exceptioncode );
    // check for being child:
    bool checkIsChild( NodeImpl *oldchild, int &exceptioncode );
    // ###

    // find out if a node is allowed to be our child
    void dispatchChildInsertedEvents( NodeImpl *child, int &exceptioncode );
    void dispatchChildRemovalEvents( NodeImpl *child, int &exceptioncode );
};

// --------------------------------------------------------------------------
class Node;
class NodeImpl;

class NodeListImpl : public khtml::Shared<NodeListImpl>
{
public:
    //Type of the item stored in the cache.
    enum Type {
        UNCACHEABLE, //Too complex to be cached like this
        CHILD_NODES,
        LAST_NODE_LIST = CHILD_NODES
    };

    struct CacheKey
    {
        NodeImpl* baseNode;
        int       type;

        CacheKey(): type(UNCACHEABLE) {}

        CacheKey(NodeImpl* _baseNode, int _type):
            baseNode(_baseNode), type(_type)
        {}

        int hash() const
        {
            return int(reinterpret_cast<unsigned long>(baseNode) >> 2) ^
                       (unsigned(type) << 26);
        }

        bool operator==(const CacheKey& other) const
        {
            return baseNode == other.baseNode &&
                   type     == other.type;
        }
    };

    struct Cache: public khtml::Shared<Cache>
    {
        static Cache* make() { return new Cache; }

        CacheKey key;//### We must store this in here due to TQCache in Qt3 sucking

        unsigned int version;
        union
        {
            NodeImpl*    node;
            unsigned int index;
        } current;
        unsigned int position;
        unsigned int length;
        bool         hasLength;

        void updateNodeListInfo(DocumentImpl* doc);

        virtual void clear(DocumentImpl* doc);
        virtual ~Cache();
    };

    typedef Cache* CacheFactory();

    NodeListImpl(NodeImpl* node, int type, CacheFactory* factory = 0);
    virtual ~NodeListImpl();

    // DOM methods & attributes for NodeList
    virtual unsigned long length() const;
    virtual NodeImpl *item ( unsigned long index ) const;

    // Other methods (not part of DOM)

protected:
    virtual unsigned long calcLength(NodeImpl *start) const;
    // helper functions for searching all ElementImpls in a tree

    NodeImpl *recursiveItem    ( NodeImpl* absStart, NodeImpl *start, unsigned long &offset ) const;
    NodeImpl *recursiveItemBack( NodeImpl* absStart, NodeImpl *start, unsigned long &offset ) const;

    // Override this to determine what nodes to return. Set doRecurse to
    // false if the children of this node do not need to be entered.
    virtual bool nodeMatches( NodeImpl *testNode, bool& doRecurse ) const = 0;

    NodeImpl*      m_refNode;
    mutable Cache* m_cache;
};

class ChildNodeListImpl : public NodeListImpl
{
public:

    ChildNodeListImpl( NodeImpl *n);

protected:
    virtual bool nodeMatches( NodeImpl *testNode, bool& doRecurse ) const;
};


/**
 * NodeList which lists all Nodes in a document with a given tag name
 */
class TagNodeListImpl : public NodeListImpl
{
public:
    TagNodeListImpl( NodeImpl *n, NodeImpl::Id id );
    TagNodeListImpl( NodeImpl *n, const DOMString &namespaceURI, const DOMString &localName );

    // Other methods (not part of DOM)

protected:
    virtual bool nodeMatches( NodeImpl *testNode, bool& doRecurse ) const;
    NodeImpl::Id m_id;
    DOMString m_namespaceURI;
    DOMString m_localName;

    bool m_matchAllNames;
    bool m_matchAllNamespaces;
    bool m_namespaceAware;
};


/**
 * NodeList which lists all Nodes in a Element with a given "name=" tag
 */
class NameNodeListImpl : public NodeListImpl
{
public:
    NameNodeListImpl( NodeImpl *doc, const DOMString &t );

    // Other methods (not part of DOM)

protected:
    virtual bool nodeMatches( NodeImpl *testNode, bool& doRecurse ) const;

    DOMString nodeName;
};

// Generic NamedNodeMap interface
// Other classes implement this for more specific situations e.g. attributes
// of an element
class NamedNodeMapImpl : public khtml::Shared<NamedNodeMapImpl>
{
public:
    NamedNodeMapImpl();
    virtual ~NamedNodeMapImpl();

    // DOM methods & attributes for NamedNodeMap
    virtual NodeImpl *getNamedItem ( NodeImpl::Id id, bool nsAware = false, DOMStringImpl* qName = 0 ) const = 0;
    virtual Node removeNamedItem ( NodeImpl::Id id, bool nsAware, DOMStringImpl* qName, int &exceptioncode ) = 0;
    virtual Node setNamedItem ( NodeImpl* arg, bool nsAware, DOMStringImpl* qName, int &exceptioncode ) = 0;

    virtual NodeImpl *item ( unsigned long index ) const = 0;
    virtual unsigned long length(  ) const = 0;

    // Other methods (not part of DOM)
    virtual NodeImpl::Id mapId(DOMStringImpl* namespaceURI,
				DOMStringImpl* localName, bool readonly) = 0;
    virtual bool isReadOnly() { return false; }
};

// Generic read-only NamedNodeMap implementation
// Used for e.g. entities and notations in DocumentType.
// You can add nodes using addNode
class GenericRONamedNodeMapImpl : public NamedNodeMapImpl
{
public:
    GenericRONamedNodeMapImpl(DocumentImpl* doc);
    virtual ~GenericRONamedNodeMapImpl();

    // DOM methods & attributes for NamedNodeMap

    virtual NodeImpl *getNamedItem ( NodeImpl::Id id, bool nsAware = false, DOMStringImpl* qName = 0 ) const;
    virtual Node removeNamedItem ( NodeImpl::Id id, bool nsAware, DOMStringImpl* qName, int &exceptioncode );
    virtual Node setNamedItem ( NodeImpl* arg, bool nsAware, DOMStringImpl* qName, int &exceptioncode );

    virtual NodeImpl *item ( unsigned long index ) const;
    virtual unsigned long length(  ) const;

    // Other methods (not part of DOM)
    virtual NodeImpl::Id mapId(DOMStringImpl* namespaceURI,
                               DOMStringImpl* localName, bool readonly);

    virtual bool isReadOnly() { return true; }

    void addNode(NodeImpl *n);

protected:
    DocumentImpl* m_doc;
    TQPtrList<NodeImpl> *m_contents;
};

} //namespace
#endif