From f3778f2f83882ed658901698e8d8723799df0d0d Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Fri, 8 Dec 2006 11:25:44 +0000 Subject: 2006-12-05 Roman Kennke * javax/swing/text/html/ImageView.java (imageUpdate): Use spans field to determine if the CSS width/height are set. Call safePreferenceChanged to protect view structure from threading issues. (spans): Made package private. (ImageView): Initialize loadOnDemand with false. (loadImage): Call Toolkit.prepareImage() to make sure we have our Observer registered. (safePreferenceChanged): New helper method. Calls preferenceChanged in a thread safe environment. 2006-12-05 Roman Kennke * NEWS: Add entry about improved HTML support. 2006-12-05 Roman Kennke * javax/swing/text/html/ImageView.java (ImageView): Initialize spans array here. (setPropertiesFromAttributes): Moved init of spans array to constructor. 2006-12-05 Roman Kennke * javax/swing/text/html/BlockView.java (painter): Made package visible. * javax/swing/text/html/StyleSheet.java (translateBorder): New helper method. (translateHTMLToCSS): Add mappings for border attributes. * javax/swing/text/html/TableView.java Made class subclass of BlockView to get CSS goodness. (CellView.rowSpan): New field. (CellView.setPropertiesFromAttributes): Fetch rowspan. (RowView.overlap): New field. (RowView.rowIndex): New field. (RowView.layoutMajorAxis): Skip overlapping cells. (RowView.layoutMinorAxis): Layout cells that span more than 1 row. (numColumns): New field. (tmpRect): New field. (TableView): Initialize tmpRect. (calculateColumnRequirements): Adjusted and fixed for multirows. (getAlignment): Overridden to center tables. (paint): Overridden to fix clipping. (getStyleSheet): Made protected. (layoutMajorAxis): Invalidate rows. (setPropertiesFromAttributes): Made protected and call super. (updateGrid): Update the overlapping information for multirows. 2006-12-05 Roman Kennke * javax/swing/text/html/HTMLEditorKit.java (HTMLFactory.create): Removed debug output. * javax/swing/text/html/InlineView.java (getBreakWeight): Likewise. * javax/swing/text/html/StyleSheet.java (addRule): Likewise. (ListPainter.paint): Removed debug output. 2006-12-06 Roman Kennke * javax/swing/text/html/BlockView.java (getAlignment): Align blocks horizontally by the superclass. * javax/swing/text/html/HTMLEditorKit.java (HTMLFactory.create): Replace equals comparison by == for efficiency. Add mapping for misplaced tr, td and th tags. Include object mapping. * javax/swing/text/html/TableView.java (RowView.replace): Invalidate grid early. (gridValid): Initialize with false. (create): Only create RowView and CellView for correctly placed tags. Avoid unnecessary casts. (getAlignment): Removed. (replace): Invalidate grid early. 2006-12-06 Roman Kennke * javax/swing/text/html/TableView.java (RowView.layoutMajorAxis): Check column index for invalid value. (updateGrid): Check column index for invalid value. 2006-12-06 Roman Kennke * javax/swing/JEditorPane.java (getStream): Buffer the stream for efficiency. (setPage): Don't scroll the view at this point. * javax/swing/plaf/basic/BasicTextUI.java (RootView.paint): Call RootView's setSize to get synchronization. (RootView.setSize): Synchronize to prevent race in layout code. * javax/swing/text/AbstractDocument.java (notifyListeners): New field. (fireChangedUpdate): Track notifyListener field. (fireRemoveUpdate): Track notifyListener field. (fireIndertUpdate): Track notifyListener field. (writeLock): Check notifyListener and throw IllegalStateException. * javax/swing/text/View.java (preferenceChanged): Create local var for better thread safety and more efficiency. 2006-12-06 Roman Kennke * examples/gnu/classpath/examples/icons/back.png, * examples/gnu/classpath/examples/icons/reload.png: New icons for the HTML browser. * examples/gnu/classpath/examples/swing/HtmlDemo.java (history): New field. Manages the browsing history. (HtmlDemo): Initialize history. (createContent): Set location and add history. Add toolbar. (createToolBar): New helper method. (main): Make default size bigger. * examples/gnu/classpath/examples/swing/frame1.html, * examples/gnu/classpath/examples/swing/frame2.html, * examples/gnu/classpath/examples/swing/frame3.html, * examples/gnu/classpath/examples/swing/frame4.html, * examples/gnu/classpath/examples/swing/frames.html, * examples/gnu/classpath/examples/swing/tables.html: New example pages. * examples/gnu/classpath/examples/swing/welcome.html Add a couple of links and new test pages. 2006-12-06 Roman Kennke * examples/gnu/classpath/examples/swing/Demo.java (getIcon): Made package private. * examples/gnu/classpath/examples/swing/HtmlDemo.java (hyperlinkUpdate): Convert URL to string. 2006-12-06 Roman Kennke * javax/swing/text/DefaultCaret.java (appear): Adjust visibility here. (setDotImpl): Don't adjust visibility here. (moveDotImpl): Don't adjust visibility here. 2006-12-06 Roman Kennke * javax/swing/text/html/FormView.java (SubmitThread.postData): Implemented. (SubmitThread.run): Pass data to postData(). (actionPerformed): Reset form when reset button is activated. (createComponent): Add support for select lists and comboboxes. Don't set value of text and password fields here, this is done now in HTMLDocument for consistency. (getElementFormData): Add support for fetching form data from select lists and comboboxes as well as textareas. (getSelectData): New helper method. Fetches form data from select boxes. (getTextAreaData): New helper method. Fetches form data from textareas. (resetForm): New helper method. Resets the entire form. * javax/swing/text/html/HTMLDocument.java (HTMLReader.FormAction.end): Handle SELECT and OPTION tags. (HTMLReader.FormAction.start): Handle SELECT and OPTION tags. (HTMLReader.FormAction.setModel): Initialize text and password values here. Also, use the resetable special models. Group radio buttons into ButtonGroup for exclusive selection. (HTMLReader.FormTagAction): New class. Handles FORM tags. (HTMLReader.buttonGroups): New field. (HTMLReader.numOptions): New field. (HTMLReader.option): New field. (HTMLReader.selectModel): New field. (HTMLReader.textAreaDocument): Make ResetablePlainDocument. (HTMLReader.handleText): Handle OPTION text. (HTMLReader.initTags): Map FORM tags to FormTagAction. (HTMLReader.textAreaContent): Set initial content. * javax/swing/text/html/Option.java (Option): Make copy of attribute set. Initialize selected state. (getValue): Fetch value from attribute set. * javax/swing/text/html/ResetableModel.java: New interface. * javax/swing/text/html/ResetablePlainDocument.java: New class. Supports resetting the state. * javax/swing/text/html/ResetableToggleButtonModel.java: Likewise. * javax/swing/text/html/SelectComboBoxModel.java: Likewise. * javax/swing/text/html/SelectListModel.java: Likewise. 2006-12-06 Roman Kennke * examples/gnu/classpath/examples/swing/BrowserEditorKit.java: New class. * examples/gnu/classpath/examples/swing/HtmlDemo.java (LoadActionListener): Call setPage() helper method. (createContent): Register tweaked editor kit. For FormSubmitEvents call submitForm(), otherwise setPage(). (postData): Helper method for posting form data. (setPage): Helper method for navigating to a new URL. (submitForm): Helper method for submitting a form. * examples/gnu/classpath/examples/swing/forms.html: Added text/password fields and select boxes. * examples/gnu/classpath/examples/swing/welcome.html: Fixed typo. 2006-12-07 Mark Wielaard * java/net/URL.java (URL(URL,String,URLStreamHandler,boolean)): New private constructor. (URL(URL,String,URLStreamHandler)): Call new constructor. (URL(URL,String)): Likewise. (URL(String)): Likewise. 2006-12-07 Mark Wielaard * javax/swing/JEditorPane.java (createEditorKitForContentType): Always load from system class loader. --- ChangeLog | 204 +++++++++++++++ NEWS | 1 + examples/gnu/classpath/examples/icons/back.png | Bin 0 -> 828 bytes examples/gnu/classpath/examples/icons/reload.png | Bin 0 -> 1324 bytes .../classpath/examples/swing/BrowserEditorKit.java | 57 ++++ examples/gnu/classpath/examples/swing/Demo.java | 2 +- .../gnu/classpath/examples/swing/HtmlDemo.java | 215 +++++++++++++-- examples/gnu/classpath/examples/swing/forms.html | 37 ++- examples/gnu/classpath/examples/swing/frame1.html | 41 +++ examples/gnu/classpath/examples/swing/frame2.html | 42 +++ examples/gnu/classpath/examples/swing/frame3.html | 42 +++ examples/gnu/classpath/examples/swing/frame4.html | 41 +++ examples/gnu/classpath/examples/swing/frames.html | 44 ++++ examples/gnu/classpath/examples/swing/tables.html | 66 +++++ examples/gnu/classpath/examples/swing/welcome.html | 17 +- java/net/URL.java | 32 ++- javax/swing/JEditorPane.java | 13 +- javax/swing/plaf/basic/BasicTextUI.java | 9 +- javax/swing/text/AbstractDocument.java | 53 +++- javax/swing/text/DefaultCaret.java | 11 +- javax/swing/text/View.java | 5 +- javax/swing/text/html/BlockView.java | 7 +- javax/swing/text/html/FormView.java | 184 ++++++++++--- javax/swing/text/html/HTMLDocument.java | 177 +++++++++++-- javax/swing/text/html/HTMLEditorKit.java | 60 +++-- javax/swing/text/html/ImageView.java | 65 ++++- javax/swing/text/html/InlineView.java | 5 +- javax/swing/text/html/Option.java | 12 +- javax/swing/text/html/ResetableModel.java | 50 ++++ javax/swing/text/html/ResetablePlainDocument.java | 82 ++++++ .../text/html/ResetableToggleButtonModel.java | 71 +++++ javax/swing/text/html/SelectComboBoxModel.java | 84 ++++++ javax/swing/text/html/SelectListModel.java | 106 ++++++++ javax/swing/text/html/StyleSheet.java | 38 ++- javax/swing/text/html/TableView.java | 291 +++++++++++++++------ 35 files changed, 1921 insertions(+), 243 deletions(-) create mode 100644 examples/gnu/classpath/examples/icons/back.png create mode 100644 examples/gnu/classpath/examples/icons/reload.png create mode 100644 examples/gnu/classpath/examples/swing/BrowserEditorKit.java create mode 100644 examples/gnu/classpath/examples/swing/frame1.html create mode 100644 examples/gnu/classpath/examples/swing/frame2.html create mode 100644 examples/gnu/classpath/examples/swing/frame3.html create mode 100644 examples/gnu/classpath/examples/swing/frame4.html create mode 100644 examples/gnu/classpath/examples/swing/frames.html create mode 100644 examples/gnu/classpath/examples/swing/tables.html create mode 100644 javax/swing/text/html/ResetableModel.java create mode 100644 javax/swing/text/html/ResetablePlainDocument.java create mode 100644 javax/swing/text/html/ResetableToggleButtonModel.java create mode 100644 javax/swing/text/html/SelectComboBoxModel.java create mode 100644 javax/swing/text/html/SelectListModel.java diff --git a/ChangeLog b/ChangeLog index db3fe40bc..fc1b5b9e5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,207 @@ +2006-12-05 Roman Kennke + + * javax/swing/text/html/ImageView.java + (imageUpdate): Use spans field to determine if the CSS width/height + are set. Call safePreferenceChanged to protect view structure + from threading issues. + (spans): Made package private. + (ImageView): Initialize loadOnDemand with false. + (loadImage): Call Toolkit.prepareImage() to make sure we have + our Observer registered. + (safePreferenceChanged): New helper method. Calls preferenceChanged + in a thread safe environment. + +2006-12-05 Roman Kennke + + * NEWS: Add entry about improved HTML support. + +2006-12-05 Roman Kennke + + * javax/swing/text/html/ImageView.java + (ImageView): Initialize spans array here. + (setPropertiesFromAttributes): Moved init of spans array to + constructor. + +2006-12-05 Roman Kennke + + * javax/swing/text/html/BlockView.java + (painter): Made package visible. + * javax/swing/text/html/StyleSheet.java + (translateBorder): New helper method. + (translateHTMLToCSS): Add mappings for border attributes. + * javax/swing/text/html/TableView.java + Made class subclass of BlockView to get CSS goodness. + (CellView.rowSpan): New field. + (CellView.setPropertiesFromAttributes): Fetch rowspan. + (RowView.overlap): New field. + (RowView.rowIndex): New field. + (RowView.layoutMajorAxis): Skip overlapping cells. + (RowView.layoutMinorAxis): Layout cells that span more than 1 row. + (numColumns): New field. + (tmpRect): New field. + (TableView): Initialize tmpRect. + (calculateColumnRequirements): Adjusted and fixed for multirows. + (getAlignment): Overridden to center tables. + (paint): Overridden to fix clipping. + (getStyleSheet): Made protected. + (layoutMajorAxis): Invalidate rows. + (setPropertiesFromAttributes): Made protected and call super. + (updateGrid): Update the overlapping information for multirows. + +2006-12-05 Roman Kennke + + * javax/swing/text/html/HTMLEditorKit.java + (HTMLFactory.create): Removed debug output. + * javax/swing/text/html/InlineView.java + (getBreakWeight): Likewise. + * javax/swing/text/html/StyleSheet.java + (addRule): Likewise. + (ListPainter.paint): Removed debug output. + +2006-12-06 Roman Kennke + + * javax/swing/text/html/BlockView.java + (getAlignment): Align blocks horizontally by the superclass. + * javax/swing/text/html/HTMLEditorKit.java + (HTMLFactory.create): Replace equals comparison by == for efficiency. + Add mapping for misplaced tr, td and th tags. Include object mapping. + * javax/swing/text/html/TableView.java + (RowView.replace): Invalidate grid early. + (gridValid): Initialize with false. + (create): Only create RowView and CellView for correctly placed + tags. Avoid unnecessary casts. + (getAlignment): Removed. + (replace): Invalidate grid early. + + +2006-12-06 Roman Kennke + + * javax/swing/text/html/TableView.java + (RowView.layoutMajorAxis): Check column index for invalid value. + (updateGrid): Check column index for invalid value. + +2006-12-06 Roman Kennke + + * javax/swing/JEditorPane.java + (getStream): Buffer the stream for efficiency. + (setPage): Don't scroll the view at this point. + * javax/swing/plaf/basic/BasicTextUI.java + (RootView.paint): Call RootView's setSize to get synchronization. + (RootView.setSize): Synchronize to prevent race in layout code. + * javax/swing/text/AbstractDocument.java + (notifyListeners): New field. + (fireChangedUpdate): Track notifyListener field. + (fireRemoveUpdate): Track notifyListener field. + (fireIndertUpdate): Track notifyListener field. + (writeLock): Check notifyListener and throw IllegalStateException. + * javax/swing/text/View.java + (preferenceChanged): Create local var for better thread safety and + more efficiency. + +2006-12-06 Roman Kennke + + * examples/gnu/classpath/examples/icons/back.png, + * examples/gnu/classpath/examples/icons/reload.png: + New icons for the HTML browser. + * examples/gnu/classpath/examples/swing/HtmlDemo.java + (history): New field. Manages the browsing history. + (HtmlDemo): Initialize history. + (createContent): Set location and add history. Add toolbar. + (createToolBar): New helper method. + (main): Make default size bigger. + * examples/gnu/classpath/examples/swing/frame1.html, + * examples/gnu/classpath/examples/swing/frame2.html, + * examples/gnu/classpath/examples/swing/frame3.html, + * examples/gnu/classpath/examples/swing/frame4.html, + * examples/gnu/classpath/examples/swing/frames.html, + * examples/gnu/classpath/examples/swing/tables.html: + New example pages. + * examples/gnu/classpath/examples/swing/welcome.html + Add a couple of links and new test pages. + +2006-12-06 Roman Kennke + + * examples/gnu/classpath/examples/swing/Demo.java + (getIcon): Made package private. + * examples/gnu/classpath/examples/swing/HtmlDemo.java + (hyperlinkUpdate): Convert URL to string. + +2006-12-06 Roman Kennke + + * javax/swing/text/DefaultCaret.java + (appear): Adjust visibility here. + (setDotImpl): Don't adjust visibility here. + (moveDotImpl): Don't adjust visibility here. + +2006-12-06 Roman Kennke + + * javax/swing/text/html/FormView.java + (SubmitThread.postData): Implemented. + (SubmitThread.run): Pass data to postData(). + (actionPerformed): Reset form when reset button is activated. + (createComponent): Add support for select lists and comboboxes. + Don't set value of text and password fields here, this is done + now in HTMLDocument for consistency. + (getElementFormData): Add support for fetching form data from + select lists and comboboxes as well as textareas. + (getSelectData): New helper method. Fetches form data from + select boxes. + (getTextAreaData): New helper method. Fetches form data from + textareas. + (resetForm): New helper method. Resets the entire form. + * javax/swing/text/html/HTMLDocument.java + (HTMLReader.FormAction.end): Handle SELECT and OPTION tags. + (HTMLReader.FormAction.start): Handle SELECT and OPTION tags. + (HTMLReader.FormAction.setModel): Initialize text and password + values here. Also, use the resetable special models. + Group radio buttons into ButtonGroup for exclusive selection. + (HTMLReader.FormTagAction): New class. Handles FORM tags. + (HTMLReader.buttonGroups): New field. + (HTMLReader.numOptions): New field. + (HTMLReader.option): New field. + (HTMLReader.selectModel): New field. + (HTMLReader.textAreaDocument): Make ResetablePlainDocument. + (HTMLReader.handleText): Handle OPTION text. + (HTMLReader.initTags): Map FORM tags to FormTagAction. + (HTMLReader.textAreaContent): Set initial content. + * javax/swing/text/html/Option.java + (Option): Make copy of attribute set. Initialize selected state. + (getValue): Fetch value from attribute set. + * javax/swing/text/html/ResetableModel.java: New interface. + * javax/swing/text/html/ResetablePlainDocument.java: New class. + Supports resetting the state. + * javax/swing/text/html/ResetableToggleButtonModel.java: Likewise. + * javax/swing/text/html/SelectComboBoxModel.java: Likewise. + * javax/swing/text/html/SelectListModel.java: Likewise. + +2006-12-06 Roman Kennke + + * examples/gnu/classpath/examples/swing/BrowserEditorKit.java: + New class. + * examples/gnu/classpath/examples/swing/HtmlDemo.java + (LoadActionListener): Call setPage() helper method. + (createContent): Register tweaked editor kit. For FormSubmitEvents + call submitForm(), otherwise setPage(). + (postData): Helper method for posting form data. + (setPage): Helper method for navigating to a new URL. + (submitForm): Helper method for submitting a form. + * examples/gnu/classpath/examples/swing/forms.html: + Added text/password fields and select boxes. + * examples/gnu/classpath/examples/swing/welcome.html: Fixed typo. + +2006-12-07 Mark Wielaard + + * java/net/URL.java (URL(URL,String,URLStreamHandler,boolean)): New + private constructor. + (URL(URL,String,URLStreamHandler)): Call new constructor. + (URL(URL,String)): Likewise. + (URL(String)): Likewise. + +2006-12-07 Mark Wielaard + + * javax/swing/JEditorPane.java (createEditorKitForContentType): + Always load from system class loader. + 2006-12-06 Ben Konrath Fixes PR 29853. diff --git a/NEWS b/NEWS index 8f24e6301..06c4a43b0 100644 --- a/NEWS +++ b/NEWS @@ -26,6 +26,7 @@ New in release 0.93 (UNRELEASED) natively. Blocking IO classes have been refactored to call non-blocking classes. Non-blocking accepts, connects, and scatter-gather IO should now be better supported. +* HTML support for Swing has been greatly enhanced. Runtime interface changes: diff --git a/examples/gnu/classpath/examples/icons/back.png b/examples/gnu/classpath/examples/icons/back.png new file mode 100644 index 000000000..d320f26c6 Binary files /dev/null and b/examples/gnu/classpath/examples/icons/back.png differ diff --git a/examples/gnu/classpath/examples/icons/reload.png b/examples/gnu/classpath/examples/icons/reload.png new file mode 100644 index 000000000..04c575002 Binary files /dev/null and b/examples/gnu/classpath/examples/icons/reload.png differ diff --git a/examples/gnu/classpath/examples/swing/BrowserEditorKit.java b/examples/gnu/classpath/examples/swing/BrowserEditorKit.java new file mode 100644 index 000000000..f61275e57 --- /dev/null +++ b/examples/gnu/classpath/examples/swing/BrowserEditorKit.java @@ -0,0 +1,57 @@ +/* BrowserEditorKit.java -- A tweaked editor kit for the browser + 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 gnu.classpath.examples.swing; + +import javax.swing.text.html.HTMLEditorKit; + +/** + * A tweaked editor kit for out browser. + */ +public class BrowserEditorKit + extends HTMLEditorKit +{ + public BrowserEditorKit() + { + super(); + // Turn off automatic form submission so that we can receive notification + // instead and can update out location field. + setAutoFormSubmission(false); + } +} + diff --git a/examples/gnu/classpath/examples/swing/Demo.java b/examples/gnu/classpath/examples/swing/Demo.java index 6570cdbad..3c7f0b887 100644 --- a/examples/gnu/classpath/examples/swing/Demo.java +++ b/examples/gnu/classpath/examples/swing/Demo.java @@ -66,7 +66,7 @@ public class Demo return getIcon("/gnu/classpath/examples/icons/big-" + s + ".png", s); } - private static Icon getIcon(String location, String name) + static Icon getIcon(String location, String name) { URL url = Demo.class.getResource(location); if (url == null) System.err.println("WARNING " + location + " not found."); diff --git a/examples/gnu/classpath/examples/swing/HtmlDemo.java b/examples/gnu/classpath/examples/swing/HtmlDemo.java index 4cbf3ce47..35a9df290 100644 --- a/examples/gnu/classpath/examples/swing/HtmlDemo.java +++ b/examples/gnu/classpath/examples/swing/HtmlDemo.java @@ -43,19 +43,28 @@ import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.net.MalformedURLException; import java.net.URL; +import java.net.URLConnection; +import java.util.LinkedList; import javax.swing.BoxLayout; +import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComponent; +import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.JTextPane; +import javax.swing.JToolBar; import javax.swing.SwingUtilities; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; +import javax.swing.text.html.FormSubmitEvent; /** * Parses and displays HTML content. @@ -74,11 +83,11 @@ public class HtmlDemo extends JPanel String urlStr = url.getText(); try { - html.setPage(url.getText()); + setPage(new URL(url.getText())); } - catch (IOException ex) + catch (MalformedURLException ex) { - System.err.println("exception while loading: " + ex); + // Do something more useful here. ex.printStackTrace(); } } @@ -98,10 +107,17 @@ public class HtmlDemo extends JPanel int n; + /** + * The browsing history. + * + * Package private to avoid accessor method. + */ + LinkedList history; + public HtmlDemo() { super(); - html.setContentType("text/html"); // not now. + history = new LinkedList(); createContent(); } @@ -115,23 +131,24 @@ public class HtmlDemo extends JPanel { setLayout(new BorderLayout()); + JEditorPane.registerEditorKitForContentType("text/html", + BrowserEditorKit.class.getName()); html.setEditable(false); html.addHyperlinkListener(new HyperlinkListener() { public void hyperlinkUpdate(HyperlinkEvent event) { - URL u = event.getURL(); - if (u != null) + if (event instanceof FormSubmitEvent) { - url.setText(u.toString()); - try - { - html.setPage(u); - } - catch (IOException ex) + submitForm((FormSubmitEvent) event); + } + else + { + URL u = event.getURL(); + if (u != null) { - ex.printStackTrace(); + setPage(u); } } } @@ -148,24 +165,93 @@ public class HtmlDemo extends JPanel JButton loadButton = new JButton("go"); urlPanel.add(loadButton); loadButton.addActionListener(action); - add(urlPanel, BorderLayout.NORTH); - add(scroller, BorderLayout.CENTER); + + // Setup control panel. + JToolBar controlPanel = createToolBar(); + JPanel browserPanel = new JPanel(); + browserPanel.setLayout(new BorderLayout()); + browserPanel.add(urlPanel, BorderLayout.NORTH); + browserPanel.add(scroller, BorderLayout.CENTER); + add(controlPanel, BorderLayout.NORTH); + add(browserPanel, BorderLayout.CENTER); // Load start page. - URL startpage = getClass().getResource("welcome.html"); try { + URL startpage = getClass().getResource("welcome.html"); html.setPage(startpage); url.setText(startpage.toString()); + history.addLast(startpage); } - catch (IOException ex) + catch (Exception ex) { - System.err.println("couldn't load page: " + startpage); + System.err.println("couldn't load page: "/* + startpage*/); + ex.printStackTrace(); } - - setPreferredSize(new Dimension(600, 400)); + setPreferredSize(new Dimension(800, 600)); } + + /** + * Creates the toolbar with the control buttons. + * + * @return the toolbar with the control buttons + */ + JToolBar createToolBar() + { + JToolBar tb = new JToolBar(); + Icon backIcon = Demo.getIcon("/gnu/classpath/examples/icons/back.png", + "back"); + JButton back = new JButton(backIcon); + back.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent ev) + { + if (history.size() > 1) + { + URL last = (URL) history.removeLast(); + last = (URL) history.getLast(); + url.setText(last.toString()); + try + { + html.setPage(last); + } + catch (IOException ex) + { + // Do something more useful. + ex.printStackTrace(); + } + } + } + }); + tb.add(back); + Icon reloadIcon = Demo.getIcon("/gnu/classpath/examples/icons/reload.png", + "reload"); + JButton reload = new JButton(reloadIcon); + reload.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent ev) + { + if (history.size() > 0) + { + URL last = (URL) history.getLast(); + url.setText(last.toString()); + try + { + html.setPage(last); + } + catch (IOException ex) + { + // Do something more useful. + ex.printStackTrace(); + } + } + } + }); + tb.add(reload); + return tb; + } + /** * The executable method to display the editable table. * @@ -182,12 +268,99 @@ public class HtmlDemo extends JPanel HtmlDemo demo = new HtmlDemo(); JFrame frame = new JFrame(); frame.getContentPane().add(demo); - frame.setSize(new Dimension(700, 480)); + frame.setSize(new Dimension(750, 480)); frame.setVisible(true); } }); } + /** + * Helper method to navigate to a new URL. + * + * @param u the new URL to navigate to + */ + void setPage(URL u) + { + try + { + url.setText(u.toString()); + html.setPage(u.toString()); + history.addLast(u); + } + catch (IOException ex) + { + // Do something more useful here. + ex.printStackTrace(); + } + } + + /** + * Submits a form when a FormSubmitEvent is received. The HTML API + * provides automatic form submit but when this is enabled we don't + * receive any notification and can't update our location field. + * + * @param ev the form submit event + */ + void submitForm(FormSubmitEvent ev) + { + URL url = ev.getURL(); + String data = ev.getData(); + FormSubmitEvent.MethodType method = ev.getMethod(); + if (method == FormSubmitEvent.MethodType.POST) + { + try + { + URLConnection conn = url.openConnection(); + postData(conn, data); + } + catch (IOException ex) + { + // Deal with this. + ex.printStackTrace(); + } + } + else + { + try + { + url = new URL(url.toString() + "?" + data); + } + catch (MalformedURLException ex) + { + ex.printStackTrace(); + } + } + setPage(url); + } + + /** + * Posts the form data for forms with HTTP POST method. + * + * @param conn the connection + * @param data the form data + */ + private void postData(URLConnection conn, String data) + { + conn.setDoOutput(true); + PrintWriter out = null; + try + { + out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream())); + out.print(data); + out.flush(); + } + catch (IOException ex) + { + // Deal with this! + ex.printStackTrace(); + } + finally + { + if (out != null) + out.close(); + } + } + /** * Returns a DemoFactory that creates a HtmlDemo. * diff --git a/examples/gnu/classpath/examples/swing/forms.html b/examples/gnu/classpath/examples/swing/forms.html index 2cfdb4bcc..010a94c93 100644 --- a/examples/gnu/classpath/examples/swing/forms.html +++ b/examples/gnu/classpath/examples/swing/forms.html @@ -41,6 +41,7 @@ exception statement from your version. --> HTML text styles +
Back to start page

Some form elements

Textarea

@@ -49,6 +50,12 @@ exception statement from your version. --> that has a size of 30 columns and 5 rows +

Input fields

+

+ + +

+

Buttons

@@ -58,12 +65,34 @@ exception statement from your version. -->

Checkboxes and Radiobuttons

- Check this! - Or this + Check this! + Or this +

+

+ A radio button + Another radio +

+

Select lists and combo boxes

+

+

- A radio button - Another radio +

+
\ No newline at end of file diff --git a/examples/gnu/classpath/examples/swing/frame1.html b/examples/gnu/classpath/examples/swing/frame1.html new file mode 100644 index 000000000..b9150592f --- /dev/null +++ b/examples/gnu/classpath/examples/swing/frame1.html @@ -0,0 +1,41 @@ + + + +

Top Left Frame

+ + diff --git a/examples/gnu/classpath/examples/swing/frame2.html b/examples/gnu/classpath/examples/swing/frame2.html new file mode 100644 index 000000000..9dbf33c5a --- /dev/null +++ b/examples/gnu/classpath/examples/swing/frame2.html @@ -0,0 +1,42 @@ + + + +

Top Right + Frame

+ + diff --git a/examples/gnu/classpath/examples/swing/frame3.html b/examples/gnu/classpath/examples/swing/frame3.html new file mode 100644 index 000000000..e677bd6a1 --- /dev/null +++ b/examples/gnu/classpath/examples/swing/frame3.html @@ -0,0 +1,42 @@ + + + +

Bottom Left Frame

+ + + diff --git a/examples/gnu/classpath/examples/swing/frame4.html b/examples/gnu/classpath/examples/swing/frame4.html new file mode 100644 index 000000000..1da53b101 --- /dev/null +++ b/examples/gnu/classpath/examples/swing/frame4.html @@ -0,0 +1,41 @@ + + + +

Bottom Left Frame

+ + diff --git a/examples/gnu/classpath/examples/swing/frames.html b/examples/gnu/classpath/examples/swing/frames.html new file mode 100644 index 000000000..e7e2bf87c --- /dev/null +++ b/examples/gnu/classpath/examples/swing/frames.html @@ -0,0 +1,44 @@ + + + + + + + + + \ No newline at end of file diff --git a/examples/gnu/classpath/examples/swing/tables.html b/examples/gnu/classpath/examples/swing/tables.html new file mode 100644 index 000000000..af908e1ab --- /dev/null +++ b/examples/gnu/classpath/examples/swing/tables.html @@ -0,0 +1,66 @@ + + + + + + HTML text styles + + +

Table examples

+

Table with grid and mixed rowspan/colspan

+ + + + + + + + + + + + + + + + + + + +
Spans two columnsSpans three rows
Spans two rowsThis is the center
This should be in the middle of row number 3
A small one cell boxSpans two x two cells
Another small one cell box
+ diff --git a/examples/gnu/classpath/examples/swing/welcome.html b/examples/gnu/classpath/examples/swing/welcome.html index 62fb51429..8bc987494 100644 --- a/examples/gnu/classpath/examples/swing/welcome.html +++ b/examples/gnu/classpath/examples/swing/welcome.html @@ -40,13 +40,24 @@ exception statement from your version. --> GNU Classpath HTML Browser - +

Welcome to GNU Classpath

-

These pages are here to demonstrate the HTML rendering capabilities - of GNU Classpath's Swing.

+

A couple of websites that you might want to try out

+ + +

Testpages

+

These few pages are here to demonstrate and test the HTML rendering + capabilities of GNU Classpath's Swing.

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