001    /*
002      Copyright (C) 2002-2003 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      USA */
018    
019    package org.objectweb.jac.ide;
020    
021    import java.io.File;
022    import java.util.Arrays;
023    import java.util.Collection;
024    import java.util.HashSet;
025    import java.util.Iterator;
026    import java.util.List;
027    import java.util.Map;
028    import java.util.Set;
029    import java.util.Vector;
030    import org.objectweb.jac.aspects.gui.DisplayContext;
031    import org.objectweb.jac.aspects.gui.HandlerResult;
032    import org.objectweb.jac.core.ObjectRepository;
033    import org.objectweb.jac.util.Strings;
034    
035    /**
036     * This class represents a class meta element. 
037     */
038    public class Class extends Type {
039    
040        public String getGenerationName() {
041            return Strings.toUSAscii(getName());
042        }
043    
044        Type superClass;
045        /**
046         * Get the value of superClass.
047         * @return value of superClass.
048         */
049        public Type getSuperClass() {
050            return superClass;
051        }
052        /**
053         * Set the value of superClass.
054         * @param v  Value to assign to superClass.
055         */
056        public void setSuperClass(Type v) {
057            if (v!=superClass && superClass!=null) {
058                // Remove existing inheritance links from diagrams
059                // This should rather be done with an aspect
060                Collection diagrams = ObjectRepository.getObjects(Diagram.class);
061                Iterator it = diagrams.iterator();
062                while(it.hasNext()) {
063                    Diagram d = (Diagram)it.next();
064                    if (superClass instanceof Class)
065                        d.removeInheritanceLink(this,(Class)superClass);
066                }         
067            }
068    
069            this.superClass = v;
070        }
071    
072        /**
073         * Finds a field with a given name
074         * @param name field name
075         * @return a field with the given name, or null
076         */
077        public Field findField(String name) {
078            Iterator it = getFields().iterator();
079            while (it.hasNext()) {
080                Field f = (Field)it.next();
081                if (f.getName().equals(name)) {
082                    return f;
083                }
084            }
085            return null;
086        }
087    
088        Vector fields = new Vector();
089        /**
090         * Get the value of fields.
091         * @return value of fields.
092         */
093        public List getFields() {
094            return fields;
095        }
096        public void addField(Field f) {
097            fields.add(f);
098        }
099        public void removeField(Field f) {
100            fields.remove(f);
101        }
102    
103        /**
104         * Returns all fields, including inherited ones
105         */
106        public List getAllFields() {
107            Vector result = new Vector();
108            if (superClass instanceof Class)
109                result.addAll(((Class)superClass).getAllFields());
110            result.addAll(getFields());
111            return result;
112        }
113    
114        Vector methods = new Vector();
115        /**
116         * Get the value of methods.
117         * @return value of methods.
118         */
119        public List getMethods() {
120            return methods;
121        }
122        public void addMethod(Method m) {
123            methods.add(m);
124        }
125        public void removeMethod(Method m) {
126            methods.remove(m);
127        }
128        public void addConstructor(Constructor c) {
129            methods.add(c);
130        }
131    
132        /**
133         * Gets al methods, including specific
134         * getter,setters,adders,removers and clearers.
135         */
136        public List getAllMethods() {
137            Vector allMethods = new Vector();
138            allMethods.addAll(methods);
139            Method m;
140            Iterator it = fields.iterator();
141            while (it.hasNext()) {
142                Field field = (Field)it.next();
143                if ((m=field.getSetter())!=null)
144                    allMethods.add(m);
145                if ((m=field.getGetter())!=null)
146                    allMethods.add(m);
147            }
148    
149            it = getNavigableRoles().iterator();
150            while (it.hasNext()) {
151                RelationRole role = (RelationRole)it.next();
152                if ((m=role.getGetter())!=null)
153                    allMethods.add(m);
154                if ((m=role.getAdder())!=null)
155                    allMethods.add(m);
156                if ((m=role.getRemover())!=null)
157                    allMethods.add(m);
158                if ((m=role.getClearer())!=null)
159                    allMethods.add(m);
160            }
161            return allMethods;
162        }
163    
164        public List getInheritedMethods() {
165            if (superClass instanceof Class) {
166                List superMethods = ((Class)superClass).getAllMethods();
167                List superInheritedMethods = ((Class)superClass).getInheritedMethods();         
168                superMethods.addAll(superInheritedMethods);
169                return superMethods;
170            } else {
171                return new Vector();
172            }
173        }
174    
175        public List getAbstractMethods() {
176            Vector abstractMethods = new Vector();
177            Iterator i = methods.iterator();
178            while (i.hasNext()) {
179                Method m = (Method)i.next();
180                if (m.isAbstract()) {
181                    Method m2 = findMethod(m);
182                    if (m2==null || m2==m)
183                        abstractMethods.add(m);
184                }
185            }
186            if (superClass instanceof Class) {
187                List superMethods = ((Class)superClass).getAbstractMethods();
188                i = superMethods.iterator();
189                while (i.hasNext()) {
190                    Method m = (Method)i.next();
191                    Method m2 = findMethod(m);
192                    if (m2==null || m2==m)
193                        abstractMethods.add(m);
194                }
195            } 
196            return abstractMethods;
197        }
198    
199        /**
200         * Finds a method with a given name and parameters
201         * @param name method name
202         * @param parameters the types of the parameters. 
203         * @return a method with the given name and parameter types, or null 
204         * @see #findMethod(Method)
205         */
206        public Method findMethod(String name, List parameters) {
207            Iterator it = getAllMethods().iterator();
208            while (it.hasNext()) {
209                Method m = (Method)it.next();
210                if (m.getName().equals(name)) {
211                    if (Arrays.asList(m.getParameterTypes()).equals(parameters)) {
212                        return m;
213                    }
214                }
215            }
216            return null;
217        }
218    
219        /**
220         * Finds a method with the same name and the same parameter types
221         * as a given method.
222         * @param method method whose name and parameter types must match
223         * @return a method with the same name and the same parameter types, or null
224         * @see #findMethod(String,List)
225         */
226        public Method findMethod(Method method) {
227            return findMethod(method.getName(),Arrays.asList(method.getParameterTypes()));
228        }
229    
230        public void addMethodIntf(Method m) {
231            addMethod(m);
232        }
233    
234        public void removeMethodIntf(Method m) {
235            removeMethod(m);
236        }
237    
238        /**
239         * Adds a "public static void main(String[] parameters)" method
240         */
241        public void addMainMethod() {
242            Method main = new Method();
243            main.setName("main");
244            main.setVisibility(Visibility.PUBLIC);
245            main.setStatic(true);
246            Parameter param = new Parameter();
247            param.setName("parameters");
248            param.setType(Projects.types.resolveType("String", "java.lang"));
249            param.setArray(true);
250            main.addParameter(param);
251            addMethod(main);
252        }
253    
254        Package container;
255        /**
256         * Get the value of container.
257         * @return value of container.
258         */
259        public Package getContainer() {
260            return container;
261        }
262        /**
263         * Set the value of container.
264         * @param v  Value to assign to container.
265         */
266        public void setContainer(Package  v) {
267            this.container = v;
268        }
269    
270        public String getFullName() {
271            if (container == null) {
272                return name;
273            } else {
274                return container.getPPath()+"."+name;
275            }
276        }
277    
278        public String getGenerationFullName() {
279            if (container == null) {
280                return getGenerationName();
281            } else {
282                return container.getPPath()+"."+getGenerationName();
283            }
284        }
285    
286    
287        /**
288         * Gets navigable roles
289         * @return a collection of RelationRole
290         */
291        public Collection getNavigableRoles() {
292            Vector result = new Vector();
293            Iterator it = links.iterator();
294            while (it.hasNext()) {
295                Role role = (Role)it.next();
296                if (role instanceof RelationRole && ((RelationRole)role).isNavigable())
297                    result.add(role);
298            }
299            return result;
300        }
301    
302        /**
303         * Gets all navigable roles, including those form inherited classes.
304         */
305        public Collection getAllNavigableRoles() {
306            Vector result = new Vector();
307            if (superClass instanceof Class)
308                result.addAll(((Class)superClass).getAllNavigableRoles());
309            result.addAll(getNavigableRoles());
310            return result;
311        }
312    
313        /**
314         * Gets all navigable reference roles (whose cardinality is 1 or
315         * 0-1), including those form inherited classes.
316         */
317        public Collection getReferenceRoles() {
318            Vector result = new Vector();
319            if (superClass instanceof Class)
320                result.addAll(((Class)superClass).getReferenceRoles());
321    
322            Iterator it = links.iterator();
323            while (it.hasNext()) {
324                Role role = (Role)it.next();
325                if (role instanceof RelationRole) {
326                    RelationRole relRole = (RelationRole)role;
327                    if (relRole.isNavigable() && !relRole.isMultiple()) {
328                        result.add(role);
329                    }
330                }
331            }
332    
333            return result;
334        }
335    
336        public Collection getRelationRoles() {
337            Vector result = new Vector();
338            Iterator it = links.iterator();
339            while (it.hasNext()) {
340                Role role = (Role)it.next();
341                if (role instanceof RelationRole)
342                    result.add(role);
343            }
344            return result;
345        }
346    
347        public Collection getRelationLinks() {
348            Vector result = new Vector();
349            Iterator it = links.iterator();
350            while (it.hasNext()) {
351                Role role = (Role)it.next();
352                if (role instanceof RelationRole)
353                    result.add(role.getLink());
354            }
355            return result;
356        }
357    
358        public Project getProject() {
359            if (container!=null)
360                return container.getProject();
361            else 
362                return null;
363        }
364    
365        Vector imports = new Vector();
366        public List getImports() {
367            return imports;
368        }
369        public void addImport(String _import) {
370            imports.add(_import);
371        }
372        public void removeImport(String _import) {
373            imports.remove(_import);
374        }
375    
376        boolean isAbstract = false;
377        public boolean isAbstract() {
378            return isAbstract;
379        }
380        public void setAbstract(boolean value) {
381            isAbstract = value;
382        }
383    
384        Set interfaces = new HashSet();
385        public Set getInterfaces() {
386            return interfaces;
387        }
388        public void addInterface(Interface _interface) {
389            interfaces.add(_interface);
390        }
391        public void removeInterface(Interface _interface) {
392            interfaces.remove(_interface);
393        }
394    
395        /**
396         * Adds the necessary fields and methods to implement a interface
397         * @param intf the interface to implement
398         */
399        public void implementInterface(Interface intf) {
400            Iterator it = intf.getAllFields().iterator();
401            while (it.hasNext()) {
402                Field intfField = (Field)it.next();
403                if (findField(intfField.getName())!=null)
404                    continue;
405                Field field = new Field();
406                field.setName(intfField.getName());
407                field.setType(intfField.getType());
408                field.setArray(intfField.isArray());
409                addField(field);
410            }
411    
412            it = intf.getAllMethods().iterator();
413            while (it.hasNext()) {
414                Method intfMethod = (Method)it.next();
415                if (findMethod(intfMethod)!=null)
416                    continue;
417                addMethod(intfMethod.cloneMethod());
418            }
419        }
420    
421        /**
422         * Adds an overriding method
423         * @param method method to override
424         */
425        public void overrideMethod(Method method) {
426            addMethod(method.cloneMethod());
427        }
428    
429        /**
430         * Adds an implementation for an abstract method
431         * @param method abstract method to implement
432         */    
433        public void implementMethod(Method method) {
434            addMethod(method.cloneMethod());
435        }
436    
437        public HandlerResult gotoLine(DisplayContext context,int lineNumber) {
438            Map lineNumbers = CodeGeneration.getClassLineNumbers(this);
439            if (lineNumbers.isEmpty()) {
440                throw new RuntimeException("No line number information available. Please (re)generate code.");
441            }
442            Member member = null;
443            Iterator i = lineNumbers.entrySet().iterator();
444            int closestLine = 0;
445            while (i.hasNext()) {
446                Map.Entry entry = (Map.Entry)i.next();
447                int line = ((Integer)entry.getValue()).intValue();
448                if (lineNumber > line && line > closestLine) {
449                    closestLine = line;
450                    member = (Member)entry.getKey();
451                }
452            }
453            if (member!=null) {
454                if (member instanceof Method) {
455                    Method method = (Method)member;
456                    return new HandlerResult(
457                        context.getDisplay().getCustomizedView("ide"),
458                        org.objectweb.jac.core.rtti.ClassRepository.get()
459                        .getClass(org.objectweb.jac.ide.Class.class).getField("methods"),
460                        method,"body",new Integer(lineNumber-closestLine-1));
461                } else {
462                    return new HandlerResult(
463                        context.getDisplay().getCustomizedView("ide"),
464                        org.objectweb.jac.core.rtti.ClassRepository.get()
465                        .getClass(org.objectweb.jac.ide.Class.class).getField("fields"),
466                        member,null,null);
467                }
468            } else {
469                return null;        
470            }
471        }
472    }
473