From 5b46b46ff3fdcc16a7420b55fb57b804fb1eb3e3 Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Fri, 1 Dec 2006 23:20:28 +0000 Subject: 2006-12-01 Roman Kennke * javax/swing/text/html/HTML.java (Attribute.DYNAMIC_CLASS): New field. (Attribute.PSEUDO_CLASS): New field. * javax/swing/text/html/HTMLDocument.java (HTMLReader.CharacterAction.start): Initialize anchor with link pseudo attribute. (updateSpecialClass): New helper method. Updates the dynamic or pseudo class for anchor tags. * javax/swing/text/html/HTMLEditorKit.java (LinkController.lastAnchorElement): New field. For tracking enter/exit of anchors. (LinkController.activateLink): Set pseudo class to 'visited'. (LinkController.mouseMoved): Added support for tracking the 'hover' dynamic class. * javax/swing/text/html/InlineView.java (changedUpdate): Fetch new properties. * javax/swing/text/html/StyleSheet.java (attributeSetToMap): New helper method. (getRule): Also append dynamic and pseudo class to key. (resolveStyle): Resolve style based generally on all attributes. * javax/swing/text/html/TableView.java (RowView.layoutMajorAxis): Make sure the grid is valid. (updateGrid): Made package private. * gnu/javax/swing/text/html/css/Selector.java (calculateSpecificity): Added support for dynamic and pseudo classes. (matches): Changed to operate on general attributes. Added support for dynamic and pseudo classes. --- ChangeLog | 30 ++++++++++++ gnu/javax/swing/text/html/css/Selector.java | 17 +++++-- javax/swing/text/html/HTML.java | 10 ++++ javax/swing/text/html/HTMLDocument.java | 49 +++++++++++++++++++ javax/swing/text/html/HTMLEditorKit.java | 44 +++++++++++++++-- javax/swing/text/html/InlineView.java | 2 + javax/swing/text/html/StyleSheet.java | 73 ++++++++++++++++++++--------- javax/swing/text/html/TableView.java | 5 +- 8 files changed, 201 insertions(+), 29 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2e1e969da..43ef94e5d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,33 @@ +2006-12-01 Roman Kennke + + * javax/swing/text/html/HTML.java + (Attribute.DYNAMIC_CLASS): New field. + (Attribute.PSEUDO_CLASS): New field. + * javax/swing/text/html/HTMLDocument.java + (HTMLReader.CharacterAction.start): Initialize anchor with link + pseudo attribute. + (updateSpecialClass): New helper method. Updates the dynamic + or pseudo class for anchor tags. + * javax/swing/text/html/HTMLEditorKit.java + (LinkController.lastAnchorElement): New field. For tracking + enter/exit of anchors. + (LinkController.activateLink): Set pseudo class to 'visited'. + (LinkController.mouseMoved): Added support for tracking + the 'hover' dynamic class. + * javax/swing/text/html/InlineView.java + (changedUpdate): Fetch new properties. + * javax/swing/text/html/StyleSheet.java + (attributeSetToMap): New helper method. + (getRule): Also append dynamic and pseudo class to key. + (resolveStyle): Resolve style based generally on all attributes. + * javax/swing/text/html/TableView.java + (RowView.layoutMajorAxis): Make sure the grid is valid. + (updateGrid): Made package private. + * gnu/javax/swing/text/html/css/Selector.java + (calculateSpecificity): Added support for dynamic and pseudo classes. + (matches): Changed to operate on general attributes. + Added support for dynamic and pseudo classes. + 2006-12-01 Mario Torre * java/text/DecimalFormat.java (formatInternal): move the formatting of diff --git a/gnu/javax/swing/text/html/css/Selector.java b/gnu/javax/swing/text/html/css/Selector.java index b8128233b..210df3a7b 100644 --- a/gnu/javax/swing/text/html/css/Selector.java +++ b/gnu/javax/swing/text/html/css/Selector.java @@ -38,6 +38,7 @@ exception statement from your version. */ package gnu.javax.swing.text.html.css; +import java.util.Map; import java.util.StringTokenizer; /** @@ -98,7 +99,7 @@ public class Selector * @return true when this selector matches the element path, * false otherwise */ - public boolean matches(String[] tags, String[] pathClasses, String[] pathIds) + public boolean matches(String[] tags, Map[] attributes) { // TODO: This implements class, id and descendent matching. These are // the most commonly used selector matchers in CSS together with HTML. @@ -119,15 +120,22 @@ public class Selector boolean tagMatch = false; for (; tagIndex < numTags && tagMatch == false; tagIndex++) { + Object pathClass = attributes[tagIndex].get("class"); + // Try pseudo class too. + Object pseudoClass = attributes[tagIndex].get("_pseudo"); + Object dynClass = attributes[tagIndex].get("_dynamic"); + Object pathId = attributes[tagIndex].get("id"); String tag = elements[j]; String clazz = classes[j]; String id = ids[j]; tagMatch = tag.equals("") || tag.equals("*") || tag.equals(tags[tagIndex]); tagMatch = tagMatch && (clazz.equals("*") - || clazz.equals(pathClasses[tagIndex])); + || clazz.equals(dynClass) + || clazz.equals(pseudoClass) + || clazz.equals(pathClass)); tagMatch = tagMatch && (id.equals("*") - || id.equals(pathIds[tagIndex])); + || id.equals(pathId)); // For the last element in the selector we must not look // further. if (j == 0) @@ -190,6 +198,9 @@ public class Selector { String sel = selector[i]; int clazzIndex = sel.indexOf('.'); + // Try pseudo class too. + if (clazzIndex == -1) + clazzIndex = sel.indexOf(':'); int idIndex = sel.indexOf('#'); String clazz; if (clazzIndex == -1) diff --git a/javax/swing/text/html/HTML.java b/javax/swing/text/html/HTML.java index 2c908f6fc..29e6335a0 100644 --- a/javax/swing/text/html/HTML.java +++ b/javax/swing/text/html/HTML.java @@ -464,6 +464,16 @@ public class HTML */ public static final Attribute WIDTH = new Attribute("width"); + /** + * This is used to reflect the pseudo class for the a tag. + */ + static final Attribute PSEUDO_CLASS = new Attribute("_pseudo"); + + /** + * This is used to reflect the dynamic class for the a tag. + */ + static final Attribute DYNAMIC_CLASS = new Attribute("_dynamic"); + /** * The attribute name. */ diff --git a/javax/swing/text/html/HTMLDocument.java b/javax/swing/text/html/HTMLDocument.java index c4f4222ec..8ef4c0e87 100644 --- a/javax/swing/text/html/HTMLDocument.java +++ b/javax/swing/text/html/HTMLDocument.java @@ -791,6 +791,10 @@ public class HTMLDocument extends DefaultStyledDocument // Put the old attribute set on the stack. pushCharacterStyle(); + // Initialize with link pseudo class. + if (t == HTML.Tag.A) + a.addAttribute(HTML.Attribute.PSEUDO_CLASS, "link"); + // Just add the attributes in a. charAttr.addAttribute(t, a.copyAttributes()); } @@ -2117,4 +2121,49 @@ public void setOuterHTML(Element elem, String htmlText) { return baseTarget; } + + /** + * Updates the A tag's pseudo class value in response to a hyperlink + * action. + * + * @param el the corresponding element + * @param value the new value + */ + void updateSpecialClass(Element el, HTML.Attribute cl, String value) + { + try + { + writeLock(); + DefaultDocumentEvent ev = + new DefaultDocumentEvent(el.getStartOffset(), 1, + DocumentEvent.EventType.CHANGE); + AttributeSet elAtts = el.getAttributes(); + AttributeSet anchorAtts = (AttributeSet) elAtts.getAttribute(HTML.Tag.A); + if (anchorAtts != null) + { + AttributeSet copy = elAtts.copyAttributes(); + StyleSheet ss = getStyleSheet(); + if (value != null) + { + anchorAtts = ss.addAttribute(anchorAtts, cl, value); + } + else + { + anchorAtts = ss.removeAttribute(anchorAtts, cl); + } + MutableAttributeSet matts = (MutableAttributeSet) elAtts; + ev.addEdit(new AttributeUndoableEdit(el, copy, false)); + matts.removeAttribute(HTML.Tag.A); + matts.addAttribute(HTML.Tag.A, anchorAtts); + ev.end(); + fireChangedUpdate(ev); + fireUndoableEditUpdate(new UndoableEditEvent(this, ev)); + } + } + finally + { + writeUnlock(); + } + } + } diff --git a/javax/swing/text/html/HTMLEditorKit.java b/javax/swing/text/html/HTMLEditorKit.java index 78b5df99f..3b122bb36 100644 --- a/javax/swing/text/html/HTMLEditorKit.java +++ b/javax/swing/text/html/HTMLEditorKit.java @@ -98,7 +98,12 @@ public class HTMLEditorKit extends MouseAdapter implements MouseMotionListener, Serializable { - + + /** + * The element of the last anchor tag. + */ + private Element lastAnchorElement; + /** * Constructor */ @@ -162,10 +167,41 @@ public class HTMLEditorKit AttributeSet aAtts = (AttributeSet) el.getAttributes().getAttribute(HTML.Tag.A); if (aAtts != null) - newCursor = kit.getLinkCursor(); + { + if (el != lastAnchorElement) + { + if (lastAnchorElement != null) + htmlDoc.updateSpecialClass(lastAnchorElement, + HTML.Attribute.DYNAMIC_CLASS, + null); + lastAnchorElement = el; + htmlDoc.updateSpecialClass(el, + HTML.Attribute.DYNAMIC_CLASS, + "hover"); + } + newCursor = kit.getLinkCursor(); + } + else + { + if (lastAnchorElement != null) + htmlDoc.updateSpecialClass(lastAnchorElement, + HTML.Attribute.DYNAMIC_CLASS, + null); + lastAnchorElement = null; + } + } + else + { + if (lastAnchorElement != null) + htmlDoc.updateSpecialClass(lastAnchorElement, + HTML.Attribute.DYNAMIC_CLASS, + null); + lastAnchorElement = null; } if (editor.getCursor() != newCursor) - editor.setCursor(newCursor); + { + editor.setCursor(newCursor); + } } } } @@ -198,6 +234,8 @@ public class HTMLEditorKit if (anchorAtts != null) { href = (String) anchorAtts.getAttribute(HTML.Attribute.HREF); + htmlDoc.updateSpecialClass(el, HTML.Attribute.PSEUDO_CLASS, + "visited"); } else { diff --git a/javax/swing/text/html/InlineView.java b/javax/swing/text/html/InlineView.java index 6b134ae39..cea0782b1 100644 --- a/javax/swing/text/html/InlineView.java +++ b/javax/swing/text/html/InlineView.java @@ -139,6 +139,7 @@ public class InlineView StyleSheet ss = getStyleSheet(); attributes = ss.getViewAttributes(this); preferenceChanged(null, true, true); + setPropertiesFromAttributes(); } /** @@ -303,4 +304,5 @@ public class InlineView } return span; } + } diff --git a/javax/swing/text/html/StyleSheet.java b/javax/swing/text/html/StyleSheet.java index eadd325f2..acc14e73e 100644 --- a/javax/swing/text/html/StyleSheet.java +++ b/javax/swing/text/html/StyleSheet.java @@ -68,6 +68,7 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import javax.swing.border.Border; import javax.swing.event.ChangeListener; @@ -302,11 +303,21 @@ public class StyleSheet extends StyleContext selector.append('#'); selector.append(atts.getAttribute(HTML.Attribute.ID)); } - else if (atts.isDefined(HTML.Attribute.CLASS)) + if (atts.isDefined(HTML.Attribute.CLASS)) { selector.append('.'); selector.append(atts.getAttribute(HTML.Attribute.CLASS)); } + if (atts.isDefined(HTML.Attribute.DYNAMIC_CLASS)) + { + selector.append(':'); + selector.append(atts.getAttribute(HTML.Attribute.DYNAMIC_CLASS)); + } + if (atts.isDefined(HTML.Attribute.PSEUDO_CLASS)) + { + selector.append(':'); + selector.append(atts.getAttribute(HTML.Attribute.PSEUDO_CLASS)); + } selector.append(' '); } selector.append(t.toString()); @@ -328,11 +339,21 @@ public class StyleSheet extends StyleContext selector.append('#'); selector.append(atts.getAttribute(HTML.Attribute.ID)); } - else if (atts.isDefined(HTML.Attribute.CLASS)) + if (atts.isDefined(HTML.Attribute.CLASS)) { selector.append('.'); selector.append(atts.getAttribute(HTML.Attribute.CLASS)); } + if (atts.isDefined(HTML.Attribute.DYNAMIC_CLASS)) + { + selector.append(':'); + selector.append(atts.getAttribute(HTML.Attribute.DYNAMIC_CLASS)); + } + if (atts.isDefined(HTML.Attribute.PSEUDO_CLASS)) + { + selector.append(':'); + selector.append(atts.getAttribute(HTML.Attribute.PSEUDO_CLASS)); + } } return getResolvedStyle(selector.toString(), path, t); } @@ -359,7 +380,7 @@ public class StyleSheet extends StyleContext /** * Resolves a style. This creates arrays that hold the tag names, * class and id attributes and delegates the work to - * {@link #resolveStyle(String, String[], String[], String[])}. + * {@link #resolveStyle(String, String[], Map[])}. * * @param selector the selector * @param path the Element path @@ -371,8 +392,7 @@ public class StyleSheet extends StyleContext { int count = path.size(); String[] tags = new String[count]; - String[] ids = new String[count]; - String[] classes = new String[count]; + Map[] attributes = new Map[count]; for (int i = 0; i < count; i++) { Element el = (Element) path.get(i); @@ -393,24 +413,16 @@ public class StyleSheet extends StyleContext tags[i] = t.toString(); else tags[i] = null; - if (atts.isDefined(HTML.Attribute.CLASS)) - classes[i] = atts.getAttribute(HTML.Attribute.CLASS).toString(); - else - classes[i] = null; - if (atts.isDefined(HTML.Attribute.ID)) - ids[i] = atts.getAttribute(HTML.Attribute.ID).toString(); - else - ids[i] = null; + attributes[i] = attributeSetToMap(atts); } else { tags[i] = null; - classes[i] = null; - ids[i] = null; + attributes[i] = null; } } tags[0] = tag.toString(); - return resolveStyle(selector, tags, ids, classes); + return resolveStyle(selector, tags, attributes); } /** @@ -418,13 +430,11 @@ public class StyleSheet extends StyleContext * * @param selector the selector * @param tags the tags - * @param ids the corresponding ID attributes - * @param classes the corresponding CLASS attributes + * @param attributes the attributes of the tags * * @return the resolved style */ - private Style resolveStyle(String selector, String[] tags, String[] ids, - String[] classes) + private Style resolveStyle(String selector, String[] tags, Map[] attributes) { // FIXME: This style resolver is not correct. But it works good enough for // the default.css. @@ -433,7 +443,7 @@ public class StyleSheet extends StyleContext for (Iterator i = css.iterator(); i.hasNext();) { CSSStyle style = (CSSStyle) i.next(); - if (style.selector.matches(tags, classes, ids)) + if (style.selector.matches(tags, attributes)) styles.add(style); } @@ -446,7 +456,7 @@ public class StyleSheet extends StyleContext for (int j = ss.css.size() - 1; j >= 0; j--) { CSSStyle style = (CSSStyle) ss.css.get(j); - if (style.selector.matches(tags, classes, ids)) + if (style.selector.matches(tags, attributes)) styles.add(style); } } @@ -1395,4 +1405,23 @@ public class StyleSheet extends StyleContext } } + /** + * Converts an AttributeSet to a Map. This is used for CSS resolving. + * + * @param atts the attributes to convert + * + * @return the converted map + */ + private Map attributeSetToMap(AttributeSet atts) + { + HashMap map = new HashMap(); + Enumeration keys = atts.getAttributeNames(); + while (keys.hasMoreElements()) + { + Object key = keys.nextElement(); + Object value = atts.getAttribute(key); + map.put(key.toString(), value.toString()); + } + return map; + } } diff --git a/javax/swing/text/html/TableView.java b/javax/swing/text/html/TableView.java index c142462bc..90b3ecc4f 100644 --- a/javax/swing/text/html/TableView.java +++ b/javax/swing/text/html/TableView.java @@ -140,6 +140,7 @@ class TableView 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++) @@ -664,8 +665,10 @@ class TableView /** * Updates the arrays that contain the row and column data in response * to a change to the table structure. + * + * Package private to avoid accessor methods. */ - private void updateGrid() + void updateGrid() { if (! gridValid) { -- cgit v1.2.1