Mega Code Archive

 
Categories / Java / Swing JFC
 

Container which can transform its children

/*  * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle,  * Santa Clara, California 95054, U.S.A. All rights reserved.  *  * This library is free software; you can redistribute it and/or  * modify it under the terms of the GNU Lesser General Public  * License as published by the Free Software Foundation; either  * version 2.1 of the License, or (at your option) any later version.  *  * This library is distributed in the hope that it will be useful,  * but WITHOUT ANY WARRANTY; without even the implied warranty of  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  * Lesser General Public License for more details.  *  * You should have received a copy of the GNU Lesser General Public  * License along with this library; if not, write to the Free Software  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  */ import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.awt.geom.AffineTransform; import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Point2D; import java.util.Map; import java.util.HashMap; /**  * Container which can transform its children, for example:<br>  * <pre>  * JButton button = new JButton("Hello");  * JXTransformer t = new JXTransformer(button);  * t.rotate(Math.PI/2);</pre>   *   * <strong>Note:</strong>  * This component was designed to transform simple components   * like JButton, JLabel etc.     *   * @author Alexander Potochkin  *   * https://swinghelper.dev.java.net/  * http://weblogs.java.net/blog/alexfromsun/   */ public class JXTransformer extends JPanel {     private Component glassPane = new MagicGlassPane();     private Component view;     private Rectangle visibleRect;     private Map<?,?> renderingHints;     private AffineTransform at;     public JXTransformer() {         this(null);     }     public JXTransformer(JComponent view) {         this(view, new AffineTransform());     }     public JXTransformer(JComponent view, AffineTransform at) {         super(null);         setTransform(at);         super.addImpl(glassPane, null, 0);         setView(view);         Handler handler = new Handler();         addHierarchyBoundsListener(handler);         addComponentListener(handler);             }     public Component getView() {         return view;     }     public void setView(Component view) {         if (getView() != null) {             super.remove(getView());         }         if (view != null) {             super.addImpl(view, null, 1);         }         this.view = view;         doLayout();         revalidate();         repaint();     }     public Map<?,?> getRenderingHints() {         if (renderingHints == null) {             return null;         }         return new HashMap<Object,Object>(renderingHints);     }     public void setRenderingHints(Map<?,?> renderingHints) {         if (renderingHints == null) {             this.renderingHints = null;         } else {             this.renderingHints = new HashMap<Object,Object>(renderingHints);         }         repaint();     }     protected void addImpl(Component comp, Object constraints, int index) {         setView(comp);     }     public void remove(int index) {         Component c = getComponent(index);         if (c == view) {             view = null;             super.remove(index);         } else if (c == glassPane) {             throw new IllegalArgumentException("GlassPane can't be removed");         } else {             throw new AssertionError("Unknown component with index " + index);         }     }     public void removeAll() {         remove(view);     }     //This is important     public boolean isOptimizedDrawingEnabled() {         return false;     }     public void setLayout(LayoutManager mgr) {         if (mgr != null) {             throw new IllegalArgumentException("Only null layout is supported");         }         super.setLayout(mgr);     }     public void doLayout() {         if (view != null) {             view.setSize(view.getPreferredSize());             visibleRect = getVisibleRect();             view.setLocation(visibleRect.x, visibleRect.y);         }         glassPane.setLocation(0, 0);         glassPane.setSize(getWidth(), getHeight());     }     public Dimension getPreferredSize() {         if (isPreferredSizeSet()) {             return super.getPreferredSize();         }         Dimension size = getTransformedSize().getSize();         Insets insets = getInsets();         size.width += insets.left + insets.right;         size.height += insets.top + insets.bottom;         return size;     }     private Rectangle getTransformedSize() {         if (view != null) {             Dimension viewSize = view.getSize();             Rectangle viewRect = new Rectangle(viewSize);             return at.createTransformedShape(viewRect).getBounds();         }         return new Rectangle(super.getPreferredSize());     }     public void paint(Graphics g) {         //repaint the whole transformer in case the view component was repainted         Rectangle clipBounds = g.getClipBounds();                 if (clipBounds != null && !clipBounds.equals(visibleRect)) {             repaint();         }         //clear the background         g.setColor(getBackground());         g.fillRect(0, 0, getWidth(), getHeight());         if (view != null && at.getDeterminant() != 0) {             Graphics2D g2 = (Graphics2D) g.create();             Insets insets = getInsets();             Rectangle bounds = getBounds();                          //don't forget about insets             bounds.x += insets.left;             bounds.y += insets.top;             bounds.width -= insets.left + insets.right;             bounds.height -= insets.top + insets.bottom;             double centerX1 = bounds.getCenterX();             double centerY1 = bounds.getCenterY();             Rectangle tb = getTransformedSize();             double centerX2 = tb.getCenterX();             double centerY2 = tb.getCenterY();             //set antialiasing by default             g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);             if (renderingHints != null) {                 g2.addRenderingHints(renderingHints);             }             //translate it to the center of the view component again             double tx = centerX1 - centerX2 - getX();             double ty = centerY1 - centerY2 - getY();             g2.translate((int) tx, (int) ty);             g2.transform(at);             view.paint(g2);             g2.dispose();         }         //paint the border         paintBorder(g);     }     private class MagicGlassPane extends JPanel {         private Component mouseEnteredComponent;         private Component mouseDraggedComponent;         private Component mouseCurrentComponent;         public MagicGlassPane() {             super(null);             setOpaque(false);             enableEvents(AWTEvent.MOUSE_EVENT_MASK);             enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);             enableEvents(AWTEvent.MOUSE_WHEEL_EVENT_MASK);             ToolTipManager.sharedInstance().registerComponent(this);         }         private MouseEvent transformMouseEvent(MouseEvent event) {             if (event == null) {                 throw new IllegalArgumentException("MouseEvent is null");             }             MouseEvent newEvent;             if (event instanceof MouseWheelEvent) {                 MouseWheelEvent mouseWheelEvent = (MouseWheelEvent) event;                 newEvent = new MouseWheelEvent(mouseWheelEvent.getComponent(), mouseWheelEvent.getID(),                         mouseWheelEvent.getWhen(), mouseWheelEvent.getModifiers(),                         mouseWheelEvent.getX(), mouseWheelEvent.getY(),                         mouseWheelEvent.getClickCount(), mouseWheelEvent.isPopupTrigger(),                         mouseWheelEvent.getScrollType(), mouseWheelEvent.getScrollAmount(),                         mouseWheelEvent.getWheelRotation());             } else {                 newEvent = new MouseEvent(event.getComponent(), event.getID(),                         event.getWhen(), event.getModifiers(),                         event.getX(), event.getY(),                         event.getClickCount(), event.isPopupTrigger(), event.getButton());             }             if (view != null && at.getDeterminant() != 0) {                 Rectangle viewBounds = getTransformedSize();                 Insets insets = JXTransformer.this.getInsets();                 int xgap = (getWidth() - (viewBounds.width + insets.left + insets.right)) / 2;                 int ygap = (getHeight() - (viewBounds.height + insets.top + insets.bottom)) / 2;                                  double x = newEvent.getX() + viewBounds.getX() - insets.left;                 double y = newEvent.getY() + viewBounds.getY() - insets.top;                 Point2D p = new Point2D.Double(x - xgap, y - ygap);                 Point2D tp;                 try {                     tp = at.inverseTransform(p, null);                 } catch (NoninvertibleTransformException ex) {                     //can't happen, we check it before                     throw new AssertionError("NoninvertibleTransformException");                 }                 //Use transformed coordinates to get the current component                 mouseCurrentComponent =                         SwingUtilities.getDeepestComponentAt(view, (int) tp.getX(), (int) tp.getY());                 if (mouseCurrentComponent == null) {                     mouseCurrentComponent = JXTransformer.this;                 }                 Component tempComponent = mouseCurrentComponent;                 if (mouseDraggedComponent != null) {                     tempComponent = mouseDraggedComponent;                 }                 Point point = SwingUtilities.convertPoint(view, (int) tp.getX(), (int) tp.getY(), tempComponent);                 newEvent.setSource(tempComponent);                 newEvent.translatePoint(point.x - event.getX(), point.y - event.getY());             }             return newEvent;         }         protected void processMouseEvent(MouseEvent e) {             MouseEvent transformedEvent = transformMouseEvent(e);             switch (e.getID()) {                 case MouseEvent.MOUSE_ENTERED:                     if (mouseDraggedComponent == null || mouseCurrentComponent == mouseDraggedComponent) {                         dispatchMouseEvent(transformedEvent);                     }                     break;                 case MouseEvent.MOUSE_EXITED:                     if (mouseEnteredComponent != null) {                         dispatchMouseEvent(createEnterExitEvent(mouseEnteredComponent, MouseEvent.MOUSE_EXITED, e));                         mouseEnteredComponent = null;                     }                     break;                 case MouseEvent.MOUSE_RELEASED:                     if (mouseDraggedComponent != null && e.getButton() == MouseEvent.BUTTON1) {                         transformedEvent.setSource(mouseDraggedComponent);                         mouseDraggedComponent = null;                     }                     dispatchMouseEvent(transformedEvent);                     break;                 default:                     dispatchMouseEvent(transformedEvent);             }             super.processMouseEvent(e);         }         private void dispatchMouseEvent(MouseEvent event) {             MouseListener[] mouseListeners =                     event.getComponent().getMouseListeners();             for (MouseListener listener : mouseListeners) {                 //skip all ToolTipManager's related listeners                 if (!listener.getClass().getName().startsWith("javax.swing.ToolTipManager")) {                     switch (event.getID()) {                         case MouseEvent.MOUSE_PRESSED:                             listener.mousePressed(event);                             break;                         case MouseEvent.MOUSE_RELEASED:                             listener.mouseReleased(event);                             break;                         case MouseEvent.MOUSE_CLICKED:                             listener.mouseClicked(event);                             break;                         case MouseEvent.MOUSE_EXITED:                             listener.mouseExited(event);                             break;                         case MouseEvent.MOUSE_ENTERED:                             listener.mouseEntered(event);                             break;                         default:                             throw new AssertionError();                     }                 }             }         }         protected void processMouseMotionEvent(MouseEvent e) {             MouseEvent transformedEvent = transformMouseEvent(e);             if (mouseEnteredComponent == null) {                 mouseEnteredComponent = mouseCurrentComponent;             }             switch (e.getID()) {                 case MouseEvent.MOUSE_MOVED:                     if (mouseCurrentComponent != mouseEnteredComponent) {                         dispatchMouseEvent(createEnterExitEvent(mouseEnteredComponent, MouseEvent.MOUSE_EXITED, e));                         dispatchMouseEvent(createEnterExitEvent(mouseCurrentComponent, MouseEvent.MOUSE_ENTERED, e));                     }                     break;                 case MouseEvent.MOUSE_DRAGGED:                     if (mouseDraggedComponent == null) {                         mouseDraggedComponent = mouseEnteredComponent;                     }                     if (mouseEnteredComponent == mouseDraggedComponent && mouseCurrentComponent != mouseDraggedComponent) {                         dispatchMouseEvent(createEnterExitEvent(mouseDraggedComponent, MouseEvent.MOUSE_EXITED, e));                     } else if (mouseEnteredComponent != mouseDraggedComponent && mouseCurrentComponent == mouseDraggedComponent) {                         dispatchMouseEvent(createEnterExitEvent(mouseDraggedComponent, MouseEvent.MOUSE_ENTERED, e));                     }                     if (mouseDraggedComponent != null) {                         transformedEvent.setSource(mouseDraggedComponent);                     }                     break;             }             mouseEnteredComponent = mouseCurrentComponent;             //dispatch MouseMotionEvent             MouseMotionListener[] mouseMotionListeners =                     transformedEvent.getComponent().getMouseMotionListeners();             for (MouseMotionListener listener : mouseMotionListeners) {                 //skip all ToolTipManager's related listeners                 if (!listener.getClass().getName().startsWith("javax.swing.ToolTipManager")) {                     switch (transformedEvent.getID()) {                         case MouseEvent.MOUSE_MOVED:                             listener.mouseMoved(transformedEvent);                             break;                         case MouseEvent.MOUSE_DRAGGED:                             listener.mouseDragged(transformedEvent);                             break;                         default:                             throw new AssertionError();                     }                 }             }             super.processMouseMotionEvent(e);         }         protected void processMouseWheelEvent(MouseWheelEvent e) {             MouseWheelEvent transformedEvent = (MouseWheelEvent) transformMouseEvent(e);             MouseWheelListener[] mouseWheelListeners =                     transformedEvent.getComponent().getMouseWheelListeners();             for (MouseWheelListener listener : mouseWheelListeners) {                 listener.mouseWheelMoved(transformedEvent);             }             super.processMouseWheelEvent(e);         }         public String getToolTipText(MouseEvent event) {             if (mouseEnteredComponent instanceof JComponent) {                 return ((JComponent) mouseEnteredComponent).getToolTipText();             }             return null;         }         private MouseEvent createEnterExitEvent(Component c, int eventId, MouseEvent mouseEvent) {             return new MouseEvent(c, eventId, mouseEvent.getWhen(), 0,                     mouseEvent.getX(), mouseEvent.getY(), 0,                     false, MouseEvent.NOBUTTON);         }         public String toString() {             return "GlassPane";         }     }     /**      * This class helps view component to be in the visible area;      * this is important when transformer is inside JScrollPane       */          private class Handler extends ComponentAdapter implements HierarchyBoundsListener {         public void componentMoved(ComponentEvent e) {             update();         }         public void ancestorMoved(HierarchyEvent e) {             update();         }         public void ancestorResized(HierarchyEvent e) {             update();         }         private void update() {             if (!getVisibleRect().equals(visibleRect)) {                 revalidate();             }         }     }     /**      * Never returns null      */     public AffineTransform getTransform() {         return new AffineTransform(at);     }     public void setTransform(AffineTransform at) {         if (at == null) {             throw new IllegalArgumentException("AffineTransform is null");         }         this.at = new AffineTransform(at);         revalidate();         repaint();     }     public void rotate(double theta) {         AffineTransform transform = getTransform();         transform.rotate(theta);         setTransform(transform);     }     public void scale(double sx, double sy) {         AffineTransform transform = getTransform();         transform.scale(sx, sy);         setTransform(transform);     }     public void shear(double sx, double sy) {         AffineTransform transform = getTransform();         transform.shear(sx, sy);         setTransform(transform);     } } ///////////// /*  * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle,  * Santa Clara, California 95054, U.S.A. All rights reserved.  *  * This library is free software; you can redistribute it and/or  * modify it under the terms of the GNU Lesser General Public  * License as published by the Free Software Foundation; either  * version 2.1 of the License, or (at your option) any later version.  *  * This library is distributed in the hope that it will be useful,  * but WITHOUT ANY WARRANTY; without even the implied warranty of  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  * Lesser General Public License for more details.  *  * You should have received a copy of the GNU Lesser General Public  * License along with this library; if not, write to the Free Software  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  */ import javax.swing.*; import javax.swing.border.TitledBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.*; import java.awt.event.*; import java.awt.geom.AffineTransform; import java.util.ArrayList; import java.util.List; import java.util.Vector; /*  * @author Alexander Potochkin  *   * https://swinghelper.dev.java.net/  * http://weblogs.java.net/blog/alexfromsun/   */ class TransformerDemo extends JFrame implements ChangeListener {     private List<JXTransformer> transformers = new ArrayList<JXTransformer>();     private JSlider rotationSlider;     private JSlider scalingSlider;     private JSlider shearingSlider;     public TransformerDemo() {         super("Transformer demo");         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);         JMenuBar bar = new JMenuBar();         JMenu lafMenu = new JMenu("LaF");         JMenuItem winLaf = new JMenuItem("Windows LaF");         lafMenu.add(winLaf);         winLaf.addActionListener(new ActionListener() {             public void actionPerformed(ActionEvent e) {                 setLaf("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");             }         });         JMenuItem motifLaf = new JMenuItem("Motif LaF");         lafMenu.add(motifLaf);         motifLaf.addActionListener(new ActionListener() {             public void actionPerformed(ActionEvent e) {                 setLaf("com.sun.java.swing.plaf.motif.MotifLookAndFeel");             }         });         bar.add(lafMenu);         JMenuItem metalLaf = new JMenuItem("Metal LaF");         lafMenu.add(metalLaf);         metalLaf.addActionListener(new ActionListener() {             public void actionPerformed(ActionEvent e) {                 setLaf("javax.swing.plaf.metal.MetalLookAndFeel");             }         });         JMenu settingsMenu = new JMenu("Settings");         settingsMenu.setMnemonic(KeyEvent.VK_S);         JMenuItem item = new JMenuItem("Reset sliders", KeyEvent.VK_R);         item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.ALT_MASK));         item.addActionListener(new ActionListener() {             public void actionPerformed(ActionEvent e) {                 rotationSlider.setValue(0);                 scalingSlider.setValue(100);                 shearingSlider.setValue(0);             }         });         settingsMenu.add(item);         bar.add(settingsMenu);         setJMenuBar(bar);         JPanel panel = new JPanel(new BorderLayout());         panel.add(createDemoPanel());         panel.add(createStressTestPanel(), BorderLayout.EAST);         add(new JScrollPane(panel));         add(new JScrollPane(createToolPanel()), BorderLayout.SOUTH);         pack();     }     private void setLaf(String laf) {         try {             UIManager.setLookAndFeel(laf);             SwingUtilities.updateComponentTreeUI(this);         } catch (Exception e) {             e.printStackTrace();         }         for (JXTransformer t : transformers) {             t.revalidate();             t.repaint();         }     }     private JPanel createStressTestPanel() {         JPanel panel = new JPanel();         TitledBorder titledBorder = BorderFactory.createTitledBorder("Stress test (with tooltips)");         titledBorder.setTitleJustification(TitledBorder.CENTER);         panel.setBorder(titledBorder);         JButton lowerButton = new JButton("Button");         lowerButton.setLayout(new FlowLayout());         lowerButton.setToolTipText("Lower button");         JButton middleButton = new JButton();         middleButton.setToolTipText("Middle button");         middleButton.setLayout(new FlowLayout());         lowerButton.add(middleButton);         JButton upperButton = new JButton("Upper button");         upperButton.setToolTipText("Upper button");         middleButton.add(upperButton);         panel.add(createTransformer(lowerButton));         return panel;     }     private JPanel createDemoPanel() {         JPanel buttonPanel = new JPanel(new GridLayout(3, 2));         TitledBorder titledBorder = BorderFactory.createTitledBorder("Try three sliders below !");         Font titleFont = titledBorder.getTitleFont();         titledBorder.setTitleFont(titleFont.deriveFont(titleFont.getSize2D() + 10));         titledBorder.setTitleJustification(TitledBorder.CENTER);         buttonPanel.setBorder(titledBorder);         JButton b = new JButton("JButton");         b.setPreferredSize(new Dimension(100,50));         buttonPanel.add(createTransformer(b));         Vector<String> v = new Vector<String>();         v.add("One");         v.add("Two");         v.add("Three");         JList list = new JList(v);         buttonPanel.add(createTransformer(list));                  buttonPanel.add(createTransformer(new JCheckBox("JCheckBox")));                  JSlider slider = new JSlider(0, 100);         slider.setLabelTable(slider.createStandardLabels(25, 0));         slider.setPaintLabels(true);         slider.setPaintTicks(true);         slider.setMajorTickSpacing(10);         buttonPanel.add(createTransformer(slider));         buttonPanel.add(createTransformer(new JRadioButton("JRadioButton")));         final JLabel label = new JLabel("JLabel");         label.addMouseListener(new MouseAdapter() {             public void mouseEntered(MouseEvent e) {                 Font font = label.getFont();                 label.setFont(font.deriveFont(font.getSize2D() + 10));             }             public void mouseExited(MouseEvent e) {                 Font font = label.getFont();                 label.setFont(font.deriveFont(font.getSize2D() - 10));             }         });         buttonPanel.add(createTransformer(label));         return buttonPanel;     }     private JXTransformer createTransformer(JComponent c) {         JXTransformer t = new JXTransformer(c);         transformers.add(t);         return t;     }     private JPanel createToolPanel() {         JPanel panel = new JPanel(new GridLayout(1, 0));         rotationSlider = new JSlider(-180, 180, 0);         rotationSlider.setLabelTable(rotationSlider.createStandardLabels(90, -180));         rotationSlider.setPaintLabels(true);         rotationSlider.setPaintTicks(true);         rotationSlider.setMajorTickSpacing(45);         rotationSlider.addChangeListener(this);         rotationSlider.setBorder(BorderFactory.createTitledBorder("Rotate"));         panel.add(rotationSlider);         shearingSlider = new JSlider(-10, 10, 0);         shearingSlider.setLabelTable(shearingSlider.createStandardLabels(5, -10));         shearingSlider.setPaintLabels(true);         shearingSlider.setPaintTicks(true);         shearingSlider.setMajorTickSpacing(2);         shearingSlider.addChangeListener(this);         shearingSlider.setBorder(BorderFactory.createTitledBorder("Shear"));         panel.add(shearingSlider);                  scalingSlider = new JSlider(50, 150, 100);         scalingSlider.setLabelTable(scalingSlider.createStandardLabels(25, 50));         scalingSlider.setPaintLabels(true);         scalingSlider.setPaintTicks(true);         scalingSlider.setMajorTickSpacing(10);         scalingSlider.addChangeListener(this);         scalingSlider.setBorder(BorderFactory.createTitledBorder("Scale"));         panel.add(scalingSlider);         return panel;     }     public void stateChanged(ChangeEvent e) {         AffineTransform at = new AffineTransform();         at.rotate(rotationSlider.getValue() * Math.PI / 180);         double scale = scalingSlider.getValue() / 100.0;         at.scale(scale, scale);         double shear = shearingSlider.getValue() / 10.0;         at.shear(shear, 0);         for (JXTransformer t : transformers) {             t.setTransform(at);         }     }     public static void main(String[] args) {         TransformerDemo demo = new TransformerDemo();         demo.setSize(800, 600);         demo.setVisible(true);     } }