All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.phloc.html.hc.html.AbstractHCBaseTable Maven / Gradle / Ivy

There is a newer version: 4.4.9
Show newest version
/**
 * Copyright (C) 2006-2015 phloc systems
 * http://www.phloc.com
 * office[at]phloc[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.phloc.html.hc.html;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;

import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.OverridingMethodsMustInvokeSuper;

import com.phloc.commons.CGlobal;
import com.phloc.commons.ValueEnforcer;
import com.phloc.commons.annotations.Nonempty;
import com.phloc.commons.annotations.OverrideOnDemand;
import com.phloc.commons.annotations.ReturnsMutableCopy;
import com.phloc.commons.annotations.ReturnsMutableObject;
import com.phloc.commons.string.StringHelper;
import com.phloc.commons.string.ToStringGenerator;
import com.phloc.html.EHTMLElement;
import com.phloc.html.css.ICSSClassProvider;
import com.phloc.html.hc.IHCCell;
import com.phloc.html.hc.IHCNode;
import com.phloc.html.hc.IHCTable;
import com.phloc.html.hc.conversion.HCConsistencyChecker;
import com.phloc.html.hc.conversion.IHCConversionSettingsToNode;
import com.phloc.html.hc.impl.AbstractHCElement;
import com.phloc.html.hc.impl.HCTextNode;

/**
 * This is the common base class for regular HC tables as well as for more
 * complex constructs (e.g. PUI)
 * 
 * @author Philip Helger
 * @param 
 *        Implementation type
 */
public abstract class AbstractHCBaseTable > extends AbstractHCElement  implements IHCTable 
{
  private HCColGroup m_aColGroup;
  private int m_nCellSpacing = CGlobal.ILLEGAL_UINT;
  private int m_nCellPadding = CGlobal.ILLEGAL_UINT;

  private HCTHead m_aHead = new HCTHead ();
  private HCTBody m_aBody = new HCTBody ();
  private HCTFoot m_aFoot = new HCTFoot ();

  /**
   * This constructor is used to create elements with logic like a table but
   * actually not having a top 'table' element
   * 
   * @param aElement
   *        The HTML element to be used to create the table
   */
  protected AbstractHCBaseTable (@Nonnull @Nonempty final EHTMLElement aElement)
  {
    super (aElement);
  }

  /**
   * @return The table header. Never null.
   */
  @Nonnull
  public final HCTHead getHead ()
  {
    return m_aHead;
  }

  @Nonnull
  public final IMPLTYPE setHead (@Nonnull final HCTHead aHead)
  {
    m_aHead = ValueEnforcer.notNull (aHead, "Head");
    return thisAsT ();
  }

  /**
   * @return The table body. Never null.
   */
  @Nonnull
  public final HCTBody getBody ()
  {
    return m_aBody;
  }

  @Nonnull
  public final IMPLTYPE setBody (@Nonnull final HCTBody aBody)
  {
    m_aBody = ValueEnforcer.notNull (aBody, "Body");
    return thisAsT ();
  }

  /**
   * @return The table footer. Never null.
   */
  @Nonnull
  public final HCTFoot getFoot ()
  {
    return m_aFoot;
  }

  @Nonnull
  public final IMPLTYPE setFoot (@Nonnull final HCTFoot aFoot)
  {
    m_aFoot = ValueEnforcer.notNull (aFoot, "Foot");
    return thisAsT ();
  }

  public final boolean hasChildren ()
  {
    return m_aHead.hasChildren () || m_aBody.hasChildren () || m_aFoot.hasChildren ();
  }

  @Nonnegative
  public final int getChildCount ()
  {
    return m_aHead.getChildCount () + m_aBody.getChildCount () + m_aFoot.getChildCount ();
  }

  @Nullable
  public final HCRow getFirstChild ()
  {
    HCRow ret = getFirstHeaderRow ();
    if (ret == null)
    {
      ret = getFirstBodyRow ();
      if (ret == null)
        ret = getFirstFooterRow ();
    }
    return ret;
  }

