001    package org.jfree.chart.block;
002    
003    import java.awt.Color;
004    import java.awt.Font;
005    import java.awt.Graphics2D;
006    import java.awt.Paint;
007    import java.awt.Shape;
008    import java.awt.geom.Rectangle2D;
009    import java.io.IOException;
010    import java.io.ObjectInputStream;
011    import java.io.ObjectOutputStream;
012    
013    import org.jfree.chart.entity.ChartEntity;
014    import org.jfree.chart.entity.StandardEntityCollection;
015    import org.jfree.io.SerialUtilities;
016    import org.jfree.text.TextBlock;
017    import org.jfree.text.TextBlockAnchor;
018    import org.jfree.text.TextUtilities;
019    import org.jfree.ui.HorizontalAlignment;
020    import org.jfree.ui.Size2D;
021    import org.jfree.util.ObjectUtilities;
022    import org.jfree.util.PaintUtilities;
023    import org.jfree.util.PublicCloneable;
024    
025    /**
026     * A block containing a label.
027     */
028    public class LabelBlock extends AbstractBlock 
029                                    implements Block, PublicCloneable {
030        
031        /** For serialization. */
032        static final long serialVersionUID = 249626098864178017L;
033    
034        /** 
035         * The text for the label - retained in case the label needs 
036         * regenerating (for example, to change the font). 
037         */
038        private String text;
039        
040        /** The label. */
041        private TextBlock label;
042        
043        /** The font. */
044        private Font font;
045        
046        /** The tool tip text (can be <code>null</code>). */
047        private String toolTipText;
048        
049        /** The URL text (can be <code>null</code>). */
050        private String urlText;
051        
052        /** The default color. */
053        public static final Paint DEFAULT_PAINT = Color.black;
054    
055        /** The paint. */
056        private transient Paint paint;
057        
058        /**
059         * Creates a new label block.
060         * 
061         * @param label  the label (<code>null</code> not permitted).
062         */
063        public LabelBlock(String label) {
064            this(label, new Font("SansSerif", Font.PLAIN, 10), DEFAULT_PAINT);
065        }
066        
067        /**
068         * Creates a new label block.
069         * 
070         * @param text  the text for the label (<code>null</code> not permitted).
071         * @param font  the font (<code>null</code> not permitted).
072         */
073        public LabelBlock(String text, Font font) {        
074            this(text, font, DEFAULT_PAINT);
075        }
076        
077        /**
078         * Creates a new label block.
079         *
080         * @param text  the text for the label (<code>null</code> not permitted).
081         * @param font  the font (<code>null</code> not permitted).
082         * @param paint the paint (<code>null</code> not permitted).
083         */
084        public LabelBlock(String text, Font font, Paint paint) {  
085            this.text = text;
086            this.paint = paint; 
087            this.label = TextUtilities.createTextBlock(text, font, this.paint); 
088            this.label.setLineAlignment(HorizontalAlignment.LEFT);
089            this.font = font;
090            this.toolTipText = null;
091            this.urlText = null;
092        }
093        
094        /**
095         * Returns the font.
096         * @return The font (never <code>null</code>).
097         */
098        public Font getFont() {
099            return this.font;    
100        }
101        
102        /**
103         * Sets the font and regenerates the label.
104         * @param font  the font (<code>null</code> not permitted).
105         */
106        public void setFont(Font font) {
107            if (font == null) {
108                throw new IllegalArgumentException("Null 'font' argument.");
109            }
110            this.font = font;
111            this.label = TextUtilities.createTextBlock(this.text, font, this.paint);
112            this.label.setLineAlignment(HorizontalAlignment.LEFT); 
113        }
114       
115        /**
116         * Returns the paint.
117         * @return The paint (never <code>null</code>).
118         */
119        public Paint getPaint() {
120            return this.paint;   
121        }
122       
123        /**
124         * Sets the paint and regenerates the label.
125         * @param paint  the paint (<code>null</code> not permitted).
126         */
127        public void setPaint(Paint paint) {
128            if (paint == null) {
129                throw new IllegalArgumentException("Null 'paint' argument.");
130            }
131            this.paint = paint;
132            this.label = TextUtilities.createTextBlock(this.text, this.font, this.paint);
133            this.label.setLineAlignment(HorizontalAlignment.LEFT); 
134        }
135    
136        /**
137         * Returns the tool tip text.
138         * @return The tool tip text (possibly <code>null</code>).
139         */
140        public String getToolTipText() {
141            return this.toolTipText;
142        }
143        
144        /**
145         * Sets the tool tip text.
146         * @param text  the text (<code>null</code> permitted).
147         */
148        public void setToolTipText(String text) {
149            this.toolTipText = text;   
150        }
151        
152        /**
153         * Returns the URL text.
154         * @return The URL text (possibly <code>null</code>).
155         */
156        public String getURLText() {
157            return this.urlText;
158        }
159        
160        /**
161         * Sets the URL text.
162         * @param text  the text (<code>null</code> permitted).
163         */
164        public void setURLText(String text) {
165            this.urlText = text;   
166        }
167        
168        /**
169         * Arranges the contents of the block, within the given constraints, and 
170         * returns the block size.
171         * 
172         * @param g2  the graphics device.
173         * @param constraint  the constraint (<code>null</code> not permitted).
174         * 
175         * @return The block size (in Java2D units, never <code>null</code>).
176         */
177        public Size2D arrange(Graphics2D g2, RectangleConstraint constraint) {
178            g2.setFont(this.font);
179            Size2D s = this.label.calculateDimensions(g2);
180            return new Size2D(calculateTotalWidth(s.getWidth()), 
181                    calculateTotalHeight(s.getHeight()));
182        }
183        
184        /**
185         * Draws the block.
186         * 
187         * @param g2  the graphics device.
188         * @param area  the area.
189         */
190        public void draw(Graphics2D g2, Rectangle2D area) {
191            draw(g2, area, null);
192        }
193        
194        /**
195         * Draws the block within the specified area.
196         * 
197         * @param g2  the graphics device.
198         * @param area  the area.
199         * @param params  ignored (<code>null</code> permitted).
200         * 
201         * @return Always <code>null</code>.
202         */
203        public Object draw(Graphics2D g2, Rectangle2D area, Object params) {
204            area = trimMargin(area);
205            drawBorder(g2, area);
206            area = trimBorder(area);
207            area = trimPadding(area);
208            
209            // check if we need to collect chart entities from the container
210            EntityBlockParams ebp = null;
211            StandardEntityCollection sec = null;
212            Shape entityArea = null;
213            if (params instanceof EntityBlockParams) {
214                ebp = (EntityBlockParams) params;
215                if (ebp.getGenerateEntities()) {
216                    sec = new StandardEntityCollection();
217                    entityArea = (Shape) area.clone();
218                }
219            }
220            g2.setPaint(this.paint);
221            g2.setFont(this.font);
222            this.label.draw(g2, (float) area.getX(), (float) area.getY(), 
223                    TextBlockAnchor.TOP_LEFT);
224            BlockResult result = null;
225            if (ebp != null && sec != null) {
226                if (this.toolTipText != null || this.urlText != null) {
227                    ChartEntity entity = new ChartEntity(entityArea, 
228                            this.toolTipText, this.urlText);   
229                    sec.add(entity);
230                    result = new BlockResult();
231                    result.setEntityCollection(sec);
232                }
233            }
234            return result;
235        }
236        
237        /**
238         * Tests this <code>LabelBlock</code> for equality with an arbitrary 
239         * object.
240         * 
241         * @param obj  the object (<code>null</code> permitted).
242         * 
243         * @return A boolean.
244         */
245        public boolean equals(Object obj) {
246            if (!(obj instanceof LabelBlock)) {
247                return false;
248            }
249            LabelBlock that = (LabelBlock) obj;
250            if (!this.text.equals(that.text)) {
251                return false;
252            }
253            if (!this.font.equals(that.font)) {
254                return false;
255            }
256            if (!PaintUtilities.equal(this.paint, that.paint)) {
257                return false;
258            }
259            if (!ObjectUtilities.equal(this.toolTipText, that.toolTipText)) {
260                return false;
261            }
262            if (!ObjectUtilities.equal(this.urlText, that.urlText)) {
263                return false;
264            }
265            return super.equals(obj);
266        }
267    
268        /**
269         * Returns a clone of this <code>LabelBlock</code> instance.
270         * 
271         * @return A clone.
272         * 
273         * @throws CloneNotSupportedException if there is a problem cloning.
274         */
275        public Object clone() throws CloneNotSupportedException {
276            return super.clone();
277        }
278        
279        /**
280         * Provides serialization support.
281         *
282         * @param stream  the output stream.
283         *
284         * @throws IOException if there is an I/O error.
285         */
286        private void writeObject(ObjectOutputStream stream) throws IOException {
287            stream.defaultWriteObject();
288            SerialUtilities.writePaint(this.paint, stream);
289        }
290    
291        /**
292         * Provides serialization support.
293         *
294         * @param stream  the input stream.
295         *
296         * @throws IOException  if there is an I/O error.
297         * @throws ClassNotFoundException  if there is a classpath problem.
298         */
299        private void readObject(ObjectInputStream stream) 
300            throws IOException, ClassNotFoundException {
301            stream.defaultReadObject();
302            this.paint = SerialUtilities.readPaint(stream);
303        }
304    
305    }