001    /*
002      Copyright (C) 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, but
010      WITHOUT ANY WARRANTY; without even the implied warranty of
011      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
012      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.swing;
020    
021    import java.awt.BorderLayout;
022    import java.awt.event.TextEvent;
023    import java.awt.event.TextListener;
024    import java.io.StringReader;
025    import java.util.Arrays;
026    import java.util.Set;
027    import javax.swing.JLabel;
028    import javax.swing.event.CaretEvent;
029    import javax.swing.event.CaretListener;
030    import org.apache.log4j.Logger;
031    import org.objectweb.jac.aspects.gui.GuiAC;
032    import org.objectweb.jac.aspects.gui.swing.AbstractCodeEditor;
033    import org.objectweb.jac.core.ACManager;
034    import org.objectweb.jac.core.AspectComponent;
035    import org.objectweb.jac.core.Collaboration;
036    import org.objectweb.jac.core.parsers.acc.NonTerminal;
037    import org.objectweb.jac.core.parsers.acc.SyntaxElement;
038    import org.objectweb.jac.core.parsers.acc.Terminal;
039    import org.objectweb.jac.core.parsers.acc.ToolParserWrapper;
040    import org.objectweb.jac.core.rtti.ClassItem;
041    import org.objectweb.jac.core.rtti.ClassRepository;
042    import org.objectweb.jac.core.rtti.FieldItem;
043    import org.objectweb.jac.core.rtti.MethodItem;
044    import org.objectweb.jac.core.rtti.NoSuchMethodException;
045    import org.objectweb.jac.ide.Application;
046    import org.objectweb.jac.ide.Projects;
047    import org.objectweb.jac.ide.AspectConfiguration;
048    import org.objectweb.jac.util.Strings;
049    
050    /**
051     * A Java source code editor
052     */
053    public class AccCodeEditor extends AbstractCodeEditor
054    {
055        static final Logger logger = Logger.getLogger("ide.editor");
056    
057        JLabel statusLine = new JLabel();
058        AccCodeStatus codeStatus;
059        ToolParserWrapper parser;
060        AccCompletionEngine ce;
061    
062        public AccCodeEditor(Object substance, FieldItem field) {
063            super(substance,field);
064            editor.setConfig(Projects.prefs.getEditorPrefs());
065            editor.setMinDisplayedLines(10);
066            editor.setWordSeparators(
067                new char [] { '\n', ' ', ',', '(', ')', '{', '}', '[', ']', '/', '-', '+', '*', 
068                              '<', '>', '=', ';', '"', '\'', '&', '|', '!' });
069            add(BorderLayout.SOUTH,statusLine);
070            parser = new ToolParserWrapper();
071            Application application = ((AspectConfiguration)getSubstance()).getApplication();
072            if (application==null) {
073                application = (Application)Collaboration.get().getAttribute(GuiAC.SUBSTANCE);
074            }
075    
076            if (application!=null) {
077                ce = new AccCompletionEngine(parser,application.getProject());
078                editor.setCompletionEngine(ce);
079            }
080            editor.addCaretListener(new AccCodeStatus());
081            init();
082            editor.addTextListener(
083                new TextListener() {
084                        public void textValueChanged(TextEvent e) {
085                            logger.debug("textValueChanged");
086                            parser.parse(new StringReader(editor.getText()),"");
087                            updateStatusLine();
088                        }
089                    });
090        }  
091    
092        static String[] defaultBlockKeywords = 
093            new String[] {"class","member","attribute","method","block"};
094    
095        protected void init() {
096            editor.clearKeywords();
097            editor.addKeywords(defaultBlockKeywords);
098            if (getSubstance() instanceof AspectConfiguration) {
099                // instanciate the aspect so that we can know its block keywords
100                AspectConfiguration config = (AspectConfiguration)getSubstance();
101                try {
102                    if (!Strings.isEmpty(config.getName())) {
103                        String acClassName = 
104                            ACManager.getACM().getACPathFromName(config.getName());
105                        Class acClass = Class.forName(acClassName);
106                        aspectClass = ClassRepository.get().getClass(acClassName);
107                        AspectComponent acInstance = (AspectComponent)acClass.newInstance();
108                        Set keywords = acInstance.getBlockKeywords();
109                        logger.debug("keywords for "+config.getName()+": "+keywords);
110                        editor.addKeywords(keywords);
111    
112                        if (parser!=null)
113                            parser.setBlockKeywords(keywords);
114                        if (ce!=null) {
115                            ce.setAspectInstance(acInstance);
116                            ce.clearBaseWords();
117                            ce.addBaseWords(acInstance.getConfigurationMethodsName());
118                            ce.addBaseWords(acInstance.getBlockKeywords());
119                            ce.addBaseWords(Arrays.asList(defaultBlockKeywords));
120                        }
121                    }
122                } catch (Exception e) {
123                    logger.error("Failed to init the code editor",e);
124                }
125            }
126        }
127    
128        /*
129          public void setValue(Object value) {
130          super.setValue(value);
131          init();
132          if (parser!=null) {
133          parser.parse(new StringReader(editor.getText()),"");
134          }
135          }
136        */
137    
138        ClassItem aspectClass;
139    
140        /**
141         * Updates the "modeline" to display the current configuration method
142         */
143        void updateStatusLine() {
144            SyntaxElement currentElement = parser.getSyntaxElementAt(editor.getCaretPosition());
145            logger.debug("currentElement = "+currentElement);
146            String newStatus = " ";
147            NonTerminal parent=null;
148            if (currentElement!=null)
149                parent = (NonTerminal)currentElement.findParent("conf_method");
150            if (parent!=null) {
151                logger.debug("parent = "+parent);
152                String currentName = parent.getName();
153                Terminal confMethod = 
154                    (Terminal)parent.getChild("CONF_METHOD");
155                if (confMethod!=null) {
156                    if (aspectClass!=null) {
157                        try {
158                            MethodItem[] methods = 
159                                aspectClass.getMethods(confMethod.getValue());
160                            if (methods.length==1) {
161                                newStatus = methods[0].getCompactFullName();
162                            } else {
163                                newStatus = confMethod.getValue()+"(...)";
164                            }
165                        } catch (NoSuchMethodException e) {
166                            newStatus = "???";
167                        }
168                    } else {
169                        newStatus = confMethod.getValue();
170                    }
171                } else {
172                    newStatus = currentElement.toString();
173                }
174            } else if (currentElement!=null) {
175                newStatus = currentElement.toString();
176            }
177            statusLine.setText(newStatus);
178        }
179    
180        class AccCodeStatus implements CaretListener {
181            public AccCodeStatus() {
182            }
183            public void caretUpdate(CaretEvent event) {
184                updateStatusLine();
185            }
186        }
187    
188        public void fieldUpdated(Object object, FieldItem field, 
189                                 Object value, Object param) {
190            init();
191            super.fieldUpdated(object,field,value,param);
192        }
193    }
194