|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
package javax.swing.text.html; |
|
|
|
import java.awt.*; |
|
import java.util.*; |
|
import javax.swing.*; |
|
import javax.swing.text.*; |
|
import javax.swing.event.*; |
|
|
|
/** |
|
* Implements a FrameSetView, intended to support the HTML |
|
* <FRAMESET> tag. Supports the ROWS and COLS attributes. |
|
* |
|
* @author Sunita Mani |
|
* |
|
* Credit also to the hotjava browser engineers that |
|
* worked on making the allocation of space algorithms |
|
* conform to the HTML 4.0 standard and also be netscape |
|
* compatible. |
|
* |
|
*/ |
|
|
|
class FrameSetView extends javax.swing.text.BoxView { |
|
|
|
String[] children; |
|
int[] percentChildren; |
|
int[] absoluteChildren; |
|
int[] relativeChildren; |
|
int percentTotals; |
|
int absoluteTotals; |
|
int relativeTotals; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public FrameSetView(Element elem, int axis) { |
|
super(elem, axis); |
|
children = null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private String[] parseRowColSpec(HTML.Attribute key) { |
|
|
|
AttributeSet attributes = getElement().getAttributes(); |
|
String spec = "*"; |
|
if (attributes != null) { |
|
if (attributes.getAttribute(key) != null) { |
|
spec = (String)attributes.getAttribute(key); |
|
} |
|
} |
|
|
|
StringTokenizer tokenizer = new StringTokenizer(spec, ","); |
|
int nTokens = tokenizer.countTokens(); |
|
int n = getViewCount(); |
|
String[] items = new String[Math.max(nTokens, n)]; |
|
int i = 0; |
|
for (; i < nTokens; i++) { |
|
items[i] = tokenizer.nextToken().trim(); |
|
// As per the spec, 100% is the same as * |
|
// hence the mapping. |
|
|
|
if (items[i].equals("100%")) { |
|
items[i] = "*"; |
|
} |
|
} |
|
// extend spec if we have more children than specified |
|
|
|
for (; i < items.length; i++) { |
|
items[i] = "*"; |
|
} |
|
return items; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void init() { |
|
if (getAxis() == View.Y_AXIS) { |
|
children = parseRowColSpec(HTML.Attribute.ROWS); |
|
} else { |
|
children = parseRowColSpec(HTML.Attribute.COLS); |
|
} |
|
percentChildren = new int[children.length]; |
|
relativeChildren = new int[children.length]; |
|
absoluteChildren = new int[children.length]; |
|
|
|
for (int i = 0; i < children.length; i++) { |
|
percentChildren[i] = -1; |
|
relativeChildren[i] = -1; |
|
absoluteChildren[i] = -1; |
|
|
|
if (children[i].endsWith("*")) { |
|
if (children[i].length() > 1) { |
|
relativeChildren[i] = |
|
Integer.parseInt(children[i].substring( |
|
0, children[i].length()-1)); |
|
relativeTotals += relativeChildren[i]; |
|
} else { |
|
relativeChildren[i] = 1; |
|
relativeTotals += 1; |
|
} |
|
} else if (children[i].indexOf('%') != -1) { |
|
percentChildren[i] = parseDigits(children[i]); |
|
percentTotals += percentChildren[i]; |
|
} else { |
|
absoluteChildren[i] = Integer.parseInt(children[i]); |
|
} |
|
} |
|
if (percentTotals > 100) { |
|
for (int i = 0; i < percentChildren.length; i++) { |
|
if (percentChildren[i] > 0) { |
|
percentChildren[i] = |
|
(percentChildren[i] * 100) / percentTotals; |
|
} |
|
} |
|
percentTotals = 100; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, |
|
int[] spans) { |
|
if (children == null) { |
|
init(); |
|
} |
|
SizeRequirements.calculateTiledPositions(targetSpan, null, |
|
getChildRequests(targetSpan, |
|
axis), |
|
offsets, spans); |
|
} |
|
|
|
protected SizeRequirements[] getChildRequests(int targetSpan, int axis) { |
|
|
|
int span[] = new int[children.length]; |
|
|
|
spread(targetSpan, span); |
|
int n = getViewCount(); |
|
SizeRequirements[] reqs = new SizeRequirements[n]; |
|
for (int i = 0, sIndex = 0; i < n; i++) { |
|
View v = getView(i); |
|
if ((v instanceof FrameView) || (v instanceof FrameSetView)) { |
|
reqs[i] = new SizeRequirements((int) v.getMinimumSpan(axis), |
|
span[sIndex], |
|
(int) v.getMaximumSpan(axis), |
|
0.5f); |
|
sIndex++; |
|
} else { |
|
int min = (int) v.getMinimumSpan(axis); |
|
int pref = (int) v.getPreferredSpan(axis); |
|
int max = (int) v.getMaximumSpan(axis); |
|
float a = v.getAlignment(axis); |
|
reqs[i] = new SizeRequirements(min, pref, max, a); |
|
} |
|
} |
|
return reqs; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void spread(int targetSpan, int span[]) { |
|
|
|
if (targetSpan == 0) { |
|
return; |
|
} |
|
|
|
int tempSpace = 0; |
|
int remainingSpace = targetSpan; |
|
|
|
// allocate the absolute's first, they have |
|
// precedence |
|
|
|
for (int i = 0; i < span.length; i++) { |
|
if (absoluteChildren[i] > 0) { |
|
span[i] = absoluteChildren[i]; |
|
remainingSpace -= span[i]; |
|
} |
|
} |
|
|
|
// then deal with percents. |
|
|
|
tempSpace = remainingSpace; |
|
for (int i = 0; i < span.length; i++) { |
|
if (percentChildren[i] > 0 && tempSpace > 0) { |
|
span[i] = (percentChildren[i] * tempSpace) / 100; |
|
remainingSpace -= span[i]; |
|
} else if (percentChildren[i] > 0 && tempSpace <= 0) { |
|
span[i] = targetSpan / span.length; |
|
remainingSpace -= span[i]; |
|
} |
|
} |
|
|
|
|
|
if (remainingSpace > 0 && relativeTotals > 0) { |
|
for (int i = 0; i < span.length; i++) { |
|
if (relativeChildren[i] > 0) { |
|
span[i] = (remainingSpace * |
|
relativeChildren[i]) / relativeTotals; |
|
} |
|
} |
|
} else if (remainingSpace > 0) { |
|
// There are no relative columns and the space has been |
|
// under- or overallocated. In this case, turn all the |
|
// percentage and pixel specified columns to percentage |
|
// columns based on the ratio of their pixel count to the |
|
// total "virtual" size. (In the case of percentage columns, |
|
// the pixel count would equal the specified percentage |
|
// of the screen size. |
|
|
|
// This action is in accordance with the HTML |
|
// 4.0 spec (see section 8.3, the end of the discussion of |
|
// the FRAMESET tag). The precedence of percentage and pixel |
|
// specified columns is unclear (spec seems to indicate that |
|
// they share priority, however, unspecified what happens when |
|
// overallocation occurs.) |
|
|
|
// addendum is that we behave similar to netscape in that specified |
|
// widths have precedance over percentage widths... |
|
|
|
float vTotal = (float)(targetSpan - remainingSpace); |
|
float[] tempPercents = new float[span.length]; |
|
remainingSpace = targetSpan; |
|
for (int i = 0; i < span.length; i++) { |
|
// ok we know what our total space is, and we know how large each |
|
// column should be relative to each other... therefore we can use |
|
// that relative information to deduce their percentages of a whole |
|
|
|
tempPercents[i] = ((float)span[i] / vTotal) * 100.00f; |
|
span[i] = (int) ( ((float)targetSpan * tempPercents[i]) / 100.00f); |
|
remainingSpace -= span[i]; |
|
} |
|
|
|
|
|
// this is for just in case there is something left over.. if there is we just |
|
// add it one pixel at a time to the frames in order.. We shouldn't really ever get |
|
|
|
int i = 0; |
|
while (remainingSpace != 0) { |
|
if (remainingSpace < 0) { |
|
span[i++]--; |
|
remainingSpace++; |
|
} |
|
else { |
|
span[i++]++; |
|
remainingSpace--; |
|
} |
|
|
|
|
|
if (i == span.length)i = 0; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
private int parseDigits(String mixedStr) { |
|
int result = 0; |
|
for (int i = 0; i < mixedStr.length(); i++) { |
|
char ch = mixedStr.charAt(i); |
|
if (Character.isDigit(ch)) { |
|
result = (result * 10) + Character.digit(ch, 10); |
|
} |
|
} |
|
return result; |
|
} |
|
|
|
} |