diff options
Diffstat (limited to 'javax/swing')
-rw-r--r-- | javax/swing/JEditorPane.java | 13 | ||||
-rw-r--r-- | javax/swing/plaf/basic/BasicTextUI.java | 9 | ||||
-rw-r--r-- | javax/swing/text/AbstractDocument.java | 53 | ||||
-rw-r--r-- | javax/swing/text/DefaultCaret.java | 11 | ||||
-rw-r--r-- | javax/swing/text/View.java | 5 | ||||
-rw-r--r-- | javax/swing/text/html/BlockView.java | 7 | ||||
-rw-r--r-- | javax/swing/text/html/FormView.java | 184 | ||||
-rw-r--r-- | javax/swing/text/html/HTMLDocument.java | 177 | ||||
-rw-r--r-- | javax/swing/text/html/HTMLEditorKit.java | 60 | ||||
-rw-r--r-- | javax/swing/text/html/ImageView.java | 65 | ||||
-rw-r--r-- | javax/swing/text/html/InlineView.java | 5 | ||||
-rw-r--r-- | javax/swing/text/html/Option.java | 12 | ||||
-rw-r--r-- | javax/swing/text/html/ResetableModel.java | 50 | ||||
-rw-r--r-- | javax/swing/text/html/ResetablePlainDocument.java | 82 | ||||
-rw-r--r-- | javax/swing/text/html/ResetableToggleButtonModel.java | 71 | ||||
-rw-r--r-- | javax/swing/text/html/SelectComboBoxModel.java | 84 | ||||
-rw-r--r-- | javax/swing/text/html/SelectListModel.java | 106 | ||||
-rw-r--r-- | javax/swing/text/html/StyleSheet.java | 38 | ||||
-rw-r--r-- | javax/swing/text/html/TableView.java | 291 |
19 files changed, 1113 insertions, 210 deletions
diff --git a/javax/swing/JEditorPane.java b/javax/swing/JEditorPane.java index 4f7ad7119..ab683c7a5 100644 --- a/javax/swing/JEditorPane.java +++ b/javax/swing/JEditorPane.java @@ -40,7 +40,7 @@ package javax.swing; import java.awt.Container; import java.awt.Dimension; -import java.awt.Rectangle; +import java.io.BufferedInputStream; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; @@ -711,7 +711,10 @@ public class JEditorPane extends JTextComponent { try { - e = (EditorKit) Class.forName(className).newInstance(); + // XXX - This should actually depend on the classloader + // registered with the type. See registerEditorKitForContentType. + ClassLoader ldr = ClassLoader.getSystemClassLoader(); + e = (EditorKit) Class.forName(className, true, ldr).newInstance(); } catch (Exception e2) { @@ -898,7 +901,7 @@ public class JEditorPane extends JTextComponent if (type != null) setContentType(type); InputStream stream = conn.getInputStream(); - return stream; + return new BufferedInputStream(stream); } public String getText() @@ -1061,10 +1064,6 @@ public class JEditorPane extends JTextComponent throw new IOException("invalid url"); URL old = getPage(); - // Reset scrollbar when URL actually changes. - if (! page.equals(old) && page.getRef() == null) - scrollRectToVisible(new Rectangle(0, 0, 1, 1)); - // Only reload if the URL doesn't point to the same file. // This is not the same as equals because there might be different // URLs on the same file with different anchors. diff --git a/javax/swing/plaf/basic/BasicTextUI.java b/javax/swing/plaf/basic/BasicTextUI.java index d4e43c60e..e152a3034 100644 --- a/javax/swing/plaf/basic/BasicTextUI.java +++ b/javax/swing/plaf/basic/BasicTextUI.java @@ -362,7 +362,12 @@ public abstract class BasicTextUI extends TextUI return textComponent; } - public void setSize(float w, float h) + /** + * Sets the size of the renderer. This is synchronized because that + * potentially triggers layout and we don't want more than one thread + * playing with the layout information. + */ + public synchronized void setSize(float w, float h) { if (view != null) view.setSize(w, h); @@ -379,7 +384,7 @@ public abstract class BasicTextUI extends TextUI if (view != null) { Rectangle b = s instanceof Rectangle ? (Rectangle) s : s.getBounds(); - view.setSize(b.width, b.height); + setSize(b.width, b.height); view.paint(g, s); } } diff --git a/javax/swing/text/AbstractDocument.java b/javax/swing/text/AbstractDocument.java index 76f1602f4..eead8de52 100644 --- a/javax/swing/text/AbstractDocument.java +++ b/javax/swing/text/AbstractDocument.java @@ -176,6 +176,12 @@ public abstract class AbstractDocument implements Document, Serializable private BidiRootElement bidiRoot; /** + * True when we are currently notifying any listeners. This is used + * to detect illegal situations in writeLock(). + */ + private transient boolean notifyListeners; + + /** * Creates a new <code>AbstractDocument</code> with the specified * {@link Content} model. * @@ -325,10 +331,17 @@ public abstract class AbstractDocument implements Document, Serializable */ protected void fireChangedUpdate(DocumentEvent event) { - DocumentListener[] listeners = getDocumentListeners(); - - for (int index = 0; index < listeners.length; ++index) - listeners[index].changedUpdate(event); + notifyListeners = true; + try + { + DocumentListener[] listeners = getDocumentListeners(); + for (int index = 0; index < listeners.length; ++index) + listeners[index].changedUpdate(event); + } + finally + { + notifyListeners = false; + } } /** @@ -339,10 +352,17 @@ public abstract class AbstractDocument implements Document, Serializable */ protected void fireInsertUpdate(DocumentEvent event) { - DocumentListener[] listeners = getDocumentListeners(); - - for (int index = 0; index < listeners.length; ++index) - listeners[index].insertUpdate(event); + notifyListeners = true; + try + { + DocumentListener[] listeners = getDocumentListeners(); + for (int index = 0; index < listeners.length; ++index) + listeners[index].insertUpdate(event); + } + finally + { + notifyListeners = false; + } } /** @@ -353,10 +373,17 @@ public abstract class AbstractDocument implements Document, Serializable */ protected void fireRemoveUpdate(DocumentEvent event) { - DocumentListener[] listeners = getDocumentListeners(); - - for (int index = 0; index < listeners.length; ++index) - listeners[index].removeUpdate(event); + notifyListeners = true; + try + { + DocumentListener[] listeners = getDocumentListeners(); + for (int index = 0; index < listeners.length; ++index) + listeners[index].removeUpdate(event); + } + finally + { + notifyListeners = false; + } } /** @@ -1338,6 +1365,8 @@ public abstract class AbstractDocument implements Document, Serializable { if (Thread.currentThread() == currentWriter) { + if (notifyListeners) + throw new IllegalStateException("Mutation during notify"); numWriters++; return; } diff --git a/javax/swing/text/DefaultCaret.java b/javax/swing/text/DefaultCaret.java index 8557e63c3..c4c2580c3 100644 --- a/javax/swing/text/DefaultCaret.java +++ b/javax/swing/text/DefaultCaret.java @@ -1075,8 +1075,6 @@ public class DefaultCaret extends Rectangle handleHighlight(); appear(); - - adjustVisibility(this); } } @@ -1114,8 +1112,6 @@ public class DefaultCaret extends Rectangle clearHighlight(); appear(); - - adjustVisibility(this); } } @@ -1154,7 +1150,12 @@ public class DefaultCaret extends Rectangle // e.printStackTrace(); } if (area != null) - damage(area); + { + adjustVisibility(area); + if (getMagicCaretPosition() == null) + setMagicCaretPosition(new Point(area.x, area.y)); + damage(area); + } } repaint(); } diff --git a/javax/swing/text/View.java b/javax/swing/text/View.java index dc611fe49..c63ddbce7 100644 --- a/javax/swing/text/View.java +++ b/javax/swing/text/View.java @@ -335,8 +335,9 @@ public abstract class View implements SwingConstants public void preferenceChanged(View child, boolean width, boolean height) { - if (parent != null) - parent.preferenceChanged(this, width, height); + View p = getParent(); + if (p != null) + p.preferenceChanged(this, width, height); } public int getBreakWeight(int axis, float pos, float len) diff --git a/javax/swing/text/html/BlockView.java b/javax/swing/text/html/BlockView.java index 9e4d9310d..b05c983e9 100644 --- a/javax/swing/text/html/BlockView.java +++ b/javax/swing/text/html/BlockView.java @@ -40,7 +40,6 @@ package javax.swing.text.html; import gnu.javax.swing.text.html.css.Length; -import java.awt.Color; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.Shape; @@ -142,8 +141,10 @@ public class BlockView extends BoxView /** * The box painter for this view. + * + * This is package private because the TableView needs access to it. */ - private StyleSheet.BoxPainter painter; + StyleSheet.BoxPainter painter; /** * The width and height as specified in the stylesheet, null if not @@ -522,7 +523,7 @@ public class BlockView extends BoxView public float getAlignment(int axis) { if (axis == X_AXIS) - return 0.0F; + return super.getAlignment(axis); if (axis == Y_AXIS) { if (getViewCount() == 0) diff --git a/javax/swing/text/html/FormView.java b/javax/swing/text/html/FormView.java index 340f85490..ef362bd3d 100644 --- a/javax/swing/text/html/FormView.java +++ b/javax/swing/text/html/FormView.java @@ -45,6 +45,8 @@ import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; @@ -54,13 +56,15 @@ import javax.swing.ButtonModel; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; +import javax.swing.JComboBox; import javax.swing.JEditorPane; +import javax.swing.JList; import javax.swing.JPasswordField; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; -import javax.swing.JToggleButton; +import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.HyperlinkEvent; @@ -165,7 +169,7 @@ public class FormView // Perform POST. url = actionURL; conn = url.openConnection(); - postData(conn); + postData(conn, data); } else { @@ -285,9 +289,26 @@ public class FormView * * @param conn the connection */ - private void postData(URLConnection conn) + private void postData(URLConnection conn, String data) { - // TODO: Implement. + conn.setDoOutput(true); + PrintWriter out = null; + try + { + out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream())); + out.print(data); + out.flush(); + } + catch (IOException ex) + { + // Deal with this! + ex.printStackTrace(); + } + finally + { + if (out != null) + out.close(); + } } /** @@ -390,15 +411,15 @@ public class FormView } else if (type.equals("checkbox")) { - JCheckBox c = new JCheckBox(); - if (model != null) + if (model instanceof ResetableToggleButtonModel) { - boolean sel = atts.getAttribute(HTML.Attribute.CHECKED) != null; - ((JToggleButton.ToggleButtonModel) model).setSelected(sel); - c.setModel((ButtonModel) model); + ResetableToggleButtonModel m = + (ResetableToggleButtonModel) model; + JCheckBox c = new JCheckBox(); + c.setModel(m); + comp = c; + maxIsPreferred = true; } - comp = c; - maxIsPreferred = true; } else if (type.equals("image")) { @@ -434,24 +455,21 @@ public class FormView tf.setColumns(20); if (model != null) tf.setDocument((Document) model); - String value = (String) atts.getAttribute(HTML.Attribute.VALUE); - if (value != null) - tf.setText(value); tf.addActionListener(this); comp = tf; maxIsPreferred = true; } else if (type.equals("radio")) { - JRadioButton c = new JRadioButton(); - if (model != null) + if (model instanceof ResetableToggleButtonModel) { - boolean sel = atts.getAttribute(HTML.Attribute.CHECKED) != null; - ((JToggleButton.ToggleButtonModel) model).setSelected(sel); - c.setModel((ButtonModel) model); + ResetableToggleButtonModel m = + (ResetableToggleButtonModel) model; + JRadioButton c = new JRadioButton(); + c.setModel(m); + comp = c; + maxIsPreferred = true; } - comp = c; - maxIsPreferred = true; } else if (type.equals("reset")) { @@ -492,9 +510,6 @@ public class FormView tf.setColumns(20); if (model != null) tf.setDocument((Document) model); - String value = (String) atts.getAttribute(HTML.Attribute.VALUE); - if (value != null) - tf.setText(value); tf.addActionListener(this); comp = tf; maxIsPreferred = true; @@ -512,7 +527,25 @@ public class FormView JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); } - // FIXME: Implement the remaining components. + else if (tag == HTML.Tag.SELECT) + { + if (model instanceof SelectListModel) + { + SelectListModel slModel = (SelectListModel) model; + JList list = new JList(slModel); + int size = HTML.getIntegerAttributeValue(atts, HTML.Attribute.SIZE, + 1); + list.setVisibleRowCount(size); + list.setSelectionModel(slModel.getSelectionModel()); + comp = new JScrollPane(list); + } + else if (model instanceof SelectComboBoxModel) + { + SelectComboBoxModel scbModel = (SelectComboBoxModel) model; + comp = new JComboBox(scbModel); + } + maxIsPreferred = true; + } return comp; } @@ -557,6 +590,8 @@ public class FormView String type = (String) atts.getAttribute(HTML.Attribute.TYPE); if (type.equals("submit")) submitData(getFormData()); + else if (type.equals("reset")) + resetForm(); } // FIXME: Implement the remaining actions. } @@ -680,17 +715,83 @@ public class FormView { String value = null; HTML.Tag tag = (HTML.Tag) atts.getAttribute(StyleConstants.NameAttribute); - if (tag == HTML.Tag.INPUT) - value = getInputFormData(atts); - // TODO: Implement textarea and select. - if (name != null && value != null) + if (tag == HTML.Tag.SELECT) + { + getSelectData(atts, b); + } + else { - addData(b, name, value); + if (tag == HTML.Tag.INPUT) + value = getInputFormData(atts); + else if (tag == HTML.Tag.TEXTAREA) + value = getTextAreaData(atts); + if (name != null && value != null) + { + addData(b, name, value); + } } } } /** + * Fetches form data from select boxes. + * + * @param atts the attributes of the element + * + * @param b the form data string to append to + */ + private void getSelectData(AttributeSet atts, StringBuilder b) + { + String name = (String) atts.getAttribute(HTML.Attribute.NAME); + if (name != null) + { + Object m = atts.getAttribute(StyleConstants.ModelAttribute); + if (m instanceof SelectListModel) + { + SelectListModel sl = (SelectListModel) m; + ListSelectionModel lsm = sl.getSelectionModel(); + for (int i = 0; i < sl.getSize(); i++) + { + if (lsm.isSelectedIndex(i)) + { + Option o = (Option) sl.getElementAt(i); + addData(b, name, o.getValue()); + } + } + } + else if (m instanceof SelectComboBoxModel) + { + SelectComboBoxModel scb = (SelectComboBoxModel) m; + Option o = (Option) scb.getSelectedItem(); + if (o != null) + addData(b, name, o.getValue()); + } + } + } + + /** + * Fetches form data from a textarea. + * + * @param atts the attributes + * + * @return the form data + */ + private String getTextAreaData(AttributeSet atts) + { + Document doc = (Document) atts.getAttribute(StyleConstants.ModelAttribute); + String data; + try + { + data = doc.getText(0, doc.getLength()); + } + catch (BadLocationException ex) + { + data = null; + } + return data; + } + + /** * Fetches form data from an input tag. * * @param atts the attributes from which to fetch the data @@ -743,4 +844,27 @@ public class FormView String encValue = URLEncoder.encode(value); b.append(encValue); } + + /** + * Resets the form data to their initial state. + */ + private void resetForm() + { + Element form = getFormElement(); + if (form != null) + { + ElementIterator iter = new ElementIterator(form); + Element next; + while ((next = iter.next()) != null) + { + if (next.isLeaf()) + { + AttributeSet atts = next.getAttributes(); + Object m = atts.getAttribute(StyleConstants.ModelAttribute); + if (m instanceof ResetableModel) + ((ResetableModel) m).reset(); + } + } + } + } } diff --git a/javax/swing/text/html/HTMLDocument.java b/javax/swing/text/html/HTMLDocument.java index 25b44615e..f3d3ce3fa 100644 --- a/javax/swing/text/html/HTMLDocument.java +++ b/javax/swing/text/html/HTMLDocument.java @@ -49,16 +49,16 @@ import java.util.HashMap; import java.util.Stack; import java.util.Vector; +import javax.swing.ButtonGroup; import javax.swing.DefaultButtonModel; import javax.swing.JEditorPane; -import javax.swing.JToggleButton; +import javax.swing.ListSelectionModel; import javax.swing.event.DocumentEvent; import javax.swing.event.UndoableEditEvent; import javax.swing.text.AbstractDocument; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultStyledDocument; -import javax.swing.text.Document; import javax.swing.text.Element; import javax.swing.text.ElementIterator; import javax.swing.text.GapContent; @@ -729,7 +729,28 @@ public class HTMLDocument extends DefaultStyledDocument * * This is package private to avoid accessor methods. */ - Document textAreaDocument; + ResetablePlainDocument textAreaDocument; + + /** + * The current model of a select tag. Can be a ComboBoxModel or a + * ListModel depending on the type of the select box. + */ + Object selectModel; + + /** + * The current option beeing read. + */ + Option option; + + /** + * The current number of options in the current select model. + */ + int numOptions; + + /** + * The current button groups mappings. + */ + HashMap buttonGroups; /** * The token threshold. This gets increased while loading. @@ -834,13 +855,59 @@ public class HTMLDocument extends DefaultStyledDocument else if (t == HTML.Tag.TEXTAREA) { inTextArea = true; - textAreaDocument = new PlainDocument(); + textAreaDocument = new ResetablePlainDocument(); a.addAttribute(StyleConstants.ModelAttribute, textAreaDocument); } - // TODO: Handle select and option tags. - - // Build the element. - super.start(t, a); + else if (t == HTML.Tag.SELECT) + { + int size = HTML.getIntegerAttributeValue(a, HTML.Attribute.SIZE, + 1); + boolean multi = a.getAttribute(HTML.Attribute.MULTIPLE) != null; + if (size > 1 || multi) + { + SelectListModel m = new SelectListModel(); + if (multi) + m.getSelectionModel().setSelectionMode(ListSelectionModel + .MULTIPLE_INTERVAL_SELECTION); + selectModel = m; + } + else + { + selectModel = new SelectComboBoxModel(); + } + a.addAttribute(StyleConstants.ModelAttribute, selectModel); + } + if (t == HTML.Tag.OPTION) + { + option = new Option(a); + if (selectModel instanceof SelectListModel) + { + SelectListModel m = (SelectListModel) selectModel; + m.addElement(option); + if (option.isSelected()) + { + m.getSelectionModel().addSelectionInterval(numOptions, + numOptions); + m.addInitialSelection(numOptions); + } + } + else if (selectModel instanceof SelectComboBoxModel) + { + SelectComboBoxModel m = (SelectComboBoxModel) selectModel; + m.addElement(option); + if (option.isSelected()) + { + m.setSelectedItem(option); + m.setInitialSelection(option); + } + } + numOptions++; + } + else + { + // Build the element. + super.start(t, a); + } } /** @@ -849,15 +916,24 @@ public class HTMLDocument extends DefaultStyledDocument */ public void end(HTML.Tag t) { - if (t == HTML.Tag.TEXTAREA) + if (t == HTML.Tag.OPTION) { - inTextArea = false; + option = null; + } + else + { + if (t == HTML.Tag.TEXTAREA) + { + inTextArea = false; + } + else if (t == HTML.Tag.SELECT) + { + selectModel = null; + numOptions = 0; + } + // Finish the element. + super.end(t); } - - // TODO: Handle select and option tags. - - // Finish the element. - super.end(t); } private void setModel(String type, MutableAttributeSet attrs) @@ -871,9 +947,22 @@ public class HTMLDocument extends DefaultStyledDocument } else if (type.equals("text") || type.equals("password")) { - // TODO: Handle fixed length input fields. - attrs.addAttribute(StyleConstants.ModelAttribute, - new PlainDocument()); + String text = (String) attrs.getAttribute(HTML.Attribute.VALUE); + ResetablePlainDocument doc = new ResetablePlainDocument(); + if (text != null) + { + doc.setInitialText(text); + try + { + doc.insertString(0, text, null); + } + catch (BadLocationException ex) + { + // Shouldn't happen. + assert false; + } + } + attrs.addAttribute(StyleConstants.ModelAttribute, doc); } else if (type.equals("file")) { @@ -882,14 +971,50 @@ public class HTMLDocument extends DefaultStyledDocument } else if (type.equals("checkbox") || type.equals("radio")) { - JToggleButton.ToggleButtonModel model = - new JToggleButton.ToggleButtonModel(); - // TODO: Handle radio button via ButtonGroups. + ResetableToggleButtonModel model = + new ResetableToggleButtonModel(); + if (attrs.getAttribute(HTML.Attribute.SELECTED) != null) + { + model.setSelected(true); + model.setInitial(true); + } + if (type.equals("radio")) + { + String name = (String) attrs.getAttribute(HTML.Attribute.NAME); + if (name != null) + { + if (buttonGroups == null) + buttonGroups = new HashMap(); + ButtonGroup group = (ButtonGroup) buttonGroups.get(name); + if (group == null) + { + group = new ButtonGroup(); + buttonGroups.put(name, group); + } + model.setGroup(group); + } + } attrs.addAttribute(StyleConstants.ModelAttribute, model); } } } - + + /** + * Called for form tags. + */ + class FormTagAction + extends BlockAction + { + /** + * Clears the button group mapping. + */ + public void end(HTML.Tag t) + { + super.end(t); + buttonGroups = null; + } + } + /** * This action indicates that the content between starting and closing HTML * elements (like script - /script) should not be visible. The content is @@ -1327,7 +1452,7 @@ public class HTMLDocument extends DefaultStyledDocument tagToAction.put(HTML.Tag.DT, paragraphAction); tagToAction.put(HTML.Tag.EM, characterAction); tagToAction.put(HTML.Tag.FONT, convertAction); - tagToAction.put(HTML.Tag.FORM, blockAction); + tagToAction.put(HTML.Tag.FORM, new FormTagAction()); tagToAction.put(HTML.Tag.FRAME, specialAction); tagToAction.put(HTML.Tag.FRAMESET, blockAction); tagToAction.put(HTML.Tag.H1, paragraphAction); @@ -1454,6 +1579,8 @@ public class HTMLDocument extends DefaultStyledDocument textAreaContent(data); else if (inPreTag) preContent(data); + else if (option != null) + option.setLabel(new String(data)); else if (inStyleTag) { if (styles == null) @@ -1588,7 +1715,9 @@ public class HTMLDocument extends DefaultStyledDocument try { int offset = textAreaDocument.getLength(); - textAreaDocument.insertString(offset, new String(data), null); + String text = new String(data); + textAreaDocument.setInitialText(text); + textAreaDocument.insertString(offset, text, null); } catch (BadLocationException ex) { diff --git a/javax/swing/text/html/HTMLEditorKit.java b/javax/swing/text/html/HTMLEditorKit.java index 3b122bb36..0ede1c74e 100644 --- a/javax/swing/text/html/HTMLEditorKit.java +++ b/javax/swing/text/html/HTMLEditorKit.java @@ -792,52 +792,56 @@ public class HTMLEditorKit { HTML.Tag tag = (HTML.Tag) attr; - if (tag.equals(HTML.Tag.IMPLIED) || tag.equals(HTML.Tag.P) - || tag.equals(HTML.Tag.H1) || tag.equals(HTML.Tag.H2) - || tag.equals(HTML.Tag.H3) || tag.equals(HTML.Tag.H4) - || tag.equals(HTML.Tag.H5) || tag.equals(HTML.Tag.H6) - || tag.equals(HTML.Tag.DT)) + if (tag == HTML.Tag.IMPLIED || tag == HTML.Tag.P + || tag == HTML.Tag.H1 || tag == HTML.Tag.H2 + || tag == HTML.Tag.H3 || tag == HTML.Tag.H4 + || tag == HTML.Tag.H5 || tag == HTML.Tag.H6 + || tag == HTML.Tag.DT) view = new ParagraphView(element); - else if (tag.equals(HTML.Tag.LI) || tag.equals(HTML.Tag.DL) - || tag.equals(HTML.Tag.DD) || tag.equals(HTML.Tag.BODY) - || tag.equals(HTML.Tag.HTML) || tag.equals(HTML.Tag.CENTER) - || tag.equals(HTML.Tag.DIV) - || tag.equals(HTML.Tag.BLOCKQUOTE) - || tag.equals(HTML.Tag.PRE) - || tag.equals(HTML.Tag.FORM)) + else if (tag == HTML.Tag.LI || tag == HTML.Tag.DL + || tag == HTML.Tag.DD || tag == HTML.Tag.BODY + || tag == HTML.Tag.HTML || tag == HTML.Tag.CENTER + || tag == HTML.Tag.DIV + || tag == HTML.Tag.BLOCKQUOTE + || tag == HTML.Tag.PRE + || tag == HTML.Tag.FORM + // Misplaced TD and TH tags get mapped as vertical block. + // Note that correctly placed tags get mapped in TableView. + || tag == HTML.Tag.TD || tag == HTML.Tag.TH) view = new BlockView(element, View.Y_AXIS); - else if (tag.equals(HTML.Tag.IMG)) + else if (tag == HTML.Tag.TR) + // Misplaced TR tags get mapped as horizontal blocks. + // Note that correctly placed tags get mapped in TableView. + view = new BlockView(element, View.X_AXIS); + else if (tag == HTML.Tag.IMG) view = new ImageView(element); - else if (tag.equals(HTML.Tag.CONTENT)) + else if (tag == HTML.Tag.CONTENT) view = new InlineView(element); else if (tag == HTML.Tag.HEAD) view = new NullView(element); - else if (tag.equals(HTML.Tag.TABLE)) + else if (tag == HTML.Tag.TABLE) view = new javax.swing.text.html.TableView(element); - else if (tag.equals(HTML.Tag.HR)) + else if (tag == HTML.Tag.HR) view = new HRuleView(element); - else if (tag.equals(HTML.Tag.BR)) + else if (tag == HTML.Tag.BR) view = new BRView(element); - else if (tag.equals(HTML.Tag.INPUT) || tag.equals(HTML.Tag.SELECT) - || tag.equals(HTML.Tag.TEXTAREA)) + else if (tag == HTML.Tag.INPUT || tag == HTML.Tag.SELECT + || tag == HTML.Tag.TEXTAREA) view = new FormView(element); - else if (tag.equals(HTML.Tag.MENU) || tag.equals(HTML.Tag.DIR) - || tag.equals(HTML.Tag.UL) || tag.equals(HTML.Tag.OL)) + else if (tag == HTML.Tag.MENU || tag == HTML.Tag.DIR + || tag == HTML.Tag.UL || tag == HTML.Tag.OL) view = new ListView(element); - else if (tag.equals(HTML.Tag.FRAMESET)) + else if (tag == HTML.Tag.FRAMESET) view = new FrameSetView(element); - else if (tag.equals(HTML.Tag.FRAME)) + else if (tag == HTML.Tag.FRAME) view = new FrameView(element); - // FIXME: Uncomment when the views have been implemented - /* - else if (tag.equals(HTML.Tag.OBJECT)) - view = new ObjectView(element); */ + else if (tag == HTML.Tag.OBJECT) + view = new ObjectView(element); } if (view == null) { - System.err.println("missing tag->view mapping for: " + element); view = new NullView(element); } return view; diff --git a/javax/swing/text/html/ImageView.java b/javax/swing/text/html/ImageView.java index 050eb16e2..bf906e450 100644 --- a/javax/swing/text/html/ImageView.java +++ b/javax/swing/text/html/ImageView.java @@ -1,6 +1,5 @@ package javax.swing.text.html; -import gnu.javax.swing.text.html.CombinedAttributes; import gnu.javax.swing.text.html.ImageViewIconFactory; import gnu.javax.swing.text.html.css.Length; @@ -15,6 +14,8 @@ import java.net.MalformedURLException; import java.net.URL; import javax.swing.Icon; +import javax.swing.SwingUtilities; +import javax.swing.text.AbstractDocument; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.Document; @@ -40,16 +41,15 @@ public class ImageView extends View public boolean imageUpdate(Image image, int flags, int x, int y, int width, int height) { boolean widthChanged = false; - if ((flags & ImageObserver.WIDTH) != 0 - && ! getElement().getAttributes().isDefined(HTML.Attribute.WIDTH)) + if ((flags & ImageObserver.WIDTH) != 0 && spans[X_AXIS] == null) widthChanged = true; boolean heightChanged = false; - if ((flags & ImageObserver.HEIGHT) != 0 - && ! getElement().getAttributes().isDefined(HTML.Attribute.HEIGHT)) - widthChanged = true; + if ((flags & ImageObserver.HEIGHT) != 0 && spans[Y_AXIS] == null) + heightChanged = true; if (widthChanged || heightChanged) - preferenceChanged(ImageView.this, widthChanged, heightChanged); - return (flags & ALLBITS) != 0; + safePreferenceChanged(ImageView.this, widthChanged, heightChanged); + boolean ret = (flags & ALLBITS) != 0; + return ret; } } @@ -112,8 +112,10 @@ public class ImageView extends View /** * The CSS width and height. + * + * Package private to avoid synthetic accessor methods. */ - private Length[] spans; + Length[] spans; /** * The cached attributes. @@ -128,9 +130,11 @@ public class ImageView extends View public ImageView(Element element) { super(element); + spans = new Length[2]; observer = new Observer(); reloadProperties = true; reloadImage = true; + loadOnDemand = false; } /** @@ -416,7 +420,6 @@ public class ImageView extends View StyleSheet ss = getStyleSheet(); float emBase = ss.getEMBase(atts); float exBase = ss.getEXBase(atts); - spans = new Length[2]; spans[X_AXIS] = (Length) atts.getAttribute(CSS.Attribute.WIDTH); if (spans[X_AXIS] != null) { @@ -487,7 +490,9 @@ public class ImageView extends View if (src != null) { // Call getImage(URL) to allow the toolkit caching of that image URL. - newImage = Toolkit.getDefaultToolkit().getImage(src); + Toolkit tk = Toolkit.getDefaultToolkit(); + newImage = tk.getImage(src); + tk.prepareImage(newImage, -1, -1, observer); if (newImage != null && getLoadsSynchronously()) { // Load image synchronously. @@ -548,4 +553,42 @@ public class ImageView extends View tk.prepareImage(newIm, -1, -1, observer); } } + + /** + * Calls preferenceChanged from the event dispatch thread and within + * a read lock to protect us from threading issues. + * + * @param v the view + * @param width true when the width changed + * @param height true when the height changed + */ + void safePreferenceChanged(final View v, final boolean width, + final boolean height) + { + if (SwingUtilities.isEventDispatchThread()) + { + Document doc = getDocument(); + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readLock(); + try + { + preferenceChanged(v, width, height); + } + finally + { + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readUnlock(); + } + } + else + { + SwingUtilities.invokeLater(new Runnable() + { + public void run() + { + safePreferenceChanged(v, width, height); + } + }); + } + } } diff --git a/javax/swing/text/html/InlineView.java b/javax/swing/text/html/InlineView.java index cea0782b1..58edc7385 100644 --- a/javax/swing/text/html/InlineView.java +++ b/javax/swing/text/html/InlineView.java @@ -162,9 +162,8 @@ public class InlineView public int getBreakWeight(int axis, float pos, float len) { int weight; - if (nowrap) { if (getText(getStartOffset(), getEndOffset()).toString().contains("Web")) - System.err.println("Web NOWRAP"); - weight = BadBreakWeight;} + if (nowrap) + weight = BadBreakWeight; else weight = super.getBreakWeight(axis, pos, len); return weight; diff --git a/javax/swing/text/html/Option.java b/javax/swing/text/html/Option.java index 1def51b2f..18d5c2bd8 100644 --- a/javax/swing/text/html/Option.java +++ b/javax/swing/text/html/Option.java @@ -72,10 +72,10 @@ public class Option */ public Option(AttributeSet attr) { - attributes = attr; + // Protect the attribute set. + attributes = attr.copyAttributes(); label = null; - selected = false; - // FIXME: Probably initialize something using the attributes. + selected = attr.getAttribute(HTML.Attribute.SELECTED) != null; } /** @@ -151,7 +151,9 @@ public class Option */ public String getValue() { - // FIXME: Return some attribute here if specified. - return label; + String value = (String) attributes.getAttribute(HTML.Attribute.VALUE); + if (value == null) + value = label; + return value; } } diff --git a/javax/swing/text/html/ResetableModel.java b/javax/swing/text/html/ResetableModel.java new file mode 100644 index 000000000..17f65b97d --- /dev/null +++ b/javax/swing/text/html/ResetableModel.java @@ -0,0 +1,50 @@ +/* ResetableModel.java -- Form models that can be resetted + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html; + +/** + * Form models that can be resetted implement this. + */ +interface ResetableModel +{ + /** + * Resets the model. + */ + void reset(); +} diff --git a/javax/swing/text/html/ResetablePlainDocument.java b/javax/swing/text/html/ResetablePlainDocument.java new file mode 100644 index 000000000..6177f9b86 --- /dev/null +++ b/javax/swing/text/html/ResetablePlainDocument.java @@ -0,0 +1,82 @@ +/* ResetablePlainDocument.java -- A plain document for use in the HTML renderer + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html; + +import javax.swing.text.BadLocationException; +import javax.swing.text.PlainDocument; + +/** + * A PlainDocument that can be resetted. + */ +class ResetablePlainDocument + extends PlainDocument + implements ResetableModel +{ + /** + * The initial text. + */ + private String initial; + + /** + * Stores the initial text. + * + * @param text the initial text + */ + void setInitialText(String text) + { + initial = text; + } + + /** + * Resets the model. + */ + public void reset() + { + try + { + replace(0, getLength(), initial, null); + } + catch (BadLocationException ex) + { + // Shouldn't happen. + assert false; + } + } + +} diff --git a/javax/swing/text/html/ResetableToggleButtonModel.java b/javax/swing/text/html/ResetableToggleButtonModel.java new file mode 100644 index 000000000..619c24e47 --- /dev/null +++ b/javax/swing/text/html/ResetableToggleButtonModel.java @@ -0,0 +1,71 @@ +/* ResetableToggleButtonModel.java -- A toggle button model with reset support + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html; + +import javax.swing.ButtonGroup; +import javax.swing.JToggleButton.ToggleButtonModel; + +class ResetableToggleButtonModel + extends ToggleButtonModel + implements ResetableModel +{ + + /** + * The initial state. + */ + private boolean initial; + + /** + * Sets the initial selection value. + * + * @param state the initial value + */ + public void setInitial(boolean state) + { + initial = state; + } + + /** + * Resets the model. + */ + public void reset() + { + setSelected(initial); + } +} diff --git a/javax/swing/text/html/SelectComboBoxModel.java b/javax/swing/text/html/SelectComboBoxModel.java new file mode 100644 index 000000000..999746413 --- /dev/null +++ b/javax/swing/text/html/SelectComboBoxModel.java @@ -0,0 +1,84 @@ +/* SelectComboBoxModel.java -- A special ComboBoxModel for use in HTML renderer + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html; + +import javax.swing.DefaultComboBoxModel; + +/** + * A special ComboBoxModel that supports storing the initial value so that + * the combobox can be resetted later. + */ +class SelectComboBoxModel + extends DefaultComboBoxModel + implements ResetableModel +{ + + /** + * The initial selection. + */ + private Option initial; + + /** + * Sets the initial selection. + * + * @param option the initial selection + */ + void setInitialSelection(Option option) + { + initial = option; + } + + /** + * Returns the initial selection. + * + * @return the initial selection + */ + Option getInitialSelection() + { + return initial; + } + + /** + * Resets the model. + */ + public void reset() + { + setSelectedItem(initial); + } +} diff --git a/javax/swing/text/html/SelectListModel.java b/javax/swing/text/html/SelectListModel.java new file mode 100644 index 000000000..23bfaa11b --- /dev/null +++ b/javax/swing/text/html/SelectListModel.java @@ -0,0 +1,106 @@ +/* OptionListModel.java -- A special ListModel for use in the HTML renderer + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html; + +import java.util.BitSet; + +import javax.swing.DefaultListModel; +import javax.swing.DefaultListSelectionModel; +import javax.swing.ListSelectionModel; + +/** + * A special list model that encapsulates its selection model and supports + * storing of the initial value so that it can be resetted. + */ +class SelectListModel + extends DefaultListModel + implements ResetableModel +{ + /** + * The selection model. + */ + private DefaultListSelectionModel selectionModel; + + /** + * The initial selection. + */ + private BitSet initialSelection; + + /** + * Creates a new SelectListModel. + */ + SelectListModel() + { + selectionModel = new DefaultListSelectionModel(); + initialSelection = new BitSet(); + } + + /** + * Sets the initial selection. + * + * @param init the initial selection + */ + void addInitialSelection(int init) + { + initialSelection.set(init); + } + + /** + * Resets the model. + */ + public void reset() + { + selectionModel.clearSelection(); + for (int i = initialSelection.size(); i >= 0; i--) + { + if (initialSelection.get(i)) + selectionModel.addSelectionInterval(i, i); + } + } + + /** + * Returns the associated selection model. + * + * @return the associated selection model + */ + ListSelectionModel getSelectionModel() + { + return selectionModel; + } +} diff --git a/javax/swing/text/html/StyleSheet.java b/javax/swing/text/html/StyleSheet.java index 15384e16d..01f19fd7b 100644 --- a/javax/swing/text/html/StyleSheet.java +++ b/javax/swing/text/html/StyleSheet.java @@ -38,6 +38,7 @@ exception statement from your version. */ package javax.swing.text.html; +import gnu.javax.swing.text.html.css.BorderWidth; import gnu.javax.swing.text.html.css.CSSColor; import gnu.javax.swing.text.html.css.CSSParser; import gnu.javax.swing.text.html.css.CSSParserCallback; @@ -511,8 +512,7 @@ public class StyleSheet extends StyleContext } catch (IOException ex) { - // Shouldn't happen. And if, then we - System.err.println("IOException while parsing stylesheet: " + ex.getMessage()); + // Shouldn't happen. And if, then don't let it bork the outside code. } // Clean up resolved styles cache so that the new styles are recognized // on next stylesheet request. @@ -760,12 +760,45 @@ public class StyleSheet extends StyleContext cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING_RIGHT, l); cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING_TOP, l); } + o = tableAttrs.getAttribute(HTML.Attribute.BORDER); + cssAttr = translateBorder(cssAttr, o); } + + // Translate border attribute. + o = cssAttr.getAttribute(HTML.Attribute.BORDER); + cssAttr = translateBorder(cssAttr, o); + // TODO: Add more mappings. return cssAttr; } /** + * Translates a HTML border attribute to a corresponding set of CSS + * attributes. + * + * @param cssAttr the original set of CSS attributes to add to + * @param o the value of the border attribute + * + * @return the new set of CSS attributes + */ + private AttributeSet translateBorder(AttributeSet cssAttr, Object o) + { + if (o != null) + { + BorderWidth l = new BorderWidth(o.toString()); + if (l.getValue() > 0) + { + cssAttr = addAttribute(cssAttr, CSS.Attribute.BORDER_WIDTH, l); + cssAttr = addAttribute(cssAttr, CSS.Attribute.BORDER_STYLE, + "solid"); + cssAttr = addAttribute(cssAttr, CSS.Attribute.BORDER_COLOR, + new CSSColor("black")); + } + } + return cssAttr; + } + + /** * Adds an attribute to the given set and returns a new set. This is implemented * to convert StyleConstants attributes to CSS before forwarding them to the superclass. * The StyleConstants attribute do not have corresponding CSS entry, the attribute @@ -1397,7 +1430,6 @@ public class StyleSheet extends StyleContext } if (centerY == -1) { - System.err.println("WARNING LI child is not a paragraph view " + itemView.getView(0) + ", " + itemView.getViewCount()); centerY =(int) (h / 2 + y); } g.fillOval(centerX - 3, centerY - 3, 6, 6); diff --git a/javax/swing/text/html/TableView.java b/javax/swing/text/html/TableView.java index 90b3ecc4f..f87d7b35f 100644 --- a/javax/swing/text/html/TableView.java +++ b/javax/swing/text/html/TableView.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.text.html; +import java.awt.Graphics; +import java.awt.Rectangle; import java.awt.Shape; import gnu.javax.swing.text.html.css.Length; @@ -45,7 +47,6 @@ import gnu.javax.swing.text.html.css.Length; import javax.swing.SizeRequirements; import javax.swing.event.DocumentEvent; import javax.swing.text.AttributeSet; -import javax.swing.text.BoxView; import javax.swing.text.Element; import javax.swing.text.StyleConstants; import javax.swing.text.View; @@ -58,7 +59,7 @@ import javax.swing.text.ViewFactory; * and the rows are horizontal BoxViews that contain the actual columns. */ class TableView - extends BoxView + extends BlockView implements ViewFactory { @@ -69,6 +70,17 @@ class TableView extends BlockView { /** + * Has true at column positions where an above row's cell overlaps into + * this row. + */ + boolean[] overlap; + + /** + * Stores the row index of this row. + */ + int rowIndex; + + /** * Creates a new RowView. * * @param el the element for the row view @@ -80,8 +92,8 @@ class TableView public void replace(int offset, int len, View[] views) { - super.replace(offset, len, views); gridValid = false; + super.replace(offset, len, views); } /** @@ -137,26 +149,63 @@ class TableView /** * Lays out the columns in this row. */ + protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, + int spans[]) + { + super.layoutMinorAxis(targetSpan, axis, offsets, spans); + + // Adjust columns that have rowSpan > 1. + int numCols = getViewCount(); + for (int i = 0; i < numCols; i++) + { + View v = getView(i); + if (v instanceof CellView) + { + CellView cell = (CellView) v; + if (cell.rowSpan > 1) + { + for (int r = 1; r < cell.rowSpan; r++) + { + spans[i] += TableView.this.getSpan(axis, rowIndex + r); + spans[i] += cellSpacing; + } + } + } + } + } + + /** + * Lays out the columns in this row. + */ protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int spans[]) { updateGrid(); int numCols = offsets.length; int realColumn = 0; - for (int i = 0; i < numCols; i++) + int colCount = getViewCount(); + for (int i = 0; i < numColumns;) { - View v = getView(i); - if (v instanceof CellView) + if (! overlap[i] && realColumn < colCount) { - CellView cv = (CellView) v; - offsets[i] = columnOffsets[realColumn]; - spans[i] = 0; - for (int j = 0; j < cv.colSpan; j++, realColumn++) + View v = getView(realColumn); + if (v instanceof CellView) { - spans[i] += columnSpans[realColumn]; - if (j < cv.colSpan - 1) - spans[i] += cellSpacing; + CellView cv = (CellView) v; + offsets[realColumn] = columnOffsets[i]; + spans[realColumn] = 0; + for (int j = 0; j < cv.colSpan; j++, i++) + { + spans[realColumn] += columnSpans[i]; + if (j < cv.colSpan - 1) + spans[realColumn] += cellSpacing; + } } + realColumn++; + } + else + { + i++; } } } @@ -175,6 +224,11 @@ class TableView int colSpan; /** + * The number of rows that this cell spans. + */ + int rowSpan; + + /** * Creates a new CellView for the specified element. * * @param el the element for which to create the colspan @@ -213,6 +267,20 @@ class TableView colSpan = 1; } } + rowSpan = 1; + o = atts.getAttribute(HTML.Attribute.ROWSPAN); + if (o != null) + { + try + { + rowSpan = Integer.parseInt(o.toString()); + } + catch (NumberFormatException ex) + { + // Couldn't parse the colspan, assume 1. + rowSpan = 1; + } + } } } @@ -256,6 +324,11 @@ class TableView Length[] columnWidths; /** + * The total number of columns. + */ + int numColumns; + + /** * The table width. */ private Length width; @@ -263,7 +336,7 @@ class TableView /** * Indicates if the grid setup is ok. */ - boolean gridValid; + boolean gridValid = false; /** * Additional space that is added _between_ table cells. @@ -273,6 +346,11 @@ class TableView int cellSpacing; /** + * A cached Rectangle object for reuse in paint(). + */ + private Rectangle tmpRect; + + /** * Creates a new HTML table view for the specified element. * * @param el the element for the table view @@ -281,6 +359,7 @@ class TableView { super(el, Y_AXIS); totalColumnRequirements = new SizeRequirements(); + tmpRect = new Rectangle(); } /** @@ -292,21 +371,20 @@ class TableView View view = null; AttributeSet atts = elem.getAttributes(); Object name = atts.getAttribute(StyleConstants.NameAttribute); - if (name instanceof HTML.Tag) - { - HTML.Tag tag = (HTML.Tag) name; - if (tag == HTML.Tag.TR) - view = new RowView(elem); - else if (tag == HTML.Tag.TD || tag == HTML.Tag.TH) - view = new CellView(elem); - else if (tag == HTML.Tag.CAPTION) - view = new ParagraphView(elem); - } - - // If we haven't mapped the element, then fall back to the standard - // view factory. - if (view == null) + AttributeSet pAtts = elem.getParentElement().getAttributes(); + Object pName = pAtts.getAttribute(StyleConstants.NameAttribute); + + if (name == HTML.Tag.TR && pName == HTML.Tag.TABLE) + view = new RowView(elem); + else if ((name == HTML.Tag.TD || name == HTML.Tag.TH) + && pName == HTML.Tag.TR) + view = new CellView(elem); + else if (name == HTML.Tag.CAPTION) + view = new ParagraphView(elem); + else { + // If we haven't mapped the element, then fall back to the standard + // view factory. View parent = getParent(); if (parent != null) { @@ -343,7 +421,7 @@ class TableView * * @return the stylesheet associated with this view */ - private StyleSheet getStyleSheet() + protected StyleSheet getStyleSheet() { HTMLDocument doc = (HTMLDocument) getDocument(); return doc.getStyleSheet(); @@ -405,7 +483,8 @@ class TableView { updateGrid(); - // Mark all rows as invalid. + // Mark all rows as invalid along their minor axis to force correct + // layout of multi-row cells. int n = getViewCount(); for (int i = 0; i < n; i++) { @@ -446,7 +525,8 @@ class TableView SizeRequirements total = new SizeRequirements(); SizeRequirements relTotal = new SizeRequirements(); float totalPercent = 0.F; - for (int c = 0; c < numCols; ) + int realCol = 0; + for (int c = 0; c < numCols; c++) { View v = rowView.getView(c); if (v instanceof CellView) @@ -463,7 +543,7 @@ class TableView long currentMax = 0; for (int i = 0; i < colSpan; i++) { - SizeRequirements req = columnRequirements[c + i]; + SizeRequirements req = columnRequirements[realCol]; currentMin += req.minimum; currentPref += req.preferred; currentMax += req.maximum; @@ -474,15 +554,15 @@ class TableView // Distribute delta. for (int i = 0; i < colSpan; i++) { - SizeRequirements req = columnRequirements[c + i]; + SizeRequirements req = columnRequirements[realCol]; if (deltaMin > 0) req.minimum += deltaMin / colSpan; if (deltaPref > 0) req.preferred += deltaPref / colSpan; if (deltaMax > 0) req.maximum += deltaMax / colSpan; - if (columnWidths[c + i] == null - || ! columnWidths[c + i].isPercentage()) + if (columnWidths[realCol] == null + || ! columnWidths[realCol].isPercentage()) { total.minimum += req.minimum; total.preferred += req.preferred; @@ -493,35 +573,37 @@ class TableView relTotal.minimum = Math.max(relTotal.minimum, (int) (req.minimum - * columnWidths[c + i].getValue())); + * columnWidths[realCol].getValue())); relTotal.preferred = Math.max(relTotal.preferred, (int) (req.preferred - * columnWidths[c + i].getValue())); + * columnWidths[realCol].getValue())); relTotal.maximum = Math.max(relTotal.maximum, (int) (req.maximum - * columnWidths[c + i].getValue())); - totalPercent += columnWidths[c + i].getValue(); + * columnWidths[realCol].getValue())); + totalPercent += columnWidths[realCol].getValue(); } } + realCol += colSpan; } else { // Shortcut for colSpan == 1. - SizeRequirements req = columnRequirements[c]; + SizeRequirements req = columnRequirements[realCol]; req.minimum = Math.max(req.minimum, - (int) cellView.getMinimumSpan(X_AXIS)); + (int) cellView.getMinimumSpan(X_AXIS)); req.preferred = Math.max(req.preferred, - (int) cellView.getPreferredSpan(X_AXIS)); + (int) cellView.getPreferredSpan(X_AXIS)); req.maximum = Math.max(req.maximum, - (int) cellView.getMaximumSpan(X_AXIS)); - if (columnWidths[c] == null - || ! columnWidths[c].isPercentage()) + (int) cellView.getMaximumSpan(X_AXIS)); + if (columnWidths[realCol] == null + || ! columnWidths[realCol].isPercentage()) { - total.minimum += columnRequirements[c].minimum; - total.preferred += columnRequirements[c].preferred; - total.maximum += columnRequirements[c].maximum; + total.minimum += columnRequirements[realCol].minimum; + total.preferred += + columnRequirements[realCol].preferred; + total.maximum += columnRequirements[realCol].maximum; } else { @@ -539,11 +621,9 @@ class TableView / columnWidths[c].getValue())); totalPercent += columnWidths[c].getValue(); } + realCol += 1; } - c += colSpan; } - else - c++; } // Update the total requirements as follows: @@ -681,38 +761,67 @@ class TableView for (int r = 0; r < numRows; r++) { View rowView = getView(r); - int numCols; + int numCols = 0; if (rowView instanceof RowView) - numCols = ((RowView) rowView).getViewCount(); - else - numCols = 0; + { + int numCells = ((RowView) rowView).getViewCount(); + for (int i = 0; i < numCells; i++) + { + View v = rowView.getView(i); + if (v instanceof CellView) + numCols += ((CellView) v).colSpan; + } + } maxColumns = Math.max(numCols, maxColumns); } + numColumns = maxColumns; columnWidths = new Length[maxColumns]; + int[] rowSpans = new int[maxColumns]; for (int r = 0; r < numRows; r++) { - View rowView = getView(r); - int numCols; - if (rowView instanceof RowView) - numCols = ((RowView) rowView).getViewCount(); - else - numCols = 0; - int colIndex = 0; - for (int c = 0; c < numCols; c++) + View view = getView(r); + if (view instanceof RowView) { - View v = rowView.getView(c); - if (v instanceof CellView) + RowView rowView = (RowView) view; + rowView.rowIndex = r; + rowView.overlap = new boolean[maxColumns]; + int colIndex = 0; + int colCount = rowView.getViewCount(); + for (int c = 0; c < maxColumns;) { - CellView cv = (CellView) v; - Object o = - cv.getAttributes().getAttribute(CSS.Attribute.WIDTH); - if (o != null && columnWidths[colIndex] == null - && o instanceof Length) + if (rowSpans[c] > 0) + { + rowSpans[c]--; + rowView.overlap[c] = true; + c++; + } + else if (colIndex < colCount) + { + View v = rowView.getView(colIndex); + colIndex++; + if (v instanceof CellView) + { + CellView cv = (CellView) v; + Object o = + cv.getAttributes().getAttribute(CSS.Attribute.WIDTH); + if (o != null && columnWidths[c] == null + && o instanceof Length) + { + columnWidths[c]= (Length) o; + columnWidths[c].setFontBases(emBase, exBase); + } + int rs = cv.rowSpan - 1; + for (int col = cv.colSpan - 1; col >= 0; col--) + { + rowSpans[c] = rs; + c++; + } + } + } + else { - columnWidths[colIndex]= (Length) o; - columnWidths[colIndex].setFontBases(emBase, exBase); + c++; } - colIndex += cv.colSpan; } } } @@ -752,8 +861,10 @@ class TableView /** * Fetches CSS and HTML layout attributes. */ - private void setPropertiesFromAttributes() + protected void setPropertiesFromAttributes() { + super.setPropertiesFromAttributes(); + // Fetch and parse cell spacing. AttributeSet atts = getAttributes(); StyleSheet ss = getStyleSheet(); @@ -794,6 +905,16 @@ class TableView protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int spans[]) { + // Mark all rows as invalid along their minor axis to force correct + // layout of multi-row cells. + int n = getViewCount(); + for (int i = 0; i < n; i++) + { + View row = getView(i); + if (row instanceof RowView) + ((RowView) row).layoutChanged(axis); + } + int adjust = (getViewCount() + 1) * cellSpacing; super.layoutMajorAxis(targetSpan - adjust, axis, offsets, spans); for (int i = 0; i < offsets.length; i++) @@ -828,7 +949,27 @@ class TableView public void replace(int offset, int len, View[] views) { - super.replace(offset, len, views); gridValid = false; + super.replace(offset, len, views); } + + /** + * We can't use the super class's paint() method because it might cut + * off multi-row children. Instead we trigger painting for all rows + * and let the rows sort out what to paint and what not. + */ + public void paint(Graphics g, Shape a) + { + Rectangle rect = a instanceof Rectangle ? (Rectangle) a : a.getBounds(); + painter.paint(g, rect.x, rect.y, rect.width, rect.height, this); + int nRows = getViewCount(); + Rectangle inside = getInsideAllocation(a); + for (int r = 0; r < nRows; r++) + { + tmpRect.setBounds(inside); + childAllocation(r, tmpRect); + paintChild(g, tmpRect, r); + } + } + } |