Source Code Cross Referenced for ImageView.java in  » 6.0-JDK-Core » swing » javax » swing » text » html » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » swing » javax.swing.text.html 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001        /*
0002         * Copyright 1997-2005 Sun Microsystems, Inc.  All Rights Reserved.
0003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004         *
0005         * This code is free software; you can redistribute it and/or modify it
0006         * under the terms of the GNU General Public License version 2 only, as
0007         * published by the Free Software Foundation.  Sun designates this
0008         * particular file as subject to the "Classpath" exception as provided
0009         * by Sun in the LICENSE file that accompanied this code.
0010         *
0011         * This code is distributed in the hope that it will be useful, but WITHOUT
0012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014         * version 2 for more details (a copy is included in the LICENSE file that
0015         * accompanied this code).
0016         *
0017         * You should have received a copy of the GNU General Public License version
0018         * 2 along with this work; if not, write to the Free Software Foundation,
0019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020         *
0021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022         * CA 95054 USA or visit www.sun.com if you need additional information or
0023         * have any questions.
0024         */
0025        package javax.swing.text.html;
0026
0027        import java.awt.*;
0028        import java.awt.event.*;
0029        import java.awt.image.ImageObserver;
0030        import java.io.*;
0031        import java.net.*;
0032        import java.util.Dictionary;
0033        import javax.swing.*;
0034        import javax.swing.text.*;
0035        import javax.swing.event.*;
0036
0037        /**
0038         * View of an Image, intended to support the HTML <IMG> tag.
0039         * Supports scaling via the HEIGHT and WIDTH attributes of the tag.
0040         * If the image is unable to be loaded any text specified via the
0041         * <code>ALT</code> attribute will be rendered.
0042         * <p>
0043         * While this class has been part of swing for a while now, it is public
0044         * as of 1.4.
0045         *
0046         * @author  Scott Violet
0047         * @version 1.64 05/05/07
0048         * @see IconView
0049         * @since 1.4
0050         */
0051        public class ImageView extends View {
0052            /**
0053             * If true, when some of the bits are available a repaint is done.
0054             * <p>
0055             * This is set to false as swing does not offer a repaint that takes a
0056             * delay. If this were true, a bunch of immediate repaints would get
0057             * generated that end up significantly delaying the loading of the image
0058             * (or anything else going on for that matter).
0059             */
0060            private static boolean sIsInc = false;
0061            /**
0062             * Repaint delay when some of the bits are available.
0063             */
0064            private static int sIncRate = 100;
0065            /**
0066             * Property name for pending image icon
0067             */
0068            private static final String PENDING_IMAGE = "html.pendingImage";
0069            /**
0070             * Property name for missing image icon
0071             */
0072            private static final String MISSING_IMAGE = "html.missingImage";
0073
0074            /**
0075             * Document property for image cache.
0076             */
0077            private static final String IMAGE_CACHE_PROPERTY = "imageCache";
0078
0079            // Height/width to use before we know the real size, these should at least
0080            // the size of <code>sMissingImageIcon</code> and
0081            // <code>sPendingImageIcon</code>
0082            private static final int DEFAULT_WIDTH = 38;
0083            private static final int DEFAULT_HEIGHT = 38;
0084
0085            /**
0086             * Default border to use if one is not specified.
0087             */
0088            private static final int DEFAULT_BORDER = 2;
0089
0090            // Bitmask values
0091            private static final int LOADING_FLAG = 1;
0092            private static final int LINK_FLAG = 2;
0093            private static final int WIDTH_FLAG = 4;
0094            private static final int HEIGHT_FLAG = 8;
0095            private static final int RELOAD_FLAG = 16;
0096            private static final int RELOAD_IMAGE_FLAG = 32;
0097            private static final int SYNC_LOAD_FLAG = 64;
0098
0099            private AttributeSet attr;
0100            private Image image;
0101            private int width;
0102            private int height;
0103            /** Bitmask containing some of the above bitmask values. Because the
0104             * image loading notification can happen on another thread access to
0105             * this is synchronized (at least for modifying it). */
0106            private int state;
0107            private Container container;
0108            private Rectangle fBounds;
0109            private Color borderColor;
0110            // Size of the border, the insets contains this valid. For example, if
0111            // the HSPACE attribute was 4 and BORDER 2, leftInset would be 6.
0112            private short borderSize;
0113            // Insets, obtained from the painter.
0114            private short leftInset;
0115            private short rightInset;
0116            private short topInset;
0117            private short bottomInset;
0118            /**
0119             * We don't directly implement ImageObserver, instead we use an instance
0120             * that calls back to us.
0121             */
0122            private ImageObserver imageObserver;
0123            /**
0124             * Used for alt text. Will be non-null if the image couldn't be found,
0125             * and there is valid alt text.
0126             */
0127            private View altView;
0128            /** Alignment along the vertical (Y) axis. */
0129            private float vAlign;
0130
0131            /**
0132             * Creates a new view that represents an IMG element.
0133             *
0134             * @param elem the element to create a view for
0135             */
0136            public ImageView(Element elem) {
0137                super (elem);
0138                fBounds = new Rectangle();
0139                imageObserver = new ImageHandler();
0140                state = RELOAD_FLAG | RELOAD_IMAGE_FLAG;
0141            }
0142
0143            /**
0144             * Returns the text to display if the image can't be loaded. This is
0145             * obtained from the Elements attribute set with the attribute name
0146             * <code>HTML.Attribute.ALT</code>.
0147             */
0148            public String getAltText() {
0149                return (String) getElement().getAttributes().getAttribute(
0150                        HTML.Attribute.ALT);
0151            }
0152
0153            /**
0154             * Return a URL for the image source, 
0155             * or null if it could not be determined.
0156             */
0157            public URL getImageURL() {
0158                String src = (String) getElement().getAttributes()
0159                        .getAttribute(HTML.Attribute.SRC);
0160                if (src == null) {
0161                    return null;
0162                }
0163
0164                URL reference = ((HTMLDocument) getDocument()).getBase();
0165                try {
0166                    URL u = new URL(reference, src);
0167                    return u;
0168                } catch (MalformedURLException e) {
0169                    return null;
0170                }
0171            }
0172
0173            /**
0174             * Returns the icon to use if the image couldn't be found.
0175             */
0176            public Icon getNoImageIcon() {
0177                return (Icon) UIManager.getLookAndFeelDefaults().get(
0178                        MISSING_IMAGE);
0179            }
0180
0181            /**
0182             * Returns the icon to use while in the process of loading the image.
0183             */
0184            public Icon getLoadingImageIcon() {
0185                return (Icon) UIManager.getLookAndFeelDefaults().get(
0186                        PENDING_IMAGE);
0187            }
0188
0189            /**
0190             * Returns the image to render.
0191             */
0192            public Image getImage() {
0193                sync();
0194                return image;
0195            }
0196
0197            /**
0198             * Sets how the image is loaded. If <code>newValue</code> is true,
0199             * the image we be loaded when first asked for, otherwise it will
0200             * be loaded asynchronously. The default is to not load synchronously,
0201             * that is to load the image asynchronously.
0202             */
0203            public void setLoadsSynchronously(boolean newValue) {
0204                synchronized (this ) {
0205                    if (newValue) {
0206                        state |= SYNC_LOAD_FLAG;
0207                    } else {
0208                        state = (state | SYNC_LOAD_FLAG) ^ SYNC_LOAD_FLAG;
0209                    }
0210                }
0211            }
0212
0213            /**
0214             * Returns true if the image should be loaded when first asked for.
0215             */
0216            public boolean getLoadsSynchronously() {
0217                return ((state & SYNC_LOAD_FLAG) != 0);
0218            }
0219
0220            /**
0221             * Convenience method to get the StyleSheet.
0222             */
0223            protected StyleSheet getStyleSheet() {
0224                HTMLDocument doc = (HTMLDocument) getDocument();
0225                return doc.getStyleSheet();
0226            }
0227
0228            /**
0229             * Fetches the attributes to use when rendering.  This is
0230             * implemented to multiplex the attributes specified in the
0231             * model with a StyleSheet.
0232             */
0233            public AttributeSet getAttributes() {
0234                sync();
0235                return attr;
0236            }
0237
0238            /**
0239             * For images the tooltip text comes from text specified with the
0240             * <code>ALT</code> attribute. This is overriden to return
0241             * <code>getAltText</code>.
0242             *
0243             * @see JTextComponent#getToolTipText
0244             */
0245            public String getToolTipText(float x, float y, Shape allocation) {
0246                return getAltText();
0247            }
0248
0249            /**
0250             * Update any cached values that come from attributes.
0251             */
0252            protected void setPropertiesFromAttributes() {
0253                StyleSheet sheet = getStyleSheet();
0254                this .attr = sheet.getViewAttributes(this );
0255
0256                // Gutters
0257                borderSize = (short) getIntAttr(HTML.Attribute.BORDER,
0258                        isLink() ? DEFAULT_BORDER : 0);
0259
0260                leftInset = rightInset = (short) (getIntAttr(
0261                        HTML.Attribute.HSPACE, 0) + borderSize);
0262                topInset = bottomInset = (short) (getIntAttr(
0263                        HTML.Attribute.VSPACE, 0) + borderSize);
0264
0265                borderColor = ((StyledDocument) getDocument())
0266                        .getForeground(getAttributes());
0267
0268                AttributeSet attr = getElement().getAttributes();
0269
0270                // Alignment.
0271                // PENDING: This needs to be changed to support the CSS versions
0272                // when conversion from ALIGN to VERTICAL_ALIGN is complete.
0273                Object alignment = attr.getAttribute(HTML.Attribute.ALIGN);
0274
0275                vAlign = 1.0f;
0276                if (alignment != null) {
0277                    alignment = alignment.toString();
0278                    if ("top".equals(alignment)) {
0279                        vAlign = 0f;
0280                    } else if ("middle".equals(alignment)) {
0281                        vAlign = .5f;
0282                    }
0283                }
0284
0285                AttributeSet anchorAttr = (AttributeSet) attr
0286                        .getAttribute(HTML.Tag.A);
0287                if (anchorAttr != null
0288                        && anchorAttr.isDefined(HTML.Attribute.HREF)) {
0289                    synchronized (this ) {
0290                        state |= LINK_FLAG;
0291                    }
0292                } else {
0293                    synchronized (this ) {
0294                        state = (state | LINK_FLAG) ^ LINK_FLAG;
0295                    }
0296                }
0297            }
0298
0299            /**
0300             * Establishes the parent view for this view.
0301             * Seize this moment to cache the AWT Container I'm in.
0302             */
0303            public void setParent(View parent) {
0304                View oldParent = getParent();
0305                super .setParent(parent);
0306                container = (parent != null) ? getContainer() : null;
0307                if (oldParent != parent) {
0308                    synchronized (this ) {
0309                        state |= RELOAD_FLAG;
0310                    }
0311                }
0312            }
0313
0314            /**
0315             * Invoked when the Elements attributes have changed. Recreates the image.
0316             */
0317            public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
0318                super .changedUpdate(e, a, f);
0319
0320                synchronized (this ) {
0321                    state |= RELOAD_FLAG | RELOAD_IMAGE_FLAG;
0322                }
0323
0324                // Assume the worst.
0325                preferenceChanged(null, true, true);
0326            }
0327
0328            /**
0329             * Paints the View.
0330             *
0331             * @param g the rendering surface to use
0332             * @param a the allocated region to render into
0333             * @see View#paint
0334             */
0335            public void paint(Graphics g, Shape a) {
0336                sync();
0337
0338                Rectangle rect = (a instanceof  Rectangle) ? (Rectangle) a : a
0339                        .getBounds();
0340
0341                Image image = getImage();
0342                Rectangle clip = g.getClipBounds();
0343
0344                fBounds.setBounds(rect);
0345                paintHighlights(g, a);
0346                paintBorder(g, rect);
0347                if (clip != null) {
0348                    g.clipRect(rect.x + leftInset, rect.y + topInset,
0349                            rect.width - leftInset - rightInset, rect.height
0350                                    - topInset - bottomInset);
0351                }
0352                if (image != null) {
0353                    if (!hasPixels(image)) {
0354                        // No pixels yet, use the default
0355                        Icon icon = (image == null) ? getNoImageIcon()
0356                                : getLoadingImageIcon();
0357
0358                        if (icon != null) {
0359                            icon.paintIcon(getContainer(), g, rect.x
0360                                    + leftInset, rect.y + topInset);
0361                        }
0362                    } else {
0363                        // Draw the image
0364                        g.drawImage(image, rect.x + leftInset, rect.y
0365                                + topInset, width, height, imageObserver);
0366                    }
0367                } else {
0368                    Icon icon = getNoImageIcon();
0369
0370                    if (icon != null) {
0371                        icon.paintIcon(getContainer(), g, rect.x + leftInset,
0372                                rect.y + topInset);
0373                    }
0374                    View view = getAltView();
0375                    // Paint the view representing the alt text, if its non-null
0376                    if (view != null
0377                            && ((state & WIDTH_FLAG) == 0 || width > DEFAULT_WIDTH)) {
0378                        // Assume layout along the y direction
0379                        Rectangle altRect = new Rectangle(rect.x + leftInset
0380                                + DEFAULT_WIDTH, rect.y + topInset, rect.width
0381                                - leftInset - rightInset - DEFAULT_WIDTH,
0382                                rect.height - topInset - bottomInset);
0383
0384                        view.paint(g, altRect);
0385                    }
0386                }
0387                if (clip != null) {
0388                    // Reset clip.
0389                    g.setClip(clip.x, clip.y, clip.width, clip.height);
0390                }
0391            }
0392
0393            private void paintHighlights(Graphics g, Shape shape) {
0394                if (container instanceof  JTextComponent) {
0395                    JTextComponent tc = (JTextComponent) container;
0396                    Highlighter h = tc.getHighlighter();
0397                    if (h instanceof  LayeredHighlighter) {
0398                        ((LayeredHighlighter) h).paintLayeredHighlights(g,
0399                                getStartOffset(), getEndOffset(), shape, tc,
0400                                this );
0401                    }
0402                }
0403            }
0404
0405            private void paintBorder(Graphics g, Rectangle rect) {
0406                Color color = borderColor;
0407
0408                if ((borderSize > 0 || image == null) && color != null) {
0409                    int xOffset = leftInset - borderSize;
0410                    int yOffset = topInset - borderSize;
0411                    g.setColor(color);
0412                    int n = (image == null) ? 1 : borderSize;
0413                    for (int counter = 0; counter < n; counter++) {
0414                        g.drawRect(rect.x + xOffset + counter, rect.y + yOffset
0415                                + counter, rect.width - counter - counter
0416                                - xOffset - xOffset - 1, rect.height - counter
0417                                - counter - yOffset - yOffset - 1);
0418                    }
0419                }
0420            }
0421
0422            /**
0423             * Determines the preferred span for this view along an
0424             * axis.
0425             *
0426             * @param axis may be either X_AXIS or Y_AXIS
0427             * @return   the span the view would like to be rendered into;
0428             *           typically the view is told to render into the span
0429             *           that is returned, although there is no guarantee;  
0430             *           the parent may choose to resize or break the view
0431             */
0432            public float getPreferredSpan(int axis) {
0433                sync();
0434
0435                // If the attributes specified a width/height, always use it!
0436                if (axis == View.X_AXIS && (state & WIDTH_FLAG) == WIDTH_FLAG) {
0437                    getPreferredSpanFromAltView(axis);
0438                    return width + leftInset + rightInset;
0439                }
0440                if (axis == View.Y_AXIS && (state & HEIGHT_FLAG) == HEIGHT_FLAG) {
0441                    getPreferredSpanFromAltView(axis);
0442                    return height + topInset + bottomInset;
0443                }
0444
0445                Image image = getImage();
0446
0447                if (image != null) {
0448                    switch (axis) {
0449                    case View.X_AXIS:
0450                        return width + leftInset + rightInset;
0451                    case View.Y_AXIS:
0452                        return height + topInset + bottomInset;
0453                    default:
0454                        throw new IllegalArgumentException("Invalid axis: "
0455                                + axis);
0456                    }
0457                } else {
0458                    View view = getAltView();
0459                    float retValue = 0f;
0460
0461                    if (view != null) {
0462                        retValue = view.getPreferredSpan(axis);
0463                    }
0464                    switch (axis) {
0465                    case View.X_AXIS:
0466                        return retValue
0467                                + (float) (width + leftInset + rightInset);
0468                    case View.Y_AXIS:
0469                        return retValue
0470                                + (float) (height + topInset + bottomInset);
0471                    default:
0472                        throw new IllegalArgumentException("Invalid axis: "
0473                                + axis);
0474                    }
0475                }
0476            }
0477
0478            /**
0479             * Determines the desired alignment for this view along an
0480             * axis.  This is implemented to give the alignment to the
0481             * bottom of the icon along the y axis, and the default
0482             * along the x axis.
0483             *
0484             * @param axis may be either X_AXIS or Y_AXIS
0485             * @return the desired alignment; this should be a value
0486             *   between 0.0 and 1.0 where 0 indicates alignment at the
0487             *   origin and 1.0 indicates alignment to the full span
0488             *   away from the origin; an alignment of 0.5 would be the
0489             *   center of the view
0490             */
0491            public float getAlignment(int axis) {
0492                switch (axis) {
0493                case View.Y_AXIS:
0494                    return vAlign;
0495                default:
0496                    return super .getAlignment(axis);
0497                }
0498            }
0499
0500            /**
0501             * Provides a mapping from the document model coordinate space
0502             * to the coordinate space of the view mapped to it.
0503             *
0504             * @param pos the position to convert
0505             * @param a the allocated region to render into
0506             * @return the bounding box of the given position
0507             * @exception BadLocationException  if the given position does not represent a
0508             *   valid location in the associated document
0509             * @see View#modelToView
0510             */
0511            public Shape modelToView(int pos, Shape a, Position.Bias b)
0512                    throws BadLocationException {
0513                int p0 = getStartOffset();
0514                int p1 = getEndOffset();
0515                if ((pos >= p0) && (pos <= p1)) {
0516                    Rectangle r = a.getBounds();
0517                    if (pos == p1) {
0518                        r.x += r.width;
0519                    }
0520                    r.width = 0;
0521                    return r;
0522                }
0523                return null;
0524            }
0525
0526            /**
0527             * Provides a mapping from the view coordinate space to the logical
0528             * coordinate space of the model.
0529             *
0530             * @param x the X coordinate
0531             * @param y the Y coordinate
0532             * @param a the allocated region to render into
0533             * @return the location within the model that best represents the
0534             *  given point of view
0535             * @see View#viewToModel
0536             */
0537            public int viewToModel(float x, float y, Shape a,
0538                    Position.Bias[] bias) {
0539                Rectangle alloc = (Rectangle) a;
0540                if (x < alloc.x + alloc.width) {
0541                    bias[0] = Position.Bias.Forward;
0542                    return getStartOffset();
0543                }
0544                bias[0] = Position.Bias.Backward;
0545                return getEndOffset();
0546            }
0547
0548            /**
0549             * Sets the size of the view.  This should cause 
0550             * layout of the view if it has any layout duties.
0551             *
0552             * @param width the width >= 0
0553             * @param height the height >= 0
0554             */
0555            public void setSize(float width, float height) {
0556                sync();
0557
0558                if (getImage() == null) {
0559                    View view = getAltView();
0560
0561                    if (view != null) {
0562                        view
0563                                .setSize(
0564                                        Math
0565                                                .max(
0566                                                        0f,
0567                                                        width
0568                                                                - (float) (DEFAULT_WIDTH
0569                                                                        + leftInset + rightInset)),
0570                                        Math
0571                                                .max(
0572                                                        0f,
0573                                                        height
0574                                                                - (float) (topInset + bottomInset)));
0575                    }
0576                }
0577            }
0578
0579            /**
0580             * Returns true if this image within a link?
0581             */
0582            private boolean isLink() {
0583                return ((state & LINK_FLAG) == LINK_FLAG);
0584            }
0585
0586            /**
0587             * Returns true if the passed in image has a non-zero width and height.
0588             */
0589            private boolean hasPixels(Image image) {
0590                return image != null && (image.getHeight(imageObserver) > 0)
0591                        && (image.getWidth(imageObserver) > 0);
0592            }
0593
0594            /**
0595             * Returns the preferred span of the View used to display the alt text,
0596             * or 0 if the view does not exist.
0597             */
0598            private float getPreferredSpanFromAltView(int axis) {
0599                if (getImage() == null) {
0600                    View view = getAltView();
0601
0602                    if (view != null) {
0603                        return view.getPreferredSpan(axis);
0604                    }
0605                }
0606                return 0f;
0607            }
0608
0609            /**
0610             * Request that this view be repainted.
0611             * Assumes the view is still at its last-drawn location.
0612             */
0613            private void repaint(long delay) {
0614                if (container != null && fBounds != null) {
0615                    container.repaint(delay, fBounds.x, fBounds.y,
0616                            fBounds.width, fBounds.height);
0617                }
0618            }
0619
0620            /**
0621             * Convenience method for getting an integer attribute from the elements
0622             * AttributeSet.
0623             */
0624            private int getIntAttr(HTML.Attribute name, int deflt) {
0625                AttributeSet attr = getElement().getAttributes();
0626                if (attr.isDefined(name)) { // does not check parents!
0627                    int i;
0628                    String val = (String) attr.getAttribute(name);
0629                    if (val == null) {
0630                        i = deflt;
0631                    } else {
0632                        try {
0633                            i = Math.max(0, Integer.parseInt(val));
0634                        } catch (NumberFormatException x) {
0635                            i = deflt;
0636                        }
0637                    }
0638                    return i;
0639                } else
0640                    return deflt;
0641            }
0642
0643            /**
0644             * Makes sure the necessary properties and image is loaded.
0645             */
0646            private void sync() {
0647                int s = state;
0648                if ((s & RELOAD_IMAGE_FLAG) != 0) {
0649                    refreshImage();
0650                }
0651                s = state;
0652                if ((s & RELOAD_FLAG) != 0) {
0653                    synchronized (this ) {
0654                        state = (state | RELOAD_FLAG) ^ RELOAD_FLAG;
0655                    }
0656                    setPropertiesFromAttributes();
0657                }
0658            }
0659
0660            /**
0661             * Loads the image and updates the size accordingly. This should be
0662             * invoked instead of invoking <code>loadImage</code> or
0663             * <code>updateImageSize</code> directly.
0664             */
0665            private void refreshImage() {
0666                synchronized (this ) {
0667                    // clear out width/height/realoadimage flag and set loading flag
0668                    state = (state | LOADING_FLAG | RELOAD_IMAGE_FLAG
0669                            | WIDTH_FLAG | HEIGHT_FLAG)
0670                            ^ (WIDTH_FLAG | HEIGHT_FLAG | RELOAD_IMAGE_FLAG);
0671                    image = null;
0672                    width = height = 0;
0673                }
0674
0675                try {
0676                    // Load the image
0677                    loadImage();
0678
0679                    // And update the size params
0680                    updateImageSize();
0681                } finally {
0682                    synchronized (this ) {
0683                        // Clear out state in case someone threw an exception.
0684                        state = (state | LOADING_FLAG) ^ LOADING_FLAG;
0685                    }
0686                }
0687            }
0688
0689            /**
0690             * Loads the image from the URL <code>getImageURL</code>. This should
0691             * only be invoked from <code>refreshImage</code>.
0692             */
0693            private void loadImage() {
0694                URL src = getImageURL();
0695                Image newImage = null;
0696                if (src != null) {
0697                    Dictionary cache = (Dictionary) getDocument().getProperty(
0698                            IMAGE_CACHE_PROPERTY);
0699                    if (cache != null) {
0700                        newImage = (Image) cache.get(src);
0701                    } else {
0702                        newImage = Toolkit.getDefaultToolkit().createImage(src);
0703                        if (newImage != null && getLoadsSynchronously()) {
0704                            // Force the image to be loaded by using an ImageIcon.
0705                            ImageIcon ii = new ImageIcon();
0706                            ii.setImage(newImage);
0707                        }
0708                    }
0709                }
0710                image = newImage;
0711            }
0712
0713            /**
0714             * Recreates and reloads the image.  This should
0715             * only be invoked from <code>refreshImage</code>.
0716             */
0717            private void updateImageSize() {
0718                int newWidth = 0;
0719                int newHeight = 0;
0720                int newState = 0;
0721                Image newImage = getImage();
0722
0723                if (newImage != null) {
0724                    Element elem = getElement();
0725                    AttributeSet attr = elem.getAttributes();
0726
0727                    // Get the width/height and set the state ivar before calling
0728                    // anything that might cause the image to be loaded, and thus the
0729                    // ImageHandler to be called.
0730                    newWidth = getIntAttr(HTML.Attribute.WIDTH, -1);
0731                    if (newWidth > 0) {
0732                        newState |= WIDTH_FLAG;
0733                    }
0734                    newHeight = getIntAttr(HTML.Attribute.HEIGHT, -1);
0735                    if (newHeight > 0) {
0736                        newState |= HEIGHT_FLAG;
0737                    }
0738
0739                    if (newWidth <= 0) {
0740                        newWidth = newImage.getWidth(imageObserver);
0741                        if (newWidth <= 0) {
0742                            newWidth = DEFAULT_WIDTH;
0743                        }
0744                    }
0745
0746                    if (newHeight <= 0) {
0747                        newHeight = newImage.getHeight(imageObserver);
0748                        if (newHeight <= 0) {
0749                            newHeight = DEFAULT_HEIGHT;
0750                        }
0751                    }
0752
0753                    // Make sure the image starts loading:
0754                    if ((newState & (WIDTH_FLAG | HEIGHT_FLAG)) != 0) {
0755                        Toolkit.getDefaultToolkit().prepareImage(newImage,
0756                                newWidth, newHeight, imageObserver);
0757                    } else {
0758                        Toolkit.getDefaultToolkit().prepareImage(newImage, -1,
0759                                -1, imageObserver);
0760                    }
0761
0762                    boolean createText = false;
0763                    synchronized (this ) {
0764                        // If imageloading failed, other thread may have called
0765                        // ImageLoader which will null out image, hence we check
0766                        // for it.
0767                        if (image != null) {
0768                            if ((newState & WIDTH_FLAG) == WIDTH_FLAG
0769                                    || width == 0) {
0770                                width = newWidth;
0771                            }
0772                            if ((newState & HEIGHT_FLAG) == HEIGHT_FLAG
0773                                    || height == 0) {
0774                                height = newHeight;
0775                            }
0776                        } else {
0777                            createText = true;
0778                            if ((newState & WIDTH_FLAG) == WIDTH_FLAG) {
0779                                width = newWidth;
0780                            }
0781                            if ((newState & HEIGHT_FLAG) == HEIGHT_FLAG) {
0782                                height = newHeight;
0783                            }
0784                        }
0785                        state = state | newState;
0786                        state = (state | LOADING_FLAG) ^ LOADING_FLAG;
0787                    }
0788                    if (createText) {
0789                        // Only reset if this thread determined image is null
0790                        updateAltTextView();
0791                    }
0792                } else {
0793                    width = height = DEFAULT_HEIGHT;
0794                    updateAltTextView();
0795                }
0796            }
0797
0798            /**
0799             * Updates the view representing the alt text.
0800             */
0801            private void updateAltTextView() {
0802                String text = getAltText();
0803
0804                if (text != null) {
0805                    ImageLabelView newView;
0806
0807                    newView = new ImageLabelView(getElement(), text);
0808                    synchronized (this ) {
0809                        altView = newView;
0810                    }
0811                }
0812            }
0813
0814            /**
0815             * Returns the view to use for alternate text. This may be null.
0816             */
0817            private View getAltView() {
0818                View view;
0819
0820                synchronized (this ) {
0821                    view = altView;
0822                }
0823                if (view != null && view.getParent() == null) {
0824                    view.setParent(getParent());
0825                }
0826                return view;
0827            }
0828
0829            /**
0830             * Invokes <code>preferenceChanged</code> on the event displatching
0831             * thread.
0832             */
0833            private void safePreferenceChanged() {
0834                if (SwingUtilities.isEventDispatchThread()) {
0835                    Document doc = getDocument();
0836                    if (doc instanceof  AbstractDocument) {
0837                        ((AbstractDocument) doc).readLock();
0838                    }
0839                    preferenceChanged(null, true, true);
0840                    if (doc instanceof  AbstractDocument) {
0841                        ((AbstractDocument) doc).readUnlock();
0842                    }
0843                } else {
0844                    SwingUtilities.invokeLater(new Runnable() {
0845                        public void run() {
0846                            safePreferenceChanged();
0847                        }
0848                    });
0849                }
0850            }
0851
0852            /**
0853             * ImageHandler implements the ImageObserver to correctly update the
0854             * display as new parts of the image become available.
0855             */
0856            private class ImageHandler implements  ImageObserver {
0857                // This can come on any thread. If we are in the process of reloading
0858                // the image and determining our state (loading == true) we don't fire
0859                // preference changed, or repaint, we just reset the fWidth/fHeight as
0860                // necessary and return. This is ok as we know when loading finishes
0861                // it will pick up the new height/width, if necessary.
0862                public boolean imageUpdate(Image img, int flags, int x, int y,
0863                        int newWidth, int newHeight) {
0864                    if (image == null || image != img || getParent() == null) {
0865                        return false;
0866                    }
0867
0868                    // Bail out if there was an error:
0869                    if ((flags & (ABORT | ERROR)) != 0) {
0870                        repaint(0);
0871                        synchronized (ImageView.this ) {
0872                            if (image == img) {
0873                                // Be sure image hasn't changed since we don't
0874                                // initialy synchronize
0875                                image = null;
0876                                if ((state & WIDTH_FLAG) != WIDTH_FLAG) {
0877                                    width = DEFAULT_WIDTH;
0878                                }
0879                                if ((state & HEIGHT_FLAG) != HEIGHT_FLAG) {
0880                                    height = DEFAULT_HEIGHT;
0881                                }
0882                            }
0883                            if ((state & LOADING_FLAG) == LOADING_FLAG) {
0884                                // No need to resize or repaint, still in the process
0885                                // of loading.
0886                                return false;
0887                            }
0888                        }
0889                        updateAltTextView();
0890                        safePreferenceChanged();
0891                        return false;
0892                    }
0893
0894                    // Resize image if necessary:
0895                    short changed = 0;
0896                    if ((flags & ImageObserver.HEIGHT) != 0
0897                            && !getElement().getAttributes().isDefined(
0898                                    HTML.Attribute.HEIGHT)) {
0899                        changed |= 1;
0900                    }
0901                    if ((flags & ImageObserver.WIDTH) != 0
0902                            && !getElement().getAttributes().isDefined(
0903                                    HTML.Attribute.WIDTH)) {
0904                        changed |= 2;
0905                    }
0906
0907                    synchronized (ImageView.this ) {
0908                        if (image != img) {
0909                            return false;
0910                        }
0911                        if ((changed & 1) == 1 && (state & WIDTH_FLAG) == 0) {
0912                            width = newWidth;
0913                        }
0914                        if ((changed & 2) == 2 && (state & HEIGHT_FLAG) == 0) {
0915                            height = newHeight;
0916                        }
0917                        if ((state & LOADING_FLAG) == LOADING_FLAG) {
0918                            // No need to resize or repaint, still in the process of
0919                            // loading.
0920                            return true;
0921                        }
0922                    }
0923                    if (changed != 0) {
0924                        // May need to resize myself, asynchronously:
0925                        safePreferenceChanged();
0926                        return true;
0927                    }
0928
0929                    // Repaint when done or when new pixels arrive:
0930                    if ((flags & (FRAMEBITS | ALLBITS)) != 0) {
0931                        repaint(0);
0932                    } else if ((flags & SOMEBITS) != 0 && sIsInc) {
0933                        repaint(sIncRate);
0934                    }
0935                    return ((flags & ALLBITS) == 0);
0936                }
0937            }
0938
0939            /**
0940             * ImageLabelView is used if the image can't be loaded, and
0941             * the attribute specified an alt attribute. It overriden a handle of
0942             * methods as the text is hardcoded and does not come from the document.
0943             */
0944            private class ImageLabelView extends InlineView {
0945                private Segment segment;
0946                private Color fg;
0947
0948                ImageLabelView(Element e, String text) {
0949                    super (e);
0950                    reset(text);
0951                }
0952
0953                public void reset(String text) {
0954                    segment = new Segment(text.toCharArray(), 0, text.length());
0955                }
0956
0957                public void paint(Graphics g, Shape a) {
0958                    // Don't use supers paint, otherwise selection will be wrong
0959                    // as our start/end offsets are fake.
0960                    GlyphPainter painter = getGlyphPainter();
0961
0962                    if (painter != null) {
0963                        g.setColor(getForeground());
0964                        painter.paint(this , g, a, getStartOffset(),
0965                                getEndOffset());
0966                    }
0967                }
0968
0969                public Segment getText(int p0, int p1) {
0970                    if (p0 < 0 || p1 > segment.array.length) {
0971                        throw new RuntimeException("ImageLabelView: Stale view");
0972                    }
0973                    segment.offset = p0;
0974                    segment.count = p1 - p0;
0975                    return segment;
0976                }
0977
0978                public int getStartOffset() {
0979                    return 0;
0980                }
0981
0982                public int getEndOffset() {
0983                    return segment.array.length;
0984                }
0985
0986                public View breakView(int axis, int p0, float pos, float len) {
0987                    // Don't allow a break
0988                    return this ;
0989                }
0990
0991                public Color getForeground() {
0992                    View parent;
0993                    if (fg == null && (parent = getParent()) != null) {
0994                        Document doc = getDocument();
0995                        AttributeSet attr = parent.getAttributes();
0996
0997                        if (attr != null && (doc instanceof  StyledDocument)) {
0998                            fg = ((StyledDocument) doc).getForeground(attr);
0999                        }
1000                    }
1001                    return fg;
1002                }
1003            }
1004        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.