fix logic
[personal-kdelibs.git] / khtml / html / html_tableimpl.cpp
blobd92c3346c9465783f3aa52235f0ca78225ccec34
1 /**
2 * This file is part of the DOM implementation for KDE.
4 * Copyright (C) 1997 Martin Jones (mjones@kde.org)
5 * (C) 1997 Torben Weis (weis@kde.org)
6 * (C) 1998 Waldo Bastian (bastian@kde.org)
7 * (C) 1999-2003 Lars Knoll (knoll@kde.org)
8 * (C) 1999 Antti Koivisto (koivisto@kde.org)
9 * (C) 2003 Apple Computer, Inc.
10 * (C) 2006 Maksim Orlovich (maksim@kde.org)
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public License
23 * along with this library; see the file COPYING.LIB. If not, write to
24 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 * Boston, MA 02110-1301, USA.
28 #include "html_tableimpl.h"
30 #include "html_documentimpl.h"
32 #include <dom/dom_exception.h>
33 #include <dom/dom_node.h>
35 #include <misc/htmlhashes.h>
36 #include <khtmlview.h>
37 #include <khtml_part.h>
39 #include <css/cssstyleselector.h>
40 #include <css/cssproperties.h>
41 #include <css/cssvalues.h>
42 #include <css/csshelper.h>
44 #include <rendering/render_table.h>
46 #include <kdebug.h>
47 #include <kglobal.h>
49 using namespace khtml;
50 using namespace DOM;
52 HTMLTableElementImpl::HTMLTableElementImpl(DocumentImpl *doc)
53 : HTMLElementImpl(doc)
55 rules = None;
56 frame = Void;
58 padding = 1;
60 m_solid = false;
63 HTMLTableElementImpl::~HTMLTableElementImpl()
67 NodeImpl::Id HTMLTableElementImpl::id() const
69 return ID_TABLE;
72 NodeImpl* HTMLTableElementImpl::setCaption( HTMLTableCaptionElementImpl *c )
74 int exceptioncode = 0;
75 NodeImpl* r;
76 if(ElementImpl* cap = caption()) {
77 replaceChild ( c, cap, exceptioncode );
78 r = c;
80 else
81 r = insertBefore( c, firstChild(), exceptioncode );
82 tCaption = c;
83 return r;
86 NodeImpl* HTMLTableElementImpl::setTHead( HTMLTableSectionElementImpl *s )
88 int exceptioncode = 0;
89 NodeImpl* r;
90 if( ElementImpl* head = tHead() ) {
91 replaceChild( s, head, exceptioncode );
92 r = s;
94 else if(ElementImpl* foot = tFoot())
95 r = insertBefore( s, foot, exceptioncode );
96 else if(ElementImpl* firstBody = tFirstBody())
97 r = insertBefore( s, firstBody, exceptioncode );
98 else
99 r = appendChild( s, exceptioncode );
101 head = s;
102 return r;
105 NodeImpl* HTMLTableElementImpl::setTFoot( HTMLTableSectionElementImpl *s )
107 int exceptioncode = 0;
108 NodeImpl* r;
109 if(ElementImpl* foot = tFoot()) {
110 replaceChild ( s, foot, exceptioncode );
111 r = s;
112 } else if(ElementImpl* firstBody = tFirstBody())
113 r = insertBefore( s, firstBody, exceptioncode );
114 else
115 r = appendChild( s, exceptioncode );
116 foot = s;
117 return r;
120 NodeImpl* HTMLTableElementImpl::setTBody( HTMLTableSectionElementImpl *s )
122 int exceptioncode = 0;
123 NodeImpl* r;
125 if(ElementImpl* firstBody = tFirstBody()) {
126 replaceChild ( s, firstBody, exceptioncode );
127 r = s;
128 } else
129 r = appendChild( s, exceptioncode );
130 firstBody = s;
132 return r;
135 HTMLElementImpl *HTMLTableElementImpl::createTHead( )
137 if(!tHead())
139 int exceptioncode = 0;
140 ElementImpl* head = new HTMLTableSectionElementImpl(docPtr(), ID_THEAD, true /* implicit */);
141 if(ElementImpl* foot = tFoot())
142 insertBefore( head, foot, exceptioncode );
143 else if(ElementImpl* firstBody = tFirstBody())
144 insertBefore( head, firstBody, exceptioncode);
145 else
146 appendChild(head, exceptioncode);
148 return tHead();
151 void HTMLTableElementImpl::deleteTHead( )
153 if(ElementImpl* head = tHead()) {
154 int exceptioncode = 0;
155 removeChild(head, exceptioncode);
159 HTMLElementImpl *HTMLTableElementImpl::createTFoot( )
161 if(!tFoot())
163 int exceptioncode = 0;
164 ElementImpl* foot = new HTMLTableSectionElementImpl(docPtr(), ID_TFOOT, true /*implicit */);
165 if(ElementImpl* firstBody = tFirstBody())
166 insertBefore( foot, firstBody, exceptioncode );
167 else
168 appendChild(foot, exceptioncode);
170 return tFoot();
173 void HTMLTableElementImpl::deleteTFoot( )
175 if(ElementImpl* foot = tFoot()) {
176 int exceptioncode = 0;
177 removeChild(foot, exceptioncode);
181 HTMLElementImpl *HTMLTableElementImpl::createCaption( )
183 if(!caption())
185 int exceptioncode = 0;
186 ElementImpl* tCaption = new HTMLTableCaptionElementImpl(docPtr());
187 insertBefore( tCaption, firstChild(), exceptioncode );
189 return caption();
192 void HTMLTableElementImpl::deleteCaption( )
194 if(ElementImpl* tCaption = caption()) {
195 int exceptioncode = 0;
196 removeChild(tCaption, exceptioncode);
201 Helper. This checks whether the section contains the desired index, and if so,
202 returns the section. Otherwise, it adjust the index, and returns 0.
203 indices < 0 are considered to be infinite.
205 lastSection is adjusted to reflect the parameter passed in.
207 static inline HTMLTableSectionElementImpl* processSection(HTMLTableSectionElementImpl* section,
208 HTMLTableSectionElementImpl* &lastSection, long& index)
210 lastSection = section;
211 if ( index < 0 ) //append/last mode
212 return 0;
214 long rows = section->numRows();
215 if ( index >= rows ) {
216 section = 0;
217 index -= rows;
219 return section;
223 bool HTMLTableElementImpl::findRowSection(long index,
224 HTMLTableSectionElementImpl*& outSection,
225 long& outIndex) const
227 HTMLTableSectionElementImpl* foot = tFoot();
228 HTMLTableSectionElementImpl* head = tHead();
230 HTMLTableSectionElementImpl* section = 0L;
231 HTMLTableSectionElementImpl* lastSection = 0L;
233 if ( head )
234 section = processSection( head, lastSection, index );
236 if ( !section ) {
237 for ( NodeImpl *node = firstChild(); node; node = node->nextSibling() ) {
238 if ( ( node->id() == ID_THEAD || node->id() == ID_TFOOT || node->id() == ID_TBODY ) &&
239 node != foot && node != head ) {
240 section = processSection( static_cast<HTMLTableSectionElementImpl *>(node),
241 lastSection, index );
242 if ( section )
243 break;
248 if ( !section && foot )
249 section = processSection( foot, lastSection, index );
251 outIndex = index;
252 if ( section ) {
253 outSection = section;
254 return true;
255 } else {
256 outSection = lastSection;
257 return false;
261 HTMLElementImpl *HTMLTableElementImpl::insertRow( long index, int &exceptioncode )
263 // The DOM requires that we create a tbody if the table is empty
264 // (cf DOM2TS HTMLTableElement31 test). This includes even the cases where
265 // there are <tr>'s immediately under the table, as they're essentially
266 // ignored by these functions.
267 HTMLTableSectionElementImpl* foot = tFoot();
268 HTMLTableSectionElementImpl* head = tHead();
269 if(!tFirstBody() && !foot && !head)
270 setTBody( new HTMLTableSectionElementImpl(docPtr(), ID_TBODY, true /* implicit */) );
272 //kDebug(6030) << index;
274 long sectionIndex;
275 HTMLTableSectionElementImpl* section;
276 if ( findRowSection( index, section, sectionIndex ) )
277 return section->insertRow( sectionIndex, exceptioncode );
278 else if ( index == -1 || sectionIndex == 0 )
279 return section->insertRow( section->numRows(), exceptioncode );
281 // The index is too big.
282 exceptioncode = DOMException::INDEX_SIZE_ERR;
283 return 0L;
286 void HTMLTableElementImpl::deleteRow( long index, int &exceptioncode )
288 long sectionIndex;
289 HTMLTableSectionElementImpl* section;
290 if ( findRowSection( index, section, sectionIndex ) )
291 section->deleteRow( sectionIndex, exceptioncode );
292 else if ( section && index == -1 )
293 section->deleteRow( -1, exceptioncode );
294 else
295 exceptioncode = DOMException::INDEX_SIZE_ERR;
298 NodeImpl *HTMLTableElementImpl::appendChild(NodeImpl *child, int &exceptioncode)
300 NodeImpl* retval = HTMLElementImpl::appendChild( child, exceptioncode );
301 if(retval)
302 handleChildAppend( child );
303 return retval;
306 void HTMLTableElementImpl::handleChildAdd( NodeImpl *child )
308 if (!child) return;
309 switch(child->id()) {
310 case ID_CAPTION:
311 tCaption.childAdded(this, child);
312 break;
313 case ID_THEAD:
314 head.childAdded(this, child);
315 break;
316 case ID_TFOOT:
317 foot.childAdded(this, child);
318 break;
319 case ID_TBODY:
320 firstBody.childAdded(this, child);
321 break;
325 void HTMLTableElementImpl::handleChildAppend( NodeImpl *child )
327 if (!child) return;
328 switch(child->id()) {
329 case ID_CAPTION:
330 tCaption.childAppended(child);
331 break;
332 case ID_THEAD:
333 head.childAppended(child);
334 break;
335 case ID_TFOOT:
336 foot.childAppended(child);
337 break;
338 case ID_TBODY:
339 firstBody.childAppended(child);
340 break;
344 void HTMLTableElementImpl::handleChildRemove( NodeImpl *child )
346 if (!child) return;
347 switch(child->id()) {
348 case ID_CAPTION:
349 tCaption.childRemoved(this, child);
350 break;
351 case ID_THEAD:
352 head.childRemoved(this, child);
353 break;
354 case ID_TFOOT:
355 foot.childRemoved(this, child);
356 break;
357 case ID_TBODY:
358 firstBody.childRemoved(this, child);
359 break;
363 NodeImpl *HTMLTableElementImpl::addChild(NodeImpl *child)
365 #ifdef DEBUG_LAYOUT
366 kDebug( 6030 ) << nodeName().string() << "(Table)::addChild( " << child->nodeName().string() << " )";
367 #endif
369 NodeImpl *retval = HTMLElementImpl::addChild( child );
370 if ( retval )
371 handleChildAppend( child );
373 return retval;
376 NodeImpl *HTMLTableElementImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode )
378 NodeImpl* retval = HTMLElementImpl::insertBefore( newChild, refChild, exceptioncode);
379 if (retval)
380 handleChildAdd( newChild );
382 return retval;
385 void HTMLTableElementImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode )
387 handleChildRemove( oldChild ); //Always safe.
388 HTMLElementImpl::replaceChild( newChild, oldChild, exceptioncode );
389 if ( !exceptioncode )
390 handleChildAdd( newChild );
393 void HTMLTableElementImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode )
395 handleChildRemove( oldChild );
396 HTMLElementImpl::removeChild( oldChild, exceptioncode);
399 static inline bool isTableCellAncestor(NodeImpl* n)
401 return n->id() == ID_THEAD || n->id() == ID_TBODY ||
402 n->id() == ID_TFOOT || n->id() == ID_TR;
405 static bool setTableCellsChanged(NodeImpl* n)
407 assert(n);
408 bool cellChanged = false;
410 if (n->id() == ID_TD || n->id() == ID_TH)
411 cellChanged = true;
412 else if (isTableCellAncestor(n)) {
413 for (NodeImpl* child = n->firstChild(); child; child = child->nextSibling())
414 cellChanged |= setTableCellsChanged(child);
417 if (cellChanged)
418 n->setChanged();
420 return cellChanged;
423 void HTMLTableElementImpl::parseAttribute(AttributeImpl *attr)
425 // ### to CSS!!
426 switch(attr->id())
428 case ATTR_WIDTH:
429 if (!attr->value().isEmpty())
430 addCSSLength( CSS_PROP_WIDTH, attr->value() );
431 else
432 removeCSSProperty(CSS_PROP_WIDTH);
433 break;
434 case ATTR_HEIGHT:
435 if (!attr->value().isEmpty())
436 addCSSLength(CSS_PROP_HEIGHT, attr->value());
437 else
438 removeCSSProperty(CSS_PROP_HEIGHT);
439 break;
440 case ATTR_BORDER:
442 int border;
443 bool ok = true;
444 // ### this needs more work, as the border value is not only
445 // the border of the box, but also between the cells
446 if(!attr->val())
447 border = 0;
448 else if(attr->val()->l == 0)
449 border = 1;
450 else
451 border = attr->val()->toInt(&ok);
452 if (!ok)
453 border = 1;
454 #ifdef DEBUG_DRAW_BORDER
455 border=1;
456 #endif
457 DOMString v = QString::number( border );
458 addCSSLength(CSS_PROP_BORDER_WIDTH, v );
460 attr->rewriteValue( v );
462 // wanted by HTML4 specs
463 if(!border)
464 frame = Void, rules = None;
465 else
466 frame = Box, rules = All;
468 if (attached()) {
469 updateFrame();
470 if (tFirstBody())
471 setTableCellsChanged(tFirstBody());
473 break;
475 case ATTR_BGCOLOR:
476 if (!attr->value().isEmpty())
477 addHTMLColor(CSS_PROP_BACKGROUND_COLOR, attr->value());
478 else
479 removeCSSProperty(CSS_PROP_BACKGROUND_COLOR);
480 break;
481 case ATTR_BORDERCOLOR:
482 if(!attr->value().isEmpty()) {
483 addHTMLColor(CSS_PROP_BORDER_COLOR, attr->value());
484 m_solid = true;
487 if (attached()) updateFrame();
488 break;
489 case ATTR_BACKGROUND:
491 if (!attr->value().isEmpty()) {
492 QString url = khtml::parseURL( attr->value() ).string();
493 url = document()->completeURL( url );
494 addCSSProperty(CSS_PROP_BACKGROUND_IMAGE, DOMString("url('"+url+"')") );
496 else
497 removeCSSProperty(CSS_PROP_BACKGROUND_IMAGE);
498 break;
500 case ATTR_FRAME:
502 if ( strcasecmp( attr->value(), "void" ) == 0 )
503 frame = Void;
504 else if ( strcasecmp( attr->value(), "border" ) == 0 )
505 frame = Box;
506 else if ( strcasecmp( attr->value(), "box" ) == 0 )
507 frame = Box;
508 else if ( strcasecmp( attr->value(), "hsides" ) == 0 )
509 frame = Hsides;
510 else if ( strcasecmp( attr->value(), "vsides" ) == 0 )
511 frame = Vsides;
512 else if ( strcasecmp( attr->value(), "above" ) == 0 )
513 frame = Above;
514 else if ( strcasecmp( attr->value(), "below" ) == 0 )
515 frame = Below;
516 else if ( strcasecmp( attr->value(), "lhs" ) == 0 )
517 frame = Lhs;
518 else if ( strcasecmp( attr->value(), "rhs" ) == 0 )
519 frame = Rhs;
521 if (attached()) updateFrame();
522 break;
523 case ATTR_RULES:
524 if ( strcasecmp( attr->value(), "none" ) == 0 )
525 rules = None;
526 else if ( strcasecmp( attr->value(), "groups" ) == 0 )
527 rules = Groups;
528 else if ( strcasecmp( attr->value(), "rows" ) == 0 )
529 rules = Rows;
530 else if ( strcasecmp( attr->value(), "cols" ) == 0 )
531 rules = Cols;
532 else if ( strcasecmp( attr->value(), "all" ) == 0 )
533 rules = All;
535 if (attached() && tFirstBody())
536 if (setTableCellsChanged(tFirstBody()))
537 setChanged();
538 break;
539 case ATTR_CELLSPACING:
540 if (!attr->value().isEmpty())
541 addCSSLength(CSS_PROP_BORDER_SPACING, attr->value(), true);
542 else
543 removeCSSProperty(CSS_PROP_BORDER_SPACING);
544 break;
545 case ATTR_CELLPADDING:
546 if (!attr->value().isEmpty())
547 padding = qMax( 0, attr->value().toInt() );
548 else
549 padding = 1;
550 if (m_render && m_render->isTable()) {
551 static_cast<RenderTable *>(m_render)->setCellPadding(padding);
552 if (!m_render->needsLayout())
553 m_render->setNeedsLayout(true);
555 break;
556 case ATTR_COLS:
558 // ###
559 #if 0
560 int c;
561 c = attr->val()->toInt();
562 addColumns(c-totalCols);
563 #endif
564 break;
567 case ATTR_ALIGN:
568 setChanged();
569 break;
570 case ATTR_VALIGN:
571 if (!attr->value().isEmpty())
572 addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower());
573 else
574 removeCSSProperty(CSS_PROP_VERTICAL_ALIGN);
575 break;
576 case ATTR_NOSAVE:
577 break;
578 default:
579 HTMLElementImpl::parseAttribute(attr);
583 void HTMLTableElementImpl::attach()
585 updateFrame();
586 HTMLElementImpl::attach();
587 if ( m_render && m_render->isTable() )
588 static_cast<RenderTable *>(m_render)->setCellPadding( padding );
591 void HTMLTableElementImpl::close()
593 ElementImpl* firstBody = tFirstBody();
594 if (firstBody && !firstBody->closed())
595 firstBody->close();
596 HTMLElementImpl::close();
599 void HTMLTableElementImpl::updateFrame()
601 int v = m_solid ? CSS_VAL_SOLID : CSS_VAL_OUTSET;
602 if ( frame & Above )
603 addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, v);
604 else
605 addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_NONE);
606 if ( frame & Below )
607 addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, v);
608 else
609 addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_NONE);
610 if ( frame & Lhs )
611 addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, v);
612 else
613 addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_NONE);
614 if ( frame & Rhs )
615 addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, v);
616 else
617 addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_NONE);
620 // --------------------------------------------------------------------------
622 void HTMLTablePartElementImpl::parseAttribute(AttributeImpl *attr)
624 switch(attr->id())
626 case ATTR_BGCOLOR:
627 if (attr->val())
628 addHTMLColor(CSS_PROP_BACKGROUND_COLOR, attr->value() );
629 else
630 removeCSSProperty(CSS_PROP_BACKGROUND_COLOR);
631 break;
632 case ATTR_BACKGROUND:
634 if (attr->val()) {
635 QString url = khtml::parseURL( attr->value() ).string();
636 url = document()->completeURL( url );
637 addCSSProperty(CSS_PROP_BACKGROUND_IMAGE, DOMString("url('"+url+"')") );
639 else
640 removeCSSProperty(CSS_PROP_BACKGROUND_IMAGE);
641 break;
643 case ATTR_BORDERCOLOR:
645 if(!attr->value().isEmpty()) {
646 addHTMLColor(CSS_PROP_BORDER_COLOR, attr->value());
647 addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_SOLID);
648 addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_SOLID);
649 addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_SOLID);
650 addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_SOLID);
652 break;
654 case ATTR_ALIGN:
656 DOMString v = attr->value();
657 if ( strcasecmp( attr->value(), "middle" ) == 0 || strcasecmp( attr->value(), "center" ) == 0 )
658 addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_CENTER);
659 else if (strcasecmp(attr->value(), "absmiddle") == 0)
660 addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL_CENTER);
661 else if (strcasecmp(attr->value(), "left") == 0)
662 addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_LEFT);
663 else if (strcasecmp(attr->value(), "right") == 0)
664 addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_RIGHT);
665 else
666 addCSSProperty(CSS_PROP_TEXT_ALIGN, v);
667 break;
669 case ATTR_VALIGN:
671 if (!attr->value().isEmpty())
672 addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower());
673 else
674 removeCSSProperty(CSS_PROP_VERTICAL_ALIGN);
675 break;
677 case ATTR_HEIGHT:
678 if (!attr->value().isEmpty())
679 addCSSLength(CSS_PROP_HEIGHT, attr->value());
680 else
681 removeCSSProperty(CSS_PROP_HEIGHT);
682 break;
683 case ATTR_NOSAVE:
684 break;
685 default:
686 HTMLElementImpl::parseAttribute(attr);
690 // -------------------------------------------------------------------------
692 HTMLTableSectionElementImpl::HTMLTableSectionElementImpl(DocumentImpl *doc,
693 ushort tagid, bool implicit)
694 : HTMLTablePartElementImpl(doc)
696 _id = tagid;
697 m_implicit = implicit;
700 HTMLTableSectionElementImpl::~HTMLTableSectionElementImpl()
704 NodeImpl::Id HTMLTableSectionElementImpl::id() const
706 return _id;
709 // these functions are rather slow, since we need to get the row at
710 // the index... but they aren't used during usual HTML parsing anyway
711 HTMLElementImpl *HTMLTableSectionElementImpl::insertRow( long index, int& exceptioncode )
713 HTMLTableRowElementImpl *r = 0L;
714 HTMLCollectionImpl rows(const_cast<HTMLTableSectionElementImpl*>(this), HTMLCollectionImpl::TSECTION_ROWS);
715 int numRows = rows.length();
716 //kDebug(6030) << "index=" << index << " numRows=" << numRows;
717 if ( index < -1 || index > numRows ) {
718 exceptioncode = DOMException::INDEX_SIZE_ERR; // per the DOM
720 else
722 r = new HTMLTableRowElementImpl(docPtr());
723 if ( numRows == index || index == -1 )
724 appendChild(r, exceptioncode);
725 else {
726 NodeImpl *n;
727 if(index < 1)
728 n = firstChild();
729 else
730 n = rows.item(index);
731 insertBefore(r, n, exceptioncode );
734 return r;
737 void HTMLTableSectionElementImpl::deleteRow( long index, int &exceptioncode )
739 HTMLCollectionImpl rows(const_cast<HTMLTableSectionElementImpl*>(this), HTMLCollectionImpl::TSECTION_ROWS);
740 int numRows = rows.length();
741 if ( index == -1 ) index = numRows - 1;
742 if( index >= 0 && index < numRows )
743 HTMLElementImpl::removeChild(rows.item(index), exceptioncode);
744 else
745 exceptioncode = DOMException::INDEX_SIZE_ERR;
749 int HTMLTableSectionElementImpl::numRows() const
751 HTMLCollectionImpl rows(const_cast<HTMLTableSectionElementImpl*>(this), HTMLCollectionImpl::TSECTION_ROWS);
752 return rows.length();
755 // -------------------------------------------------------------------------
757 NodeImpl::Id HTMLTableRowElementImpl::id() const
759 return ID_TR;
762 long HTMLTableRowElementImpl::rowIndex() const
764 int rIndex = 0;
766 NodeImpl *table = parentNode();
767 if ( !table )
768 return -1;
769 table = table->parentNode();
770 if ( !table || table->id() != ID_TABLE )
771 return -1;
773 HTMLTableSectionElementImpl *head = static_cast<HTMLTableElementImpl *>(table)->tHead();
774 HTMLTableSectionElementImpl *foot = static_cast<HTMLTableElementImpl *>(table)->tFoot();
776 if ( head ) {
777 const NodeImpl *row = head->firstChild();
778 while ( row ) {
779 if ( row == this )
780 return rIndex;
781 if (row->id() == ID_TR)
782 rIndex++;
783 row = row->nextSibling();
787 NodeImpl *node = table->firstChild();
788 while ( node ) {
789 if ( node != foot && node != head && (node->id() == ID_THEAD || node->id() == ID_TFOOT || node->id() == ID_TBODY) ) {
790 HTMLTableSectionElementImpl* section = static_cast<HTMLTableSectionElementImpl *>(node);
791 const NodeImpl *row = section->firstChild();
792 while ( row ) {
793 if ( row == this )
794 return rIndex;
795 if (row->id() == ID_TR)
796 rIndex++;
797 row = row->nextSibling();
800 node = node->nextSibling();
802 const NodeImpl *row = foot->firstChild();
803 while ( row ) {
804 if ( row == this )
805 return rIndex;
806 if (row->id() == ID_TR)
807 rIndex++;
808 row = row->nextSibling();
810 // should never happen
811 return -1;
814 long HTMLTableRowElementImpl::sectionRowIndex() const
816 int rIndex = 0;
817 const NodeImpl *n = this;
818 do {
819 n = n->previousSibling();
820 if (n && n->id() == ID_TR)
821 rIndex++;
823 while (n);
825 return rIndex;
828 HTMLElementImpl *HTMLTableRowElementImpl::insertCell( long index, int &exceptioncode )
830 HTMLTableCellElementImpl *c = 0L;
831 HTMLCollectionImpl children(const_cast<HTMLTableRowElementImpl*>(this), HTMLCollectionImpl::TR_CELLS);
832 int numCells = children.length();
833 if ( index < -1 || index > numCells )
834 exceptioncode = DOMException::INDEX_SIZE_ERR; // per the DOM
835 else
837 c = new HTMLTableCellElementImpl(docPtr(), ID_TD);
838 if(numCells == index || index == -1)
839 appendChild(c, exceptioncode);
840 else {
841 NodeImpl *n;
842 if(index < 1)
843 n = firstChild();
844 else
845 n = children.item(index);
846 insertBefore(c, n, exceptioncode);
849 return c;
852 void HTMLTableRowElementImpl::deleteCell( long index, int &exceptioncode )
854 HTMLCollectionImpl children(const_cast<HTMLTableRowElementImpl*>(this), HTMLCollectionImpl::TR_CELLS);
855 int numCells = children.length();
856 if ( index == -1 ) index = numCells-1;
857 if( index >= 0 && index < numCells )
858 HTMLElementImpl::removeChild(children.item(index), exceptioncode);
859 else
860 exceptioncode = DOMException::INDEX_SIZE_ERR;
863 // -------------------------------------------------------------------------
865 HTMLTableCellElementImpl::HTMLTableCellElementImpl(DocumentImpl *doc, int tag)
866 : HTMLTablePartElementImpl(doc)
868 _col = -1;
869 _row = -1;
870 cSpan = rSpan = 1;
871 _id = tag;
872 rowHeight = 0;
873 m_solid = false;
876 HTMLTableCellElementImpl::~HTMLTableCellElementImpl()
880 long HTMLTableCellElementImpl::cellIndex() const
882 int index = 0;
883 for (const NodeImpl * node = previousSibling(); node; node = node->previousSibling()) {
884 if (node->id() == ID_TD || node->id() == ID_TH)
885 index++;
888 return index;
891 void HTMLTableCellElementImpl::parseAttribute(AttributeImpl *attr)
893 switch(attr->id())
895 case ATTR_BORDER:
896 // euhm? not supported by other browsers as far as I can see (Dirk)
897 //addCSSLength(CSS_PROP_BORDER_WIDTH, attr->value());
898 break;
899 case ATTR_ROWSPAN:
900 rSpan = attr->val() ? attr->val()->toInt() : 1;
901 // limit this to something not causing an overflow with short int
902 if(rSpan < 1 || rSpan > 1024) rSpan = 1;
903 if (renderer())
904 renderer()->updateFromElement();
905 break;
906 case ATTR_COLSPAN:
907 cSpan = attr->val() ? attr->val()->toInt() : 1;
908 // limit this to something not causing an overflow with short int
909 if(cSpan < 1 || cSpan > 1024) cSpan = 1;
910 if (renderer())
911 renderer()->updateFromElement();
912 break;
913 case ATTR_NOWRAP:
914 if (attr->val() != 0)
915 addCSSProperty(CSS_PROP_WHITE_SPACE, CSS_VAL__KHTML_NOWRAP);
916 else
917 removeCSSProperty(CSS_PROP_WHITE_SPACE);
918 break;
919 case ATTR_WIDTH:
920 if (!attr->value().isEmpty())
921 addCSSLength( CSS_PROP_WIDTH, attr->value() );
922 else
923 removeCSSProperty(CSS_PROP_WIDTH);
924 break;
925 case ATTR_NOSAVE:
926 break;
927 default:
928 HTMLTablePartElementImpl::parseAttribute(attr);
932 void HTMLTableCellElementImpl::attach()
934 HTMLTablePartElementImpl::attach();
937 // -------------------------------------------------------------------------
939 HTMLTableColElementImpl::HTMLTableColElementImpl(DocumentImpl *doc, ushort i)
940 : HTMLTablePartElementImpl(doc)
942 _id = i;
943 _span = 1;
946 NodeImpl::Id HTMLTableColElementImpl::id() const
948 return _id;
952 void HTMLTableColElementImpl::parseAttribute(AttributeImpl *attr)
954 switch(attr->id())
956 case ATTR_SPAN:
957 _span = attr->val() ? attr->val()->toInt() : 1;
958 if (_span < 1) _span = 1;
959 break;
960 case ATTR_WIDTH:
961 if (!attr->value().isEmpty())
962 addCSSLength(CSS_PROP_WIDTH, attr->value(), false, true );
963 else
964 removeCSSProperty(CSS_PROP_WIDTH);
965 break;
966 case ATTR_VALIGN:
967 if (!attr->value().isEmpty())
968 addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower());
969 else
970 removeCSSProperty(CSS_PROP_VERTICAL_ALIGN);
971 break;
972 default:
973 HTMLTablePartElementImpl::parseAttribute(attr);
978 // -------------------------------------------------------------------------
980 NodeImpl::Id HTMLTableCaptionElementImpl::id() const
982 return ID_CAPTION;
986 void HTMLTableCaptionElementImpl::parseAttribute(AttributeImpl *attr)
988 switch(attr->id())
990 case ATTR_ALIGN:
991 if (!attr->value().isEmpty())
992 addCSSProperty(CSS_PROP_CAPTION_SIDE, attr->value().lower());
993 else
994 removeCSSProperty(CSS_PROP_CAPTION_SIDE);
995 break;
996 default:
997 HTMLElementImpl::parseAttribute(attr);