blob: 5c77c57ea7a270d0f1a1ec276976e4ac376aca89 [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.doctree.DocCommentTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Scope;
import com.sun.source.tree.Tree;
import com.sun.source.util.TreePath;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ItemEvent;
import java.io.IOException;
import javax.lang.model.element.Element;
import javax.lang.model.type.TypeMirror;
import javax.swing.*;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Position;
import org.netbeans.api.editor.DialogBinding;
import org.netbeans.api.java.source.CancellableTask;
import org.netbeans.api.java.source.CodeStyle;
import org.netbeans.api.java.source.CompilationController;
import org.netbeans.api.java.source.JavaSource;
import org.netbeans.api.java.source.TreePathHandle;
import org.netbeans.editor.Utilities;
import org.netbeans.modules.refactoring.java.RefactoringModule;
import org.netbeans.modules.refactoring.java.plugins.JavaPluginUtils;
import org.netbeans.modules.refactoring.java.ui.ChangeParametersPanel.Javadoc;
import org.netbeans.modules.refactoring.spi.ui.CustomRefactoringPanel;
import org.openide.filesystems.FileObject;
import org.openide.loaders.DataObject;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
/**
* @author Jan Becicka
*/
public class IntroduceParameterPanel extends JPanel implements CustomRefactoringPanel {
private static final String OVERLOADMETHOD = "overloadmethod.introduceParameter"; // NOI18N
private static final String REPLACEALL = "replaceall.introduceParameter"; // NOI18N
private static final String DECLAREFINAL = "declarefinal.introduceParameter"; // NOI18N
private static final String UPDATEJAVADOC = "updateJavadoc.introduceParameters"; // NOI18N
private static final String GENJAVADOC = "generateJavadoc.introduceParameters"; // NOI18N
private static final String MIME_JAVA = "text/x-java"; // NOI18N
private static final String DEFAULT_NAME = "par"; // NOI18N
TreePathHandle refactoredObj;
private ChangeListener parent;
private final JComponent[] singleLineEditor;
private final DocumentListener nameChangedListener;
private int startOffset;
@Override
public Component getComponent() {
return this;
}
/** Creates new form ChangeMethodSignature */
public IntroduceParameterPanel(TreePathHandle refactoredObj, final ChangeListener parent) {
this.refactoredObj = refactoredObj;
this.parent = parent;
singleLineEditor = Utilities.createSingleLineEditor(MIME_JAVA);
initComponents();
nameChangedListener = new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent de) {
postUpdate();
}
@Override
public void removeUpdate(DocumentEvent de) {
postUpdate();
}
@Override
public void changedUpdate(DocumentEvent de) {
postUpdate();
}
};
((JEditorPane) singleLineEditor[1]).getDocument().addDocumentListener(nameChangedListener);
}
private void postUpdate() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
parent.stateChanged(null);
}
});
}
private boolean initialized = false;
@Override
public void initialize() {
try {
if (initialized) {
return;
}
JavaSource source = JavaSource.forFileObject(refactoredObj.getFileObject());
source.runUserActionTask(new CancellableTask<CompilationController>() {
@Override
public void run(org.netbeans.api.java.source.CompilationController info) {
try {
info.toPhase(org.netbeans.api.java.source.JavaSource.Phase.RESOLVED);
final FileObject fileObject = refactoredObj.getFileObject();
DataObject dob = DataObject.find(fileObject);
((JEditorPane)singleLineEditor[1]).getDocument().putProperty(
Document.StreamDescriptionProperty,
dob);
final TreePath path = refactoredObj.resolve(info);
final TreePath methodPath = JavaPluginUtils.findMethod(path);
MethodTree methodTree = (MethodTree) methodPath.getLeaf();
final int[] parameterSpan = info.getTreeUtilities().findMethodParameterSpan(methodTree);
TypeMirror typeMirror = info.getTrees().getTypeMirror(path);
final String tm = typeMirror == null ? "Object" : typeMirror.toString();
Element methodElement = info.getTrees().getElement(methodPath);
DocCommentTree javadocDoc = info.getDocTrees().getDocCommentTree(methodElement);
if(javadocDoc != null && !javadocDoc.getFullBody().isEmpty()) {
chkGenJavadoc.setEnabled(true);
chkGenJavadoc.setVisible(true);
chkUpdateJavadoc.setVisible(false);
} else {
chkUpdateJavadoc.setEnabled(true);
chkUpdateJavadoc.setVisible(true);
chkGenJavadoc.setVisible(false);
}
String name = JavaPluginUtils.getName(path.getLeaf());
if (name == null) {
name = DEFAULT_NAME;
}
Scope scope = null;
if(methodTree.getBody() != null) {
TreePath bodyPath = new TreePath(methodPath, methodTree.getBody());
scope = info.getTrees().getScope(bodyPath);
}
CodeStyle cs;
Document doc = info.getDocument();
if(doc != null) {
cs = CodeStyle.getDefault(doc);
} else {
cs = CodeStyle.getDefault(info.getFileObject());
}
final String parameterName = JavaPluginUtils.makeNameUnique(info, scope, name, cs.getParameterNamePrefix(), cs.getParameterNameSuffix());
final boolean variableRewrite = path.getLeaf().getKind() == Tree.Kind.VARIABLE;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
final JEditorPane editorPane = (JEditorPane)singleLineEditor[1];
DialogBinding.bindComponentToFile(fileObject, parameterSpan[0] + 1, parameterSpan[1] - parameterSpan[0], editorPane);
editorPane.setText(tm + " " + parameterName); //NOI18N
startOffset = tm.length() + 1;
int endOffset = parameterName.length() + startOffset;
editorPane.select(startOffset, endOffset);
try {
Position startPos = editorPane.getDocument().createPosition(startOffset);
Position endPos = editorPane.getDocument().createPosition(endOffset);
editorPane.putClientProperty("document-view-start-position", startPos); //NOI18N
editorPane.putClientProperty("document-view-end-position", endPos); //NOI18N
} catch (BadLocationException ex) {
Exceptions.printStackTrace(ex);
}
((JEditorPane)singleLineEditor[1]).getDocument().addDocumentListener(nameChangedListener);
if(variableRewrite) {
chkIsReplaceAll.setEnabled(false);
chkIsReplaceAll.setSelected(false);
}
initialized = true;
}});
}
catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
@Override
public void cancel() {
}
}, true);
initialized = true;
}
catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
/** 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() {
bgOverloadMethod = new javax.swing.ButtonGroup();
lblName = new javax.swing.JLabel();
chkIsDeclareFinal = new javax.swing.JCheckBox();
chkIsReplaceAll = new javax.swing.JCheckBox();
jScrollPane1 = (JScrollPane)singleLineEditor[0];
chkGenJavadoc = new javax.swing.JCheckBox();
chkUpdateJavadoc = new javax.swing.JCheckBox();
rbUpdateMethod = new javax.swing.JRadioButton();
rbOverloadMethod = new javax.swing.JRadioButton();
lblCodeGeneration = new javax.swing.JLabel();
setBorder(javax.swing.BorderFactory.createEmptyBorder(12, 12, 11, 11));
setAutoscrolls(true);
setName(getString("LBL_TitleIntroduceParameter"));
lblName.setLabelFor(jScrollPane1);
org.openide.awt.Mnemonics.setLocalizedText(lblName, org.openide.util.NbBundle.getMessage(IntroduceParameterPanel.class, "IntroduceParameterPanel.lblName.text")); // NOI18N
chkIsDeclareFinal.setSelected(((Boolean) RefactoringModule.getOption(DECLAREFINAL, Boolean.FALSE)).booleanValue());
org.openide.awt.Mnemonics.setLocalizedText(chkIsDeclareFinal, org.openide.util.NbBundle.getMessage(IntroduceParameterPanel.class, "IntroduceParameterPanel.chkIsDeclareFinal.text")); // NOI18N
chkIsDeclareFinal.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
chkIsDeclareFinalItemStateChanged(evt);
}
});
chkIsReplaceAll.setSelected(((Boolean) RefactoringModule.getOption(REPLACEALL, Boolean.FALSE)).booleanValue());
org.openide.awt.Mnemonics.setLocalizedText(chkIsReplaceAll, org.openide.util.NbBundle.getMessage(IntroduceParameterPanel.class, "IntroduceParameterPanel.chkIsReplaceAll.text")); // NOI18N
chkIsReplaceAll.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
chkIsReplaceAllItemStateChanged(evt);
}
});
chkGenJavadoc.setSelected(((Boolean) RefactoringModule.getOption(GENJAVADOC, Boolean.FALSE)).booleanValue());
org.openide.awt.Mnemonics.setLocalizedText(chkGenJavadoc, org.openide.util.NbBundle.getMessage(IntroduceParameterPanel.class, "IntroduceParameterPanel.chkGenJavadoc.text")); // NOI18N
chkGenJavadoc.setEnabled(false);
chkGenJavadoc.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
chkGenJavadocItemStateChanged(evt);
}
});
chkUpdateJavadoc.setSelected(((Boolean) RefactoringModule.getOption(UPDATEJAVADOC, Boolean.FALSE)).booleanValue());
org.openide.awt.Mnemonics.setLocalizedText(chkUpdateJavadoc, org.openide.util.NbBundle.getMessage(IntroduceParameterPanel.class, "IntroduceParameterPanel.chkUpdateJavadoc.text")); // NOI18N
chkUpdateJavadoc.setEnabled(false);
chkUpdateJavadoc.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
chkUpdateJavadocItemStateChanged(evt);
}
});
bgOverloadMethod.add(rbUpdateMethod);
rbUpdateMethod.setSelected(!((Boolean) RefactoringModule.getOption(OVERLOADMETHOD, Boolean.FALSE)).booleanValue());
org.openide.awt.Mnemonics.setLocalizedText(rbUpdateMethod, org.openide.util.NbBundle.getMessage(IntroduceParameterPanel.class, "IntroduceParameterPanel.rbUpdateMethod.text")); // NOI18N
bgOverloadMethod.add(rbOverloadMethod);
rbOverloadMethod.setSelected(((Boolean) RefactoringModule.getOption(OVERLOADMETHOD, Boolean.FALSE)).booleanValue());
org.openide.awt.Mnemonics.setLocalizedText(rbOverloadMethod, org.openide.util.NbBundle.getMessage(IntroduceParameterPanel.class, "IntroduceParameterPanel.rbOverloadMethod.text")); // NOI18N
rbOverloadMethod.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
rbOverloadMethodItemStateChanged(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(lblCodeGeneration, org.openide.util.NbBundle.getMessage(IntroduceParameterPanel.class, "IntroduceParameterPanel.lblCodeGeneration.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(lblName)
.addGap(2, 2, 2)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 428, Short.MAX_VALUE))
.addComponent(chkIsDeclareFinal)
.addComponent(chkIsReplaceAll)
.addComponent(chkUpdateJavadoc)
.addComponent(chkGenJavadoc)
.addComponent(lblCodeGeneration)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(rbUpdateMethod))
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(rbOverloadMethod))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(lblName, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jScrollPane1))
.addGap(18, 18, 18)
.addComponent(chkIsDeclareFinal)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(chkIsReplaceAll)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(chkUpdateJavadoc)
.addComponent(chkGenJavadoc))
.addGap(18, 18, 18)
.addComponent(lblCodeGeneration)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(rbUpdateMethod)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(rbOverloadMethod)
.addContainerGap(24, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
private void chkIsReplaceAllItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_chkIsReplaceAllItemStateChanged
Boolean b = evt.getStateChange() == ItemEvent.SELECTED ? Boolean.TRUE : Boolean.FALSE;
RefactoringModule.setOption(REPLACEALL, b);
parent.stateChanged(null);
}//GEN-LAST:event_chkIsReplaceAllItemStateChanged
private void chkIsDeclareFinalItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_chkIsDeclareFinalItemStateChanged
Boolean b = evt.getStateChange() == ItemEvent.SELECTED ? Boolean.TRUE : Boolean.FALSE;
RefactoringModule.setOption(DECLAREFINAL, b);
parent.stateChanged(null);
}//GEN-LAST:event_chkIsDeclareFinalItemStateChanged
private void chkGenJavadocItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_chkGenJavadocItemStateChanged
Boolean b = evt.getStateChange() == ItemEvent.SELECTED ? Boolean.TRUE : Boolean.FALSE;
RefactoringModule.setOption(GENJAVADOC, b); // NOI18N
parent.stateChanged(null);
}//GEN-LAST:event_chkGenJavadocItemStateChanged
private void chkUpdateJavadocItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_chkUpdateJavadocItemStateChanged
Boolean b = evt.getStateChange() == ItemEvent.SELECTED ? Boolean.TRUE : Boolean.FALSE;
RefactoringModule.setOption(UPDATEJAVADOC, b); // NOI18N
parent.stateChanged(null);
}//GEN-LAST:event_chkUpdateJavadocItemStateChanged
private void rbOverloadMethodItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbOverloadMethodItemStateChanged
Boolean b = evt.getStateChange() == ItemEvent.SELECTED ? Boolean.TRUE : Boolean.FALSE;
RefactoringModule.setOption(OVERLOADMETHOD, b);
parent.stateChanged(null);
}//GEN-LAST:event_rbOverloadMethodItemStateChanged
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.ButtonGroup bgOverloadMethod;
private javax.swing.JCheckBox chkGenJavadoc;
private javax.swing.JCheckBox chkIsDeclareFinal;
private javax.swing.JCheckBox chkIsReplaceAll;
private javax.swing.JCheckBox chkUpdateJavadoc;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JLabel lblCodeGeneration;
private javax.swing.JLabel lblName;
private javax.swing.JRadioButton rbOverloadMethod;
private javax.swing.JRadioButton rbUpdateMethod;
// End of variables declaration//GEN-END:variables
private static String getString(String key) {
return NbBundle.getMessage(ChangeParametersPanel.class, key);
}
public boolean isCompatible() {
return rbOverloadMethod.isSelected();
}
public boolean isDeclareFinal() {
return chkIsDeclareFinal.isSelected();
}
public boolean isReplaceAll() {
return chkIsReplaceAll.isSelected();
}
public String getParameterName() {
final String text = ((JEditorPane)singleLineEditor[1]).getText();
final String substring;
if(text.length() < startOffset) {
// try to recover from not fully implemented document-view-start-position #204788
substring = text;
} else {
substring = text.substring(startOffset);
}
return substring;
}
protected Javadoc getJavadoc() {
if(chkUpdateJavadoc.isVisible() && chkUpdateJavadoc.isSelected()) {
return Javadoc.UPDATE;
} else if(chkGenJavadoc.isVisible() && chkGenJavadoc.isSelected()) {
return Javadoc.GENERATE;
} else {
return Javadoc.NONE;
}
}
@Override
public boolean requestFocusInWindow() {
((JEditorPane)singleLineEditor[1]).requestFocusInWindow();
return true;
}
}