diff -r 9387523afe84 editor.lib2/src/org/netbeans/spi/editor/codegen/package.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor.lib2/src/org/netbeans/spi/editor/codegen/package.html Wed May 07 13:29:41 2008 +0200 @@ -0,0 +1,148 @@ + + + + + + + org.netbeans.spi.editor.codegen + + + +

+ The Code Generator SPI gives modules a chance to plug their own code generators + into the popup that appears in the editor on the Insert Code action invocation. +

+ + +

Key parts of the SPI

+ +

+ The whole SPI is organized around the + CodeGenerator + interface, which is the ultimate thing that modules need to implement in order to generate + code snippets and insert them into a document on the Insert Code action invocation. + The CodeGenerators are created by + CodeGenerator.Factory + instances. +

+ +

+ Instances of the + CodeGeneratorContextProvider + interface serve for adding an additonal content to the context which is passed + as a parameter to the + CodeGenerator.Factory.create + method. +

+ + +

CodeGenerator and CodeGeneratorContextProvider registration

+ +

+ The registration of CodeGenerators has to be done through an + instance of the CodeGenerator.Factory class. The factory should + be registered in MimeLookup under the mime-type of documents, which + the CodeGenerator should be used for, in the CodeGenerators + folder. For example, if a module wants to provide CodeGenerator + for text/x-something documents, it should implement its own + CodeGenerator.Factory (e.g. org.some.module.CGFactory + class) and register it in MimeLookup using its XML layer as it is + shown on the example below. +

+ +
+<folder name="Editors">
+  <folder name="text">
+    <folder name="x-something">
+      <folder name="CodeGenerators">
+        <file name="org-some-module-CGFactory.instance" />
+      </folder>
+    </folder>
+  </folder>
+</folder>
+  
+ +

+ The CGFactory class will simply return a new instance of + the module's implementation of the CodeGenerator interface from its + create + method. The method can create and return multiple CodeGenerators. +

+ +

+ The parameter of the create method provides by default access to + the JTextComponent, which the generator is being created for. However, + a group of factories could exist for a mime-type which require access to + an additional data (e.g. some parser result, etc.) when creating their + CodeGenerators. To that purpose, an instance of + CodeGeneratorContextProvider interface could be created and registered + in MimeLookup under the mime-type in the CodeGeneratorContextProviders + folder. For example, if a module wants to provide an additional context for + text/x-something CodeGenerator.Factory it should + implement its own CodeGeneratorContextProvider + (e.g. org.some.module.CGContextProvider class) and register it in + MimeLookup using its XML layer as it is shown on the example below. +

+ +
+<folder name="Editors">
+  <folder name="text">
+    <folder name="x-something">
+      <folder name="CodeGeneratorContextProviders">
+        <file name="org-some-module-CGContextProvider.instance" />
+      </folder>
+    </folder>
+  </folder>
+</folder>
+  
+ +

+ The CGContextProvider class in its + runTaskWithinContext + method creates the new context by merging the original context content + with the additional data and runs the task obtained as the parameter with the newly + created context. +

