001    /*
002      Copyright (C) 2002 Renaud Pawlak <renaud@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.TextFigure;
022    import CH.ifa.draw.framework.Connector;
023    import CH.ifa.draw.framework.DrawingView;
024    import CH.ifa.draw.framework.Figure;
025    import CH.ifa.draw.framework.FigureChangeEvent;
026    import CH.ifa.draw.framework.FigureEnumeration;
027    import CH.ifa.draw.standard.CompositeFigure;
028    import CH.ifa.draw.standard.NullHandle;
029    import CH.ifa.draw.standard.RelativeLocator;
030    import org.objectweb.jac.aspects.gui.ObjectUpdate;
031    import org.objectweb.jac.aspects.gui.Utils;
032    import org.objectweb.jac.core.Wrappee;
033    import org.objectweb.jac.core.Wrapping;
034    import org.objectweb.jac.ide.Class;
035    import org.objectweb.jac.ide.Field;
036    import org.objectweb.jac.ide.Method;
037    import org.objectweb.jac.ide.ModelElement;
038    import org.objectweb.jac.ide.Package;
039    import org.objectweb.jac.ide.Projects;
040    import org.objectweb.jac.util.Log;
041    import java.awt.Color;
042    import java.awt.Dimension;
043    import java.awt.Graphics;
044    import java.awt.Point;
045    import java.awt.Rectangle;
046    import java.util.Iterator;
047    import java.util.Vector;
048    
049    public class ClassFigure extends CompositeFigure 
050        implements ObjectUpdate, ModelElementFigure
051    {
052    
053        private static final int BORDER = 3;
054        //   private Rectangle fDisplayBox;
055       
056        Vector relationLinkFigures = new Vector();
057        Vector inheritanceLinkFigures = new Vector();
058        Vector fieldFigures = new Vector();
059        Vector methodFigures = new Vector();
060    
061        DrawingView view;
062    
063        org.objectweb.jac.ide.ClassFigure classFig;
064        Dimension dimension = new Dimension();
065    
066        public ClassFigure(org.objectweb.jac.ide.ClassFigure figure, Package pack, 
067                           DrawingView view) {
068            initialize();
069            this.classFig = figure;
070            this.containerPackage = pack;
071            this.view = view;
072    
073            ClassNameFigure name=new ClassNameFigure(figure.getCl(),this);
074            name.setZValue(1);
075            add(name);
076    
077            DiagramView.init = true;
078            try {
079                initFields();
080                initMethods();
081            } finally {
082                DiagramView.init = false;
083            }
084            Utils.registerObject(classFig.getCl(),this);
085            Utils.registerObject(classFig,this);
086    
087            layout();
088        }
089    
090        // ObjectUpdate interface
091        public void objectUpdated(Object object, Object extra) {
092            Vector fs = new Vector();
093            fs.add(this);
094            initClass();
095            layout();
096            changed();
097            //editor().validate();
098            //      view.draw(view.getGraphics(),new FigureEnumerator(fs));
099        }
100    
101        public void close() {
102            // we should unregister from all objectUpdate events
103            Utils.unregisterObject(classFig.getCl(),this);
104            Utils.unregisterObject(classFig,this);      
105        }
106    
107        //Serialization support.
108        private static final long serialVersionUID = -7877776240236946511L;
109        private int pertFigureSerializedDataVersion = 1;
110       
111    
112        boolean isInternal() {
113            return containerPackage.getClasses().contains(classFig.getCl());
114        }
115    
116        Package containerPackage;
117    
118        /**
119         * Get the value of containerPackage.
120         * @return value of containerPackage.
121         */
122        public Package getContainerPackage() {
123            return containerPackage;
124        }
125       
126        /**
127         * Set the value of containerPackage.
128         * @param v  Value to assign to containerPackage.
129         */
130        public void setContainerPackage(Package  v) {
131            this.containerPackage = v;
132        }
133          
134        void initClass() {
135            if (classFig.getCl() == null) {
136                Log.warning("UNRESOLVED CLASS!");
137            } else {
138                Log.trace("figures","init class "+classFig.getCl().getName());
139                DiagramView.init = true;
140                try {
141                    removeAllMembers();
142                    initTitle();
143                    initFields();
144                    initMethods();
145                } finally {
146                    DiagramView.init = false;
147                }
148                /*
149                  Wrapping.invokeRoleMethod((Wrappee)classFig.getCl(),"registerObject",
150                  new Object[]{this,null});
151                  Wrapping.invokeRoleMethod((Wrappee)classFig,"registerObject",
152                  new Object[]{this,null});
153                */
154            }
155        }
156    
157        void initTitle() {
158            ClassNameFigure nf = (ClassNameFigure)figures().nextFigure(); 
159            nf.setSubstance(classFig.getCl());
160            nf.setText(classFig.getCl().getName());
161        }
162    
163    
164        void initFields() {
165            if (!classFig.isHideFields()) {
166                Iterator it = classFig.getCl().getFields().iterator();
167                while(it.hasNext()) {
168                    Field field = (Field)it.next();
169                    FieldFigure fieldFigure = new FieldFigure(field,this);
170                    Log.trace("figures","adding field "+field);
171                    fieldFigures.add(fieldFigure);
172                    add(fieldFigure);
173                }
174            }
175        }
176    
177        void initMethods() {
178            if (!classFig.isHideMethods()) {
179                Iterator it = classFig.getCl().getAllMethods().iterator();
180                while(it.hasNext()) {
181                    Method method = (Method)it.next();
182                    MethodFigure methodFigure = new MethodFigure(method,this);
183                    Log.trace("figures","adding method "+method);
184                    add(methodFigure);
185                    methodFigures.add(methodFigure);
186                }
187            }
188        }
189    
190        void removeAllMembers() {
191            FigureEnumeration it = figures();
192            // skip the title
193            it.nextFigure();
194            while (it.hasMoreElements()) {
195                Figure f = it.nextFigure();
196                Log.trace("figures","removing "+f);
197                remove(f);
198                Wrapping.invokeRoleMethod( (Wrappee) ((ModelElementFigure)f).getSubstance(),
199                                           "unregisterObject",new Object[]{this});
200            }
201            methodFigures.clear();
202            fieldFigures.clear();
203        }
204    
205        protected void basicMoveBy(int dx, int dy) {
206            Log.trace("figures",2,this+".basicMoveBy "+dx+","+dy);
207            classFig.translate(dx, dy);
208            super.basicMoveBy(dx, dy);
209        } 
210    
211        public Rectangle displayBox() {
212            return new Rectangle(classFig.getCorner(),dimension);
213        }
214    
215        public void basicDisplayBox(Point origin, Point corner) {
216            classFig.setCorner(origin);
217            dimension.width = corner.x-origin.x;
218            dimension.height = corner.y-origin.y;
219            layout();
220        }
221    
222        protected Color getFillColor() {
223            if (isInternal())
224                return Color.white;
225            else
226                return Color.lightGray;
227        }
228    
229        static final Color VERY_LIGHT_GRAY = new Color(220,220,220);
230    
231        protected Color getColor() {
232            if (classFig.getCl().getContainer()!=null)
233                return Color.black;
234            else
235                return VERY_LIGHT_GRAY;
236        }
237    
238        protected void drawBorder(Graphics g) {
239            Rectangle r = displayBox();
240          
241            g.setColor(getFillColor());
242            g.fillRect(r.x, r.y, r.width, r.height);
243          
244            g.setColor(getColor());
245            g.drawRect(r.x, r.y, r.width, r.height);
246          
247            Figure f = figureAt(0);
248            Rectangle rf = f.displayBox();
249          
250            g.drawLine(r.x,r.y+rf.height+1,r.x+r.width,r.y+rf.height+1);
251          
252            if( fieldFigures.size() > 0 ) {
253                f = (Figure) fieldFigures.get(0);
254                rf = f.displayBox();
255                g.drawLine(r.x,rf.y,r.x+r.width,rf.y);
256            }
257        }
258    
259        public void draw(Graphics g) {
260            Log.trace("diagram.draw",this+".draw");
261            drawBorder(g);
262            super.draw(g);
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.southWest()));
270            handles.addElement(new NullHandle(this, RelativeLocator.southEast()));
271            return handles;
272        }
273    
274        void addRelationLinkFigure(RelationLinkFigure a) {
275            relationLinkFigures.add(a);
276        }
277    
278        void addInheritanceLinkFigure(InheritanceLinkFigure link) {
279            inheritanceLinkFigures.add(link);
280        }
281    
282        void removeInheritanceLinkFigure(InheritanceLinkFigure link) {
283            inheritanceLinkFigures.remove(link);
284        }
285    
286        void removeRelationLinkFigure(RelationLinkFigure a) {
287            relationLinkFigures.remove(a);
288        }
289    
290        public Vector getRelationLinkFigures() {
291            return relationLinkFigures;
292        }
293    
294        void addFieldFigure() {
295            addFieldFigure("newField","void");
296        }
297    
298        /**
299         * Add a new field to the class
300         * @param name the name  of the field
301         * @param type the type of the field
302         */
303        void addFieldFigure(String name, String type) {
304            Field f = new Field();
305            f.setName(name);
306            f.setType(Projects.types.resolveType(type));
307            classFig.getCl().addField(f); 
308        }
309    
310        /*
311          void addFieldFigure(FieldFigure f) {
312          fieldFigures.add(f);
313          }
314        */
315    
316        void addMethodFigure() {
317            Method m = new Method();
318            m.setName("newMethod");
319            m.setType(Projects.types.resolveType("void"));
320            classFig.getCl().addMethod(m); 
321        }
322    
323        void addMethodFigure(MethodFigure f) {
324            methodFigures.add(f);
325        }
326    
327        public String getName() {
328            return ((TextFigure)figures().nextFigure()).getText();
329        }
330    
331        /**
332         * Returns all the internal figures of this class (field and
333         * method figures)
334         */
335        Vector getClassFigures() {
336            Vector ret = new Vector();
337            ret.add(figures().nextFigure());
338            ret.addAll(methodFigures);
339            ret.addAll(fieldFigures);
340            return ret;
341        }
342    
343        private void initialize() {
344            //      fDisplayBox = new Rectangle(0, 0, 0, 0);
345            setZValue(2);
346        }
347    
348        /**
349         * Compute the width of the figure, and the position of field and
350         * method figures 
351         */
352        public void layout() {
353            Point partOrigin = (Point)classFig.getCorner().clone();
354            partOrigin.translate(BORDER, BORDER);
355            Dimension extent = new Dimension(0, 0);
356          
357            Iterator it = getClassFigures().iterator();
358            while(it.hasNext()) {
359                Figure f = (Figure)it.next();
360             
361                Dimension partExtent = f.size();
362                Point corner = new Point(
363                    partOrigin.x+partExtent.width,
364                    partOrigin.y+partExtent.height);
365                f.basicDisplayBox(partOrigin, corner);
366             
367                extent.width = Math.max(extent.width, partExtent.width);
368                extent.height += partExtent.height;
369                partOrigin.y += partExtent.height;
370            }
371            dimension.width = extent.width + 2*BORDER;
372            dimension.height = extent.height + 2*BORDER;
373        }
374    
375        private boolean needsLayout() {
376            /*              
377                    Dimension extent = new Dimension(0, 0);
378           
379                    FigureEnumeration k = figures();
380                    while (k.hasMoreElements()) {
381                    Figure f = k.nextFigure();
382                    extent.width = Math.max(extent.width, f.size().width);
383                    }
384                    int newExtent = extent.width + 2*BORDER;
385                    return newExtent != fDisplayBox.width;
386            */
387            return true;
388        }
389    
390        public void update(FigureChangeEvent e) {
391            Log.trace("figures",this+".update");
392            if (needsLayout()) {
393                layout();
394                changed();
395            }
396        }
397    
398        public void figureChanged(FigureChangeEvent e) {
399            update(e);
400        }
401    
402    
403        public void figureRemoved(FigureChangeEvent e) {
404            update(e);
405        }
406       
407        public void release() {
408            Log.trace("diagram","release "+this);
409            super.release();
410            close();
411            if (classFig!=null && classFig.getDiagram()!=null)
412                classFig.getDiagram().removeFigure(classFig);
413        }
414    
415        public org.objectweb.jac.ide.ClassFigure getClassFig() {
416            return classFig;
417        }
418    
419        public void setClassFig(org.objectweb.jac.ide.ClassFigure classFig) {
420            this.classFig = classFig;
421            initClass();
422            layout();
423        }
424       
425        public Point getCorner() {
426            return classFig.getCorner();
427        }
428    
429        public ModelElement getSubstance() {
430            return classFig.getCl();
431        }
432    
433        public Class getClassElement() {
434            return classFig.getCl();
435        }
436    
437        // Helper methods
438        public Connector connectorAt(Point p) {
439            return connectorAt(p.x,p.y);
440        }
441    }
442