summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew John Hughes <gnu_andrew@member.fsf.org>2006-11-04 18:55:49 +0000
committerAndrew John Hughes <gnu_andrew@member.fsf.org>2006-11-04 18:55:49 +0000
commit237bdd93058f891ae4567cf4e051c5831bd4646b (patch)
tree61bf13ecf1942efef4ef00642e2ff0f4318a9fb7
parente36d2a50b5a1a677c7ecaf926e73a5dac386c1ef (diff)
downloadclasspath-237bdd93058f891ae4567cf4e051c5831bd4646b.tar.gz
2006-11-04 Andrew John Hughes <gnu_andrew@member.fsf.org>
* Merge of HEAD-->generics-branch for 2006/10/29 to 2006/11/04.
-rw-r--r--ChangeLog293
-rw-r--r--gnu/java/awt/peer/ClasspathFontPeer.java14
-rw-r--r--gnu/java/awt/peer/gtk/CairoGraphics2D.java2
-rw-r--r--gnu/java/awt/peer/gtk/FreetypeGlyphVector.java21
-rw-r--r--gnu/java/awt/peer/gtk/GdkFontMetrics.java16
-rw-r--r--gnu/java/awt/peer/gtk/GdkFontPeer.java12
-rw-r--r--gnu/java/awt/peer/gtk/GtkWindowPeer.java3
-rw-r--r--gnu/java/awt/peer/qt/QtFontPeer.java11
-rw-r--r--gnu/java/awt/peer/x/XFontPeer.java7
-rw-r--r--gnu/java/awt/peer/x/XFontPeer2.java6
-rw-r--r--java/awt/Font.java25
-rw-r--r--java/awt/GridBagLayout.java10
-rw-r--r--java/awt/ScrollPaneAdjustable.java21
-rw-r--r--java/awt/TextArea.java68
-rw-r--r--java/awt/datatransfer/DataFlavor.java280
-rw-r--r--java/awt/datatransfer/MimeType.java281
-rw-r--r--java/awt/dnd/DragGestureRecognizer.java9
-rw-r--r--java/awt/dnd/DragSourceContext.java46
-rw-r--r--java/awt/event/ComponentEvent.java39
-rw-r--r--java/awt/geom/GeneralPath.java39
-rw-r--r--javax/swing/JEditorPane.java7
-rw-r--r--javax/swing/JTextField.java3
-rw-r--r--javax/swing/text/FlowView.java136
-rw-r--r--javax/swing/text/GlyphView.java93
-rw-r--r--javax/swing/text/Utilities.java5
-rw-r--r--javax/swing/text/html/FormView.java166
-rw-r--r--javax/swing/text/html/HTMLDocument.java225
-rw-r--r--javax/swing/text/html/HTMLEditorKit.java181
-rw-r--r--javax/swing/text/html/HTMLWriter.java1126
-rw-r--r--javax/swing/text/html/ImageView.java25
-rw-r--r--javax/swing/text/html/StyleSheet.java21
-rw-r--r--native/plugin/gcjwebplugin.cc9
32 files changed, 2716 insertions, 484 deletions
diff --git a/ChangeLog b/ChangeLog
index 97fd1ba36..e19e1bb74 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,296 @@
+2006-11-03 Tania Bento <tbento@redhat.com>
+
+ * java/awt/TextArea.java
+ (getMinimumSize): Changed documentation.
+ (getPreferredSize): Changed documentation.
+ (getMinimumSize(int,int)): Changed documenation.
+ (getPreferredSize(int,int)): Changed documenation.
+ (minimumSize): Changed documentation.
+ (preferredSize): Changed documenation.
+ (minimumSize(int,int)): Changed documentation. Checked if
+ minimum size had been previously set and changed values of
+ Dimension returned if peer == null.
+ (preferredSize(int, int)): Checked if preferred size had been
+ previously set and changed values of Dimension returned if
+ peer = null.
+
+2006-11-03 Tania Bento <tbento@redhat.com>
+
+ * java/awt/event/ComponentEvent.java
+ (paramString): Changed format of string representation returned.
+
+2006-11-03 Roman Kennke <kennke@aicas.com>
+
+ * javax/swing/text/html/HTMLDocument.java
+ (HTMLReader.FormAction.start): Added support for textarea.
+ (HTMLReader.FormAction.end): Added support for textarea.
+ (HTMLReader.HeadAction.end): Call super to actually close the
+ block.
+ (HTMLReader.inTextArea): New field.
+ (HTMLReader.textAreaDocument): New field.
+ (HTMLReader.handleText): Call textAreaContent when inside
+ a textarea tag.
+ (HTMLReader.textAreaContent): Implemented to initialize
+ the text area's model.
+ * javax/swing/text/html/FormView.java
+ (createComponent): Added support for textarea tag.
+
+2006-11-03 Roman Kennke <kennke@aicas.com>
+
+ * javax/swing/text/html/HTMLDocument.java
+ (HTMLReader.IsindexAction.start): Implemented.
+
+2006-11-03 Roman Kennke <kennke@aicas.com>
+
+ * javax/swing/text/html/StyleSheet.java
+ (addRule): Implemented.
+ * javax/swing/text/html/HTMLDocument.java
+ (HTMLReader.inStyleTag): New field.
+ (HTMLReader.styles): New field.
+ (HTMLReader.HeadAction.end): Implemented to read all stylesheets,
+ if any.
+ (HTMLReader.StyleAction.start): Set inStyleTag flag.
+ (HTMLReader.StyleAction.end): Set inStyleTag flag.
+ (HTMLReader.handleText): When inside a style tag, add
+ content to the styles array.
+
+2006-11-02 Roman Kennke <kennke@aicas.com>
+
+ * javax/swing/text/html/FormView.java
+ (maxIsPreferred): New field.
+ (createComponent): Initialize components correctly.
+ (getMaximumSpan): Return the preferred span for components
+ that need this. The maxIsPreferred flag is set accordingly
+ in createComponent.
+ * javax/swing/text/html/HTMLDocument.java
+ (HTMLReader.FormAction.start): Implemented to set the
+ correct model as attribute.
+ (HTMLReader.FormAction.setModel): New helper method.
+ (HTMLReader.FormAction.end): Call super to finish the element.
+ Added TODO about things left to do.
+ (HTMLReader.handleComment): Use SimpleAttributeSet rather
+ than htmlAttributeSet.
+ * javax/swing/text/html/HTMLEditorKit.java
+ (HTMLFactory.create): Create BlockView for FORM tags.
+ Create FormView for INPUT, TEXTAREA and SELECT tags.
+
+2006-11-02 David Gilbert <david.gilbert@object-refinery.com>
+
+ * java/awt/geom/GeneralPath.java: API doc fixes.
+
+2006-11-02 Roman Kennke <kennke@aicas.com>
+
+ * javax/swing/text/html/ImageView.java
+ (getImageURL): Fetch attribute from element. Consider the
+ base URL for relative image locations.
+
+2006-11-02 Roman Kennke <kennke@aicas.com>
+
+ * javax/swing/JEditorPane.java
+ (setContentType): Strip off attributes.
+ * javax/swing/text/html/HTMLEditorKit.java
+ (LinkController.activateLink(int,JEditorPane,int,int): New
+ method. Implements activation of a hyperlink.
+ (LinkController.activateLinke(int,JEditorPane)): Delegate
+ to the other activateLink() method.
+ (LinkController.createHyperlinkEvent): New helper method.
+ (LinkController.mouseClicked): Implemented to activate the link.
+ (LinkController.mouseDragged): Added comment that this
+ method does nothing.
+ (LinkController.mouseMoved): Update cursor for hyperlinks.
+ (mouseHandler): Renamed field to linkController.
+ (HTMLEditorKit): Create a link controller.
+ (clone): Give the clone a new link controller.
+ (deinstall): De-install link controller as mouseMotionListener too.
+ (install): Install link controller as mouseMotionListener too.
+
+2006-11-02 Roman Kennke <kennke@aicas.com>
+
+ PR 29644
+ * javax/swing/text/FlowView.java
+ (FlowStrategy.changedUpdate): Reversed condition. This caused
+ wrong layout and bad performance.
+ (FlowStrategy.insertUpdate): Reversed condition. This caused
+ wrong layout and bad performance.
+ (FlowStrategy.removeUpdate): Reversed condition. This caused
+ wrong layout and bad performance.
+ (LogicalView): Changed to be a subclass of CompositeView.
+ (LogicalView()): Only take one Element argument.
+ (LogicalView.childAllocation): New method for implementing
+ the abstract CompositeView method.
+ (LogicalView.forwardUpdateToView): Overridden for correct
+ reparenting.
+ (getMinimumSpan): Overridden to handle line breaking correctly.
+ (getPreferredSpan): Implemented to handle line breaking correctly.
+ (getViewAtPoint): New method for implementing
+ the abstract CompositeView method.
+ (getViewIndexAtPosition): Overridden to handle leaf elements
+ correctly.
+ (isAfter): New method for implementing
+ the abstract CompositeView method.
+ (isBefore): New method for implementing
+ the abstract CompositeView method.
+ (loadChildren): Overridden to handle leaf elements
+ correctly.
+ (paint): New method for implementing
+ the abstract CompositeView method.
+ (calculateMinorAxisRequirements): Use preferredSpan in calculation.
+ (loadChildren): Initialize flow layout by sending a synthetic
+ insertUpdate() to the layout strategy.
+ * javax/swing/text/GlyphView.java
+ (DefaultGlyphPainter.getBoundedPosition): Fall back to Toolkit's
+ font metrics if component is not available. Add initial offset
+ to result.
+ (breakView): Be more clever when breaking the view.
+ (getBreakLocation): New helper method to determine a good
+ break location.
+ (getBreakWeight): Be more clever when breaking the view.
+ (getTabbedSpan): Make sure we have a painter. Use view's
+ start and end offset rather than the element's.
+ * javax/swing/text/Utilities.java
+ (drawTabbedText): Avoid useless add and sub with the y offset.
+
+2006-11-02 Roman Kennke <kennke@aicas.com>
+
+ PR 29644
+ * gnu/java/awt/peer/ClasspathFontPeer.java
+ (getStringBounds): Removed abstract method. This is replaced
+ in java.awt.Font to use a TextLayout.
+ * gnu/java/awt/peer/gtk/GtkWindowPeer.java
+ (GtkWindowPeer): Set a font on the window object.
+ * gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
+ (FreetypeGlyphVector(Font,String,FontRenderContext,int)):
+ Changed to take char,int,int instead of String. Filter
+ control characters.
+ (FreetypeGlyphVector(Font,String,FontRenderContext)):
+ Create char array out of string.
+ (getLogicalBounds): Don't translate bounds. They already are
+ translated.
+ * gnu/java/awt/peer/gtk/GdkFontMetrics.java
+ (stringWidth): Filter out control characters.
+ * gnu/java/awt/peer/gtk/GdkFontPeer.java
+ (getStringBounds): Removed unneeded method.
+ (layoutGlyphVector): Pass char array directly to FreetypeGlyphVector
+ constructor.
+ * gnu/java/awt/peer/qt/QtFontPeer.java
+ (getStringBounds): Removed unneeded method.
+ * gnu/java/awt/peer/x/XFontPeer.java
+ (getStringBounds): Removed unneeded method.
+ * gnu/java/awt/peer/x/XFontPeer2.java
+ (getStringBounds): Removed unneeded method.
+ * java/awt/Font.java
+ (getStringBounds(char[],int,int,FontRenderContext)):
+ Use TextLayout to determine the bounds.
+ (getStringBounds(CharacterIterator,int,int,FontRenderContext)):
+ Delegate to the char[] version of this method.
+ (getStringBounds(String,FontRenderContext)):
+ Delegate to the char[] version of this method.
+ (getStringBounds(String,int,int,FontRenderContext)):
+ Delegate to the String version of this method.
+
+2006-11-01 Tania Bento <tbento@redhat.com>
+
+ * java/awt/ScrollPaneAdjustable.java
+ (paramString): Changed format of string representation returned.
+ (paramStringHelper): New private method.
+
+2006-11-01 Tania Bento <tbento@redhat.com>
+
+ * java/awt/GridBagLayout.java
+ (toString): Implemented method.
+
+2006-10-30 Thomas Fitzsimmons <fitzsim@redhat.com>
+
+ * native/plugin/gcjwebplugin.cc (GCJ_New): Move GLib threading
+ initialization to NP_Initialize.
+ (NP_Initialize): Initialize GLib threading.
+
+2006-10-31 Tania Bento <tbento@redhat.com>
+
+ * javax/swing/JTextField.java
+ (fireActionPerformed): When creating the new event, if
+ actionCommand == null, then getText() is used.
+
+2006-10-31 Francis Kung <fkung@redhat.com>
+
+ * gnu/java/awt/peer/gtk/CairoGraphics2D.java
+ (fillArc): Corrected arc type to Arc2D.PIE.
+
+2006-10-31 Roman Kennke <kennke@aicas.com>
+
+ * javax/swing/text/html/HTMLDocument.java
+ (HTMLReader.PreAction.end): Implemented.
+ (HTMLReader.PreAction.start): Implemented.
+ (HTMLReader.inPreTag): New field.
+ (HTMLReader.handleTag): When inside a pre tag, call preContent().
+ (HTMLReader.preContent): Implemented.
+
+2006-10-31 Tania Bento <tbento@redhat.com>
+
+ * javax/swing/JTextField.java
+ (fireActionPerformed): When creating the new event,
+ actionCommand should be used as the command, not
+ getText().
+
+2006-10-31 Roman Kennke <kennke@aicas.com>
+
+ * javax/swing/text/html/HTMLEditorKit.java
+ (write): Use HTMLWriter or MinimalHTMLWriter for writing
+ HTML or Styled documents.
+
+2006-10-31 David Fu <fchoong@netbeans.jp>
+
+ * javax/swing/text/html/HTMLWriter.java: New class.
+
+2006-10-30 Roman Kennke <kennke@aicas.com>
+
+ * java/awt/dnd/DragSourceContext.java
+ (dragExit): Use constant fields instead of 0.
+ (updateCurrentCursor): Completed implementation.
+
+2006-10-30 Roman Kennke <kennke@aicas.com>
+
+ * java/awt/dnd/DragGestureRecognizer.java
+ (resetRecognizer): Added API docs. Do not replace the events object
+ but rather clear() it. Removed not implemented tag.
+
+2006-10-30 Roman Kennke <kennke@aicas.com>
+
+ * java/awt/datatransfer/DataFlavor.java
+ (writeExternal): Remove not implemented tag.
+
+2006-10-30 Roman Kennke <kennke@aicas.com>
+
+ * java/awt/datatransfer/DataFlavor.java
+ (javaFileListFlavor): Don't explicitly specify class.
+ (plainTextFlavor): Don't explicitly specify class.
+ (mimeType): Changed to type MimeType. Remove final.
+ (representationClass): Remove final.
+ (DataFlavor): Don't do anything here.
+ (DataFlavor(Class,String,String)): Removed.
+ (DataFlavor(Class,String)): Initialize here.
+ (DataFlavor(String,String,ClassLoader)): Initialize in init().
+ (DataFlavor(String,String)): Initialize in init().
+ (DataFlavor(String)): Initialize in init().
+ (init): New initialization method.
+ (getMimeType): Delegate to MimeType.toString().
+ (getParameter(String,String)): Removed. Is now done in MimeType.
+ (getParameter(String)): Delegate to MimeType.
+ (getPrimaryType): Delegate to MimeType.
+ (getRepresentationClassFromMime): Removed.
+ (getRepresentationClassFromMimeThrows): Removed.
+ (getSubType): Delegate to MimeType.
+ (hashCode): Take MimeType.toString() for the hashCode.
+ (isFlavorRemoveObjectType): Return true only when representation
+ class is remove and serializable and the mime type is remote.
+ (isFlavorSerializedObjectType): Return true only when representation
+ class is serializable and the mime type is serialized.
+ (isMimeTypeEqual): Rewritten to delegate to MimeType.matches().
+ (isMimeTypeSerializedObject): Delegate to isMimeTypeEqual().
+ (readExternal): Implemented stub method.
+ (writeExternal): Implemented stub method.
+ * java/awt/datatransfer/MimeType.java: New helper class.
+
2006-10-28 Roman Kennke <kennke@aicas.com>
* javax/swing/TransferHandler.java
diff --git a/gnu/java/awt/peer/ClasspathFontPeer.java b/gnu/java/awt/peer/ClasspathFontPeer.java
index dad7bb0b0..2176f34a5 100644
--- a/gnu/java/awt/peer/ClasspathFontPeer.java
+++ b/gnu/java/awt/peer/ClasspathFontPeer.java
@@ -832,18 +832,4 @@ public abstract class ClasspathFontPeer
public abstract Rectangle2D getMaxCharBounds (Font font,
FontRenderContext rc);
- /**
- * Implementation of {@link Font#getStringBounds(CharacterIterator, int,
- * int, FontRenderContext)}
- *
- * @param font the font this peer is being called from. This may be
- * useful if you are sharing peers between Font objects. Otherwise it may
- * be ignored.
- */
-
- public abstract Rectangle2D getStringBounds (Font font,
- CharacterIterator ci,
- int begin, int limit,
- FontRenderContext frc);
-
}
diff --git a/gnu/java/awt/peer/gtk/CairoGraphics2D.java b/gnu/java/awt/peer/gtk/CairoGraphics2D.java
index 4c60336a3..7f55747c6 100644
--- a/gnu/java/awt/peer/gtk/CairoGraphics2D.java
+++ b/gnu/java/awt/peer/gtk/CairoGraphics2D.java
@@ -1154,7 +1154,7 @@ public abstract class CairoGraphics2D extends Graphics2D
{
fill(new Arc2D.Double((double) x, (double) y, (double) width,
(double) height, (double) startAngle,
- (double) arcAngle, Arc2D.OPEN));
+ (double) arcAngle, Arc2D.PIE));
}
public void fillRect(int x, int y, int width, int height)
diff --git a/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java b/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
index 1449cdf61..98f1bd69b 100644
--- a/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
+++ b/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
@@ -92,16 +92,23 @@ public class FreetypeGlyphVector extends GlyphVector
*/
public FreetypeGlyphVector(Font f, String s, FontRenderContext frc)
{
- this(f, s, frc, Font.LAYOUT_LEFT_TO_RIGHT);
+ this(f, s.toCharArray(), 0, s.length(), frc, Font.LAYOUT_LEFT_TO_RIGHT);
}
/**
* Create a glyphvector from a given (Freetype) font and a String.
*/
- public FreetypeGlyphVector(Font f, String s, FontRenderContext frc,
- int flags)
+ public FreetypeGlyphVector(Font f, char[] chars, int start, int len,
+ FontRenderContext frc, int flags)
{
- this.s = s;
+ // We need to filter out control characters (and possibly other
+ // non-renderable characters here).
+ StringBuilder b = new StringBuilder(chars.length);
+ for (int i = start; i < start + len; i++)
+ if (!Character.isISOControl(chars[i]))
+ b.append(chars[i]);
+ this.s = b.toString();
+
this.font = f;
this.frc = frc;
if( !(font.getPeer() instanceof GdkFontPeer ) )
@@ -429,12 +436,6 @@ public class FreetypeGlyphVector extends GlyphVector
{
Rectangle2D r2 = (Rectangle2D)getGlyphLogicalBounds( i );
- // Translate to the glyph's position
- tx.setToTranslation(glyphPositions[i*2], glyphPositions[i*2+1]);
- Point2D pt = new Point2D.Double(r2.getMinX(), r2.getMinY());
- tx.transform(pt, pt);
- r2.setRect(pt.getX(), pt.getY(), r2.getWidth(), r2.getHeight());
-
rect = rect.createUnion( r2 );
}
diff --git a/gnu/java/awt/peer/gtk/GdkFontMetrics.java b/gnu/java/awt/peer/gtk/GdkFontMetrics.java
index b2ffed10e..30b1ff15e 100644
--- a/gnu/java/awt/peer/gtk/GdkFontMetrics.java
+++ b/gnu/java/awt/peer/gtk/GdkFontMetrics.java
@@ -95,8 +95,22 @@ public class GdkFontMetrics extends FontMetrics
public int stringWidth (String str)
{
+
+// TextLayout layout = new TextLayout(str, getFont(), null);
+// return (int) layout.getAdvance();
+ // We need to filter control chars, because they are never displayed
+ // in Java and thus also have no metrics.
+ int len = str.length();
+ StringBuilder b = new StringBuilder(len);
+ for (int i = 0; i < len; i++)
+ {
+ char ch = str.charAt(i);
+ if (! Character.isISOControl(ch))
+ b.append(ch);
+ }
double [] hires = new double[6];
- peer.getTextMetrics(str, hires);
+ String string = b.toString();
+ peer.getTextMetrics(string, hires);
return (int) hires [TEXT_METRICS_WIDTH];
}
diff --git a/gnu/java/awt/peer/gtk/GdkFontPeer.java b/gnu/java/awt/peer/gtk/GdkFontPeer.java
index 11635c354..40b234984 100644
--- a/gnu/java/awt/peer/gtk/GdkFontPeer.java
+++ b/gnu/java/awt/peer/gtk/GdkFontPeer.java
@@ -345,15 +345,6 @@ public class GdkFontPeer extends ClasspathFontPeer
return buf.getShort(4);
}
- public Rectangle2D getStringBounds (Font font, CharacterIterator ci,
- int begin, int limit, FontRenderContext frc)
- {
- GlyphVector gv = new FreetypeGlyphVector( font,
- buildString(ci, begin, limit),
- frc);
- return gv.getVisualBounds();
- }
-
public boolean hasUniformLineMetrics (Font font)
{
return true;
@@ -363,8 +354,7 @@ public class GdkFontPeer extends ClasspathFontPeer
char[] chars, int start, int limit,
int flags)
{
- return new FreetypeGlyphVector( font, new String( chars, start,
- limit - start),
+ return new FreetypeGlyphVector( font, chars, start, limit - start,
frc, flags);
}
diff --git a/gnu/java/awt/peer/gtk/GtkWindowPeer.java b/gnu/java/awt/peer/gtk/GtkWindowPeer.java
index 1abc5ca84..8d49719b1 100644
--- a/gnu/java/awt/peer/gtk/GtkWindowPeer.java
+++ b/gnu/java/awt/peer/gtk/GtkWindowPeer.java
@@ -41,6 +41,7 @@ package gnu.java.awt.peer.gtk;
import gnu.java.awt.ComponentReshapeEvent;
import java.awt.Component;
+import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.KeyboardFocusManager;
@@ -151,6 +152,8 @@ public class GtkWindowPeer extends GtkContainerPeer
public GtkWindowPeer (Window window)
{
super (window);
+ // Set reasonable font for the window.
+ window.setFont(new Font("Dialog", Font.PLAIN, 12));
}
public native void toBack();
diff --git a/gnu/java/awt/peer/qt/QtFontPeer.java b/gnu/java/awt/peer/qt/QtFontPeer.java
index d847a8053..6ffe3f691 100644
--- a/gnu/java/awt/peer/qt/QtFontPeer.java
+++ b/gnu/java/awt/peer/qt/QtFontPeer.java
@@ -194,15 +194,4 @@ public class QtFontPeer extends ClasspathFontPeer
throw new UnsupportedOperationException();
}
- public Rectangle2D getStringBounds (Font font,
- CharacterIterator ci,
- int begin, int limit,
- FontRenderContext frc)
- {
- int index = begin;
- String s = "" + ci.setIndex( index );
- while( index++ <= limit )
- s = s + ci.next();
- return metrics.getStringBounds(s);
- }
}
diff --git a/gnu/java/awt/peer/x/XFontPeer.java b/gnu/java/awt/peer/x/XFontPeer.java
index fd293d8dd..8183fed0c 100644
--- a/gnu/java/awt/peer/x/XFontPeer.java
+++ b/gnu/java/awt/peer/x/XFontPeer.java
@@ -608,13 +608,6 @@ public class XFontPeer
throw new UnsupportedOperationException("Not yet implemented.");
}
- public Rectangle2D getStringBounds(Font font, CharacterIterator ci,
- int begin, int limit, FontRenderContext frc)
- {
- // TODO: Implement this.
- throw new UnsupportedOperationException("Not yet implemented.");
- }
-
/**
* Encodes a font name + style + size specification into a X logical font
* description (XLFD) as described here:
diff --git a/gnu/java/awt/peer/x/XFontPeer2.java b/gnu/java/awt/peer/x/XFontPeer2.java
index 25371de1a..ef9507f30 100644
--- a/gnu/java/awt/peer/x/XFontPeer2.java
+++ b/gnu/java/awt/peer/x/XFontPeer2.java
@@ -326,10 +326,4 @@ public class XFontPeer2
throw new UnsupportedOperationException("Not yet implemented");
}
- public Rectangle2D getStringBounds(Font font, CharacterIterator ci, int begin, int limit, FontRenderContext frc)
- {
- // FIXME: Implement this.
- throw new UnsupportedOperationException("Not yet implemented");
- }
-
}
diff --git a/java/awt/Font.java b/java/awt/Font.java
index e630207d5..29b87d6af 100644
--- a/java/awt/Font.java
+++ b/java/awt/Font.java
@@ -1087,7 +1087,8 @@ public class Font implements Serializable
*/
public Rectangle2D getStringBounds(String str, FontRenderContext frc)
{
- return getStringBounds(str, 0, str.length() - 1, frc);
+ char[] chars = str.toCharArray();
+ return getStringBounds(chars, 0, chars.length, frc);
}
/**
@@ -1115,8 +1116,8 @@ public class Font implements Serializable
public Rectangle2D getStringBounds(String str, int begin,
int limit, FontRenderContext frc)
{
- return peer.getStringBounds(this, new StringCharacterIterator(str), begin,
- limit, frc);
+ String sub = str.substring(begin, limit);
+ return getStringBounds(sub, frc);
}
/**
@@ -1144,7 +1145,16 @@ public class Font implements Serializable
public Rectangle2D getStringBounds(CharacterIterator ci, int begin,
int limit, FontRenderContext frc)
{
- return peer.getStringBounds(this, ci, begin, limit, frc);
+ int start = ci.getBeginIndex();
+ int end = ci.getEndIndex();
+ char[] chars = new char[limit - start];
+ ci.setIndex(start);
+ for (int index = 0; index < chars.length; index++)
+ {
+ chars[index] = ci.current();
+ ci.next();
+ }
+ return getStringBounds(chars, 0, chars.length, frc);
}
/**
@@ -1172,9 +1182,10 @@ public class Font implements Serializable
public Rectangle2D getStringBounds(char[] chars, int begin,
int limit, FontRenderContext frc)
{
- return peer.getStringBounds(this,
- new StringCharacterIterator(new String(chars)),
- begin, limit, frc);
+ String str = new String(chars, begin, limit - begin);
+ TextLayout layout = new TextLayout(str, this, frc);
+ return new Rectangle2D.Float(0, -layout.getAscent(), layout.getAdvance(),
+ layout.getDescent() + layout.getLeading());
}
/**
diff --git a/java/awt/GridBagLayout.java b/java/awt/GridBagLayout.java
index 4853ba908..0415c7bd3 100644
--- a/java/awt/GridBagLayout.java
+++ b/java/awt/GridBagLayout.java
@@ -321,6 +321,16 @@ public class GridBagLayout
}
/**
+ * Return a string representation of this GridBagLayout.
+ *
+ * @return a string representation
+ */
+ public String toString()
+ {
+ return getClass().getName();
+ }
+
+ /**
* Move and resize a rectangle according to a set of grid bag
* constraints. The x, y, width and height fields of the
* rectangle argument are adjusted to the new values.
diff --git a/java/awt/ScrollPaneAdjustable.java b/java/awt/ScrollPaneAdjustable.java
index 6ce79b1f6..ca61801bf 100644
--- a/java/awt/ScrollPaneAdjustable.java
+++ b/java/awt/ScrollPaneAdjustable.java
@@ -196,13 +196,23 @@ public class ScrollPaneAdjustable
public String paramString ()
{
- return ("scrollpane=" + sp + ", orientation=" + orientation
- + ", value=" + value + ", minimum=" + minimum
- + ", maximum=" + maximum + ", visibleAmount=" + visibleAmount
- + ", unitIncrement=" + unitIncrement
- + ", blockIncrement=" + blockIncrement);
+ return paramStringHelper()
+ + ",[" + getMinimum() + ".." + getMaximum()
+ + "],val=" + getValue()
+ + ",vis=" + getVisibleAmount()
+ + ",unit=" + getUnitIncrement()
+ + ",block=" + getBlockIncrement()
+ + ",isAdjusting=" + valueIsAdjusting;
}
+ private String paramStringHelper()
+ {
+ if (getOrientation() == HORIZONTAL)
+ return "horizontal";
+ else
+ return "vertical";
+ }
+
public String toString()
{
return getClass().getName() + "[" + paramString() + "]";
@@ -227,5 +237,6 @@ public class ScrollPaneAdjustable
{
this.valueIsAdjusting = valueIsAdjusting;
}
+
} // class ScrollPaneAdjustable
diff --git a/java/awt/TextArea.java b/java/awt/TextArea.java
index 7e3463ab8..30b278d0c 100644
--- a/java/awt/TextArea.java
+++ b/java/awt/TextArea.java
@@ -284,11 +284,7 @@ public class TextArea extends TextComponent implements java.io.Serializable
}
/**
- * Retrieve the minimum size for this text area, considering the
- * text area's current row and column values. A text area's minimum
- * size depends on the number of rows and columns of text it would
- * prefer to display, and on the size of the font in which the text
- * would be displayed.
+ * Retrieve the minimum size for this text area.
*
* @return The minimum size for this text field.
*/
@@ -298,11 +294,8 @@ public class TextArea extends TextComponent implements java.io.Serializable
}
/**
- * Retrieve the minimum size that this text area would have if its
- * row and column values were equal to those specified. A text
- * area's minimum size depends on the number of rows and columns of
- * text it would prefer to display, and on the size of the font in
- * which the text would be displayed.
+ * Retrieve the minimum size for this text area. If the minimum
+ * size has been set, then rows and columns are used in the calculation.
*
* @param rows The number of rows to use in the minimum size
* calculation.
@@ -317,12 +310,8 @@ public class TextArea extends TextComponent implements java.io.Serializable
}
/**
- * Retrieve the minimum size for this text area, considering the
- * text area's current row and column values. A text area's minimum
- * size depends on the number of rows and columns of text it would
- * prefer to display, and on the size of the font in which the text
- * would be displayed.
- *
+ * Retrieve the minimum size for this text area.
+ *
* @return The minimum size for this text area.
*
* @deprecated This method is deprecated in favor of
@@ -334,11 +323,8 @@ public class TextArea extends TextComponent implements java.io.Serializable
}
/**
- * Retrieve the minimum size that this text area would have if its
- * row and column values were equal to those specified. A text
- * area's minimum size depends on the number of rows and columns of
- * text it would prefer to display, and on the size of the font in
- * which the text would be displayed.
+ * Retrieve the minimum size for this text area. If the minimum
+ * size has been set, then rows and columns are used in the calculation.
*
* @param rows The number of rows to use in the minimum size
* calculation.
@@ -352,21 +338,18 @@ public class TextArea extends TextComponent implements java.io.Serializable
*/
public Dimension minimumSize (int rows, int columns)
{
+ if (isMinimumSizeSet())
+ return new Dimension(minSize);
+
TextAreaPeer peer = (TextAreaPeer) getPeer ();
-
- // Sun returns Dimension (0,0) in this case.
if (peer == null)
- return new Dimension (0, 0);
+ return new Dimension (getWidth(), getHeight());
return peer.getMinimumSize (rows, columns);
}
/**
- * Retrieve the preferred size for this text area, considering the
- * text area's current row and column values. A text area's preferred
- * size depends on the number of rows and columns of text it would
- * prefer to display, and on the size of the font in which the text
- * would be displayed.
+ * Retrieve the preferred size for this text area.
*
* @return The preferred size for this text field.
*/
@@ -376,11 +359,8 @@ public class TextArea extends TextComponent implements java.io.Serializable
}
/**
- * Retrieve the preferred size that this text area would have if its
- * row and column values were equal to those specified. A text
- * area's preferred size depends on the number of rows and columns
- * of text it would prefer to display, and on the size of the font
- * in which the text would be displayed.
+ * Retrieve the preferred size for this text area. If the preferred
+ * size has been set, then rows and columns are used in the calculation.
*
* @param rows The number of rows to use in the preferred size
* calculation.
@@ -395,11 +375,7 @@ public class TextArea extends TextComponent implements java.io.Serializable
}
/**
- * Retrieve the preferred size for this text area, considering the
- * text area's current row and column values. A text area's preferred
- * size depends on the number of rows and columns of text it would
- * prefer to display, and on the size of the font in which the text
- * would be displayed.
+ * Retrieve the preferred size for this text area.
*
* @return The preferred size for this text field.
*
@@ -412,11 +388,8 @@ public class TextArea extends TextComponent implements java.io.Serializable
}
/**
- * Retrieve the preferred size that this text area would have if its
- * row and column values were equal to those specified. A text
- * area's preferred size depends on the number of rows and columns
- * of text it would prefer to display, and on the size of the font
- * in which the text would be displayed.
+ * Retrieve the preferred size for this text area. If the preferred
+ * size has been set, then rows and columns are used in the calculation.
*
* @param rows The number of rows to use in the preferred size
* calculation.
@@ -430,11 +403,12 @@ public class TextArea extends TextComponent implements java.io.Serializable
*/
public Dimension preferredSize (int rows, int columns)
{
+ if (isPreferredSizeSet())
+ return new Dimension(prefSize);
+
TextAreaPeer peer = (TextAreaPeer) getPeer ();
-
- // Sun returns Dimension (0,0) in this case.
if (peer == null)
- return new Dimension (0, 0);
+ return new Dimension (getWidth(), getHeight());
return peer.getPreferredSize (rows, columns);
}
diff --git a/java/awt/datatransfer/DataFlavor.java b/java/awt/datatransfer/DataFlavor.java
index d31c7065f..baaf43d85 100644
--- a/java/awt/datatransfer/DataFlavor.java
+++ b/java/awt/datatransfer/DataFlavor.java
@@ -38,14 +38,13 @@ exception statement from your version. */
package java.awt.datatransfer;
-import gnu.classpath.NotImplementedException;
-
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInput;
import java.io.ObjectOutput;
+import java.io.OptionalDataException;
import java.io.Reader;
import java.io.Serializable;
import java.io.StringReader;
@@ -76,8 +75,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
* deals with bytes not chars. Use <code>getRederForText()</code>.
*/
public static final DataFlavor plainTextFlavor =
- new DataFlavor(java.io.InputStream.class,
- "text/plain; charset=unicode",
+ new DataFlavor("text/plain; charset=unicode; class=java.io.InputStream",
"plain unicode text");
/**
@@ -94,8 +92,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
* element of the list being a <code>java.io.File</code>.
*/
public static final DataFlavor javaFileListFlavor =
- new DataFlavor(java.util.List.class,
- "application/x-java-file-list; class=java.util.List",
+ new DataFlavor("application/x-java-file-list; class=java.util.List",
"Java File List");
/**
@@ -132,10 +129,10 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
*/
// The MIME type for this flavor
- private final String mimeType;
+ private MimeType mimeType;
// The representation class for this flavor
- private final Class<?> representationClass;
+ private Class<?> representationClass;
// The human readable name of this flavor
private String humanPresentableName;
@@ -198,62 +195,6 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
throw new ClassNotFoundException(className);
}
- private static Class getRepresentationClassFromMimeThrows(String mimeString,
- ClassLoader classLoader)
- throws ClassNotFoundException
- {
- String classname = getParameter("class", mimeString);
- if (classname != null)
- return tryToLoadClass(classname, classLoader);
- else
- return java.io.InputStream.class;
- }
-
- // Same as above, but wraps any ClassNotFoundExceptions
- private static Class getRepresentationClassFromMime(String mimeString,
- ClassLoader classLoader)
- {
- try
- {
- return getRepresentationClassFromMimeThrows(mimeString, classLoader);
- }
- catch(ClassNotFoundException cnfe)
- {
- IllegalArgumentException iae;
- iae = new IllegalArgumentException("mimeString: "
- + mimeString
- + " classLoader: "
- + classLoader);
- iae.initCause(cnfe);
- throw iae;
- }
- }
-
- /**
- * Returns the value of the named MIME type parameter, or <code>null</code>
- * if the parameter does not exist. Given the parameter name and the mime
- * string.
- *
- * @param paramName The name of the parameter.
- * @param mimeString The mime string from where the name should be found.
- *
- * @return The value of the parameter or null.
- */
- private static String getParameter(String paramName, String mimeString)
- {
- int idx = mimeString.indexOf(paramName + "=");
- if (idx == -1)
- return(null);
-
- String value = mimeString.substring(idx + paramName.length() + 1);
-
- idx = value.indexOf(";");
- if (idx == -1)
- return(value);
- else
- return(value.substring(0, idx));
- }
-
/**
* XXX - Currently returns <code>plainTextFlavor</code>.
*/
@@ -321,31 +262,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
*/
public DataFlavor()
{
- mimeType = null;
- representationClass = null;
- humanPresentableName = null;
- }
-
- /**
- * Private constructor.
- */
- private DataFlavor(Class<?> representationClass,
- String mimeType,
- String humanPresentableName)
- {
- this.representationClass = representationClass;
- this.mimeType = mimeType;
-
- // Do some simple validity checks
- String type = getPrimaryType() + "/" + getSubType();
- if (type.indexOf('=') != -1
- || type.indexOf(';') != -1)
- throw new IllegalArgumentException(mimeType);
-
- if (humanPresentableName != null)
- this.humanPresentableName = humanPresentableName;
- else
- this.humanPresentableName = mimeType;
+ // Used for deserialization only, nothing to do here.
}
/**
@@ -360,11 +277,21 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
*/
public DataFlavor(Class<?> representationClass, String humanPresentableName)
{
- this(representationClass,
- "application/x-java-serialized-object"
- + "; class="
- + representationClass.getName(),
- humanPresentableName);
+ if (representationClass == null)
+ throw new NullPointerException("representationClass must not be null");
+ try
+ {
+ mimeType = new MimeType(javaSerializedObjectMimeType);
+ }
+ catch (MimeTypeParseException ex)
+ {
+ // Must not happen as we use a constant string.
+ assert false;
+ }
+ if (humanPresentableName == null)
+ humanPresentableName = javaSerializedObjectMimeType;
+ this.humanPresentableName = humanPresentableName;
+ this.representationClass = representationClass;
}
/**
@@ -389,8 +316,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
ClassLoader classLoader)
throws ClassNotFoundException
{
- this(getRepresentationClassFromMimeThrows(mimeType, classLoader),
- mimeType, humanPresentableName);
+ init(mimeType, humanPresentableName, classLoader);
}
/**
@@ -411,8 +337,17 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
*/
public DataFlavor(String mimeType, String humanPresentableName)
{
- this(getRepresentationClassFromMime (mimeType, null),
- mimeType, humanPresentableName);
+ try
+ {
+ init(mimeType, humanPresentableName, getClass().getClassLoader());
+ }
+ catch (ClassNotFoundException ex)
+ {
+ IllegalArgumentException iae =
+ new IllegalArgumentException("Class not found: " + ex.getMessage());
+ iae.initCause(ex);
+ throw iae;
+ }
}
/**
@@ -431,8 +366,54 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
*/
public DataFlavor(String mimeType) throws ClassNotFoundException
{
- this(getRepresentationClassFromMimeThrows(mimeType, null),
- mimeType, null);
+ init(mimeType, null, getClass().getClassLoader());
+ }
+
+ /**
+ * Called by various constructors to initialize this object.
+ *
+ * @param mime the mime string
+ * @param humanPresentableName the human presentable name
+ * @param loader the class loader to use for loading the representation
+ * class
+ */
+ private void init(String mime, String humanPresentableName,
+ ClassLoader loader)
+ throws ClassNotFoundException
+ {
+ if (mime == null)
+ throw new NullPointerException("The mime type must not be null");
+ try
+ {
+ mimeType = new MimeType(mime);
+ }
+ catch (MimeTypeParseException ex)
+ {
+ IllegalArgumentException iae =
+ new IllegalArgumentException("Invalid mime type");
+ iae.initCause(ex);
+ throw iae;
+ }
+ String className = mimeType.getParameter("class");
+ if (className == null)
+ {
+ if (mimeType.getBaseType().equals(javaSerializedObjectMimeType))
+ throw new IllegalArgumentException("Serialized object type must have"
+ + " a representation class parameter");
+ else
+ representationClass = java.io.InputStream.class;
+ }
+ else
+ representationClass = tryToLoadClass(className, loader);
+ mimeType.addParameter("class", representationClass.getName());
+
+ if (humanPresentableName == null)
+ {
+ humanPresentableName = mimeType.getParameter("humanPresentableName");
+ if (humanPresentableName == null)
+ humanPresentableName = mimeType.getBaseType();
+ }
+ this.humanPresentableName = humanPresentableName;
}
/**
@@ -442,7 +423,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
*/
public String getMimeType()
{
- return(mimeType);
+ return(mimeType.toString());
}
/**
@@ -472,11 +453,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
*/
public String getPrimaryType()
{
- int idx = mimeType.indexOf("/");
- if (idx == -1)
- return(mimeType);
-
- return(mimeType.substring(0, idx));
+ return(mimeType.getPrimaryType());
}
/**
@@ -486,15 +463,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
*/
public String getSubType()
{
- int start = mimeType.indexOf("/");
- if (start == -1)
- return "";
-
- int end = mimeType.indexOf(";", start + 1);
- if (end == -1)
- return mimeType.substring(start + 1);
- else
- return mimeType.substring(start + 1, end);
+ return mimeType.getSubType();
}
/**
@@ -510,7 +479,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
if ("humanPresentableName".equals(paramName))
return getHumanPresentableName();
- return getParameter(paramName, mimeType);
+ return mimeType.getParameter(paramName);
}
/**
@@ -536,16 +505,22 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
*/
public boolean isMimeTypeEqual(String mimeType)
{
- String mime = getMimeType();
- int i = mime.indexOf(";");
- if (i != -1)
- mime = mime.substring(0, i);
-
- i = mimeType.indexOf(";");
- if (i != -1)
- mimeType = mimeType.substring(0, i);
-
- return mime.equals(mimeType);
+ if (mimeType == null)
+ throw new NullPointerException("mimeType must not be null");
+ boolean equal = false;
+ try
+ {
+ if (this.mimeType != null)
+ {
+ MimeType other = new MimeType(mimeType);
+ equal = this.mimeType.matches(other);
+ }
+ }
+ catch (MimeTypeParseException ex)
+ {
+ // Return false in this case.
+ }
+ return equal;
}
/**
@@ -570,7 +545,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
*/
public boolean isMimeTypeSerializedObject()
{
- return mimeType.startsWith(javaSerializedObjectMimeType);
+ return isMimeTypeEqual(javaSerializedObjectMimeType);
}
/**
@@ -616,8 +591,8 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
*/
public boolean isFlavorSerializedObjectType()
{
- // FIXME: What is the diff between this and isMimeTypeSerializedObject?
- return(mimeType.startsWith(javaSerializedObjectMimeType));
+ return isRepresentationClassSerializable()
+ && isMimeTypeEqual(javaSerializedObjectMimeType);
}
/**
@@ -628,7 +603,9 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
*/
public boolean isFlavorRemoteObjectType()
{
- return(mimeType.startsWith(javaRemoteObjectMimeType));
+ return isRepresentationClassRemote()
+ && isRepresentationClassSerializable()
+ && isMimeTypeEqual(javaRemoteObjectMimeType);
}
/**
@@ -769,7 +746,7 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
*/
public int hashCode()
{
- return mimeType.toLowerCase().hashCode() ^ representationClass.hashCode();
+ return mimeType.toString().hashCode() ^ representationClass.hashCode();
}
/**
@@ -821,9 +798,17 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
* @exception IOException If an error occurs.
*/
public void writeExternal(ObjectOutput stream)
- throws IOException, NotImplementedException
+ throws IOException
{
- // FIXME: Implement me
+ if (mimeType != null)
+ {
+ mimeType.addParameter("humanPresentableName", humanPresentableName);
+ stream.writeObject(mimeType);
+ mimeType.removeParameter("humanPresentableName");
+ }
+ else
+ stream.writeObject(null);
+ stream.writeObject(representationClass);
}
@@ -837,9 +822,34 @@ public class DataFlavor implements java.io.Externalizable, Cloneable
* cannot be found.
*/
public void readExternal(ObjectInput stream)
- throws IOException, ClassNotFoundException, NotImplementedException
+ throws IOException, ClassNotFoundException
{
- // FIXME: Implement me
+ mimeType = (MimeType) stream.readObject();
+ String className = null;
+ if (mimeType != null)
+ {
+ humanPresentableName =
+ mimeType.getParameter("humanPresentableName");
+ mimeType.removeParameter("humanPresentableName");
+ className = mimeType.getParameter("class");
+ if (className == null)
+ throw new IOException("No class in mime type");
+ }
+ try
+ {
+ representationClass = (Class) stream.readObject();
+ }
+ catch (OptionalDataException ex)
+ {
+ if (ex.eof && ex.length == 0)
+ {
+ if (className != null)
+ representationClass = tryToLoadClass(className,
+ getClass().getClassLoader());
+ }
+ else
+ throw ex;
+ }
}
/**
diff --git a/java/awt/datatransfer/MimeType.java b/java/awt/datatransfer/MimeType.java
new file mode 100644
index 000000000..438d78e9e
--- /dev/null
+++ b/java/awt/datatransfer/MimeType.java
@@ -0,0 +1,281 @@
+/* MimeType.java -- A helper class for mime handling in DataFlavor
+ 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 java.awt.datatransfer;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+/**
+ * A helper class for mime handling in DataFlavor.
+ *
+ * A Mauve test for DataFlavor.writeExternal() shows that a non-public
+ * class java.awt.datatransfer.MimeType gets serialized. This class
+ * is mainly here for serialization compatibility. Of course,
+ * now that we have it here, we can just as well implement some
+ * mime handling facility here.
+ */
+class MimeType
+ implements Externalizable
+{
+
+ /**
+ * The primary type.
+ */
+ private String primaryType;
+
+ /**
+ * The subtype.
+ */
+ private String subType;
+
+ /**
+ * Additional parameters to be appended to the mime string.
+ */
+ private HashMap parameters;
+
+ /**
+ * This is only here for deserialization.
+ */
+ public MimeType()
+ {
+ parameters = new HashMap();
+ }
+
+ /**
+ * Creates a new MimeType object.
+ *
+ * @param mime the mime type
+ */
+ MimeType(String mime)
+ throws MimeTypeParseException
+ {
+ this();
+ parse(mime);
+ }
+
+ /**
+ * Adds a mime parameter.
+ *
+ * @param param the parameter key
+ * @param value the parameter value
+ */
+ void addParameter(String param, String value)
+ {
+ parameters.put(param, value);
+ }
+
+ /**
+ * Removes the parameter with the specified key.
+ *
+ * @param param the parameter to remove
+ */
+ void removeParameter(String param)
+ {
+ parameters.remove(param);
+ }
+
+ /**
+ * Returns the parameter for the <code>key</code>.
+ *
+ * @param key the parameter key
+ *
+ * @return the parameter for the <code>key</code>
+ */
+ String getParameter(String key)
+ {
+ return (String) parameters.get(key);
+ }
+
+ /**
+ * Returns the primary type.
+ *
+ * @return the primary type
+ */
+ String getPrimaryType()
+ {
+ return primaryType;
+ }
+
+ String getSubType()
+ {
+ return subType;
+ }
+
+ /**
+ * Returns the base type of this mime type. This is the primary
+ * type plus the subtype, separated by '/'.
+ *
+ * @return the base type of this mime type
+ */
+ String getBaseType()
+ {
+ return primaryType + '/' + subType;
+ }
+
+ /**
+ * Returns <code>true</code> if this mime type and another mime type
+ * match. This will be true when their primary types are equal, and their
+ * subtypes are equal (or when either subtype is * ).
+ *
+ * @param other the other mime type
+ *
+ * @return <code>true</code> if the mime types match, <code>false</code>
+ * otherwise
+ */
+ boolean matches(MimeType other)
+ {
+ boolean match = false;
+ if (other != null)
+ {
+ match = primaryType.equals(other.primaryType)
+ && (subType.equals("*") || other.subType.equals("*")
+ || subType.equals(other.subType));
+ }
+ return match;
+ }
+
+ /**
+ * Serializes the mime type.
+ *
+ * @param in the input stream to read from
+ *
+ * @throws ClassNotFoundException not thrown here
+ * @throws IOException when something goes wrong on the input stream,
+ * or when the mime type can't be parsed
+ */
+ public void readExternal(ObjectInput in)
+ throws ClassNotFoundException, IOException
+ {
+ String mime = in.readUTF();
+ parameters.clear();
+ try
+ {
+ parse(mime);
+ }
+ catch (MimeTypeParseException ex)
+ {
+ IOException ioEx = new IOException();
+ ioEx.initCause(ex);
+ throw ioEx;
+ }
+ }
+
+ /**
+ * Serializes this mime type.
+ *
+ * @param out the output stream
+ *
+ * @throws IOException when something goes wrong on the output stream
+ */
+ public void writeExternal(ObjectOutput out)
+ throws IOException
+ {
+ out.writeUTF(toString());
+ }
+
+ /**
+ * Creates a string representation of this mime type.
+ *
+ * @return a string representation of this mime type
+ */
+ public String toString()
+ {
+ StringBuilder s = new StringBuilder();
+ s.append(primaryType);
+ s.append('/');
+ s.append(subType);
+ if (parameters.size() > 0)
+ {
+ Set entries = parameters.entrySet();
+ for (Iterator i = entries.iterator(); i.hasNext();)
+ {
+ s.append("; ");
+ Map.Entry entry = (Map.Entry) i.next();
+ s.append(entry.getKey());
+ s.append('=');
+ s.append(entry.getValue());
+ }
+ }
+ return s.toString();
+ }
+
+ /**
+ * Parses the specified mime type string and initializes the fields
+ * of this object.
+ *
+ * @param mime the mime type string
+ */
+ private void parse(String mime)
+ throws MimeTypeParseException
+ {
+ // FIXME: Maybe implement more sophisticated mime string parsing according
+ // to RFC 2045 and 2046.
+ StringTokenizer tokenizer = new StringTokenizer(mime);
+ try
+ {
+ primaryType = tokenizer.nextToken("/");
+ subType = tokenizer.nextToken("/;");
+ }
+ catch (NoSuchElementException ex)
+ {
+ throw new MimeTypeParseException("Expected / separator");
+ }
+
+ // Add any parameters.
+ while (tokenizer.hasMoreTokens())
+ {
+ String keyValuePair = tokenizer.nextToken(";");
+ int i = keyValuePair.indexOf('=');
+ if (i == -1)
+ throw new MimeTypeParseException("Expected = as parameter separator");
+ String key = keyValuePair.substring(0, i).trim();
+ String value = keyValuePair.substring(i + 1).trim();
+ parameters.put(key, value);
+ }
+ }
+
+}
diff --git a/java/awt/dnd/DragGestureRecognizer.java b/java/awt/dnd/DragGestureRecognizer.java
index 6a00347b2..3973e5284 100644
--- a/java/awt/dnd/DragGestureRecognizer.java
+++ b/java/awt/dnd/DragGestureRecognizer.java
@@ -38,8 +38,6 @@ exception statement from your version. */
package java.awt.dnd;
-import gnu.classpath.NotImplementedException;
-
import java.awt.Component;
import java.awt.Point;
import java.awt.event.InputEvent;
@@ -129,11 +127,12 @@ public abstract class DragGestureRecognizer implements Serializable
return events.size() > 0 ? (InputEvent) events.get(0) : null;
}
+ /**
+ * Resets the recognizer. If a gesture is currently recognize, discard it.
+ */
public void resetRecognizer()
- throws NotImplementedException
{
- events = new ArrayList();
- // FIXME: Not implemented fully.
+ events.clear();
}
/**
diff --git a/java/awt/dnd/DragSourceContext.java b/java/awt/dnd/DragSourceContext.java
index 1fee5c0c3..ed1cbaa44 100644
--- a/java/awt/dnd/DragSourceContext.java
+++ b/java/awt/dnd/DragSourceContext.java
@@ -38,8 +38,6 @@ exception statement from your version. */
package java.awt.dnd;
-import gnu.classpath.NotImplementedException;
-
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Image;
@@ -268,7 +266,8 @@ public class DragSourceContext
for (int i = 0; i < dsl.length; i++)
dsl[i].dragExit(e);
- updateCurrentCursor(0, 0, DEFAULT);
+ updateCurrentCursor(DnDConstants.ACTION_NONE, DnDConstants.ACTION_NONE,
+ DEFAULT);
}
/**
@@ -340,26 +339,45 @@ public class DragSourceContext
* @param status - the status of the cursor (constant).
*/
protected void updateCurrentCursor(int dropOp, int targetAct, int status)
- throws NotImplementedException
{
- // FIXME: Not implemented fully
- if (!useCustomCursor)
+ if (! useCustomCursor)
{
- Cursor cursor = null;
+ Cursor newCursor = null;
switch (status)
{
+ default:
+ targetAct = DnDConstants.ACTION_NONE;
case ENTER:
- break;
case CHANGED:
- break;
case OVER:
- break;
- default:
- break;
+ int action = dropOp & targetAct;
+ if (action == DnDConstants.ACTION_NONE)
+ {
+ if ((dropOp & DnDConstants.ACTION_LINK) != 0)
+ newCursor = DragSource.DefaultLinkNoDrop;
+ else if ((dropOp & DnDConstants.ACTION_MOVE) != 0)
+ newCursor = DragSource.DefaultMoveNoDrop;
+ else
+ newCursor = DragSource.DefaultCopyNoDrop;
+ }
+ else
+ {
+ if ((dropOp & DnDConstants.ACTION_LINK) != 0)
+ newCursor = DragSource.DefaultLinkDrop;
+ else if ((dropOp & DnDConstants.ACTION_MOVE) != 0)
+ newCursor = DragSource.DefaultMoveDrop;
+ else
+ newCursor = DragSource.DefaultCopyDrop;
+ }
}
- this.cursor = cursor;
- peer.setCursor(cursor);
+ if (cursor == null || ! cursor.equals(newCursor))
+ {
+ cursor = newCursor;
+ DragSourceContextPeer p = peer;
+ if (p != null)
+ p.setCursor(cursor);
+ }
}
}
} // class DragSourceContext
diff --git a/java/awt/event/ComponentEvent.java b/java/awt/event/ComponentEvent.java
index ba9c2a5b3..6d478055a 100644
--- a/java/awt/event/ComponentEvent.java
+++ b/java/awt/event/ComponentEvent.java
@@ -1,5 +1,5 @@
/* ComponentEvent.java -- notification of events for components
- Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2002, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -114,24 +114,27 @@ public class ComponentEvent extends AWTEvent
*/
public String paramString()
{
+ StringBuffer s = new StringBuffer();
+
// Unlike Sun, we don't throw NullPointerException or ClassCastException
// when source was illegally changed.
- switch (id)
- {
- case COMPONENT_MOVED:
- return "COMPONENT_MOVED "
- + (source instanceof Component
- ? ((Component) source).getBounds() : (Object) "");
- case COMPONENT_RESIZED:
- return "COMPONENT_RESIZED "
- + (source instanceof Component
- ? ((Component) source).getBounds() : (Object) "");
- case COMPONENT_SHOWN:
- return "COMPONENT_SHOWN";
- case COMPONENT_HIDDEN:
- return "COMPONENT_HIDDEN";
- default:
- return "unknown type";
- }
+ if (id == COMPONENT_MOVED)
+ s.append("COMPONENT_MOVED ");
+ else if (id == COMPONENT_RESIZED)
+ s.append("COMPONENT_RESIZED ");
+ else if (id == COMPONENT_SHOWN)
+ s.append("COMPONENT_SHOWN ");
+ else if (id == COMPONENT_HIDDEN)
+ s.append("COMPONENT_HIDDEN ");
+ else
+ return "unknown type";
+
+ s.append("(").append(getComponent().getX()).append(",")
+ .append(getComponent().getY()).append(" ")
+ .append(getComponent().getWidth()).append("x")
+ .append(getComponent().getHeight()).append(")");
+
+ return s.toString();
}
+
} // class ComponentEvent
diff --git a/java/awt/geom/GeneralPath.java b/java/awt/geom/GeneralPath.java
index e0ca8e183..1e9ede5ee 100644
--- a/java/awt/geom/GeneralPath.java
+++ b/java/awt/geom/GeneralPath.java
@@ -86,7 +86,7 @@ public final class GeneralPath implements Shape, Cloneable
public static final int WIND_EVEN_ODD
= java.awt.geom.PathIterator.WIND_EVEN_ODD;
- /** Same constant as {@link PathIterator.WIND_NON_ZERO}. */
+ /** Same constant as {@link PathIterator#WIND_NON_ZERO}. */
public static final int WIND_NON_ZERO
= java.awt.geom.PathIterator.WIND_NON_ZERO;
@@ -140,7 +140,11 @@ public final class GeneralPath implements Shape, Cloneable
/**
* Constructs a GeneralPath with a specific winding rule
* and the default initial capacity (20).
- * @param rule the winding rule (WIND_NON_ZERO or WIND_EVEN_ODD)
+ * @param rule the winding rule ({@link #WIND_NON_ZERO} or
+ * {@link #WIND_EVEN_ODD})
+ *
+ * @throws IllegalArgumentException if <code>rule</code> is not one of the
+ * listed values.
*/
public GeneralPath(int rule)
{
@@ -151,8 +155,12 @@ public final class GeneralPath implements Shape, Cloneable
* Constructs a GeneralPath with a specific winding rule
* and the initial capacity. The initial capacity should be
* the approximate number of path segments to be used.
- * @param rule the winding rule (WIND_NON_ZERO or WIND_EVEN_ODD)
+ * @param rule the winding rule ({@link #WIND_NON_ZERO} or
+ * {@link #WIND_EVEN_ODD})
* @param capacity the inital capacity, in path segments
+ *
+ * @throws IllegalArgumentException if <code>rule</code> is not one of the
+ * listed values.
*/
public GeneralPath(int rule, int capacity)
{
@@ -169,7 +177,10 @@ public final class GeneralPath implements Shape, Cloneable
/**
* Constructs a GeneralPath from an arbitrary shape object.
* The Shapes PathIterator path and winding rule will be used.
- * @param s the shape
+ *
+ * @param s the shape (<code>null</code> not permitted).
+ *
+ * @throws NullPointerException if <code>shape</code> is <code>null</code>.
*/
public GeneralPath(Shape s)
{
@@ -183,6 +194,9 @@ public final class GeneralPath implements Shape, Cloneable
/**
* Adds a new point to a path.
+ *
+ * @param x the x-coordinate.
+ * @param y the y-coordinate.
*/
public void moveTo(float x, float y)
{
@@ -263,6 +277,11 @@ public final class GeneralPath implements Shape, Cloneable
* Appends the segments of a Shape to the path. If <code>connect</code> is
* true, the new path segments are connected to the existing one with a line.
* The winding rule of the Shape is ignored.
+ *
+ * @param s the shape (<code>null</code> not permitted).
+ * @param connect whether to connect the new shape to the existing path.
+ *
+ * @throws NullPointerException if <code>s</code> is <code>null</code>.
*/
public void append(Shape s, boolean connect)
{
@@ -276,7 +295,7 @@ public final class GeneralPath implements Shape, Cloneable
* PathIterator#SEG_LINETO} segment.
*
* @param iter the PathIterator specifying which segments shall be
- * appended.
+ * appended (<code>null</code> not permitted).
*
* @param connect <code>true</code> for substituting the initial
* {@link PathIterator#SEG_MOVETO} segment by a {@link
@@ -327,6 +346,8 @@ public final class GeneralPath implements Shape, Cloneable
/**
* Returns the path&#x2019;s current winding rule.
+ *
+ * @return {@link #WIND_EVEN_ODD} or {@link #WIND_NON_ZERO}.
*/
public int getWindingRule()
{
@@ -338,6 +359,8 @@ public final class GeneralPath implements Shape, Cloneable
* considered &#x2019;inside&#x2019; or &#x2019;outside&#x2019; the path
* on drawing. Valid rules are WIND_EVEN_ODD for an even-odd winding rule,
* or WIND_NON_ZERO for a non-zero winding rule.
+ *
+ * @param rule the rule ({@link #WIND_EVEN_ODD} or {@link #WIND_NON_ZERO}).
*/
public void setWindingRule(int rule)
{
@@ -348,6 +371,8 @@ public final class GeneralPath implements Shape, Cloneable
/**
* Returns the current appending point of the path.
+ *
+ * @return The point.
*/
public Point2D getCurrentPoint()
{
@@ -367,6 +392,8 @@ public final class GeneralPath implements Shape, Cloneable
/**
* Applies a transform to the path.
+ *
+ * @param xform the transform (<code>null</code> not permitted).
*/
public void transform(AffineTransform xform)
{
@@ -706,6 +733,8 @@ public final class GeneralPath implements Shape, Cloneable
/**
* Helper method - ensure the size of the data arrays,
* otherwise, reallocate new ones twice the size
+ *
+ * @param size the minimum array size.
*/
private void ensureSize(int size)
{
diff --git a/javax/swing/JEditorPane.java b/javax/swing/JEditorPane.java
index 06844355a..a503bb6e8 100644
--- a/javax/swing/JEditorPane.java
+++ b/javax/swing/JEditorPane.java
@@ -869,6 +869,13 @@ public class JEditorPane extends JTextComponent
public final void setContentType(String type)
{
+ // Strip off content type parameters.
+ int paramIndex = type.indexOf(';');
+ if (paramIndex > -1)
+ {
+ // TODO: Handle character encoding.
+ type = type.substring(0, paramIndex).trim();
+ }
if (editorKit != null
&& editorKit.getContentType().equals(type))
return;
diff --git a/javax/swing/JTextField.java b/javax/swing/JTextField.java
index 367503b73..ace358f89 100644
--- a/javax/swing/JTextField.java
+++ b/javax/swing/JTextField.java
@@ -270,7 +270,8 @@ public class JTextField extends JTextComponent
*/
protected void fireActionPerformed()
{
- ActionEvent event = new ActionEvent(this, 0, getText());
+ ActionEvent event = new ActionEvent(this, 0,
+ actionCommand == null ? getText() : actionCommand);
ActionListener[] listeners = getActionListeners();
for (int index = 0; index < listeners.length; ++index)
diff --git a/javax/swing/text/FlowView.java b/javax/swing/text/FlowView.java
index c4625fc62..cee5bb126 100644
--- a/javax/swing/text/FlowView.java
+++ b/javax/swing/text/FlowView.java
@@ -39,6 +39,7 @@ exception statement from your version. */
package javax.swing.text;
import java.awt.Component;
+import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
@@ -86,7 +87,7 @@ public abstract class FlowView extends BoxView
*/
public void insertUpdate(FlowView fv, DocumentEvent e, Rectangle alloc)
{
- if (alloc != null)
+ if (alloc == null)
{
fv.layoutChanged(X_AXIS);
fv.layoutChanged(Y_AXIS);
@@ -95,7 +96,7 @@ public abstract class FlowView extends BoxView
{
Component host = fv.getContainer();
if (host != null)
- host.repaint();
+ host.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
}
}
@@ -112,7 +113,7 @@ public abstract class FlowView extends BoxView
*/
public void removeUpdate(FlowView fv, DocumentEvent e, Rectangle alloc)
{
- if (alloc != null)
+ if (alloc == null)
{
fv.layoutChanged(X_AXIS);
fv.layoutChanged(Y_AXIS);
@@ -121,7 +122,7 @@ public abstract class FlowView extends BoxView
{
Component host = fv.getContainer();
if (host != null)
- host.repaint();
+ host.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
}
}
@@ -138,7 +139,7 @@ public abstract class FlowView extends BoxView
*/
public void changedUpdate(FlowView fv, DocumentEvent e, Rectangle alloc)
{
- if (alloc != null)
+ if (alloc == null)
{
fv.layoutChanged(X_AXIS);
fv.layoutChanged(Y_AXIS);
@@ -147,7 +148,7 @@ public abstract class FlowView extends BoxView
{
Component host = fv.getContainer();
if (host != null)
- host.repaint();
+ host.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
}
}
@@ -432,14 +433,14 @@ public abstract class FlowView extends BoxView
* visual representation, this is handled by the physical view implemented
* in the <code>FlowView</code>.
*/
- class LogicalView extends BoxView
+ class LogicalView extends CompositeView
{
/**
* Creates a new LogicalView instance.
*/
- LogicalView(Element el, int axis)
+ LogicalView(Element el)
{
- super(el, axis);
+ super(el);
}
/**
@@ -451,6 +452,117 @@ public abstract class FlowView extends BoxView
View p = getParent();
return p != null ? p.getAttributes() : null;
}
+
+ protected void childAllocation(int index, Rectangle a)
+ {
+ // Nothing to do here (not visual).
+ }
+
+ protected View getViewAtPoint(int x, int y, Rectangle r)
+ {
+ // Nothing to do here (not visual).
+ return null;
+ }
+
+ protected boolean isAfter(int x, int y, Rectangle r)
+ {
+ // Nothing to do here (not visual).
+ return false;
+ }
+
+ protected boolean isBefore(int x, int y, Rectangle r)
+ {
+ // Nothing to do here (not visual).
+ return false;
+ }
+
+ public float getPreferredSpan(int axis)
+ {
+ float max = 0;
+ float pref = 0;
+ int n = getViewCount();
+ for (int i = 0; i < n; i++)
+ {
+ View v = getView(i);
+ pref += v.getPreferredSpan(axis);
+ if (v.getBreakWeight(axis, 0, Integer.MAX_VALUE)
+ >= ForcedBreakWeight)
+ {
+ max = Math.max(pref, pref);
+ pref = 0;
+ }
+ }
+ max = Math.max(max, pref);
+ return max;
+ }
+
+ public float getMinimumSpan(int axis)
+ {
+ float max = 0;
+ float min = 0;
+ boolean wrap = true;
+ int n = getViewCount();
+ for (int i = 0; i < n; i++)
+ {
+ View v = getView(i);
+ if (v.getBreakWeight(axis, 0, Integer.MAX_VALUE)
+ == BadBreakWeight)
+ {
+ min += v.getPreferredSpan(axis);
+ wrap = false;
+ }
+ else if (! wrap)
+ {
+ max = Math.max(min, max);
+ wrap = true;
+ min = 0;
+ }
+ }
+ max = Math.max(max, min);
+ return max;
+ }
+
+ public void paint(Graphics g, Shape s)
+ {
+ // Nothing to do here (not visual).
+ }
+
+ /**
+ * Overridden to handle possible leaf elements.
+ */
+ protected void loadChildren(ViewFactory f)
+ {
+ Element el = getElement();
+ if (el.isLeaf())
+ {
+ View v = new LabelView(el);
+ append(v);
+ }
+ else
+ super.loadChildren(f);
+ }
+
+ /**
+ * Overridden to reparent the children to this logical view, in case
+ * they have been parented by a row.
+ */
+ protected void forwardUpdateToView(View v, DocumentEvent e, Shape a,
+ ViewFactory f)
+ {
+ v.setParent(this);
+ super.forwardUpdateToView(v, e, a, f);
+ }
+
+ /**
+ * Overridden to handle possible leaf element.
+ */
+ protected int getViewIndexAtPosition(int pos)
+ {
+ int index = 0;
+ if (! getElement().isLeaf())
+ index = super.getViewIndexAtPosition(pos);
+ return index;
+ }
}
/**
@@ -565,9 +677,11 @@ public abstract class FlowView extends BoxView
{
if (layoutPool == null)
{
- layoutPool = new LogicalView(getElement(), getAxis());
+ layoutPool = new LogicalView(getElement());
layoutPool.setParent(this);
}
+ // Initialize the flow strategy.
+ strategy.insertUpdate(this, null, null);
}
/**
@@ -722,7 +836,7 @@ public abstract class FlowView extends BoxView
res = new SizeRequirements();
res.minimum = (int) layoutPool.getMinimumSpan(axis);
res.preferred = Math.max(res.minimum,
- (int) layoutPool.getMinimumSpan(axis));
+ (int) layoutPool.getPreferredSpan(axis));
res.maximum = Integer.MAX_VALUE;
res.alignment = 0.5F;
return res;
diff --git a/javax/swing/text/GlyphView.java b/javax/swing/text/GlyphView.java
index e177d927d..cb7f8f05d 100644
--- a/javax/swing/text/GlyphView.java
+++ b/javax/swing/text/GlyphView.java
@@ -433,10 +433,15 @@ public class GlyphView extends View implements TabableView, Cloneable
TabExpander te = v.getTabExpander();
Segment txt = v.getText(p0, v.getEndOffset());
Font font = v.getFont();
- FontMetrics fm = v.getContainer().getFontMetrics(font);
+ Container c = v.getContainer();
+ FontMetrics fm;
+ if (c != null)
+ fm = c.getFontMetrics(font);
+ else
+ fm = Toolkit.getDefaultToolkit().getFontMetrics(font);
int pos = Utilities.getTabbedTextOffset(txt, fm, (int) x,
(int) (x + len), te, p0, false);
- return pos;
+ return pos + p0;
}
/**
@@ -655,9 +660,9 @@ public class GlyphView extends View implements TabableView, Cloneable
*/
public float getTabbedSpan(float x, TabExpander te)
{
- Element el = getElement();
- return getGlyphPainter().getSpan(this, el.getStartOffset(),
- el.getEndOffset(), te, x);
+ checkPainter();
+ return getGlyphPainter().getSpan(this, getStartOffset(),
+ getEndOffset(), te, x);
}
/**
@@ -905,31 +910,19 @@ public class GlyphView extends View implements TabableView, Cloneable
*/
public View breakView(int axis, int p0, float pos, float len)
{
- if (axis == Y_AXIS)
- return this;
-
- checkPainter();
-
- // Try to find a suitable line break.
- Segment txt = new Segment();
- try
+ View brokenView = this;
+ if (axis == X_AXIS)
{
- int start = getStartOffset();
- int length = getEndOffset() - start;
- getDocument().getText(start, length, txt);
- }
- catch (BadLocationException ex)
- {
- AssertionError err = new AssertionError("BadLocationException must not "
- + "be thrown here.");
- err.initCause(ex);
- throw err;
+ checkPainter();
+ int end = glyphPainter.getBoundedPosition(this, p0, pos, len);
+ int breakLoc = getBreakLocation(p0, end);
+ if (breakLoc != -1)
+ end = breakLoc;
+ if (p0 != getStartOffset() || end != getEndOffset())
+ {
+ brokenView = createFragment(p0, end);
+ }
}
- int breakLocation =
- Utilities.getBreakLocation(txt, getContainer().getFontMetrics(getFont()),
- (int) pos, (int) (pos + len),
- getTabExpander(), p0);
- View brokenView = createFragment(p0, breakLocation);
return brokenView;
}
@@ -955,28 +948,36 @@ public class GlyphView extends View implements TabableView, Cloneable
weight = super.getBreakWeight(axis, pos, len);
else
{
- // FIXME: Commented out because the Utilities.getBreakLocation method
- // is still buggy. The GoodBreakWeight is a reasonable workaround for
- // now.
-// int startOffset = getStartOffset();
-// int endOffset = getEndOffset() - 1;
-// Segment s = getText(startOffset, endOffset);
-// Container c = getContainer();
-// FontMetrics fm = c.getFontMetrics(c.getFont());
-// int x0 = (int) pos;
-// int x = (int) (pos + len);
-// int breakLoc = Utilities.getBreakLocation(s, fm, x0, x,
-// getTabExpander(),
-// startOffset);
-// if (breakLoc == startOffset || breakLoc == endOffset)
-// weight = GoodBreakWeight;
-// else
-// weight = ExcellentBreakWeight;
- weight = GoodBreakWeight;
+ checkPainter();
+ int start = getStartOffset();
+ int end = glyphPainter.getBoundedPosition(this, start, pos, len);
+ if (end == 0)
+ weight = BadBreakWeight;
+ else
+ {
+ if (getBreakLocation(start, end) != -1)
+ weight = ExcellentBreakWeight;
+ else
+ weight = GoodBreakWeight;
+ }
}
return weight;
}
+ private int getBreakLocation(int start, int end)
+ {
+ int loc = -1;
+ Segment s = getText(start, end);
+ for (char c = s.last(); c != Segment.DONE && loc == -1; c = s.previous())
+ {
+ if (Character.isWhitespace(c))
+ {
+ loc = s.getIndex() - s.getBeginIndex() + 1 + start;
+ }
+ }
+ return loc;
+ }
+
/**
* Receives notification that some text attributes have changed within the
* text fragment that this view is responsible for. This calls
diff --git a/javax/swing/text/Utilities.java b/javax/swing/text/Utilities.java
index 8ddf97a12..fa2d1ab52 100644
--- a/javax/swing/text/Utilities.java
+++ b/javax/swing/text/Utilities.java
@@ -93,7 +93,6 @@ public class Utilities
// The current x and y pixel coordinates.
int pixelX = x;
- int pixelY = y - ascent;
int pixelWidth = 0;
int pos = s.offset;
@@ -107,7 +106,7 @@ public class Utilities
if (c == '\t')
{
if (len > 0) {
- g.drawChars(buffer, pos, len, pixelX, pixelY + ascent);
+ g.drawChars(buffer, pos, len, pixelX, y);
pixelX += pixelWidth;
pixelWidth = 0;
}
@@ -134,7 +133,7 @@ public class Utilities
}
if (len > 0)
- g.drawChars(buffer, pos, len, pixelX, pixelY + ascent);
+ g.drawChars(buffer, pos, len, pixelX, y);
return pixelX + pixelWidth;
}
diff --git a/javax/swing/text/html/FormView.java b/javax/swing/text/html/FormView.java
index d54021066..031a8b7a4 100644
--- a/javax/swing/text/html/FormView.java
+++ b/javax/swing/text/html/FormView.java
@@ -44,15 +44,23 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.swing.ButtonModel;
+import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
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.UIManager;
import javax.swing.text.AttributeSet;
import javax.swing.text.ComponentView;
+import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.StyleConstants;
@@ -125,6 +133,11 @@ public class FormView
UIManager.getString("FormView.resetButtonText");
/**
+ * If this is true, the maximum size is set to the preferred size.
+ */
+ private boolean maxIsPreferred;
+
+ /**
* Creates a new <code>FormView</code>.
*
* @param el the element that is displayed by this view.
@@ -141,37 +154,147 @@ public class FormView
{
Component comp = null;
Element el = getElement();
- Object tag = el.getAttributes().getAttribute(StyleConstants.NameAttribute);
+ AttributeSet atts = el.getAttributes();
+ Object tag = atts.getAttribute(StyleConstants.NameAttribute);
+ Object model = atts.getAttribute(StyleConstants.ModelAttribute);
if (tag.equals(HTML.Tag.INPUT))
{
- AttributeSet atts = el.getAttributes();
String type = (String) atts.getAttribute(HTML.Attribute.TYPE);
- String value = (String) atts.getAttribute(HTML.Attribute.VALUE);
if (type.equals("button"))
- comp = new JButton(value);
+ {
+ String value = (String) atts.getAttribute(HTML.Attribute.VALUE);
+ JButton b = new JButton(value);
+ if (model != null)
+ {
+ b.setModel((ButtonModel) model);
+ b.addActionListener(this);
+ }
+ comp = b;
+ maxIsPreferred = true;
+ }
else if (type.equals("checkbox"))
- comp = new JCheckBox(value);
+ {
+ JCheckBox c = new JCheckBox();
+ if (model != null)
+ {
+ boolean sel = atts.getAttribute(HTML.Attribute.CHECKED) != null;
+ ((JToggleButton.ToggleButtonModel) model).setSelected(sel);
+ c.setModel((ButtonModel) model);
+ }
+ comp = c;
+ maxIsPreferred = true;
+ }
else if (type.equals("image"))
- comp = new JButton(value); // FIXME: Find out how to fetch the image.
+ {
+ String src = (String) atts.getAttribute(HTML.Attribute.SRC);
+ JButton b;
+ try
+ {
+ URL base = ((HTMLDocument) el.getDocument()).getBase();
+ URL srcURL = new URL(base, src);
+ ImageIcon icon = new ImageIcon(srcURL);
+ b = new JButton(icon);
+ }
+ catch (MalformedURLException ex)
+ {
+ b = new JButton(src);
+ }
+ if (model != null)
+ {
+ b.setModel((ButtonModel) model);
+ b.addActionListener(this);
+ }
+ comp = b;
+ maxIsPreferred = true;
+ }
else if (type.equals("password"))
- comp = new JPasswordField(value);
+ {
+ int size = HTML.getIntegerAttributeValue(atts, HTML.Attribute.SIZE,
+ -1);
+ JTextField tf = new JPasswordField();
+ if (size > 0)
+ tf.setColumns(size);
+ else
+ 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"))
- comp = new JRadioButton(value);
+ {
+ JRadioButton c = new JRadioButton();
+ if (model != null)
+ {
+ boolean sel = atts.getAttribute(HTML.Attribute.CHECKED) != null;
+ ((JToggleButton.ToggleButtonModel) model).setSelected(sel);
+ c.setModel((ButtonModel) model);
+ }
+ comp = c;
+ maxIsPreferred = true;
+ }
else if (type.equals("reset"))
{
- if (value == null || value.equals(""))
- value = RESET;
- comp = new JButton(value);
+ String value = (String) atts.getAttribute(HTML.Attribute.VALUE);
+ if (value == null)
+ value = UIManager.getString("FormView.resetButtonText");
+ JButton b = new JButton(value);
+ if (model != null)
+ {
+ b.setModel((ButtonModel) model);
+ b.addActionListener(this);
+ }
+ comp = b;
+ maxIsPreferred = true;
}
else if (type.equals("submit"))
{
- if (value == null || value.equals(""))
- value = SUBMIT;
- comp = new JButton(value);
+ String value = (String) atts.getAttribute(HTML.Attribute.VALUE);
+ if (value == null)
+ value = UIManager.getString("FormView.submitButtonText");
+ JButton b = new JButton(value);
+ if (model != null)
+ {
+ b.setModel((ButtonModel) model);
+ b.addActionListener(this);
+ }
+ comp = b;
+ maxIsPreferred = true;
}
else if (type.equals("text"))
- comp = new JTextField(value);
-
+ {
+ int size = HTML.getIntegerAttributeValue(atts, HTML.Attribute.SIZE,
+ -1);
+ JTextField tf = new JTextField();
+ if (size > 0)
+ tf.setColumns(size);
+ else
+ 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 (tag == HTML.Tag.TEXTAREA)
+ {
+ JTextArea textArea = new JTextArea((Document) model);
+ int rows = HTML.getIntegerAttributeValue(atts, HTML.Attribute.ROWS, 1);
+ textArea.setRows(rows);
+ int cols = HTML.getIntegerAttributeValue(atts, HTML.Attribute.COLS, 20);
+ textArea.setColumns(cols);
+ maxIsPreferred = true;
+ comp = new JScrollPane(textArea,
+ JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
+ JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
}
// FIXME: Implement the remaining components.
return comp;
@@ -188,16 +311,11 @@ public class FormView
*/
public float getMaximumSpan(int axis)
{
- // FIXME: The specs say that for some components the maximum span == the
- // preferred span of the component. This should be figured out and
- // implemented accordingly.
float span;
- if (axis == X_AXIS)
- span = getComponent().getMaximumSize().width;
- else if (axis == Y_AXIS)
- span = getComponent().getMaximumSize().height;
+ if (maxIsPreferred)
+ span = getPreferredSpan(axis);
else
- throw new IllegalArgumentException("Invalid axis parameter");
+ span = super.getMaximumSpan(axis);
return span;
}
diff --git a/javax/swing/text/html/HTMLDocument.java b/javax/swing/text/html/HTMLDocument.java
index 00372cd36..2e2eb3abc 100644
--- a/javax/swing/text/html/HTMLDocument.java
+++ b/javax/swing/text/html/HTMLDocument.java
@@ -44,19 +44,24 @@ import gnu.javax.swing.text.html.parser.htmlAttributeSet;
import java.io.IOException;
import java.io.StringReader;
import java.net.URL;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Stack;
import java.util.Vector;
+import javax.swing.DefaultButtonModel;
import javax.swing.JEditorPane;
+import javax.swing.JToggleButton;
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;
import javax.swing.text.MutableAttributeSet;
+import javax.swing.text.PlainDocument;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.html.HTML.Tag;
@@ -559,7 +564,42 @@ public class HTMLDocument extends DefaultStyledDocument
/** A temporary variable that helps with the printing out of debug information **/
boolean debug = false;
-
+
+ /**
+ * This is true when we are inside a pre tag.
+ */
+ boolean inPreTag = false;
+
+ /**
+ * This is true when we are inside a style tag. This will add text
+ * content inside this style tag beeing parsed as CSS.
+ *
+ * This is package private to avoid accessor methods.
+ */
+ boolean inStyleTag = false;
+
+ /**
+ * This is true when we are inside a &lt;textarea&gt; tag. Any text
+ * content will then be added to the text area.
+ *
+ * This is package private to avoid accessor methods.
+ */
+ boolean inTextArea = false;
+
+ /**
+ * This contains all stylesheets that are somehow read, either
+ * via embedded style tags, or via linked stylesheets. The
+ * elements will be String objects containing a stylesheet each.
+ */
+ ArrayList styles;
+
+ /**
+ * The document model for a textarea.
+ *
+ * This is package private to avoid accessor methods.
+ */
+ Document textAreaDocument;
+
void print (String line)
{
if (debug)
@@ -634,7 +674,11 @@ public class HTMLDocument extends DefaultStyledDocument
popCharacterStyle();
}
}
-
+
+ /**
+ * Processes elements that make up forms: &lt;input&gt;, &lt;textarea&gt;,
+ * &lt;select&gt; and &lt;option&gt;.
+ */
public class FormAction extends SpecialAction
{
/**
@@ -642,10 +686,27 @@ public class HTMLDocument extends DefaultStyledDocument
* of tags associated with this Action.
*/
public void start(HTML.Tag t, MutableAttributeSet a)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("FormAction.start not implemented");
+ if (t == HTML.Tag.INPUT)
+ {
+ String type = (String) a.getAttribute(HTML.Attribute.TYPE);
+ if (type == null)
+ {
+ type = "text"; // Default to 'text' when nothing was specified.
+ a.addAttribute(HTML.Attribute.TYPE, type);
+ }
+ setModel(type, a);
+ }
+ else if (t == HTML.Tag.TEXTAREA)
+ {
+ inTextArea = true;
+ textAreaDocument = new PlainDocument();
+ a.addAttribute(StyleConstants.ModelAttribute, textAreaDocument);
+ }
+ // TODO: Handle select and option tags.
+
+ // Build the element.
+ super.start(t, a);
}
/**
@@ -653,11 +714,46 @@ public class HTMLDocument extends DefaultStyledDocument
* with this Action.
*/
public void end(HTML.Tag t)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("FormAction.end not implemented");
- }
+ if (t == HTML.Tag.TEXTAREA)
+ {
+ inTextArea = false;
+ }
+
+ // TODO: Handle select and option tags.
+
+ // Finish the element.
+ super.end(t);
+ }
+
+ private void setModel(String type, MutableAttributeSet attrs)
+ {
+ if (type.equals("submit") || type.equals("reset")
+ || type.equals("image"))
+ {
+ // Create button.
+ attrs.addAttribute(StyleConstants.ModelAttribute,
+ new DefaultButtonModel());
+ }
+ else if (type.equals("text") || type.equals("password"))
+ {
+ // TODO: Handle fixed length input fields.
+ attrs.addAttribute(StyleConstants.ModelAttribute,
+ new PlainDocument());
+ }
+ else if (type.equals("file"))
+ {
+ attrs.addAttribute(StyleConstants.ModelAttribute,
+ new PlainDocument());
+ }
+ else if (type.equals("checkbox") || type.equals("radio"))
+ {
+ JToggleButton.ToggleButtonModel model =
+ new JToggleButton.ToggleButtonModel();
+ // TODO: Handle radio button via ButtonGroups.
+ attrs.addAttribute(StyleConstants.ModelAttribute, model);
+ }
+ }
}
/**
@@ -690,7 +786,10 @@ public class HTMLDocument extends DefaultStyledDocument
blockClose(t);
}
}
-
+
+ /**
+ * Handles &lt;isindex&gt; tags.
+ */
public class IsindexAction extends TagAction
{
/**
@@ -698,10 +797,10 @@ public class HTMLDocument extends DefaultStyledDocument
* of tags associated with this Action.
*/
public void start(HTML.Tag t, MutableAttributeSet a)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("IsindexAction.start not implemented");
+ blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet());
+ addSpecialElement(t, a);
+ blockClose(HTML.Tag.IMPLIED);
}
}
@@ -725,7 +824,10 @@ public class HTMLDocument extends DefaultStyledDocument
blockClose(t);
}
}
-
+
+ /**
+ * This action is performed when a &lt;pre&gt; tag is parsed.
+ */
public class PreAction extends BlockAction
{
/**
@@ -733,11 +835,11 @@ public class HTMLDocument extends DefaultStyledDocument
* of tags associated with this Action.
*/
public void start(HTML.Tag t, MutableAttributeSet a)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("PreAction.start not implemented");
- super.start(t, a);
+ inPreTag = true;
+ blockOpen(t, a);
+ a.addAttribute(CSS.Attribute.WHITE_SPACE, "pre");
+ blockOpen(HTML.Tag.IMPLIED, a);
}
/**
@@ -745,11 +847,10 @@ public class HTMLDocument extends DefaultStyledDocument
* with this Action.
*/
public void end(HTML.Tag t)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("PreAction.end not implemented");
- super.end(t);
+ blockClose(HTML.Tag.IMPLIED);
+ inPreTag = false;
+ blockClose(t);
}
}
@@ -875,12 +976,20 @@ public class HTMLDocument extends DefaultStyledDocument
* with this Action.
*/
public void end(HTML.Tag t)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("HeadAction.end not implemented: "+t);
+ // We read in all the stylesheets that are embedded or referenced
+ // inside the header.
+ if (styles != null)
+ {
+ int numStyles = styles.size();
+ for (int i = 0; i < numStyles; i++)
+ {
+ String style = (String) styles.get(i);
+ getStyleSheet().addRule(style);
+ }
+ }
super.end(t);
- }
+ }
}
class LinkAction extends TagAction
@@ -957,7 +1066,7 @@ public class HTMLDocument extends DefaultStyledDocument
print ("MetaAction.end not implemented");
}
}
-
+
class StyleAction extends TagAction
{
/**
@@ -965,10 +1074,8 @@ public class HTMLDocument extends DefaultStyledDocument
* of tags associated with this Action.
*/
public void start(HTML.Tag t, MutableAttributeSet a)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("StyleAction.start not implemented");
+ inStyleTag = true;
}
/**
@@ -976,10 +1083,8 @@ public class HTMLDocument extends DefaultStyledDocument
* with this Action.
*/
public void end(HTML.Tag t)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("StyleAction.end not implemented");
+ inStyleTag = false;
}
}
@@ -1182,7 +1287,21 @@ public class HTMLDocument extends DefaultStyledDocument
public void handleText(char[] data, int pos)
{
if (shouldInsert() && data != null && data.length > 0)
- addContent(data, 0, data.length);
+ {
+ if (inTextArea)
+ textAreaContent(data);
+ else if (inPreTag)
+ preContent(data);
+ else if (inStyleTag)
+ {
+ if (styles == null)
+ styles = new ArrayList();
+ styles.add(new String(data));
+ }
+ else
+ addContent(data, 0, data.length);
+
+ }
}
/**
@@ -1305,22 +1424,46 @@ public class HTMLDocument extends DefaultStyledDocument
* @param data the text to add to the textarea
*/
protected void textAreaContent(char[] data)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("HTMLReader.textAreaContent not implemented yet");
+ try
+ {
+ int offset = textAreaDocument.getLength();
+ textAreaDocument.insertString(offset, new String(data), null);
+ }
+ catch (BadLocationException ex)
+ {
+ // Must not happen as we insert at a model location that we
+ // got from the document itself.
+ assert false;
+ }
}
/**
* Adds the given text that was encountered in a <PRE> element.
- *
+ * This adds synthesized lines to hold the text runs.
+ *
* @param data the text
*/
protected void preContent(char[] data)
- throws NotImplementedException
{
- // FIXME: Implement
- print ("HTMLReader.preContent not implemented yet");
+ int start = 0;
+ for (int i = 0; i < data.length; i++)
+ {
+ if (data[i] == '\n')
+ {
+ addContent(data, start, i - start + 1);
+ blockClose(HTML.Tag.IMPLIED);
+ MutableAttributeSet atts = new SimpleAttributeSet();
+ atts.addAttribute(CSS.Attribute.WHITE_SPACE, "pre");
+ blockOpen(HTML.Tag.IMPLIED, atts);
+ start = i + 1;
+ }
+ }
+ if (start < data.length)
+ {
+ // Add remaining last line.
+ addContent(data, start, data.length - start);
+ }
}
/**
diff --git a/javax/swing/text/html/HTMLEditorKit.java b/javax/swing/text/html/HTMLEditorKit.java
index 523c2aca0..c541a4d34 100644
--- a/javax/swing/text/html/HTMLEditorKit.java
+++ b/javax/swing/text/html/HTMLEditorKit.java
@@ -46,6 +46,7 @@ import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.Cursor;
+import java.awt.Point;
import java.io.IOException;
import java.io.InputStream;
@@ -54,18 +55,24 @@ import java.io.Reader;
import java.io.Serializable;
import java.io.StringReader;
import java.io.Writer;
+import java.net.MalformedURLException;
+import java.net.URL;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.swing.Action;
import javax.swing.JEditorPane;
+import javax.swing.SwingUtilities;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.EditorKit;
import javax.swing.text.Element;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.StyleConstants;
+import javax.swing.text.StyledDocument;
import javax.swing.text.StyledEditorKit;
import javax.swing.text.TextAction;
import javax.swing.text.View;
@@ -111,11 +118,14 @@ public class HTMLEditorKit
*/
public void mouseClicked(MouseEvent e)
{
- /*
- These MouseInputAdapter methods generate mouse appropriate events around
- hyperlinks (entering, exiting, and activating).
- */
- // FIXME: Not implemented.
+ JEditorPane editor = (JEditorPane) e.getSource();
+ if (! editor.isEditable() && SwingUtilities.isLeftMouseButton(e))
+ {
+ Point loc = e.getPoint();
+ int pos = editor.viewToModel(loc);
+ if (pos >= 0)
+ activateLink(pos, editor, e.getX(), e.getY());
+ }
}
/**
@@ -125,11 +135,7 @@ public class HTMLEditorKit
*/
public void mouseDragged(MouseEvent e)
{
- /*
- These MouseInputAdapter methods generate mouse appropriate events around
- hyperlinks (entering, exiting, and activating).
- */
- // FIXME: Not implemented.
+ // Nothing to do here.
}
/**
@@ -139,29 +145,111 @@ public class HTMLEditorKit
*/
public void mouseMoved(MouseEvent e)
{
- /*
- These MouseInputAdapter methods generate mouse appropriate events around
- hyperlinks (entering, exiting, and activating).
- */
- // FIXME: Not implemented.
+ JEditorPane editor = (JEditorPane) e.getSource();
+ HTMLEditorKit kit = (HTMLEditorKit) editor.getEditorKit();
+ if (! editor.isEditable())
+ {
+ Document doc = editor.getDocument();
+ if (doc instanceof HTMLDocument)
+ {
+ Cursor newCursor = kit.getDefaultCursor();
+ HTMLDocument htmlDoc = (HTMLDocument) doc;
+ Point loc = e.getPoint();
+ int pos = editor.viewToModel(loc);
+ Element el = htmlDoc.getCharacterElement(pos);
+ if (pos < el.getStartOffset() || pos >= el.getEndOffset())
+ el = null;
+ if (el != null)
+ {
+ AttributeSet aAtts = (AttributeSet)
+ el.getAttributes().getAttribute(HTML.Tag.A);
+ if (aAtts != null)
+ newCursor = kit.getLinkCursor();
+ }
+ if (editor.getCursor() != newCursor)
+ editor.setCursor(newCursor);
+ }
+ }
}
-
+
/**
* If the given position represents a link, then linkActivated is called
- * on the JEditorPane. Implemented to forward to the method with the same
- * name, but pos == editor == -1.
- *
- * @param pos - the position
- * @param editor - the editor pane
+ * on the JEditorPane.
+ *
+ * @param pos the position
+ * @param editor the editor pane
*/
- protected void activateLink(int pos,
- JEditorPane editor)
+ protected void activateLink(int pos, JEditorPane editor)
{
- /*
- This method creates and fires a HyperlinkEvent if the document is an
- instance of HTMLDocument and the href tag of the link is not null.
- */
- // FIXME: Not implemented.
+ activateLink(pos, editor);
+ }
+
+ private void activateLink(int pos, JEditorPane editor, int x, int y)
+ {
+ // TODO: This is here for future extension for mapped links support.
+ // For the time beeing we implement simple hyperlinks.
+ Document doc = editor.getDocument();
+ if (doc instanceof HTMLDocument)
+ {
+ HTMLDocument htmlDoc = (HTMLDocument) doc;
+ Element el = htmlDoc.getCharacterElement(pos);
+ AttributeSet atts = el.getAttributes();
+ AttributeSet anchorAtts =
+ (AttributeSet) atts.getAttribute(HTML.Tag.A);
+ String href = null;
+ if (anchorAtts != null)
+ {
+ href = (String) anchorAtts.getAttribute(HTML.Attribute.HREF);
+ }
+ else
+ {
+ // TODO: Implement link maps here.
+ }
+ HyperlinkEvent event = null;
+ if (href != null)
+ event = createHyperlinkEvent(editor, htmlDoc, href,
+ anchorAtts, el);
+ if (event != null)
+ editor.fireHyperlinkUpdate(event);
+ }
+
+ }
+
+ /**
+ * Creates a HyperlinkEvent for the specified href and anchor if
+ * possible. If for some reason this won't work, return null.
+ *
+ * @param editor the editor
+ * @param doc the document
+ * @param href the href link
+ * @param anchor the anchor
+ * @param el the element
+ *
+ * @return the hyperlink event, or <code>null</code> if we couldn't
+ * create one
+ */
+ private HyperlinkEvent createHyperlinkEvent(JEditorPane editor,
+ HTMLDocument doc,
+ String href,
+ AttributeSet anchor,
+ Element el)
+ {
+ URL url;
+ try
+ {
+ URL base = doc.getBase();
+ url = new URL(base, href);
+
+ }
+ catch (MalformedURLException ex)
+ {
+ url = null;
+ }
+ // TODO: Handle frame documents and target here.
+ HyperlinkEvent ev =
+ new HyperlinkEvent(editor, HyperlinkEvent.EventType.ACTIVATED, url,
+ href, el);
+ return ev;
}
}
@@ -552,7 +640,8 @@ public class HTMLEditorKit
|| 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.PRE)
+ || tag.equals(HTML.Tag.FORM))
view = new BlockView(element, View.Y_AXIS);
else if (tag.equals(HTML.Tag.IMG))
view = new ImageView(element);
@@ -570,14 +659,14 @@ public class HTMLEditorKit
view = new HRuleView(element);
else if (tag.equals(HTML.Tag.BR))
view = new BRView(element);
+ else if (tag.equals(HTML.Tag.INPUT) || tag.equals(HTML.Tag.SELECT)
+ || tag.equals(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))
view = new ListView(element);
- else if (tag.equals(HTML.Tag.INPUT) || tag.equals(HTML.Tag.SELECT)
- || tag.equals(HTML.Tag.TEXTAREA))
- view = new FormView(element);
else if (tag.equals(HTML.Tag.OBJECT))
view = new ObjectView(element);
else if (tag.equals(HTML.Tag.FRAMESET))
@@ -830,7 +919,7 @@ public class HTMLEditorKit
/**
* The mouse listener used for links.
*/
- LinkController mouseListener;
+ private LinkController linkController;
/** The content type */
String contentType = "text/html";
@@ -846,7 +935,7 @@ public class HTMLEditorKit
*/
public HTMLEditorKit()
{
- // Nothing to do here.
+ linkController = new LinkController();
}
/**
@@ -982,8 +1071,15 @@ public class HTMLEditorKit
{
if (doc instanceof HTMLDocument)
{
- // FIXME: Not implemented. Use HTMLWriter.
- out.write(doc.getText(pos, len));
+ HTMLWriter writer = new HTMLWriter(out, (HTMLDocument) doc, pos, len);
+ writer.write();
+ }
+ else if (doc instanceof StyledDocument)
+ {
+ MinimalHTMLWriter writer = new MinimalHTMLWriter(out,
+ (StyledDocument) doc,
+ pos, len);
+ writer.write();
}
else
super.write(out, doc, pos, len);
@@ -1008,7 +1104,9 @@ public class HTMLEditorKit
public Object clone()
{
// FIXME: Need to clone all fields
- return (HTMLEditorKit) super.clone();
+ HTMLEditorKit copy = (HTMLEditorKit) super.clone();
+ copy.linkController = new LinkController();
+ return copy;
}
/**
@@ -1035,10 +1133,9 @@ public class HTMLEditorKit
public void install(JEditorPane c)
{
super.install(c);
- mouseListener = new LinkController();
- c.addMouseListener(mouseListener);
+ c.addMouseListener(linkController);
+ c.addMouseMotionListener(linkController);
editorPane = c;
- // FIXME: need to set up hyperlinklistener object
}
/**
@@ -1050,8 +1147,8 @@ public class HTMLEditorKit
public void deinstall(JEditorPane c)
{
super.deinstall(c);
- c.removeMouseListener(mouseListener);
- mouseListener = null;
+ c.removeMouseListener(linkController);
+ c.removeMouseMotionListener(linkController);
editorPane = null;
}
diff --git a/javax/swing/text/html/HTMLWriter.java b/javax/swing/text/html/HTMLWriter.java
new file mode 100644
index 000000000..16e9a7163
--- /dev/null
+++ b/javax/swing/text/html/HTMLWriter.java
@@ -0,0 +1,1126 @@
+/* HTMLWriter.java --
+ 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.io.IOException;
+import java.io.Writer;
+
+import java.util.Enumeration;
+import java.util.HashSet;
+
+import javax.swing.ComboBoxModel;
+
+import javax.swing.text.AbstractWriter;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.StyleConstants;
+
+import javax.swing.text.html.HTML;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.Option;
+
+/**
+ * HTMLWriter,
+ * A Writer for HTMLDocuments.
+ *
+ * @author David Fu (fchoong at netbeans.jp)
+ */
+
+public class HTMLWriter
+ extends AbstractWriter
+{
+ /**
+ * We keep a reference of the writer passed by the construct.
+ */
+ private Writer outWriter = null;
+
+ /**
+ * We keep a reference of the HTMLDocument passed by the construct.
+ */
+ private HTMLDocument htmlDoc = null;
+
+ /**
+ * Used to keep track of which embeded has been written out.
+ */
+ private HashSet openEmbededTagHashSet = null;
+
+ private String new_line_str = "" + NEWLINE;
+
+ private char[] html_entity_char_arr = {'<', '>', '&', '"'};
+
+ private String[] html_entity_escape_str_arr = {"&lt;", "&gt;", "&amp;",
+ "&quot;"};
+
+ // variables used to output Html Fragment
+ private int doc_pos = -1;
+ private int doc_len = -1;
+ private int doc_offset_remaining = -1;
+ private int doc_len_remaining = -1;
+ private HashSet htmlFragmentParentHashSet = null;
+ private Element startElem = null;
+ private Element endElem = null;
+ private boolean fg_pass_start_elem = false;
+ private boolean fg_pass_end_elem = false;
+
+ /**
+ * Constructs a HTMLWriter.
+ *
+ * @param writer writer to write output to
+ * @param doc the HTMLDocument to output
+ */
+ public HTMLWriter(Writer writer, HTMLDocument doc)
+ {
+ super(writer, doc);
+ outWriter = writer;
+ htmlDoc = doc;
+ openEmbededTagHashSet = new HashSet();
+ } // public HTMLWriter(Writer writer, HTMLDocument doc)
+
+ /**
+ * Constructs a HTMLWriter which outputs a Html Fragment.
+ *
+ * @param writer <code>Writer</code> to write output to
+ * @param doc the <code>javax.swing.text.html.HTMLDocument</code>
+ * to output
+ * @param pos position to start outputing the document
+ * @param len amount to output the document
+ */
+ public HTMLWriter(Writer writer, HTMLDocument doc, int pos, int len)
+ {
+ super(writer, doc, pos, len);
+ outWriter = writer;
+ htmlDoc = doc;
+ openEmbededTagHashSet = new HashSet();
+
+ doc_pos = pos;
+ doc_offset_remaining = pos;
+ doc_len = len;
+ doc_len_remaining = len;
+ htmlFragmentParentHashSet = new HashSet();
+ } // public HTMLWriter(Writer writer, HTMLDocument doc, int pos, int len)
+
+ /**
+ * Call this method to start outputing HTML.
+ *
+ * @throws IOException on any I/O exceptions
+ * @throws BadLocationException if a pos is not a valid position in the
+ * html doc element
+ */
+ public void write()
+ throws IOException, BadLocationException
+ {
+ Element rootElem = htmlDoc.getDefaultRootElement();
+
+ if (doc_pos == -1 && doc_len == -1)
+ {
+ // Normal traversal.
+ traverse(rootElem);
+ } // if(doc_pos == -1 && doc_len == -1)
+ else
+ {
+ // Html fragment traversal.
+ if (doc_pos == -1 || doc_len == -1)
+ throw new BadLocationException("Bad Location("
+ + doc_pos + ", " + doc_len + ")", doc_pos);
+
+ startElem = htmlDoc.getCharacterElement(doc_pos);
+
+ int start_offset = startElem.getStartOffset();
+
+ // Positions before start_offset will not be traversed, and thus
+ // will not be counted.
+ if (start_offset > 0)
+ doc_offset_remaining = doc_offset_remaining - start_offset;
+
+ Element tempParentElem = startElem;
+
+ while ((tempParentElem = tempParentElem.getParentElement()) != null)
+ {
+ if (!htmlFragmentParentHashSet.contains(tempParentElem))
+ htmlFragmentParentHashSet.add(tempParentElem);
+ } // while((tempParentElem = tempParentElem.getParentElement())
+ // != null)
+
+ // NOTE: 20061030 - fchoong - the last index should not be included.
+ endElem = htmlDoc.getCharacterElement(doc_pos + doc_len - 1);
+
+ tempParentElem = endElem;
+
+ while ((tempParentElem = tempParentElem.getParentElement()) != null)
+ {
+ if (!htmlFragmentParentHashSet.contains(tempParentElem))
+ htmlFragmentParentHashSet.add(tempParentElem);
+ } // while((tempParentElem = tempParentElem.getParentElement())
+ // != null)
+
+ traverseHtmlFragment(rootElem);
+
+ } // else
+
+ // NOTE: close out remaining open embeded tags.
+ Object[] tag_arr = openEmbededTagHashSet.toArray();
+
+ for (int i = 0; i < tag_arr.length; i++)
+ {
+ writeRaw("</" + tag_arr[i].toString() + ">");
+ } // for(int i = 0; i < tag_arr.length; i++)
+
+ } // public void write() throws IOException, BadLocationException
+
+ /**
+ * Writes all the attributes in the attrSet, except for attrbutes with
+ * keys of <code>javax.swing.text.html.HTML.Tag</code>,
+ * <code>javax.swing.text.StyleConstants</code> or
+ * <code>javax.swing.text.html.HTML.Attribute.ENDTAG</code>.
+ *
+ * @param attrSet attrSet to write out
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ protected void writeAttributes(AttributeSet attrSet)
+ throws IOException
+ {
+ Enumeration attrNameEnum = attrSet.getAttributeNames();
+
+ while (attrNameEnum.hasMoreElements())
+ {
+ Object key = attrNameEnum.nextElement();
+ Object value = attrSet.getAttribute(key);
+
+ // HTML.Attribute.ENDTAG is an instance, not a class.
+ if (!((key instanceof HTML.Tag) || (key instanceof StyleConstants)
+ || (key == HTML.Attribute.ENDTAG)))
+ {
+ if (key == HTML.Attribute.SELECTED)
+ writeRaw(" selected");
+ else if (key == HTML.Attribute.CHECKED)
+ writeRaw(" checked");
+ else
+ writeRaw(" " + key + "=\"" + value + "\"");
+ } // if(!((key instanceof HTML.Tag) || (key instanceof
+ // StyleConstants) || (key == HTML.Attribute.ENDTAG)))
+ } // while(attrNameEnum.hasMoreElements())
+
+ } // protected void writeAttributes(AttributeSet attrSet) throws IOException
+
+ /**
+ * Writes out an empty tag. i.e. a tag without any child elements.
+ *
+ * @param paramElem the element to output as an empty tag
+ *
+ * @throws IOException on any I/O exceptions
+ * @throws BadLocationException if a pos is not a valid position in the
+ * html doc element
+ */
+ protected void emptyTag(Element paramElem)
+ throws IOException, BadLocationException
+ {
+ String elem_name = paramElem.getName();
+ AttributeSet attrSet = paramElem.getAttributes();
+
+ writeRaw("<" + elem_name);
+ writeAttributes(attrSet);
+ writeRaw(">");
+
+ if (isBlockTag(attrSet))
+ {
+ writeRaw("</" + elem_name + ">");
+ } // if(isBlockTag(attrSet))
+
+ } // protected void emptyTag(Element paramElem)
+ // throws IOException, BadLocationException
+
+ /**
+ * Determines if it is a block tag or not.
+ *
+ * @param attrSet the attrSet of the element
+ *
+ * @return <code>true</code> if it is a block tag
+ * <code>false</code> if it is a not block tag
+ */
+ protected boolean isBlockTag(AttributeSet attrSet)
+ {
+ return ((HTML.Tag)
+ attrSet.getAttribute(StyleConstants.NameAttribute)).isBlock();
+ } // protected boolean isBlockTag(AttributeSet attrSet)
+
+ /**
+ * Writes out a start tag. Synthesized elements are skipped.
+ *
+ * @param paramElem the element to output as a start tag
+ * @throws IOException on any I/O exceptions
+ * @throws BadLocationException if a pos is not a valid position in the
+ * html doc element
+ */
+ protected void startTag(Element paramElem)
+ throws IOException, BadLocationException
+ {
+ // NOTE: Sysnthesized elements do no call this method at all.
+ String elem_name = paramElem.getName();
+ AttributeSet attrSet = paramElem.getAttributes();
+
+ indent();
+ writeRaw("<" + elem_name);
+ writeAttributes(attrSet);
+ writeRaw(">");
+ writeLineSeparator(); // Extra formatting to look more like the RI.
+ incrIndent();
+
+ } // protected void startTag(Element paramElem)
+ // throws IOException, BadLocationException
+
+ /**
+ * Writes out the contents of a textarea.
+ *
+ * @param attrSet the attrSet of the element to output as a text area
+ * @throws IOException on any I/O exceptions
+ * @throws BadLocationException if a pos is not a valid position in the
+ * html doc element
+ */
+ protected void textAreaContent(AttributeSet attrSet)
+ throws IOException, BadLocationException
+ {
+ writeLineSeparator(); // Extra formatting to look more like the RI.
+ indent();
+ writeRaw("<textarea");
+ writeAttributes(attrSet);
+ writeRaw(">");
+
+ Document tempDocument =
+ (Document) attrSet.getAttribute(StyleConstants.ModelAttribute);
+
+ writeRaw(tempDocument.getText(0, tempDocument.getLength()));
+ indent();
+ writeRaw("</textarea>");
+
+ } // protected void textAreaContent(AttributeSet attrSet)
+ // throws IOException, BadLocationException
+
+ /**
+ * Writes out text, within the appropriate range if it is specified.
+ *
+ * @param paramElem the element to output as a text
+ * @throws IOException on any I/O exceptions
+ * @throws BadLocationException if a pos is not a valid position in the
+ * html doc element
+ */
+ protected void text(Element paramElem)
+ throws IOException, BadLocationException
+ {
+ int offset = paramElem.getStartOffset();
+ int len = paramElem.getEndOffset() - paramElem.getStartOffset();
+ String txt_value = htmlDoc.getText(offset, len);
+
+ writeContent(txt_value);
+
+ } // protected void text(Element paramElem)
+ // throws IOException, BadLocationException
+
+ /**
+ * Writes out the contents of a select element.
+ *
+ * @param attrSet the attrSet of the element to output as a select box
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ protected void selectContent(AttributeSet attrSet)
+ throws IOException
+ {
+ writeLineSeparator(); // Extra formatting to look more like the RI.
+ indent();
+ writeRaw("<select");
+ writeAttributes(attrSet);
+ writeRaw(">");
+ incrIndent();
+ writeLineSeparator(); // extra formatting to look more like the RI.
+
+ ComboBoxModel comboBoxModel =
+ (ComboBoxModel) attrSet.getAttribute(StyleConstants.ModelAttribute);
+
+ for (int i = 0; i < comboBoxModel.getSize(); i++)
+ {
+ writeOption((Option) comboBoxModel.getElementAt(i));
+ } // for(int i = 0; i < comboBoxModel.getSize(); i++)
+
+ decrIndent();
+ indent();
+ writeRaw("</select>");
+
+ } // protected void selectContent(AttributeSet attrSet) throws IOException
+
+ /**
+ * Writes out the contents of an option element.
+ *
+ * @param option the option object to output as a select option
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ protected void writeOption(Option option)
+ throws IOException
+ {
+ indent();
+ writeRaw("<option");
+ writeAttributes(option.getAttributes());
+ writeRaw(">");
+
+ writeContent(option.getLabel());
+
+ writeRaw("</option>");
+ writeLineSeparator(); // extra formatting to look more like the RI.
+
+ } // protected void writeOption(Option option) throws IOException
+
+ /**
+ * Writes out an end tag.
+ *
+ * @param paramElem the element to output as an end tag
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ protected void endTag(Element paramElem)
+ throws IOException
+ {
+ String elem_name = paramElem.getName();
+
+ //writeLineSeparator(); // Extra formatting to look more like the RI.
+ decrIndent();
+ indent();
+ writeRaw("</" + elem_name + ">");
+ writeLineSeparator(); // Extra formatting to look more like the RI.
+
+ } // protected void endTag(Element paramElem) throws IOException
+
+ /**
+ * Writes out the comment.
+ *
+ * @param paramElem the element to output as a comment
+ */
+ protected void comment(Element paramElem)
+ throws IOException, BadLocationException
+ {
+ AttributeSet attrSet = paramElem.getAttributes();
+
+ String comment_str = (String) attrSet.getAttribute(HTML.Attribute.COMMENT);
+
+ writeRaw("<!--" + comment_str + "-->");
+
+ } // protected void comment(Element paramElem)
+ // throws IOException, BadLocationException
+
+ /**
+ * Determines if element is a synthesized
+ * <code>javax.swing.text.Element</code> or not.
+ *
+ * @param element the element to test
+ *
+ * @return <code>true</code> if it is a synthesized element,
+ * <code>false</code> if it is a not synthesized element
+ */
+ protected boolean synthesizedElement(Element element)
+ {
+ AttributeSet attrSet = element.getAttributes();
+ Object tagType = attrSet.getAttribute(StyleConstants.NameAttribute);
+
+ if (tagType == HTML.Tag.CONTENT || tagType == HTML.Tag.COMMENT
+ || tagType == HTML.Tag.IMPLIED)
+ return true;
+ else
+ return false;
+ } // protected boolean synthesizedElement(Element element)
+
+ /**
+ * Determines if
+ * <code>javax.swing.text.StyleConstants.NameAttribute</code>
+ * matches tag or not.
+ *
+ * @param attrSet the <code>javax.swing.text.AttributeSet</code> of
+ * element to be matched
+ * @param tag the HTML.Tag to match
+ *
+ * @return <code>true</code> if it matches,
+ * <code>false</code> if it does not match
+ */
+ protected boolean matchNameAttribute(AttributeSet attrSet, HTML.Tag tag)
+ {
+ Object tagType = attrSet.getAttribute(StyleConstants.NameAttribute);
+
+ if (tagType == tag)
+ return true;
+ else
+ return false;
+ } // protected boolean matchNameAttribute(AttributeSet attrSet,
+ // HTML.Tag tag)
+
+ /**
+ * Writes out an embedded tag. The tags not already in
+ * openEmbededTagHashSet will written out.
+ *
+ * @param attrSet the <code>javax.swing.text.AttributeSet</code> of
+ * the element to write out
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ protected void writeEmbeddedTags(AttributeSet attrSet)
+ throws IOException
+ {
+ Enumeration attrNameEnum = attrSet.getAttributeNames();
+
+ while (attrNameEnum.hasMoreElements())
+ {
+ Object key = attrNameEnum.nextElement();
+ Object value = attrSet.getAttribute(key);
+
+ if (key instanceof HTML.Tag)
+ {
+ if (!openEmbededTagHashSet.contains(key))
+ {
+ writeRaw("<" + key);
+ writeAttributes((AttributeSet) value);
+ writeRaw(">");
+ openEmbededTagHashSet.add(key);
+ } // if(!openEmbededTagHashSet.contains(key))
+ } // if(key instanceof HTML.Tag)
+ } // while(attrNameEnum.hasMoreElements())
+
+ } // protected void writeEmbeddedTags(AttributeSet attrSet)
+ // throws IOException
+
+ /**
+ * Closes out an unwanted embedded tag. The tags from the
+ * openEmbededTagHashSet not found in attrSet will be written out.
+ *
+ * @param attrSet the AttributeSet of the element to write out
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ protected void closeOutUnwantedEmbeddedTags(AttributeSet attrSet)
+ throws IOException
+ {
+ Object[] tag_arr = openEmbededTagHashSet.toArray();
+
+ for (int i = 0; i < tag_arr.length; i++)
+ {
+ HTML.Tag key = (HTML.Tag) tag_arr[i];
+
+ if (!attrSet.isDefined(key))
+ {
+ writeRaw("</" + key.toString() + ">");
+ openEmbededTagHashSet.remove(key);
+ } // if(!attrSet.isDefined(key))
+ } // for(int i = 0; i < tag_arr.length; i++)
+
+ } // protected void closeOutUnwantedEmbeddedTags(AttributeSet attrSet)
+ // throws IOException
+
+ /**
+ * Writes out a line separator. Overwrites the parent to write out a new
+ * line.
+ *
+ * @throws IOException on any I/O exceptions.
+ */
+ protected void writeLineSeparator()
+ throws IOException
+ {
+ writeRaw(new_line_str);
+ } // protected void writeLineSeparator() throws IOException
+
+ /**
+ * Write to the writer. Character entites such as &lt;, &gt;
+ * are escaped appropriately.
+ *
+ * @param chars char array to write out
+ * @param off offset
+ * @param len length
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ protected void output(char[] chars, int off, int len)
+ throws IOException
+ {
+ StringBuffer strBuffer = new StringBuffer();
+
+ for (int i = 0; i < chars.length; i++)
+ {
+ if (isCharHtmlEntity(chars[i]))
+ strBuffer.append(escapeCharHtmlEntity(chars[i]));
+ else
+ strBuffer.append(chars[i]);
+ } // for(int i = 0; i < chars.length; i++)
+
+ writeRaw(strBuffer.toString());
+
+ } // protected void output(char[] chars, int off, int len)
+ // throws IOException
+
+ //-------------------------------------------------------------------------
+ // private methods
+
+ /**
+ * The main method used to traverse through the elements.
+ *
+ * @param paramElem element to traverse
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ private void traverse(Element paramElem)
+ throws IOException, BadLocationException
+ {
+ Element currElem = paramElem;
+
+ AttributeSet attrSet = currElem.getAttributes();
+
+ closeOutUnwantedEmbeddedTags(attrSet);
+
+ // NOTE: 20061030 - fchoong - GNU CP uses a different implimentation of
+ // the IMPLIED tag.
+ boolean fg_gnu_cp_implied_tag = false;
+
+ if (matchNameAttribute(attrSet, HTML.Tag.P))
+ {
+ //writeAllAttributes(attrSet);
+
+ Enumeration attrNameEnum = attrSet.getAttributeNames();
+
+ while (attrNameEnum.hasMoreElements())
+ {
+ Object key = attrNameEnum.nextElement();
+ Object value = attrSet.getAttribute(key);
+
+ if (key.equals("_implied_") && value.toString().equals("true"))
+ fg_gnu_cp_implied_tag = true;
+ } // while(attrNameEnum.hasMoreElements())
+ } // if(matchNameAttribute(attrSet, HTML.Tag.P))
+
+ // handle the tag
+ if (synthesizedElement(paramElem) || fg_gnu_cp_implied_tag)
+ {
+ if (matchNameAttribute(attrSet, HTML.Tag.CONTENT))
+ {
+ writeEmbeddedTags(attrSet);
+ text(currElem);
+ } // if(matchNameAttribute(attrSet, HTML.Tag.CONTENT))
+ else if (matchNameAttribute(attrSet, HTML.Tag.COMMENT))
+ {
+ comment(currElem);
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.COMMENT))
+ else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED)
+ || fg_gnu_cp_implied_tag) // NOTE: GNU CP specific
+ {
+ int child_elem_count = currElem.getElementCount();
+
+ if (child_elem_count > 0)
+ {
+ for (int i = 0; i < child_elem_count; i++)
+ {
+ Element childElem = paramElem.getElement(i);
+
+ traverse(childElem);
+
+ } // for(int i = 0; i < child_elem_count; i++)
+ } // if(child_elem_count > 0)
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.IMPLIED))
+ } // if(synthesizedElement(paramElem))
+ else
+ {
+ // NOTE: 20061030 - fchoong - title is treated specially here.
+ // based on RI behavior.
+ if (matchNameAttribute(attrSet, HTML.Tag.TITLE))
+ {
+ boolean fg_is_end_tag = false;
+ Enumeration attrNameEnum = attrSet.getAttributeNames();
+
+ while (attrNameEnum.hasMoreElements())
+ {
+ Object key = attrNameEnum.nextElement();
+ Object value = attrSet.getAttribute(key);
+
+ if (key == HTML.Attribute.ENDTAG && value.equals("true"))
+ fg_is_end_tag = true;
+ } // while(attrNameEnum.hasMoreElements())
+
+ if (fg_is_end_tag)
+ writeRaw("</title>");
+ else
+ {
+ indent();
+ writeRaw("<title>");
+
+ String title_str =
+ (String) htmlDoc.getProperty(HTMLDocument.TitleProperty);
+
+ if (title_str != null)
+ writeContent(title_str);
+
+ } // else
+ } // if(matchNameAttribute(attrSet, HTML.Tag.TITLE))
+ else if (matchNameAttribute(attrSet, HTML.Tag.PRE))
+ {
+ // We pursue more stringent formating here.
+ attrSet = paramElem.getAttributes();
+
+ indent();
+ writeRaw("<pre");
+ writeAttributes(attrSet);
+ writeRaw(">");
+
+ int child_elem_count = currElem.getElementCount();
+
+ for (int i = 0; i < child_elem_count; i++)
+ {
+ Element childElem = paramElem.getElement(i);
+
+ traverse(childElem);
+
+ } // for(int i = 0; i < child_elem_count; i++)
+
+ writeRaw("</pre>");
+
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.PRE))
+ else if (matchNameAttribute(attrSet, HTML.Tag.SELECT))
+ {
+ selectContent(attrSet);
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.SELECT))
+ else if (matchNameAttribute(attrSet, HTML.Tag.TEXTAREA))
+ {
+ textAreaContent(attrSet);
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.TEXTAREA))
+ else
+ {
+ int child_elem_count = currElem.getElementCount();
+
+ if (child_elem_count > 0)
+ {
+ startTag(currElem);
+
+ for (int i = 0; i < child_elem_count; i++)
+ {
+ Element childElem = paramElem.getElement(i);
+
+ traverse(childElem);
+
+ } // for(int i = 0; i < child_elem_count; i++)
+
+ endTag(currElem);
+
+ } // if(child_elem_count > 0)
+ else
+ {
+ emptyTag(currElem);
+ } // else
+ } // else
+ } // else
+
+ } // private void traverse(Element paramElem)
+ // throws IOException, BadLocationException
+
+ /**
+ * The method used to traverse through a html fragment.
+ *
+ * @param paramElem element to traverse
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ private void traverseHtmlFragment(Element paramElem)
+ throws IOException, BadLocationException
+ {
+ // NOTE: This method is similar to traverse(Element paramElem)
+ Element currElem = paramElem;
+
+ boolean fg_is_fragment_parent_elem = false;
+ boolean fg_is_start_and_end_elem = false;
+
+ if (htmlFragmentParentHashSet.contains(paramElem))
+ fg_is_fragment_parent_elem = true;
+
+ if (paramElem == startElem)
+ fg_pass_start_elem = true;
+
+ if (paramElem == startElem && paramElem == endElem)
+ fg_is_start_and_end_elem = true;
+
+ AttributeSet attrSet = currElem.getAttributes();
+
+ closeOutUnwantedEmbeddedTags(attrSet);
+
+ if (fg_is_fragment_parent_elem || (fg_pass_start_elem
+ && fg_pass_end_elem == false) || fg_is_start_and_end_elem)
+ {
+ // NOTE: 20061030 - fchoong - GNU CP uses a different implimentation of
+ // the IMPLIED tag.
+ boolean fg_gnu_cp_implied_tag = false;
+
+ if (matchNameAttribute(attrSet, HTML.Tag.P))
+ {
+ //writeAllAttributes(attrSet);
+
+ Enumeration attrNameEnum = attrSet.getAttributeNames();
+
+ while (attrNameEnum.hasMoreElements())
+ {
+ Object key = attrNameEnum.nextElement();
+ Object value = attrSet.getAttribute(key);
+
+ if (key.equals("_implied_") && value.toString().equals("true"))
+ fg_gnu_cp_implied_tag = true;
+ } // while(attrNameEnum.hasMoreElements())
+ } // if(matchNameAttribute(attrSet, HTML.Tag.P))
+
+ // handle the tag
+ if (synthesizedElement(paramElem) || fg_gnu_cp_implied_tag)
+ {
+ if (matchNameAttribute(attrSet, HTML.Tag.CONTENT))
+ {
+ writeEmbeddedTags(attrSet);
+
+ int content_offset = paramElem.getStartOffset();
+ int content_length = currElem.getEndOffset() - content_offset;
+
+ if (doc_offset_remaining > 0)
+ {
+ if (content_length > doc_offset_remaining)
+ {
+ int split_len = content_length;
+
+ split_len = split_len - doc_offset_remaining;
+
+ if (split_len > doc_len_remaining)
+ split_len = doc_len_remaining;
+
+ // we need to split it.
+ String txt_value = htmlDoc.getText(content_offset
+ + doc_offset_remaining, split_len);
+
+ writeContent(txt_value);
+
+ doc_offset_remaining = 0; // the offset is used up.
+ doc_len_remaining = doc_len_remaining - split_len;
+ } // if(content_length > doc_offset_remaining)
+ else
+ {
+ // doc_offset_remaining is greater than the entire
+ // length of content
+ doc_offset_remaining = doc_offset_remaining
+ - content_length;
+ } // else
+ } // if(doc_offset_remaining > 0)
+ else if (content_length <= doc_len_remaining)
+ {
+ // we can fit the entire content.
+ text(currElem);
+ doc_len_remaining = doc_len_remaining - content_length;
+ } // else if(content_length <= doc_len_remaining)
+ else
+ {
+ // we need to split it.
+ String txt_value = htmlDoc.getText(content_offset,
+ doc_len_remaining);
+
+ writeContent(txt_value);
+
+ doc_len_remaining = 0;
+ } // else
+
+ } // if(matchNameAttribute(attrSet, HTML.Tag.CONTENT))
+ else if (matchNameAttribute(attrSet, HTML.Tag.COMMENT))
+ {
+ comment(currElem);
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.COMMENT))
+ else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED)
+ || fg_gnu_cp_implied_tag) // NOTE: GNU CP specific
+ {
+ int child_elem_count = currElem.getElementCount();
+
+ if (child_elem_count > 0)
+ {
+ for (int i = 0; i < child_elem_count; i++)
+ {
+ Element childElem = paramElem.getElement(i);
+
+ traverseHtmlFragment(childElem);
+
+ } // for(int i = 0; i < child_elem_count; i++)
+ } // if(child_elem_count > 0)
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.IMPLIED))
+ } // if(synthesizedElement(paramElem))
+ else
+ {
+ // NOTE: 20061030 - fchoong - the isLeaf() condition seems to
+ // generate the closest behavior to the RI.
+ if (paramElem.isLeaf())
+ {
+ if (doc_offset_remaining > 0)
+ {
+ doc_offset_remaining--;
+ } // if(doc_offset_remaining > 0)
+ else if (doc_len_remaining > 0)
+ {
+ doc_len_remaining--;
+ } // else if(doc_len_remaining > 0)
+ } // if(paramElem.isLeaf())
+
+ // NOTE: 20061030 - fchoong - title is treated specially here.
+ // based on RI behavior.
+ if (matchNameAttribute(attrSet, HTML.Tag.TITLE))
+ {
+ boolean fg_is_end_tag = false;
+ Enumeration attrNameEnum = attrSet.getAttributeNames();
+
+ while (attrNameEnum.hasMoreElements())
+ {
+ Object key = attrNameEnum.nextElement();
+ Object value = attrSet.getAttribute(key);
+
+ if (key == HTML.Attribute.ENDTAG && value.equals("true"))
+ fg_is_end_tag = true;
+ } // while(attrNameEnum.hasMoreElements())
+
+ if (fg_is_end_tag)
+ writeRaw("</title>");
+ else
+ {
+ indent();
+ writeRaw("<title>");
+
+ String title_str =
+ (String) htmlDoc.getProperty(HTMLDocument.TitleProperty);
+
+ if (title_str != null)
+ writeContent(title_str);
+
+ } // else
+ } // if(matchNameAttribute(attrSet, HTML.Tag.TITLE))
+ else if (matchNameAttribute(attrSet, HTML.Tag.PRE))
+ {
+ // We pursue more stringent formating here.
+ attrSet = paramElem.getAttributes();
+
+ indent();
+ writeRaw("<pre");
+ writeAttributes(attrSet);
+ writeRaw(">");
+
+ int child_elem_count = currElem.getElementCount();
+
+ for (int i = 0; i < child_elem_count; i++)
+ {
+ Element childElem = paramElem.getElement(i);
+
+ traverseHtmlFragment(childElem);
+
+ } // for(int i = 0; i < child_elem_count; i++)
+
+ writeRaw("</pre>");
+
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.PRE))
+ else if (matchNameAttribute(attrSet, HTML.Tag.SELECT))
+ {
+ selectContent(attrSet);
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.SELECT))
+ else if (matchNameAttribute(attrSet, HTML.Tag.TEXTAREA))
+ {
+ textAreaContent(attrSet);
+ } // else if(matchNameAttribute(attrSet, HTML.Tag.TEXTAREA))
+ else
+ {
+ int child_elem_count = currElem.getElementCount();
+
+ if (child_elem_count > 0)
+ {
+ startTag(currElem);
+
+ for (int i = 0; i < child_elem_count; i++)
+ {
+ Element childElem = paramElem.getElement(i);
+
+ traverseHtmlFragment(childElem);
+
+ } // for(int i = 0; i < child_elem_count; i++)
+
+ endTag(currElem);
+
+ } // if(child_elem_count > 0)
+ else
+ {
+ emptyTag(currElem);
+ } // else
+ } // else
+ } // else
+
+ } // if(fg_is_fragment_parent_elem || (fg_pass_start_elem
+ // && fg_pass_end_elem == false) || fg_is_start_and_end_elem)
+
+ if (paramElem == endElem)
+ fg_pass_end_elem = true;
+
+ } // private void traverseHtmlFragment(Element paramElem)
+ // throws IOException, BadLocationException
+
+ /**
+ * Write to the writer without any modifications.
+ *
+ * @param param_str the str to write out
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ private void writeRaw(String param_str)
+ throws IOException
+ {
+ super.output(param_str.toCharArray(), 0, param_str.length());
+ } // private void writeRaw(char[] chars, int off, int len)
+ // throws IOException
+
+ /**
+ * Write to the writer, escaping HTML character entitie where neccessary.
+ *
+ * @param param_str the str to write out
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ private void writeContent(String param_str)
+ throws IOException
+ {
+ char[] str_char_arr = param_str.toCharArray();
+
+ if (hasHtmlEntity(param_str))
+ output(str_char_arr, 0, str_char_arr.length);
+ else
+ super.output(str_char_arr, 0, str_char_arr.length);
+
+ } // private void writeContent(String param_str) throws IOException
+
+ /**
+ * Use this for debugging. Writes out all attributes regardless of type.
+ *
+ * @param attrSet the <code>javax.swing.text.AttributeSet</code> to
+ * write out
+ *
+ * @throws IOException on any I/O exceptions
+ */
+ private void writeAllAttributes(AttributeSet attrSet)
+ throws IOException
+ {
+ Enumeration attrNameEnum = attrSet.getAttributeNames();
+
+ while (attrNameEnum.hasMoreElements())
+ {
+ Object key = attrNameEnum.nextElement();
+ Object value = attrSet.getAttribute(key);
+
+ writeRaw(" " + key + "=\"" + value + "\"");
+ writeRaw(" " + key.getClass().toString() + "=\""
+ + value.getClass().toString() + "\"");
+ } // while(attrNameEnum.hasMoreElements())
+
+ } // private void writeAllAttributes(AttributeSet attrSet)
+ // throws IOException
+
+ /**
+ * Tests if the str contains any html entities.
+ *
+ * @param param_str the str to test
+ *
+ * @return <code>true</code> if it has a html entity
+ * <code>false</code> if it does not have a html entity
+ */
+ private boolean hasHtmlEntity(String param_str)
+ {
+ boolean ret_bool = false;
+
+ for (int i = 0; i < html_entity_char_arr.length; i++)
+ {
+ if (param_str.indexOf(html_entity_char_arr[i]) != -1)
+ {
+ ret_bool = true;
+ break;
+ } // if(param_str.indexOf(html_entity_char_arr[i]) != -1)
+ } // for(int i = 0; i < html_entity_char_arr.length; i++)
+
+ return ret_bool;
+ } // private boolean hasHtmlEntity(String param_str)
+
+ /**
+ * Tests if the char is a html entities.
+ *
+ * @param param_char the char to test
+ *
+ * @return <code>true</code> if it is a html entity
+ * <code>false</code> if it is not a html entity.
+ */
+ private boolean isCharHtmlEntity(char param_char)
+ {
+ boolean ret_bool = false;
+
+ for (int i = 0; i < html_entity_char_arr.length; i++)
+ {
+ if (param_char == html_entity_char_arr[i])
+ {
+ ret_bool = true;
+ break;
+ } // if(param_char == html_entity_char_arr[i])
+ } // for(int i = 0; i < html_entity_char_arr.length; i++)
+
+ return ret_bool;
+ } // private boolean hasHtmlEntity(String param_str)
+
+ /**
+ * Escape html entities.
+ *
+ * @param param_char the char to escape
+ *
+ * @return escaped html entity. Original char is returned as a str if is
+ * is not a html entity
+ */
+ private String escapeCharHtmlEntity(char param_char)
+ {
+ String ret_str = "" + param_char;
+
+ for (int i = 0; i < html_entity_char_arr.length; i++)
+ {
+ if (param_char == html_entity_char_arr[i])
+ {
+ ret_str = html_entity_escape_str_arr[i];
+ break;
+ } // if(param_char == html_entity_char_arr[i])
+ } // for(int i = 0; i < html_entity_char_arr.length; i++)
+
+ return ret_str;
+ } // private String escapeCharHtmlEntity(char param_char)
+
+} // public class HTMLWriter extends AbstractWriter \ No newline at end of file
diff --git a/javax/swing/text/html/ImageView.java b/javax/swing/text/html/ImageView.java
index 84b021070..ff0d3ea40 100644
--- a/javax/swing/text/html/ImageView.java
+++ b/javax/swing/text/html/ImageView.java
@@ -175,19 +175,22 @@ public class ImageView extends View
*/
public URL getImageURL()
{
- Object url = getAttributes().getAttribute(Attribute.SRC);
- if (url == null)
- return null;
-
- try
- {
- return new URL(url.toString());
- }
- catch (MalformedURLException e)
+ Element el = getElement();
+ String src = (String) el.getAttributes().getAttribute(Attribute.SRC);
+ URL url = null;
+ if (src != null)
{
- // The URL is malformed - no image.
- return null;
+ URL base = ((HTMLDocument) getDocument()).getBase();
+ try
+ {
+ url = new URL(base, src);
+ }
+ catch (MalformedURLException ex)
+ {
+ // Return null.
+ }
}
+ return url;
}
/**
diff --git a/javax/swing/text/html/StyleSheet.java b/javax/swing/text/html/StyleSheet.java
index 520076652..703a3864a 100644
--- a/javax/swing/text/html/StyleSheet.java
+++ b/javax/swing/text/html/StyleSheet.java
@@ -38,7 +38,6 @@ exception statement from your version. */
package javax.swing.text.html;
-import gnu.classpath.NotImplementedException;
import gnu.javax.swing.text.html.css.CSSColor;
import gnu.javax.swing.text.html.css.CSSParser;
import gnu.javax.swing.text.html.css.CSSParserCallback;
@@ -53,6 +52,7 @@ import java.awt.Graphics;
import java.io.IOException;
import java.io.Reader;
import java.io.Serializable;
+import java.io.StringReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
@@ -94,8 +94,10 @@ public class StyleSheet extends StyleContext
/**
* Parses CSS stylesheets using the parser in gnu/javax/swing/html/css.
+ *
+ * This is package private to avoid accessor methods.
*/
- private class CSSStyleSheetParserCallback
+ class CSSStyleSheetParserCallback
implements CSSParserCallback
{
/**
@@ -405,9 +407,20 @@ public class StyleSheet extends StyleContext
* @param rule - the rule to add to the sheet
*/
public void addRule(String rule)
- throws NotImplementedException
{
- // FIXME: Implement.
+ CSSStyleSheetParserCallback cb = new CSSStyleSheetParserCallback();
+ // FIXME: Handle ref.
+ StringReader in = new StringReader(rule);
+ CSSParser parser = new CSSParser(in, cb);
+ try
+ {
+ parser.parse();
+ }
+ catch (IOException ex)
+ {
+ // Shouldn't happen. And if, then we
+ assert false;
+ }
}
/**
diff --git a/native/plugin/gcjwebplugin.cc b/native/plugin/gcjwebplugin.cc
index 1202c4719..bb2bfa223 100644
--- a/native/plugin/gcjwebplugin.cc
+++ b/native/plugin/gcjwebplugin.cc
@@ -283,10 +283,6 @@ GCJ_New (NPMIMEType pluginType, NPP instance, uint16 mode,
goto cleanup_done;
}
- // Initialize threads (needed for mutexes).
- if (!g_thread_supported ())
- g_thread_init (NULL);
-
// data
plugin_data_new (&data);
if (data == NULL)
@@ -1686,6 +1682,11 @@ NP_Initialize (NPNetscapeFuncs* browserTable, NPPluginFuncs* pluginTable)
pluginTable->getvalue = NewNPP_GetValueProc (GCJ_GetValue);
initialized = true;
+
+ // Initialize threads (needed for mutexes).
+ if (!g_thread_supported ())
+ g_thread_init (NULL);
+
plugin_instance_mutex = g_mutex_new ();
PLUGIN_DEBUG ("NP_Initialize: using " APPLETVIEWER_EXECUTABLE ".");