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