📄 myimageview.java
字号:
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.
*/
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.
*/
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.
*/
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.
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 )
if( ! getElement().getAttributes().isDefined(HTML.Attribute.HEIGHT) ) {
changed |= 1;
}
if( (flags & ImageObserver.WIDTH) != 0 )
if( ! getElement().getAttributes().isDefined(HTML.Attribute.WIDTH) ) {
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("ImageView: resized to "+fWidth+"x"+fHeight);
Document doc = getDocument();
try {
if (doc instanceof AbstractDocument) {
((AbstractDocument)doc).readLock();
}
preferenceChanged(this,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
*/
private static boolean sIsInc = true;
private static int sIncRate = 100;
// --- Layout ----------------------------------------------------------
/** Determines the preferred span for this view along an axis.
*
* @param axis may be either X_AXIS or Y_AXIS
* @returns the span the view would like to be rendered into.
* Typically the view is told to render into the span
* that is returned, although there is no guarantee.
* The parent may choose to resize or break the view.
*/
public float getPreferredSpan(int axis) {
//if(DEBUG)System.out.println("ImageView: getPreferredSpan");
int extra = 2*(getBorder()+getSpace(axis));
switch (axis) {
case View.X_AXIS:
return fWidth+extra;
case View.Y_AXIS:
return fHeight+extra;
default:
throw new IllegalArgumentException("Invalid axis: " + axis);
}
}
/** Determines the desired alignment for this view along an
* axis. This is implemented to give the alignment to the
* bottom of the icon along the y axis, and the default
* along the x axis.
*
* @param axis may be either X_AXIS or Y_AXIS
* @returns the desired alignment. This should be a value
* between 0.0 and 1.0 where 0 indicates alignment at the
* origin and 1.0 indicates alignment to the full span
* away from the origin. An alignment of 0.5 would be the
* center of the view.
*/
public float getAlignment(int axis) {
switch (axis) {
case View.Y_AXIS:
return getVerticalAlignment();
default:
return super.getAlignment(axis);
}
}
/** Provides a mapping from the document model coordinate space
* to the coordinate space of the view mapped to it.
*
* @param pos the position to convert
* @param a the allocated region to render into
* @return the bounding box of the given position
* @exception BadLocationException if the given position does not represent a
* valid location in the associated document
* @see View#modelToView
*/
public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {
int p0 = getStartOffset();
int p1 = getEndOffset();
if ((pos >= p0) && (pos <= p1)) {
Rectangle r = a.getBounds();
if (pos == p1) {
r.x += r.width;
}
r.width = 0;
return r;
}
return null;
}
/** Provides a mapping from the view coordinate space to the logical
* coordinate space of the model.
*
* @param x the X coordinate
* @param y the Y coordinate
* @param a the allocated region to render into
* @return the location within the model that best represents the
* given point of view
* @see View#viewToModel
*/
public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) {
Rectangle alloc = (Rectangle) a;
if (x < alloc.x + alloc.width) {
bias[0] = Position.Bias.Forward;
return getStartOffset();
}
bias[0] = Position.Bias.Backward;
return getEndOffset();
}
/** Set the size of the view. (Ignored.)
*
* @param width the width
* @param height the height
*/
public void setSize(float width, float height) {
// Ignore this -- image size is determined by the tag attrs and
// the image itself, not the surrounding layout!
}
/** Change the size of this image. This alters the HEIGHT and WIDTH
* attributes of the Element and causes a re-layout.
*/
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();
attr.addAttribute(HTML.Attribute.WIDTH ,Integer.toString(width));
attr.addAttribute(HTML.Attribute.HEIGHT,Integer.toString(height));
((StyledDocument)getDocument()).setCharacterAttributes(
fElement.getStartOffset(),
fElement.getEndOffset(),
attr, false);
}
// --- Mouse event handling --------------------------------------------
/** Select or grow image when clicked.
*/
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("ImageView: 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:
*/
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);
}
}
public void mouseReleased(MouseEvent e){
fGrowBase = null;
//! Should post some command to make the action undo-able
}
/** On double-click, open image properties dialog.
*/
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 -------------------------------------------
/**
*/
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.
*/
InputStream resource = MyImageView.class.getResourceAsStream(gifFile);
if (resource == null) {
if (DEBUG)
System.err.println(MyImageView.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);
}
/**
*/
private void loadIcons() {
try {
if ( sPendingImageIcon == null )
sPendingImageIcon = makeIcon(PENDING_IMAGE_SRC);
if ( sMissingImageIcon == null )
sMissingImageIcon = makeIcon(MISSING_IMAGE_SRC);
} catch( Exception x ) {
Debug.signal( Debug.WARNING, null, "ImageView: Couldn't load image icons" );
}
}
/**
*/
protected StyleSheet getStyleSheet() {
HTMLDocument doc = (HTMLDocument) getDocument();
return doc.getStyleSheet();
}
// --- member variables ------------------------------------------------
private AttributeSet attr;
private Element fElement;
private Image fImage;
private int fHeight,fWidth;
private Container fContainer;
private Rectangle fBounds;
private Component fComponent;
private Point fGrowBase; // base of drag while growing image
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. */
private boolean loading;
// --- constants and static stuff --------------------------------
private static Icon sPendingImageIcon, sMissingImageIcon;
private static final String PENDING_IMAGE_SRC = "icons/image-delayed.gif"; // both stolen from HotJava
private static final String MISSING_IMAGE_SRC = "icons/image-failed.gif";
private static final boolean DEBUG = false;
//$ move this someplace public
static final String IMAGE_CACHE_PROPERTY = "imageCache";
// Height/width to use before we know the real size:
private static final int DEFAULT_WIDTH = 32;
private static final int DEFAULT_HEIGHT = 32;
// Default value of BORDER param: //? possibly move into stylesheet?
private static final int DEFAULT_BORDER = 2;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -