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: */package org.netbeans.modules.vmd.midp.converter.wizard;
041:
042: import com.sun.source.tree.ClassTree;
043: import com.sun.source.tree.Tree;
044: import org.netbeans.api.editor.guards.GuardedSection;
045: import org.netbeans.api.editor.guards.GuardedSectionManager;
046: import org.netbeans.api.editor.guards.InteriorSection;
047: import org.netbeans.api.java.source.CancellableTask;
048: import org.netbeans.api.java.source.CompilationController;
049: import org.netbeans.api.java.source.JavaSource;
050: import org.netbeans.modules.vmd.api.codegen.JavaCodeGenerator;
051: import org.netbeans.modules.vmd.api.model.Debug;
052: import org.netbeans.modules.vmd.api.model.DesignComponent;
053: import org.netbeans.modules.vmd.api.model.DesignDocument;
054: import org.netbeans.modules.vmd.midp.components.MidpDocumentSupport;
055: import org.netbeans.modules.vmd.midp.components.listeners.CommandListenerCD;
056: import org.netbeans.modules.vmd.midp.components.listeners.ItemCommandListenerCD;
057: import org.openide.text.NbDocument;
058: import org.openide.util.Exceptions;
059:
060: import javax.lang.model.element.Modifier;
061: import javax.swing.text.BadLocationException;
062: import javax.swing.text.StyledDocument;
063: import java.io.IOException;
064: import java.util.HashMap;
065: import java.util.List;
066: import java.util.Map;
067:
068: /**
069: * @author David Kaspar
070: */
071: public class ConverterCode {
072:
073: static void convertCode(List<ConverterItem> items,
074: StyledDocument styledDocument,
075: final StyledDocument outputStyledDocument,
076: DesignDocument document, String oldDesignName,
077: String newDesignName) throws BadLocationException {
078: HashMap<String, String> replaceTable = createUserCodeConvertTable(items);
079: replaceTable.put(oldDesignName, newDesignName);
080: GuardedSectionManager manager = GuardedSectionManager
081: .getInstance(styledDocument);
082:
083: final StringBuffer globalCode = new StringBuffer();
084: String getDisplayMethodBody = ""; // NOI18N
085: String exitMIDletMethodBody = ""; // NOI18N
086: String getDisplayBeforeCode = null;
087: String exitMIDletBeforeCode = null;
088:
089: for (GuardedSection section : manager.getGuardedSections()) {
090: if ("MVDFields".equals(section.getName())) { // NOI18N
091: String before = getUserCodeBeforeSection(
092: styledDocument, section);
093: if (before != null)
094: globalCode
095: .append(
096: processUserCodeByTable(
097: replaceTable, before))
098: .append('\n'); // NOI18N
099: } else if ("MVDMethods".equals(section.getName())) { // NOI18N
100: String before = getUserCodeBeforeSection(
101: styledDocument, section);
102: if (before != null)
103: globalCode
104: .append(
105: processUserCodeByTable(
106: replaceTable, before))
107: .append('\n'); // NOI18N
108:
109: } else if ("MVDInitBegin".equals(section.getName())) { // NOI18N
110: long rootID = document.getRootComponent()
111: .getComponentID();
112: putUserCode(outputStyledDocument, rootID
113: + "-initialize", rootID + "-preInitialize",
114: replaceTable, getUserCodeAfterSection(
115: styledDocument, section)); // NOI18N
116:
117: String before = getUserCodeBeforeSection(
118: styledDocument, section);
119: if (before != null)
120: globalCode
121: .append(
122: processUserCodeByTable(
123: replaceTable, before))
124: .append('\n'); // NOI18N
125: } else if ("MVDInitEnd".equals(section.getName())) { // NOI18N
126: long rootID = document.getRootComponent()
127: .getComponentID();
128: putUserCode(outputStyledDocument, rootID
129: + "-initialize", rootID + "-postInitialize",
130: replaceTable, getUserCodeBeforeSection(
131: styledDocument, section)); // NOI18N
132:
133: } else if ("MVDGetDisplay".equals(section.getName())) { // NOI18N
134: getDisplayBeforeCode = getUserCodeBeforeSection(
135: styledDocument, section);
136:
137: InteriorSection is = (InteriorSection) section;
138: getDisplayMethodBody = is.getBody();
139: } else if ("MVDExitMidlet".equals(section.getName())) { // NOI18N
140: exitMIDletBeforeCode = getUserCodeBeforeSection(
141: styledDocument, section);
142:
143: InteriorSection is = (InteriorSection) section;
144: exitMIDletMethodBody = is.getBody();
145:
146: } else if (section.getName().startsWith("MVDGetBegin")) { // NOI18N
147: ConverterItem item = findItemWithUID(items, section
148: .getName().substring("MVDGetBegin".length())); // NOI18N
149: long id = item.getRelatedComponent().getComponentID();
150: putUserCode(
151: outputStyledDocument,
152: id + "-getter",
153: id + "-preInit",
154: replaceTable,
155: getUserCodeAfterSection(styledDocument, section)); // NOI18N
156:
157: String before = getUserCodeBeforeSection(
158: styledDocument, section);
159: if (before != null)
160: globalCode
161: .append(
162: processUserCodeByTable(
163: replaceTable, before))
164: .append('\n'); // NOI18N
165: } else if (section.getName().startsWith("MVDGetEnd")) { // NOI18N
166: ConverterItem item = findItemWithUID(items, section
167: .getName().substring("MVDGetEnd".length())); // NOI18N
168: long id = item.getRelatedComponent().getComponentID();
169: putUserCode(outputStyledDocument, id + "-getter", id
170: + "-postInit", replaceTable,
171: getUserCodeBeforeSection(styledDocument,
172: section)); // NOI18N
173:
174: } else if (section.getName().startsWith("MVDCABegin")) { // NOI18N
175: DesignComponent listener = MidpDocumentSupport
176: .getCommandListener(document,
177: CommandListenerCD.TYPEID);
178: putUserCode(
179: outputStyledDocument,
180: listener.getComponentID() + "-commandAction",
181: listener.getComponentID() + "-preCommandAction",
182: replaceTable,
183: getUserCodeAfterSection(styledDocument, section)); // NOI18N
184:
185: String before = getUserCodeBeforeSection(
186: styledDocument, section);
187: if (before != null)
188: globalCode
189: .append(
190: processUserCodeByTable(
191: replaceTable, before))
192: .append('\n'); // NOI18N
193: } else if (section.getName().startsWith("MVDCAEnd")) { // NOI18N
194: DesignComponent listener = MidpDocumentSupport
195: .getCommandListener(document,
196: CommandListenerCD.TYPEID);
197: putUserCode(outputStyledDocument, listener
198: .getComponentID()
199: + "-commandAction", listener.getComponentID()
200: + "-postCommandAction", replaceTable,
201: getUserCodeBeforeSection(styledDocument,
202: section)); // NOI18N
203:
204: } else if (section.getName().startsWith("MVDCAAction")) { // NOI18N
205: ConverterItem item = findItemWithUID(items, section
206: .getName().substring("MVDCAAction".length())); // NOI18N
207: long id = item.getRelatedComponent().getComponentID();
208: DesignComponent listener = MidpDocumentSupport
209: .getCommandListener(document,
210: CommandListenerCD.TYPEID);
211: putUserCode(outputStyledDocument, listener
212: .getComponentID()
213: + "-commandAction", id + "-preAction",
214: replaceTable, getUserCodeBeforeSection(
215: styledDocument, section)); // NOI18N
216: } else if (section.getName().startsWith("MVDCACase")) { // NOI18N
217: ConverterItem item = findItemWithUID(items, section
218: .getName().substring("MVDCACase".length())); // NOI18N
219: long id = item.getRelatedComponent().getComponentID();
220: DesignComponent listener = MidpDocumentSupport
221: .getCommandListener(document,
222: CommandListenerCD.TYPEID);
223: putUserCode(outputStyledDocument, listener
224: .getComponentID()
225: + "-commandAction", id + "-postAction",
226: replaceTable, getUserCodeBeforeSection(
227: styledDocument, section)); // NOI18N
228:
229: } else if (section.getName().startsWith("MVDICABegin")) { // NOI18N
230: DesignComponent listener = MidpDocumentSupport
231: .getCommandListener(document,
232: ItemCommandListenerCD.TYPEID);
233: putUserCode(
234: outputStyledDocument,
235: listener.getComponentID()
236: + "-itemCommandAction",
237: listener.getComponentID()
238: + "-preItemCommandAction",
239: replaceTable,
240: getUserCodeAfterSection(styledDocument, section)); // NOI18N
241:
242: String before = getUserCodeBeforeSection(
243: styledDocument, section);
244: if (before != null)
245: globalCode
246: .append(
247: processUserCodeByTable(
248: replaceTable, before))
249: .append('\n'); // NOI18N
250: } else if (section.getName().startsWith("MVDICAEnd")) { // NOI18N
251: DesignComponent listener = MidpDocumentSupport
252: .getCommandListener(document,
253: ItemCommandListenerCD.TYPEID);
254: putUserCode(outputStyledDocument, listener
255: .getComponentID()
256: + "-itemCommandAction", listener
257: .getComponentID()
258: + "-postItemCommandAction", replaceTable,
259: getUserCodeBeforeSection(styledDocument,
260: section)); // NOI18N
261:
262: } else if (section.getName().startsWith("MVDICAAction")) { // NOI18N
263: ConverterItem item = findItemWithUID(items, section
264: .getName().substring("MVDICAAction".length())); // NOI18N
265: long id = item.getRelatedComponent().getComponentID();
266: DesignComponent listener = MidpDocumentSupport
267: .getCommandListener(document,
268: ItemCommandListenerCD.TYPEID);
269: putUserCode(outputStyledDocument, listener
270: .getComponentID()
271: + "-itemCommandAction", id + "-preAction",
272: replaceTable, getUserCodeBeforeSection(
273: styledDocument, section)); // NOI18N
274: } else if (section.getName().startsWith("MVDICACase")) { // NOI18N
275: ConverterItem item = findItemWithUID(items, section
276: .getName().substring("MVDICACase".length())); // NOI18N
277: long id = item.getRelatedComponent().getComponentID();
278: DesignComponent listener = MidpDocumentSupport
279: .getCommandListener(document,
280: ItemCommandListenerCD.TYPEID);
281: putUserCode(outputStyledDocument, listener
282: .getComponentID()
283: + "-itemCommandAction", id + "-postAction",
284: replaceTable, getUserCodeBeforeSection(
285: styledDocument, section)); // NOI18N
286: }
287: }
288:
289: if (getDisplayBeforeCode != null)
290: globalCode.append(
291: processUserCodeByTable(replaceTable,
292: getDisplayBeforeCode)).append('\n'); // NOI18N
293: getDisplayMethodBody += "\n // return Display.getDisplay (this);\n"; // NOI18N
294: globalCode
295: .append(" /**\n * Returns a display instance.\n * @return the display instance.\n */\n"); // NOI18N
296: globalCode.append("public Display getDisplay () {\n").append(
297: processUserCodeByTable(replaceTable,
298: getDisplayMethodBody)).append("}\n"); // NOI18N
299: globalCode.append('\n'); // NOI18N
300:
301: if (exitMIDletBeforeCode != null)
302: globalCode.append(
303: processUserCodeByTable(replaceTable,
304: exitMIDletBeforeCode)).append('\n'); // NOI18N
305: exitMIDletMethodBody += "\n // switchDisplayable (null, null);\n // destroyApp(true);\n // notifyDestroyed();\n"; // NOI18N
306: globalCode.append(" /**\n * Exits MIDlet.\n */\n"); // NOI18N
307: globalCode.append("public void exitMIDlet() {\n").append(
308: processUserCodeByTable(replaceTable,
309: exitMIDletMethodBody)).append("}\n"); // NOI18N
310: globalCode.append('\n'); // NOI18N
311:
312: final int[] indices = new int[] { -1, -1 };
313: findIndices(styledDocument, indices);
314:
315: if (indices[0] >= 0) {
316: int i = getFirstGuardedSectionOffset(styledDocument);
317: if (i != Integer.MAX_VALUE && indices[0] < i) {
318: globalCode.append(processUserCodeByTable(replaceTable,
319: styledDocument.getText(indices[0], i
320: - indices[0])));
321: globalCode.append('\n'); // NOI18N
322: }
323: }
324:
325: if (indices[1] >= 0) {
326: int i = getLastGuardedSectionOffset(styledDocument);
327: if (i != Integer.MIN_VALUE && i < indices[1]) {
328: globalCode.append(processUserCodeByTable(replaceTable,
329: styledDocument.getText(i, indices[1] - i)));
330: globalCode.append('\n'); // NOI18N
331: }
332: }
333:
334: NbDocument.runAtomic(outputStyledDocument, new Runnable() {
335: public void run() {
336: int outputOffset = getLastGuardedSectionOffset(outputStyledDocument);
337: assert outputOffset != Integer.MIN_VALUE;
338: try {
339: outputStyledDocument.insertString(outputOffset,
340: globalCode.toString(), null);
341: } catch (BadLocationException e) {
342: Exceptions.printStackTrace(e);
343: }
344: }
345: });
346:
347: // TODO - imports, extends, implements sections
348: // TODO - other classes in the file
349: }
350:
351: private static void findIndices(StyledDocument styledDocument,
352: final int[] indices) {
353: JavaSource source = JavaSource.forDocument(styledDocument);
354: try {
355: source.runUserActionTask(
356: new CancellableTask<CompilationController>() {
357: public void cancel() {
358: }
359:
360: public void run(CompilationController controller)
361: throws Exception {
362: controller
363: .toPhase(JavaSource.Phase.ELEMENTS_RESOLVED);
364: ClassTree mainClass = findMainClass(controller);
365: if (mainClass == null)
366: return;
367:
368: int start = (int) controller
369: .getTrees()
370: .getSourcePositions()
371: .getStartPosition(
372: controller
373: .getCompilationUnit(),
374: mainClass);
375: int end = (int) controller
376: .getTrees()
377: .getSourcePositions()
378: .getEndPosition(
379: controller
380: .getCompilationUnit(),
381: mainClass);
382:
383: if (start < 0 || end < 0 || start >= end)
384: return;
385:
386: int bracket = controller.getText().indexOf(
387: '{', start); // NOI18N
388:
389: if (bracket < 0 || bracket > end)
390: return;
391: if (controller.getText().charAt(end - 1) == '}') // NOI18N
392: end--;
393: indices[0] = bracket + 1;
394: indices[1] = end;
395: }
396: }, true);
397: } catch (IOException e) {
398: throw Debug.error(e);
399: }
400: }
401:
402: static ClassTree findMainClass(CompilationController controller) {
403: for (Tree decl : controller.getCompilationUnit().getTypeDecls()) {
404: if (decl.getKind() == Tree.Kind.CLASS) {
405: ClassTree ct = (ClassTree) decl;
406: if (ct.getModifiers().getFlags().contains(
407: Modifier.PUBLIC))
408: return ct;
409: }
410: }
411: return null;
412: }
413:
414: private static int getFirstGuardedSectionOffset(
415: StyledDocument styledDocument) {
416: GuardedSectionManager manager = GuardedSectionManager
417: .getInstance(styledDocument);
418: int offset = Integer.MAX_VALUE;
419: for (GuardedSection section : manager.getGuardedSections())
420: offset = Math.min(offset, section.getStartPosition()
421: .getOffset());
422: return offset;
423: }
424:
425: private static int getLastGuardedSectionOffset(
426: StyledDocument styledDocument) {
427: GuardedSectionManager manager = GuardedSectionManager
428: .getInstance(styledDocument);
429: int offset = Integer.MIN_VALUE;
430: for (GuardedSection section : manager.getGuardedSections())
431: offset = Math.max(offset, section.getEndPosition()
432: .getOffset() + 1);
433: return offset;
434: }
435:
436: private static String getUserCodeBeforeSection(
437: StyledDocument styledDocument, GuardedSection section)
438: throws BadLocationException {
439: GuardedSectionManager manager = GuardedSectionManager
440: .getInstance(styledDocument);
441: int offset = section.getStartPosition().getOffset();
442: GuardedSection best = null;
443: int bestOffset = 0;
444:
445: for (GuardedSection s : manager.getGuardedSections()) {
446: int o = s.getStartPosition().getOffset();
447: if (offset <= o)
448: continue;
449: if (best == null || bestOffset < o) {
450: best = s;
451: bestOffset = o;
452: }
453: }
454: if (best == null)
455: return null;
456: int start = best.getEndPosition().getOffset() + 1;
457: int end = section.getStartPosition().getOffset();
458: return styledDocument.getText(start, end - start);
459: }
460:
461: private static String getUserCodeAfterSection(
462: StyledDocument styledDocument, GuardedSection section)
463: throws BadLocationException {
464: GuardedSectionManager manager = GuardedSectionManager
465: .getInstance(styledDocument);
466: int offset = section.getStartPosition().getOffset();
467: GuardedSection best = null;
468: int bestOffset = 0;
469:
470: for (GuardedSection s : manager.getGuardedSections()) {
471: int o = s.getStartPosition().getOffset();
472: if (o <= offset)
473: continue;
474: if (best == null || o < bestOffset) {
475: best = s;
476: bestOffset = o;
477: }
478: }
479: if (best == null)
480: return null;
481: int start = section.getEndPosition().getOffset() + 1;
482: int end = best.getStartPosition().getOffset();
483: return styledDocument.getText(start, end - start);
484: }
485:
486: private static ConverterItem findItemWithUID(
487: List<ConverterItem> items, String itemUID) {
488: for (ConverterItem item : items)
489: if (item.getUID().equals(itemUID))
490: return item;
491: return null;
492: }
493:
494: private static void putUserCode(StyledDocument styledDocument,
495: String guardedID, String editableID,
496: HashMap<String, String> replaceTable, String userCode) {
497: userCode = processUserCodeByTable(replaceTable, userCode);
498: JavaCodeGenerator.getDefault().putUserCode(styledDocument,
499: guardedID, editableID, userCode);
500: }
501:
502: private static String processUserCodeByTable(
503: HashMap<String, String> replaceTable, String userCode) {
504: for (Map.Entry<String, String> entry : replaceTable.entrySet()) {
505: String key = entry.getKey();
506: int len = key.length();
507: if (len < 0)
508: continue;
509: int i = 0;
510: for (;;) {
511: i = userCode.indexOf(key, i);
512: if (i < 0)
513: break;
514: if (i > 0
515: && Character.isJavaIdentifierPart(userCode
516: .charAt(i - 1))) {
517: i += len;
518: continue;
519: }
520: if (i + len < userCode.length()
521: && Character.isJavaIdentifierPart(userCode
522: .charAt(i + len))) {
523: i += len;
524: continue;
525: }
526: String value = entry.getValue();
527: userCode = userCode.substring(0, i) + value
528: + userCode.substring(i + len);
529: i += value.length();
530: }
531: }
532: return userCode;
533: }
534:
535: private static HashMap<String, String> createUserCodeConvertTable(
536: List<ConverterItem> items) {
537: HashMap<String, String> table = new HashMap<String, String>();
538: for (ConverterItem item : items) {
539: if (!item.isClass())
540: continue;
541: String name = item.getID();
542: table.put("get_" + name, "get"
543: + Character.toUpperCase(name.charAt(0))
544: + name.substring(1)); // NOI18N
545: }
546: return table;
547: }
548:
549: }
|