  @Nullable
  public final HCRow getLastChild ()
  {
    HCRow ret = getLastFooterRow ();
    if (ret == null)
    {
      ret = getLastBodyRow ();
      if (ret == null)
        ret = getLastHeaderRow ();
    }
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public final List  getChildren ()
  {
    final List  ret = new ArrayList  ();
    ret.addAll (m_aHead.getChildren ());
    ret.addAll (m_aBody.getChildren ());
    ret.addAll (m_aFoot.getChildren ());
    return ret;
  }

  @Nullable
  public final HCRow getChildAtIndex (@Nonnegative final int nIndex)
  {
    int nRealIndex = nIndex;
    if (nRealIndex < getHeaderRowCount ())
      return getHeaderRowAtIndex (nRealIndex);
    nRealIndex -= getHeaderRowCount ();
    if (nRealIndex < getBodyRowCount ())
      return getBodyRowAtIndex (nRealIndex);
    nRealIndex -= getBodyRowCount ();
    if (nRealIndex < getFooterRowCount ())
      return getFooterRowAtIndex (nRealIndex);
    return null;
  }

  public final int getCellSpacing ()
  {
    return m_nCellSpacing;
  }

  @Nonnull
  public final IMPLTYPE setCellSpacing (final int nCellSpacing)
  {
    m_nCellSpacing = nCellSpacing;
    return thisAsT ();
  }

  public final int getCellPadding ()
  {
    return m_nCellPadding;
  }

  @Nonnull
  public final IMPLTYPE setCellPadding (final int nCellPadding)
  {
    m_nCellPadding = nCellPadding;
    return thisAsT ();
  }

  //
  // column handling
  //

  @Nullable
  public final HCColGroup getColGroup ()
  {
    return m_aColGroup;
  }

  @Nonnull
  public final IMPLTYPE addColumn (@Nullable final HCCol aCol)
  {
    if (aCol != null)
    {
      if (m_aColGroup == null)
        m_aColGroup = new HCColGroup ();
      m_aColGroup.addColumn (aCol);
    }
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE addColumn (@Nonnegative final int nIndex, @Nullable final HCCol aCol)
  {
    if (aCol != null)
    {
      if (m_aColGroup == null)
        m_aColGroup = new HCColGroup ();
      m_aColGroup.addColumn (nIndex, aCol);
    }
    return thisAsT ();
  }

  @Nonnull
  @Deprecated
  public final IMPLTYPE addColumns (@Nullable final HCCol aCol)
  {
    return addColumn (aCol);
  }

  @Nonnull
  public final IMPLTYPE addColumns (@Nullable final HCCol... aCols)
  {
    if (aCols != null)
      for (final HCCol aCol : aCols)
        addColumn (aCol);
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE addColumns (@Nullable final Iterable  aCols)
  {
    if (aCols != null)
      for (final HCCol aCol : aCols)
        addColumn (aCol);
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE removeColumnAtIndex (@Nonnegative final int nColumnIndex)
  {
    if (m_aColGroup != null)
      m_aColGroup.removeColumnAtIndex (nColumnIndex);
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE removeAllColumns ()
  {
    m_aColGroup = null;
    return thisAsT ();
  }

  @Nonnegative
  public final int getColumnCount ()
  {
    return m_aColGroup == null ? 0 : m_aColGroup.getColumnCount ();
  }

  //
  // header row handling
  //

  @Nullable
  public final String getHeaderID ()
  {
    return m_aHead.getID ();
  }

  @Nonnull
  public final IMPLTYPE setHeaderID (@Nullable final String sID)
  {
    m_aHead.setID (sID);
    return thisAsT ();
  }

  public final boolean hasHeaderID ()
  {
    return m_aHead.hasID ();
  }

  @Nonnull
  @ReturnsMutableCopy
  public final Set  getAllHeaderClasses ()
  {
    return m_aHead.getAllClasses ();
  }

  @Nonnull
  public final String getAllHeaderClassesAsString ()
  {
    return m_aHead.getAllClassesAsString ();
  }

  @Nonnull
  public final IMPLTYPE addHeaderClass (@Nonnull final ICSSClassProvider aCSSClassProvider)
  {
    m_aHead.addClass (aCSSClassProvider);
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE removeHeaderClass (@Nonnull final ICSSClassProvider aCSSClassProvider)
  {
    m_aHead.removeClass (aCSSClassProvider);
    return thisAsT ();
  }

  public final boolean hasHeaderClasses ()
  {
    return m_aHead.hasAnyClass ();
  }

  public final boolean hasHeaderRows ()
  {
    return m_aHead.hasChildren ();
  }

  @Nonnegative
  public final int getHeaderRowCount ()
  {
    return m_aHead.getChildCount ();
  }

  /**
   * Get the contained list object that holds all the rows. Handle with care
   * because it alters the internal data structures of this table.
   * 
   * @return The contained list object for external row order handling.
   */
  @Nullable
  @ReturnsMutableObject (reason = "For performance reasons in derived classes")
  protected final List  directGetHeaderRowList ()
  {
    return m_aHead.directGetRowList ();
  }

  @Nullable
  public final HCRow getFirstHeaderRow ()
  {
    return m_aHead.getFirstChild ();
  }

  @Nullable
  public final HCRow getHeaderRowAtIndex (@Nonnegative final int nIndex)
  {
    return m_aHead.getChildAtIndex (nIndex);
  }

  @Nullable
  public final HCRow getLastHeaderRow ()
  {
    return m_aHead.getLastChild ();
  }

  @Nonnull
  @ReturnsMutableCopy
  public final List  getAllHeaderRows ()
  {
    return m_aHead.getChildren ();
  }

  @Nonnull
  public final HCRow addHeaderRow ()
  {
    return m_aHead.addRow ();
  }

  @Nonnull
  public final HCRow addHeaderRow (@Nonnegative final int nIndex)
  {
    return m_aHead.addRow (nIndex);
  }

  @Nonnull
  public final IMPLTYPE addHeaderRow (@Nullable final HCRow aRow)
  {
    m_aHead.addChild (aRow);
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE addHeaderRow (@Nonnegative final int nIndex, @Nullable final HCRow aRow)
  {
    m_aHead.addChild (nIndex, aRow);
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE removeHeaderRowAtIndex (@Nonnegative final int nIndex)
  {
    m_aHead.removeChild (nIndex);
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE removeAllHeaderRows ()
  {
    m_aHead.removeAllChildren ();
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE sortAllHeaderRows (@Nonnull final Comparator  aComparator)
  {
    m_aHead.sortAllChildren (aComparator);
    return thisAsT ();
  }

  //
  // footer row handling
  //
  @Nullable
  public final String getFooterID ()
  {
    return m_aFoot.getID ();
  }

  @Nonnull
  public final IMPLTYPE setFooterID (@Nullable final String sID)
  {
    m_aFoot.setID (sID);
    return thisAsT ();
  }

  public final boolean hasFooterID ()
  {
    return m_aFoot.hasID ();
  }

  @Nonnull
  @ReturnsMutableCopy
  public final Set  getAllFooterClasses ()
  {
    return m_aFoot.getAllClasses ();
  }

  @Nonnull
  public final String getAllFooterClassesAsString ()
  {
    return m_aFoot.getAllClassesAsString ();
  }

  @Nonnull
  public final IMPLTYPE addFooterClass (@Nonnull final ICSSClassProvider aCSSClassProvider)
  {
    m_aFoot.addClass (aCSSClassProvider);
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE removeFooterClass (@Nonnull final ICSSClassProvider aCSSClassProvider)
  {
    m_aFoot.removeClass (aCSSClassProvider);
    return thisAsT ();
  }

  public final boolean hasFooterClasses ()
  {
    return m_aFoot.hasAnyClass ();
  }

  public final boolean hasFooterRows ()
  {
    return m_aFoot.hasChildren ();
  }

  @Nonnegative
  public final int getFooterRowCount ()
  {
    return m_aFoot.getChildCount ();
  }

  /**
   * Get the contained list object that holds all the rows. Handle with care
   * because it alters the internal data structures of this table.
   * 
   * @return The contained list object for external row order handling.
   */
  @Nullable
  @ReturnsMutableObject (reason = "For performance reasons in derived classes")
  protected final List  directGetFooterRowList ()
  {
    return m_aFoot.directGetRowList ();
  }

  @Nullable
  public final HCRow getFirstFooterRow ()
  {
    return m_aFoot.getFirstChild ();
  }

  @Nullable
  public final HCRow getFooterRowAtIndex (@Nonnegative final int nIndex)
  {
    return m_aFoot.getChildAtIndex (nIndex);
  }

  @Nullable
  public final HCRow getLastFooterRow ()
  {
    return m_aFoot.getLastChild ();
  }

  @Nonnull
  @ReturnsMutableCopy
  public final List  getAllFooterRows ()
  {
    return m_aFoot.getChildren ();
  }

  @Nonnull
  public final HCRow addFooterRow ()
  {
    return m_aFoot.addRow ();
  }

  @Nonnull
  public final HCRow addFooterRow (@Nonnegative final int nIndex)
  {
    return m_aFoot.addRow (nIndex);
  }

  @Nonnull
  public final IMPLTYPE addFooterRow (@Nullable final HCRow aRow)
  {
    m_aFoot.addChild (aRow);
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE addFooterRow (@Nonnegative final int nIndex, @Nullable final HCRow aRow)
  {
    m_aFoot.addChild (nIndex, aRow);
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE removeFooterRowAtIndex (@Nonnegative final int nIndex)
  {
    m_aFoot.removeChild (nIndex);
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE removeAllFooterRows ()
  {
    m_aFoot.removeAllChildren ();
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE sortAllFooterRows (@Nonnull final Comparator  aComparator)
  {
    m_aFoot.sortAllChildren (aComparator);
    return thisAsT ();
  }

  //
  // body row handling
  //

  @Nullable
  public final String getBodyID ()
  {
    return m_aBody.getID ();
  }

  @Nonnull
  public final IMPLTYPE setBodyID (@Nullable final String sID)
  {
    m_aBody.setID (sID);
    return thisAsT ();
  }

  public final boolean hasBodyID ()
  {
    return m_aBody.hasID ();
  }

  @Nonnull
  @ReturnsMutableCopy
  public final Set  getAllBodyClasses ()
  {
    return m_aBody.getAllClasses ();
  }

  @Nonnull
  public final String getAllBodyClassesAsString ()
  {
    return m_aBody.getAllClassesAsString ();
  }

  @Nonnull
  public final IMPLTYPE addBodyClass (@Nonnull final ICSSClassProvider aCSSClassProvider)
  {
    m_aBody.addClass (aCSSClassProvider);
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE removeBodyClass (@Nonnull final ICSSClassProvider aCSSClassProvider)
  {
    m_aBody.removeClass (aCSSClassProvider);
    return thisAsT ();
  }

  public final boolean hasBodyClasses ()
  {
    return m_aBody.hasAnyClass ();
  }

  public final boolean hasBodyRows ()
  {
    return m_aBody.hasChildren ();
  }

  @Nonnegative
  public final int getBodyRowCount ()
  {
    return m_aBody.getChildCount ();
  }

  /**
   * Get the contained list object that holds all the rows. Handle with care
   * because it alters the internal data structures of this table.
   * 
   * @return The contained list object for external row order handling.
   */
  @Nullable
  @ReturnsMutableObject (reason = "For performance reasons in derived classes")
  protected final List  directGetBodyRowList ()
  {
    return m_aBody.directGetRowList ();
  }

  @Nullable
  public final HCRow getFirstBodyRow ()
  {
    return m_aBody.getFirstChild ();
  }

  @Nullable
  public final HCRow getBodyRowAtIndex (@Nonnegative final int nIndex)
  {
    return m_aBody.getChildAtIndex (nIndex);
  }

  @Nullable
  public final HCRow getLastBodyRow ()
  {
    return m_aBody.getLastChild ();
  }

  @Nonnull
  @ReturnsMutableCopy
  public final List  getAllBodyRows ()
  {
    return m_aBody.getChildren ();
  }

  @Nonnull
  public final HCRow addBodyRow ()
  {
    return m_aBody.addRow ();
  }

  @Nonnull
  public final HCRow addBodyRow (@Nonnegative final int nIndex)
  {
    return m_aBody.addRow (nIndex);
  }

  @Nonnull
  public final IMPLTYPE addBodyRow (@Nullable final HCRow aRow)
  {
    m_aBody.addChild (aRow);
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE addBodyRow (@Nonnegative final int nIndex, @Nullable final HCRow aRow)
  {
    m_aBody.addChild (nIndex, aRow);
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE removeBodyRowAtIndex (@Nonnegative final int nIndex)
  {
    m_aBody.removeChild (nIndex);
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE removeAllBodyRows ()
  {
    m_aBody.removeAllChildren ();
    return thisAsT ();
  }

  @Nonnull
  public final IMPLTYPE sortAllBodyRows (@Nonnull final Comparator  aComparator)
  {
    m_aBody.sortAllChildren (aComparator);
    return thisAsT ();
  }

  @Nonnull
  public IMPLTYPE setSpanningHeaderContent (@Nullable final String sText)
  {
    return setSpanningHeaderContent (HCTextNode.createOnDemand (sText));
  }

  @Nonnull
  public IMPLTYPE setSpanningHeaderContent (@Nullable final IHCNode aNode)
  {
    removeAllHeaderRows ();
    return addSpanningHeaderContent (aNode);
  }

  @Nonnull
  public IMPLTYPE addSpanningHeaderContent (@Nullable final String sText)
  {
    return addSpanningHeaderContent (HCTextNode.createOnDemand (sText));
  }

  @Nonnull
  public IMPLTYPE addSpanningHeaderContent (@Nullable final IHCNode aNode)
  {
    addHeaderRow ().addAndReturnCell (aNode).setColspan (getColumnCount ());
    return thisAsT ();
  }

  @Nonnull
  public IMPLTYPE addSpanningBodyContent (@Nullable final String sText)
  {
    return addSpanningBodyContent (HCTextNode.createOnDemand (sText));
  }

  @Nonnull
  public IMPLTYPE addSpanningBodyContent (@Nullable final IHCNode aNode)
  {
    addBodyRow ().addAndReturnCell (aNode).setColspan (getColumnCount ());
    return thisAsT ();
  }

  @Nonnull
  public IMPLTYPE setSpanningFooterContent (@Nullable final String sText)
  {
    return setSpanningFooterContent (HCTextNode.createOnDemand (sText));
  }

  @Nonnull
  public IMPLTYPE setSpanningFooterContent (@Nullable final IHCNode aNode)
  {
    removeAllFooterRows ();
    return addSpanningFooterContent (aNode);
  }

  @Nonnull
  public IMPLTYPE addSpanningFooterContent (@Nullable final String sText)
  {
    return addSpanningFooterContent (HCTextNode.createOnDemand (sText));
  }

  @Nonnull
  public IMPLTYPE addSpanningFooterContent (@Nullable final IHCNode aNode)
  {
    addFooterRow ().addAndReturnCell (aNode).setColspan (getColumnCount ());
    return thisAsT ();
  }

  //
  // code generation
  //

  @Override
  @OverridingMethodsMustInvokeSuper
  public boolean canConvertToNode (@Nonnull final IHCConversionSettingsToNode aConversionSettings)
  {
    // Avoid creating a table without header, body and footer
    return m_aBody.canConvertToNode (aConversionSettings) ||
           m_aHead.canConvertToNode (aConversionSettings) ||
           m_aFoot.canConvertToNode (aConversionSettings);
  }

  private static int _getApplicableRowspan (final int nCellIndex, @Nullable final List  aRowSpans)
  {
    int nApplicableRowspan = 0;
    if (aRowSpans != null)
    {
      // The table has at least one rowspan defined
      int nDecrease = 1;
      for (final int [] aPrevRowRowspans : aRowSpans)
      {
        if (aPrevRowRowspans != null)
          if (nCellIndex < aPrevRowRowspans.length)
          {
            final int nEffectiveRowspan = aPrevRowRowspans[nCellIndex] - nDecrease;
            if (nEffectiveRowspan > 0)
              nApplicableRowspan++;
          }
        ++nDecrease;
      }
    }
    return nApplicableRowspan;
  }

  @Nonnegative
  private static int _getEffectiveCellCount (@Nonnull final HCRow aRow, @Nullable final List  aRowSpans)
  {
    int nCellIndex = 0;
    for (final IHCCell  aCell : aRow.getChildren ())
      nCellIndex += _getApplicableRowspan (nCellIndex, aRowSpans) + aCell.getColspan ();
    // Any rowspan after the last cell?
    nCellIndex += _getApplicableRowspan (nCellIndex, aRowSpans);
    return nCellIndex;
  }

  private static void _checkConsistency (@Nonnull final String sContext,
                                         @Nonnull final AbstractHCTablePart  aPart,
                                         @Nonnegative final int nCols)
  {
    int nRowIndex = 0;
    boolean bTotalHasRowSpans = false;
    final List  aTotalRowSpans = new ArrayList  (aPart.getChildCount ());
    if (aPart.hasChildren ())
      for (final HCRow aBodyRow : aPart.directGetRowList ())
      {
        // Pass null if no row spans are defined!
        final int nRowCols = _getEffectiveCellCount (aBodyRow, bTotalHasRowSpans ? aTotalRowSpans : null);
        if (nRowCols != nCols)
          HCConsistencyChecker.consistencyWarning (sContext +
                                                   " row #" +
                                                   (nRowIndex + 1) +
                                                   " has " +
                                                   nRowCols +
                                                   " cells but was expecting " +
                                                   nCols +
                                                   " cells");
        // Add row span at the end of the row so that it affects following rows
        {
          final int [] aRowRowSpans = new int [aBodyRow.getCellCount ()];
          int nCellIndex = 0;
          boolean bRowHasRowSpans = false;
          for (final IHCCell  aCell : aBodyRow.getChildren ())
          {
            final int nRowSpan = aCell.getRowspan ();
            aRowRowSpans[nCellIndex++] = nRowSpan;
            if (nRowSpan != 1)
              bRowHasRowSpans = true;
          }
          if (bRowHasRowSpans)
          {
            // This row has at least one row span!
            aTotalRowSpans.add (0, aRowRowSpans);
            bTotalHasRowSpans = true;
          }
          else
          {
            // There are no row spans defined in this row
            aTotalRowSpans.add (0, null);
          }
        }
        nRowIndex++;
      }
  }

  public static void checkInternalConsistency (@Nonnull final AbstractHCBaseTable  aBaseTable)
  {
    // Determine number of columns to use
    int nCols = 0;
    if (aBaseTable.m_aColGroup != null)
      nCols = aBaseTable.m_aColGroup.getColumnCount ();
    if (nCols == 0 && aBaseTable.m_aHead.hasChildren ())
      nCols = aBaseTable.m_aHead.getFirstChild ().getEffectiveCellCount ();
    if (nCols == 0 && aBaseTable.m_aBody.hasChildren ())
      nCols = aBaseTable.m_aBody.getFirstChild ().getEffectiveCellCount ();
    if (nCols == 0 && aBaseTable.m_aFoot.hasChildren ())
      nCols = aBaseTable.m_aFoot.getFirstChild ().getEffectiveCellCount ();

    String sPrefix = "Table";
    if (StringHelper.hasText (aBaseTable.getID ()))
      sPrefix += " with ID " + aBaseTable.getID ();
    _checkConsistency (sPrefix + " header", aBaseTable.m_aHead, nCols);
    _checkConsistency (sPrefix + " body", aBaseTable.m_aBody, nCols);
    _checkConsistency (sPrefix + " footer", aBaseTable.m_aFoot, nCols);
  }

  @Override
  @OverrideOnDemand
  @OverridingMethodsMustInvokeSuper
  protected void internalBeforeConvertToNode (@Nonnull final IHCConversionSettingsToNode aConversionSettings)
  {
    // Propagate to children
    if (m_aHead.hasChildren ())
      for (final HCRow aHeaderRow : m_aHead.directGetRowList ())
        aHeaderRow.beforeConvertToNode (aConversionSettings);
    if (m_aBody.hasChildren ())
      for (final HCRow aBodyRow : m_aBody.directGetRowList ())
        aBodyRow.beforeConvertToNode (aConversionSettings);
    if (m_aFoot.hasChildren ())
      for (final HCRow aFooterRow : m_aFoot.directGetRowList ())
        aFooterRow.beforeConvertToNode (aConversionSettings);
  }

  @Override
  @Nonnull
  public final String getPlainText ()
  {
    final StringBuilder ret = new StringBuilder ();
    ret.append (m_aHead.getPlainText ());
    ret.append (m_aBody.getPlainText ());
    ret.append (m_aFoot.getPlainText ());
    return ret.toString ();
  }

  @Override
  public String toString ()
  {
    return ToStringGenerator.getDerived (super.toString ())
                            .appendIfNotNull ("colGroup", m_aColGroup)
                            .append ("cellSpacing", m_nCellSpacing)
                            .append ("cellPadding", m_nCellPadding)
                            .append ("header", m_aHead)
                            .append ("body", m_aBody)
                            .append ("footer", m_aFoot)
                            .toString ();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy