All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.globalmentor.swing.text.xml.XMLImageView Maven / Gradle / Ivy

The newest version!
/*
 * Copyright © 1996-2009 GlobalMentor, Inc. 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.globalmentor.swing.text.xml;

import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.ImageObserver;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.net.URISyntaxException;
import javax.swing.text.*;
import javax.swing.text.html.ImageView;

import com.globalmentor.log.Log;

/**
 * View that displays an image. The image reference is kept using a soft pointer so that when memory is low the JVM can reclaim the image memory. The image,
 * therefore, can be loaded or reloaded at any time using loadImage().
 * 

* A class should be derived from this class that correctly sets the image href, width, and height. *

*

* This class was written referencing {@link ImageView} by Jens Alfke version 1.40 02/02/00, and the original version was based on code from that class. *

* @author Garret Wilson * @see ImageView * @see XMLObjectView#setHeight(int) * @see XMLObjectView#setWidth(int) * @see #setHRef(String) */ public abstract class XMLImageView extends XMLObjectView implements ImageObserver //TODO fix, MouseListener, MouseMotionListener { /** The reference to the image, which can be reclaimed if memory is running low. */ private SoftReference imageReference = null; /** * Whether or not the image has started loading. * @see #paint * @see #imageUpdate */ //TODO del; not needed now that FRAMEBITS has been discovered protected boolean startedLoading=false; protected boolean startedLoading = false; /** * Whether or not the image has finished loading. * @see #paint * @see #imageUpdate */ protected boolean finishedLoading = false; /** The source of the image. */ private String href = null; /** @return The source of the image. */ public String getHRef() { return href; } /** * Sets the source of the image. * @param newHRef The new source of the image. */ protected void setHRef(final String newHRef) { href = newHRef; } // --- Attribute Values ------------------------------------------ /*TODO del if not needed public static final String TOP = "top", TEXTTOP = "texttop", MIDDLE = "middle", ABSMIDDLE = "absmiddle", CENTER = "center", BOTTOM = "bottom"; */ /** * Creates a view that represents an image. * @param element The element for which to create the view. */ public XMLImageView(final Element element) { super(element); //do the default constructing } /** * Loads the image immediately and returns it. * @return The loaded image. */ /*TODO fix after deciding how this method should be used protected Image loadImage() { final Image image=(Image)document.getResource(src); //get the image resource TODO check to make sure what is returned is really an image imageReference=new SoftReference(image); //create a soft reference to the image to store locally } */ /** * Sets whether or not an view is showing. This version includes the parent functionality, and sets the startedLoading and * finishedLoading variables to false to reflect the fact that the image will need to possibly be reloaded. The internal hard * reference to the image is removed, so that the image memory may be reclaimed if needed. * @param newShowing true if the view is beginning to be shown, false if the view is beginning to be hidden. * @see #isShowing */ public void setShowing(final boolean newShowing) { Log.trace(); //TODO del super.setShowing(newShowing); //do the default functionality if(!newShowing) { //if we're being hidden shownImage = null; //remove our hard reference to the image so that its memory may be reclaimed if needed startedLoading = false; //show that the image hasn't started loading, yet finishedLoading = false; //show that the image hasn't finished loading, either } } /** * Returns the image to be drawn. Because memory usage may cause the image memory to be reclaimed, this method may reload the image. initialize() * must therefore have first been called to appropriately set the image information. * @throws URISyntaxException Thrown if the image href does not allow a syntactically correct URI to be contructed. * @throws IOException Thrown if there is an error getting the image, usually because the image needed to be loaded but could not be. * @see #freeImage * @see #initialize */ protected Image getImage() throws URISyntaxException, IOException { Log.trace("XMLImageView.getImage(): ", getHRef()); //TODO del if(shownImage != null) //TODO testing; comment return shownImage; //TODO comment else { //TODO put some sort of assert that the image reference is not equal to null or something; or maybe this isn't needed, since the constructor calls initialize() Image image = imageReference != null ? (Image)imageReference.get() : null; //get the image to which the soft reference refers if(image == null) { //if we have not loaded the image yet, or the image memory has been reclaimed //TODO put all this into a separate function Log.trace("loading image"); //TODO del if(imageReference != null) { //if we used to have a reference to an image, but memory was running low and it was reclaimed Log.trace("Image memory reclaimed, reloading."); //TODO del System.gc(); //indicate that garbage collection should occur to attempt to give us more memory TODO testing memory } startedLoading = false; //show that the image hasn't started loading, yet finishedLoading = false; //show that the image hasn't finished loading, either final XMLDocument document = (XMLDocument)getDocument(); //get the document used to load resources TODO make sure this is an XML document //get the href, taking into account that the href is relative to this file's base URL //TODO del System.out.println("image href: "+getHRef()); //TODO del final String href = XMLStyles.getBaseRelativeHRef(getAttributes(), getHRef()); //TODO del System.out.println("image base relateive href: "+href); //TODO del image = (Image)document.getResource(href); //get the image resource TODO check to make sure what is returned is really an image imageReference = new SoftReference(image); //create a soft reference to the image to store locally } return image; //return the image } } /** * Frees the image, if one has been loaded. This allows the garbage collector to reclaim the memory used by the image, which will cause the image to be * reloaded the next time getImage() is called. * @see #getImage */ protected void freeImage() { if(imageReference != null) { //if there is a memory reference imageReference.clear(); //clear the reference to the image imageReference = null; //remove the image reference; this frees more memory, and it would have to have been recreated, anyway } } /** * The image currently being painted. This hard reference ensures that, while this view is showing, the image memory will not be reclaimed. When the view is * not showing, this image will be set to false so that the image memory may be recollected if needed. */ protected Image shownImage = null; /** * Fetches the attributes to use when rendering. This is implemented to multiplex the attributes specified in the model with a StyleSheet. */ /*TODO fix public AttributeSet getAttributes() { return attr; } */ /** Is this image within a link? */ /*TODO fix boolean isLink( ) { return isLink; } */ /** Returns the size of the border to use. */ /*TODO fix int getBorder( ) { return border; } */ /** Returns the amount of extra space to add along an axis. */ /*TODO fix int getSpace( int axis ) { if (axis == X_AXIS) { return xSpace; } return ySpace; } */ /** Returns the border's color, or null if this is not a link. */ /*TODO fix or delete Color getBorderColor( ) { StyledDocument doc = (StyledDocument) getDocument(); return doc.getForeground(getAttributes()); } */ /*TODO fix boolean hasPixels( ImageObserver obs ) { return fImage != null && fImage.getHeight(obs)>0 && fImage.getWidth(obs)>0; } */ /** * Return a URL for the image source, or null if it could not be determined. */ /*TODO fix private URL getSourceURL( ) { String src = "file:/D:/Projects/oeb/understandingoeb/oebobjects_classdiagram.jpg"; //TODO fix String src = (String) fElement.getAttributes().getAttribute(HTML.Attribute.SRC); if( src==null ) return null; //TODO fix URL reference = ((HTMLDocument)getDocument()).getBase(); try { //TODO fix URL u = new URL(reference,src); URL u = new URL(src); return u; } catch (MalformedURLException e) { return null; } } */ /** Look up an integer-valued attribute. Not recursive. */ /*TODO fix private int getIntAttr(HTML.Attribute name, int deflt ) { AttributeSet attr = fElement.getAttributes(); if( attr.isDefined(name) ) { // does not check parents! int i; String val = (String) attr.getAttribute(name); if( val == null ) i = deflt; else try{ i = Math.max(0, Integer.parseInt(val)); }catch( NumberFormatException x ) { i = deflt; } return i; } else return deflt; } */ /** My attributes may have changed. */ /*TODO del if we don't need public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) { if(DEBUG) System.out.println("OEBImageView: changedUpdate begin..."); super.changedUpdate(e,a,f); int height = fHeight; int width = fWidth; initialize(getElement()); boolean hChanged = fHeight!=height; boolean wChanged = fWidth!=width; if( hChanged || wChanged) { if(DEBUG) System.out.println("OEBImageView: calling preferenceChanged"); preferenceChanged(null,hChanged,wChanged); } } */ /** * Paints the image. * @param graphics The rendering surface to use. * @param allocation The allocated region to render into. * @see XMLObjectView#paint */ public void paint(Graphics graphics, Shape allocation) { Log.trace("(before super) paint() {0}, isShowing: {1} startedLoading: {2} finishedLoading: {3}", new Object[] { getHRef(), new Boolean(isShowing()), new Boolean(startedLoading), new Boolean(finishedLoading) }); super.paint(graphics, allocation); //do the default painting final Graphics2D graphics2D = (Graphics2D)graphics; //cast to the 2D version of graphics //set pixel interpolation to its highest quality TODO probably do this conditionally, based on some sort of flag graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); Log.trace("(after super) paint() {0}, isShowing: {1} startedLoading: {2} finishedLoading: {3}", new Object[] { getHRef(), new Boolean(isShowing()), new Boolean(startedLoading), new Boolean(finishedLoading) }); //TODO del Log.trace("imageView.paint() currentWidth: "+currentWidth+" currentHeight: "+currentHeight); //TODO del when works paintingVisible=true; //show that calls to getComponent().repaint() are actually causes this image view to get repainted //TODO fix Color oldColor = g.getColor(); //TODO switch to using getBounds() final Rectangle rectangle = (allocation instanceof Rectangle) ? (Rectangle)allocation : allocation.getBounds(); //get the bounding rectangle of the painting area //TODO del Log.trace("Inside OEBImageView.paint(), width: "+currentWidth+" height: "+currentHeight+" alloc width: "+alloc.width+" alloc height: "+alloc.height); //TODO del; testing image /*TODO fix fBounds.setBounds(alloc); int border = getBorder(); */ /*TODO del when works int x = fBounds.x + border + getSpace(X_AXIS); int y = fBounds.y + border + getSpace(Y_AXIS); int width = fWidth; int height = fHeight; */ final int x = rectangle.x; //TODO comment final int y = rectangle.y; final int width = getCurrentWidth(); //get the current image width final int height = getCurrentHeight(); //get the current image height //TODO fix int sel = getSelectionState(); // Make sure my Component is in the right place: /* if( fComponent == null ) { fComponent = new Component() { }; fComponent.addMouseListener(this); fComponent.addMouseMotionListener(this); fComponent.setCursor(Cursor.getDefaultCursor()); // use arrow cursor fContainer.add(fComponent); } fComponent.setBounds(x,y,width,height); */ // If no pixels yet, draw gray outline and icon: /*TODO fix if( ! hasPixels(this) ) { g.setColor(Color.lightGray); g.drawRect(x,y,width-1,height-1); g.setColor(oldColor); */ /*TODO fix loadIcons(); Icon icon = fImage==null ?sMissingImageIcon :sPendingImageIcon; if( icon != null ) icon.paintIcon(getContainer(), g, x, y); } */ // Draw image: try { //TODO del when works final Image image=getImage(); //get the image, which may include relading it shownImage = getImage(); //get the image, which may include relading it; this will for now set a hard reference to the image so that the image memory will not be reclaimed while it it showing if(shownImage != null) { Log.trace("got the image"); //TODO fix fImageIcon.paintIcon((Component)getContainer(), g, x, y); //TODO testing if(finishedLoading || !startedLoading) { //if we've finished loading the image, or we haven't even started loading it, yet Log.trace("ready to draw image with current width {0} and current height {1}", new Object[] { new Integer(getCurrentWidth()), new Integer(getCurrentHeight()) }); //draw the image, which will start loading the image if it isn't loaded yet //note that many small images apparently never call imageUpdate(), meaning // this function will return with the image already loaded without // imageUpdate() being called, so we have to manipulate the // finishedLoading and startedLoading variables here as well //TODO bring back; testing finishedLoading=g.drawImage(image, x, y, alloc.width, alloc.height, this); Log.trace("Painting image " + href + " at " + x + ", " + y + " width " + getCurrentWidth() + " height " + getCurrentHeight()); //TODO del finishedLoading = graphics.drawImage(shownImage, x, y, getCurrentWidth(), getCurrentHeight(), this); //TODO fix or del final boolean isImageDrawn=g.drawImage(fImage, x, y, alloc.width, alloc.height, this); //TODO del when works final boolean isImageDrawn=g.drawImage(fImage, x, y, width/2, height/2, this); if(!startedLoading && !finishedLoading) { //if the image has not yet started loading (and loading hasn't already finished) ((Graphics2D)graphics).setPaint(Color.black); graphics.setFont(new Font("Arial", Font.PLAIN, 14)); //TODO fix all this; use a constant final String statusString = "Loading image..."; //TODO fix; i18n; comment final FontRenderContext fontRenderContext = graphics2D.getFontRenderContext(); //get the font rendering context //TODO probably make sure that it is antialiased, here final Rectangle2D statusBounds = graphics2D.getFont().getStringBounds(statusString, fontRenderContext); //get the bounds of the status string final int statusX = x; //find out where we would paint the status final int statusY = y + 20; //if the string we would draw doesn't go outside our image if(statusX + statusBounds.getWidth() < x + getCurrentWidth() && statusY + statusBounds.getHeight() < x + getCurrentHeight()) { graphics.drawString(statusString, statusX, statusY); //TODO testing; i18n } //TODO del if not needed startedLoading=true; //TODO testing } //TODO should we update startedLoading for consistency, since finishedLoading might be set without startedLoading being set? } //TODO del Log.trace("image drawn: "+isImageDrawn); //TODO del //TODO fix g.drawImage(fImage,x, y,width,height,this); //TODO fix g.drawImage(fImage, x, y, (int)getParent().getPreferredSpan(X_AXIS)/3, height, this); // Use the following instead of g.drawImage when // BufferedImageGraphics2D.setXORMode is fixed (4158822). // Use Xor mode when selected/highlighted. //! Could darken image instead, but it would be more expensive. /* if( sel > 0 ) g.setXORMode(Color.white); g.drawImage(fImage,x, y, width,height,this); if( sel > 0 ) g.setPaintMode(); */ } } catch(URISyntaxException uriSyntaxException) { //if there was an error getting the image TODO probably set some sort of flag so that we won't try to load it again next time Log.error(uriSyntaxException); //report the error ((Graphics2D)graphics).setPaint(Color.black); //TODO fix all this graphics.setFont(new Font("Arial", Font.PLAIN, 14)); graphics.drawString("Error loading image.", x, y + 20); //TODO testing; i18n } catch(IOException ioException) { //if there was an error getting the image TODO probably set some sort of flag so that we won't try to load it again next time Log.error(ioException); //report the error ((Graphics2D)graphics).setPaint(Color.black); //TODO fix all this graphics.setFont(new Font("Arial", Font.PLAIN, 14)); graphics.drawString("Error loading image.", x, y + 20); //TODO testing; i18n } // If selected exactly, we need a black border & grow-box: /*TODO del or fix Color bc = getBorderColor(); if( sel == 2 ) { // Make sure there's room for a border: int delta = 2-border; if( delta > 0 ) { x += delta; y += delta; width -= delta<<1; height -= delta<<1; border = 2; } bc = null; g.setColor(Color.black); // Draw grow box: g.fillRect(x+width-5,y+height-5,5,5); } */ // Draw border: /*TODO del or fix if( border > 0 ) { if( bc != null ) g.setColor(bc); // Draw a thick rectangle: for( int i=1; i<=border; i++ ) g.drawRect(x-i, y-i, width-1+i+i, height-1+i+i); g.setColor(oldColor); } */ } /** * Request that this view be repainted. Assumes the view is still at its last-drawn location. */ /*TODO fix protected void repaint( long delay ) { if( fContainer != null && fBounds!=null ) { fContainer.repaint(delay, fBounds.x,fBounds.y,fBounds.width,fBounds.height); } } */ /** * Determines whether the image is selected, and if it's the only thing selected. * @return 0 if not selected, 1 if selected, 2 if exclusively selected. "Exclusive" selection is only returned when editable. */ /*TODO fix protected int getSelectionState( ) { int p0 = fElement.getStartOffset(); int p1 = fElement.getEndOffset(); if (fContainer instanceof JTextComponent) { JTextComponent textComp = (JTextComponent)fContainer; int start = textComp.getSelectionStart(); int end = textComp.getSelectionEnd(); if( start<=p0 && end>=p1 ) { if( start==p0 && end==p1 && isEditable() ) return 2; else return 1; } } return 0; } protected boolean isEditable( ) { return fContainer instanceof JEditorPane && ((JEditorPane)fContainer).isEditable(); } */ /** Returns the text editor's highlight color. */ /*TODO fix protected Color getHighlightColor( ) { JTextComponent textComp = (JTextComponent)fContainer; return textComp.getSelectionColor(); } */ // --- Progressive display --------------------------------------------- // This can come on any thread. If we are in the process of reloading // the image and determining our state (loading == true) we don't fire // preference changed, or repaint, we just reset the fWidth/fHeight as // necessary and return. This is ok as we know when loading finishes // it will pick up the new height/width, if necessary. /*TODO del if not needed public boolean imageUpdate( Image img, int flags, int x, int y, int width, int height ) { if( fImage==null || fImage != img ) return false; // Bail out if there was an error: if( (flags & (ABORT|ERROR)) != 0 ) { fImage = null; repaint(0); return false; } // Resize image if necessary: short changed = 0; if( (flags & ImageObserver.HEIGHT) != 0 ) */ /*TODO fix if( ! getElement().getAttributes().isDefined(HTML.Attribute.HEIGHT) ) { changed |= 1; } */ //TODO del if not needed changed |= 1; /*TODO fix if( (flags & ImageObserver.WIDTH) != 0 ) if( ! getElement().getAttributes().isDefined(HTML.Attribute.WIDTH) ) { changed |= 2; } */ /*TODO del if not needed changed |= 2; synchronized(this) { if ((changed & 1) == 1) { fWidth = width; } if ((changed & 2) == 2) { fHeight = height; } if (loading) { // No need to resize or repaint, still in the process of // loading. return true; } } if( changed != 0 ) { // May need to resize myself, asynchronously: if( DEBUG ) System.out.println("OEBImageView: resized to "+fWidth+"x"+fHeight); Document doc = getDocument(); try { if (doc instanceof AbstractDocument) { ((AbstractDocument)doc).readLock(); } preferenceChanged(null,true,true); } finally { if (doc instanceof AbstractDocument) { ((AbstractDocument)doc).readUnlock(); } } return true; } // Repaint when done or when new pixels arrive: if( (flags & (FRAMEBITS|ALLBITS)) != 0 ) repaint(0); else if( (flags & SOMEBITS) != 0 ) if( sIsInc ) repaint(sIncRate); return ((flags & ALLBITS) == 0); } */ /* /** * Static properties for incremental drawing. * Swiped from Component.java * @see #imageUpdate */ //TODO fix private static boolean sIsInc = true; //TODO fix private static int sIncRate = 100; // --- Layout ---------------------------------------------------------- /** * Determines the resizability of the view along the given axis. A value of 0 or less is not resizable. * * @param axis View.X_AXIS or View.Y_AXIS * @return the weight */ /*TODO fix after figuring out what can be returned public int getResizeWeight(int axis) { return 0; } */ /** * Change the size of this image. This alters the HEIGHT and WIDTH attributes of the Element and causes a re-layout. */ /*TODO fix protected void resize( int width, int height ) { if( width==fWidth && height==fHeight ) return; fWidth = width; fHeight= height; // Replace attributes in document: MutableAttributeSet attr = new SimpleAttributeSet(); */ /*TODO fix attr.addAttribute(HTML.Attribute.WIDTH ,Integer.toString(width)); attr.addAttribute(HTML.Attribute.HEIGHT,Integer.toString(height)); */ /*TODO fix ((StyledDocument)getDocument()).setCharacterAttributes( fElement.getStartOffset(), fElement.getEndOffset(), attr, false); } */ // --- Mouse event handling -------------------------------------------- /** Select or grow image when clicked. */ /*TODO fix public void mousePressed(MouseEvent e){ Dimension size = fComponent.getSize(); if( e.getX() >= size.width-7 && e.getY() >= size.height-7 && getSelectionState()==2 ) { // Click in selected grow-box: if(DEBUG)System.out.println("OEBImageView: grow!!! Size="+fWidth+"x"+fHeight); Point loc = fComponent.getLocationOnScreen(); fGrowBase = new Point(loc.x+e.getX() - fWidth, loc.y+e.getY() - fHeight); fGrowProportionally = e.isShiftDown(); } else { // Else select image: fGrowBase = null; JTextComponent comp = (JTextComponent)fContainer; int start = fElement.getStartOffset(); int end = fElement.getEndOffset(); int mark = comp.getCaret().getMark(); int dot = comp.getCaret().getDot(); if( e.isShiftDown() ) { // extend selection if shift key down: if( mark <= start ) comp.moveCaretPosition(end); else comp.moveCaretPosition(start); } else { // just select image, without shift: if( mark!=start ) comp.setCaretPosition(start); if( dot!=end ) comp.moveCaretPosition(end); } } } */ /** Resize image if initial click was in grow-box: */ /*TODO fix public void mouseDragged(MouseEvent e ) { if( fGrowBase != null ) { Point loc = fComponent.getLocationOnScreen(); int width = Math.max(2, loc.x+e.getX() - fGrowBase.x); int height= Math.max(2, loc.y+e.getY() - fGrowBase.y); if( e.isShiftDown() && fImage!=null ) { // Make sure size is proportional to actual image size: float imgWidth = fImage.getWidth(this); float imgHeight = fImage.getHeight(this); if( imgWidth>0 && imgHeight>0 ) { float prop = imgHeight / imgWidth; float pwidth = height / prop; float pheight= width * prop; if( pwidth > width ) width = (int) pwidth; else height = (int) pheight; } } resize(width,height); } } */ /*TODO fix public void mouseReleased(MouseEvent e){ fGrowBase = null; //! Should post some command to make the action undo-able } */ /** On double-click, open image properties dialog. */ /*TODO fix public void mouseClicked(MouseEvent e){ if( e.getClickCount() == 2 ) { //$ IMPLEMENT } } public void mouseEntered(MouseEvent e){ } public void mouseMoved(MouseEvent e ) { } public void mouseExited(MouseEvent e){ } */ // --- Static icon accessors ------------------------------------------- //TODO fix private Icon makeIcon(final String gifFile) throws IOException { /* Copy resource into a byte array. This is * necessary because several browsers consider * Class.getResource a security risk because it * can be used to load additional classes. * Class.getResourceAsStream just returns raw * bytes, which we can convert to an image. */ /*TODO fix InputStream resource = HTMLEditorKit.getResourceAsStream(gifFile); if (resource == null) { System.err.println(OEBImageView.class.getName() + "/" + gifFile + " not found."); return null; } BufferedInputStream in = new BufferedInputStream(resource); ByteArrayOutputStream out = new ByteArrayOutputStream(1024); byte[] buffer = new byte[1024]; int n; while ((n = in.read(buffer)) > 0) { out.write(buffer, 0, n); } in.close(); out.flush(); buffer = out.toByteArray(); if (buffer.length == 0) { System.err.println("warning: " + gifFile + " is zero-length"); return null; } return new ImageIcon(buffer); } */ /*TODO fix private void loadIcons( ) { try{ if( sPendingImageIcon == null ) sPendingImageIcon = makeIcon(PENDING_IMAGE_SRC); if( sMissingImageIcon == null ) sMissingImageIcon = makeIcon(MISSING_IMAGE_SRC); }catch( Exception x ) { System.err.println("OEBImageView: Couldn't load image icons"); } } */ /*TODO fix protected StyleSheet getStyleSheet() { HTMLDocument doc = (HTMLDocument) getDocument(); return doc.getStyleSheet(); } */ // --- member variables ------------------------------------------------ //TODO fix private AttributeSet attr; //TODO fix private Element fElement; //TODO del when works private Image fImage; //TODO fix private Container fContainer; //TODO fix private Rectangle fBounds; //TODO fix private Component fComponent; //TODO fix private Point fGrowBase; // base of drag while growing image //TODO fix private boolean fGrowProportionally; // should grow be proportional? /** * Set to true, while the receiver is locked, to indicate the reciever is loading the image. This is used in imageUpdate. */ //TODO fix private boolean loading; //TODO fix private boolean isLink; //TODO fix private int border; //TODO fix private int xSpace; //TODO fix private int ySpace; // --- constants and static stuff -------------------------------- /*TODO fix private static Icon sPendingImageIcon, sMissingImageIcon; private static final String PENDING_IMAGE_SRC = "icons/image-delayed.gif", // both stolen from HotJava MISSING_IMAGE_SRC = "icons/image-failed.gif"; */ //TODO test private static final boolean DEBUG = false; //TODO del private static final boolean DEBUG = true; //TODO del; testing //$ move this someplace public //TODO fix static final String IMAGE_CACHE_PROPERTY = "imageCache"; // Height/width to use before we know the real size: /*TODO fix private static final int DEFAULT_WIDTH = 32, DEFAULT_HEIGHT= 32, // Default value of BORDER param: //? possibly move into stylesheet? DEFAULT_BORDER= 2; */ /** * Called when information about an image which was previously requested using an asynchronous interface becomes available. * @param img The image being observed. * @param infoflags The bitwise inclusive OR of the following flags: WIDTH, HEIGHT, PROPERTIES, SOMEBITS, * FRAMEBITS, ALLBITS, ERROR, ABORT. * @param x The x coordinate. * @param y The y coordinate. * @param width The width. * @param height The height. * @return false if the infoflags indicate that the image is completely loaded; true otherwise. */ public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) { //TODO testing //TODO del Log.trace(getHRef()); //TODO del /*TODO del Log.trace("imageUpdate() {0}, infoflags: {1}"+ " isShowing: {2} finishedLoading: {3}\n parent: {4}\n parent parent: {5}"+ "\n parent parent parent: {6}\n container: {7}", new Object[] { getHRef(), new Integer(infoflags), new Boolean(isShowing()), new Boolean(finishedLoading), (getParent()!=null ? getParent().getClass().getName() : "null"), (getParent()!=null && getParent().getParent()!=null ? getParent().getParent().getClass().getName() : "null"), (getParent()!=null && getParent().getParent()!=null && getParent().getParent().getParent()!=null ? getParent().getParent().getParent().getClass().getName() : "null"), getContainer() } ); */ /*TODO fix if((infoflags & SOMEBITS)!=0) //if there are some bits coming in, the image has started loading startedLoading=true; //show that the image has started loading TODO what if, for a small image, if( if(!infoflags & ALLBITS)!=0) //if all bits have been loaded */ //TODO fix Log.trace("imageUpdate() visible: "+paintingVisible+" Started loading: "+startedLoading+" Finished loading: "+finishedLoading); /*TODO del Log.trace("Parent: "+getParent()); //TODO del; testing if(getParent()!=null) { //TODO del Log.trace("Parent's parent: "+getParent().getParent()); //TODO del; testing if(getParent().getParent()!=null) //TODO del Log.trace("Parent's parent's parent: "+getParent().getParent().getParent()); //TODO del; testing } Log.trace("Container: "+getContainer()); //TODO del; testing */ //TODO del Log.trace(getHRef()+" allbits: ", infoflags & ALLBITS); //TODO del Log.trace(getHRef()+" framebits: ", infoflags & FRAMEBITS); startedLoading = true; //if imageUpdate() is ever called, we've at least started loading the image if((infoflags & (ALLBITS | FRAMEBITS)) != 0) //if we at any time receive all the bits, or if we're suddenly receiving frames from a multiple frame image, we've finished loading the image finishedLoading = true; //show that we've finished loading the image if(finishedLoading) { //only repaint the image if it has finished loading Log.trace("Finished loading ", getHRef()); /*TODO del Log.trace("image finished loading, ready to repaint\n{0}, infoflags: {1}"+ " isShowing: {2} finishedLoading: {3}\n parent: {4}\n parent parent: {5}"+ "\n parent parent parent: {6}\n container: {7}", new Object[] { getHRef(), new Integer(infoflags), new Boolean(isShowing()), new Boolean(finishedLoading), (getParent()!=null ? getParent().getClass().getName() : "null"), (getParent()!=null && getParent().getParent()!=null ? getParent().getParent().getClass().getName() : "null"), (getParent()!=null && getParent().getParent()!=null && getParent().getParent().getParent()!=null ? getParent().getParent().getParent().getClass().getName() : "null"), getContainer() } ); */ //TODO del when works if(paintingVisible) //if calls to getComponent().repaint() are actually causes this image view to get repainted if(isShowing()) { //if this view is showing Log.trace("Is showing ", getHRef()); //TODO del Log.trace("*********OEBImageView.imageUpdate(), SOMEBITS: "+(infoflags & SOMEBITS)+" ALLBITS: "+(infoflags & ALLBITS)+" FRAMEBITS: "+(infoflags & FRAMEBITS)); //TODO del /*TODO del; Debug no longer has a format trace method Log.trace("image finished loading, ready to repaint\n{0}, infoflags: {1}"+ " isShowing: {2} finishedLoading: {3}\n parent: {4}\n parent parent: {5}"+ "\n parent parent parent: {6}"+ "\n parent parent parent parent: {7}"+ "\n parent parent parent parent parent: {8}\n container: {9}", new Object[] { getHRef(), new Integer(infoflags), new Boolean(isShowing()), new Boolean(finishedLoading), (getParent()!=null ? getParent().getClass().getName() : "null"), (getParent()!=null && getParent().getParent()!=null ? getParent().getParent().getClass().getName() : "null"), (getParent()!=null && getParent().getParent()!=null && getParent().getParent().getParent()!=null ? getParent().getParent().getParent().getClass().getName() : "null"), (getParent()!=null && getParent().getParent()!=null && getParent().getParent().getParent()!=null && getParent().getParent().getParent().getParent()!=null ? getParent().getParent().getParent().getParent().getClass().getName() : "null"), (getParent()!=null && getParent().getParent()!=null && getParent().getParent().getParent()!=null && getParent().getParent().getParent().getParent()!=null && getParent().getParent().getParent().getParent().getParent()!=null ? getParent().getParent().getParent().getParent().getParent().getClass().getName() : "null"), getContainer() } ); */ if(getContainer() != null) { //TODO testing Log.trace("Have container ", getHRef()); //TODO del when works paintingVisible=false; //for our next repaint force paint() to prove once more that it is still getting called final Rectangle bounds = getBounds(); //get our painting bounds Log.trace(getHRef() + " painting bounds: ", bounds); /*TODO del; gives wrong coordinates bounds.x=x; //TODO testing image repaint bounds.y=y; */ //TODO del Log.trace("Found container, ready to call repaint with bounds: "+bounds); if(bounds.width == 0 || bounds.height == 0) { //TODO testing; kludge to compensate for table layout errors bounds.width = getCurrentWidth(); //get the current image width bounds.height = getCurrentHeight(); //get the current image height } Log.trace("Repainting image " + href + " with bounds: ", bounds); //TODO del //since the image is still visible (and imageUpdate() is still being called), repaint the image -- but only the areas within our bounds getContainer().repaint(bounds.x, bounds.y, bounds.width, bounds.height); //repaint only the areas within our bounds } } } final boolean isAnimation = (infoflags & FRAMEBITS) != 0; //see if this image has multiple frames final boolean isFinished = (infoflags & (ALLBITS | ABORT)) != 0; //see if loading has finished or has been aborted //we want to keep getting image data until we're finished, or until a multi-frame image is hidden //(put another way, we want to continue loading non-animation images, even if they are hidden return !isFinished && (isShowing() || !isAnimation); //TODO del return ((infoflags & (ALLBITS|ABORT)) == 0) && isShowing(); //TODO testing isShowing() } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy