001    /////////////////////////////////////////////////
002    //This file is part of Sears project.
003    //Subtitle Editor And Re-Synch
004    //A tool to easily modify and resynch movies subtitles.
005    /////////////////////////////////////////////////
006    //This program is free software; 
007    //you can redistribute it and/or modify it under the terms 
008    //of the GNU General Public License 
009    //as published by the Free Software Foundation; 
010    //either version 2 of the License, or (at your option) any later version.
011    /////////////////////////////////////////////////
012    //Sears project is available under sourceforge
013    //at adress: http://sourceforge.net/projects/sears/
014    //Copyright (C) 2005 Booba Skaya
015    //Mail: booba.skaya@gmail.com
016    /////////////////////////////////////////////////
017    
018    // some suggestions about this class: floriaen@gmail.com
019    
020    package sears.gui.glassPane;
021    
022    import java.awt.Graphics;
023    import java.awt.Graphics2D;
024    import java.awt.Rectangle;
025    
026    import javax.swing.JComponent;
027    import javax.swing.JFrame;
028    import javax.swing.JViewport;
029    import javax.swing.SwingUtilities;
030    
031    /**
032     * <p>
033     * This class provides a way to have a virtual rectangle over a viewport
034     * with viewport size and position.
035     * <br>Let the register listener and a resize of the viewport will affect the virtual bounds.
036     * <br>The advantage of this resides in the fact that you can do the same things out and inside of 
037     * this virtual bounds.
038     * </p>
039     * <b>How to use it:</b>
040     * <pre>
041     * <i>// init components:</i>
042     * JComponent component = new JComponent();
043     * JScrollPane scrollPane = new JScrollPane(component);
044     * frame.add(scrollPane);
045     *      
046     * <i>// set up the <code>ViewportGlassPane</code> object</i>
047     * ViewportGlassPane gp = new ViewPortGlassPane(scrollPane.getViewport());
048     * <i>// this method simply call frame.setGlassPane(gp) method</i>
049     * gp.addAsAGlassPane(frame);
050     * 
051     * (...)
052     *      
053     * EventQueue.invokeLater(new Runnable() {
054     *      public void run() {
055     *              gp.setVisible(true);
056     *      }
057     * });
058     * </pre>
059     * 
060     * @see JViewport
061     */
062    public abstract class ViewportGlassPane extends JComponent {
063    
064            private static final long serialVersionUID = 5504986050347441090L;
065    
066            private JViewport viewport;     
067            private Rectangle virtualBounds;
068            private ViewportListener listener;
069    
070            /**
071             * Constructs a new <code>ViewportGlassPane</code> instance
072             * <br>Register a component listener, instance of <code>ViewportListener</code> to the viewport.
073             * <br>Resizing the view (viewport) will have no indesirable effect on the virtual bounds
074             * 
075             * @param viewport      the viewport on which the virtual bounds is set
076             * @throws                      NullPointerException if viewport is null
077             */
078            public ViewportGlassPane(JViewport viewport) {
079                    super();
080                    if( viewport == null ) {
081                            throw new NullPointerException("viewport cannot be null");
082                    }
083                    this.viewport = viewport;
084                    listener = new ViewportListener(this);
085                    viewport.addComponentListener(listener);
086            }
087            
088            /**
089             * Removes the listener associate to the viewport by the class constructor
090             * <br><b>SECURITY:</b>
091             * this method require that object which calls it knows and have an access 
092             * to the viewport gives in parameter of the class constructor
093             * 
094             * @param viewport      must be equals to the one given in the class constructor parameter
095             * @see                         Object#equals(Object)
096             */
097            protected void removeViewportListener(JViewport viewport) {
098                    if( viewport.equals(this.viewport)) {
099                            viewport.removeComponentListener(listener);
100                    }
101            }
102    
103            /*
104             * (non-Javadoc)
105             * @see javax.swing.JComponent#paint(java.awt.Graphics)
106             */
107            public void paintComponent(Graphics g) {
108                    super.paintComponent(g);
109                    if( g instanceof Graphics2D ) {
110                            Graphics2D gr = (Graphics2D) g;
111                            paintComponentWithGraphics(gr);
112                    }
113            }
114    
115            /**
116             * This method is called in <code>paint(g)</code> method.
117             * Allow a way to use the graphics context of this component
118             * 
119             * @param gr the graphics context of this component
120             */
121            protected abstract void paintComponentWithGraphics(Graphics2D gr);
122    
123            /**
124             * When viewport changed when a resize is set on it.
125             * And so, is needed to recalculate the virtual bounds
126             */
127            public void fireViewportSizeChanged() {
128                    virtualBounds = null;
129            }
130    
131            /**
132             * Determines, if it is not already do, the virtual bounds size and position
133             * @return the virtual bonds as a <code>Rectangle</code> object
134             */
135            public Rectangle getVirtualBounds() {
136                    if( virtualBounds == null ) {
137                            virtualBounds = SwingUtilities.convertRectangle(viewport, viewport.getVisibleRect(), this);
138                    }
139                    return virtualBounds;
140            }
141            
142            /**
143             * Sets this as the glass pane of the frame given in parameters.
144             * If frame is null this method is a no op.
145             * @param frame if null nothing is done
146             * @see JFrame#setGlassPane(java.awt.Component)
147             */
148            public void addAsAGlassPane(JFrame frame) {
149                    if( frame != null ) {           
150                            frame.setGlassPane(this);
151                    }
152            }
153    
154            /**
155             * Convert and return the component's graphics context
156             * @return      the component's graphics context or null if it is null 
157             *                      or not instance of <code>Graphics2D</code>
158             */
159            @Deprecated
160            protected Graphics2D getGraphics2D() {
161                    Graphics2D gr = null;
162                    Graphics g = getGraphics();
163                    if( g != null ) {
164                            if( g instanceof Graphics2D ) {
165                                    gr = (Graphics2D) g;
166                            }
167                    }
168                    return gr;
169            }
170    }