summaryrefslogtreecommitdiffstats
path: root/tdehtml/html/html_tableimpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tdehtml/html/html_tableimpl.cpp')
-rw-r--r--tdehtml/html/html_tableimpl.cpp994
1 files changed, 994 insertions, 0 deletions
diff --git a/tdehtml/html/html_tableimpl.cpp b/tdehtml/html/html_tableimpl.cpp
new file mode 100644
index 000000000..3fc4ba757
--- /dev/null
+++ b/tdehtml/html/html_tableimpl.cpp
@@ -0,0 +1,994 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1997 Martin Jones (mjones@kde.org)
+ * (C) 1997 Torben Weis (weis@kde.org)
+ * (C) 1998 Waldo Bastian (bastian@kde.org)
+ * (C) 1999-2003 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2003 Apple Computer, Inc.
+ * (C) 2006 Maksim Orlovich (maksim@kde.org)
+ *
+ * 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.
+ */
+
+#include "html/html_documentimpl.h"
+#include "html/html_tableimpl.h"
+
+#include "dom/dom_exception.h"
+#include "dom/dom_node.h"
+
+#include "misc/htmlhashes.h"
+#include "tdehtmlview.h"
+#include "tdehtml_part.h"
+
+#include "css/cssstyleselector.h"
+#include "css/cssproperties.h"
+#include "css/cssvalues.h"
+#include "css/csshelper.h"
+
+#include "rendering/render_table.h"
+
+#include <kdebug.h>
+#include <kglobal.h>
+
+using namespace tdehtml;
+using namespace DOM;
+
+HTMLTableElementImpl::HTMLTableElementImpl(DocumentImpl *doc)
+ : HTMLElementImpl(doc)
+{
+ rules = None;
+ frame = Void;
+
+ padding = 1;
+
+ m_solid = false;
+
+ // reset font color and sizes here, if we don't have strict parse mode.
+ // this is 90% compatible to ie and mozilla, and the by way easiest solution...
+ // only difference to 100% correct is that in strict mode <font> elements are propagated into tables.
+ if ( getDocument()->parseMode() < DocumentImpl::Transitional ) {
+ addCSSProperty( CSS_PROP_FONT_SIZE, CSS_VAL_MEDIUM );
+ addCSSProperty( CSS_PROP_COLOR, CSS_VAL__KHTML_TEXT );
+ }
+}
+
+HTMLTableElementImpl::~HTMLTableElementImpl()
+{
+}
+
+NodeImpl::Id HTMLTableElementImpl::id() const
+{
+ return ID_TABLE;
+}
+
+NodeImpl* HTMLTableElementImpl::setCaption( HTMLTableCaptionElementImpl *c )
+{
+ int exceptioncode = 0;
+ NodeImpl* r;
+ if(ElementImpl* cap = caption()) {
+ replaceChild ( c, cap, exceptioncode );
+ r = c;
+ }
+ else
+ r = insertBefore( c, firstChild(), exceptioncode );
+ tCaption = c;
+ return r;
+}
+
+NodeImpl* HTMLTableElementImpl::setTHead( HTMLTableSectionElementImpl *s )
+{
+ int exceptioncode = 0;
+ NodeImpl* r;
+ if( ElementImpl* head = tHead() ) {
+ replaceChild( s, head, exceptioncode );
+ r = s;
+ }
+ else if(ElementImpl* foot = tFoot())
+ r = insertBefore( s, foot, exceptioncode );
+ else if(ElementImpl* firstBody = tFirstBody())
+ r = insertBefore( s, firstBody, exceptioncode );
+ else
+ r = appendChild( s, exceptioncode );
+
+ head = s;
+ return r;
+}
+
+NodeImpl* HTMLTableElementImpl::setTFoot( HTMLTableSectionElementImpl *s )
+{
+ int exceptioncode = 0;
+ NodeImpl* r;
+ if(ElementImpl* foot = tFoot()) {
+ replaceChild ( s, foot, exceptioncode );
+ r = s;
+ } else if(ElementImpl* firstBody = tFirstBody())
+ r = insertBefore( s, firstBody, exceptioncode );
+ else
+ r = appendChild( s, exceptioncode );
+ foot = s;
+ return r;
+}
+
+NodeImpl* HTMLTableElementImpl::setTBody( HTMLTableSectionElementImpl *s )
+{
+ int exceptioncode = 0;
+ NodeImpl* r;
+
+ if(ElementImpl* firstBody = tFirstBody()) {
+ replaceChild ( s, firstBody, exceptioncode );
+ r = s;
+ } else
+ r = appendChild( s, exceptioncode );
+ firstBody = s;
+
+ return r;
+}
+
+HTMLElementImpl *HTMLTableElementImpl::createTHead( )
+{
+ if(!tHead())
+ {
+ int exceptioncode = 0;
+ ElementImpl* head = new HTMLTableSectionElementImpl(docPtr(), ID_THEAD, true /* implicit */);
+ if(ElementImpl* foot = tFoot())
+ insertBefore( head, foot, exceptioncode );
+ else if(ElementImpl* firstBody = tFirstBody())
+ insertBefore( head, firstBody, exceptioncode);
+ else
+ appendChild(head, exceptioncode);
+ }
+ return tHead();
+}
+
+void HTMLTableElementImpl::deleteTHead( )
+{
+ if(ElementImpl* head = tHead()) {
+ int exceptioncode = 0;
+ removeChild(head, exceptioncode);
+ }
+}
+
+HTMLElementImpl *HTMLTableElementImpl::createTFoot( )
+{
+ if(!tFoot())
+ {
+ int exceptioncode = 0;
+ ElementImpl* foot = new HTMLTableSectionElementImpl(docPtr(), ID_TFOOT, true /*implicit */);
+ if(ElementImpl* firstBody = tFirstBody())
+ insertBefore( foot, firstBody, exceptioncode );
+ else
+ appendChild(foot, exceptioncode);
+ }
+ return tFoot();
+}
+
+void HTMLTableElementImpl::deleteTFoot( )
+{
+ if(ElementImpl* foot = tFoot()) {
+ int exceptioncode = 0;
+ removeChild(foot, exceptioncode);
+ }
+}
+
+HTMLElementImpl *HTMLTableElementImpl::createCaption( )
+{
+ if(!caption())
+ {
+ int exceptioncode = 0;
+ ElementImpl* tCaption = new HTMLTableCaptionElementImpl(docPtr());
+ insertBefore( tCaption, firstChild(), exceptioncode );
+ }
+ return caption();
+}
+
+void HTMLTableElementImpl::deleteCaption( )
+{
+ if(ElementImpl* tCaption = caption()) {
+ int exceptioncode = 0;
+ removeChild(tCaption, exceptioncode);
+ }
+}
+
+/**
+ Helper. This checks whether the section contains the desired index, and if so,
+ returns the section. Otherwise, it adjust the index, and returns 0.
+ indeces < 0 are considered to be infinite.
+
+ lastSection is adjusted to reflect the parameter passed in.
+*/
+static inline HTMLTableSectionElementImpl* processSection(HTMLTableSectionElementImpl* section,
+ HTMLTableSectionElementImpl* &lastSection, long& index)
+{
+ lastSection = section;
+ if ( index < 0 ) //append/last mode
+ return 0;
+
+ long rows = section->numRows();
+ if ( index >= rows ) {
+ section = 0;
+ index -= rows;
+ }
+ return section;
+}
+
+
+bool HTMLTableElementImpl::findRowSection(long index,
+ HTMLTableSectionElementImpl*& outSection,
+ long& outIndex) const
+{
+ HTMLTableSectionElementImpl* foot = tFoot();
+ HTMLTableSectionElementImpl* head = tHead();
+
+ HTMLTableSectionElementImpl* section = 0L;
+ HTMLTableSectionElementImpl* lastSection = 0L;
+
+ if ( head )
+ section = processSection( head, lastSection, index );
+
+ if ( !section ) {
+ for ( NodeImpl *node = firstChild(); node; node = node->nextSibling() ) {
+ if ( ( node->id() == ID_THEAD || node->id() == ID_TFOOT || node->id() == ID_TBODY ) &&
+ node != foot && node != head ) {
+ section = processSection( static_cast<HTMLTableSectionElementImpl *>(node),
+ lastSection, index );
+ if ( section )
+ break;
+ }
+ }
+ }
+
+ if ( !section && foot )
+ section = processSection( foot, lastSection, index );
+
+ outIndex = index;
+ if ( section ) {
+ outSection = section;
+ return true;
+ } else {
+ outSection = lastSection;
+ return false;
+ }
+}
+
+HTMLElementImpl *HTMLTableElementImpl::insertRow( long index, int &exceptioncode )
+{
+ // The DOM requires that we create a tbody if the table is empty
+ // (cf DOM2TS HTMLTableElement31 test). This includes even the cases where
+ // there are <tr>'s immediately under the table, as they're essentially
+ // ignored by these functions.
+ HTMLTableSectionElementImpl* foot = tFoot();
+ HTMLTableSectionElementImpl* head = tHead();
+ if(!tFirstBody() && !foot && !head)
+ setTBody( new HTMLTableSectionElementImpl(docPtr(), ID_TBODY, true /* implicit */) );
+
+ //kdDebug(6030) << k_funcinfo << index << endl;
+
+ long sectionIndex;
+ HTMLTableSectionElementImpl* section;
+ if ( findRowSection( index, section, sectionIndex ) )
+ return section->insertRow( sectionIndex, exceptioncode );
+ else if ( index == -1 || sectionIndex == 0 )
+ return section->insertRow( section->numRows(), exceptioncode );
+
+ // The index is too big.
+ exceptioncode = DOMException::INDEX_SIZE_ERR;
+ return 0L;
+}
+
+void HTMLTableElementImpl::deleteRow( long index, int &exceptioncode )
+{
+ long sectionIndex;
+ HTMLTableSectionElementImpl* section;
+ if ( findRowSection( index, section, sectionIndex ) )
+ section->deleteRow( sectionIndex, exceptioncode );
+ else if ( section && index == -1 )
+ section->deleteRow( -1, exceptioncode );
+ else
+ exceptioncode = DOMException::INDEX_SIZE_ERR;
+}
+
+NodeImpl *HTMLTableElementImpl::appendChild(NodeImpl *child, int &exceptioncode)
+{
+ NodeImpl* retval = HTMLElementImpl::appendChild( child, exceptioncode );
+ if(retval)
+ handleChildAppend( child );
+ return retval;
+}
+
+void HTMLTableElementImpl::handleChildAdd( NodeImpl *child )
+{
+ if (!child) return;
+ switch(child->id()) {
+ case ID_CAPTION:
+ tCaption.childAdded(this, child);
+ break;
+ case ID_THEAD:
+ head.childAdded(this, child);
+ break;
+ case ID_TFOOT:
+ foot.childAdded(this, child);
+ break;
+ case ID_TBODY:
+ firstBody.childAdded(this, child);
+ break;
+ }
+}
+
+void HTMLTableElementImpl::handleChildAppend( NodeImpl *child )
+{
+ if (!child) return;
+ switch(child->id()) {
+ case ID_CAPTION:
+ tCaption.childAppended(child);
+ break;
+ case ID_THEAD:
+ head.childAppended(child);
+ break;
+ case ID_TFOOT:
+ foot.childAppended(child);
+ break;
+ case ID_TBODY:
+ firstBody.childAppended(child);
+ break;
+ }
+}
+
+void HTMLTableElementImpl::handleChildRemove( NodeImpl *child )
+{
+ if (!child) return;
+ switch(child->id()) {
+ case ID_CAPTION:
+ tCaption.childRemoved(this, child);
+ break;
+ case ID_THEAD:
+ head.childRemoved(this, child);
+ break;
+ case ID_TFOOT:
+ foot.childRemoved(this, child);
+ break;
+ case ID_TBODY:
+ firstBody.childRemoved(this, child);
+ break;
+ }
+}
+
+NodeImpl *HTMLTableElementImpl::addChild(NodeImpl *child)
+{
+#ifdef DEBUG_LAYOUT
+ kdDebug( 6030 ) << nodeName().string() << "(Table)::addChild( " << child->nodeName().string() << " )" << endl;
+#endif
+
+ NodeImpl *retval = HTMLElementImpl::addChild( child );
+ if ( retval )
+ handleChildAppend( child );
+
+ return retval;
+}
+
+NodeImpl *HTMLTableElementImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode )
+{
+ NodeImpl* retval = HTMLElementImpl::insertBefore( newChild, refChild, exceptioncode);
+ if (retval)
+ handleChildAdd( newChild );
+
+ return retval;
+}
+
+void HTMLTableElementImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode )
+{
+ handleChildRemove( oldChild ); //Always safe.
+ HTMLElementImpl::replaceChild( newChild, oldChild, exceptioncode );
+ if ( !exceptioncode )
+ handleChildAdd( newChild );
+}
+
+void HTMLTableElementImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode )
+{
+ handleChildRemove( oldChild );
+ HTMLElementImpl::removeChild( oldChild, exceptioncode);
+}
+
+void HTMLTableElementImpl::parseAttribute(AttributeImpl *attr)
+{
+ // ### to CSS!!
+ switch(attr->id())
+ {
+ case ATTR_WIDTH:
+ if (!attr->value().isEmpty())
+ addCSSLength( CSS_PROP_WIDTH, attr->value() );
+ else
+ removeCSSProperty(CSS_PROP_WIDTH);
+ break;
+ case ATTR_HEIGHT:
+ if (!attr->value().isEmpty())
+ addCSSLength(CSS_PROP_HEIGHT, attr->value());
+ else
+ removeCSSProperty(CSS_PROP_HEIGHT);
+ break;
+ case ATTR_BORDER:
+ {
+ int border;
+ // ### this needs more work, as the border value is not only
+ // the border of the box, but also between the cells
+ if(!attr->val())
+ border = 0;
+ else if(attr->val()->l == 0)
+ border = 1;
+ else
+ border = attr->val()->toInt();
+#ifdef DEBUG_DRAW_BORDER
+ border=1;
+#endif
+ DOMString v = TQString::number( border );
+ addCSSLength(CSS_PROP_BORDER_WIDTH, v );
+
+ // wanted by HTML4 specs
+ if(!border)
+ frame = Void, rules = None;
+ else
+ frame = Box, rules = All;
+
+
+ if (attached()) updateFrame();
+ break;
+ }
+ case ATTR_BGCOLOR:
+ if (!attr->value().isEmpty())
+ addHTMLColor(CSS_PROP_BACKGROUND_COLOR, attr->value());
+ else
+ removeCSSProperty(CSS_PROP_BACKGROUND_COLOR);
+ break;
+ case ATTR_BORDERCOLOR:
+ if(!attr->value().isEmpty()) {
+ addHTMLColor(CSS_PROP_BORDER_COLOR, attr->value());
+ m_solid = true;
+ }
+
+ if (attached()) updateFrame();
+ break;
+ case ATTR_BACKGROUND:
+ {
+ if (!attr->value().isEmpty()) {
+ TQString url = tdehtml::parseURL( attr->value() ).string();
+ url = getDocument()->completeURL( url );
+ addCSSProperty(CSS_PROP_BACKGROUND_IMAGE, "url('"+url+"')" );
+ }
+ else
+ removeCSSProperty(CSS_PROP_BACKGROUND_IMAGE);
+ break;
+ }
+ case ATTR_FRAME:
+
+ if ( strcasecmp( attr->value(), "void" ) == 0 )
+ frame = Void;
+ else if ( strcasecmp( attr->value(), "border" ) == 0 )
+ frame = Box;
+ else if ( strcasecmp( attr->value(), "box" ) == 0 )
+ frame = Box;
+ else if ( strcasecmp( attr->value(), "hsides" ) == 0 )
+ frame = Hsides;
+ else if ( strcasecmp( attr->value(), "vsides" ) == 0 )
+ frame = Vsides;
+ else if ( strcasecmp( attr->value(), "above" ) == 0 )
+ frame = Above;
+ else if ( strcasecmp( attr->value(), "below" ) == 0 )
+ frame = Below;
+ else if ( strcasecmp( attr->value(), "lhs" ) == 0 )
+ frame = Lhs;
+ else if ( strcasecmp( attr->value(), "rhs" ) == 0 )
+ frame = Rhs;
+
+ if (attached()) updateFrame();
+ break;
+ case ATTR_RULES:
+ if ( strcasecmp( attr->value(), "none" ) == 0 )
+ rules = None;
+ else if ( strcasecmp( attr->value(), "groups" ) == 0 )
+ rules = Groups;
+ else if ( strcasecmp( attr->value(), "rows" ) == 0 )
+ rules = Rows;
+ else if ( strcasecmp( attr->value(), "cols" ) == 0 )
+ rules = Cols;
+ else if ( strcasecmp( attr->value(), "all" ) == 0 )
+ rules = All;
+ if (attached()) updateFrame();
+ break;
+ case ATTR_CELLSPACING:
+ if (!attr->value().isEmpty())
+ addCSSLength(CSS_PROP_BORDER_SPACING, attr->value(), true);
+ else
+ removeCSSProperty(CSS_PROP_BORDER_SPACING);
+ break;
+ case ATTR_CELLPADDING:
+ if (!attr->value().isEmpty())
+ padding = kMax( 0, attr->value().toInt() );
+ else
+ padding = 1;
+ if (m_render && m_render->isTable()) {
+ static_cast<RenderTable *>(m_render)->setCellPadding(padding);
+ if (!m_render->needsLayout())
+ m_render->setNeedsLayout(true);
+ }
+ break;
+ case ATTR_COLS:
+ {
+ // ###
+#if 0
+ int c;
+ c = attr->val()->toInt();
+ addColumns(c-totalCols);
+#endif
+ break;
+
+ }
+ case ATTR_ALIGN:
+ setChanged();
+ break;
+ case ATTR_VALIGN:
+ if (!attr->value().isEmpty())
+ addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower());
+ else
+ removeCSSProperty(CSS_PROP_VERTICAL_ALIGN);
+ break;
+ case ATTR_NOSAVE:
+ break;
+ default:
+ HTMLElementImpl::parseAttribute(attr);
+ }
+}
+
+void HTMLTableElementImpl::attach()
+{
+ updateFrame();
+ HTMLElementImpl::attach();
+ if ( m_render && m_render->isTable() )
+ static_cast<RenderTable *>(m_render)->setCellPadding( padding );
+}
+
+void HTMLTableElementImpl::close()
+{
+ ElementImpl* firstBody = tFirstBody();
+ if (firstBody && !firstBody->closed())
+ firstBody->close();
+ HTMLElementImpl::close();
+}
+
+void HTMLTableElementImpl::updateFrame()
+{
+ int v = m_solid ? CSS_VAL_SOLID : CSS_VAL_OUTSET;
+ if ( frame & Above )
+ addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, v);
+ else
+ addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_NONE);
+ if ( frame & Below )
+ addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, v);
+ else
+ addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_NONE);
+ if ( frame & Lhs )
+ addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, v);
+ else
+ addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_NONE);
+ if ( frame & Rhs )
+ addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, v);
+ else
+ addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_NONE);
+}
+
+// --------------------------------------------------------------------------
+
+void HTMLTablePartElementImpl::parseAttribute(AttributeImpl *attr)
+{
+ switch(attr->id())
+ {
+ case ATTR_BGCOLOR:
+ if (attr->val())
+ addHTMLColor(CSS_PROP_BACKGROUND_COLOR, attr->value() );
+ else
+ removeCSSProperty(CSS_PROP_BACKGROUND_COLOR);
+ break;
+ case ATTR_BACKGROUND:
+ {
+ if (attr->val()) {
+ TQString url = tdehtml::parseURL( attr->value() ).string();
+ url = getDocument()->completeURL( url );
+ addCSSProperty(CSS_PROP_BACKGROUND_IMAGE, "url('"+url+"')" );
+ }
+ else
+ removeCSSProperty(CSS_PROP_BACKGROUND_IMAGE);
+ break;
+ }
+ case ATTR_BORDERCOLOR:
+ {
+ if(!attr->value().isEmpty()) {
+ addHTMLColor(CSS_PROP_BORDER_COLOR, attr->value());
+ addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_SOLID);
+ addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_SOLID);
+ addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_SOLID);
+ addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_SOLID);
+ }
+ break;
+ }
+ case ATTR_ALIGN:
+ {
+ DOMString v = attr->value();
+ if ( strcasecmp( attr->value(), "middle" ) == 0 || strcasecmp( attr->value(), "center" ) == 0 )
+ addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_CENTER);
+ else if (strcasecmp(attr->value(), "absmiddle") == 0)
+ addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL_CENTER);
+ else if (strcasecmp(attr->value(), "left") == 0)
+ addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_LEFT);
+ else if (strcasecmp(attr->value(), "right") == 0)
+ addCSSProperty(CSS_PROP_TEXT_ALIGN, CSS_VAL__KHTML_RIGHT);
+ else
+ addCSSProperty(CSS_PROP_TEXT_ALIGN, v);
+ break;
+ }
+ case ATTR_VALIGN:
+ {
+ if (!attr->value().isEmpty())
+ addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower());
+ else
+ removeCSSProperty(CSS_PROP_VERTICAL_ALIGN);
+ break;
+ }
+ case ATTR_HEIGHT:
+ if (!attr->value().isEmpty())
+ addCSSLength(CSS_PROP_HEIGHT, attr->value());
+ else
+ removeCSSProperty(CSS_PROP_HEIGHT);
+ break;
+ case ATTR_NOSAVE:
+ break;
+ default:
+ HTMLElementImpl::parseAttribute(attr);
+ }
+}
+
+// -------------------------------------------------------------------------
+
+HTMLTableSectionElementImpl::HTMLTableSectionElementImpl(DocumentImpl *doc,
+ ushort tagid, bool implicit)
+ : HTMLTablePartElementImpl(doc)
+{
+ _id = tagid;
+ m_implicit = implicit;
+}
+
+HTMLTableSectionElementImpl::~HTMLTableSectionElementImpl()
+{
+}
+
+NodeImpl::Id HTMLTableSectionElementImpl::id() const
+{
+ return _id;
+}
+
+// these functions are rather slow, since we need to get the row at
+// the index... but they aren't used during usual HTML parsing anyway
+HTMLElementImpl *HTMLTableSectionElementImpl::insertRow( long index, int& exceptioncode )
+{
+ HTMLTableRowElementImpl *r = 0L;
+ HTMLCollectionImpl rows(const_cast<HTMLTableSectionElementImpl*>(this), HTMLCollectionImpl::TSECTION_ROWS);
+ int numRows = rows.length();
+ //kdDebug(6030) << k_funcinfo << "index=" << index << " numRows=" << numRows << endl;
+ if ( index < -1 || index > numRows ) {
+ exceptioncode = DOMException::INDEX_SIZE_ERR; // per the DOM
+ }
+ else
+ {
+ r = new HTMLTableRowElementImpl(docPtr());
+ if ( numRows == index || index == -1 )
+ appendChild(r, exceptioncode);
+ else {
+ NodeImpl *n;
+ if(index < 1)
+ n = firstChild();
+ else
+ n = rows.item(index);
+ insertBefore(r, n, exceptioncode );
+ }
+ }
+ return r;
+}
+
+void HTMLTableSectionElementImpl::deleteRow( long index, int &exceptioncode )
+{
+ HTMLCollectionImpl rows(const_cast<HTMLTableSectionElementImpl*>(this), HTMLCollectionImpl::TSECTION_ROWS);
+ int numRows = rows.length();
+ if ( index == -1 ) index = numRows - 1;
+ if( index >= 0 && index < numRows )
+ HTMLElementImpl::removeChild(rows.item(index), exceptioncode);
+ else
+ exceptioncode = DOMException::INDEX_SIZE_ERR;
+}
+
+
+int HTMLTableSectionElementImpl::numRows() const
+{
+ HTMLCollectionImpl rows(const_cast<HTMLTableSectionElementImpl*>(this), HTMLCollectionImpl::TSECTION_ROWS);
+ return rows.length();
+}
+
+// -------------------------------------------------------------------------
+
+NodeImpl::Id HTMLTableRowElementImpl::id() const
+{
+ return ID_TR;
+}
+
+long HTMLTableRowElementImpl::rowIndex() const
+{
+ int rIndex = 0;
+
+ NodeImpl *table = parentNode();
+ if ( !table )
+ return -1;
+ table = table->parentNode();
+ if ( !table || table->id() != ID_TABLE )
+ return -1;
+
+ HTMLTableSectionElementImpl *head = static_cast<HTMLTableElementImpl *>(table)->tHead();
+ HTMLTableSectionElementImpl *foot = static_cast<HTMLTableElementImpl *>(table)->tFoot();
+
+ if ( head ) {
+ const NodeImpl *row = head->firstChild();
+ while ( row ) {
+ if ( row == this )
+ return rIndex;
+ rIndex++;
+ row = row->nextSibling();
+ }
+ }
+
+ NodeImpl *node = table->firstChild();
+ while ( node ) {
+ if ( node != foot && node != head && (node->id() == ID_THEAD || node->id() == ID_TFOOT || node->id() == ID_TBODY) ) {
+ HTMLTableSectionElementImpl* section = static_cast<HTMLTableSectionElementImpl *>(node);
+ const NodeImpl *row = section->firstChild();
+ while ( row ) {
+ if ( row == this )
+ return rIndex;
+ rIndex++;
+ row = row->nextSibling();
+ }
+ }
+ node = node->nextSibling();
+ }
+ const NodeImpl *row = foot->firstChild();
+ while ( row ) {
+ if ( row == this )
+ return rIndex;
+ rIndex++;
+ row = row->nextSibling();
+ }
+ // should never happen
+ return -1;
+}
+
+long HTMLTableRowElementImpl::sectionRowIndex() const
+{
+ int rIndex = 0;
+ const NodeImpl *n = this;
+ do {
+ n = n->previousSibling();
+ if (n && n->id() == ID_TR)
+ rIndex++;
+ }
+ while (n);
+
+ return rIndex;
+}
+
+HTMLElementImpl *HTMLTableRowElementImpl::insertCell( long index, int &exceptioncode )
+{
+ HTMLTableCellElementImpl *c = 0L;
+ NodeListImpl *children = childNodes();
+ int numCells = children ? children->length() : 0;
+ if ( index < -1 || index > numCells )
+ exceptioncode = DOMException::INDEX_SIZE_ERR; // per the DOM
+ else
+ {
+ c = new HTMLTableCellElementImpl(docPtr(), ID_TD);
+ if(numCells == index || index == -1)
+ appendChild(c, exceptioncode);
+ else {
+ NodeImpl *n;
+ if(index < 1)
+ n = firstChild();
+ else
+ n = children->item(index);
+ insertBefore(c, n, exceptioncode);
+ }
+ }
+ delete children;
+ return c;
+}
+
+void HTMLTableRowElementImpl::deleteCell( long index, int &exceptioncode )
+{
+ NodeListImpl *children = childNodes();
+ int numCells = children ? children->length() : 0;
+ if ( index == -1 ) index = numCells-1;
+ if( index >= 0 && index < numCells )
+ HTMLElementImpl::removeChild(children->item(index), exceptioncode);
+ else
+ exceptioncode = DOMException::INDEX_SIZE_ERR;
+ delete children;
+}
+
+// -------------------------------------------------------------------------
+
+HTMLTableCellElementImpl::HTMLTableCellElementImpl(DocumentImpl *doc, int tag)
+ : HTMLTablePartElementImpl(doc)
+{
+ _col = -1;
+ _row = -1;
+ cSpan = rSpan = 1;
+ _id = tag;
+ rowHeight = 0;
+ m_solid = false;
+}
+
+HTMLTableCellElementImpl::~HTMLTableCellElementImpl()
+{
+}
+
+long HTMLTableCellElementImpl::cellIndex() const
+{
+ int index = 0;
+ for (const NodeImpl * node = previousSibling(); node; node = node->previousSibling()) {
+ if (node->id() == ID_TD || node->id() == ID_TH)
+ index++;
+ }
+
+ return index;
+}
+
+void HTMLTableCellElementImpl::parseAttribute(AttributeImpl *attr)
+{
+ switch(attr->id())
+ {
+ case ATTR_BORDER:
+ // euhm? not supported by other browsers as far as I can see (Dirk)
+ //addCSSLength(CSS_PROP_BORDER_WIDTH, attr->value());
+ break;
+ case ATTR_ROWSPAN:
+ // ###
+ rSpan = attr->val() ? attr->val()->toInt() : 1;
+ // limit this to something not causing an overflow with short int
+ if(rSpan < 1 || rSpan > 1024) rSpan = 1;
+ break;
+ case ATTR_COLSPAN:
+ // ###
+ cSpan = attr->val() ? attr->val()->toInt() : 1;
+ // limit this to something not causing an overflow with short int
+ if(cSpan < 1 || cSpan > 1024) cSpan = 1;
+ break;
+ case ATTR_NOWRAP:
+ if (attr->val() != 0)
+ addCSSProperty(CSS_PROP_WHITE_SPACE, CSS_VAL__KHTML_NOWRAP);
+ else
+ removeCSSProperty(CSS_PROP_WHITE_SPACE);
+ break;
+ case ATTR_WIDTH:
+ if (!attr->value().isEmpty())
+ addCSSLength( CSS_PROP_WIDTH, attr->value() );
+ else
+ removeCSSProperty(CSS_PROP_WIDTH);
+ break;
+ case ATTR_NOSAVE:
+ break;
+ default:
+ HTMLTablePartElementImpl::parseAttribute(attr);
+ }
+}
+
+void HTMLTableCellElementImpl::attach()
+{
+ HTMLElementImpl* p = static_cast<HTMLElementImpl*>(parentNode());
+ while(p && p->id() != ID_TABLE)
+ p = static_cast<HTMLElementImpl*>(p->parentNode());
+
+ if(p) {
+ HTMLTableElementImpl* table = static_cast<HTMLTableElementImpl*>(p);
+ if (table->rules == HTMLTableElementImpl::None) {
+ addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, CSS_VAL_NONE);
+ addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, CSS_VAL_NONE);
+ addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, CSS_VAL_NONE);
+ addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, CSS_VAL_NONE);
+ }
+ else {
+ addCSSProperty(CSS_PROP_BORDER_WIDTH, "1px");
+ int v = (table->m_solid || m_solid) ? CSS_VAL_SOLID : CSS_VAL_INSET;
+ addCSSProperty(CSS_PROP_BORDER_TOP_STYLE, v);
+ addCSSProperty(CSS_PROP_BORDER_BOTTOM_STYLE, v);
+ addCSSProperty(CSS_PROP_BORDER_LEFT_STYLE, v);
+ addCSSProperty(CSS_PROP_BORDER_RIGHT_STYLE, v);
+
+ if (!m_solid)
+ addCSSProperty(CSS_PROP_BORDER_COLOR, CSS_VAL_INHERIT);
+ }
+ }
+
+ HTMLTablePartElementImpl::attach();
+}
+
+// -------------------------------------------------------------------------
+
+HTMLTableColElementImpl::HTMLTableColElementImpl(DocumentImpl *doc, ushort i)
+ : HTMLTablePartElementImpl(doc)
+{
+ _id = i;
+ _span = 1;
+}
+
+NodeImpl::Id HTMLTableColElementImpl::id() const
+{
+ return _id;
+}
+
+
+void HTMLTableColElementImpl::parseAttribute(AttributeImpl *attr)
+{
+ switch(attr->id())
+ {
+ case ATTR_SPAN:
+ _span = attr->val() ? attr->val()->toInt() : 1;
+ if (_span < 1) _span = 1;
+ break;
+ case ATTR_WIDTH:
+ if (!attr->value().isEmpty())
+ addCSSLength(CSS_PROP_WIDTH, attr->value(), false, true );
+ else
+ removeCSSProperty(CSS_PROP_WIDTH);
+ break;
+ case ATTR_VALIGN:
+ if (!attr->value().isEmpty())
+ addCSSProperty(CSS_PROP_VERTICAL_ALIGN, attr->value().lower());
+ else
+ removeCSSProperty(CSS_PROP_VERTICAL_ALIGN);
+ break;
+ default:
+ HTMLTablePartElementImpl::parseAttribute(attr);
+ }
+
+}
+
+// -------------------------------------------------------------------------
+
+NodeImpl::Id HTMLTableCaptionElementImpl::id() const
+{
+ return ID_CAPTION;
+}
+
+
+void HTMLTableCaptionElementImpl::parseAttribute(AttributeImpl *attr)
+{
+ switch(attr->id())
+ {
+ case ATTR_ALIGN:
+ if (!attr->value().isEmpty())
+ addCSSProperty(CSS_PROP_CAPTION_SIDE, attr->value().lower());
+ else
+ removeCSSProperty(CSS_PROP_CAPTION_SIDE);
+ break;
+ default:
+ HTMLElementImpl::parseAttribute(attr);
+ }
+
+}