blob: 7deb97f5a4cc0fd444e8be31624ce465c257a7d8 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.refactoring.java.ui;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.Tree;
import org.netbeans.api.java.source.support.ErrorAwareTreePathScanner;
import java.awt.Component;
import java.awt.event.ItemEvent;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.util.ElementFilter;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.netbeans.api.java.source.CancellableTask;
import org.netbeans.api.java.source.CompilationController;
import org.netbeans.api.java.source.CompilationInfo;
import org.netbeans.api.java.source.JavaSource;
import org.netbeans.api.java.source.JavaSource.Phase;
import org.netbeans.api.java.source.Task;
import org.netbeans.api.java.source.TreePathHandle;
import org.netbeans.modules.refactoring.java.RefactoringModule;
import org.netbeans.modules.refactoring.java.RefactoringUtils;
import org.netbeans.modules.refactoring.spi.ui.CustomRefactoringPanel;
import org.netbeans.spi.gototest.TestLocator;
import org.netbeans.spi.gototest.TestLocator.LocationResult;
import org.openide.filesystems.FileObject;
import org.openide.util.Lookup;
/**
* Rename refactoring parameters panel
*
* @author Pavel Flaska
*/
public class RenamePanel extends JPanel implements CustomRefactoringPanel {
private static final Logger LOG = Logger.getLogger(RenamePanel.class.getName());
private final transient String oldName;
private final transient ChangeListener parent;
private final transient TreePathHandle handle;
/** Creates new form RenamePanelName */
public RenamePanel(TreePathHandle handle, String oldName, ChangeListener parent, String name, boolean editable, boolean showUpdateReferences) {
setName(name);
this.oldName = oldName;
this.parent = parent;
this.handle = handle;
initComponents();
updateReferencesCheckBox.setVisible(showUpdateReferences);
nameField.setEnabled(editable);
//parent.setPreviewEnabled(false);
nameField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void changedUpdate(DocumentEvent event) {
RenamePanel.this.parent.stateChanged(null);
}
@Override
public void insertUpdate(DocumentEvent event) {
RenamePanel.this.parent.stateChanged(null);
}
@Override
public void removeUpdate(DocumentEvent event) {
RenamePanel.this.parent.stateChanged(null);
}
});
renameGettersAndCheckersCheckBox.setVisible(false);
renameTestClassCheckBox.setVisible(false);
renameTestClassMethodCheckBox.setVisible(false);
}
private boolean initialized = false;
@Override
public void initialize() {
if (initialized) {
return;
}
if (handle!=null && handle.getKind() != Tree.Kind.LABELED_STATEMENT &&
handle.getElementHandle() != null
&& (handle.getElementHandle().getKind() == ElementKind.FIELD
|| handle.getElementHandle().getKind() == ElementKind.CLASS
|| handle.getElementHandle().getKind() == ElementKind.METHOD)) {
JavaSource source = JavaSource.forFileObject(handle.getFileObject());
CancellableTask<CompilationController> task = new CancellableTask<CompilationController>() {
@Override
public void cancel() {
throw new UnsupportedOperationException("Not supported yet."); // NOI18N
}
@Override
public void run(CompilationController info) throws Exception {
info.toPhase(Phase.RESOLVED);
if(handle.getElementHandle().getKind() == ElementKind.FIELD) {
VariableElement element = (VariableElement) handle.resolveElement(info);
if(element == null) {
LOG.log(Level.WARNING, "Cannot resolve ElementHandle {0} {1}", new Object[] {handle, info.getClasspathInfo()});
return;
}
TypeElement parent = (TypeElement) element.getEnclosingElement();
boolean hasGetters = false;
for (ExecutableElement method : ElementFilter.methodsIn(parent.getEnclosedElements())) {
if (RefactoringUtils.isGetter(info, method, element) || RefactoringUtils.isSetter(info, method, element)) {
hasGetters = true;
break;
}
}
if (hasGetters) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
renameGettersAndCheckersCheckBox.setVisible(true);
}
});
}
}
if(handle.getElementHandle().getKind() == ElementKind.CLASS || handle.getElementHandle().getKind() == ElementKind.METHOD) {
final Element methodElement = handle.resolveElement(info);
if(methodElement == null) {
LOG.log(Level.WARNING, "Cannot resolve ElementHandle {0} {1}", new Object[] {handle, info.getClasspathInfo()});
return;
}
final FileObject fileObject = handle.getFileObject();
Collection<? extends TestLocator> testLocators = Lookup.getDefault().lookupAll(TestLocator.class);
for (final TestLocator testLocator : testLocators) {
if(testLocator.appliesTo(fileObject)) {
if(testLocator.asynchronous()) {
testLocator.findOpposite(fileObject, -1, new TestLocator.LocationListener() {
@Override
public void foundLocation(FileObject fo, LocationResult location) {
if(handle.getElementHandle().getKind() == ElementKind.CLASS) {
addTestFile(location, testLocator);
} else if(handle.getElementHandle().getKind() == ElementKind.METHOD) {
addTestMethod(location, testLocator, methodElement);
}
}
});
} else {
if(handle.getElementHandle().getKind() == ElementKind.CLASS) {
addTestFile(testLocator.findOpposite(fileObject, -1), testLocator);
} else if (handle.getElementHandle().getKind() == ElementKind.METHOD) {
addTestMethod(testLocator.findOpposite(fileObject, -1), testLocator, methodElement);
}
}
}
}
}
}
};
try {
source.runUserActionTask(task, true);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
initialized = true;
}
private class TestClassMethodsVisitor extends ErrorAwareTreePathScanner<Void, Void> {
private CompilationInfo info;
private List<ExecutableElement> testClassMethods;
public TestClassMethodsVisitor(CompilationInfo info) {
this.info = info;
}
@Override
public Void visitClass(ClassTree t, Void v) {
Element el = info.getTrees().getElement(getCurrentPath());
if (el != null) {
testClassMethods = ElementFilter.methodsIn(((TypeElement) el).getEnclosedElements());
}
return null;
}
public boolean containsTestMethod(Element methodElement) {
if (testClassMethods != null) {
String methodName = RefactoringUtils.getTestMethodName(methodElement.getSimpleName().toString());
for (ExecutableElement testClassMethod : testClassMethods) {
if (testClassMethod.getSimpleName().contentEquals(methodName)
&& testClassMethod.getReturnType().getKind().equals(TypeKind.VOID)) { // test method should at least be void
return true;
}
}
}
return false;
}
}
private void addTestMethod(LocationResult location, TestLocator locator, final Element methodElement) {
if (!renameTestClassMethodCheckBox.isVisible()) {
if (location != null && location.getFileObject() != null) {
if(locator.getFileType(location.getFileObject()) == TestLocator.FileType.TEST) {
JavaSource js = JavaSource.forFileObject(location.getFileObject());
try {
js.runUserActionTask(new Task<CompilationController>() {
@Override
public void run(CompilationController parameter) throws IOException {
parameter.toPhase(Phase.ELEMENTS_RESOLVED);
TestClassMethodsVisitor testClassVisitor = new TestClassMethodsVisitor(parameter);
testClassVisitor.scan(parameter.getCompilationUnit(), null);
if (testClassVisitor.containsTestMethod(methodElement)) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
renameTestClassMethodCheckBox.setVisible(true);
}
});
}
}
}, true);
} catch (IOException e) {
Logger.getLogger(RenamePanel.class.getName()).log(Level.SEVERE, e.getMessage(), e);
}
}
}
}
}
private void addTestFile(LocationResult location, TestLocator locator) {
if (!renameTestClassCheckBox.isVisible()) {
if (location != null && location.getFileObject() != null) {
if(locator.getFileType(location.getFileObject()) == TestLocator.FileType.TEST) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
renameTestClassCheckBox.setVisible(true);
}
});
}
}
}
}
@Override
public boolean requestFocusInWindow() {
if(nameField.isEnabled()) {
nameField.requestFocusInWindow();
} else {
textCheckBox.requestFocusInWindow();
}
return true;
}
/** 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.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
label = new javax.swing.JLabel();
nameField = new javax.swing.JTextField();
jPanel1 = new javax.swing.JPanel();
textCheckBox = new javax.swing.JCheckBox();
updateReferencesCheckBox = new javax.swing.JCheckBox();
renameGettersAndCheckersCheckBox = new javax.swing.JCheckBox();
renameTestClassCheckBox = new javax.swing.JCheckBox();
renameTestClassMethodCheckBox = new javax.swing.JCheckBox();
setBorder(javax.swing.BorderFactory.createEmptyBorder(12, 12, 11, 11));
setLayout(new java.awt.GridBagLayout());
label.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
label.setLabelFor(nameField);
org.openide.awt.Mnemonics.setLocalizedText(label, org.openide.util.NbBundle.getMessage(RenamePanel.class, "LBL_NewName")); // NOI18N
add(label, new java.awt.GridBagConstraints());
nameField.setText(oldName);
nameField.selectAll();
nameField.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusLost(java.awt.event.FocusEvent evt) {
nameFieldFocusLost(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
add(nameField, gridBagConstraints);
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("org/netbeans/modules/refactoring/java/ui/Bundle"); // NOI18N
nameField.getAccessibleContext().setAccessibleDescription(bundle.getString("ACSD_nameField")); // NOI18N
jPanel1.setMinimumSize(new java.awt.Dimension(0, 0));
jPanel1.setPreferredSize(new java.awt.Dimension(0, 0));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.gridheight = 2;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
add(jPanel1, gridBagConstraints);
textCheckBox.setSelected(((Boolean) RefactoringModule.getOption("searchInComments.rename", Boolean.FALSE)).booleanValue());
org.openide.awt.Mnemonics.setLocalizedText(textCheckBox, org.openide.util.NbBundle.getBundle(RenamePanel.class).getString("LBL_RenameComments")); // NOI18N
textCheckBox.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
textCheckBoxItemStateChanged(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
add(textCheckBox, gridBagConstraints);
textCheckBox.getAccessibleContext().setAccessibleDescription(textCheckBox.getText());
org.openide.awt.Mnemonics.setLocalizedText(updateReferencesCheckBox, org.openide.util.NbBundle.getBundle(RenamePanel.class).getString("LBL_RenameWithoutRefactoring")); // NOI18N
updateReferencesCheckBox.setBorder(javax.swing.BorderFactory.createEmptyBorder(4, 4, 0, 4));
updateReferencesCheckBox.setMargin(new java.awt.Insets(2, 2, 0, 2));
updateReferencesCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
updateReferencesCheckBoxActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 5;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
add(updateReferencesCheckBox, gridBagConstraints);
renameGettersAndCheckersCheckBox.setSelected(((Boolean) RefactoringModule.getOption("gettersAndSetters.rename", Boolean.FALSE)).booleanValue());
org.openide.awt.Mnemonics.setLocalizedText(renameGettersAndCheckersCheckBox, org.openide.util.NbBundle.getMessage(RenamePanel.class, "RenamePanel.renameGettersAndCheckersCheckBox.text")); // NOI18N
renameGettersAndCheckersCheckBox.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
renameGettersAndCheckersCheckBoxItemStateChanged(evt);
}
});
renameGettersAndCheckersCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
renameGettersAndCheckersCheckBoxActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
add(renameGettersAndCheckersCheckBox, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(renameTestClassCheckBox, org.openide.util.NbBundle.getMessage(RenamePanel.class, "RenamePanel.renameTestClassCheckBox.text")); // NOI18N
renameTestClassCheckBox.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
renameTestClassCheckBoxStateChanged(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
add(renameTestClassCheckBox, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(renameTestClassMethodCheckBox, org.openide.util.NbBundle.getMessage(RenamePanel.class, "RenamePanel.renameTestClassMethodCheckBox.text")); // NOI18N
renameTestClassMethodCheckBox.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
renameTestClassMethodCheckBoxStateChanged(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 4;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
add(renameTestClassMethodCheckBox, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
private void updateReferencesCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_updateReferencesCheckBoxActionPerformed
textCheckBox.setEnabled(!updateReferencesCheckBox.isSelected());
parent.stateChanged(null);
}//GEN-LAST:event_updateReferencesCheckBoxActionPerformed
private void textCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_textCheckBoxItemStateChanged
// used for change default value for searchInComments check-box.
// The value is persisted and then used as default in next IDE run.
Boolean b = evt.getStateChange() == ItemEvent.SELECTED ? Boolean.TRUE : Boolean.FALSE;
RefactoringModule.setOption("searchInComments.rename", b); // NOI18N
}//GEN-LAST:event_textCheckBoxItemStateChanged
private void renameGettersAndCheckersCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_renameGettersAndCheckersCheckBoxActionPerformed
parent.stateChanged(null);
}//GEN-LAST:event_renameGettersAndCheckersCheckBoxActionPerformed
private void renameTestClassCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_renameTestClassCheckBoxStateChanged
parent.stateChanged(null);
}//GEN-LAST:event_renameTestClassCheckBoxStateChanged
private void renameTestClassMethodCheckBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_renameTestClassMethodCheckBoxStateChanged
parent.stateChanged(null);
}//GEN-LAST:event_renameTestClassMethodCheckBoxStateChanged
private void renameGettersAndCheckersCheckBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_renameGettersAndCheckersCheckBoxItemStateChanged
// used for change default value for gettersAndSetters check-box.
// The value is persisted and then used as default in next IDE run.
Boolean b = evt.getStateChange() == ItemEvent.SELECTED ? Boolean.TRUE : Boolean.FALSE;
RefactoringModule.setOption("gettersAndSetters.rename", b); // NOI18N
}//GEN-LAST:event_renameGettersAndCheckersCheckBoxItemStateChanged
private void nameFieldFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_nameFieldFocusLost
parent.stateChanged(null);
}//GEN-LAST:event_nameFieldFocusLost
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JPanel jPanel1;
private javax.swing.JLabel label;
private javax.swing.JTextField nameField;
private javax.swing.JCheckBox renameGettersAndCheckersCheckBox;
private javax.swing.JCheckBox renameTestClassCheckBox;
private javax.swing.JCheckBox renameTestClassMethodCheckBox;
private javax.swing.JCheckBox textCheckBox;
private javax.swing.JCheckBox updateReferencesCheckBox;
// End of variables declaration//GEN-END:variables
public String getNameValue() {
return nameField.getText();
}
public boolean searchJavadoc() {
return textCheckBox.isSelected();
}
public boolean isUpdateReferences() {
if (updateReferencesCheckBox.isVisible() && updateReferencesCheckBox.isSelected()) {
return false;
}
return true;
}
public boolean isRenameGettersSetters() {
return renameGettersAndCheckersCheckBox.isSelected();
}
@Override
public Component getComponent() {
return this;
}
boolean isRenameTestClass() {
return renameTestClassCheckBox.isSelected();
}
boolean isRenameTestClassMethod() {
return renameTestClassMethodCheckBox.isSelected();
}
}