/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 ro.nextreports.designer.util;
/**
* Created by IntelliJ IDEA.
* User: mihai.panaitescu
* Date: Jun 7, 2006
* Time: 1:18:09 PM
*/
import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
import javax.swing.event.MouseInputListener;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.net.URL;
/**
* Created by IntelliJ IDEA.
* User: mihai.panaitescu
* Date: Jun 7, 2006
* Time: 1:18:09 PM
* To change this template use File | Settings | File Templates.
*/
public class DecoratedScrollPane extends JComponent {
private static final double MAX_SIZE = 200;
private JScrollPane theScrollPane;
private JComponent theComponent;
private JPopupMenu thePopupMenu;
private JButton theButton;
private BufferedImage theImage;
private Rectangle theStartRectangle;
private Rectangle theRectangle;
private Point theStartPoint;
private double theScale;
private DecoratedScrollPane(JScrollPane aScrollPane) {
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
theScrollPane = aScrollPane;
theComponent = (JComponent) theScrollPane.getViewport().getView();
theImage = null;
theStartRectangle = null;
theRectangle = null;
theStartPoint = null;
theScale = 0.0;
theButton = new JButton(new AbstractAction("", ImageUtil.getImageIcon("view")) {
public void actionPerformed(ActionEvent e) {
display();
}
});
theButton.setToolTipText(I18NSupport.getString("designer.scroll"));
theScrollPane.setCorner(JScrollPane.LOWER_RIGHT_CORNER, theButton);
setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
MouseInputListener mil = new MouseInputAdapter() {
public void mousePressed(MouseEvent e) {
theStartPoint = e.getPoint();
}
public void mouseReleased(MouseEvent e) {
if (theStartPoint != null) {
Point newPoint = e.getPoint();
int deltaX = (int) ((newPoint.x - theStartPoint.x) / theScale);
int deltaY = (int) ((newPoint.y - theStartPoint.y) / theScale);
scroll(deltaX, deltaY);
}
theStartPoint = null;
theStartRectangle = theRectangle;
}
public void mouseDragged(MouseEvent e) {
if (theStartPoint == null) return;
Point newPoint = e.getPoint();
moveRectangle(newPoint.x - theStartPoint.x, newPoint.y - theStartPoint.y);
}
};
addMouseListener(mil);
addMouseMotionListener(mil);
thePopupMenu = new JPopupMenu();
thePopupMenu.setLayout(new BorderLayout());
thePopupMenu.add(this, BorderLayout.CENTER);
thePopupMenu.setBorder(BorderFactory.createLineBorder(Color.BLACK));
}
public static void decorate(JScrollPane aScrollPane) {
new DecoratedScrollPane(aScrollPane);
}
protected void paintComponent(Graphics g1D) {
if (theImage == null || theRectangle == null) return;
Graphics2D g = (Graphics2D) g1D;
Insets insets = getInsets();
int xOffset = insets.left;
int yOffset = insets.top;
int availableWidth = getWidth() - insets.left - insets.right;
int availableHeight = getHeight() - insets.top - insets.bottom;
g.drawImage(theImage, xOffset, yOffset, null);
Color tmpColor = g.getColor();
Area area = new Area(new Rectangle(xOffset, yOffset, availableWidth, availableHeight));
area.subtract(new Area(theRectangle));
g.setColor(new Color(255, 255, 255, 128));
g.fill(area);
g.setColor(Color.BLACK);
g.draw(theRectangle);
g.setColor(tmpColor);
}
public Dimension getPreferredSize() {
if (theImage == null || theRectangle == null) return new Dimension();
Insets insets = getInsets();
return new Dimension(theImage.getWidth(null) + insets.left + insets.right,
theImage.getHeight(null) + insets.top + insets.bottom);
}
private void display() {
double compWidth = theComponent.getWidth();
double compHeight = theComponent.getHeight();
double scaleX = MAX_SIZE / compWidth;
double scaleY = MAX_SIZE / compHeight;
theScale = Math.min(scaleX, scaleY);
theImage = new BufferedImage((int) (theComponent.getWidth() * theScale),
(int) (theComponent.getHeight() * theScale),
BufferedImage.TYPE_INT_RGB);
Graphics2D g = theImage.createGraphics();
g.scale(theScale, theScale);
theComponent.paint(g);
theStartRectangle = theComponent.getVisibleRect();
Insets insets = getInsets();
theStartRectangle.x = (int) (theScale * theStartRectangle.x + insets.left);
theStartRectangle.y = (int) (theScale * theStartRectangle.y + insets.right);
theStartRectangle.width *= theScale;
theStartRectangle.height *= theScale;
theRectangle = theStartRectangle;
Dimension pref = thePopupMenu.getPreferredSize();
thePopupMenu.show(theButton,
(theButton.getWidth() - pref.width) / 2,
(theButton.getHeight() - pref.height) / 2);
try {
Robot robot = new Robot();
Point centerPoint = new Point(theRectangle.x + theRectangle.width / 2,
theRectangle.y + theRectangle.height / 2);
SwingUtilities.convertPointToScreen(centerPoint, this);
robot.mouseMove(centerPoint.x, centerPoint.y);
} catch (AWTException e) {
e.printStackTrace();
}
}
private void moveRectangle(int aDeltaX, int aDeltaY) {
if (theStartRectangle == null) return;
Insets insets = getInsets();
Rectangle newRect = new Rectangle(theStartRectangle);
newRect.x += aDeltaX;
newRect.y += aDeltaY;
newRect.x = Math.min(Math.max(newRect.x, insets.left), getWidth() - insets.right - newRect.width);
newRect.y = Math.min(Math.max(newRect.y, insets.right), getHeight() - insets.bottom - newRect.height);
Rectangle clip = new Rectangle();
Rectangle.union(theRectangle, newRect, clip);
clip.grow(2, 2);
theRectangle = newRect;
paintImmediately(clip);
}
private void scroll(int aDeltaX, int aDeltaY) {
JComponent component = (JComponent) theScrollPane.getViewport().getView();
Rectangle rect = component.getVisibleRect();
rect.x += aDeltaX;
rect.y += aDeltaY;
component.scrollRectToVisible(rect);
thePopupMenu.setVisible(false);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
JFrame frame = new JFrame(DecoratedScrollPane.class.getName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
URL imageURL = new URL("http://www.aboutstonehenge.info/images/education/stonehenge-wallpaper-1.jpg");
JLabel label = new JLabel(new ImageIcon(ImageIO.read(imageURL)));
JScrollPane scrollPane = new JScrollPane(label);
new DecoratedScrollPane(scrollPane);
frame.setContentPane(scrollPane);
frame.pack();
frame.setVisible(true);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}