From: <ls...@us...> - 2006-12-09 18:47:59
|
Revision: 2883 http://jnode.svn.sourceforge.net/jnode/?rev=2883&view=rev Author: lsantha Date: 2006-12-09 10:47:57 -0800 (Sat, 09 Dec 2006) Log Message: ----------- Classpath patches. Modified Paths: -------------- trunk/core/src/classpath/javax/javax/swing/JEditorPane.java trunk/core/src/classpath/javax/javax/swing/JTextField.java trunk/core/src/classpath/javax/javax/swing/plaf/basic/BasicHTML.java trunk/core/src/classpath/javax/javax/swing/plaf/basic/BasicTextUI.java Modified: trunk/core/src/classpath/javax/javax/swing/JEditorPane.java =================================================================== --- trunk/core/src/classpath/javax/javax/swing/JEditorPane.java 2006-12-09 18:47:15 UTC (rev 2882) +++ trunk/core/src/classpath/javax/javax/swing/JEditorPane.java 2006-12-09 18:47:57 UTC (rev 2883) @@ -40,6 +40,8 @@ import java.awt.Container; import java.awt.Dimension; +import java.io.BufferedInputStream; +import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -47,6 +49,7 @@ import java.io.StringReader; import java.net.MalformedURLException; import java.net.URL; +import java.net.URLConnection; import java.util.HashMap; import javax.accessibility.AccessibleContext; @@ -56,6 +59,8 @@ import javax.accessibility.AccessibleText; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; +import javax.swing.plaf.TextUI; +import javax.swing.text.AbstractDocument; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultEditorKit; import javax.swing.text.Document; @@ -482,6 +487,34 @@ } /** + * Used to store a mapping for content-type to editor kit class. + */ + private static class EditorKitMapping + { + /** + * The classname of the editor kit. + */ + String className; + + /** + * The classloader with which the kit is to be loaded. + */ + ClassLoader classLoader; + + /** + * Creates a new EditorKitMapping object. + * + * @param cn the classname + * @param cl the classloader + */ + EditorKitMapping(String cn, ClassLoader cl) + { + className = cn; + classLoader = cl; + } + } + + /** * An EditorKit used for plain text. This is the default editor kit for * JEditorPanes. * @@ -505,19 +538,159 @@ } } + /** + * A special stream that can be cancelled. + */ + private class PageStream + extends FilterInputStream + { + /** + * True when the stream has been cancelled, false otherwise. + */ + private boolean cancelled; + + protected PageStream(InputStream in) + { + super(in); + cancelled = false; + } + + private void checkCancelled() + throws IOException + { + if (cancelled) + throw new IOException("Stream has been cancelled"); + } + + void cancel() + { + cancelled = true; + } + + public int read() + throws IOException + { + checkCancelled(); + return super.read(); + } + + public int read(byte[] b, int off, int len) + throws IOException + { + checkCancelled(); + return super.read(b, off, len); + } + + public long skip(long n) + throws IOException + { + checkCancelled(); + return super.skip(n); + } + + public int available() + throws IOException + { + checkCancelled(); + return super.available(); + } + + public void reset() + throws IOException + { + checkCancelled(); + super.reset(); + } + } + + /** + * The thread that loads documents asynchronously. + */ + private class PageLoader + implements Runnable + { + private Document doc; + private PageStream in; + private URL old; + URL page; + PageLoader(Document doc, InputStream in, URL old, URL page) + { + this.doc = doc; + this.in = new PageStream(in); + this.old = old; + this.page = page; + } + + public void run() + { + try + { + read(in, doc); + } + catch (IOException ex) + { + UIManager.getLookAndFeel().provideErrorFeedback(JEditorPane.this); + } + finally + { + if (SwingUtilities.isEventDispatchThread()) + firePropertyChange("page", old, page); + else + { + SwingUtilities.invokeLater(new Runnable() + { + public void run() + { + firePropertyChange("page", old, page); + } + }); + } + } + } + + void cancel() + { + in.cancel(); + } + } + private static final long serialVersionUID = 3140472492599046285L; - private URL page; private EditorKit editorKit; boolean focus_root; + /** + * Maps content-types to editor kit instances. + */ + static HashMap editorKits; + // A mapping between content types and registered EditorKit types static HashMap registerMap; + static + { + registerMap = new HashMap(); + editorKits = new HashMap(); + registerEditorKitForContentType("application/rtf", + "javax.swing.text.rtf.RTFEditorKit"); + registerEditorKitForContentType("text/plain", + "javax.swing.JEditorPane$PlainEditorKit"); + registerEditorKitForContentType("text/html", + "javax.swing.text.html.HTMLEditorKit"); + registerEditorKitForContentType("text/rtf", + "javax.swing.text.rtf.RTFEditorKit"); + + } + // A mapping between content types and used EditorKits HashMap editorMap; + /** + * The currently loading stream, if any. + */ + private PageLoader loader; + public JEditorPane() { init(); @@ -550,15 +723,6 @@ void init() { editorMap = new HashMap(); - registerMap = new HashMap(); - registerEditorKitForContentType("application/rtf", - "javax.swing.text.rtf.RTFEditorKit"); - registerEditorKitForContentType("text/plain", - "javax.swing.JEditorPane$PlainEditorKit"); - registerEditorKitForContentType("text/html", - "javax.swing.text.html.HTMLEditorKit"); - registerEditorKitForContentType("text/rtf", - "javax.swing.text.rtf.RTFEditorKit"); } protected EditorKit createDefaultEditorKit() @@ -578,21 +742,29 @@ */ public static EditorKit createEditorKitForContentType(String type) { - // TODO: Have to handle the case where a ClassLoader was specified - // when the EditorKit was registered - EditorKit e = null; - String className = (String) registerMap.get(type); - if (className != null) + // Try cached instance. + EditorKit e = (EditorKit) editorKits.get(type); + if (e == null) { + EditorKitMapping m = (EditorKitMapping) registerMap.get(type); + if (m != null) + { + String className = m.className; + ClassLoader loader = m.classLoader; try { - e = (EditorKit) Class.forName(className).newInstance(); + e = (EditorKit) loader.loadClass(className).newInstance(); } catch (Exception e2) { - // TODO: Not sure what to do here. + // The reference implementation returns null when class is not + // loadable or instantiatable. } } + // Cache this for later retrieval. + if (e != null) + editorKits.put(type, e); + } return e; } @@ -652,7 +824,9 @@ */ public static String getEditorKitClassNameForContentType(String type) { - return (String) registerMap.get(type); + EditorKitMapping m = (EditorKitMapping) registerMap.get(type); + String kitName = m != null ? m.className : null; + return kitName; } /** @@ -675,10 +849,14 @@ EditorKit e = (EditorKit) editorMap.get(type); // Then check to see if we can create one. if (e == null) + { e = createEditorKitForContentType(type); + if (e != null) + setEditorKitForContentType(type, e); + } // Otherwise default to PlainEditorKit. if (e == null) - e = new PlainEditorKit(); + e = createDefaultEditorKit(); return e; } @@ -695,10 +873,28 @@ public Dimension getPreferredSize() { Dimension pref = super.getPreferredSize(); - if (getScrollableTracksViewportWidth()) - pref.width = getUI().getMinimumSize(this).width; - if (getScrollableTracksViewportHeight()) - pref.height = getUI().getMinimumSize(this).height; + Container parent = getParent(); + if (parent instanceof JViewport) + { + JViewport vp = (JViewport) getParent(); + TextUI ui = getUI(); + Dimension min = null; + if (! getScrollableTracksViewportWidth()) + { + min = ui.getMinimumSize(this); + int vpWidth = vp.getWidth(); + if (vpWidth != 0 && vpWidth < min.width) + pref.width = min.width; + } + if (! getScrollableTracksViewportHeight()) + { + if (min == null) + min = ui.getMinimumSize(this); + int vpHeight = vp.getHeight(); + if (vpHeight != 0 && vpHeight < min.height) + pref.height = min.height; + } + } return pref; } @@ -716,9 +912,11 @@ // Tests show that this returns true when the parent is a JViewport // and has a height > minimum UI height. Container parent = getParent(); + int height = parent.getHeight(); + TextUI ui = getUI(); return parent instanceof JViewport - && parent.getHeight() >= getUI().getMinimumSize(this).height - && parent.getHeight() <= getUI().getMaximumSize(this).height; + && height >= ui.getMinimumSize(this).height + && height <= ui.getMaximumSize(this).height; } /** @@ -741,13 +939,19 @@ public URL getPage() { - return page; + return loader != null ? loader.page : null; } protected InputStream getStream(URL page) throws IOException { - return page.openStream(); + URLConnection conn = page.openConnection(); + // Try to detect the content type of the stream data. + String type = conn.getContentType(); + if (type != null) + setContentType(type); + InputStream stream = conn.getInputStream(); + return new BufferedInputStream(stream); } public String getText() @@ -778,10 +982,12 @@ EditorKit kit = getEditorKit(); if (kit instanceof HTMLEditorKit && desc instanceof HTMLDocument) { - Document doc = (Document) desc; + HTMLDocument doc = (HTMLDocument) desc; + setDocument(doc); try { - kit.read(in, doc, 0); + InputStreamReader reader = new InputStreamReader(in); + kit.read(reader, doc, 0); } catch (BadLocationException ex) { @@ -806,7 +1012,8 @@ public static void registerEditorKitForContentType(String type, String classname) { - registerMap.put(type, classname); + registerEditorKitForContentType(type, classname, + Thread.currentThread().getContextClassLoader()); } /** @@ -816,7 +1023,7 @@ String classname, ClassLoader loader) { - // TODO: Implement this properly. + registerMap.put(type, new EditorKitMapping(classname, loader)); } /** @@ -840,6 +1047,13 @@ public final void setContentType(String type) { + // Strip off content type parameters. + int paramIndex = type.indexOf(';'); + if (paramIndex > -1) + { + // TODO: Handle character encoding. + type = type.substring(0, paramIndex).trim(); + } if (editorKit != null && editorKit.getContentType().equals(type)) return; @@ -900,14 +1114,45 @@ if (page == null) throw new IOException("invalid url"); - try + URL old = getPage(); + // 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. + if (old == null || ! old.sameFile(page)) { - this.page = page; - getEditorKit().read(page.openStream(), getDocument(), 0); + InputStream in = getStream(page); + if (editorKit != null) + { + Document doc = editorKit.createDefaultDocument(); + doc.putProperty(Document.StreamDescriptionProperty, page); + + if (loader != null) + loader.cancel(); + loader = new PageLoader(doc, in, old, page); + + int prio = -1; + if (doc instanceof AbstractDocument) + { + AbstractDocument aDoc = (AbstractDocument) doc; + prio = aDoc.getAsynchronousLoadPriority(); + } + if (prio >= 0) + { + // Load asynchronously. + setDocument(doc); + Thread loadThread = new Thread(loader, + "JEditorPane.PageLoader"); + loadThread.setDaemon(true); + loadThread.setPriority(prio); + loadThread.start(); } - catch (BadLocationException e) + else { - // Ignored. '0' is always a valid offset. + // Load synchronously. + loader.run(); + setDocument(doc); + } + } } } Modified: trunk/core/src/classpath/javax/javax/swing/JTextField.java =================================================================== --- trunk/core/src/classpath/javax/javax/swing/JTextField.java 2006-12-09 18:47:15 UTC (rev 2882) +++ trunk/core/src/classpath/javax/javax/swing/JTextField.java 2006-12-09 18:47:57 UTC (rev 2883) @@ -270,7 +270,8 @@ */ protected void fireActionPerformed() { - ActionEvent event = new ActionEvent(this, 0, getText()); + ActionEvent event = new ActionEvent(this, 0, + actionCommand == null ? getText() : actionCommand); ActionListener[] listeners = getActionListeners(); for (int index = 0; index < listeners.length; ++index) Modified: trunk/core/src/classpath/javax/javax/swing/plaf/basic/BasicHTML.java =================================================================== --- trunk/core/src/classpath/javax/javax/swing/plaf/basic/BasicHTML.java 2006-12-09 18:47:15 UTC (rev 2882) +++ trunk/core/src/classpath/javax/javax/swing/plaf/basic/BasicHTML.java 2006-12-09 18:47:57 UTC (rev 2883) @@ -48,6 +48,7 @@ import javax.swing.JComponent; import javax.swing.SwingConstants; import javax.swing.event.DocumentEvent; +import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.EditorKit; @@ -355,6 +356,22 @@ { return document; } + + /** + * Overridden to return null, as a RootView has no attributes on its own. + */ + public AttributeSet getAttributes() + { + return null; + } + + /** + * Overridden to provide an element for the view. + */ + public Element getElement() + { + return view.getElement(); + } } /** Modified: trunk/core/src/classpath/javax/javax/swing/plaf/basic/BasicTextUI.java =================================================================== --- trunk/core/src/classpath/javax/javax/swing/plaf/basic/BasicTextUI.java 2006-12-09 18:47:15 UTC (rev 2882) +++ trunk/core/src/classpath/javax/javax/swing/plaf/basic/BasicTextUI.java 2006-12-09 18:47:57 UTC (rev 2883) @@ -38,6 +38,8 @@ package javax.swing.plaf.basic; +import gnu.classpath.SystemProperties; + import java.awt.Color; import java.awt.Container; import java.awt.Dimension; @@ -121,7 +123,141 @@ } } + private static class FocusHandler + implements FocusListener + { + public void focusGained(FocusEvent e) + { + // Nothing to do here. + } + public void focusLost(FocusEvent e) + { + JTextComponent textComponent = (JTextComponent) e.getComponent(); + // Integrates Swing text components with the system clipboard: + // The idea is that if one wants to copy text around X11-style + // (select text and middle-click in the target component) the focus + // will move to the new component which gives the old focus owner the + // possibility to paste its selection into the clipboard. + if (!e.isTemporary() + && textComponent.getSelectionStart() + != textComponent.getSelectionEnd()) + { + SecurityManager sm = System.getSecurityManager(); + try + { + if (sm != null) + sm.checkSystemClipboardAccess(); + + Clipboard cb = Toolkit.getDefaultToolkit().getSystemSelection(); + if (cb != null) + { + StringSelection selection = new StringSelection( + textComponent.getSelectedText()); + cb.setContents(selection, selection); + } + } + catch (SecurityException se) + { + // Not allowed to access the clipboard: Ignore and + // do not access it. + } + catch (HeadlessException he) + { + // There is no AWT: Ignore and do not access the + // clipboard. + } + catch (IllegalStateException ise) + { + // Clipboard is currently unavaible. + } + } + } + } + /** + * This FocusListener triggers repaints on focus shift. + */ + private static FocusListener focusListener; + + /** + * Receives notifications when properties of the text component change. + */ + private class Handler + implements PropertyChangeListener, DocumentListener + { + /** + * Notifies when a property of the text component changes. + * + * @param event the PropertyChangeEvent describing the change + */ + public void propertyChange(PropertyChangeEvent event) + { + if (event.getPropertyName().equals("document")) + { + // Document changed. + Object oldValue = event.getOldValue(); + if (oldValue != null) + { + Document oldDoc = (Document) oldValue; + oldDoc.removeDocumentListener(handler); + } + Object newValue = event.getNewValue(); + if (newValue != null) + { + Document newDoc = (Document) newValue; + newDoc.addDocumentListener(handler); + } + modelChanged(); + } + + BasicTextUI.this.propertyChange(event); + } + + /** + * Notification about a document change event. + * + * @param ev the DocumentEvent describing the change + */ + public void changedUpdate(DocumentEvent ev) + { + // Updates are forwarded to the View even if 'getVisibleEditorRect' + // method returns null. This means the View classes have to be + // aware of that possibility. + rootView.changedUpdate(ev, getVisibleEditorRect(), + rootView.getViewFactory()); + } + + /** + * Notification about a document insert event. + * + * @param ev the DocumentEvent describing the insertion + */ + public void insertUpdate(DocumentEvent ev) + { + // Updates are forwarded to the View even if 'getVisibleEditorRect' + // method returns null. This means the View classes have to be + // aware of that possibility. + rootView.insertUpdate(ev, getVisibleEditorRect(), + rootView.getViewFactory()); + } + + /** + * Notification about a document removal event. + * + * @param ev the DocumentEvent describing the removal + */ + public void removeUpdate(DocumentEvent ev) + { + // Updates are forwarded to the View even if 'getVisibleEditorRect' + // method returns null. This means the View classes have to be + // aware of that possibility. + rootView.removeUpdate(ev, getVisibleEditorRect(), + rootView.getViewFactory()); + } + + } + + /** * This view forms the root of the View hierarchy. However, it delegates * most calls to another View which is the real root of the hierarchy. * The purpose is to make sure that all Views in the hierarchy, including @@ -227,24 +363,13 @@ } /** - * Returns the preferred span along the specified <code>axis</code>. - * This is delegated to the real root view. - * - * @param axis the axis for which the preferred span is queried - * - * @return the preferred span along the axis + * 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 float getPreferredSpan(int axis) + public synchronized void setSize(float w, float h) { if (view != null) - return view.getPreferredSpan(axis); - - return Integer.MAX_VALUE; - } - - public void setSize(float w, float h) - { - if (view != null) view.setSize(w, h); } @@ -258,8 +383,8 @@ { if (view != null) { - Rectangle b = s.getBounds(); - view.setSize(b.width, b.height); + Rectangle b = s instanceof Rectangle ? (Rectangle) s : s.getBounds(); + setSize(b.width, b.height); view.paint(g, s); } } @@ -319,6 +444,7 @@ */ public void insertUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) { + if (view != null) view.insertUpdate(ev, shape, vf); } @@ -332,6 +458,7 @@ */ public void removeUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) { + if (view != null) view.removeUpdate(ev, shape, vf); } @@ -345,6 +472,7 @@ */ public void changedUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) { + if (view != null) view.changedUpdate(ev, shape, vf); } @@ -415,103 +543,60 @@ { return null; } - } /** - * Receives notifications when properties of the text component change. - */ - private class PropertyChangeHandler implements PropertyChangeListener - { - /** - * Notifies when a property of the text component changes. - * - * @param event the PropertyChangeEvent describing the change + * Overridden to forward to the view. */ - public void propertyChange(PropertyChangeEvent event) - { - if (event.getPropertyName().equals("document")) - { - // Document changed. - Object oldValue = event.getOldValue(); - if (oldValue != null) + public float getPreferredSpan(int axis) { - Document oldDoc = (Document) oldValue; - oldDoc.removeDocumentListener(documentHandler); - } - Object newValue = event.getNewValue(); - if (newValue != null) - { - Document newDoc = (Document) newValue; - newDoc.addDocumentListener(documentHandler); - } - modelChanged(); - } - - BasicTextUI.this.propertyChange(event); - } + // The RI returns 10 in the degenerate case. + float span = 10; + if (view != null) + span = view.getPreferredSpan(axis); + return span; } /** - * Listens for changes on the underlying model and forwards notifications - * to the View. This also updates the caret position of the text component. - * - * TODO: Maybe this should somehow be handled through EditorKits + * Overridden to forward to the real view. */ - class DocumentHandler implements DocumentListener - { - /** - * Notification about a document change event. - * - * @param ev the DocumentEvent describing the change - */ - public void changedUpdate(DocumentEvent ev) + public float getMinimumSpan(int axis) { - // Updates are forwarded to the View even if 'getVisibleEditorRect' - // method returns null. This means the View classes have to be - // aware of that possibility. - rootView.changedUpdate(ev, getVisibleEditorRect(), - rootView.getViewFactory()); + // The RI returns 10 in the degenerate case. + float span = 10; + if (view != null) + span = view.getMinimumSpan(axis); + return span; } /** - * Notification about a document insert event. - * - * @param ev the DocumentEvent describing the insertion + * Overridden to return Integer.MAX_VALUE. */ - public void insertUpdate(DocumentEvent ev) + public float getMaximumSpan(int axis) { - // Updates are forwarded to the View even if 'getVisibleEditorRect' - // method returns null. This means the View classes have to be - // aware of that possibility. - rootView.insertUpdate(ev, getVisibleEditorRect(), - rootView.getViewFactory()); + // The RI returns Integer.MAX_VALUE here, regardless of the real view's + // maximum size. + return Integer.MAX_VALUE; } + } /** - * Notification about a document removal event. - * - * @param ev the DocumentEvent describing the removal + * The EditorKit used by this TextUI. */ - public void removeUpdate(DocumentEvent ev) - { - // Updates are forwarded to the View even if 'getVisibleEditorRect' - // method returns null. This means the View classes have to be - // aware of that possibility. - rootView.removeUpdate(ev, getVisibleEditorRect(), - rootView.getViewFactory()); - } - } + private static EditorKit kit; /** - * The EditorKit used by this TextUI. + * The combined event handler for text components. + * + * This is package private to avoid accessor methods. */ - // FIXME: should probably be non-static. - static EditorKit kit = new DefaultEditorKit(); + Handler handler; /** * The root view. + * + * This is package private to avoid accessor methods. */ - RootView rootView = new RootView(); + RootView rootView; /** * The text component that we handle. @@ -519,14 +604,6 @@ JTextComponent textComponent; /** - * Receives notification when the model changes. - */ - private PropertyChangeHandler updateHandler = new PropertyChangeHandler(); - - /** The DocumentEvent handler. */ - DocumentHandler documentHandler = new DocumentHandler(); - - /** * Creates a new <code>BasicTextUI</code> instance. */ public BasicTextUI() @@ -573,17 +650,31 @@ public void installUI(final JComponent c) { textComponent = (JTextComponent) c; + + if (rootView == null) + rootView = new RootView(); + installDefaults(); - textComponent.addPropertyChangeListener(updateHandler); + installFixedDefaults(); + + // These listeners must be installed outside of installListeners(), + // because overriding installListeners() doesn't prevent installing + // these in the RI, but overriding isntallUI() does. + if (handler == null) + handler = new Handler(); + textComponent.addPropertyChangeListener(handler); Document doc = textComponent.getDocument(); if (doc == null) { + // The Handler takes care of installing the necessary listeners + // on the document here. doc = getEditorKit(textComponent).createDefaultDocument(); textComponent.setDocument(doc); } else { - doc.addDocumentListener(documentHandler); + // Must install the document listener. + doc.addDocumentListener(handler); modelChanged(); } @@ -601,7 +692,6 @@ LookAndFeel.installColorsAndFont(textComponent, prefix + ".background", prefix + ".foreground", prefix + ".font"); LookAndFeel.installBorder(textComponent, prefix + ".border"); - textComponent.setMargin(UIManager.getInsets(prefix + ".margin")); // Some additional text component only properties. Color color = textComponent.getCaretColor(); @@ -615,7 +705,7 @@ color = textComponent.getDisabledTextColor(); if (color == null || color instanceof UIResource) { - color = UIManager.getColor(prefix + ".inactiveBackground"); + color = UIManager.getColor(prefix + ".inactiveForeground"); textComponent.setDisabledTextColor(color); } color = textComponent.getSelectedTextColor(); @@ -638,6 +728,15 @@ textComponent.setMargin(margin); } + } + + /** + * Installs defaults that can't be overridden by overriding + * installDefaults(). + */ + private void installFixedDefaults() + { + String prefix = getPropertyPrefix(); Caret caret = textComponent.getCaret(); if (caret == null || caret instanceof UIResource) { @@ -653,64 +752,18 @@ } /** - * This FocusListener triggers repaints on focus shift. - */ - private FocusListener focuslistener = new FocusListener() { - public void focusGained(FocusEvent e) - { - textComponent.repaint(); - } - public void focusLost(FocusEvent e) - { - textComponent.repaint(); - - // Integrates Swing text components with the system clipboard: - // The idea is that if one wants to copy text around X11-style - // (select text and middle-click in the target component) the focus - // will move to the new component which gives the old focus owner the - // possibility to paste its selection into the clipboard. - if (!e.isTemporary() - && textComponent.getSelectionStart() - != textComponent.getSelectionEnd()) - { - SecurityManager sm = System.getSecurityManager(); - try - { - if (sm != null) - sm.checkSystemClipboardAccess(); - - Clipboard cb = Toolkit.getDefaultToolkit().getSystemSelection(); - if (cb != null) - { - StringSelection selection = new StringSelection( - textComponent.getSelectedText()); - cb.setContents(selection, selection); - } - } - catch (SecurityException se) - { - // Not allowed to access the clipboard: Ignore and - // do not access it. - } - catch (HeadlessException he) - { - // There is no AWT: Ignore and do not access the - // clipboard. - } - catch (IllegalStateException ise) - { - // Clipboard is currently unavaible. - } - } - } - }; - - /** * Install all listeners on the text component. */ protected void installListeners() { - textComponent.addFocusListener(focuslistener); + // + if (SystemProperties.getProperty("gnu.swing.text.no-xlike-clipboard") + == null) + { + if (focusListener == null) + focusListener = new FocusHandler(); + textComponent.addFocusListener(focusListener); + } } /** @@ -849,10 +902,12 @@ */ public void uninstallUI(final JComponent component) { - super.uninstallUI(component); + textComponent.removePropertyChangeListener(handler); + textComponent.getDocument().removeDocumentListener(handler); rootView.setView(null); uninstallDefaults(); + uninstallFixedDefaults(); uninstallListeners(); uninstallKeyboardActions(); @@ -865,17 +920,41 @@ */ protected void uninstallDefaults() { - // Do nothing here. + if (textComponent.getCaretColor() instanceof UIResource) + textComponent.setCaretColor(null); + if (textComponent.getSelectionColor() instanceof UIResource) + textComponent.setSelectionColor(null); + if (textComponent.getDisabledTextColor() instanceof UIResource) + textComponent.setDisabledTextColor(null); + if (textComponent.getSelectedTextColor() instanceof UIResource) + textComponent.setSelectedTextColor(null); + LookAndFeel.uninstallBorder(textComponent); + if (textComponent.getMargin() instanceof UIResource) + textComponent.setMargin(null); } /** + * Uninstalls additional fixed defaults that were installed + * by installFixedDefaults(). + */ + private void uninstallFixedDefaults() + { + if (textComponent.getCaret() instanceof UIResource) + textComponent.setCaret(null); + if (textComponent.getHighlighter() instanceof UIResource) + textComponent.setHighlighter(null); + } + + /** * Uninstalls all listeners that have previously been installed by * this UI. */ protected void uninstallListeners() { - textComponent.removeFocusListener(focuslistener); - textComponent.getDocument().removeDocumentListener(documentHandler); + // Don't nullify the focusListener field, as it is static and shared + // between components. + if (focusListener != null) + textComponent.removeFocusListener(focusListener); } /** @@ -909,14 +988,33 @@ { Dimension d = c.getSize(); Insets i = c.getInsets(); + // We need to lock here, since we require the view hierarchy to _not_ + // change in between. + float w; + float h; + Document doc = textComponent.getDocument(); + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readLock(); + try + { if (d.width > (i.left + i.right) && d.height > (i.top + i.bottom)) { rootView.setSize(d.width - i.left - i.right, d.height - i.top - i.bottom); } - float w = rootView.getPreferredSpan(View.X_AXIS); - float h = rootView.getPreferredSpan(View.Y_AXIS); - + else + { + // Not laid out yet. Force some pseudo size. + rootView.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE); + } + w = rootView.getPreferredSpan(View.X_AXIS); + h = rootView.getPreferredSpan(View.Y_AXIS); + } + finally + { + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readUnlock(); + } Dimension size = new Dimension((int) w + i.left + i.right, (int) h + i.top + i.bottom); return size; @@ -933,8 +1031,27 @@ */ public Dimension getMaximumSize(JComponent c) { - // Sun's implementation returns Integer.MAX_VALUE here, so do we. - return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); + Dimension d = new Dimension(); + Insets i = c.getInsets(); + Document doc = textComponent.getDocument(); + // We need to lock here, since we require the view hierarchy to _not_ + // change in between. + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readLock(); + try + { + // Check for overflow here. + d.width = (int) Math.min((long) rootView.getMaximumSpan(View.X_AXIS) + + i.left + i.right, Integer.MAX_VALUE); + d.height = (int) Math.min((long) rootView.getMaximumSpan(View.Y_AXIS) + + i.top + i.bottom, Integer.MAX_VALUE); + } + finally + { + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readUnlock(); + } + return d; } /** @@ -945,8 +1062,26 @@ */ public Dimension getMinimumSize(JComponent c) { + Dimension d = new Dimension(); + Document doc = textComponent.getDocument(); + // We need to lock here, since we require the view hierarchy to _not_ + // change in between. + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readLock(); + try + { + d.width = (int) rootView.getMinimumSpan(View.X_AXIS); + d.height = (int) rootView.getMinimumSpan(View.Y_AXIS); + } + finally + { + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readUnlock(); + } Insets i = c.getInsets(); - return new Dimension(i.left + i.right, i.top + i.bottom); + d.width += i.left + i.right; + d.height += i.top + i.bottom; + return d; } /** @@ -967,7 +1102,6 @@ AbstractDocument aDoc = (AbstractDocument) doc; aDoc.readLock(); } - paintSafely(g); } finally @@ -1017,7 +1151,6 @@ g.setColor(oldColor); } - rootView.paint(g, getVisibleEditorRect()); if (caret != null && textComponent.hasFocus()) @@ -1125,6 +1258,8 @@ */ public EditorKit getEditorKit(JTextComponent t) { + if (kit == null) + kit = new DefaultEditorKit(); return kit; } @@ -1147,13 +1282,27 @@ Position.Bias[] biasRet) throws BadLocationException { - // A comment in the spec of NavigationFilter.getNextVisualPositionFrom() - // suggests that this method should be implemented by forwarding the call - // the root view. - return rootView.getNextVisualPositionFrom(pos, b, - getVisibleEditorRect(), + int offset = -1; + Document doc = textComponent.getDocument(); + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readLock(); + try + { + Rectangle alloc = getVisibleEditorRect(); + if (alloc != null) + { + rootView.setSize(alloc.width, alloc.height); + offset = rootView.getNextVisualPositionFrom(pos, b, alloc, direction, biasRet); } + } + finally + { + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readUnlock(); + } + return offset; + } /** * Returns the root {@link View} of a text component. @@ -1262,7 +1411,25 @@ */ public int viewToModel(JTextComponent t, Point pt, Position.Bias[] biasReturn) { - return rootView.viewToModel(pt.x, pt.y, getVisibleEditorRect(), biasReturn); + int offset = -1; + Document doc = textComponent.getDocument(); + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readLock(); + try + { + Rectangle alloc = getVisibleEditorRect(); + if (alloc != null) + { + rootView.setSize(alloc.width, alloc.height); + offset = rootView.viewToModel(pt.x, pt.y, alloc, biasReturn); + } + } + finally + { + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readUnlock(); + } + return offset; } /** @@ -1294,6 +1461,11 @@ } /** + * A cached Insets instance to be reused below. + */ + private Insets cachedInsets; + + /** * Returns the allocation to give the root view. * * @return the allocation to give the root view @@ -1311,7 +1483,7 @@ if (width <= 0 || height <= 0) return null; - Insets insets = textComponent.getInsets(); + Insets insets = textComponent.getInsets(cachedInsets); return new Rectangle(insets.left, insets.top, width - insets.left - insets.right, height - insets.top - insets.bottom); @@ -1362,4 +1534,5 @@ { // The default implementation does nothing. } + } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |