/* * Copyright(c) 2001-2010, FineReport Inc, All Rights Reserved. */ package com.fr.design.style.background.image; import com.fr.base.BaseUtils; import com.fr.base.GraphHelper; import com.fr.base.Style; import com.fr.design.gui.iscrollbar.UIScrollBar; import com.fr.general.ImageWithSuffix; import com.fr.stable.CoreGraphHelper; import javax.swing.JComponent; import javax.swing.JViewport; import javax.swing.Scrollable; import javax.swing.SwingConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Image; import java.awt.Rectangle; import java.util.ArrayList; import java.util.List; /** * The pane use to preview image */ public class ImagePreviewPane extends JComponent implements Scrollable, ImagePreviewer { private ImageWithSuffix image = null; // carl:image style private Style imageStyle = null; private int imageWidth = 0; private int imageHeight = 0; private boolean isLoading = false; private List changeListenerList = new ArrayList(); public ImagePreviewPane() { this.setToolTipText("View Image"); } /** * Return image */ public Image getImage() { return image == null ? null : image.getImage(); } /** * Return image */ public ImageWithSuffix getImageWithSuffix() { return this.image; } public void showLoading() { isLoading = true; setImage(null); repaint(); } @Override public void setImage(Image image) { setImageWithSuffix(ImageWithSuffix.build(image)); } /** * Set image. * * @param image the new image. */ @Override public void setImageWithSuffix(ImageWithSuffix image) { this.image = image; //need to reset the size of JViewPort. if (this.image == null) { if (this.getParent() instanceof JViewport) { UIScrollBar tmpJScrollBar = new UIScrollBar(UIScrollBar.HORIZONTAL); Dimension newDimension = new Dimension( this.getSize().width - tmpJScrollBar.getPreferredSize().height, this.getSize().height - tmpJScrollBar.getPreferredSize().height); ((JViewport) this.getParent()).setPreferredSize(newDimension); (this.getParent()).setSize(newDimension); ((JViewport) this.getParent()).setMinimumSize(newDimension); ((JViewport) this.getParent()).setMaximumSize(newDimension); } } else { //wait for the size of image. isLoading = false; CoreGraphHelper.waitForImage(image); imageWidth = image.getWidth(null); imageHeight = image.getHeight(null); this.setToolTipText("Image Size: " + imageWidth + "x" + imageHeight + "px"); } fireChangeListener(); this.revalidate(); } /** * Paint component. */ @Override public void paintComponent(Graphics g) { super.paintComponent(g); if (isLoading) { g.drawString(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Basic_Image_Loading"), getWidth() / 2 - 25, getHeight() / 2); return; } if (this.getImage() != null) { //draw image. // carl:让imagePreviewPane能预览样式 if (this.getImageStyle() == null) { g.drawImage(this.getImage(), 0, 0, this); } else { GraphHelper.paintImage( g, this.getWidth(), this.getHeight(), this.getImage(), this.getImageStyle().getImageLayout(), BaseUtils.getAlignment4Horizontal(this.getImageStyle()), this.getImageStyle().getVerticalAlignment(), -1, -1 ); } } } @Override public Dimension getPreferredSize() { if (this.image == null) { return super.getPreferredSize(); } return new Dimension(imageWidth, imageHeight); } /** * Add change listener. */ public void addChangeListener(ChangeListener changeListener) { changeListenerList.add(changeListener); } /** * fire change listener when image changed. */ private void fireChangeListener() { if (this.changeListenerList.size() > 0) { ChangeEvent evt = new ChangeEvent(this); for (int i = 0; i < changeListenerList.size(); i++) { changeListenerList.get(i).stateChanged(evt); } } } // --- Scrollable methods --------------------------------------------- /** * Returns the preferred size of the viewport for a view component. * This is implemented to do the default behavior of returning * the preferred size of the component. * * @return the preferredSize of a JViewport * whose view is this Scrollable */ @Override public Dimension getPreferredScrollableViewportSize() { return getPreferredSize(); } /** * Components that display logical rows or columns should compute * the scroll increment that will completely expose one new row * or column, depending on the value of orientation. Ideally, * components should handle a partially exposed row or column by * returning the distance required to completely expose the item. *

* The default implementation of this is to simply return 10% of * the visible area. Subclasses are likely to be able to provide * a much more reasonable value. * * @param visibleRect the view area visible within the viewport * @param orientation either SwingConstants.VERTICAL or * SwingConstants.HORIZONTAL * @param direction less than zero to scroll up/left, greater than * zero for down/right * @return the "unit" increment for scrolling in the specified direction * @throws IllegalArgumentException for an invalid orientation * @see javax.swing.JScrollBar#setUnitIncrement */ public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { switch (orientation) { case SwingConstants.VERTICAL: return visibleRect.height / 10; case SwingConstants.HORIZONTAL: return visibleRect.width / 10; default: throw new IllegalArgumentException("Invalid orientation: " + orientation); } } /** * Components that display logical rows or columns should compute * the scroll increment that will completely expose one block * of rows or columns, depending on the value of orientation. *

* The default implementation of this is to simply return the visible * area. Subclasses will likely be able to provide a much more * reasonable value. * * @param visibleRect the view area visible within the viewport * @param orientation either SwingConstants.VERTICAL or * SwingConstants.HORIZONTAL * @param direction less than zero to scroll up/left, greater than zero * for down/right * @return the "block" increment for scrolling in the specified direction * @throws IllegalArgumentException for an invalid orientation * @see javax.swing.JScrollBar#setBlockIncrement */ @Override public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { switch (orientation) { case SwingConstants.VERTICAL: return visibleRect.height; case SwingConstants.HORIZONTAL: return visibleRect.width; default: throw new IllegalArgumentException("Invalid orientation: " + orientation); } } /** * Returns true if a viewport should always force the width of this * Scrollable to match the width of the viewport. * For example a normal text view that supported line wrapping * would return true here, since it would be undesirable for * wrapped lines to disappear beyond the right * edge of the viewport. Note that returning true for a * Scrollable whose ancestor is a JScrollPane * effectively disables horizontal scrolling. *

* Scrolling containers, like JViewport, * will use this method each time they are validated. * * @return true if a viewport should force the Scrollables * width to match its own */ @Override public boolean getScrollableTracksViewportWidth() { if (getParent() instanceof JViewport) { return (getParent().getWidth() > getPreferredSize().width); } return false; } /** * Returns true if a viewport should always force the height of this * Scrollable to match the height of the viewport. * For example a columnar text view that flowed text in left to * right columns could effectively disable vertical scrolling by * returning true here. *

* Scrolling containers, like JViewport, * will use this method each time they are validated. * * @return true if a viewport should force the Scrollables height * to match its own */ @Override public boolean getScrollableTracksViewportHeight() { if (getParent() instanceof JViewport) { return (getParent().getHeight() > getPreferredSize().height); } return false; } @Override public void setImageStyle(Style imageStyle) { this.imageStyle = imageStyle; } public Style getImageStyle() { return imageStyle; } }