+ + + diff -r 9387523afe84 editor/src/org/netbeans/modules/editor/codegen/NbGenerateCodeAction.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor/src/org/netbeans/modules/editor/codegen/NbGenerateCodeAction.java Wed May 07 13:29:42 2008 +0200 @@ -0,0 +1,184 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ +package org.netbeans.modules.editor.codegen; + +import javax.swing.text.AbstractDocument; +import javax.swing.text.Document; +import org.netbeans.api.editor.mimelookup.MimePath; +import org.netbeans.api.lexer.TokenHierarchy; +import org.netbeans.api.lexer.TokenSequence; +import org.netbeans.modules.editor.*; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import javax.swing.JMenuItem; +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; +import javax.swing.text.JTextComponent; +import org.netbeans.api.editor.mimelookup.MimeLookup; +import org.netbeans.editor.BaseAction; +import org.netbeans.editor.ext.ExtKit; +import org.netbeans.spi.editor.codegen.CodeGenerator; +import org.netbeans.spi.editor.codegen.CodeGeneratorContextProvider; +import org.openide.util.Lookup; +import org.openide.util.NbBundle; +import org.openide.util.lookup.Lookups; + +/** + * + * @author Dusan Balek, Jan Lahoda + */ +public class NbGenerateCodeAction extends BaseAction { + + public static final String generateCode = "generate-code"; //NOI18N + + public NbGenerateCodeAction(){ + super(generateCode); + putValue(ExtKit.TRIMMED_TEXT, NbBundle.getBundle(NbGenerateCodeAction.class).getString("generate-code-trimmed")); //NOI18N + putValue(SHORT_DESCRIPTION, NbBundle.getBundle(NbGenerateCodeAction.class).getString("desc-generate-code")); //NOI18N + putValue(POPUP_MENU_TEXT, NbBundle.getBundle(NbGenerateCodeAction.class).getString("popup-generate-code")); //NOI18N + } + + public void actionPerformed(ActionEvent evt, final JTextComponent target) { + Task task = new Task(getFullMimePath(target.getDocument(), target.getCaretPosition())); + task.run(Lookups.singleton(target)); + if (task.codeGenerators.size() > 0) { + int altHeight = -1; + Point where = null; + try { + Rectangle carretRectangle = target.modelToView(target.getCaretPosition()); + altHeight = carretRectangle.height; + where = new Point( carretRectangle.x, carretRectangle.y + carretRectangle.height ); + SwingUtilities.convertPointToScreen(where, target); + } catch (BadLocationException ble) { + } + if (where == null) + where = new Point(-1, -1); + PopupUtil.showPopup(new GenerateCodePanel(target, task.codeGenerators), null, where.x, where.y, true, altHeight); + } else { + target.getToolkit().beep(); + } + } + + static String[] test(Document doc, int pos) { + Task task = new Task(getFullMimePath(doc, pos)); + task.run(Lookups.fixed()); + String[] ret = new String[task.codeGenerators.size()]; + int i = 0; + for (CodeGenerator codeGenerator : task.codeGenerators) + ret[i++] = codeGenerator.getDisplayName(); + return ret; + } + + private static MimePath getFullMimePath(Document document, int offset) { + String langPath = null; + + if (document instanceof AbstractDocument) { + AbstractDocument adoc = (AbstractDocument)document; + adoc.readLock(); + try { + List> list = TokenHierarchy.get(document).embeddedTokenSequences(offset, true); + if (list.size() > 1) { + langPath = list.get(list.size() - 1).languagePath().mimePath(); + } + } finally { + adoc.readUnlock(); + } + } + + if (langPath == null) { + langPath = NbEditorUtilities.getMimeType(document); + } + + if (langPath != null) { + return MimePath.parse(langPath); + } else { + return null; + } + } + + private static class Task implements CodeGeneratorContextProvider.Task { + private MimePath mimePath; + private Iterator contextProviders; + private List codeGenerators = new ArrayList(); + + private Task(MimePath mimePath) { + this.mimePath = mimePath; + contextProviders = MimeLookup.getLookup(mimePath).lookupAll(CodeGeneratorContextProvider.class).iterator(); + } + + public void run(Lookup context) { + if (contextProviders.hasNext()) { + contextProviders.next().runTaskWithinContext(context, this); + } else { + for (CodeGenerator.Factory factory : MimeLookup.getLookup(mimePath).lookupAll(CodeGenerator.Factory.class)) + codeGenerators.addAll(factory.create(context)); + } + } + } + + public static final class GlobalAction extends MainMenuAction { + + private final JMenuItem menuPresenter; + + public GlobalAction() { + super(); + this.menuPresenter = new JMenuItem(getMenuItemText()); + setMenu(); + } + + protected String getMenuItemText() { + return NbBundle.getBundle(GlobalAction.class).getString("generate-code-main-menu-source-item"); //NOI18N + } + + protected String getActionName() { + return generateCode; + } + + public JMenuItem getMenuPresenter() { + return menuPresenter; + } + + } // End of GlobalAction class +} diff -r 9387523afe84 editor/test/unit/src/org/netbeans/modules/editor/codegen/CodeGenerationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor/test/unit/src/org/netbeans/modules/editor/codegen/CodeGenerationTest.java Wed May 07 13:29:42 2008 +0200 @@ -0,0 +1,85 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ +package org.netbeans.modules.editor.codegen; + +import javax.swing.text.Document; +import org.netbeans.modules.editor.*; +import java.net.URL; +import javax.swing.text.DefaultStyledDocument; +import junit.framework.TestCase; + +/** + * + * @author Dusan Balek + */ +public class CodeGenerationTest extends TestCase { + + public CodeGenerationTest(String testName) { + super(testName); + } + + // TODO add test methods here. The name must begin with 'test'. For example: + // public void testHello() {} + protected void setUp() throws Exception { + EditorTestLookup.setLookup( + new URL[]{EditorTestConstants.EDITOR_LAYER_URL, + getClass().getClassLoader().getResource("org/netbeans/modules/editor/resources/codegen-test-layer.xml") + }, + new Object[]{}, + getClass().getClassLoader()); + } + + public void testSimpleCodeGenerator() { + Document doc = new DefaultStyledDocument(); + doc.putProperty(NbEditorDocument.MIME_TYPE_PROP, "text/x-simple-codegen-test"); + String[] generatorNames = NbGenerateCodeAction.test(doc, 0); + assertEquals(generatorNames.length, 1); + assertEquals(generatorNames[0], "SimpleCodeGenerator"); + } + + public void testCodeGenerator() { + Document doc = new DefaultStyledDocument(); + doc.putProperty(NbEditorDocument.MIME_TYPE_PROP, "text/x-codegen-test"); + String[] generatorNames = NbGenerateCodeAction.test(doc, 0); + assertEquals(generatorNames.length, 1); + assertEquals(generatorNames[0], "CodeGenerator"); + } +} diff -r 9387523afe84 editor/test/unit/src/org/netbeans/modules/editor/codegen/TestCodeGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor/test/unit/src/org/netbeans/modules/editor/codegen/TestCodeGenerator.java Wed May 07 13:29:42 2008 +0200 @@ -0,0 +1,83 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2008 Sun Microsystems, Inc. + */ + +package org.netbeans.modules.editor.codegen; + +import java.util.Collections; +import java.util.List; +import org.netbeans.spi.editor.codegen.CodeGenerator; +import org.netbeans.spi.editor.codegen.CodeGeneratorContextProvider; +import org.openide.util.Lookup; +import org.openide.util.lookup.Lookups; +import org.openide.util.lookup.ProxyLookup; + +/** + * + * @author Dusan Balek + */ +public class TestCodeGenerator implements CodeGenerator { + + private boolean b; + + public TestCodeGenerator(boolean b) { + this.b = b; + } + + public String getDisplayName() { + return b ? "CodeGenerator" : "SimpleCodeGenerator"; + } + + public void invoke() { + } + + public static class Factory implements CodeGenerator.Factory { + + public List create(Lookup context) { + Object o = context.lookup(ContextProvider.class); + return Collections.singletonList(new TestCodeGenerator(o != null)); + } + } + + public static class ContextProvider implements CodeGeneratorContextProvider { + + public void runTaskWithinContext(Lookup context, Task task) { + task.run(new ProxyLookup(context, Lookups.singleton(this))); + } + } +} diff -r 9387523afe84 editor/test/unit/src/org/netbeans/modules/editor/resources/codegen-test-layer.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor/test/unit/src/org/netbeans/modules/editor/resources/codegen-test-layer.xml Wed May 07 13:29:42 2008 +0200 @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + +