当前页面: 开发资料首页 → Netbeans 专题 → NetBeans Copy Class Refactoring 模块教程
摘要: NetBeans Copy Class Refactoring 模块教程 反馈 请注意, 并不是本教程中介绍的所有 API 都是当前最新的 。在您自己的磁盘上使用它们。不保证本教程中使用的 NetBe...
重构是使用一些小变换重新设计代码,但不会改变任何程序行为。就像您构造一个表达式使它更容易理解和修改一样,您重构代码可以使其更容易读,更容易理解,更快更新。就像重构的表达式必须产生相同的效果一样,重构的程序必须与原始源具有相同的功能。
重构代码的一些常见目的包括:
本教程向您介绍如何通过添加附加的重构功能即 Copy Class 来扩展 IDE。Copy Class 功能允许您向相同或不同的包复制类。当您复制类时,您可以更改名称,也可以更改构造方法的名称。如果该类被复制到一个新包,则自动更新包声明。
本教程将介绍以下主题:
有关创建 NetBeans 插件模块的更多信息,请参见 NetBeans 网站上的 NetBeans Development Project 主页。如果有问题,请访问 NetBeans Developer FAQ 或使用本页顶部的反馈链接。
开始编写插件模块之前,必须确保您具备所有必要的软件。此外,您可能想在亲自构建之前使用示例。
开始之前,需要在您的计算机上安装以下软件:
采用以下步骤来安装示例:
将打开 Copy Class 对话框,如下所示:
也可以使用 To Package 下拉菜单选择将 Java 源文件复制到的包。如果没有选择包,则将该文件复制到包含原始文件的包。
现在您了解了 Copy Class Refactoring 插件模块的用户界面,让我们从头开始创建该模块。
开始编写模块前,必须确保正确地设置了项目。
当您使 IDE 的源可用于 NetBeans Platform Manager 时,您可以从 Source Editor 中访问 IDE 的源文件和 Javadoc。这样便简化了插件模块的开发,原因是它使您能够非常快速地查找有关执行的类和方法的信息。整个教程中都提到源和 Javadoc,因此应该在进行下一步前先使它们可用。
IDE 创建 CopyClassRefactoring 项目。该项目包含所有资源和项目元数据,如该项目的 Ant 构建脚本。该项目在 IDE 中打开。您可以在 Projects 窗口 (Ctrl-1) 中查看其逻辑结构,在 Files 窗口 (Ctrl-2) 中查看其文件结构。
您需要将几个属于 NetBeans API 的类设为子类。每个类都将被声明为 Module 依存关系。使用 Project Properties 对话框来执行此操作。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://www.netbeans.org/ns/project/1"> <type>org.netbeans.modules.apisupport.project</type> <configuration> <data xmlns="http://www.netbeans.org/ns/nb-module-project/2"> <code-name-base>org.netbeans.modules.refactoring.copyclass</code-name-base> <standalone/> <module-dependencies> <dependency> <code-name-base>javax.jmi.reflect</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> <release-version>1</release-version> <specification-version>1.6</specification-version> </run-dependency> </dependency> <dependency> <code-name-base>org.netbeans.api.mdr</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> <release-version>1</release-version> </run-dependency> </dependency> <dependency> <code-name-base>org.netbeans.jmi.javamodel</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> <release-version>2</release-version> <specification-version>1.19.0</specification-version> </run-dependency> </dependency> <dependency> <code-name-base>org.netbeans.modules.java</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> <release-version>1</release-version> <specification-version>1.24.0.2.2.2</specification-version> </run-dependency> </dependency> <dependency> <code-name-base>org.netbeans.modules.java.project</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> <release-version>1</release-version> <specification-version>1.7</specification-version> </run-dependency> </dependency> <dependency> <code-name-base>org.netbeans.modules.javacore</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> <release-version>1</release-version> <specification-version>1.16.0.2.2</specification-version> </run-dependency> </dependency> <dependency> <code-name-base>org.netbeans.modules.jmiutils</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> <release-version>1</release-version> <specification-version>1.4.0.2</specification-version> </run-dependency> </dependency> <dependency> <code-name-base>org.netbeans.modules.projectapi</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> <release-version>1</release-version> </run-dependency> </dependency> <dependency> <code-name-base>org.netbeans.modules.projectuiapi</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> <release-version>1</release-version> </run-dependency> </dependency> <dependency> <code-name-base>org.netbeans.modules.refactoring</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> <release-version>1</release-version> <implementation-version/> </run-dependency> </dependency> <dependency> <code-name-base>org.openide.awt</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> <specification-version>6.6</specification-version> </run-dependency> </dependency> <dependency> <code-name-base>org.openide.filesystems</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> <specification-version>6.2</specification-version> </run-dependency> </dependency> <dependency> <code-name-base>org.openide.loaders</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> <specification-version>5.4</specification-version> </run-dependency> </dependency> <dependency> <code-name-base>org.openide.modules</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> <specification-version>6.2</specification-version> </run-dependency> </dependency> <dependency> <code-name-base>org.openide.nodes</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> <specification-version>6.2</specification-version> </run-dependency> </dependency> <dependency> <code-name-base>org.openide.text</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> <specification-version>6.2</specification-version> </run-dependency> </dependency> <dependency> <code-name-base>org.openide.util</code-name-base> <build-prerequisite/> <compile-dependency/> <run-dependency> <specification-version>6.5</specification-version> </run-dependency> </dependency> </module-dependencies> <public-packages/> </data> </configuration> </project>
重构的非可视部分执行重构逻辑。基本上它由两个类组成,即“refactoring”类和“refactoring plugin”类。
refactoring 类作为用于调用重构的 API。此外,refactoring plugin 类使用它来确定重构参数。refactoring 类本身几乎不执行任何工作,所有工作都由 refactoring plugin 类来完成。refactoring 类通常只包含重构参数的获取方法和设置方法。参数为 newName、targetFolder 和 targetPackageName。它们在 Copy Class 对话框中使用:
执行以下操作:
package org.netbeans.modules.refactoring.copyclass; import org.netbeans.jmi.javamodel.Resource; import org.netbeans.modules.refactoring.api.AbstractRefactoring; import org.netbeans.modules.refactoring.classpath.Util; import org.openide.filesystems.FileObject; public final class CopyClassRefactoring extends AbstractRefactoring { private Resource resource; private FileObject targetFolder; private String targetPackageName; private String newName; /** Creates a new instance of CopyClassRefactoring * */ public CopyClassRefactoring(Resource resource) { this.resource = resource; } protected void setClassPath() { // leave the complete classpath Util.setDefaultClassPath(); } public Resource getResource() { return resource; } // --- START PARAMETERS ---------------------------------------------------------- public FileObject getTargetClassPathRoot() { return targetFolder; } public void setTargetClassPathRoot(FileObject targetFolder) { this.targetFolder = targetFolder; } public String getTargetPackageName() { return targetPackageName; } public void setTargetPackageName(String newName) { this.targetPackageName = newName; } public String getNewName() { return newName; } public void setNewName(String newName) { this.newName = newName; } // --- END PARAMETERS ---------------------------------------------------------- }
单击该链接。AbstractRefactoring 类在 Source Editor 中打开。熟悉一下源文件并理解它如何与其 CopyClassRefactoring 实现相关。
每个重构都应该至少有一个执行所有工作的插件类。重构模块本身应该提供进行 J2SE 重构的基本插件类。其他模块可以添加其他插件,这允许它们参与重构。例如,当重命名一个方法时,J2EE 插件类需要重命名 EJB(如有必要)的其他界面中的相关方法,并且更改部署描述符。下面介绍的插件类是执行所有基本 J2SE 工作的基本插件类。
插件类需要实现的四个方法为:
由 prepare() 方法实例化重构元素并将其添加到作为输出参数的 RefactoringElementsBag 的实例。
所有上面的方法都返回名为 Problem 的类的实例。该类的实例代表对于执行重构来说可能是致命的或非致命的问题。这些方法执行各种检查(如给定重构的规范中所述)并返回它们发现的问题作为提到的 Problem 类的实例。可以将这些问题链接起来(使用 Problem.setNext() 方法),这有可能返回单次操作中的几个问题。注意致命问题必须位于链首。使用 JavaRefactoringPlugin.createProblem() 方法创建问题将自动确保此要求。所有方法(除 fastCheckParameters() 之外)都应该激发进度事件,因为它们正在执行潜在的耗费时间的操作。
执行以下操作:
package org.netbeans.modules.refactoring.copyclass;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Iterator;
import java.util.StringTokenizer;
import org.netbeans.jmi.javamodel.Element;
import org.netbeans.jmi.javamodel.Import;
import org.netbeans.jmi.javamodel.ImportClass;
import org.netbeans.jmi.javamodel.JavaClass;
import org.netbeans.jmi.javamodel.JavaModelPackage;
import org.netbeans.jmi.javamodel.Resource;
import org.netbeans.modules.javacore.JMManager;
import org.netbeans.modules.javacore.api.JavaModel;
import org.netbeans.modules.javacore.internalapi.JavaMetamodel;
import org.netbeans.modules.javacore.internalapi.JavaModelUtil;
import org.netbeans.modules.refactoring.CheckUtils;
import org.netbeans.modules.refactoring.api.AbstractRefactoring;
import org.netbeans.modules.refactoring.api.MoveClassRefactoring;
import org.netbeans.modules.refactoring.api.Problem;
import org.netbeans.modules.refactoring.api.RenameRefactoring;
import org.netbeans.modules.refactoring.plugins.JavaRefactoringPlugin;
import org.netbeans.modules.refactoring.plugins.MoveClassRefactoringPlugin;
import org.netbeans.modules.refactoring.spi.SimpleRefactoringElementImpl;
import org.netbeans.modules.refactoring.spi.RefactoringElementImplementation;
import org.netbeans.modules.refactoring.spi.RefactoringElementsBag;
import org.openide.ErrorManager;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataFolder;
import org.openide.loaders.DataObject;
import org.openide.text.PositionBounds;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
/** Plugin that implements the core functionality of Copy Class Refactoring.
*/
public class CopyClassRefactoringPlugin extends JavaRefactoringPlugin {
/** Reference to the parent refactoring instance */
private final CopyClassRefactoring refactoring;
/** Creates a new instance of PullUpRefactoringPlugin
* @param refactoring Parent refactoring instance.
*/
CopyClassRefactoringPlugin(CopyClassRefactoring refactoring) {
this.refactoring = refactoring;
}
/** Checks pre-conditions of the refactoring.
* @return Problems found or null
.
*/
public Problem preCheck() {
fireProgressListenerStart(AbstractRefactoring.PRE_CHECK, 4);
try {
Resource resource = refactoring.getResource();
// check whether the element is valid
Problem result = isElementAvail(resource);
if (result != null) {
// fatal error -> don't continue with further checks
return result;
}
if (!CheckUtils.isElementInOpenProject(resource)) {
return new Problem(true, NbBundle.getMessage(JavaRefactoringPlugin.class, "ERR_ProjectNotOpened"));
}
// increase progress (step 1)
fireProgressListenerStep();
// increase progress (step 2)
fireProgressListenerStep();
// increase progress (step 3)
fireProgressListenerStep();
// all checks passed -> return null
return null;
} finally {
// fire operation end on the registered progress listeners
fireProgressListenerStop();
}
}
public Problem fastCheckParameters() {
if (!Utilities.isJavaIdentifier(refactoring.getNewName())) {
String msg = new MessageFormat(NbBundle.getMessage(RenameRefactoring.class, "ERR_InvalidIdentifier")).format(
new Object[] {refactoring.getNewName()}
);
return createProblem(null, true, msg);
}
if (!isValidPackageName(refactoring.getTargetPackageName())) {
String msg = new MessageFormat(NbBundle.getMessage(RenameRefactoring.class, "ERR_InvalidPackage")).format(
new Object[] {refactoring.getTargetPackageName()}
);
return createProblem(null, true, msg);
}
String name = refactoring.getTargetPackageName().replace('.','/') + '/' + refactoring.getNewName() + ".java";
if (refactoring.getTargetClassPathRoot().getFileObject(name) != null)
return createProblem(null, true,
new MessageFormat(NbBundle.getMessage(MoveClassRefactoring.class,
"ERR_ClassToMoveClashes")).format(new Object[]{refactoring.getNewName()}));
return null;
}
private static boolean isValidPackageName(String name) {
StringTokenizer tokenizer = new StringTokenizer(name, "."); // NOI18N
while (tokenizer.hasMoreTokens()) {
if (!Utilities.isJavaIdentifier(tokenizer.nextToken())) {
return false;
}
}
return true;
}
public Problem checkParameters() {
return null;
}
public Problem prepare(RefactoringElementsBag refactoringElements) {
refactoringElements.add(refactoring,
new CopyClass(
refactoring.getResource(),
refactoring.getTargetClassPathRoot(),
refactoring.getTargetPackageName(),
refactoring.getNewName()
));
return null;
}
}
单击该链接。JavaRefactoringPlugin 类在 Source Editor 中打开。熟悉一下源文件并理解它如何与其 CopyClassRefactoringPlugin 实现相关。
private static class CopyClass extends SimpleRefactoringElementImpl implements RefactoringElementImplementation{ private DataObject source; private FileObject targetRoot; private String targetPackageName; private String newName; private Resource resource; public CopyClass (Resource resource, FileObject targetRoot, String packageName, String newName) { this.source = ((JMManager) JMManager.getManager()).getDataObject(resource); this.resource = resource; this.targetRoot = targetRoot; this.targetPackageName = packageName; this.newName = newName; } public String getText() { return getDisplayText (); } public String getDisplayText() { return new MessageFormat (NbBundle.getMessage(CopyClassRefactoringPlugin.class, "TXT_CopyClassToPackage")).format ( // NOI18N new Object[] {newName, targetPackageName, resource.getName()} ); } public Element getJavaElement() { return null; } public PositionBounds getPosition() { return null; } public void performChange() { String nameAfterCopy = null; try { FileObject fo = FileUtil.createFolder(targetRoot, targetPackageName.replace('.','/')); DataFolder folder = DataFolder.findFolder(fo); objectToDelete = source.copy(folder); nameAfterCopy = objectToDelete.getName(); objectToDelete.rename(newName); } catch (IOException ioe) { ErrorManager.getDefault().notify(ioe); } Resource r = JavaModel.getResource(objectToDelete.getPrimaryFile()); String name = resource.getPackageName(); ImportClass proxy = ((JavaModelPackage) r.refOutermostPackage()).getImport(); Import addedImport = proxy.createImport(name, null, false, true); r.addImport(addedImport); for (Iterator i = r.getClassifiers().iterator(); i.hasNext(); ) { JavaClass c = (JavaClass) i.next(); if (c.getSimpleName().equals(nameAfterCopy)) { c.setSimpleName(newName); } } } private DataObject objectToDelete = null; public FileObject getParentFile() { return source.getPrimaryFile(); } }
单击该链接。RefactoringElementImplementation 类在 Source Editor 中打开。熟悉一下源文件并理解它如何与其内部 CopyClass 实现相关。
插件类的实例化由插件工厂执行。通过重构调用调用的 META-INF/services 文件夹中的一个条目,插件工厂在 NetBeans 查询中注册。为了确保调用给定重构时实例化插件类,您需要在工厂的 createInstance() 方法的开始部分为您的插件类添加以下实例化代码:
if (refactoring instanceof YourRefactoring) { return new YourRefactoringPlugin((YourRefactoring) refactoring); }
从上面可以看出,createInstance() 方法将父重构视为参数。每个插件类应该参考父重构以便能够从中获得重构参数。这就是插件类通常将重构作为构造方法参数的原因。
执行以下操作:
package org.netbeans.modules.refactoring.copyclass;
import org.netbeans.modules.refactoring.api.AbstractRefactoring;
import org.netbeans.modules.refactoring.spi.RefactoringPlugin;
import org.netbeans.modules.refactoring.spi.RefactoringPluginFactory;
public class PluginsFactory implements RefactoringPluginFactory {
/** Factory method called by a refactoring. Creates and returns a new plugin
* instance for a given refactoring. If no plugin for a given refactoring
* is present, this method returns null.
* @param refactoring Parent refactoring for which a plugin should be created.
* @return New instance of a refactoring plugin for the provided refactoring
* or null
.
*/
public RefactoringPlugin createInstance(AbstractRefactoring refactoring) {
if (refactoring instanceof CopyClassRefactoring) {
return new CopyClassRefactoringPlugin((CopyClassRefactoring) refactoring);
}
return null;
}
}
单击该链接。RefactoringPluginFactory 类在 Source Editor 中打开。熟悉一下源文件并理解它如何与其 PluginsFactory 实现相关。
org.netbeans.modules.refactoring.copyclass.PluginsFactory
此时,Projects 窗口应该如下所示:
用户界面由三个组件组成:
要实现重构操作,您需要创建 org.netbeans.modules.refactoring.spi.ui.AbstractRefactoringAction 的子类。感兴趣的部分是 enabled() 和 createRefactoringUI() 方法:
执行以下操作:
package org.netbeans.modules.refactoring.copyclass.ui; import org.netbeans.jmi.javamodel.Element; import org.netbeans.modules.java.JavaDataObject; import org.netbeans.modules.javacore.JMManager; import org.netbeans.modules.javacore.api.JavaModel; import org.netbeans.modules.javacore.internalapi.JavaMetamodel; import org.netbeans.modules.refactoring.spi.ui.AbstractRefactoringAction; import org.netbeans.modules.refactoring.spi.ui.RefactoringUI; import org.openide.loaders.DataObject; import org.openide.nodes.Node; import org.openide.util.NbBundle; public class CopyClassAction extends AbstractRefactoringAction { /** Creates a new instance of PullUpAction */ public CopyClassAction() { super(NbBundle.getMessage(CopyClassAction.class, "LBL_CopyClass_Action"), null); // NOI18N putValue("noIconInMenu", Boolean.TRUE); // NOI18N } /** Method responsible for creating RefactoringUI object. * @param nodes Active nodes to perform the refactoring on. * @param selectedElement Element to perform the refactoring on or null if the action * was not invoked from the editor - in that case the active nodes take * the precedence. * @return RefactoringUI object for Copy Class refactoring. */ protected RefactoringUI createRefactoringUI(Node[] nodes, Element selectedElement) { if (selectedElement == null) { // selected element is null -> action was invoked on nodes JavaDataObject ob = (JavaDataObject) nodes[0].getCookie(JavaDataObject.class); selectedElement = JavaModel.getResource(ob.getPrimaryFile()); } return new CopyClassRefactoringUI(selectedElement.getResource()); } /** Method that determines whether this action is enabled for the active nodes. * @param activatedNodes Active nodes. * @return Boolean indicating whether the action is enabled. */ protected boolean enabled(Node[] activatedNodes) { // if no nodes are active, the action should be disabled if (activatedNodes.length != 1) return false; // the action should be enabled only if all selected nodes are associated // with the same JavaDataObject (i.e. they are all declared in the same Java file) // so, let's get dataobject from the first activated node DataObject dobj = (DataObject) activatedNodes[0].getCookie(DataObject.class); // check if the dataobject is instance of JavaDataObejct and that it represents a file // that is on the IDE classpath (belongs to one of open projects) if ((dobj instanceof JavaDataObject) && ((JMManager) JavaMetamodel.getManager()).mergedCPContains(dobj.getPrimaryFile())) { return true; } else { return false; } } protected String iconResource () { return "org/netbeans/modules/refactoring/resources/refactoring.gif"; // NOI18N } }
单击该链接。AbstractRefactoringAction 类在 Source Editor 中打开。熟悉一下源文件并理解它如何与其 CopyClassAction 实现相关。
要将该模块插入到重构框架中,您需要创建 org.netbeans.modules.refactoring.spi.ui.RefactoringUI 的子类。感兴趣的部分是 getPanel() 和 checkParameters() 方法:
执行以下操作:
package org.netbeans.modules.refactoring.copyclass.ui; import org.netbeans.jmi.javamodel.JavaClass; import org.netbeans.jmi.javamodel.Resource; import org.netbeans.modules.javacore.api.JavaModel; import org.netbeans.modules.refactoring.api.AbstractRefactoring; import org.netbeans.modules.refactoring.api.Problem; import org.netbeans.modules.refactoring.copyclass.CopyClassRefactoring; import org.netbeans.modules.refactoring.spi.ui.CustomRefactoringPanel; import org.netbeans.modules.refactoring.spi.ui.ParametersPanel; import org.netbeans.modules.refactoring.spi.ui.RefactoringUI; import org.netbeans.modules.refactoring.ui.PullUpRefactoringUI; import org.openide.util.HelpCtx; import org.openide.util.NbBundle; public class CopyClassRefactoringUI implements RefactoringUI { // reference to pull up refactoring this UI object corresponds to private final CopyClassRefactoring refactoring; // UI panel for collecting parameters private CopyClassPanel panel; public CopyClassRefactoringUI(Resource resource) { refactoring = new CopyClassRefactoring(resource); } // --- IMPLEMENTATION OF RefactoringUI INTERFACE --------------------------- public boolean isQuery() { return false; } public CustomRefactoringPanel getPanel(ParametersPanel parent) { if (panel == null) { panel = new CopyClassPanel(parent, getName() + " - " + ((JavaClass) refactoring.getResource().getClassifiers().get(0)).getName(), refactoring.getResource().getPackageName(), JavaModel.getFileObject(refactoring.getResource())); } return panel; } public Problem setParameters() { setupRefactoring(); return refactoring.checkParameters(); } public Problem checkParameters() { if (panel==null) return null; setupRefactoring(); return refactoring.fastCheckParameters(); } private void setupRefactoring() { refactoring.setTargetClassPathRoot(panel.getRootFolder()); refactoring.setTargetPackageName(panel.getPackageName().replace('/', '.')); refactoring.setNewName(panel.getNewName()); } public AbstractRefactoring getRefactoring() { return refactoring; } public String getDescription() { return NbBundle.getMessage(CopyClassAction.class, "DSC_CopyClass", refactoring.getNewName()); // NOI18N } public String getName() { return NbBundle.getMessage(CopyClassAction.class, "LBL_CopyClass"); // NOI18N } public boolean hasParameters() { return true; } public HelpCtx getHelpCtx() { return new HelpCtx(PullUpRefactoringUI.class.getName()); } }
单击该链接。RefactoringUI 类在 Source Editor 中打开。熟悉一下源文件并理解它如何与其内部 CopyClassRefactoringUI 实现相关。
执行以下操作:
package org.netbeans.modules.refactoring.copyclass.ui; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListCellRenderer; import javax.swing.JList; import javax.swing.JTextField; import javax.swing.ListCellRenderer; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.netbeans.api.java.project.JavaProjectConstants; import org.netbeans.api.project.FileOwnerQuery; import org.netbeans.api.project.Project; import org.netbeans.api.project.ProjectInformation; import org.netbeans.api.project.ProjectUtils; import org.netbeans.api.project.SourceGroup; import org.netbeans.api.project.Sources; import org.netbeans.api.project.ui.OpenProjects; import org.netbeans.modules.refactoring.spi.ui.CustomRefactoringPanel; import org.netbeans.modules.refactoring.spi.ui.ParametersPanel; import org.netbeans.spi.java.project.support.ui.PackageView; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; public class CopyClassPanel extends CustomRefactoringPanel implements ActionListener, DocumentListener { private static final ListCellRenderer GROUP_CELL_RENDERER = new GroupCellRenderer(); private static final ListCellRenderer PROJECT_CELL_RENDERER = new ProjectCellRenderer(); private Project project; private ParametersPanel parent; private FileObject fo; private SourceGroup[] groups; public CopyClassPanel(final ParametersPanel parent, String title, String startPackage, FileObject f) { setName(title); this.fo = f; this.parent = parent; initComponents(); setCombosEnabled(true); setThisClassVisible(true); rootComboBox.setRenderer(GROUP_CELL_RENDERER); packageComboBox.setRenderer(PackageView.listRenderer()); projectsComboBox.setRenderer( PROJECT_CELL_RENDERER ); rootComboBox.addActionListener( this ); packageComboBox.addActionListener( this ); projectsComboBox.addActionListener( this ); Object textField = packageComboBox.getEditor().getEditorComponent(); if (textField instanceof JTextField) { ((JTextField) textField).getDocument().addDocumentListener(this); } newNameTextField.getDocument().addDocumentListener(this); newNameTextField.setSelectionStart(0); newNameTextField.setSelectionEnd(newNameTextField.getText().length()); project = fo != null ? FileOwnerQuery.getOwner(fo):OpenProjects.getDefault().getOpenProjects()[0]; initValues(startPackage); } private boolean initialized = false; public void initialize() { if (initialized) return ; //put initialization code here initialized = true; } public void initValues(String preselectedFolder ) { Project openProjects[] = OpenProjects.getDefault().getOpenProjects(); DefaultComboBoxModel projectsModel = new DefaultComboBoxModel( openProjects ); projectsComboBox.setModel( projectsModel ); projectsComboBox.setSelectedItem( project ); updateRoots(); updatePackages(); if (preselectedFolder != null) { packageComboBox.setSelectedItem(preselectedFolder); } // Determine the extension } public void requestFocus() { newNameTextField.requestFocus(); } public FileObject getRootFolder() { return ((SourceGroup) rootComboBox.getSelectedItem()).getRootFolder(); } public String getPackageName() { String packageName = packageComboBox.getEditor().getItem().toString(); return packageName.replace('.', '/'); // NOI18N } private void fireChange() { parent.stateChanged(null); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ //private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; labelProject = new javax.swing.JLabel(); projectsComboBox = new javax.swing.JComboBox(); labelLocation = new javax.swing.JLabel(); rootComboBox = new javax.swing.JComboBox(); labelPackage = new javax.swing.JLabel(); packageComboBox = new javax.swing.JComboBox(); bottomPanel = new javax.swing.JPanel(); newNameLabel = new javax.swing.JLabel(); newNameTextField = new javax.swing.JTextField(); setLayout(new java.awt.GridBagLayout()); labelProject.setLabelFor(projectsComboBox); org.openide.awt.Mnemonics.setLocalizedText(labelProject, org.openide.util.NbBundle.getMessage(CopyClassPanel.class, "LBL_Project")); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, 0, 6, 0); add(labelProject, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 6, 6, 0); add(projectsComboBox, gridBagConstraints); projectsComboBox.getAccessibleContext().setAccessibleDescription (java.util.ResourceBundle.getBundle("org/netbeans/modules/refactoring/ui/Bundle"). getString("ACSD_projectsCombo")); labelLocation.setLabelFor(rootComboBox); org.openide.awt.Mnemonics.setLocalizedText(labelLocation, org.openide.util.NbBundle.getMessage(CopyClassPanel.class, "LBL_Location")); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, 0, 6, 0); add(labelLocation, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 3; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 6, 6, 0); add(rootComboBox, gridBagConstraints); rootComboBox.getAccessibleContext().setAccessibleDescription (java.util.ResourceBundle.getBundle("org/netbeans/modules/refactoring/ui/Bundle").getString("ACSD_rootCombo")); labelPackage.setLabelFor(packageComboBox); org.openide.awt.Mnemonics.setLocalizedText(labelPackage, org.openide.util.NbBundle.getMessage(CopyClassPanel.class, "LBL_ToPackage")); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 4; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, 0, 12, 0); add(labelPackage, gridBagConstraints); packageComboBox.setEditable(true); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 4; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 6, 12, 0); add(packageComboBox, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 5; gridBagConstraints.gridwidth = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(bottomPanel, gridBagConstraints); org.openide.awt.Mnemonics.setLocalizedText(newNameLabel, org.openide.util.NbBundle.getMessage(CopyClassPanel.class, "LBL_NewName")); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, 0, 6, 0); add(newNameLabel, gridBagConstraints); newNameTextField.setText("NewClass"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 6, 6, 0); add(newNameTextField, gridBagConstraints); } // // Variables declaration - do not modify protected javax.swing.JPanel bottomPanel; private javax.swing.JLabel labelLocation; private javax.swing.JLabel labelPackage; private javax.swing.JLabel labelProject; private javax.swing.JLabel newNameLabel; private javax.swing.JTextField newNameTextField; private javax.swing.JComboBox packageComboBox; private javax.swing.JComboBox projectsComboBox; private javax.swing.JComboBox rootComboBox; // End of variables declaration // ActionListener implementation ------------------------------------------- public void actionPerformed(ActionEvent e) { if (projectsComboBox == e.getSource()) { project = (Project) projectsComboBox.getSelectedItem(); updateRoots(); updatePackages(); } else if ( rootComboBox == e.getSource() ) { updatePackages(); } else if ( packageComboBox == e.getSource() ) { } } // DocumentListener implementation ----------------------------------------- public void changedUpdate(DocumentEvent e) { fireChange(); } public void insertUpdate(DocumentEvent e) { fireChange(); } public void removeUpdate(DocumentEvent e) { fireChange(); } // Private methods --------------------------------------------------------- private void updatePackages() { SourceGroup g = (SourceGroup) rootComboBox.getSelectedItem(); packageComboBox.setModel(PackageView.createListView(g)); } void setCombosEnabled(boolean enabled) { packageComboBox.setEnabled(enabled); rootComboBox.setEnabled(enabled); projectsComboBox.setEnabled(enabled); } void setThisClassVisible(boolean visible) { newNameLabel.setVisible(visible); newNameTextField.setVisible(visible); } public String getNewName() { return newNameTextField.getText(); } private void updateRoots() { Sources sources = ProjectUtils.getSources(project); groups = sources.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA); if (groups.length == 0) { // XXX why?? This is probably wrong. If the project has no Java groups, // you cannot move anything into it. groups = sources.getSourceGroups( Sources.TYPE_GENERIC ); } int preselectedItem = 0; for( int i = 0; i < groups.length; i++ ) { if (fo!=null) { try { if (groups[i].contains(fo)) { preselectedItem = i; } } catch (IllegalArgumentException e) { // XXX this is a poor abuse of exception handling } } } // Setup comboboxes rootComboBox.setModel(new DefaultComboBoxModel(groups)); rootComboBox.setSelectedIndex(preselectedItem); } private static class GroupCellRenderer extends DefaultListCellRenderer/**/ { public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { DefaultListCellRenderer cbr = (DefaultListCellRenderer)super.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus ); SourceGroup g = (SourceGroup) value; cbr.setText(g.getDisplayName()); cbr.setIcon(g.getIcon(false)); return cbr; } } private static class ProjectCellRenderer extends DefaultListCellRenderer { public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { DefaultListCellRenderer cbr = (DefaultListCellRenderer)super.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus ); if ( value != null ) { ProjectInformation pi = ProjectUtils.getInformation((Project)value); cbr.setText(pi.getDisplayName()); cbr.setIcon(pi.getIcon()); } return cbr; } } }
IDE 使用 Ant 构建脚本来构建和安装您的模块。构建脚本是创建模块项目时为您创建的。
要在 Options 窗口中注册模块,您必须在 layer.xml 文件中执行以下操作:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.0//EN" "http://www.netbeans.org/dtds/filesystem-1_0.dtd"> <filesystem> <folder name="Menu"> <folder name="Refactoring"> <attr name="LastSeparator.instance/IntroduceVariableAction.instance" boolvalue="true"/> <attr name="copyclassSeparator.instance/UndoAction.instance" boolvalue="true"/> <attr name="MoveClassAction.instance/CopyClassAction.instance" boolvalue="true"/> <file name="CopyClassAction.instance"> <attr name="instanceClass" stringvalue="org.netbeans.modules.refactoring.copyclass.ui.CopyClassAction"/> </file> <attr name="CopyClassAction.instance/CleanUpAction.instance" boolvalue="true"/> <attr name="CopyClassAction.instance/InnerToOuterAction.instance" boolvalue="true"/> </folder> </folder> <folder name="Actions"> <folder name="Refactoring"> <file name="org-netbeans-modules-refactoring-copyclass-ui-CopyClassAction"/> </folder> </folder> <folder name="Services"> <folder name="org-netbeans-modules-refactoring"> <file name="options"> <attr name="previewAll.org.netbeans.modules.refactoring.copyclass.CopyClass" boolvalue="false"/> </file> </folder> </folder> </filesystem>
LBL_CopyClass_Action=Copy Class... LBL_CopyClass=Copy Class DSC_CopyClass=Copy Class {0} LBL_NewName=&New Name\: LBL_Project=P&roject LBL_Location=&Location LBL_ToPackage=&To Package
IDE 使用 Ant 构建脚本来构建和安装您的模块。构建脚本是创建模块项目时为您创建的。
模块即在目标 IDE 或平台中构建和安装。目标 IDE 或平台打开,您可以试用新的模块。默认目标 IDE 或平台是由开发 IDE 的当前实例使用的安装平台。
有关该模块的其他方面,请参阅介绍示例部分。
NBM 文件是一个 NetBeans 模块,该模块已被打包以便通过 Web 发送。NBM 文件和模块 JAR 文件之间的主要差别为:
NBM 文件只是具有特殊扩展名的 ZIP 文件。它们使用 JDK 机理给 JAR 文件签名。除非您正在执行一些不同寻常的操作,否则不需要担心 NBM 文件的内容,只需让 NBM 创建的标准 Ant 构建脚本为您完成所有工作。IDE 根据在 Project Properties 对话框的项目中输入的选项生成构建脚本。您可以在 Project Properties 对话框中设置模块的依存关系、版本控制和打包信息。通过为项目编辑 Ant 脚本和 Ant 属性,您可以进一步自定义程序执行。
将创建 NBM 文件并且可以在 Files 窗口中查看它 (Ctrl-2):
以下是当对 NetBeans 应用新的重构时需要采取的步骤。
有关创建和开发 NetBeans 模块的更多信息,请参见以下资源:
版本
|
日期
|
更改
|
1 | 2005 年 10 月 28 日 |
|