public DocumentFragment adjustColumnWidths()

in assets/support/faq/docbook-xsl/extensions/xalan2/com/nwalsh/xalan/Table.java [223:474]


  public DocumentFragment adjustColumnWidths (ExpressionContext context,
					      NodeIterator xalanNI) {

    int nominalWidth = convertLength(Params.getString(context,
						      "nominal.table.width"));
    String tableWidth = Params.getString(context, "table.width");
    String styleType = Params.getString(context, "stylesheet.result.type");
    boolean foStylesheet = styleType.equals("fo");

    DocumentFragment xalanRTF = (DocumentFragment) xalanNI.nextNode();
    Element colgroup = (Element) xalanRTF.getFirstChild();

    // N.B. ...stree.ElementImpl doesn't implement getElementsByTagName()

    Node firstCol = null;
    // If this is an FO tree, there might be no colgroup...
    if (colgroup.getLocalName().equals("colgroup")) {
      firstCol = colgroup.getFirstChild();
    } else {
      firstCol = colgroup;
    }

    // Count the number of columns...
    Node child = firstCol;
    int numColumns = 0;
    while (child != null) {
      if (child.getNodeType() == Node.ELEMENT_NODE
	  && (child.getNodeName().equals("col")
	      || (child.getNamespaceURI().equals(foURI)
		  && child.getLocalName().equals("table-column")))) {
	numColumns++;
      }

      child = child.getNextSibling();
    }

    String widths[] = new String[numColumns];
    Element columns[] = new Element[numColumns];
    int colnum = 0;

    child = firstCol;
    while (child != null) {
      if (child.getNodeType() == Node.ELEMENT_NODE
	  && (child.getNodeName().equals("col")
	      || (child.getNamespaceURI().equals(foURI)
		  && child.getLocalName().equals("table-column")))) {
	Element col = (Element) child;

	columns[colnum] = col;

	if (foStylesheet) {
	  if (col.getAttribute("column-width") == null) {
	    widths[colnum] = "1*";
	  } else {
	    widths[colnum] = col.getAttribute("column-width");
	  }
	} else {
	  if (col.getAttribute("width") == null) {
	    widths[colnum] = "1*";
	  } else {
	    widths[colnum] = col.getAttribute("width");
	  }
	}

	colnum++;
      }
      child = child.getNextSibling();
    }

    float relTotal = 0;
    float relParts[] = new float[numColumns];

    float absTotal = 0;
    float absParts[] = new float[numColumns];

    for (int count = 0; count < numColumns; count++) {
      String width = widths[count];
      int pos = width.indexOf("*");
      if (pos >= 0) {
	String relPart = width.substring(0, pos);
	String absPart = width.substring(pos+1);

	try {
	  float rel = Float.parseFloat(relPart);
	  relTotal += rel;
	  relParts[count] = rel;
	} catch (NumberFormatException e) {
	  System.out.println(relPart + " is not a valid relative unit.");
	}

	int pixels = 0;
	if (absPart != null && !absPart.equals("")) {
	  pixels = convertLength(absPart);
	}

	absTotal += pixels;
	absParts[count] = pixels;
      } else {
	relParts[count] = 0;

	int pixels = 0;
	if (width != null && !width.equals("")) {
	  pixels = convertLength(width);
	}

	absTotal += pixels;
	absParts[count] = pixels;
      }
    }

    // Ok, now we have the relative widths and absolute widths in
    // two parallel arrays.
    //
    // - If there are no relative widths, output the absolute widths
    // - If there are no absolute widths, output the relative widths
    // - If there are a mixture of relative and absolute widths,
    //   - If the table width is absolute, turn these all into absolute
    //     widths.
    //   - If the table width is relative, turn these all into absolute
    //     widths in the nominalWidth and then turn them back into
    //     percentages.

    if (relTotal == 0) {
      for (int count = 0; count < numColumns; count++) {
	Float f = new Float(absParts[count]);
	if (foStylesheet) {
	  int pixels = f.intValue();
	  float inches = (float) pixels / pixelsPerInch;
	  widths[count] = inches + "in";
	} else {
	  widths[count] = Integer.toString(f.intValue());
	}
      }
    } else if (absTotal == 0) {
      for (int count = 0; count < numColumns; count++) {
	float rel = relParts[count] / relTotal * 100;
	Float f = new Float(rel);
	widths[count] = Integer.toString(f.intValue());
      }
      widths = correctRoundingError(widths);
    } else {
      int pixelWidth = nominalWidth;

      if (tableWidth.indexOf("%") <= 0) {
	pixelWidth = convertLength(tableWidth);
      }

      if (pixelWidth <= absTotal) {
	System.out.println("Table is wider than table width.");
      } else {
	pixelWidth -= absTotal;
      }

      absTotal = 0;
      for (int count = 0; count < numColumns; count++) {
	float rel = relParts[count] / relTotal * pixelWidth;
	relParts[count] = rel + absParts[count];
	absTotal += rel + absParts[count];
      }

      if (tableWidth.indexOf("%") <= 0) {
	for (int count = 0; count < numColumns; count++) {
	  Float f = new Float(relParts[count]);
	  if (foStylesheet) {
	    int pixels = f.intValue();
	    float inches = (float) pixels / pixelsPerInch;
	    widths[count] = inches + "in";
	  } else {
	    widths[count] = Integer.toString(f.intValue());
	  }
	}
      } else {
	for (int count = 0; count < numColumns; count++) {
	  float rel = relParts[count] / absTotal * 100;
	  Float f = new Float(rel);
	  widths[count] = Integer.toString(f.intValue());
	}
	widths = correctRoundingError(widths);
      }
    }

    // Now rebuild the colgroup with the right widths

    DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder docBuilder = null;

    try {
      docBuilder = docFactory.newDocumentBuilder();
    } catch (ParserConfigurationException e) {
      System.out.println("PCE!");
      return xalanRTF;
    }
    Document doc = docBuilder.newDocument();
    DocumentFragment df = doc.createDocumentFragment();
    DOMBuilder rtf = new DOMBuilder(doc, df);

    try {
      String ns = colgroup.getNamespaceURI();
      String localName = colgroup.getLocalName();
      String name = colgroup.getTagName();

      if (colgroup.getLocalName().equals("colgroup")) {
	rtf.startElement(ns, localName, name,
			 copyAttributes(colgroup));
      }

      for (colnum = 0; colnum < numColumns; colnum++) {
	Element col = columns[colnum];

	NamedNodeMap domAttr = col.getAttributes();

	AttributesImpl attr = new AttributesImpl();
	for (int acount = 0; acount < domAttr.getLength(); acount++) {
	  Node a = domAttr.item(acount);
	  String a_ns = a.getNamespaceURI();
	  String a_localName = a.getLocalName();

	  if ((foStylesheet && !a_localName.equals("column-width"))
	      || !a_localName.equalsIgnoreCase("width")) {
	    attr.addAttribute(a.getNamespaceURI(),
			      a.getLocalName(),
			      a.getNodeName(),
			      "CDATA",
			      a.getNodeValue());
	  }
	}

	if (foStylesheet) {
	  attr.addAttribute("", "column-width", "column-width", "CDATA", widths[colnum]);
	} else {
	  attr.addAttribute("", "width", "width", "CDATA", widths[colnum]);
	}

	rtf.startElement(col.getNamespaceURI(),
			 col.getLocalName(),
			 col.getTagName(),
			 attr);
	rtf.endElement(col.getNamespaceURI(),
		       col.getLocalName(),
		       col.getTagName());
      }

      if (colgroup.getLocalName().equals("colgroup")) {
	rtf.endElement(ns, localName, name);
      }
    } catch (SAXException se) {
      System.out.println("SE!");
      return xalanRTF;
    }

    return df;
  }