001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.vmd.midp.components.listeners;
042:
043: import com.sun.source.tree.*;
044: import com.sun.source.util.TreePath;
045: import com.sun.source.util.TreePathScanner;
046: import com.sun.source.util.Trees;
047: import org.netbeans.api.java.source.*;
048: import org.netbeans.modules.vmd.api.codegen.*;
049: import org.netbeans.modules.vmd.api.model.Debug;
050: import org.netbeans.modules.vmd.api.model.DesignComponent;
051: import org.netbeans.modules.vmd.api.model.common.DocumentSupport;
052: import org.netbeans.modules.vmd.midp.components.sources.CommandEventSourceCD;
053: import org.netbeans.modules.vmd.midp.components.sources.ItemCommandEventSourceCD;
054:
055: import javax.lang.model.element.Element;
056: import javax.lang.model.element.Modifier;
057: import javax.lang.model.element.TypeElement;
058: import javax.swing.text.StyledDocument;
059: import java.io.IOException;
060: import java.util.ArrayList;
061: import java.util.Collections;
062: import java.util.HashMap;
063: import java.util.List;
064:
065: /**
066: * @author David Kaspar
067: */
068: class EventListenerCode {
069:
070: static class CodeImplementsPresenter extends
071: CodeGlobalLevelPresenter {
072:
073: private String className;
074: private String methodName;
075: private String[] parameters;
076:
077: public CodeImplementsPresenter(String className,
078: String methodName, String... parameters) {
079: this .className = className;
080: this .methodName = methodName;
081: this .parameters = parameters;
082: }
083:
084: protected void performGlobalGeneration(
085: StyledDocument styledDocument) {
086: JavaSource source = JavaSource.forDocument(styledDocument);
087: try {
088: ModificationResult result = source
089: .runModificationTask(new CancellableTask<WorkingCopy>() {
090: public void cancel() {
091: }
092:
093: public void run(WorkingCopy workingCopy)
094: throws Exception {
095: workingCopy
096: .toPhase(JavaSource.Phase.ELEMENTS_RESOLVED);
097: CompilationUnitTree compilationUnit = workingCopy
098: .getCompilationUnit();
099: TreeMaker treeMaker = workingCopy
100: .getTreeMaker();
101: Trees trees = workingCopy.getTrees();
102:
103: ContainsMethodTreeVisitor visitor = new ContainsMethodTreeVisitor(
104: trees, methodName, parameters);
105: visitor.scan(compilationUnit, null);
106: TreePath classTreePath = visitor
107: .getClassTreePath();
108: if (classTreePath != null) {
109: ExpressionTree expressionTree = findImplementIdentifier(
110: trees, classTreePath,
111: className);
112: if (visitor.isMethodExists()) {
113: if (expressionTree == null) {
114: TypeElement typeElement = workingCopy
115: .getElements()
116: .getTypeElement(
117: className);
118: ExpressionTree implements Clause = typeElement != null ? treeMaker
119: .QualIdent(typeElement)
120: : treeMaker
121: .Identifier(className);
122: ClassTree oldClassTree = (ClassTree) classTreePath
123: .getLeaf();
124: ClassTree newClassTree = treeMaker
125: .addClassImplementsClause(
126: oldClassTree,
127: implements Clause);
128: workingCopy.rewrite(
129: oldClassTree,
130: newClassTree);
131: }
132: } else {
133: if (expressionTree != null) {
134: ClassTree oldClassTree = (ClassTree) classTreePath
135: .getLeaf();
136: ClassTree newClassTree = treeMaker
137: .removeClassImplementsClause(
138: oldClassTree,
139: expressionTree);
140: workingCopy.rewrite(
141: oldClassTree,
142: newClassTree);
143: }
144: }
145: }
146: }
147: });
148: result.commit();
149: } catch (IOException e) {
150: throw Debug.error(e);
151: }
152: }
153:
154: }
155:
156: private static ExpressionTree findImplementIdentifier(Trees trees,
157: TreePath classTreePath, String fullyQualifiedName) {
158: ClassTree clazz = (ClassTree) classTreePath.getLeaf();
159:
160: for (Tree tree : clazz.getImplementsClause()) {
161: Element element = trees.getElement(new TreePath(
162: classTreePath, tree));
163: if (equalsElementWithFQN(element, fullyQualifiedName))
164: return (ExpressionTree) tree;
165: }
166:
167: return null;
168: }
169:
170: private static boolean equalsElementWithFQN(Element element,
171: String fullyQualifiedName) {
172: if (element.getKind().isInterface()
173: || element.getKind().isClass()) {
174: TypeElement type = (TypeElement) element;
175: if (type.getQualifiedName().contentEquals(
176: fullyQualifiedName))
177: return true;
178: }
179: return false;
180: }
181:
182: private static class ContainsMethodTreeVisitor extends
183: TreePathScanner<Void, Void> {
184:
185: private Trees trees;
186: private String methodName;
187: private String[] parameters;
188:
189: private boolean isFirstLevel;
190: private TreePath classTreePath;
191: private boolean methodExists;
192:
193: public ContainsMethodTreeVisitor(Trees trees,
194: String methodName, String... parameters) {
195: this .trees = trees;
196: this .methodName = methodName;
197: this .parameters = parameters;
198:
199: methodExists = false;
200: isFirstLevel = false;
201: }
202:
203: public boolean isMethodExists() {
204: return methodExists;
205: }
206:
207: public TreePath getClassTreePath() {
208: return classTreePath;
209: }
210:
211: @Override
212: public Void visitClass(ClassTree node, Void p) {
213: if (!isFirstLevel) {
214: isFirstLevel = true;
215: if (node.getModifiers().getFlags().contains(
216: Modifier.PUBLIC)) {
217: classTreePath = getCurrentPath();
218: return super .visitClass(node, p);
219: }
220: isFirstLevel = false;
221: }
222: return null;
223: }
224:
225: @Override
226: public Void visitMethod(MethodTree node, Void p) {
227: if (node.getName().contentEquals(methodName)) {
228: List<? extends VariableTree> parameters = node
229: .getParameters();
230: if (this .parameters.length == parameters.size()) {
231: boolean corrent = true;
232: for (int i = 0; i < this .parameters.length; i++) {
233: Tree type = parameters.get(i).getType();
234: TreePath treePath = new TreePath(
235: getCurrentPath(), type);
236: Element element = trees.getElement(treePath);
237: if (!equalsElementWithFQN(element,
238: this .parameters[i])) {
239: corrent = false;
240: break;
241: }
242: }
243: if (corrent)
244: methodExists = true;
245: }
246: }
247: return null;
248: }
249:
250: @Override
251: public Void visitVariable(VariableTree node, Void p) {
252: return null;
253: }
254:
255: }
256:
257: public static class CodeCommandListenerPresenter extends
258: CodeClassLevelPresenter.Adapter {
259:
260: @Override
261: protected void generateClassBodyCode(StyledDocument document) {
262: List<DesignComponent> sources = DocumentSupport
263: .gatherAllComponentsOfTypeID(getComponent()
264: .getDocument(), CommandEventSourceCD.TYPEID);
265: if (sources.size() == 0)
266: return;
267:
268: MultiGuardedSection section = MultiGuardedSection.create(
269: document, getComponent().getComponentID()
270: + "-commandAction"); // NOI18N
271: section
272: .getWriter()
273: .write(
274: "//<editor-fold defaultstate=\"collapsed\" desc=\" Generated Method: commandAction for Displayables \">\n"); // NOI18N
275: section
276: .getWriter()
277: .write(
278: "/**\n * Called by a system to indicated that a command has been invoked on a particular displayable.\n * @param command the Command that was invoked\n * @param displayable the Displayable where the command was invoked\n */\n"); // NOI18N
279: section
280: .getWriter()
281: .write(
282: "public void commandAction (Command command, Displayable displayable) {\n")
283: .commit(); // NOI18N
284:
285: section.switchToEditable(getComponent().getComponentID()
286: + "-preCommandAction"); // NOI18N
287: section.getWriter().write(
288: " // write pre-action user code here\n").commit(); // NOI18N
289: section.switchToGuarded();
290:
291: resolveFirstLevel(section, sources);
292:
293: section.switchToEditable(getComponent().getComponentID()
294: + "-postCommandAction"); // NOI18N
295: section.getWriter().write(
296: " // write post-action user code here\n").commit(); // NOI18N
297: section.switchToGuarded();
298:
299: section.getWriter().write("}\n"); // NOI18N
300: section.getWriter().write("//</editor-fold>\n").commit(); // NOI18N
301: section.close();
302: }
303:
304: private void resolveFirstLevel(MultiGuardedSection section,
305: List<DesignComponent> sources) {
306: HashMap<String, ArrayList<DesignComponent>> displayables2sources = gatherDisplayables(sources);
307: ArrayList<String> displayables = new ArrayList<String>(
308: displayables2sources.keySet());
309: Collections.sort(displayables);
310:
311: for (int i = 0; i < displayables.size(); i++) {
312: String displayable = displayables.get(i);
313: if (i > 0)
314: section.getWriter().write("else "); // NOI18N
315: section.getWriter().write(
316: "if (displayable == " + displayable + ") {\n"); // NOI18N
317:
318: resolveSecondLevel(section, displayables2sources
319: .get(displayable));
320:
321: assert section.isGuarded();
322: if (i < displayables.size() - 1)
323: section.getWriter().write("} "); // NOI18N
324: else
325: section.getWriter().write("}\n"); // NOI18N
326: }
327:
328: section.getWriter().commit();
329: }
330:
331: private void resolveSecondLevel(MultiGuardedSection section,
332: List<DesignComponent> sources) {
333: HashMap<String, ArrayList<DesignComponent>> commands2sources = gatherCommands(sources);
334: ArrayList<String> commands = new ArrayList<String>(
335: commands2sources.keySet());
336: Collections.sort(commands);
337:
338: for (int i = 0; i < commands.size(); i++) {
339: String command = commands.get(i);
340: if (i > 0)
341: section.getWriter().write("else "); // NOI18N
342: section.getWriter().write(
343: "if (command == " + command + ") {\n"); // NOI18N
344:
345: for (DesignComponent source : commands2sources
346: .get(command))
347: CodeMultiGuardedLevelPresenter
348: .generateMultiGuardedSectionCode(section,
349: source);
350:
351: assert section.isGuarded();
352: if (i < commands.size() - 1)
353: section.getWriter().write("} "); // NOI18N
354: else
355: section.getWriter().write("}\n"); // NOI18N
356: }
357: }
358:
359: private HashMap<String, ArrayList<DesignComponent>> gatherDisplayables(
360: List<DesignComponent> sources) {
361: HashMap<String, ArrayList<DesignComponent>> d2s = new HashMap<String, ArrayList<DesignComponent>>();
362: for (DesignComponent source : sources) {
363: String displayable = CodeReferencePresenter
364: .generateDirectAccessCode(source.readProperty(
365: CommandEventSourceCD.PROP_DISPLAYABLE)
366: .getComponent());
367: ArrayList<DesignComponent> s = d2s.get(displayable);
368: if (s == null) {
369: s = new ArrayList<DesignComponent>();
370: d2s.put(displayable, s);
371: }
372: s.add(source);
373: }
374: return d2s;
375: }
376:
377: private HashMap<String, ArrayList<DesignComponent>> gatherCommands(
378: List<DesignComponent> sources) {
379: HashMap<String, ArrayList<DesignComponent>> c2s = new HashMap<String, ArrayList<DesignComponent>>();
380: for (DesignComponent source : sources) {
381: String command = CodeReferencePresenter
382: .generateDirectAccessCode(source.readProperty(
383: CommandEventSourceCD.PROP_COMMAND)
384: .getComponent());
385: ArrayList<DesignComponent> s = c2s.get(command);
386: if (s == null) {
387: s = new ArrayList<DesignComponent>();
388: c2s.put(command, s);
389: }
390: s.add(source);
391: }
392: return c2s;
393: }
394:
395: }
396:
397: public static class CodeItemCommandListenerPresenter extends
398: CodeClassLevelPresenter.Adapter {
399:
400: @Override
401: protected void generateClassBodyCode(StyledDocument document) {
402: List<DesignComponent> sources = DocumentSupport
403: .gatherAllComponentsOfTypeID(getComponent()
404: .getDocument(),
405: ItemCommandEventSourceCD.TYPEID);
406: if (sources.size() == 0)
407: return;
408:
409: MultiGuardedSection section = MultiGuardedSection.create(
410: document, getComponent().getComponentID()
411: + "-itemCommandAction"); // NOI18N
412: section
413: .getWriter()
414: .write(
415: "//<editor-fold defaultstate=\"collapsed\" desc=\" Generated Method: commandAction for Items \">\n"); // NOI18N
416: section
417: .getWriter()
418: .write(
419: "/**\n * Called by a system to indicated that a command has been invoked on a particular item.\n * @param command the Command that was invoked\n * @param displayable the Item where the command was invoked\n */\n"); // NOI18N
420: section
421: .getWriter()
422: .write(
423: "public void commandAction (Command command, Item item) {\n")
424: .commit(); // NOI18N
425:
426: section.switchToEditable(getComponent().getComponentID()
427: + "-preItemCommandAction"); // NOI18N
428: section.getWriter().write(
429: " // write pre-action user code here\n").commit(); // NOI18N
430: section.switchToGuarded();
431:
432: resolveFirstLevel(section, sources);
433:
434: section.switchToEditable(getComponent().getComponentID()
435: + "-postItemCommandAction"); // NOI18N
436: section.getWriter().write(
437: " // write post-action user code here\n").commit(); // NOI18N
438: section.switchToGuarded();
439:
440: section.getWriter().write("}\n"); // NOI18N
441: section.getWriter().write("//</editor-fold>\n").commit(); // NOI18N
442: section.close();
443: }
444:
445: private void resolveFirstLevel(MultiGuardedSection section,
446: List<DesignComponent> sources) {
447: HashMap<String, ArrayList<DesignComponent>> items2sources = gatherItems(sources);
448: ArrayList<String> items = new ArrayList<String>(
449: items2sources.keySet());
450: Collections.sort(items);
451:
452: for (int i = 0; i < items.size(); i++) {
453: String item = items.get(i);
454: if (i > 0)
455: section.getWriter().write("else "); // NOI18N
456: section.getWriter().write(
457: "if (item == " + item + ") {\n"); // NOI18N
458:
459: resolveSecondLevel(section, items2sources.get(item));
460:
461: assert section.isGuarded();
462: if (i < items.size() - 1)
463: section.getWriter().write("} "); // NOI18N
464: else
465: section.getWriter().write("}\n"); // NOI18N
466: }
467:
468: section.getWriter().commit();
469: }
470:
471: private void resolveSecondLevel(MultiGuardedSection section,
472: List<DesignComponent> sources) {
473: HashMap<String, ArrayList<DesignComponent>> commands2sources = gatherCommands(sources);
474: ArrayList<String> commands = new ArrayList<String>(
475: commands2sources.keySet());
476: Collections.sort(commands);
477:
478: for (int i = 0; i < commands.size(); i++) {
479: String command = commands.get(i);
480: if (i > 0)
481: section.getWriter().write("else "); // NOI18N
482: section.getWriter().write(
483: "if (command == " + command + ") {\n"); // NOI18N
484:
485: for (DesignComponent source : commands2sources
486: .get(command))
487: CodeMultiGuardedLevelPresenter
488: .generateMultiGuardedSectionCode(section,
489: source);
490:
491: assert section.isGuarded();
492: if (i < commands.size() - 1)
493: section.getWriter().write("} "); // NOI18N
494: else
495: section.getWriter().write("}\n"); // NOI18N
496: }
497: }
498:
499: private HashMap<String, ArrayList<DesignComponent>> gatherItems(
500: List<DesignComponent> sources) {
501: HashMap<String, ArrayList<DesignComponent>> i2s = new HashMap<String, ArrayList<DesignComponent>>();
502: for (DesignComponent source : sources) {
503: String item = CodeReferencePresenter
504: .generateDirectAccessCode(ItemCommandEventSourceCD
505: .getItemComponent(source));
506: ArrayList<DesignComponent> s = i2s.get(item);
507: if (s == null) {
508: s = new ArrayList<DesignComponent>();
509: i2s.put(item, s);
510: }
511: s.add(source);
512: }
513: return i2s;
514: }
515:
516: private HashMap<String, ArrayList<DesignComponent>> gatherCommands(
517: List<DesignComponent> sources) {
518: HashMap<String, ArrayList<DesignComponent>> c2s = new HashMap<String, ArrayList<DesignComponent>>();
519: for (DesignComponent source : sources) {
520: String command = CodeReferencePresenter
521: .generateDirectAccessCode(source.readProperty(
522: CommandEventSourceCD.PROP_COMMAND)
523: .getComponent());
524: ArrayList<DesignComponent> s = c2s.get(command);
525: if (s == null) {
526: s = new ArrayList<DesignComponent>();
527: c2s.put(command, s);
528: }
529: s.add(source);
530: }
531: return c2s;
532: }
533:
534: }
535:
536: }
|