001    /*
002      Copyright (C) 2003 Laurent Martelli <laurent@aopsys.com>
003    
004      This program is free software; you can redistribute it and/or modify
005      it under the terms of the GNU Lesser General Public License as
006      published by the Free Software Foundation; either version 2 of the
007      License, or (at your option) any later version.
008    
009      This program is distributed in the hope that it will be useful,
010      but WITHOUT ANY WARRANTY; without even the implied warranty of
011      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012      GNU Lesser General Public License for more details.
013    
014      You should have received a copy of the GNU Lesser General Public
015      License along with this program; if not, write to the Free Software
016      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
017    */
018    
019    package org.objectweb.jac.ide.diagrams;
020    
021    import CH.ifa.draw.figures.AttributeFigure;
022    import CH.ifa.draw.figures.FontSizeHandle;
023    import CH.ifa.draw.framework.Figure;
024    import CH.ifa.draw.framework.FigureChangeEvent;
025    import CH.ifa.draw.framework.FigureChangeListener;
026    import CH.ifa.draw.standard.NullHandle;
027    import CH.ifa.draw.standard.OffsetLocator;
028    import CH.ifa.draw.standard.RelativeLocator;
029    import CH.ifa.draw.standard.TextHolder;
030    import CH.ifa.draw.util.ColorMap;
031    import java.awt.Color;
032    import java.awt.Dimension;
033    import java.awt.Font;
034    import java.awt.FontMetrics;
035    import java.awt.Graphics;
036    import java.awt.Point;
037    import java.awt.Rectangle;
038    import java.awt.Toolkit;
039    import java.util.Vector;
040    
041    /**
042     * A TextFigure whose text color can be redefined with the method <code>getTextColor()</code>
043     */
044    public  class TextFigure
045        extends AttributeFigure
046        implements FigureChangeListener, TextHolder {
047    
048        protected int fOriginX;
049        protected int fOriginY;
050    
051        // cache of the TextFigure's size
052        transient private boolean fSizeIsDirty = true;
053        transient private int     fWidth;
054        transient private int     fHeight;
055    
056        private String  fText;
057        private Font    fFont;
058        private boolean fIsReadOnly;
059    
060        private Figure  fObservedFigure = null;
061        private OffsetLocator fLocator = null;
062    
063        private static String fgCurrentFontName  = "Helvetica";
064        private static int    fgCurrentFontSize  = 12;
065        private static int    fgCurrentFontStyle = Font.PLAIN;
066    
067        /*
068         * Serialization support.
069         */
070        private static final long serialVersionUID = 4599820785949456124L;
071    
072        public TextFigure() {
073            fOriginX = 0;
074            fOriginY = 0;
075            fFont = createCurrentFont();
076            setAttribute("FillColor", ColorMap.color("None"));
077            fText = "";
078            fSizeIsDirty = true;
079        }
080    
081        public void moveBy(int x, int y) {
082            willChange();
083            basicMoveBy(x, y);
084            if (fLocator != null) {
085                fLocator.moveBy(x, y);
086            }
087            changed();
088        }
089    
090        protected void basicMoveBy(int x, int y) {
091            fOriginX += x;
092            fOriginY += y;
093        }
094    
095        public void basicDisplayBox(Point newOrigin, Point newCorner) {
096            fOriginX = newOrigin.x;
097            fOriginY = newOrigin.y;
098        }
099    
100        public Rectangle displayBox() {
101            Dimension extent = textExtent();
102            return new Rectangle(fOriginX, fOriginY, extent.width, extent.height);
103        }
104    
105        public Rectangle textDisplayBox() {
106            return displayBox();
107        }
108    
109        /**
110         * Tests whether this figure is read only.
111         */
112        public boolean readOnly() {
113            return fIsReadOnly;
114        }
115    
116        /**
117         * Sets the read only status of the text figure.
118         */
119        public void setReadOnly(boolean isReadOnly) {
120            fIsReadOnly = isReadOnly;
121        }
122    
123        /**
124         * Gets the font.
125         */
126        public Font getFont() {
127            return fFont;
128        }
129    
130        /**
131         * Sets the font.
132         */
133        public void setFont(Font newFont) {
134            willChange();
135            fFont = newFont;
136            markDirty();
137            changed();
138        }
139    
140        /**
141         * Updates the location whenever the figure changes itself.
142         */
143        public void changed() {
144            super.changed();
145            updateLocation();
146        }
147    
148        /**
149         * A text figure understands the "FontSize", "FontStyle", and "FontName"
150         * attributes.
151         */
152        public Object getAttribute(String name) {
153            Font font = getFont();
154            if (name.equals("FontSize")) {
155                return new Integer(font.getSize());
156            }
157            if (name.equals("FontStyle")) {
158                return new Integer(font.getStyle());
159            }
160            if (name.equals("FontName")) {
161                return font.getName();
162            }
163            return super.getAttribute(name);
164        }
165    
166        /**
167         * A text figure understands the "FontSize", "FontStyle", and "FontName"
168         * attributes.
169         */
170        public void setAttribute(String name, Object value) {
171            Font font = getFont();
172            if (name.equals("FontSize")) {
173                Integer s = (Integer)value;
174                setFont(new Font(font.getName(), font.getStyle(), s.intValue()) );
175            }
176            else if (name.equals("FontStyle")) {
177                Integer s = (Integer)value;
178                int style = font.getStyle();
179                if (s.intValue() == Font.PLAIN) {
180                    style = Font.PLAIN;
181                }
182                else {
183                    style = style ^ s.intValue();
184                }
185                setFont(new Font(font.getName(), style, font.getSize()) );
186            }
187            else if (name.equals("FontName")) {
188                String n = (String)value;
189                setFont(new Font(n, font.getStyle(), font.getSize()) );
190            }
191            else {
192                super.setAttribute(name, value);
193            }
194        }
195    
196        /**
197         * Gets the text shown by the text figure.
198         */
199        public String getText() {
200            return fText;
201        }
202    
203        /**
204         * Sets the text shown by the text figure.
205         */
206        public void setText(String newText) {
207            if (!newText.equals(fText)) {
208                willChange();
209                fText = newText;
210                markDirty();
211                changed();
212            }
213        }
214    
215        /**
216         * Tests whether the figure accepts typing.
217         */
218        public boolean acceptsTyping() {
219            return !fIsReadOnly;
220        }
221    
222        public void drawBackground(Graphics g) {
223            Rectangle r = displayBox();
224            g.fillRect(r.x, r.y, r.width, r.height);
225        }
226    
227        public void drawFrame(Graphics g) {
228            g.setFont(fFont);
229            g.setColor(getTextColor());
230            FontMetrics metrics = g.getFontMetrics(fFont);
231            g.drawString(fText, fOriginX, fOriginY + metrics.getAscent());
232        }
233    
234        protected Color getTextColor() {
235            return (Color)getAttribute("TextColor");
236        }
237    
238        private Dimension textExtent() {
239            if (!fSizeIsDirty) {
240                return new Dimension(fWidth, fHeight);
241            }
242            FontMetrics metrics = Toolkit.getDefaultToolkit().getFontMetrics(fFont);
243            fWidth = metrics.stringWidth(fText);
244            fHeight = metrics.getHeight();
245            fSizeIsDirty = false;
246            return new Dimension(metrics.stringWidth(fText), metrics.getHeight());
247        }
248    
249        private void markDirty() {
250            fSizeIsDirty = true;
251        }
252    
253        /**
254         * Gets the number of columns to be overlaid when the figure is edited.
255         */
256        public int overlayColumns() {
257            int length = getText().length();
258            int columns = 20;
259            if (length != 0) {
260                columns = getText().length()+ 3;
261            }
262            return columns;
263        }
264    
265        public Vector handles() {
266            Vector handles = new Vector();
267            handles.addElement(new NullHandle(this, RelativeLocator.northWest()));
268            handles.addElement(new NullHandle(this, RelativeLocator.northEast()));
269            handles.addElement(new NullHandle(this, RelativeLocator.southEast()));
270            handles.addElement(new FontSizeHandle(this, RelativeLocator.southWest()));
271            return handles;
272        }
273    
274        public void connect(Figure figure) {
275            if (fObservedFigure != null) {
276                fObservedFigure.removeFigureChangeListener(this);
277            }
278    
279            fObservedFigure = figure;
280            fLocator = new OffsetLocator(figure.connectedTextLocator(this));
281            fObservedFigure.addFigureChangeListener(this);
282            updateLocation();
283        }
284    
285        public void figureChanged(FigureChangeEvent e) {
286            updateLocation();
287        }
288    
289        public void figureRemoved(FigureChangeEvent e) {
290            if (listener() != null) {
291                listener().figureRequestRemove(new FigureChangeEvent(this));
292            }
293        }
294    
295        public void figureRequestRemove(FigureChangeEvent e) {}
296        public void figureInvalidated(FigureChangeEvent e) {}
297        public void figureRequestUpdate(FigureChangeEvent e) {}
298    
299        /**
300         * Updates the location relative to the connected figure.
301         * The TextFigure is centered around the located point.
302         */
303        protected void updateLocation() {
304            if (fLocator != null) {
305                Point p = fLocator.locate(fObservedFigure,this);
306    
307                p.x -= size().width/2 + fOriginX;
308                p.y -= size().height/2 + fOriginY;
309                if (p.x != 0 || p.y != 0) {
310                    willChange();
311                    basicMoveBy(p.x, p.y);
312                    changed();
313                }
314            }
315        }
316    
317        public void release() {
318            super.release();
319            disconnect(fObservedFigure);
320            fObservedFigure = null;
321        }
322    
323        /**
324         * Disconnects a text holder from a connect figure.
325         */
326        public void disconnect(Figure disconnectFigure) {
327            if (disconnectFigure != null) {
328                disconnectFigure.removeFigureChangeListener(this);
329            }
330            fLocator = null;
331        }
332    
333    
334        /**
335         * Creates the current font to be used for new text figures.
336         */
337        static public Font createCurrentFont() {
338            return new Font(fgCurrentFontName, fgCurrentFontStyle, fgCurrentFontSize);
339        }
340    
341        /**
342         * Sets the current font name
343         */
344        static public void setCurrentFontName(String name) {
345            fgCurrentFontName = name;
346        }
347    
348        /**
349         * Sets the current font size.
350         */
351        static public void setCurrentFontSize(int size) {
352            fgCurrentFontSize = size;
353        }
354    
355        /**
356         * Sets the current font style.
357         */
358        static public void setCurrentFontStyle(int style) {
359            fgCurrentFontStyle = style;
360        }
361    }