int ypos = starty + rowHeight/2;
boolean useOldThumbnail = false;
// Create a transaction which will be used for persisten object operations
// during painting (to avoid creating several short-livin transactions)
ODMGXAWrapper txw = new ODMGXAWrapper();
Thumbnail thumbnail = null;
log.debug( "finding thumb" );
boolean hasThumbnail = photo.hasThumbnail();
log.debug( "asked if has thumb" );
if ( hasThumbnail ) {
log.debug( "Photo " + photo.getUid() + " has thumbnail" );
thumbnail = photo.getThumbnail();
log.debug( "got thumbnail" );
} else {
/*
Check if the thumbnail has been just invalidated. If so, use the
old one until we get the new thumbnail created.
*/
thumbnail = photo.getOldThumbnail();
if ( thumbnail != null ) {
useOldThumbnail = true;
} else {
// No success, use default thumnail.
thumbnail = Thumbnail.getDefaultThumbnail();
}
// The photo does not have a thumbnail, so request one to be created
if ( !thumbCreatorThread.isBusy() ) {
log.debug( "Create thumbnail for " + photo.getUid() );
thumbCreatorThread.createThumbnail( photo );
log.debug( "Thumbnail request submitted" );
}
}
thumbReadyTime = System.currentTimeMillis();
log.debug( "starting to draw" );
// Find the position for the thumbnail
BufferedImage img = thumbnail.getImage();
if ( img.getWidth() > columnWidth || img.getHeight() > rowHeight ) {
/*
If the image is too large for the space reserved for thumbnail, crop
(yes, this should not be possible but many kinds of miracles do
happen. Also this has happened in some weird test cases!!!
*/
img = img.getSubimage( 0, 0,
Math.min( img.getWidth(), columnWidth ),
Math.min( img.getHeight(), rowHeight ) );
}
int x = startx + (columnWidth - img.getWidth())/(int)2;
int y = starty + (rowHeight - img.getHeight())/(int)2;
log.debug( "drawing thumbnail" );
// Draw shadow
int offset = isSelected? 2 : 0;
int shadowX[] = { x+3-offset, x+img.getWidth()+1+offset, x+img.getWidth()+1+offset };
int shadowY[] = { y+img.getHeight()+1+offset, y+img.getHeight()+1+offset, y+3-offset };
GeneralPath polyline =
new GeneralPath(GeneralPath.WIND_EVEN_ODD, shadowX.length);
polyline.moveTo(shadowX[0], shadowY[0]);
for (int index = 1; index < shadowX.length; index++) {
polyline.lineTo(shadowX[index], shadowY[index] );
};
BasicStroke shadowStroke = new BasicStroke(4.0f,
BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER );
Stroke oldStroke = g2.getStroke();
g2.setStroke( shadowStroke );
g2.setColor( Color.DARK_GRAY );
g2.draw( polyline );
g2.setStroke( oldStroke );
// Paint thumbnail
g2.drawImage( img, new AffineTransform( 1f, 0f, 0f, 1f, x, y ), null );
if ( useOldThumbnail ) {
creatingThumbIcon.paintIcon( this, g2,
startx + (columnWidth - creatingThumbIcon.getIconWidth())/(int)2,
starty + ( rowHeight - creatingThumbIcon.getIconHeight())/(int)2 );
}
log.debug( "Drawn, drawing decorations" );
if ( isSelected ) {
Stroke prevStroke = g2.getStroke();
Color prevColor = g2.getColor();
g2.setStroke( new BasicStroke( 3.0f) );
g2.setColor( Color.BLUE );
g2.drawRect( x, y, img.getWidth(), img.getHeight() );
g2.setColor( prevColor );
g2.setStroke( prevStroke );
}
thumbDrawnTime = System.currentTimeMillis();
// Increase ypos so that attributes are drawn under the image
ypos += ((int)img.getHeight())/2 + 9;
// Draw the attributes
// Draw the qualoity icon to the upper left corner of the thumbnail
int quality = photo.getQuality();
if ( showQuality && quality != PhotoInfo.QUALITY_UNDEFINED ) {
ImageIcon qualityIcon = qualityIcons[quality];
int qx = startx
+ (columnWidth-img.getWidth()-qualityIcon.getIconWidth())/(int)2;
int qy = starty
+ (rowHeight-img.getHeight()-qualityIcon.getIconHeight())/(int)2;
qualityIcon.paintIcon( this, g2, qx, qy );
}
if ( photo.getRawSettings() != null ) {
// Draw the "RAW" icon
int rx = startx
+ (columnWidth+img.getWidth()-rawIcon.getIconWidth())/(int)2 - 5;
int ry = starty
+ (columnWidth-img.getHeight()-rawIcon.getIconHeight())/(int)2 + 5;
rawIcon.paintIcon( this, g2, rx, ry );
}
Color prevBkg = g2.getBackground();
if ( isSelected ) {
g2.setBackground( Color.BLUE );
} else {
g2.setBackground( this.getBackground() );
}
Font attrFont = new Font( "Arial", Font.PLAIN, 10 );
FontRenderContext frc = g2.getFontRenderContext();
if ( showDate && photo.getShootTime() != null ) {
FuzzyDate fd = new FuzzyDate( photo.getShootTime(), photo.getTimeAccuracy() );
String dateStr = fd.format();
TextLayout txt = new TextLayout( dateStr, attrFont, frc );
// Calculate the position for the text
Rectangle2D bounds = txt.getBounds();
int xpos = startx + ((int)(columnWidth - bounds.getWidth()))/2 - (int)bounds.getMinX();
g2.clearRect( xpos-2, ypos-2,
(int)bounds.getWidth()+4, (int)bounds.getHeight()+4 );
txt.draw( g2, xpos, (int)(ypos + bounds.getHeight()) );
ypos += bounds.getHeight() + 4;
}
String shootPlace = photo.getShootingPlace();
if ( showPlace && shootPlace != null && shootPlace.length() > 0 ) {
TextLayout txt = new TextLayout( photo.getShootingPlace(), attrFont, frc );
// Calculate the position for the text
Rectangle2D bounds = txt.getBounds();
int xpos = startx + ((int)(columnWidth-bounds.getWidth()))/2 - (int)bounds.getMinX();
g2.clearRect( xpos-2, ypos-2,
(int)bounds.getWidth()+4, (int)bounds.getHeight()+4 );
txt.draw( g2, xpos, (int)(ypos + bounds.getHeight()) );
ypos += bounds.getHeight() + 4;
}
g2.setBackground( prevBkg );
txw.commit();
endTime = System.currentTimeMillis();
log.debug( "paintThumbnail: exit " + photo.getUid() );
log.debug( "Thumb fetch " + (thumbReadyTime - startTime ) + " ms" );
log.debug( "Thumb draw " + ( thumbDrawnTime - thumbReadyTime ) + " ms" );