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         *
097         * @return The font (never <code>null</code>).
098         * 
099         * @see #setFont(Font)
100         */
101        public Font getFont() {
102            return this.font;    
103        }
104        
105        /**
106         * Sets the font and regenerates the label.
107         *
108         * @param font  the font (<code>null</code> not permitted).
109         * 
110         * @see #getFont()
111         */
112        public void setFont(Font font) {
113            if (font == null) {
114                throw new IllegalArgumentException("Null 'font' argument.");
115            }
116            this.font = font;
117            this.label = TextUtilities.createTextBlock(this.text, font, this.paint);
118            this.label.setLineAlignment(HorizontalAlignment.LEFT); 
119        }
120       
121        /**
122         * Returns the paint.
123         *
124         * @return The paint (never <code>null</code>).
125         * 
126         * @see #setPaint(Paint)
127         */
128        public Paint getPaint() {
129            return this.paint;   
130        }
131       
132        /**
133         * Sets the paint and regenerates the label.
134         *
135         * @param paint  the paint (<code>null</code> not permitted).
136         * 
137         * @see #getPaint()
138         */
139        public void setPaint(Paint paint) {
140            if (paint == null) {
141                throw new IllegalArgumentException("Null 'paint' argument.");
142            }
143            this.paint = paint;
144            this.label = TextUtilities.createTextBlock(this.text, this.font, this.paint);
145            this.label.setLineAlignment(HorizontalAlignment.LEFT); 
146        }
147    
148        /**
149         * Returns the tool tip text.
150         * 
151         * @return The tool tip text (possibly <code>null</code>).
152         * 
153         * @see #setToolTipText(String)
154         */
155        public String getToolTipText() {
156            return this.toolTipText;
157        }
158        
159        /**
160         * Sets the tool tip text.
161         * 
162         * @param text  the text (<code>null</code> permitted).
163         * 
164         * @see #getToolTipText()
165         */
166        public void setToolTipText(String text) {
167            this.toolTipText = text;   
168        }
169        
170        /**
171         * Returns the URL text.
172         * 
173         * @return The URL text (possibly <code>null</code>).
174         * 
175         * @see #setURLText(String)
176         */
177        public String getURLText() {
178            return this.urlText;
179        }
180        
181        /**
182         * Sets the URL text.
183         * 
184         * @param text  the text (<code>null</code> permitted).
185         * 
186         * @see #getURLText()
187         */
188        public void setURLText(String text) {
189            this.urlText = text;   
190        }
191        
192        /**
193         * Arranges the contents of the block, within the given constraints, and 
194         * returns the block size.
195         * 
196         * @param g2  the graphics device.
197         * @param constraint  the constraint (<code>null</code> not permitted).
198         * 
199         * @return The block size (in Java2D units, never <code>null</code>).
200         */
201        public Size2D arrange(Graphics2D g2, RectangleConstraint constraint) {
202            g2.setFont(this.font);
203            Size2D s = this.label.calculateDimensions(g2);
204            return new Size2D(calculateTotalWidth(s.getWidth()), 
205                    calculateTotalHeight(s.getHeight()));
206        }
207        
208        /**
209         * Draws the block.
210         * 
211         * @param g2  the graphics device.
212         * @param area  the area.
213         */
214        public void draw(Graphics2D g2, Rectangle2D area) {
215            draw(g2, area, null);
216        }
217        
218        /**
219         * Draws the block within the specified area.
220         * 
221         * @param g2  the graphics device.
222         * @param area  the area.
223         * @param params  ignored (<code>null</code> permitted).
224         * 
225         * @return Always <code>null</code>.
226         */
227        public Object draw(Graphics2D g2, Rectangle2D area, Object params) {
228            area = trimMargin(area);
229            drawBorder(g2, area);
230            area = trimBorder(area);
231            area = trimPadding(area);
232            
233            // check if we need to collect chart entities from the container
234            EntityBlockParams ebp = null;
235            StandardEntityCollection sec = null;
236            Shape entityArea = null;
237            if (params instanceof EntityBlockParams) {
238                ebp = (EntityBlockParams) params;
239                if (ebp.getGenerateEntities()) {
240                    sec = new StandardEntityCollection();
241                    entityArea = (Shape) area.clone();
242                }
243            }
244            g2.setPaint(this.paint);
245            g2.setFont(this.font);
246            this.label.draw(g2, (float) area.getX(), (float) area.getY(), 
247                    TextBlockAnchor.TOP_LEFT);
248            BlockResult result = null;
249            if (ebp != null && sec != null) {
250                if (this.toolTipText != null || this.urlText != null) {
251                    ChartEntity entity = new ChartEntity(entityArea, 
252                            this.toolTipText, this.urlText);   
253                    sec.add(entity);
254                    result = new BlockResult();
255                    result.setEntityCollection(sec);
256                }
257            }
258            return result;
259        }
260        
261        /**
262         * Tests this <code>LabelBlock</code> for equality with an arbitrary 
263         * object.
264         * 
265         * @param obj  the object (<code>null</code> permitted).
266         * 
267         * @return A boolean.
268         */
269        public boolean equals(Object obj) {
270            if (!(obj instanceof LabelBlock)) {
271                return false;
272            }
273            LabelBlock that = (LabelBlock) obj;
274            if (!this.text.equals(that.text)) {
275                return false;
276            }
277            if (!this.font.equals(that.font)) {
278                return false;
279            }
280            if (!PaintUtilities.equal(this.paint, that.paint)) {
281                return false;
282            }
283            if (!ObjectUtilities.equal(this.toolTipText, that.toolTipText)) {
284                return false;
285            }
286            if (!ObjectUtilities.equal(this.urlText, that.urlText)) {
287                return false;
288            }
289            return super.equals(obj);
290        }
291    
292        /**
293         * Returns a clone of this <code>LabelBlock</code> instance.
294         * 
295         * @return A clone.
296         * 
297         * @throws CloneNotSupportedException if there is a problem cloning.
298         */
299        public Object clone() throws CloneNotSupportedException {
300            return super.clone();
301        }
302        
303        /**
304         * Provides serialization support.
305         *
306         * @param stream  the output stream.
307         *
308         * @throws IOException if there is an I/O error.
309         */
310        private void writeObject(ObjectOutputStream stream) throws IOException {
311            stream.defaultWriteObject();
312            SerialUtilities.writePaint(this.paint, stream);
313        }
314    
315        /**
316         * Provides serialization support.
317         *
318         * @param stream  the input stream.
319         *
320         * @throws IOException  if there is an I/O error.
321         * @throws ClassNotFoundException  if there is a classpath problem.
322         */
323        private void readObject(ObjectInputStream stream) 
324            throws IOException, ClassNotFoundException {
325            stream.defaultReadObject();
326            this.paint = SerialUtilities.readPaint(stream);
327        }
328    
329    }