1 /*
2 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18 */
19
20 #include "config.h"
21 #include "qwebelement.h"
22
23 #include "CSSComputedStyleDeclaration.h"
24 #include "CSSMutableStyleDeclaration.h"
25 #include "CSSParser.h"
26 #include "CSSRule.h"
27 #include "CSSRuleList.h"
28 #include "CSSStyleRule.h"
29 #include "CSSStyleSelector.h"
30 #include "Document.h"
31 #include "DocumentFragment.h"
32 #include "FrameView.h"
33 #include "GraphicsContext.h"
34 #include "HTMLElement.h"
35 #if USE(JSC)
36 #include "JSGlobalObject.h"
37 #include "JSHTMLElement.h"
38 #include "JSObject.h"
39 #include "PropertyNameArray.h"
40 #include <parser/SourceCode.h>
41 #include "qt_runtime.h"
42 #elif USE(V8)
43 #include "V8DOMWindow.h"
44 #include "V8Binding.h"
45 #include "NotImplemented.h"
46 #endif
47 #include "NodeList.h"
48 #include "RenderImage.h"
49 #include "StaticNodeList.h"
50 #include "qwebframe.h"
51 #include "qwebframe_p.h"
52 #if USE(JSC)
53 #include "runtime_root.h"
54 #endif
55 #include <wtf/Vector.h>
56 #include <wtf/text/CString.h>
57
58 #include <QPainter>
59
60 #if USE(V8)
61 using namespace V8::Bindings;
62 #endif
63
64 using namespace WebCore;
65
66 class QWebElementPrivate {
67 public:
68 };
69
70 /*!
71 \class QWebElement
72 \since 4.6
73 \brief The QWebElement class provides convenient access to DOM elements in
74 a QWebFrame.
75 \inmodule QtWebKit
76
77 A QWebElement object allows easy access to the document model, represented
78 by a tree-like structure of DOM elements. The root of the tree is called
79 the document element and can be accessed using
80 QWebFrame::documentElement().
81
82 Specific elements can be accessed using findAll() and findFirst(). These
83 elements are identified using CSS selectors. The code snippet below
84 demonstrates the use of findAll().
85
86 \snippet webkitsnippets/webelement/main.cpp FindAll
87
88 The first list contains all \c span elements in the document. The second
89 list contains \c span elements that are children of \c p, classified with
90 \c intro.
91
92 Using findFirst() is more efficient than calling findAll(), and extracting
93 the first element only in the list returned.
94
95 Alternatively you can traverse the document manually using firstChild() and
96 nextSibling():
97
98 \snippet webkitsnippets/webelement/main.cpp Traversing with QWebElement
99
100 Individual elements can be inspected or changed using methods such as attribute()
101 or setAttribute(). For examle, to capture the user's input in a text field for later
102 use (auto-completion), a browser could do something like this:
103
104 \snippet webkitsnippets/webelement/main.cpp autocomplete1
105
106 When the same page is later revisited, the browser can fill in the text field automatically
107 by modifying the value attribute of the input element:
108
109 \snippet webkitsnippets/webelement/main.cpp autocomplete2
110
111 Another use case is to emulate a click event on an element. The following
112 code snippet demonstrates how to call the JavaScript DOM method click() of
113 a submit button:
114
115 \snippet webkitsnippets/webelement/main.cpp Calling a DOM element method
116
117 The underlying content of QWebElement is explicitly shared. Creating a copy
118 of a QWebElement does not create a copy of the content. Instead, both
119 instances point to the same element.
120
121 The contents of child elements can be converted to plain text with
122 toPlainText(); to XHTML using toInnerXml(). To include the element's tag in
123 the output, use toOuterXml().
124
125 It is possible to replace the contents of child elements using
126 setPlainText() and setInnerXml(). To replace the element itself and its
127 contents, use setOuterXml().
128
129 \section1 Examples
130
131 The \l{DOM Traversal Example} shows one way to traverse documents in a running
132 example.
133
134 The \l{Simple Selector Example} can be used to experiment with the searching
135 features of this class and provides sample code you can start working with.
136 */
137
138 /*!
139 Constructs a null web element.
140 */
QWebElement()141 QWebElement::QWebElement()
142 : d(0)
143 , m_element(0)
144 {
145 }
146
147 /*!
148 \internal
149 */
QWebElement(WebCore::Element * domElement)150 QWebElement::QWebElement(WebCore::Element* domElement)
151 : d(0)
152 , m_element(domElement)
153 {
154 if (m_element)
155 m_element->ref();
156 }
157
158 /*!
159 \internal
160 */
QWebElement(WebCore::Node * node)161 QWebElement::QWebElement(WebCore::Node* node)
162 : d(0)
163 , m_element(0)
164 {
165 if (node && node->isHTMLElement()) {
166 m_element = static_cast<HTMLElement*>(node);
167 m_element->ref();
168 }
169 }
170
171 /*!
172 Constructs a copy of \a other.
173 */
QWebElement(const QWebElement & other)174 QWebElement::QWebElement(const QWebElement &other)
175 : d(0)
176 , m_element(other.m_element)
177 {
178 if (m_element)
179 m_element->ref();
180 }
181
182 /*!
183 Assigns \a other to this element and returns a reference to this element.
184 */
operator =(const QWebElement & other)185 QWebElement &QWebElement::operator=(const QWebElement &other)
186 {
187 // ### handle "d" assignment
188 if (this != &other) {
189 Element *otherElement = other.m_element;
190 if (otherElement)
191 otherElement->ref();
192 if (m_element)
193 m_element->deref();
194 m_element = otherElement;
195 }
196 return *this;
197 }
198
199 /*!
200 Destroys the element. However, the underlying DOM element is not destroyed.
201 */
~QWebElement()202 QWebElement::~QWebElement()
203 {
204 delete d;
205 if (m_element)
206 m_element->deref();
207 }
208
operator ==(const QWebElement & o) const209 bool QWebElement::operator==(const QWebElement& o) const
210 {
211 return m_element == o.m_element;
212 }
213
operator !=(const QWebElement & o) const214 bool QWebElement::operator!=(const QWebElement& o) const
215 {
216 return m_element != o.m_element;
217 }
218
219 /*!
220 Returns true if the element is a null element; otherwise returns false.
221 */
isNull() const222 bool QWebElement::isNull() const
223 {
224 return !m_element;
225 }
226
227 /*!
228 Returns a new list of child elements matching the given CSS selector
229 \a selectorQuery. If there are no matching elements, an empty list is
230 returned.
231
232 \l{Standard CSS2 selector} syntax is used for the query.
233
234 \note This search is performed recursively.
235
236 \sa findFirst()
237 */
findAll(const QString & selectorQuery) const238 QWebElementCollection QWebElement::findAll(const QString &selectorQuery) const
239 {
240 return QWebElementCollection(*this, selectorQuery);
241 }
242
243 /*!
244 Returns the first child element that matches the given CSS selector
245 \a selectorQuery.
246
247 \l{Standard CSS2 selector} syntax is used for the query.
248
249 \note This search is performed recursively.
250
251 \sa findAll()
252 */
findFirst(const QString & selectorQuery) const253 QWebElement QWebElement::findFirst(const QString &selectorQuery) const
254 {
255 if (!m_element)
256 return QWebElement();
257 ExceptionCode exception = 0; // ###
258 return QWebElement(m_element->querySelector(selectorQuery, exception).get());
259 }
260
261 /*!
262 Replaces the existing content of this element with \a text.
263
264 This is equivalent to setting the HTML innerText property.
265
266 \sa toPlainText()
267 */
setPlainText(const QString & text)268 void QWebElement::setPlainText(const QString &text)
269 {
270 if (!m_element || !m_element->isHTMLElement())
271 return;
272 ExceptionCode exception = 0;
273 static_cast<HTMLElement*>(m_element)->setInnerText(text, exception);
274 }
275
276 /*!
277 Returns the text between the start and the end tag of this
278 element.
279
280 This is equivalent to reading the HTML innerText property.
281
282 \sa setPlainText()
283 */
toPlainText() const284 QString QWebElement::toPlainText() const
285 {
286 if (!m_element || !m_element->isHTMLElement())
287 return QString();
288 return static_cast<HTMLElement*>(m_element)->innerText();
289 }
290
291 /*!
292 Replaces the contents of this element as well as its own tag with
293 \a markup. The string may contain HTML or XML tags, which is parsed and
294 formatted before insertion into the document.
295
296 \note This is currently only implemented for (X)HTML elements.
297
298 \sa toOuterXml(), toInnerXml(), setInnerXml()
299 */
setOuterXml(const QString & markup)300 void QWebElement::setOuterXml(const QString &markup)
301 {
302 if (!m_element || !m_element->isHTMLElement())
303 return;
304
305 ExceptionCode exception = 0;
306
307 static_cast<HTMLElement*>(m_element)->setOuterHTML(markup, exception);
308 }
309
310 /*!
311 Returns this element converted to XML, including the start and the end
312 tags as well as its attributes.
313
314 \note This is currently implemented for (X)HTML elements only.
315
316 \note The format of the markup returned will obey the namespace of the
317 document containing the element. This means the return value will obey XML
318 formatting rules, such as self-closing tags, only if the document is
319 'text/xhtml+xml'.
320
321 \sa setOuterXml(), setInnerXml(), toInnerXml()
322 */
toOuterXml() const323 QString QWebElement::toOuterXml() const
324 {
325 if (!m_element || !m_element->isHTMLElement())
326 return QString();
327
328 return static_cast<HTMLElement*>(m_element)->outerHTML();
329 }
330
331 /*!
332 Replaces the contents of this element with \a markup. The string may
333 contain HTML or XML tags, which is parsed and formatted before insertion
334 into the document.
335
336 \note This is currently implemented for (X)HTML elements only.
337
338 \sa toInnerXml(), toOuterXml(), setOuterXml()
339 */
setInnerXml(const QString & markup)340 void QWebElement::setInnerXml(const QString &markup)
341 {
342 if (!m_element || !m_element->isHTMLElement())
343 return;
344
345 ExceptionCode exception = 0;
346
347 static_cast<HTMLElement*>(m_element)->setInnerHTML(markup, exception);
348 }
349
350 /*!
351 Returns the XML content between the element's start and end tags.
352
353 \note This is currently implemented for (X)HTML elements only.
354
355 \note The format of the markup returned will obey the namespace of the
356 document containing the element. This means the return value will obey XML
357 formatting rules, such as self-closing tags, only if the document is
358 'text/xhtml+xml'.
359
360 \sa setInnerXml(), setOuterXml(), toOuterXml()
361 */
toInnerXml() const362 QString QWebElement::toInnerXml() const
363 {
364 if (!m_element || !m_element->isHTMLElement())
365 return QString();
366
367 return static_cast<HTMLElement*>(m_element)->innerHTML();
368 }
369
370 /*!
371 Adds an attribute with the given \a name and \a value. If an attribute with
372 the same name exists, its value is replaced by \a value.
373
374 \sa attribute(), attributeNS(), setAttributeNS()
375 */
setAttribute(const QString & name,const QString & value)376 void QWebElement::setAttribute(const QString &name, const QString &value)
377 {
378 if (!m_element)
379 return;
380 ExceptionCode exception = 0;
381 m_element->setAttribute(name, value, exception);
382 }
383
384 /*!
385 Adds an attribute with the given \a name in \a namespaceUri with \a value.
386 If an attribute with the same name exists, its value is replaced by
387 \a value.
388
389 \sa attributeNS(), attribute(), setAttribute()
390 */
setAttributeNS(const QString & namespaceUri,const QString & name,const QString & value)391 void QWebElement::setAttributeNS(const QString &namespaceUri, const QString &name, const QString &value)
392 {
393 if (!m_element)
394 return;
395 WebCore::ExceptionCode exception = 0;
396 m_element->setAttributeNS(namespaceUri, name, value, exception);
397 }
398
399 /*!
400 Returns the attribute with the given \a name. If the attribute does not
401 exist, \a defaultValue is returned.
402
403 \sa setAttribute(), setAttributeNS(), attributeNS()
404 */
attribute(const QString & name,const QString & defaultValue) const405 QString QWebElement::attribute(const QString &name, const QString &defaultValue) const
406 {
407 if (!m_element)
408 return QString();
409 if (m_element->hasAttribute(name))
410 return m_element->getAttribute(name);
411 else
412 return defaultValue;
413 }
414
415 /*!
416 Returns the attribute with the given \a name in \a namespaceUri. If the
417 attribute does not exist, \a defaultValue is returned.
418
419 \sa setAttributeNS(), setAttribute(), attribute()
420 */
attributeNS(const QString & namespaceUri,const QString & name,const QString & defaultValue) const421 QString QWebElement::attributeNS(const QString &namespaceUri, const QString &name, const QString &defaultValue) const
422 {
423 if (!m_element)
424 return QString();
425 if (m_element->hasAttributeNS(namespaceUri, name))
426 return m_element->getAttributeNS(namespaceUri, name);
427 else
428 return defaultValue;
429 }
430
431 /*!
432 Returns true if this element has an attribute with the given \a name;
433 otherwise returns false.
434
435 \sa attribute(), setAttribute()
436 */
hasAttribute(const QString & name) const437 bool QWebElement::hasAttribute(const QString &name) const
438 {
439 if (!m_element)
440 return false;
441 return m_element->hasAttribute(name);
442 }
443
444 /*!
445 Returns true if this element has an attribute with the given \a name, in
446 \a namespaceUri; otherwise returns false.
447
448 \sa attributeNS(), setAttributeNS()
449 */
hasAttributeNS(const QString & namespaceUri,const QString & name) const450 bool QWebElement::hasAttributeNS(const QString &namespaceUri, const QString &name) const
451 {
452 if (!m_element)
453 return false;
454 return m_element->hasAttributeNS(namespaceUri, name);
455 }
456
457 /*!
458 Removes the attribute with the given \a name from this element.
459
460 \sa attribute(), setAttribute(), hasAttribute()
461 */
removeAttribute(const QString & name)462 void QWebElement::removeAttribute(const QString &name)
463 {
464 if (!m_element)
465 return;
466 ExceptionCode exception = 0;
467 m_element->removeAttribute(name, exception);
468 }
469
470 /*!
471 Removes the attribute with the given \a name, in \a namespaceUri, from this
472 element.
473
474 \sa attributeNS(), setAttributeNS(), hasAttributeNS()
475 */
removeAttributeNS(const QString & namespaceUri,const QString & name)476 void QWebElement::removeAttributeNS(const QString &namespaceUri, const QString &name)
477 {
478 if (!m_element)
479 return;
480 WebCore::ExceptionCode exception = 0;
481 m_element->removeAttributeNS(namespaceUri, name, exception);
482 }
483
484 /*!
485 Returns true if the element has any attributes defined; otherwise returns
486 false;
487
488 \sa attribute(), setAttribute()
489 */
hasAttributes() const490 bool QWebElement::hasAttributes() const
491 {
492 if (!m_element)
493 return false;
494 return m_element->hasAttributes();
495 }
496
497 /*!
498 Return the list of attributes for the namespace given as \a namespaceUri.
499
500 \sa attribute(), setAttribute()
501 */
attributeNames(const QString & namespaceUri) const502 QStringList QWebElement::attributeNames(const QString& namespaceUri) const
503 {
504 if (!m_element)
505 return QStringList();
506
507 QStringList attributeNameList;
508 const NamedNodeMap* const attrs = m_element->attributes(/* read only = */ true);
509 if (attrs) {
510 const String namespaceUriString(namespaceUri); // convert QString -> String once
511 const unsigned attrsCount = attrs->length();
512 for (unsigned i = 0; i < attrsCount; ++i) {
513 const Attribute* const attribute = attrs->attributeItem(i);
514 if (namespaceUriString == attribute->namespaceURI())
515 attributeNameList.append(attribute->localName());
516 }
517 }
518 return attributeNameList;
519 }
520
521 /*!
522 Returns true if the element has keyboard input focus; otherwise, returns false
523
524 \sa setFocus()
525 */
hasFocus() const526 bool QWebElement::hasFocus() const
527 {
528 if (!m_element)
529 return false;
530 if (m_element->document())
531 return m_element == m_element->document()->focusedNode();
532 return false;
533 }
534
535 /*!
536 Gives keyboard input focus to this element
537
538 \sa hasFocus()
539 */
setFocus()540 void QWebElement::setFocus()
541 {
542 if (!m_element)
543 return;
544 if (m_element->document() && m_element->isFocusable())
545 m_element->document()->setFocusedNode(m_element);
546 }
547
548 /*!
549 Returns the geometry of this element, relative to its containing frame.
550
551 \sa tagName()
552 */
geometry() const553 QRect QWebElement::geometry() const
554 {
555 if (!m_element)
556 return QRect();
557 return m_element->getRect();
558 }
559
560 /*!
561 Returns the tag name of this element.
562
563 \sa geometry()
564 */
tagName() const565 QString QWebElement::tagName() const
566 {
567 if (!m_element)
568 return QString();
569 return m_element->tagName();
570 }
571
572 /*!
573 Returns the namespace prefix of the element. If the element has no\
574 namespace prefix, empty string is returned.
575 */
prefix() const576 QString QWebElement::prefix() const
577 {
578 if (!m_element)
579 return QString();
580 return m_element->prefix();
581 }
582
583 /*!
584 Returns the local name of the element. If the element does not use
585 namespaces, an empty string is returned.
586 */
localName() const587 QString QWebElement::localName() const
588 {
589 if (!m_element)
590 return QString();
591 return m_element->localName();
592 }
593
594 /*!
595 Returns the namespace URI of this element. If the element has no namespace
596 URI, an empty string is returned.
597 */
namespaceUri() const598 QString QWebElement::namespaceUri() const
599 {
600 if (!m_element)
601 return QString();
602 return m_element->namespaceURI();
603 }
604
605 /*!
606 Returns the parent element of this elemen. If this element is the root
607 document element, a null element is returned.
608 */
parent() const609 QWebElement QWebElement::parent() const
610 {
611 if (m_element)
612 return QWebElement(m_element->parentElement());
613 return QWebElement();
614 }
615
616 /*!
617 Returns the element's first child.
618
619 \sa lastChild(), previousSibling(), nextSibling()
620 */
firstChild() const621 QWebElement QWebElement::firstChild() const
622 {
623 if (!m_element)
624 return QWebElement();
625 for (Node* child = m_element->firstChild(); child; child = child->nextSibling()) {
626 if (!child->isElementNode())
627 continue;
628 Element* e = static_cast<Element*>(child);
629 return QWebElement(e);
630 }
631 return QWebElement();
632 }
633
634 /*!
635 Returns the element's last child.
636
637 \sa firstChild(), previousSibling(), nextSibling()
638 */
lastChild() const639 QWebElement QWebElement::lastChild() const
640 {
641 if (!m_element)
642 return QWebElement();
643 for (Node* child = m_element->lastChild(); child; child = child->previousSibling()) {
644 if (!child->isElementNode())
645 continue;
646 Element* e = static_cast<Element*>(child);
647 return QWebElement(e);
648 }
649 return QWebElement();
650 }
651
652 /*!
653 Returns the element's next sibling.
654
655 \sa firstChild(), previousSibling(), lastChild()
656 */
nextSibling() const657 QWebElement QWebElement::nextSibling() const
658 {
659 if (!m_element)
660 return QWebElement();
661 for (Node* sib = m_element->nextSibling(); sib; sib = sib->nextSibling()) {
662 if (!sib->isElementNode())
663 continue;
664 Element* e = static_cast<Element*>(sib);
665 return QWebElement(e);
666 }
667 return QWebElement();
668 }
669
670 /*!
671 Returns the element's previous sibling.
672
673 \sa firstChild(), nextSibling(), lastChild()
674 */
previousSibling() const675 QWebElement QWebElement::previousSibling() const
676 {
677 if (!m_element)
678 return QWebElement();
679 for (Node* sib = m_element->previousSibling(); sib; sib = sib->previousSibling()) {
680 if (!sib->isElementNode())
681 continue;
682 Element* e = static_cast<Element*>(sib);
683 return QWebElement(e);
684 }
685 return QWebElement();
686 }
687
688 /*!
689 Returns the document which this element belongs to.
690 */
document() const691 QWebElement QWebElement::document() const
692 {
693 if (!m_element)
694 return QWebElement();
695 Document* document = m_element->document();
696 if (!document)
697 return QWebElement();
698 return QWebElement(document->documentElement());
699 }
700
701 /*!
702 Returns the web frame which this element is a part of. If the element is a
703 null element, null is returned.
704 */
webFrame() const705 QWebFrame *QWebElement::webFrame() const
706 {
707 if (!m_element)
708 return 0;
709
710 Document* document = m_element->document();
711 if (!document)
712 return 0;
713
714 Frame* frame = document->frame();
715 if (!frame)
716 return 0;
717 return QWebFramePrivate::kit(frame);
718 }
719
720 #if USE(JSC)
setupScriptContext(WebCore::Element * element,JSC::JSValue & thisValue,ScriptState * & state,ScriptController * & scriptController)721 static bool setupScriptContext(WebCore::Element* element, JSC::JSValue& thisValue, ScriptState*& state, ScriptController*& scriptController)
722 {
723 if (!element)
724 return false;
725
726 Document* document = element->document();
727 if (!document)
728 return false;
729
730 Frame* frame = document->frame();
731 if (!frame)
732 return false;
733
734 scriptController = frame->script();
735 if (!scriptController)
736 return false;
737
738 state = scriptController->globalObject(mainThreadNormalWorld())->globalExec();
739 if (!state)
740 return false;
741
742 thisValue = toJS(state, element);
743 if (!thisValue)
744 return false;
745
746 return true;
747 }
748 #elif USE(V8)
setupScriptContext(WebCore::Element * element,v8::Handle<v8::Value> & thisValue,ScriptState * & state,ScriptController * & scriptController)749 static bool setupScriptContext(WebCore::Element* element, v8::Handle<v8::Value>& thisValue, ScriptState*& state, ScriptController*& scriptController)
750 {
751 if (!element)
752 return false;
753
754 Document* document = element->document();
755 if (!document)
756 return false;
757
758 Frame* frame = document->frame();
759 if (!frame)
760 return false;
761
762 state = mainWorldScriptState(frame);
763 // Get V8 wrapper for DOM element
764 thisValue = toV8(frame->domWindow());
765 return true;
766 }
767 #endif
768
769
770 /*!
771 Executes \a scriptSource with this element as \c this object.
772 */
evaluateJavaScript(const QString & scriptSource)773 QVariant QWebElement::evaluateJavaScript(const QString& scriptSource)
774 {
775 if (scriptSource.isEmpty())
776 return QVariant();
777
778 ScriptState* state = 0;
779 #if USE(JSC)
780 JSC::JSValue thisValue;
781 #elif USE(V8)
782 v8::Handle<v8::Value> thisValue;
783 #endif
784 ScriptController* scriptController = 0;
785
786 if (!setupScriptContext(m_element, thisValue, state, scriptController))
787 return QVariant();
788 #if USE(JSC)
789 JSC::ScopeChainNode* scopeChain = state->dynamicGlobalObject()->globalScopeChain();
790 JSC::UString script(reinterpret_cast_ptr<const UChar*>(scriptSource.data()), scriptSource.length());
791 JSC::Completion completion = JSC::evaluate(state, scopeChain, JSC::makeSource(script), thisValue);
792 if ((completion.complType() != JSC::ReturnValue) && (completion.complType() != JSC::Normal))
793 return QVariant();
794
795 JSC::JSValue result = completion.value();
796 if (!result)
797 return QVariant();
798
799 int distance = 0;
800 return JSC::Bindings::convertValueToQVariant(state, result, QMetaType::Void, &distance);
801 #elif USE(V8)
802 notImplemented();
803 return QVariant();
804 #endif
805 }
806
807 /*!
808 \enum QWebElement::StyleResolveStrategy
809
810 This enum describes how QWebElement's styleProperty resolves the given
811 property name.
812
813 \value InlineStyle Return the property value as it is defined in
814 the element, without respecting style inheritance and other CSS
815 rules.
816 \value CascadedStyle The property's value is determined using the
817 inheritance and importance rules defined in the document's
818 stylesheet.
819 \value ComputedStyle The property's value is the absolute value
820 of the style property resolved from the environment.
821 */
822
823 /*!
824 Returns the value of the style with the given \a name using the specified
825 \a strategy. If a style with \a name does not exist, an empty string is
826 returned.
827
828 In CSS, the cascading part depends on which CSS rule has priority and is
829 thus applied. Generally, the last defined rule has priority. Thus, an
830 inline style rule has priority over an embedded block style rule, which
831 in return has priority over an external style rule.
832
833 If the "!important" declaration is set on one of those, the declaration
834 receives highest priority, unless other declarations also use the
835 "!important" declaration. Then, the last "!important" declaration takes
836 predecence.
837
838 \sa setStyleProperty()
839 */
840
styleProperty(const QString & name,StyleResolveStrategy strategy) const841 QString QWebElement::styleProperty(const QString &name, StyleResolveStrategy strategy) const
842 {
843 if (!m_element || !m_element->isStyledElement())
844 return QString();
845
846 int propID = cssPropertyID(name);
847
848 if (!propID)
849 return QString();
850
851 CSSStyleDeclaration* style = static_cast<StyledElement*>(m_element)->style();
852
853 if (strategy == InlineStyle)
854 return style->getPropertyValue(propID);
855
856 if (strategy == CascadedStyle) {
857 if (style->getPropertyPriority(propID))
858 return style->getPropertyValue(propID);
859
860 // We are going to resolve the style property by walking through the
861 // list of non-inline matched CSS rules for the element, looking for
862 // the highest priority definition.
863
864 // Get an array of matched CSS rules for the given element sorted
865 // by importance and inheritance order. This include external CSS
866 // declarations, as well as embedded and inline style declarations.
867
868 Document* doc = m_element->document();
869 if (RefPtr<CSSRuleList> rules = doc->styleSelector()->styleRulesForElement(m_element, /*authorOnly*/ true)) {
870 for (int i = rules->length(); i > 0; --i) {
871 CSSStyleRule* rule = static_cast<CSSStyleRule*>(rules->item(i - 1));
872
873 if (rule->style()->getPropertyPriority(propID))
874 return rule->style()->getPropertyValue(propID);
875
876 if (style->getPropertyValue(propID).isEmpty())
877 style = rule->style();
878 }
879 }
880
881 return style->getPropertyValue(propID);
882 }
883
884 if (strategy == ComputedStyle) {
885 if (!m_element || !m_element->isStyledElement())
886 return QString();
887
888 int propID = cssPropertyID(name);
889
890 RefPtr<CSSComputedStyleDeclaration> style = computedStyle(m_element, true);
891 if (!propID || !style)
892 return QString();
893
894 return style->getPropertyValue(propID);
895 }
896
897 return QString();
898 }
899
900 /*!
901 Sets the value of the inline style with the given \a name to \a value.
902
903 Setting a value, does not necessarily mean that it will become the applied
904 value, due to the fact that the style property's value might have been set
905 earlier with a higher priority in external or embedded style declarations.
906
907 In order to ensure that the value will be applied, you may have to append
908 "!important" to the value.
909 */
setStyleProperty(const QString & name,const QString & value)910 void QWebElement::setStyleProperty(const QString &name, const QString &value)
911 {
912 if (!m_element || !m_element->isStyledElement())
913 return;
914
915 int propID = cssPropertyID(name);
916 CSSStyleDeclaration* style = static_cast<StyledElement*>(m_element)->style();
917 if (!propID || !style)
918 return;
919
920 ExceptionCode exception = 0;
921 style->setProperty(name, value, exception);
922 }
923
924 /*!
925 Returns the list of classes of this element.
926 */
classes() const927 QStringList QWebElement::classes() const
928 {
929 if (!hasAttribute(QLatin1String("class")))
930 return QStringList();
931
932 QStringList classes = attribute(QLatin1String("class")).simplified().split(QLatin1Char(' '), QString::SkipEmptyParts);
933 classes.removeDuplicates();
934 return classes;
935 }
936
937 /*!
938 Returns true if this element has a class with the given \a name; otherwise
939 returns false.
940 */
hasClass(const QString & name) const941 bool QWebElement::hasClass(const QString &name) const
942 {
943 QStringList list = classes();
944 return list.contains(name);
945 }
946
947 /*!
948 Adds the specified class with the given \a name to the element.
949 */
addClass(const QString & name)950 void QWebElement::addClass(const QString &name)
951 {
952 QStringList list = classes();
953 if (!list.contains(name)) {
954 list.append(name);
955 QString value = list.join(QLatin1String(" "));
956 setAttribute(QLatin1String("class"), value);
957 }
958 }
959
960 /*!
961 Removes the specified class with the given \a name from the element.
962 */
removeClass(const QString & name)963 void QWebElement::removeClass(const QString &name)
964 {
965 QStringList list = classes();
966 if (list.contains(name)) {
967 list.removeAll(name);
968 QString value = list.join(QLatin1String(" "));
969 setAttribute(QLatin1String("class"), value);
970 }
971 }
972
973 /*!
974 Adds the specified class with the given \a name if it is not present. If
975 the class is already present, it will be removed.
976 */
toggleClass(const QString & name)977 void QWebElement::toggleClass(const QString &name)
978 {
979 QStringList list = classes();
980 if (list.contains(name))
981 list.removeAll(name);
982 else
983 list.append(name);
984
985 QString value = list.join(QLatin1String(" "));
986 setAttribute(QLatin1String("class"), value);
987 }
988
989 /*!
990 Appends the given \a element as the element's last child.
991
992 If \a element is the child of another element, it is re-parented to this
993 element. If \a element is a child of this element, then its position in
994 the list of children is changed.
995
996 Calling this function on a null element does nothing.
997
998 \sa prependInside(), prependOutside(), appendOutside()
999 */
appendInside(const QWebElement & element)1000 void QWebElement::appendInside(const QWebElement &element)
1001 {
1002 if (!m_element || element.isNull())
1003 return;
1004
1005 ExceptionCode exception = 0;
1006 m_element->appendChild(element.m_element, exception);
1007 }
1008
1009 /*!
1010 Appends the result of parsing \a markup as the element's last child.
1011
1012 Calling this function on a null element does nothing.
1013
1014 \sa prependInside(), prependOutside(), appendOutside()
1015 */
appendInside(const QString & markup)1016 void QWebElement::appendInside(const QString &markup)
1017 {
1018 if (!m_element)
1019 return;
1020
1021 if (!m_element->isHTMLElement())
1022 return;
1023
1024 HTMLElement* htmlElement = static_cast<HTMLElement*>(m_element);
1025 RefPtr<DocumentFragment> fragment = htmlElement->Element::deprecatedCreateContextualFragment(markup);
1026
1027 ExceptionCode exception = 0;
1028 m_element->appendChild(fragment, exception);
1029 }
1030
1031 /*!
1032 Prepends \a element as the element's first child.
1033
1034 If \a element is the child of another element, it is re-parented to this
1035 element. If \a element is a child of this element, then its position in
1036 the list of children is changed.
1037
1038 Calling this function on a null element does nothing.
1039
1040 \sa appendInside(), prependOutside(), appendOutside()
1041 */
prependInside(const QWebElement & element)1042 void QWebElement::prependInside(const QWebElement &element)
1043 {
1044 if (!m_element || element.isNull())
1045 return;
1046
1047 ExceptionCode exception = 0;
1048
1049 if (m_element->hasChildNodes())
1050 m_element->insertBefore(element.m_element, m_element->firstChild(), exception);
1051 else
1052 m_element->appendChild(element.m_element, exception);
1053 }
1054
1055 /*!
1056 Prepends the result of parsing \a markup as the element's first child.
1057
1058 Calling this function on a null element does nothing.
1059
1060 \sa appendInside(), prependOutside(), appendOutside()
1061 */
prependInside(const QString & markup)1062 void QWebElement::prependInside(const QString &markup)
1063 {
1064 if (!m_element)
1065 return;
1066
1067 if (!m_element->isHTMLElement())
1068 return;
1069
1070 HTMLElement* htmlElement = static_cast<HTMLElement*>(m_element);
1071 RefPtr<DocumentFragment> fragment = htmlElement->deprecatedCreateContextualFragment(markup);
1072
1073 ExceptionCode exception = 0;
1074
1075 if (m_element->hasChildNodes())
1076 m_element->insertBefore(fragment, m_element->firstChild(), exception);
1077 else
1078 m_element->appendChild(fragment, exception);
1079 }
1080
1081
1082 /*!
1083 Inserts the given \a element before this element.
1084
1085 If \a element is the child of another element, it is re-parented to the
1086 parent of this element.
1087
1088 Calling this function on a null element does nothing.
1089
1090 \sa appendInside(), prependInside(), appendOutside()
1091 */
prependOutside(const QWebElement & element)1092 void QWebElement::prependOutside(const QWebElement &element)
1093 {
1094 if (!m_element || element.isNull())
1095 return;
1096
1097 if (!m_element->parentNode())
1098 return;
1099
1100 ExceptionCode exception = 0;
1101 m_element->parentNode()->insertBefore(element.m_element, m_element, exception);
1102 }
1103
1104 /*!
1105 Inserts the result of parsing \a markup before this element.
1106
1107 Calling this function on a null element does nothing.
1108
1109 \sa appendInside(), prependInside(), appendOutside()
1110 */
prependOutside(const QString & markup)1111 void QWebElement::prependOutside(const QString &markup)
1112 {
1113 if (!m_element)
1114 return;
1115
1116 if (!m_element->parentNode())
1117 return;
1118
1119 if (!m_element->isHTMLElement())
1120 return;
1121
1122 HTMLElement* htmlElement = static_cast<HTMLElement*>(m_element);
1123 RefPtr<DocumentFragment> fragment = htmlElement->deprecatedCreateContextualFragment(markup);
1124
1125 ExceptionCode exception = 0;
1126 m_element->parentNode()->insertBefore(fragment, m_element, exception);
1127 }
1128
1129 /*!
1130 Inserts the given \a element after this element.
1131
1132 If \a element is the child of another element, it is re-parented to the
1133 parent of this element.
1134
1135 Calling this function on a null element does nothing.
1136
1137 \sa appendInside(), prependInside(), prependOutside()
1138 */
appendOutside(const QWebElement & element)1139 void QWebElement::appendOutside(const QWebElement &element)
1140 {
1141 if (!m_element || element.isNull())
1142 return;
1143
1144 if (!m_element->parentNode())
1145 return;
1146
1147 ExceptionCode exception = 0;
1148 if (!m_element->nextSibling())
1149 m_element->parentNode()->appendChild(element.m_element, exception);
1150 else
1151 m_element->parentNode()->insertBefore(element.m_element, m_element->nextSibling(), exception);
1152 }
1153
1154 /*!
1155 Inserts the result of parsing \a markup after this element.
1156
1157 Calling this function on a null element does nothing.
1158
1159 \sa appendInside(), prependInside(), prependOutside()
1160 */
appendOutside(const QString & markup)1161 void QWebElement::appendOutside(const QString &markup)
1162 {
1163 if (!m_element)
1164 return;
1165
1166 if (!m_element->parentNode())
1167 return;
1168
1169 if (!m_element->isHTMLElement())
1170 return;
1171
1172 HTMLElement* htmlElement = static_cast<HTMLElement*>(m_element);
1173 RefPtr<DocumentFragment> fragment = htmlElement->deprecatedCreateContextualFragment(markup);
1174
1175 ExceptionCode exception = 0;
1176 if (!m_element->nextSibling())
1177 m_element->parentNode()->appendChild(fragment, exception);
1178 else
1179 m_element->parentNode()->insertBefore(fragment, m_element->nextSibling(), exception);
1180 }
1181
1182 /*!
1183 Returns a clone of this element.
1184
1185 The clone may be inserted at any point in the document.
1186
1187 \sa appendInside(), prependInside(), prependOutside(), appendOutside()
1188 */
clone() const1189 QWebElement QWebElement::clone() const
1190 {
1191 if (!m_element)
1192 return QWebElement();
1193
1194 return QWebElement(m_element->cloneElementWithChildren().get());
1195 }
1196
1197 /*!
1198 Removes this element from the document and returns a reference to it.
1199
1200 The element is still valid after removal, and can be inserted into other
1201 parts of the document.
1202
1203 \sa removeAllChildren(), removeFromDocument()
1204 */
takeFromDocument()1205 QWebElement &QWebElement::takeFromDocument()
1206 {
1207 if (!m_element)
1208 return *this;
1209
1210 ExceptionCode exception = 0;
1211 m_element->remove(exception);
1212
1213 return *this;
1214 }
1215
1216 /*!
1217 Removes this element from the document and makes it a null element.
1218
1219 \sa removeAllChildren(), takeFromDocument()
1220 */
removeFromDocument()1221 void QWebElement::removeFromDocument()
1222 {
1223 if (!m_element)
1224 return;
1225
1226 ExceptionCode exception = 0;
1227 m_element->remove(exception);
1228 m_element->deref();
1229 m_element = 0;
1230 }
1231
1232 /*!
1233 Removes all children from this element.
1234
1235 \sa removeFromDocument(), takeFromDocument()
1236 */
removeAllChildren()1237 void QWebElement::removeAllChildren()
1238 {
1239 if (!m_element)
1240 return;
1241
1242 m_element->removeAllChildren();
1243 }
1244
1245 // FIXME: This code, and all callers are wrong, and have no place in a
1246 // WebKit implementation. These should be replaced with WebCore implementations.
findInsertionPoint(PassRefPtr<Node> root)1247 static RefPtr<Node> findInsertionPoint(PassRefPtr<Node> root)
1248 {
1249 RefPtr<Node> node = root;
1250
1251 // Go as far down the tree as possible.
1252 while (node->hasChildNodes() && node->firstChild()->isElementNode())
1253 node = node->firstChild();
1254
1255 // TODO: Implement SVG support
1256 if (node->isHTMLElement()) {
1257 HTMLElement* element = static_cast<HTMLElement*>(node.get());
1258
1259 // The insert point could be a non-enclosable tag and it can thus
1260 // never have children, so go one up. Get the parent element, and not
1261 // note as a root note will always exist.
1262 if (element->ieForbidsInsertHTML())
1263 node = node->parentElement();
1264 }
1265
1266 return node;
1267 }
1268
1269 /*!
1270 Encloses the contents of this element with \a element. This element becomes
1271 the child of the deepest descendant within \a element.
1272
1273 ### illustration
1274
1275 \sa encloseWith()
1276 */
encloseContentsWith(const QWebElement & element)1277 void QWebElement::encloseContentsWith(const QWebElement &element)
1278 {
1279 if (!m_element || element.isNull())
1280 return;
1281
1282 RefPtr<Node> insertionPoint = findInsertionPoint(element.m_element);
1283
1284 if (!insertionPoint)
1285 return;
1286
1287 ExceptionCode exception = 0;
1288
1289 // reparent children
1290 for (RefPtr<Node> child = m_element->firstChild(); child;) {
1291 RefPtr<Node> next = child->nextSibling();
1292 insertionPoint->appendChild(child, exception);
1293 child = next;
1294 }
1295
1296 if (m_element->hasChildNodes())
1297 m_element->insertBefore(element.m_element, m_element->firstChild(), exception);
1298 else
1299 m_element->appendChild(element.m_element, exception);
1300 }
1301
1302 /*!
1303 Encloses the contents of this element with the result of parsing \a markup.
1304 This element becomes the child of the deepest descendant within \a markup.
1305
1306 \sa encloseWith()
1307 */
encloseContentsWith(const QString & markup)1308 void QWebElement::encloseContentsWith(const QString &markup)
1309 {
1310 if (!m_element)
1311 return;
1312
1313 if (!m_element->parentNode())
1314 return;
1315
1316 if (!m_element->isHTMLElement())
1317 return;
1318
1319 HTMLElement* htmlElement = static_cast<HTMLElement*>(m_element);
1320 RefPtr<DocumentFragment> fragment = htmlElement->deprecatedCreateContextualFragment(markup);
1321
1322 if (!fragment || !fragment->firstChild())
1323 return;
1324
1325 RefPtr<Node> insertionPoint = findInsertionPoint(fragment->firstChild());
1326
1327 if (!insertionPoint)
1328 return;
1329
1330 ExceptionCode exception = 0;
1331
1332 // reparent children
1333 for (RefPtr<Node> child = m_element->firstChild(); child;) {
1334 RefPtr<Node> next = child->nextSibling();
1335 insertionPoint->appendChild(child, exception);
1336 child = next;
1337 }
1338
1339 if (m_element->hasChildNodes())
1340 m_element->insertBefore(fragment, m_element->firstChild(), exception);
1341 else
1342 m_element->appendChild(fragment, exception);
1343 }
1344
1345 /*!
1346 Encloses this element with \a element. This element becomes the child of
1347 the deepest descendant within \a element.
1348
1349 \sa replace()
1350 */
encloseWith(const QWebElement & element)1351 void QWebElement::encloseWith(const QWebElement &element)
1352 {
1353 if (!m_element || element.isNull())
1354 return;
1355
1356 RefPtr<Node> insertionPoint = findInsertionPoint(element.m_element);
1357
1358 if (!insertionPoint)
1359 return;
1360
1361 // Keep reference to these two nodes before pulling out this element and
1362 // wrapping it in the fragment. The reason for doing it in this order is
1363 // that once the fragment has been added to the document it is empty, so
1364 // we no longer have access to the nodes it contained.
1365 Node* parent = m_element->parentNode();
1366 Node* siblingNode = m_element->nextSibling();
1367
1368 ExceptionCode exception = 0;
1369 insertionPoint->appendChild(m_element, exception);
1370
1371 if (!siblingNode)
1372 parent->appendChild(element.m_element, exception);
1373 else
1374 parent->insertBefore(element.m_element, siblingNode, exception);
1375 }
1376
1377 /*!
1378 Encloses this element with the result of parsing \a markup. This element
1379 becomes the child of the deepest descendant within \a markup.
1380
1381 \sa replace()
1382 */
encloseWith(const QString & markup)1383 void QWebElement::encloseWith(const QString &markup)
1384 {
1385 if (!m_element)
1386 return;
1387
1388 if (!m_element->parentNode())
1389 return;
1390
1391 if (!m_element->isHTMLElement())
1392 return;
1393
1394 HTMLElement* htmlElement = static_cast<HTMLElement*>(m_element);
1395 RefPtr<DocumentFragment> fragment = htmlElement->deprecatedCreateContextualFragment(markup);
1396
1397 if (!fragment || !fragment->firstChild())
1398 return;
1399
1400 RefPtr<Node> insertionPoint = findInsertionPoint(fragment->firstChild());
1401
1402 if (!insertionPoint)
1403 return;
1404
1405 // Keep reference to these two nodes before pulling out this element and
1406 // wrapping it in the fragment. The reason for doing it in this order is
1407 // that once the fragment has been added to the document it is empty, so
1408 // we no longer have access to the nodes it contained.
1409 Node* parent = m_element->parentNode();
1410 Node* siblingNode = m_element->nextSibling();
1411
1412 ExceptionCode exception = 0;
1413 insertionPoint->appendChild(m_element, exception);
1414
1415 if (!siblingNode)
1416 parent->appendChild(fragment, exception);
1417 else
1418 parent->insertBefore(fragment, siblingNode, exception);
1419 }
1420
1421 /*!
1422 Replaces this element with \a element.
1423
1424 This method will not replace the <html>, <head> or <body> elements.
1425
1426 \sa encloseWith()
1427 */
replace(const QWebElement & element)1428 void QWebElement::replace(const QWebElement &element)
1429 {
1430 if (!m_element || element.isNull())
1431 return;
1432
1433 appendOutside(element);
1434 takeFromDocument();
1435 }
1436
1437 /*!
1438 Replaces this element with the result of parsing \a markup.
1439
1440 This method will not replace the <html>, <head> or <body> elements.
1441
1442 \sa encloseWith()
1443 */
replace(const QString & markup)1444 void QWebElement::replace(const QString &markup)
1445 {
1446 if (!m_element)
1447 return;
1448
1449 appendOutside(markup);
1450 takeFromDocument();
1451 }
1452
1453 /*!
1454 \internal
1455 Walk \a node's parents until a valid QWebElement is found.
1456 For example, a WebCore::Text node is not a valid Html QWebElement, but its
1457 enclosing p tag is.
1458 */
enclosingElement(WebCore::Node * node)1459 QWebElement QWebElement::enclosingElement(WebCore::Node* node)
1460 {
1461 QWebElement element(node);
1462
1463 while (element.isNull() && node) {
1464 node = node->parentNode();
1465 element = QWebElement(node);
1466 }
1467 return element;
1468 }
1469
1470 /*!
1471 \fn inline bool QWebElement::operator==(const QWebElement& o) const;
1472
1473 Returns true if this element points to the same underlying DOM object as
1474 \a o; otherwise returns false.
1475 */
1476
1477 /*!
1478 \fn inline bool QWebElement::operator!=(const QWebElement& o) const;
1479
1480 Returns true if this element points to a different underlying DOM object
1481 than \a o; otherwise returns false.
1482 */
1483
1484
1485 /*!
1486 Render the element into \a painter .
1487 */
render(QPainter * painter)1488 void QWebElement::render(QPainter* painter)
1489 {
1490 render(painter, QRect());
1491 }
1492
1493 /*!
1494 Render the element into \a painter clipping to \a clip.
1495 */
render(QPainter * painter,const QRect & clip)1496 void QWebElement::render(QPainter* painter, const QRect& clip)
1497 {
1498 WebCore::Element* e = m_element;
1499 Document* doc = e ? e->document() : 0;
1500 if (!doc)
1501 return;
1502
1503 Frame* frame = doc->frame();
1504 if (!frame || !frame->view() || !frame->contentRenderer())
1505 return;
1506
1507 FrameView* view = frame->view();
1508
1509 view->updateLayoutAndStyleIfNeededRecursive();
1510
1511 IntRect rect = e->getRect();
1512
1513 if (rect.size().isEmpty())
1514 return;
1515
1516 QRect finalClipRect = rect;
1517 if (!clip.isEmpty())
1518 rect.intersect(clip.translated(rect.location()));
1519
1520 GraphicsContext context(painter);
1521
1522 context.save();
1523 context.translate(-rect.x(), -rect.y());
1524 painter->setClipRect(finalClipRect, Qt::IntersectClip);
1525 view->setNodeToDraw(e);
1526 view->paintContents(&context, finalClipRect);
1527 view->setNodeToDraw(0);
1528 context.restore();
1529 }
1530
1531 class QWebElementCollectionPrivate : public QSharedData
1532 {
1533 public:
1534 static QWebElementCollectionPrivate* create(const PassRefPtr<Node> &context, const QString &query);
1535
1536 RefPtr<NodeList> m_result;
1537
1538 private:
QWebElementCollectionPrivate()1539 inline QWebElementCollectionPrivate() {}
1540 };
1541
create(const PassRefPtr<Node> & context,const QString & query)1542 QWebElementCollectionPrivate* QWebElementCollectionPrivate::create(const PassRefPtr<Node> &context, const QString &query)
1543 {
1544 if (!context)
1545 return 0;
1546
1547 // Let WebKit do the hard work hehehe
1548 ExceptionCode exception = 0; // ###
1549 RefPtr<NodeList> nodes = context->querySelectorAll(query, exception);
1550 if (!nodes)
1551 return 0;
1552
1553 QWebElementCollectionPrivate* priv = new QWebElementCollectionPrivate;
1554 priv->m_result = nodes;
1555 return priv;
1556 }
1557
1558 /*!
1559 \class QWebElementCollection
1560 \since 4.6
1561 \brief The QWebElementCollection class represents a collection of web elements.
1562 \preliminary
1563
1564 Elements in a document can be selected using QWebElement::findAll() or using the
1565 QWebElement constructor. The collection is composed by choosing all elements in the
1566 document that match a specified CSS selector expression.
1567
1568 The number of selected elements is provided through the count() property. Individual
1569 elements can be retrieved by index using at().
1570
1571 It is also possible to iterate through all elements in the collection using Qt's foreach
1572 macro:
1573
1574 \code
1575 QWebElementCollection collection = document.findAll("p");
1576 foreach (QWebElement paraElement, collection) {
1577 ...
1578 }
1579 \endcode
1580 */
1581
1582 /*!
1583 Constructs an empty collection.
1584 */
QWebElementCollection()1585 QWebElementCollection::QWebElementCollection()
1586 {
1587 }
1588
1589 /*!
1590 Constructs a copy of \a other.
1591 */
QWebElementCollection(const QWebElementCollection & other)1592 QWebElementCollection::QWebElementCollection(const QWebElementCollection &other)
1593 : d(other.d)
1594 {
1595 }
1596
1597 /*!
1598 Constructs a collection of elements from the list of child elements of \a contextElement that
1599 match the specified CSS selector \a query.
1600 */
QWebElementCollection(const QWebElement & contextElement,const QString & query)1601 QWebElementCollection::QWebElementCollection(const QWebElement &contextElement, const QString &query)
1602 {
1603 d = QExplicitlySharedDataPointer<QWebElementCollectionPrivate>(QWebElementCollectionPrivate::create(contextElement.m_element, query));
1604 }
1605
1606 /*!
1607 Assigns \a other to this collection and returns a reference to this collection.
1608 */
operator =(const QWebElementCollection & other)1609 QWebElementCollection &QWebElementCollection::operator=(const QWebElementCollection &other)
1610 {
1611 d = other.d;
1612 return *this;
1613 }
1614
1615 /*!
1616 Destroys the collection.
1617 */
~QWebElementCollection()1618 QWebElementCollection::~QWebElementCollection()
1619 {
1620 }
1621
1622 /*! \fn QWebElementCollection &QWebElementCollection::operator+=(const QWebElementCollection &other)
1623
1624 Appends the items of the \a other list to this list and returns a
1625 reference to this list.
1626
1627 \sa operator+(), append()
1628 */
1629
1630 /*!
1631 Returns a collection that contains all the elements of this collection followed
1632 by all the elements in the \a other collection. Duplicates may occur in the result.
1633
1634 \sa operator+=()
1635 */
operator +(const QWebElementCollection & other) const1636 QWebElementCollection QWebElementCollection::operator+(const QWebElementCollection &other) const
1637 {
1638 QWebElementCollection n = *this; n.d.detach(); n += other; return n;
1639 }
1640
1641 /*!
1642 Extends the collection by appending all items of \a other.
1643
1644 The resulting collection may include duplicate elements.
1645
1646 \sa operator+=()
1647 */
append(const QWebElementCollection & other)1648 void QWebElementCollection::append(const QWebElementCollection &other)
1649 {
1650 if (!d) {
1651 *this = other;
1652 return;
1653 }
1654 if (!other.d)
1655 return;
1656 Vector<RefPtr<Node> > nodes;
1657 RefPtr<NodeList> results[] = { d->m_result, other.d->m_result };
1658 nodes.reserveInitialCapacity(results[0]->length() + results[1]->length());
1659
1660 for (int i = 0; i < 2; ++i) {
1661 int j = 0;
1662 Node* n = results[i]->item(j);
1663 while (n) {
1664 nodes.append(n);
1665 n = results[i]->item(++j);
1666 }
1667 }
1668
1669 d->m_result = StaticNodeList::adopt(nodes);
1670 }
1671
1672 /*!
1673 Returns the number of elements in the collection.
1674 */
count() const1675 int QWebElementCollection::count() const
1676 {
1677 if (!d)
1678 return 0;
1679 return d->m_result->length();
1680 }
1681
1682 /*!
1683 Returns the element at index position \a i in the collection.
1684 */
at(int i) const1685 QWebElement QWebElementCollection::at(int i) const
1686 {
1687 if (!d)
1688 return QWebElement();
1689 Node* n = d->m_result->item(i);
1690 return QWebElement(static_cast<Element*>(n));
1691 }
1692
1693 /*!
1694 \fn const QWebElement QWebElementCollection::operator[](int position) const
1695
1696 Returns the element at the specified \a position in the collection.
1697 */
1698
1699 /*! \fn QWebElement QWebElementCollection::first() const
1700
1701 Returns the first element in the collection.
1702
1703 \sa last(), operator[](), at(), count()
1704 */
1705
1706 /*! \fn QWebElement QWebElementCollection::last() const
1707
1708 Returns the last element in the collection.
1709
1710 \sa first(), operator[](), at(), count()
1711 */
1712
1713 /*!
1714 Returns a QList object with the elements contained in this collection.
1715 */
toList() const1716 QList<QWebElement> QWebElementCollection::toList() const
1717 {
1718 if (!d)
1719 return QList<QWebElement>();
1720 QList<QWebElement> elements;
1721 int i = 0;
1722 Node* n = d->m_result->item(i);
1723 while (n) {
1724 if (n->isElementNode())
1725 elements.append(QWebElement(static_cast<Element*>(n)));
1726 n = d->m_result->item(++i);
1727 }
1728 return elements;
1729 }
1730
1731 /*!
1732 \fn QWebElementCollection::const_iterator QWebElementCollection::begin() const
1733
1734 Returns an STL-style iterator pointing to the first element in the collection.
1735
1736 \sa end()
1737 */
1738
1739 /*!
1740 \fn QWebElementCollection::const_iterator QWebElementCollection::end() const
1741
1742 Returns an STL-style iterator pointing to the imaginary element after the
1743 last element in the list.
1744
1745 \sa begin()
1746 */
1747
1748 /*!
1749 \class QWebElementCollection::const_iterator
1750 \since 4.6
1751 \brief The QWebElementCollection::const_iterator class provides an STL-style const iterator for QWebElementCollection.
1752
1753 QWebElementCollection provides STL style const iterators for fast low-level access to the elements.
1754
1755 QWebElementCollection::const_iterator allows you to iterate over a QWebElementCollection.
1756 */
1757
1758 /*!
1759 \fn QWebElementCollection::const_iterator::const_iterator(const const_iterator &other)
1760
1761 Constructs a copy of \a other.
1762 */
1763
1764 /*!
1765 \fn QWebElementCollection::const_iterator::const_iterator(const QWebElementCollection *collection, int index)
1766 \internal
1767 */
1768
1769 /*!
1770 \fn const QWebElement QWebElementCollection::const_iterator::operator*() const
1771
1772 Returns the current element.
1773 */
1774
1775 /*!
1776 \fn bool QWebElementCollection::const_iterator::operator==(const const_iterator &other) const
1777
1778 Returns true if \a other points to the same item as this iterator;
1779 otherwise returns false.
1780
1781 \sa operator!=()
1782 */
1783
1784 /*!
1785 \fn bool QWebElementCollection::const_iterator::operator!=(const const_iterator &other) const
1786
1787 Returns true if \a other points to a different element than this;
1788 iterator; otherwise returns false.
1789
1790 \sa operator==()
1791 */
1792
1793 /*!
1794 \fn QWebElementCollection::const_iterator &QWebElementCollection::const_iterator::operator++()
1795
1796 The prefix ++ operator (\c{++it}) advances the iterator to the next element in the collection
1797 and returns an iterator to the new current element.
1798
1799 Calling this function on QWebElementCollection::end() leads to undefined results.
1800
1801 \sa operator--()
1802 */
1803
1804 /*!
1805 \fn QWebElementCollection::const_iterator QWebElementCollection::const_iterator::operator++(int)
1806
1807 \overload
1808
1809 The postfix ++ operator (\c{it++}) advances the iterator to the next element in the collection
1810 and returns an iterator to the previously current element.
1811
1812 Calling this function on QWebElementCollection::end() leads to undefined results.
1813 */
1814
1815 /*!
1816 \fn QWebElementCollection::const_iterator &QWebElementCollection::const_iterator::operator--()
1817
1818 The prefix -- operator (\c{--it}) makes the preceding element current and returns an
1819 iterator to the new current element.
1820
1821 Calling this function on QWebElementCollection::begin() leads to undefined results.
1822
1823 \sa operator++()
1824 */
1825
1826 /*!
1827 \fn QWebElementCollection::const_iterator QWebElementCollection::const_iterator::operator--(int)
1828
1829 \overload
1830
1831 The postfix -- operator (\c{it--}) makes the preceding element current and returns
1832 an iterator to the previously current element.
1833 */
1834
1835 /*!
1836 \fn QWebElementCollection::const_iterator &QWebElementCollection::const_iterator::operator+=(int j)
1837
1838 Advances the iterator by \a j elements. If \a j is negative, the iterator goes backward.
1839
1840 \sa operator-=(), operator+()
1841 */
1842
1843 /*!
1844 \fn QWebElementCollection::const_iterator &QWebElementCollection::const_iterator::operator-=(int j)
1845
1846 Makes the iterator go back by \a j elements. If \a j is negative, the iterator goes forward.
1847
1848 \sa operator+=(), operator-()
1849 */
1850
1851 /*!
1852 \fn QWebElementCollection::const_iterator QWebElementCollection::const_iterator::operator+(int j) const
1853
1854 Returns an iterator to the element at \a j positions forward from this iterator. If \a j
1855 is negative, the iterator goes backward.
1856
1857 \sa operator-(), operator+=()
1858 */
1859
1860 /*!
1861 \fn QWebElementCollection::const_iterator QWebElementCollection::const_iterator::operator-(int j) const
1862
1863 Returns an iterator to the element at \a j positiosn backward from this iterator.
1864 If \a j is negative, the iterator goes forward.
1865
1866 \sa operator+(), operator-=()
1867 */
1868
1869 /*!
1870 \fn int QWebElementCollection::const_iterator::operator-(const_iterator other) const
1871
1872 Returns the number of elements between the item point to by \a other
1873 and the element pointed to by this iterator.
1874 */
1875
1876 /*!
1877 \fn bool QWebElementCollection::const_iterator::operator<(const const_iterator &other) const
1878
1879 Returns true if the element pointed to by this iterator is less than the element pointed to
1880 by the \a other iterator.
1881 */
1882
1883 /*!
1884 \fn bool QWebElementCollection::const_iterator::operator<=(const const_iterator &other) const
1885
1886 Returns true if the element pointed to by this iterator is less than or equal to the
1887 element pointed to by the \a other iterator.
1888 */
1889
1890 /*!
1891 \fn bool QWebElementCollection::const_iterator::operator>(const const_iterator &other) const
1892
1893 Returns true if the element pointed to by this iterator is greater than the element pointed to
1894 by the \a other iterator.
1895 */
1896
1897 /*!
1898 \fn bool QWebElementCollection::const_iterator::operator>=(const const_iterator &other) const
1899
1900 Returns true if the element pointed to by this iterator is greater than or equal to the
1901 element pointed to by the \a other iterator.
1902 */
1903
1904 /*!
1905 \fn QWebElementCollection::iterator QWebElementCollection::begin()
1906
1907 Returns an STL-style iterator pointing to the first element in the collection.
1908
1909 \sa end()
1910 */
1911
1912 /*!
1913 \fn QWebElementCollection::iterator QWebElementCollection::end()
1914
1915 Returns an STL-style iterator pointing to the imaginary element after the
1916 last element in the list.
1917
1918 \sa begin()
1919 */
1920
1921 /*!
1922 \fn QWebElementCollection::const_iterator QWebElementCollection::constBegin() const
1923
1924 Returns an STL-style iterator pointing to the first element in the collection.
1925
1926 \sa end()
1927 */
1928
1929 /*!
1930 \fn QWebElementCollection::const_iterator QWebElementCollection::constEnd() const
1931
1932 Returns an STL-style iterator pointing to the imaginary element after the
1933 last element in the list.
1934
1935 \sa begin()
1936 */
1937
1938 /*!
1939 \class QWebElementCollection::iterator
1940 \since 4.6
1941 \brief The QWebElementCollection::iterator class provides an STL-style iterator for QWebElementCollection.
1942
1943 QWebElementCollection provides STL style iterators for fast low-level access to the elements.
1944
1945 QWebElementCollection::iterator allows you to iterate over a QWebElementCollection.
1946 */
1947
1948 /*!
1949 \fn QWebElementCollection::iterator::iterator(const iterator &other)
1950
1951 Constructs a copy of \a other.
1952 */
1953
1954 /*!
1955 \fn QWebElementCollection::iterator::iterator(const QWebElementCollection *collection, int index)
1956 \internal
1957 */
1958
1959 /*!
1960 \fn const QWebElement QWebElementCollection::iterator::operator*() const
1961
1962 Returns the current element.
1963 */
1964
1965 /*!
1966 \fn bool QWebElementCollection::iterator::operator==(const iterator &other) const
1967
1968 Returns true if \a other points to the same item as this iterator;
1969 otherwise returns false.
1970
1971 \sa operator!=()
1972 */
1973
1974 /*!
1975 \fn bool QWebElementCollection::iterator::operator!=(const iterator &other) const
1976
1977 Returns true if \a other points to a different element than this;
1978 iterator; otherwise returns false.
1979
1980 \sa operator==()
1981 */
1982
1983 /*!
1984 \fn QWebElementCollection::iterator &QWebElementCollection::iterator::operator++()
1985
1986 The prefix ++ operator (\c{++it}) advances the iterator to the next element in the collection
1987 and returns an iterator to the new current element.
1988
1989 Calling this function on QWebElementCollection::end() leads to undefined results.
1990
1991 \sa operator--()
1992 */
1993
1994 /*!
1995 \fn QWebElementCollection::iterator QWebElementCollection::iterator::operator++(int)
1996
1997 \overload
1998
1999 The postfix ++ operator (\c{it++}) advances the iterator to the next element in the collection
2000 and returns an iterator to the previously current element.
2001
2002 Calling this function on QWebElementCollection::end() leads to undefined results.
2003 */
2004
2005 /*!
2006 \fn QWebElementCollection::iterator &QWebElementCollection::iterator::operator--()
2007
2008 The prefix -- operator (\c{--it}) makes the preceding element current and returns an
2009 iterator to the new current element.
2010
2011 Calling this function on QWebElementCollection::begin() leads to undefined results.
2012
2013 \sa operator++()
2014 */
2015
2016 /*!
2017 \fn QWebElementCollection::iterator QWebElementCollection::iterator::operator--(int)
2018
2019 \overload
2020
2021 The postfix -- operator (\c{it--}) makes the preceding element current and returns
2022 an iterator to the previously current element.
2023 */
2024
2025 /*!
2026 \fn QWebElementCollection::iterator &QWebElementCollection::iterator::operator+=(int j)
2027
2028 Advances the iterator by \a j elements. If \a j is negative, the iterator goes backward.
2029
2030 \sa operator-=(), operator+()
2031 */
2032
2033 /*!
2034 \fn QWebElementCollection::iterator &QWebElementCollection::iterator::operator-=(int j)
2035
2036 Makes the iterator go back by \a j elements. If \a j is negative, the iterator goes forward.
2037
2038 \sa operator+=(), operator-()
2039 */
2040
2041 /*!
2042 \fn QWebElementCollection::iterator QWebElementCollection::iterator::operator+(int j) const
2043
2044 Returns an iterator to the element at \a j positions forward from this iterator. If \a j
2045 is negative, the iterator goes backward.
2046
2047 \sa operator-(), operator+=()
2048 */
2049
2050 /*!
2051 \fn QWebElementCollection::iterator QWebElementCollection::iterator::operator-(int j) const
2052
2053 Returns an iterator to the element at \a j positiosn backward from this iterator.
2054 If \a j is negative, the iterator goes forward.
2055
2056 \sa operator+(), operator-=()
2057 */
2058
2059 /*!
2060 \fn int QWebElementCollection::iterator::operator-(iterator other) const
2061
2062 Returns the number of elements between the item point to by \a other
2063 and the element pointed to by this iterator.
2064 */
2065
2066 /*!
2067 \fn bool QWebElementCollection::iterator::operator<(const iterator &other) const
2068
2069 Returns true if the element pointed to by this iterator is less than the element pointed to
2070 by the \a other iterator.
2071 */
2072
2073 /*!
2074 \fn bool QWebElementCollection::iterator::operator<=(const iterator &other) const
2075
2076 Returns true if the element pointed to by this iterator is less than or equal to the
2077 element pointed to by the \a other iterator.
2078 */
2079
2080 /*!
2081 \fn bool QWebElementCollection::iterator::operator>(const iterator &other) const
2082
2083 Returns true if the element pointed to by this iterator is greater than the element pointed to
2084 by the \a other iterator.
2085 */
2086
2087 /*!
2088 \fn bool QWebElementCollection::iterator::operator>=(const iterator &other) const
2089
2090 Returns true if the element pointed to by this iterator is greater than or equal to the
2091 element pointed to by the \a other iterator.
2092 */
2093