diff --git a/build/conf/mac/Contents/Info.plist b/build/conf/mac/Contents/Info.plist index aae772e03237..242d418c7b4c 100644 --- a/build/conf/mac/Contents/Info.plist +++ b/build/conf/mac/Contents/Info.plist @@ -58,7 +58,7 @@ Java ClassPath - $APP_PACKAGE/lib/bootstrap.jar:$APP_PACKAGE/lib/extensions.jar:$APP_PACKAGE/lib/util.jar:$APP_PACKAGE/lib/jdom.jar:$APP_PACKAGE/lib/log4j.jar:$APP_PACKAGE/lib/jna.jar + $APP_PACKAGE/lib/bootstrap.jar:$APP_PACKAGE/lib/extensions.jar:$APP_PACKAGE/lib/util.jar:$APP_PACKAGE/lib/jdom.jar:$APP_PACKAGE/lib/log4j.jar:$APP_PACKAGE/lib/jna.jar:$APP_PACKAGE/lib/trove4j.jar JVMVersion 1.6* diff --git a/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java b/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java index 844abfd2765b..9d4840cf53fd 100644 --- a/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java @@ -163,16 +163,18 @@ public class MagicConstantInspection extends LocalInspectionTool { if (module == null) { return; } - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - attachJdkAnnotations(module); - } - }); - } - }, ModalityState.NON_MODAL, module.getDisposed()); + if (!ApplicationManager.getApplication().isUnitTestMode()) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + attachJdkAnnotations(module); + } + }); + } + }, ModalityState.NON_MODAL, module.getDisposed()); + } } private static void attachJdkAnnotations(Module module) { diff --git a/platform/platform-api/src/com/intellij/ui/ColorPicker.java b/platform/platform-api/src/com/intellij/ui/ColorPicker.java index e19923d2ec3a..3d712f3b3819 100644 --- a/platform/platform-api/src/com/intellij/ui/ColorPicker.java +++ b/platform/platform-api/src/com/intellij/ui/ColorPicker.java @@ -20,6 +20,7 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.WindowManager; import com.intellij.util.Alarm; @@ -62,6 +63,7 @@ public class ColorPicker extends JPanel implements ColorListener, DocumentListen private final Alarm myUpdateQueue; private RecentColorsComponent myRecentColorsComponent; + private final ColorPipette myPicker; private ColorPicker(@NotNull Disposable parent, @Nullable Color color, boolean enableOpacity) { this(parent, color, true, enableOpacity); @@ -77,9 +79,15 @@ public class ColorPicker extends JPanel implements ColorListener, DocumentListen setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5)); myColorWheelPanel = new ColorWheelPanel(this, enableOpacity); - + myPicker = new ColorPipette(this, getColor()); + myPicker.setListener(new ColorListener() { + @Override + public void colorChanged(Color color, Object source) { + setColor(color, source); + } + }); try { - add(buildTopPanel(restoreColors), BorderLayout.NORTH); + add(buildTopPanel(true), BorderLayout.NORTH); add(myColorWheelPanel, BorderLayout.CENTER); myRecentColorsComponent = new RecentColorsComponent(new ColorListener() { @@ -166,7 +174,8 @@ public class ColorPicker extends JPanel implements ColorListener, DocumentListen private void validateAndUpdatePreview(JTextField src) { final Color color; if (myHex.hasFocus()) { - color = ColorUtil.fromHex(myHex.getText(), null); + Color c = ColorUtil.fromHex(myHex.getText(), null); + color = c != null ? new Color(c.getRed(), c.getGreen(), c.getBlue(), (int)(255 * myColorWheelPanel.myColorWheel.myOpacity)) : null; } else { color = gatherRGB(); } @@ -245,12 +254,12 @@ public class ColorPicker extends JPanel implements ColorListener, DocumentListen pipette.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - ColorPipette.pickColor(new ColorListener() { - @Override - public void colorChanged(Color color, Object source) { - setColor(color, source); - } - }, ColorPicker.this); + myPicker.myOldColor = getColor(); + myPicker.pick(); + //JBPopupFactory.getInstance().createBalloonBuilder(new JLabel("Press ESC button to close pipette")) + // .setAnimationCycle(2000) + // .setSmallVariant(true) + // .createBalloon().show(new RelativePoint(pipette, new Point(pipette.getWidth() / 2, 0)), Balloon.Position.above); } }); previewPanel.add(pipette, BorderLayout.WEST); @@ -939,6 +948,7 @@ public class ColorPicker extends JPanel implements ColorListener, DocumentListen private final Color myPreselectedColor; private ColorPicker myColorPicker; private final boolean myEnableOpacity; + private ColorPipette myPicker; public ColorPickerDialog(Component parent, String caption, Color preselectedColor, boolean enableOpacity) { super(parent, true); @@ -948,6 +958,18 @@ public class ColorPicker extends JPanel implements ColorListener, DocumentListen setResizable(false); setOKButtonText("Choose"); init(); + addMouseListener((MouseMotionListener)new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + myPicker.cancelPipette(); + } + + @Override + public void mouseExited(MouseEvent e) { + myPicker.pick(); + } + }); + } @Override @@ -1058,6 +1080,7 @@ public class ColorPicker extends JPanel implements ColorListener, DocumentListen private static class ColorPipette implements ImageObserver { private Dialog myPickerFrame; private final JComponent myParent; + private Color myOldColor; private Timer myTimer; private Point myPoint = new Point(); @@ -1074,11 +1097,13 @@ public class ColorPicker extends JPanel implements ColorListener, DocumentListen private Color myTransparentColor = new Color(0, true); private Rectangle myZoomRect; private Rectangle myGlassRect; - private ColorListener myDoWhenDone; + private ColorListener myColorListener; private BufferedImage myMaskImage; + private Alarm myColorListenersNotifier = new Alarm(Alarm.ThreadToUse.SWING_THREAD); - private ColorPipette(JComponent parent) { + private ColorPipette(JComponent parent, Color oldColor) { myParent = parent; + myOldColor = oldColor; try { myRobot = new Robot(); @@ -1088,14 +1113,16 @@ public class ColorPicker extends JPanel implements ColorListener, DocumentListen } } - public void pick(ColorListener doWhenDone) { - myDoWhenDone = doWhenDone; - getPicker(); - myTimer.start(); + public void setListener(ColorListener colorListener) { + myColorListener = colorListener; + } + + public void pick() { Dialog picker = getPicker(); picker.setVisible(true); + myTimer.start(); // it seems like it's the lowest value for opacity for mouse events to be processed correctly - WindowManager.getInstance().setAlphaModeRatio(picker, 0.99f); + WindowManager.getInstance().setAlphaModeRatio(picker, SystemInfo.isMac ? 0.95f : 0.99f); } @Override @@ -1148,18 +1175,18 @@ public class ColorPicker extends JPanel implements ColorListener, DocumentListen } }); - myPickerFrame.setSize(100, 100); + myPickerFrame.setSize(50, 50); myPickerFrame.setUndecorated(true); myPickerFrame.setAlwaysOnTop(true); JRootPane rootPane = ((JDialog)myPickerFrame).getRootPane(); rootPane.putClientProperty("Window.shadow", Boolean.FALSE); - myGlassRect = new Rectangle(2, 2, 28, 28); + myGlassRect = new Rectangle(0, 0, 32, 32); myPickOffset = new Point(0, 0); myCaptureRect = new Rectangle(-4, -4, 8, 8); myCaptureOffset = new Point(myCaptureRect.x, myCaptureRect.y); - myHotspot = new Point(16, 16); + myHotspot = new Point(14, 16); myZoomRect = new Rectangle(0, 0, 32, 32); @@ -1170,7 +1197,7 @@ public class ColorPicker extends JPanel implements ColorListener, DocumentListen maskG.setColor(Color.RED); maskG.setComposite(AlphaComposite.SrcOut); - maskG.fillOval(myGlassRect.x, myGlassRect.y, myGlassRect.width, myGlassRect.height); + maskG.fillRect(0, 0, 32, 32); maskG.dispose(); myMagnifierImage = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB); @@ -1181,14 +1208,15 @@ public class ColorPicker extends JPanel implements ColorListener, DocumentListen graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); graphics.setColor(Color.BLACK); - graphics.drawOval(1, 1, 30, 30); - graphics.drawOval(2, 2, 28, 28); - - graphics.drawLine(2, 16, 12, 16); - graphics.drawLine(20, 16, 30, 16); - - graphics.drawLine(16, 2, 16, 12); - graphics.drawLine(16, 20, 16, 30); + //graphics.drawOval(1, 1, 30, 30); + //graphics.drawOval(2, 2, 28, 28); + // + //graphics.drawLine(2, 16, 12, 16); + //graphics.drawLine(20, 16, 30, 16); + // + //graphics.drawLine(16, 2, 16, 12); + //graphics.drawLine(16, 20, 16, 30); + PICK.paintIcon(null, graphics, 14, 0); graphics.dispose(); @@ -1225,15 +1253,19 @@ public class ColorPicker extends JPanel implements ColorListener, DocumentListen private void cancelPipette() { myTimer.stop(); myPickerFrame.setVisible(false); + if (myColorListener != null && myOldColor != null) { + myColorListener.colorChanged(myOldColor, this); + } } - private void pickDone() { + public void pickDone() { cancelPipette(); PointerInfo pointerInfo = MouseInfo.getPointerInfo(); Point location = pointerInfo.getLocation(); Color pixelColor = myRobot.getPixelColor(location.x + myPickOffset.x, location.y + myPickOffset.y); - if (myDoWhenDone != null) { - myDoWhenDone.colorChanged(pixelColor, this); + if (myColorListener != null) { + myColorListener.colorChanged(pixelColor, this); + myOldColor = pixelColor; } } @@ -1246,11 +1278,12 @@ public class ColorPicker extends JPanel implements ColorListener, DocumentListen myPoint.x = mouseLoc.x + myPickOffset.x; myPoint.y = mouseLoc.y + myPickOffset.y; - Color c = myRobot.getPixelColor(myPoint.x, myPoint.y); + final Color c = myRobot.getPixelColor(myPoint.x, myPoint.y); if (!c.equals(myPreviousColor) || !mouseLoc.equals(myPreviousLocation)) { myPreviousColor = c; myPreviousLocation = mouseLoc; - myCaptureRect.setLocation(mouseLoc.x + myCaptureOffset.x, mouseLoc.y + myCaptureOffset.y); + myCaptureRect.setLocation(mouseLoc.x - 2/*+ myCaptureOffset.x*/, mouseLoc.y - 2/*+ myCaptureOffset.y*/); + myCaptureRect.setBounds(mouseLoc.x -2, mouseLoc.y -2, 5, 5); BufferedImage capture = myRobot.createScreenCapture(myCaptureRect); @@ -1273,13 +1306,27 @@ public class ColorPicker extends JPanel implements ColorListener, DocumentListen // the color picker uses the new imagery. //BufferedImage subImage = myImage.getSubimage(0, 0, myImage.getWidth(), myImage.getHeight()); myPickerFrame.setCursor(myParent.getToolkit().createCustomCursor(myImage, myHotspot, "ColorPicker")); + if (myColorListener != null) { + myColorListenersNotifier.cancelAllRequests(); + myColorListenersNotifier.addRequest(new Runnable() { + @Override + public void run() { + myColorListener.colorChanged(c, ColorPipette.this); + } + }, 300); + } } } } - public static void pickColor(ColorListener doWhenDone, JComponent c) { - new ColorPipette(c).pick(doWhenDone); - } + //public static void pickColor(ColorListener listener, JComponent c) { + // new ColorPipette(c, new ColorListener() { + // @Override + // public void colorChanged(Color color, Object source) { + // ColorPicker.this.setColor(color, my); + // } + // }).pick(listener); + //} public static boolean isAvailable() { try { @@ -1292,6 +1339,15 @@ public class ColorPicker extends JPanel implements ColorListener, DocumentListen } } } + + public static void main(String[] args) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + ColorPicker.showDialog(null, "", null, true); + } + }); + } } interface ColorListener { void colorChanged(Color color, Object source); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringBundle.properties index ca361727d6f6..eabb9abf1f80 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringBundle.properties @@ -165,3 +165,4 @@ change.usages.of.var=Change usages of variable ''{0}''? reference.to.accessor.0.is.used=Reference to accessor {0} cannot be inlined. variable.is.accessed.for.writing=Variable ''{0}'' is accessed for writing introduce.closure.parameter.elements.header=Adding parameter to a closure +extract.closure.title=Extract closure diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringSupportProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringSupportProvider.java index 49a320410131..bbf10fd7c6ca 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringSupportProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyRefactoringSupportProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; import org.jetbrains.plugins.groovy.refactoring.changeSignature.GrChangeSignatureHandler; -import org.jetbrains.plugins.groovy.refactoring.extractMethod.GroovyExtractMethodHandler; +import org.jetbrains.plugins.groovy.refactoring.extract.method.GroovyExtractMethodHandler; import org.jetbrains.plugins.groovy.refactoring.introduce.constant.GrIntroduceConstantHandler; import org.jetbrains.plugins.groovy.refactoring.introduce.field.GrIntroduceFieldHandler; import org.jetbrains.plugins.groovy.refactoring.introduce.parameter.GrIntroduceParameterHandler; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/HelpID.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/HelpID.java index 96e0c6238211..7910c41fad60 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/HelpID.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/HelpID.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,4 +20,5 @@ package org.jetbrains.plugins.groovy.refactoring; */ public interface HelpID { String GROOVY_INTRODUCE_PARAMETER = "refactoring.introduceParameter.groovy"; + String GROOVY_EXTRACT_CLOSURE = "refactoring.extractClosure.groovy"; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractException.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractException.java new file mode 100644 index 000000000000..06cd73ebd018 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractException.java @@ -0,0 +1,25 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed 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.jetbrains.plugins.groovy.refactoring.extract; + +/** + * @author Max Medvedev + */ +public class ExtractException extends RuntimeException { + public ExtractException(String message) { + super(message); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractHandlerBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractHandlerBase.java new file mode 100644 index 000000000000..3f6a56b4b6e6 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractHandlerBase.java @@ -0,0 +1,186 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed 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.jetbrains.plugins.groovy.refactoring.extract; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.SelectionModel; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiType; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.RefactoringActionHandler; +import com.intellij.refactoring.RefactoringBundle; +import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.HashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; +import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; +import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner; +import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.FragmentVariableInfos; +import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.ReachingDefinitionsCollector; +import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.VariableInfo; +import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle; +import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * @author Max Medvedev + */ +public abstract class ExtractHandlerBase implements RefactoringActionHandler { + private static final Logger LOG = Logger.getInstance(ExtractHandlerBase.class); + + public void invokeOnEditor(Project project, Editor editor, PsiFile file, int start, int end) throws ExtractException { + /*// trim it if it's necessary + GroovyRefactoringUtil.trimSpacesAndComments(editor, file, false);*/ + + if (!(file instanceof GroovyFileBase)) { + String message = RefactoringBundle.getCannotRefactorMessage(GroovyRefactoringBundle.message("only.in.groovy.files")); + throw new ExtractException(message); + } + + SelectionModel selectionModel = editor.getSelectionModel(); + PsiDocumentManager.getInstance(project).commitAllDocuments(); + + PsiElement[] elements = ExtractUtil.getElementsInOffset(file, start, end); + if (elements.length == 1 && elements[0] instanceof GrExpression) { + selectionModel.setSelection(start, elements[0].getTextRange().getEndOffset()); + } + + GrStatement[] statements = ExtractUtil.getStatementsByElements(elements); + + if (statements.length == 0) { + String message = + RefactoringBundle.getCannotRefactorMessage(GroovyRefactoringBundle.message("selected.block.should.represent.a.statement.set")); + throw new ExtractException(message); + } + + for (GrStatement statement : statements) { + if (GroovyRefactoringUtil.isSuperOrThisCall(statement, true, true)) { + String message = RefactoringBundle + .getCannotRefactorMessage(GroovyRefactoringBundle.message("selected.block.contains.invocation.of.another.class.constructor")); + throw new ExtractException(message); + } + } + + GrStatement statement0 = statements[0]; + GrMemberOwner owner = ExtractUtil.getMemberOwner(statement0); + GrStatementOwner declarationOwner = ExtractUtil.getDeclarationOwner(statement0); + if (owner == null || declarationOwner == null && !ExtractUtil.isSingleExpression(statements)) { + String message = + RefactoringBundle.getCannotRefactorMessage(GroovyRefactoringBundle.message("refactoring.is.not.supported.in.the.current.context")); + throw new ExtractException(message); + } + if (declarationOwner == null && + ExtractUtil.isSingleExpression(statements) && + statement0 instanceof GrExpression && + PsiType.VOID.equals(((GrExpression)statement0).getType())) { + String message = RefactoringBundle.getCannotRefactorMessage(GroovyRefactoringBundle.message("selected.expression.has.void.type")); + throw new ExtractException(message); + } + + + // collect information about return statements in selected statement set + + Set allReturnStatements = new HashSet(); + GrControlFlowOwner controlFlowOwner = ControlFlowUtils.findControlFlowOwner(statement0); + assert controlFlowOwner != null; + allReturnStatements.addAll(ControlFlowUtils.collectReturns(controlFlowOwner, true)); + + ArrayList returnStatements = new ArrayList(); + for (GrStatement returnStatement : allReturnStatements) { + for (GrStatement statement : statements) { + if (PsiTreeUtil.isAncestor(statement, returnStatement, false)) { + returnStatements.add(returnStatement); + break; + } + } + } + + // collect information about variables in selected block + FragmentVariableInfos + fragmentVariableInfos = ReachingDefinitionsCollector.obtainVariableFlowInformation(statement0, statements[statements.length - 1]); + VariableInfo[] inputInfos = fragmentVariableInfos.getInputVariableNames(); + VariableInfo[] outputInfos = fragmentVariableInfos.getOutputVariableNames(); + if (outputInfos.length == 1 && returnStatements.size() > 0) { + String message = GroovyRefactoringBundle.message("multiple.output.values"); + throw new ExtractException(message); + } + + boolean hasInterruptingStatements = false; + + for (GrStatement statement : statements) { + hasInterruptingStatements = + GroovyRefactoringUtil.hasWrongBreakStatements(statement) || GroovyRefactoringUtil.haswrongContinueStatements(statement); + if (hasInterruptingStatements) break; + } + + // must be replaced by return statement + boolean hasReturns = returnStatements.size() > 0; + List returnStatementsCopy = new ArrayList(returnStatements.size()); + returnStatementsCopy.addAll(returnStatements); + boolean isReturnStatement = ExtractUtil.isReturnStatement(statements[statements.length - 1], returnStatementsCopy); + boolean isLastStatementOfMethod = isLastStatementOfMethodOrClosure(statements); + if (hasReturns && !isLastStatementOfMethod && !isReturnStatement || hasInterruptingStatements) { + String message = GroovyRefactoringBundle.message("refactoring.is.not.supported.when.return.statement.interrupts.the.execution.flow"); + throw new ExtractException(message); + } + + InitialInfo info = new InitialInfo(inputInfos, outputInfos, elements, statements, owner, returnStatements); + + InfoHelper helper = getSettings(info); + if (helper == null) return; + + performRefactoring(helper, owner, declarationOwner, editor, statement0); + } + + private static boolean isLastStatementOfMethodOrClosure(GrStatement[] statements) { + final GrStatement statement0 = statements[0]; + + PsiElement returnFrom = PsiTreeUtil.getParentOfType(statement0, GrMethod.class, GrClosableBlock.class, GroovyFile.class); + if (returnFrom instanceof GrMethod) { + returnFrom = ((GrMethod)returnFrom).getBlock(); + } + LOG.assertTrue(returnFrom instanceof GrStatementOwner); + + final GrStatement[] blockStatements = ((GrStatementOwner)returnFrom).getStatements(); + final GrStatement lastFromBlock = ArrayUtil.getLastElement(blockStatements); + final GrStatement lastStatement = ArrayUtil.getLastElement(statements); + return statement0.getManager().areElementsEquivalent(lastFromBlock, lastStatement); + } + + @Nullable + public abstract InfoHelper getSettings(@NotNull final InitialInfo initialInfo); + + public abstract void performRefactoring(@NotNull final InfoHelper helper, + @NotNull final GrMemberOwner owner, + final GrStatementOwner declarationOwner, + final Editor editor, + final PsiElement startElement); +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractInfoHelper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractInfoHelper.java new file mode 100644 index 000000000000..2da2a3ddc24c --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractInfoHelper.java @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed 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.jetbrains.plugins.groovy.refactoring.extract; + +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner; +import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.VariableInfo; + +/** + * @author Max Medvedev + */ +public interface ExtractInfoHelper { + @NotNull + Project getProject(); + + @NotNull + ParameterInfo[] getParameterInfos(); + + @NotNull + VariableInfo[] getOutputNames(); + + @NotNull + String[] getArgumentNames(); + + @NotNull + PsiType getOutputType(); + + @NotNull + PsiElement[] getInnerElements(); + + @NotNull + GrStatement[] getStatements(); + + @NotNull + GrMemberOwner getOwner(); +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractInfoHelperBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractInfoHelperBase.java new file mode 100644 index 000000000000..c253ceb53596 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractInfoHelperBase.java @@ -0,0 +1,119 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed 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.jetbrains.plugins.groovy.refactoring.extract; + +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner; +import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.VariableInfo; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Max Medvedev + */ +public class ExtractInfoHelperBase implements ExtractInfoHelper { + protected final InitialInfo myInitialInfo; + protected final Map myInputNamesMap; + + public ExtractInfoHelperBase( + InitialInfo initialInfo) { + myInitialInfo = initialInfo; + + final ParameterInfo[] infos = initialInfo.getParameterInfos(); + myInputNamesMap = new HashMap(infos.length); + for (ParameterInfo info : infos) { + myInputNamesMap.put(info.getName(), info); + } + } + + @Override + @NotNull + public Project getProject() { + return myInitialInfo.getProject(); + } + + @NotNull + @Override + public ParameterInfo[] getParameterInfos() { + Collection collection = myInputNamesMap.values(); + ParameterInfo[] infos = new ParameterInfo[collection.size()]; + for (ParameterInfo info : collection) { + int position = info.getPosition(); + assert position < infos.length && infos[position] == null; + infos[position] = info; + } + return infos; + } + + @Override + @NotNull + public VariableInfo[] getOutputNames() { + return myInitialInfo.getOutputNames(); + } + + /** + * Get old names of parameters to be pasted as method call arguments + * + * @return array of argument names + */ + @NotNull + @Override + public String[] getArgumentNames() { + Collection infos = myInputNamesMap.values(); + String[] argNames = new String[infos.size()]; + for (ParameterInfo info : infos) { + int position = info.getPosition(); + assert position < argNames.length; + argNames[position] = info.passAsParameter() ? info.getOldName() : ""; + } + return argNames; + + } + + @Override + @NotNull + public PsiType getOutputType() { + return myInitialInfo.getOutputType(); + } + + @Override + @NotNull + public PsiElement[] getInnerElements() { + return myInitialInfo.getInnerElements(); + } + + @Override + @NotNull + public GrStatement[] getStatements() { + return myInitialInfo.getStatements(); + } + + @Override + @NotNull + public GrMemberOwner getOwner() { + return myInitialInfo.getOwner(); + } + + public boolean hasReturnValue() { + return myInitialInfo.hasReturnValue(); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractUtil.java similarity index 88% rename from plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodUtil.java rename to plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractUtil.java index aa0cf3eb81d2..26db5d4ee16e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jetbrains.plugins.groovy.refactoring.extractMethod; +package org.jetbrains.plugins.groovy.refactoring.extract; import com.intellij.openapi.project.Project; import com.intellij.psi.*; @@ -54,6 +54,7 @@ import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle; import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil; +import org.jetbrains.plugins.groovy.refactoring.extract.method.ExtractMethodInfoHelper; import org.jetbrains.plugins.groovy.refactoring.inline.GroovyInlineMethodUtil; import java.util.*; @@ -61,13 +62,13 @@ import java.util.*; /** * @author ilyas */ -public class ExtractMethodUtil { +public class ExtractUtil { - private ExtractMethodUtil() { + private ExtractUtil() { } @Nullable - static PsiElement calculateAnchorToInsertBefore(GrMemberOwner owner, PsiElement startElement) { + public static PsiElement calculateAnchorToInsertBefore(GrMemberOwner owner, PsiElement startElement) { while (startElement != null && !isEnclosingDefinition(owner, startElement)) { if (startElement.getParent() instanceof GroovyFile) { return startElement.getNextSibling(); @@ -94,16 +95,16 @@ public class ExtractMethodUtil { } @NotNull - static GrStatement[] createResultStatement(ExtractMethodInfoHelper helper, @NotNull String methodName) { + public static GrStatement[] createResultStatement(ExtractMethodInfoHelper helper, @NotNull String methodName) { VariableInfo[] outputVars = helper.getOutputNames(); PsiType type = helper.getOutputType(); GrStatement[] statements = helper.getStatements(); GrMethodCallExpression callExpression = createMethodCallByHelper(methodName, helper); - if ((outputVars.length == 0 || PsiType.VOID.equals(type)) && !helper.isReturnStatement()) return new GrStatement[]{callExpression}; + if ((outputVars.length == 0 || PsiType.VOID.equals(type)) && !helper.hasReturnValue()) return new GrStatement[]{callExpression}; GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(helper.getProject()); - if (helper.isReturnStatement()) { + if (helper.hasReturnValue()) { return new GrStatement[]{factory.createStatementFromText("return " + callExpression.getText())}; } @@ -114,8 +115,7 @@ public class ExtractMethodUtil { return new GrStatement[]{createAssignment(outputVars, callExpression, helper)}; } if (mustAdd.size() == outputVars.length && outputVars.length == 1) { - final GrVariableDeclaration decl = factory.createVariableDeclaration(ArrayUtil.EMPTY_STRING_ARRAY, callExpression, - outputVars[0].getType(), outputVars[0].getName()); + final GrVariableDeclaration decl = factory.createVariableDeclaration(ArrayUtil.EMPTY_STRING_ARRAY, callExpression, outputVars[0].getType(), outputVars[0].getName()); return new GrVariableDeclaration[]{decl}; } List result = generateVarDeclarations(mustAdd, helper.getProject(), null); @@ -174,7 +174,7 @@ public class ExtractMethodUtil { return GroovyPsiElementFactory.getInstance(helper.getProject()).createExpressionFromText(text.toString()); } - static boolean validateMethod(GrMethod method, ExtractMethodInfoHelper helper) { + public static boolean validateMethod(GrMethod method, ExtractMethodInfoHelper helper) { ArrayList conflicts = new ArrayList(); GrMemberOwner owner = helper.getOwner(); PsiMethod[] methods = ArrayUtil.mergeArrays(owner.getAllMethods(), new PsiMethod[]{method}, PsiMethod.ARRAY_FACTORY); @@ -213,7 +213,7 @@ public class ExtractMethodUtil { } - static void removeOldStatements(GrStatementOwner owner, ExtractMethodInfoHelper helper) throws IncorrectOperationException { + public static void removeOldStatements(GrStatementOwner owner, ExtractMethodInfoHelper helper) throws IncorrectOperationException { owner.removeElements(helper.getInnerElements()); } @@ -258,7 +258,7 @@ public class ExtractMethodUtil { return false; } - static void renameParameterOccurrences(GrMethod method, ExtractMethodInfoHelper helper) throws IncorrectOperationException { + public static void renameParameterOccurrences(GrMethod method, ExtractMethodInfoHelper helper) throws IncorrectOperationException { GrOpenBlock block = method.getBlock(); if (block == null) return; GrStatement[] statements = block.getStatements(); @@ -289,7 +289,7 @@ public class ExtractMethodUtil { } } - static GrMethod createMethodByHelper(@NotNull String name, ExtractMethodInfoHelper helper) { + public static GrMethod createMethodByHelper(@NotNull String name, ExtractMethodInfoHelper helper) { StringBuilder buffer = new StringBuilder(); //Add signature @@ -302,7 +302,7 @@ public class ExtractMethodUtil { buffer.append(typeText); buffer.append(name); buffer.append("("); - for (String param : getParameterString(helper)) { + for (String param : getParameterString(helper, true)) { buffer.append(param); } buffer.append(") { \n"); @@ -364,7 +364,7 @@ public class ExtractMethodUtil { return method; } - static String[] getParameterString(ExtractMethodInfoHelper helper) { + public static String[] getParameterString(ExtractInfoHelper helper, boolean useCanonicalText) { int i = 0; ParameterInfo[] infos = helper.getParameterInfos(); int number = 0; @@ -377,7 +377,14 @@ public class ExtractMethodUtil { PsiType paramType = info.getType(); final PsiPrimitiveType unboxed = PsiPrimitiveType.getUnboxedType(paramType); if (unboxed != null) paramType = unboxed; - String paramTypeText = paramType == null || paramType.equalsToText("java.lang.Object") ? "" : paramType.getCanonicalText() + " "; + String paramTypeText; + + if (paramType == null || paramType.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) { + paramTypeText = ""; + } + else { + paramTypeText = (useCanonicalText ? paramType.getCanonicalText() : paramType.getPresentableText()) + " "; + } params.add(paramTypeText + info.getName() + (i < number - 1 ? ", " : "")); i++; } @@ -385,12 +392,12 @@ public class ExtractMethodUtil { return ArrayUtil.toStringArray(params); } - static String getTypeString(ExtractMethodInfoHelper helper, boolean forPresentation, String modifier) { + public static String getTypeString(ExtractMethodInfoHelper helper, boolean forPresentation, String modifier) { PsiType type = helper.getOutputType(); final PsiPrimitiveType outUnboxed = PsiPrimitiveType.getUnboxedType(type); if (outUnboxed != null) type = outUnboxed; String typeText = forPresentation ? type.getPresentableText() : type.getCanonicalText(); - String returnType = typeText == null || typeText.equals("void") || typeText.equals("Object") || !helper.specifyType() ? "" : typeText; + String returnType = typeText == null || !helper.specifyType() ? "" : typeText; if (returnType.length() == 0) { if (modifier.length() == 0) { typeText = "def "; @@ -405,7 +412,7 @@ public class ExtractMethodUtil { return typeText; } - static GrStatement[] getStatementsByElements(PsiElement[] elements) { + public static GrStatement[] getStatementsByElements(PsiElement[] elements) { ArrayList statementList = new ArrayList(); for (PsiElement element : elements) { if (element instanceof GrStatement) { @@ -415,7 +422,7 @@ public class ExtractMethodUtil { return statementList.toArray(new GrStatement[statementList.size()]); } - static PsiElement[] getElementsInOffset(PsiFile file, int startOffset, int endOffset) { + public static PsiElement[] getElementsInOffset(PsiFile file, int startOffset, int endOffset) { PsiElement[] elements; GrExpression expr = GroovyRefactoringUtil.findElementInRange(file, startOffset, endOffset, GrExpression.class); @@ -432,7 +439,7 @@ public class ExtractMethodUtil { } @Nullable - static GrMemberOwner getMemberOwner(GrStatement statement) { + public static GrMemberOwner getMemberOwner(GrStatement statement) { PsiElement parent = statement.getParent(); while (parent != null && !(parent instanceof GrMemberOwner)) { if (parent instanceof GroovyFileBase) return (GrMemberOwner) ((GroovyFileBase) parent).getScriptClass(); @@ -442,17 +449,17 @@ public class ExtractMethodUtil { } @Nullable - static GrStatementOwner getDeclarationOwner(GrStatement statement) { + public static GrStatementOwner getDeclarationOwner(GrStatement statement) { PsiElement parent = statement.getParent(); return parent instanceof GrStatementOwner ? ((GrStatementOwner) parent) : null; } - static boolean isSingleExpression(GrStatement[] statements) { + public static boolean isSingleExpression(GrStatement[] statements) { return statements.length == 1 && statements[0] instanceof GrExpression && !(statements[0].getParent() instanceof GrVariableDeclarationOwner && statements[0] instanceof GrAssignmentExpression); } - static GrMethodCallExpression createMethodCallByHelper(@NotNull String name, ExtractMethodInfoHelper helper) { + public static GrMethodCallExpression createMethodCallByHelper(@NotNull String name, ExtractMethodInfoHelper helper) { StringBuilder buffer = new StringBuilder(); buffer.append(name).append("("); int number = 0; @@ -479,7 +486,7 @@ public class ExtractMethodUtil { return ((GrMethodCallExpression) expr); } - static int getCaretOffset(@NotNull GrStatement statement) { + public static int getCaretOffset(@NotNull GrStatement statement) { if (statement instanceof GrVariableDeclaration) { GrVariable[] variables = ((GrVariableDeclaration) statement).getVariables(); if (variables.length > 0) { @@ -498,7 +505,7 @@ public class ExtractMethodUtil { return statement.getTextOffset(); } - static boolean canBeStatic(GrStatement statement) { + public static boolean canBeStatic(GrStatement statement) { PsiElement parent = statement.getParent(); while (parent != null && !(parent instanceof PsiFile)) { if (parent instanceof GrMethod) { @@ -509,14 +516,14 @@ public class ExtractMethodUtil { return false; } - static String getModifierString(ExtractMethodInfoHelper helper) { + public static String getModifierString(ExtractMethodInfoHelper helper) { String visibility = helper.getVisibility(); assert visibility != null && visibility.length() > 0; visibility = visibility.equals(PsiModifier.PUBLIC) ? "" : visibility + " "; return visibility + (helper.isStatic() ? "static " : ""); } - static boolean isReturnStatement(GrStatement statement, Collection returnStatements) { + public static boolean isReturnStatement(GrStatement statement, Collection returnStatements) { if (statement instanceof GrReturnStatement) return true; if (statement instanceof GrIfStatement) { boolean checked = GroovyInlineMethodUtil.checkTailIfStatement(((GrIfStatement) statement), returnStatements); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/InitialInfo.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/InitialInfo.java new file mode 100644 index 000000000000..f25d36007bb9 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/InitialInfo.java @@ -0,0 +1,182 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed 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.jetbrains.plugins.groovy.refactoring.extract; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; +import com.intellij.psi.CommonClassNames; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiType; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner; +import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.VariableInfo; +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Max Medvedev + */ +public class InitialInfo implements ExtractInfoHelper { + private final ParameterInfo[] myParameterInfos; + private final VariableInfo[] myOutputNames; + private final PsiType myOutputType; + private final GrMemberOwner myTargetClass; + private final PsiElement[] myInnerElements; + private final Project myProject; + private final GrStatement[] myStatements; + private final boolean myHasReturnValue; + private String[] myArgumentNames; + + public InitialInfo(VariableInfo[] inputInfos, + VariableInfo[] outputInfos, + PsiElement[] innerElements, + GrStatement[] statements, + GrMemberOwner targetClass, + ArrayList returnStatements) { + myInnerElements = innerElements; + myStatements = statements; + myTargetClass = targetClass; + myOutputNames = outputInfos; + + myHasReturnValue = ContainerUtil.find(returnStatements, new Condition() { + @Override + public boolean value(GrStatement statement) { + return statement instanceof GrReturnStatement && ((GrReturnStatement)statement).getReturnValue() != null; + } + }) != null; + + assert myStatements.length > 0; + myProject = myStatements[0].getProject(); + + myParameterInfos = new ParameterInfo[inputInfos.length]; + myArgumentNames = new String[inputInfos.length]; + for (int i = 0; i < inputInfos.length; i++) { + VariableInfo info = inputInfos[i]; + PsiType type = info.getType(); + myParameterInfos[i] = new ParameterInfo(info.getName(), i, type); + myArgumentNames[i] = info.getName(); + } + + PsiType outputType = inferOutputType(outputInfos, statements, targetClass, returnStatements, myHasReturnValue); + myOutputType = outputType != null ? outputType : PsiType.VOID; + } + + @Nullable + private PsiType inferOutputType(VariableInfo[] outputInfos, + GrStatement[] statements, + GrMemberOwner targetClass, + ArrayList returnStatements, boolean hasReturnValue) { + PsiType outputType = PsiType.VOID; + if (outputInfos.length > 0) { + if (outputInfos.length == 1) { + outputType = outputInfos[0].getType(); + } + else { + outputType = JavaPsiFacade.getElementFactory(myProject).createTypeFromText(CommonClassNames.JAVA_UTIL_LIST, myTargetClass); + } + } + else if (ExtractUtil.isSingleExpression(statements)) { + final GrStatement single = statements[0]; + if (!(single.getParent() instanceof GrCodeBlock)) { + outputType = ((GrExpression)single).getType(); + } + } + else if (hasReturnValue) { + assert returnStatements.size() > 0; + List types = new ArrayList(returnStatements.size()); + for (GrStatement statement : returnStatements) { + if (statement instanceof GrReturnStatement) { + GrExpression returnValue = ((GrReturnStatement)statement).getReturnValue(); + if (returnValue != null) { + types.add(returnValue.getType()); + } + } + else if (statement instanceof GrExpression) { + types.add(((GrExpression)statement).getType()); + } + } + outputType = TypesUtil.getLeastUpperBoundNullable(types, targetClass.getManager()); + } + + return outputType; + } + + @Override + @NotNull + public Project getProject() { + return myProject; + } + + @NotNull + @Override + public ParameterInfo[] getParameterInfos() { + return myParameterInfos; + } + + @Override + @NotNull + public VariableInfo[] getOutputNames() { + return myOutputNames; + } + + /** + * Get old names of parameters to be pasted as method call arguments + * + * @return array of argument names + */ + @NotNull + @Override + public String[] getArgumentNames() { + return myArgumentNames; + } + + @Override + @NotNull + public PsiType getOutputType() { + return myOutputType; + } + + @Override + @NotNull + public PsiElement[] getInnerElements() { + return myInnerElements; + } + + @Override + @NotNull + public GrStatement[] getStatements() { + return myStatements; + } + + @Override + @NotNull + public GrMemberOwner getOwner() { + return myTargetClass; + } + + public boolean hasReturnValue() { + return myHasReturnValue; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/ParameterInfo.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ParameterInfo.java similarity index 94% rename from plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/ParameterInfo.java rename to plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ParameterInfo.java index 3674b192beba..0b05c58d0168 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/ParameterInfo.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ParameterInfo.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jetbrains.plugins.groovy.refactoring.extractMethod; +package org.jetbrains.plugins.groovy.refactoring.extract; import com.intellij.psi.PsiType; import org.jetbrains.annotations.NotNull; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/ParameterTablePanel.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ParameterTablePanel.java similarity index 62% rename from plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/ParameterTablePanel.java rename to plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ParameterTablePanel.java index 5ccf9ceb4a1f..4929f120083c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/ParameterTablePanel.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ParameterTablePanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,8 +14,9 @@ * limitations under the License. */ -package org.jetbrains.plugins.groovy.refactoring.extractMethod; +package org.jetbrains.plugins.groovy.refactoring.extract; +import com.intellij.ide.ui.ListCellRendererWrapper; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiManager; import com.intellij.psi.PsiPrimitiveType; @@ -24,56 +25,48 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.refactoring.ui.TypeSelector; import com.intellij.ui.BooleanTableCellRenderer; import com.intellij.ui.IdeBorderFactory; -import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.TableUtil; +import com.intellij.ui.ToolbarDecorator; +import com.intellij.ui.table.JBTable; import com.intellij.util.ui.AbstractTableCellEditor; -import com.intellij.util.ui.Table; +import com.intellij.util.ui.EditableModel; import org.jetbrains.annotations.NonNls; import org.jetbrains.plugins.groovy.refactoring.GroovyNamesUtil; import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle; import javax.swing.*; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellEditor; import java.awt.*; import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.KeyEvent; /** * @author ilyas */ -public class ParameterTablePanel extends JPanel { +public abstract class ParameterTablePanel extends JPanel { - private Project myProject; private ParameterInfo[] myParameterInfos; private TypeSelector[] myParameterTypeSelectors; - private GroovyExtractMethodDialog myDialog; - private Table myTable; + private JBTable myTable; private MyTableModel myTableModel; - private JButton myUpButton; - private JButton myDownButton; private JComboBox myTypeRendererCombo; public ParameterTablePanel() { super(new BorderLayout()); } - void init(GroovyExtractMethodDialog dialog, ExtractMethodInfoHelper helper) { + public void init(ExtractInfoHelper helper) { setBorder(IdeBorderFactory.createTitledBorder(GroovyRefactoringBundle.message("parameters.border.title"), false, false, true)); - myDialog = dialog; - myProject = helper.getProject(); myParameterInfos = helper.getParameterInfos(); myTableModel = new MyTableModel(); - myTable = new Table(myTableModel); - DefaultCellEditor defaultEditor = (DefaultCellEditor) myTable.getDefaultEditor(Object.class); + myTable = new JBTable(myTableModel); + DefaultCellEditor defaultEditor = (DefaultCellEditor)myTable.getDefaultEditor(Object.class); defaultEditor.setClickCountToStart(1); myTable.setTableHeader(null); @@ -89,14 +82,15 @@ public class ParameterTablePanel extends JPanel { } }); - PsiManager manager = PsiManager.getInstance(myProject); - GlobalSearchScope scope = GlobalSearchScope.allScope(myProject); + Project project = helper.getProject(); + PsiManager manager = PsiManager.getInstance(project); + GlobalSearchScope scope = GlobalSearchScope.allScope(project); myParameterTypeSelectors = new TypeSelector[myParameterInfos.length]; for (int i = 0; i < myParameterTypeSelectors.length; i++) { -// final GrExpression[] occurrences = ExtractMethodUtil.findVariableOccurrences(helper.getStatements(), myParameterInfos[i].getName()); +// final GrExpression[] occurrences = ExtractUtil.findVariableOccurrences(helper.getStatements(), myParameterInfos[i].getName()); // final TypeSelectorManager manager = new TypeSelectorManagerImpl(myProject, myParameterInfos[i].getType(), occurrences, areTypesDirected()); PsiType type = myParameterInfos[i].getType(); - myParameterTypeSelectors[i] = new TypeSelector(type != null ? type : PsiType.getJavaLangObject(manager, scope), myProject); + myParameterTypeSelectors[i] = new TypeSelector(type != null ? type : PsiType.getJavaLangObject(manager, scope), project); // myParameterInfos[i].setTypeName(myParameterTypeSelectors[i].getSelectedType()); } @@ -104,21 +98,19 @@ public class ParameterTablePanel extends JPanel { myTypeRendererCombo.setOpaque(true); myTypeRendererCombo.setBorder(null); - myTypeRendererCombo.setRenderer(new DefaultListCellRenderer() { - - public Component getListCellRendererComponent(final JList list, - final Object value, - final int index, final boolean isSelected, final boolean cellHasFocus) { - PsiType type = ((ParameterInfo) value).getType(); + myTypeRendererCombo.setRenderer(new ListCellRendererWrapper(myTypeRendererCombo.getRenderer()) { + @Override + public void customize(JList list, ParameterInfo info, int index, boolean selected, boolean hasFocus) { + PsiType type = info.getType(); PsiPrimitiveType unboxed = PsiPrimitiveType.getUnboxedType(type); type = unboxed != null ? unboxed : type; setText(type != null ? type.getPresentableText() : ""); - return this; } }); myTable.getColumnModel().getColumn(MyTableModel.PARAMETER_TYPE_COLUMN).setCellEditor(new AbstractTableCellEditor() { TypeSelector myCurrentSelector; + public Object getCellEditorValue() { return myCurrentSelector.getSelectedType(); } @@ -216,143 +208,47 @@ public class ParameterTablePanel extends JPanel { } }); - JPanel listPanel = new JPanel(new BorderLayout()); - JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myTable); - listPanel.add(scrollPane, BorderLayout.CENTER); - listPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); + JPanel listPanel = ToolbarDecorator.createDecorator(myTable).disableAddAction().disableRemoveAction().createPanel(); add(listPanel, BorderLayout.CENTER); - - JPanel buttonsPanel = new JPanel(); - buttonsPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); - add(buttonsPanel, BorderLayout.EAST); - - buttonsPanel.setLayout(new GridBagLayout()); - GridBagConstraints gbConstraints = new GridBagConstraints(); - gbConstraints.gridwidth = GridBagConstraints.REMAINDER; - gbConstraints.fill = GridBagConstraints.HORIZONTAL; - gbConstraints.insets = new Insets(2, 4, 2, 4); - - myUpButton = new JButton(); - myUpButton.setText(GroovyRefactoringBundle.message("row.move.up")); - myUpButton.setDefaultCapable(false); - myUpButton.setMnemonic(KeyEvent.VK_U); - buttonsPanel.add(myUpButton, gbConstraints); - - myDownButton = new JButton(); - myDownButton.setText(GroovyRefactoringBundle.message("row.move.down")); - myDownButton.setMnemonic(KeyEvent.VK_D); - myDownButton.setDefaultCapable(false); - buttonsPanel.add(myDownButton, gbConstraints); - - gbConstraints.weighty = 1; - buttonsPanel.add(new JPanel(), gbConstraints); - - myUpButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (myTable.isEditing()) { - final boolean isStopped = myTable.getCellEditor().stopCellEditing(); - if (!isStopped) return; - } - moveSelectedItem(-1); - updateSignature(); - myTable.requestFocus(); - } - }); - - myDownButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (myTable.isEditing()) { - final boolean isStopped = myTable.getCellEditor().stopCellEditing(); - if (!isStopped) return; - } - moveSelectedItem(+1); - updateSignature(); - myTable.requestFocus(); - } - }); - - myTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - public void valueChanged(ListSelectionEvent e) { - updateMoveButtons(); - } - }); - if (myParameterInfos.length <= 1) { - myUpButton.setEnabled(false); - myDownButton.setEnabled(false); - } - else { - myTable.getSelectionModel().setSelectionInterval(0, 0); - } - updateMoveButtons(); } - private void updateMoveButtons() { - int row = myTable.getSelectedRow(); - if (0 <= row && row < myParameterInfos.length) { - myUpButton.setEnabled(row > 0); - myDownButton.setEnabled(row < myParameterInfos.length - 1); - } - else { - myUpButton.setEnabled(false); - myDownButton.setEnabled(false); - } - } + protected abstract void updateSignature(); - public void setEnabled(boolean enabled) { - myTable.setEnabled(enabled); - if (!enabled) { - myUpButton.setEnabled(false); - myDownButton.setEnabled(false); - } - else { - updateMoveButtons(); - } - super.setEnabled(enabled); - } + protected abstract void doEnterAction(); + protected abstract void doCancelAction(); - private void moveSelectedItem(int moveIncrement) { - int row = myTable.getSelectedRow(); - if (row < 0 || row >= myParameterInfos.length) return; - int targetRow = row + moveIncrement; - if (targetRow < 0 || targetRow >= myParameterInfos.length) return; - - ParameterInfo currentItem = myParameterInfos[row]; - int currentPosition = currentItem.getPosition(); - ParameterInfo targetItem = myParameterInfos[targetRow]; - - // Change real parameter position - currentItem.setPosition(targetItem.getPosition()); - targetItem.setPosition(currentPosition); - - myParameterInfos[row] = targetItem; - myParameterInfos[targetRow] = currentItem; - - TypeSelector currentSelector = myParameterTypeSelectors[row]; - myParameterTypeSelectors[row] = myParameterTypeSelectors[targetRow]; - myParameterTypeSelectors[targetRow] = currentSelector; - myTypeRendererCombo.setModel(new DefaultComboBoxModel(myParameterInfos)); - myTableModel.fireTableRowsUpdated(Math.min(targetRow, row), Math.max(targetRow, row)); - myTable.getSelectionModel().setSelectionInterval(targetRow, targetRow); - } - - protected void updateSignature(){ - myDialog.updateSignature(); - } - - protected void doEnterAction(){ - myDialog.clickDefaultButton(); - } - - protected void doCancelAction(){ - myDialog.doCancelAction(); - } - - private class MyTableModel extends AbstractTableModel { + private class MyTableModel extends AbstractTableModel implements EditableModel { public static final int CHECKMARK_COLUMN = 0; public static final int PARAMETER_TYPE_COLUMN = 1; public static final int PARAMETER_NAME_COLUMN = 2; + @Override + public void addRow() { + throw new IllegalAccessError("Not implemented"); + } + + @Override + public void removeRow(int index) { + throw new IllegalAccessError("Not implemented"); + } + + @Override + public void exchangeRows(int oldIndex, int newIndex) { + if (oldIndex < 0 || newIndex < 0) return; + if (oldIndex >= myParameterInfos.length || newIndex >= myParameterInfos.length) return; + + final ParameterInfo old = myParameterInfos[oldIndex]; + myParameterInfos[oldIndex] = myParameterInfos[newIndex]; + myParameterInfos[newIndex] = old; + + myParameterInfos[oldIndex].setPosition(oldIndex); + myParameterInfos[newIndex].setPosition(newIndex); + + fireTableRowsUpdated(Math.min(oldIndex, newIndex), Math.max(oldIndex, newIndex)); + updateSignature(); + } + public int getRowCount() { return myParameterInfos.length; } @@ -381,7 +277,7 @@ public class ParameterTablePanel extends JPanel { public void setValueAt(Object aValue, int rowIndex, int columnIndex) { switch (columnIndex) { case CHECKMARK_COLUMN: { - myParameterInfos[rowIndex].setPassAsParameter((Boolean) aValue); + myParameterInfos[rowIndex].setPassAsParameter((Boolean)aValue); fireTableRowsUpdated(rowIndex, rowIndex); myTable.getSelectionModel().setSelectionInterval(rowIndex, rowIndex); updateSignature(); @@ -389,7 +285,7 @@ public class ParameterTablePanel extends JPanel { } case PARAMETER_NAME_COLUMN: { ParameterInfo info = myParameterInfos[rowIndex]; - String name = (String) aValue; + String name = (String)aValue; if (GroovyNamesUtil.isIdentifier(name)) { info.setNewName(name); } @@ -398,7 +294,7 @@ public class ParameterTablePanel extends JPanel { } case PARAMETER_TYPE_COLUMN: { ParameterInfo info = myParameterInfos[rowIndex]; - info.setType((PsiType) aValue); + info.setType((PsiType)aValue); updateSignature(); break; } @@ -412,7 +308,9 @@ public class ParameterTablePanel extends JPanel { case PARAMETER_NAME_COLUMN: return isEnabled() && myParameterInfos[rowIndex].passAsParameter(); case PARAMETER_TYPE_COLUMN: - return isEnabled() && myParameterInfos[rowIndex].passAsParameter() && !(myParameterTypeSelectors[rowIndex].getComponent() instanceof JLabel); + return isEnabled() && + myParameterInfos[rowIndex].passAsParameter() && + !(myParameterTypeSelectors[rowIndex].getComponent() instanceof JLabel); default: return false; } @@ -433,6 +331,4 @@ public class ParameterTablePanel extends JPanel { return rendererComponent; } } - - } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodInfoHelper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodInfoHelper.java new file mode 100644 index 000000000000..ed87a8dd84a5 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodInfoHelper.java @@ -0,0 +1,70 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed 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.jetbrains.plugins.groovy.refactoring.extract.method; + +import com.intellij.psi.PsiModifier; +import org.jetbrains.plugins.groovy.refactoring.extract.ExtractInfoHelperBase; +import org.jetbrains.plugins.groovy.refactoring.extract.ExtractUtil; +import org.jetbrains.plugins.groovy.refactoring.extract.InitialInfo; + +/** + * @author ilyas + */ +public class ExtractMethodInfoHelper extends ExtractInfoHelperBase { + + private final boolean myIsStatic; + private boolean mySpecifyType = true; + private String myVisibility; + private String myName; + + public ExtractMethodInfoHelper(InitialInfo initialInfo, String name) { + super(initialInfo); + + myVisibility = PsiModifier.PRIVATE; + myName = name; + + myIsStatic = ExtractUtil.canBeStatic(initialInfo.getStatements()[0]); + } + + public boolean isStatic() { + return myIsStatic; + } + + public String getVisibility() { + return myVisibility; + } + + public void setVisibility(String visibility) { + myVisibility = visibility; + } + + public boolean specifyType() { + return mySpecifyType; + } + + public void setSpecifyType(boolean specifyType) { + mySpecifyType = specifyType; + } + + public String getName() { + return myName; + } + + public void setName(String name) { + myName = name; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodSettings.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodSettings.java similarity index 87% rename from plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodSettings.java rename to plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodSettings.java index f5cdc4e88389..a5a381e2df07 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodSettings.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jetbrains.plugins.groovy.refactoring.extractMethod; +package org.jetbrains.plugins.groovy.refactoring.extract.method; import org.jetbrains.annotations.NotNull; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodDialog.form b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodDialog.form new file mode 100644 index 000000000000..dd89443258c5 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodDialog.form @@ -0,0 +1,105 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/GroovyExtractMethodDialog.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodDialog.java similarity index 70% rename from plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/GroovyExtractMethodDialog.java rename to plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodDialog.java index 2edec74bdd9d..60343f373f22 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/GroovyExtractMethodDialog.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jetbrains.plugins.groovy.refactoring.extractMethod; +package org.jetbrains.plugins.groovy.refactoring.extract.method; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.event.DocumentListener; @@ -23,6 +23,8 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.psi.PsiModifier; import com.intellij.refactoring.HelpID; +import com.intellij.refactoring.ui.ComboBoxVisibilityPanel; +import com.intellij.refactoring.ui.MethodSignatureComponent; import com.intellij.ui.EditorTextField; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -30,12 +32,18 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.refactoring.GroovyNamesUtil; +import org.jetbrains.plugins.groovy.refactoring.extract.ExtractUtil; +import org.jetbrains.plugins.groovy.refactoring.extract.InitialInfo; +import org.jetbrains.plugins.groovy.refactoring.extract.ParameterTablePanel; +import org.jetbrains.plugins.groovy.refactoring.ui.GrMethodSignatureComponent; +import org.jetbrains.plugins.groovy.refactoring.ui.GroovyComboboxVisibilityPanel; import org.jetbrains.plugins.groovy.settings.GroovyApplicationSettings; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.EventListenerList; +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; @@ -46,29 +54,28 @@ import java.util.EventListener; * @author ilyas */ public class GroovyExtractMethodDialog extends DialogWrapper { - private final ExtractMethodInfoHelper myHelper; - private final Project myProject; + private final EventListenerList myListenerList = new EventListenerList(); private JPanel contentPane; private EditorTextField myNameField; private JCheckBox myCbSpecifyType; private JLabel myNameLabel; - private JTextArea mySignatureArea; - private VisibilityPanel myVisibilityPanel; + private MethodSignatureComponent mySignature; + private ComboBoxVisibilityPanel myVisibilityPanel; private ParameterTablePanel myParameterTablePanel; -// private JButton buttonOK; + private final Project myProject; + + public GroovyExtractMethodDialog(InitialInfo info) { + super(info.getProject(), true); + myProject = info.getProject(); + myHelper = new ExtractMethodInfoHelper(info, ""); - public GroovyExtractMethodDialog(ExtractMethodInfoHelper helper, Project project) { - super(project, true); - myProject = project; - myHelper = helper; setUpNameField(); - myParameterTablePanel.init(this, myHelper); + myParameterTablePanel.init(myHelper); setModal(true); -// getRootPane().setDefaultButton(buttonOK); setTitle(GroovyExtractMethodHandler.REFACTORING_NAME); init(); setUpDialog(); @@ -78,8 +85,8 @@ public class GroovyExtractMethodDialog extends DialogWrapper { protected void doOKAction() { String name = getEnteredName(); if (name == null) return; - GrMethod method = ExtractMethodUtil.createMethodByHelper(name, myHelper); - if (method != null && !ExtractMethodUtil.validateMethod(method, myHelper)) { + GrMethod method = ExtractUtil.createMethodByHelper(name, myHelper); + if (method != null && !ExtractUtil.validateMethod(method, myHelper)) { return; } if (myCbSpecifyType.isEnabled()) { @@ -92,9 +99,8 @@ public class GroovyExtractMethodDialog extends DialogWrapper { private void setUpDialog() { myCbSpecifyType.setMnemonic(KeyEvent.VK_T); myCbSpecifyType.setFocusable(false); - myCbSpecifyType.setEnabled(myHelper.specifyType()); - myCbSpecifyType.setSelected(myHelper.specifyType()); - if (myCbSpecifyType.isEnabled() && GroovyApplicationSettings.getInstance().EXTRACT_METHOD_SPECIFY_TYPE != null) { + myCbSpecifyType.setSelected(true); + if (GroovyApplicationSettings.getInstance().EXTRACT_METHOD_SPECIFY_TYPE != null) { myCbSpecifyType.setSelected(GroovyApplicationSettings.getInstance().EXTRACT_METHOD_SPECIFY_TYPE); } @@ -146,6 +152,7 @@ public class GroovyExtractMethodDialog extends DialogWrapper { private void update() { String text = getEnteredName(); + myHelper.setName(text); updateSignature(); setOKActionEnabled(GroovyNamesUtil.isIdentifier(text)); } @@ -155,7 +162,8 @@ public class GroovyExtractMethodDialog extends DialogWrapper { String text = myNameField.getText(); if (text != null && text.trim().length() > 0) { return text.trim(); - } else { + } + else { return null; } } @@ -173,22 +181,39 @@ public class GroovyExtractMethodDialog extends DialogWrapper { } private void createUIComponents() { + mySignature = new GrMethodSignatureComponent("", myProject); + mySignature.setPreferredSize(new Dimension(500, 100)); + mySignature.setMinimumSize(new Dimension(500, 100)); + myNameField = new EditorTextField("", myProject, GroovyFileType.GROOVY_FILE_TYPE); - myVisibilityPanel = new VisibilityPanel(); + myVisibilityPanel = new GroovyComboboxVisibilityPanel(); String visibility = GroovyApplicationSettings.getInstance().EXTRACT_METHOD_VISIBILITY; if (visibility == null) { visibility = PsiModifier.PRIVATE; } myVisibilityPanel.setVisibility(visibility); - myVisibilityPanel.addStateChangedListener(new VisibilityPanel.VisibilityStateChanged() { - public void visibilityChanged(String newVisibility) { - myHelper.setVisibility(newVisibility); + myVisibilityPanel.addListener(new ChangeListener(){ + @Override + public void stateChanged(ChangeEvent e) { + myHelper.setVisibility(myVisibilityPanel.getVisibility()); updateSignature(); } }); - myParameterTablePanel = new ParameterTablePanel(); + myParameterTablePanel = new ParameterTablePanel() { + protected void updateSignature(){ + GroovyExtractMethodDialog.this.updateSignature(); + } + + protected void doEnterAction(){ + GroovyExtractMethodDialog.this.clickDefaultButton(); + } + + protected void doCancelAction(){ + GroovyExtractMethodDialog.this.doCancelAction(); + } + }; } class DataChangedListener implements EventListener { @@ -201,7 +226,7 @@ public class GroovyExtractMethodDialog extends DialogWrapper { Object[] list = myListenerList.getListenerList(); for (Object aList : list) { if (aList instanceof DataChangedListener) { - ((DataChangedListener) aList).dataChanged(); + ((DataChangedListener)aList).dataChanged(); } } } @@ -209,16 +234,16 @@ public class GroovyExtractMethodDialog extends DialogWrapper { /* Update signature text area */ - void updateSignature() { - if (mySignatureArea == null) return; + public void updateSignature() { + if (mySignature == null) return; @NonNls StringBuilder buffer = new StringBuilder(); - String modifier = ExtractMethodUtil.getModifierString(myHelper); + String modifier = ExtractUtil.getModifierString(myHelper); buffer.append(modifier); - buffer.append(ExtractMethodUtil.getTypeString(myHelper, true, modifier)); + buffer.append(ExtractUtil.getTypeString(myHelper, true, modifier)); String name = getEnteredName() == null ? "" : getEnteredName(); buffer.append(name); buffer.append("("); - String[] params = ExtractMethodUtil.getParameterString(myHelper); + String[] params = ExtractUtil.getParameterString(myHelper, false); if (params.length > 0) { String INDENT = " "; buffer.append("\n"); @@ -227,10 +252,10 @@ public class GroovyExtractMethodDialog extends DialogWrapper { } } buffer.append(")"); - mySignatureArea.setText(buffer.toString()); + mySignature.setSignature(buffer.toString()); } - ExtractMethodSettings getSettings() { + public ExtractMethodSettings getSettings() { return new MyExtractMethodSettings(this); } @@ -244,12 +269,12 @@ public class GroovyExtractMethodDialog extends DialogWrapper { } @NotNull - public ExtractMethodInfoHelper getHelper() { - return myHelper; - } + public ExtractMethodInfoHelper getHelper() { + return myHelper; + } public String getEnteredName() { - return myEnteredName; - } + return myEnteredName; + } } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodHandler.java new file mode 100644 index 000000000000..ec50b31297f3 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodHandler.java @@ -0,0 +1,169 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed 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.jetbrains.plugins.groovy.refactoring.extract.method; + +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.ScrollType; +import com.intellij.openapi.editor.SelectionModel; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.intellij.refactoring.RefactoringActionHandler; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.GrReferenceAdjuster; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; +import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; +import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner; +import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; +import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle; +import org.jetbrains.plugins.groovy.refactoring.extract.ExtractException; +import org.jetbrains.plugins.groovy.refactoring.extract.ExtractHandlerBase; +import org.jetbrains.plugins.groovy.refactoring.extract.ExtractUtil; +import org.jetbrains.plugins.groovy.refactoring.extract.InitialInfo; + +/** + * @author ilyas + */ +public class GroovyExtractMethodHandler extends ExtractHandlerBase implements RefactoringActionHandler { + + private static final Logger LOG = Logger.getInstance(GroovyExtractMethodHandler.class); + protected static String REFACTORING_NAME = GroovyRefactoringBundle.message("extract.method.title"); + private String myInvokeResult = "ok"; + + public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) { + invoke(project, editor, file); + } + + void invoke(Project project, Editor editor, PsiFile file) { + editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); + // select editor text fragment + final SelectionModel model = editor.getSelectionModel(); + if (!model.hasSelection()) { + model.selectLineAtCaret(); + } + + try { + invokeOnEditor(project, editor, file, model.getSelectionStart(), model.getSelectionEnd()); + } + catch (ExtractException e) { + myInvokeResult = e.getMessage(); + } + } + + public void performRefactoring(@NotNull final ExtractMethodInfoHelper helper, + @NotNull final GrMemberOwner owner, + final GrStatementOwner declarationOwner, + final Editor editor, + final PsiElement startElement) { + + final String methodName = helper.getName(); + final GrMethod method = ExtractUtil.createMethodByHelper(methodName, helper); + final Runnable runnable = new Runnable() { + public void run() { + try { + PsiElement anchor = ExtractUtil.calculateAnchorToInsertBefore(owner, startElement); + GrMethod newMethod = owner.addMemberDeclaration(method, anchor); + ExtractUtil.renameParameterOccurrences(newMethod, helper); + GrReferenceAdjuster.shortenReferences(newMethod); + GrStatement realStatement; + + if (declarationOwner != null && !ExtractUtil.isSingleExpression(helper.getStatements())) { + // Replace set of statements + final GrStatement[] newStatement = ExtractUtil.createResultStatement(helper, methodName); + // add call statement + final GrStatement[] statements = helper.getStatements(); + assert statements.length > 0; + realStatement = null; + for (GrStatement statement : newStatement) { + realStatement = declarationOwner.addStatementBefore(statement, statements[0]); + } + assert realStatement != null; + // remove old statements + ExtractUtil.removeOldStatements(declarationOwner, helper); + PsiImplUtil.removeNewLineAfter(realStatement); + } + else { + // Expression call replace + GrExpression methodCall = ExtractUtil.createMethodCallByHelper(methodName, helper); + GrExpression oldExpr = (GrExpression)helper.getStatements()[0]; + realStatement = oldExpr.replaceWithExpression(methodCall, true); + } + GrReferenceAdjuster.shortenReferences(realStatement); + + PsiElement prev = newMethod.getPrevSibling(); + IElementType elementType = prev.getNode().getElementType(); + if (!TokenSets.WHITE_SPACES_SET.contains(elementType) || !prev.getText().contains("\n")) { + newMethod.getParent().getNode().addLeaf(GroovyTokenTypes.mNLS, "\n", newMethod.getNode()); + } + + // move to offset + if (editor != null) { + PsiDocumentManager.getInstance(helper.getProject()).commitDocument(editor.getDocument()); + editor.getCaretModel().moveToOffset(ExtractUtil.getCaretOffset(realStatement)); + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + }; + + Project project = helper.getProject(); + CommandProcessor.getInstance().executeCommand(project, new Runnable() { + public void run() { + ApplicationManager.getApplication().runWriteAction(runnable); + editor.getSelectionModel().removeSelection(); + } + }, REFACTORING_NAME, null); + } + + @Override + public ExtractMethodInfoHelper getSettings(@NotNull InitialInfo initialInfo) { + if (ApplicationManager.getApplication().isUnitTestMode()) { + final ExtractMethodInfoHelper helper = new ExtractMethodInfoHelper(initialInfo, "testMethod"); + final PsiType type = helper.getOutputType(); + if (type.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) || type.equalsToText("void")) { + helper.setSpecifyType(false); + } + return helper; + } + + GroovyExtractMethodDialog dialog = new GroovyExtractMethodDialog(initialInfo); + dialog.show(); + if (!dialog.isOK()) return null; + + return dialog.getHelper(); + } + + + public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) { + // does nothing + } + + public String getInvokeResult() { + return myInvokeResult; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodInfoHelper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodInfoHelper.java deleted file mode 100644 index 827f4b35a2cc..000000000000 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodInfoHelper.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed 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.jetbrains.plugins.groovy.refactoring.extractMethod; - -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; -import com.intellij.psi.*; -import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner; -import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.VariableInfo; -import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; - -import java.util.*; - -/** - * @author ilyas - */ -public class ExtractMethodInfoHelper { - - private final Map myInputNamesMap = new HashMap(); - private final VariableInfo[] myOutputNames; - private final PsiType myOutputType; - private final GrMemberOwner myTargetClass; - private final boolean myIsStatic; - private final boolean myIsReturnStatement; - private boolean mySpecifyType; - private final PsiElement[] myInnerElements; - private String myVisibility; - private final Project myProject; - private final GrStatement[] myStatements; - - public ExtractMethodInfoHelper(VariableInfo[] inputInfos, - VariableInfo[] outputInfos, - PsiElement[] innerElements, - GrStatement[] statements, - GrMemberOwner targetClass, - boolean isStatic, - ArrayList returnStatements) { - myInnerElements = innerElements; - myStatements = statements; - myTargetClass = targetClass; - myIsStatic = isStatic; - myIsReturnStatement = ContainerUtil.find(returnStatements, new Condition() { - @Override - public boolean value(GrStatement statement) { - return statement instanceof GrReturnStatement && ((GrReturnStatement)statement).getReturnValue() != null; - } - }) != null; - myVisibility = PsiModifier.PRIVATE; - assert myStatements.length > 0; - myProject = myStatements[0].getProject(); - int i = 0; - for (VariableInfo info : inputInfos) { - PsiType type = info.getType(); - ParameterInfo pInfo = new ParameterInfo(info.getName(), i, type); - myInputNamesMap.put(info.getName(), pInfo); - i++; - } - - PsiType outputType = PsiType.VOID; - myOutputNames = outputInfos; - if (outputInfos.length > 0) { - if (outputInfos.length == 1) { - outputType = outputInfos[0].getType(); - } - else { - outputType = JavaPsiFacade.getElementFactory(myProject).createTypeFromText(CommonClassNames.JAVA_UTIL_LIST, myTargetClass); - } - } - else if (ExtractMethodUtil.isSingleExpression(statements)) { - final GrStatement lastExpr = statements[statements.length - 1]; - if (!(lastExpr.getParent() instanceof GrCodeBlock)) { - outputType = ((GrExpression)lastExpr).getType(); - } - } - else { - if (myIsReturnStatement) { - assert returnStatements.size() > 0; - List types = new ArrayList(returnStatements.size()); - for (GrStatement statement : returnStatements) { - if (statement instanceof GrReturnStatement) { - GrExpression returnValue = ((GrReturnStatement)statement).getReturnValue(); - if (returnValue != null) { - types.add(returnValue.getType()); - } - } - else if (statement instanceof GrExpression) { - types.add(((GrExpression)statement).getType()); - } - } - outputType = TypesUtil.getLeastUpperBoundNullable(types, targetClass.getManager()); - } - } - myOutputType = outputType != null ? outputType : PsiType.VOID; - mySpecifyType = !(PsiType.VOID.equals(outputType) || myOutputType.equalsToText("java.lang.Object")); - } - - @NotNull - public Project getProject() { - return myProject; - } - - public ParameterInfo[] getParameterInfos() { - Collection collection = myInputNamesMap.values(); - ParameterInfo[] infos = new ParameterInfo[collection.size()]; - for (ParameterInfo info : collection) { - int position = info.getPosition(); - assert position < infos.length && infos[position] == null; - infos[position] = info; - } - return infos; - } - - @NotNull - public VariableInfo[] getOutputNames() { - return myOutputNames; - } - - /** - * Get old names of parameters to be pasted as method call arguments - * - * @return array of argument names - */ - public String[] getArgumentNames() { - Collection infos = myInputNamesMap.values(); - String[] argNames = new String[infos.size()]; - for (ParameterInfo info : infos) { - int position = info.getPosition(); - assert position < argNames.length; - argNames[position] = info.passAsParameter() ? info.getOldName() : ""; - } - return argNames; - } - - @NotNull - public PsiType getOutputType() { - return myOutputType; - } - - @NotNull - public PsiElement[] getInnerElements() { - return myInnerElements; - } - - @NotNull - public GrStatement[] getStatements() { - return myStatements; - } - - public boolean isStatic() { - return myIsStatic; - } - - public String getVisibility() { - return myVisibility; - } - - public void setVisibility(String visibility) { - myVisibility = visibility; - } - - public boolean specifyType() { - return mySpecifyType; - } - - public void setSpecifyType(boolean specifyType) { - mySpecifyType = specifyType; - } - - @NotNull - public GrMemberOwner getOwner() { - return myTargetClass; - } - - public boolean isReturnStatement() { - return myIsReturnStatement; - } -} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/GroovyExtractMethodDialog.form b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/GroovyExtractMethodDialog.form deleted file mode 100644 index 11ea95b9d2ca..000000000000 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/GroovyExtractMethodDialog.form +++ /dev/null @@ -1,99 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/GroovyExtractMethodHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/GroovyExtractMethodHandler.java deleted file mode 100644 index d66220101e80..000000000000 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/GroovyExtractMethodHandler.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed 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.jetbrains.plugins.groovy.refactoring.extractMethod; - -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.application.Application; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.command.CommandProcessor; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.ScrollType; -import com.intellij.openapi.editor.SelectionModel; -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiType; -import com.intellij.psi.tree.IElementType; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.refactoring.HelpID; -import com.intellij.refactoring.RefactoringActionHandler; -import com.intellij.refactoring.RefactoringBundle; -import com.intellij.refactoring.util.CommonRefactoringUtil; -import com.intellij.util.ArrayUtil; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.containers.HashSet; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; -import org.jetbrains.plugins.groovy.lang.GrReferenceAdjuster; -import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; -import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; -import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner; -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; -import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; -import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner; -import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.FragmentVariableInfos; -import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.ReachingDefinitionsCollector; -import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.VariableInfo; -import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; -import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle; -import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/** - * @author ilyas - */ -public class GroovyExtractMethodHandler implements RefactoringActionHandler { - - private static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.groovy.refactoring.extractMethod.GroovyExtractMethodHandler"); - protected static String REFACTORING_NAME = GroovyRefactoringBundle.message("extract.method.title"); - private String myInvokeResult = "ok"; - - protected void showErrorMessage(String message, final Project project, Editor editor) { - Application application = ApplicationManager.getApplication(); - myInvokeResult = message; - if (!application.isUnitTestMode()) { - CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.EXTRACT_METHOD); - } - } - - public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) { - editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); - // select editor text fragment - if (!editor.getSelectionModel().hasSelection()) { - editor.getSelectionModel().selectLineAtCaret(); - } - invokeOnEditor(project, editor, file); - } - - boolean invokeOnEditor(Project project, Editor editor, PsiFile file) { - // trim it if it's necessary - GroovyRefactoringUtil.trimSpacesAndComments(editor, file, false); - - //todo implement in GSP files - if (!(file instanceof GroovyFileBase /* || file instanceof GspFile*/)) { - String message = RefactoringBundle.getCannotRefactorMessage(GroovyRefactoringBundle.message("only.in.groovy.files")); - showErrorMessage(message, project, editor); - return false; - } - - SelectionModel selectionModel = editor.getSelectionModel(); - int startOffset = selectionModel.getSelectionStart(); - int endOffset = selectionModel.getSelectionEnd(); - PsiDocumentManager.getInstance(project).commitAllDocuments(); - - PsiElement[] elements = ExtractMethodUtil.getElementsInOffset(file, startOffset, endOffset); - if (elements.length == 1 && elements[0] instanceof GrExpression) { - selectionModel.setSelection(startOffset, elements[0].getTextRange().getEndOffset()); - } - - GrStatement[] statements = ExtractMethodUtil.getStatementsByElements(elements); - - if (statements.length == 0) { - String message = RefactoringBundle.getCannotRefactorMessage(GroovyRefactoringBundle.message("selected.block.should.represent.a.statement.set")); - showErrorMessage(message, project, editor); - return false; - } - - // test for this or super constructor calls - for (GrStatement statement : statements) { - if (GroovyRefactoringUtil.isSuperOrThisCall(statement, true, true)) { - String message = RefactoringBundle.getCannotRefactorMessage(GroovyRefactoringBundle.message("selected.block.contains.invocation.of.another.class.constructor")); - showErrorMessage(message, project, editor); - return false; - } - } - - GrStatement statement0 = statements[0]; - GrMemberOwner owner = ExtractMethodUtil.getMemberOwner(statement0); - GrStatementOwner declarationOwner = ExtractMethodUtil.getDeclarationOwner(statement0); - if (owner == null || - (declarationOwner == null && !ExtractMethodUtil.isSingleExpression(statements))) { - String message = RefactoringBundle.getCannotRefactorMessage(GroovyRefactoringBundle.message("refactoring.is.not.supported.in.the.current.context")); - showErrorMessage(message, project, editor); - return false; - } - if (declarationOwner == null && - ExtractMethodUtil.isSingleExpression(statements) && - statement0 instanceof GrExpression && PsiType.VOID.equals(((GrExpression)statement0).getType())) { - String message = RefactoringBundle.getCannotRefactorMessage(GroovyRefactoringBundle.message("selected.expression.has.void.type")); - showErrorMessage(message, project, editor); - return false; - } - - - // collect information about return statements in selected statement set - - Set allReturnStatements = new HashSet(); - GrControlFlowOwner controlFlowOwner = ControlFlowUtils.findControlFlowOwner(statement0); - assert controlFlowOwner != null; - allReturnStatements.addAll(ControlFlowUtils.collectReturns(controlFlowOwner, true)); - - ArrayList returnStatements = new ArrayList(); - for (GrStatement returnStatement : allReturnStatements) { - for (GrStatement statement : statements) { - if (PsiTreeUtil.isAncestor(statement, returnStatement, false)) { - returnStatements.add(returnStatement); - break; - } - } - } - - // collect information about variables in selected block - FragmentVariableInfos fragmentVariableInfos = ReachingDefinitionsCollector.obtainVariableFlowInformation(statement0, statements[statements.length - 1]); - VariableInfo[] inputInfos = fragmentVariableInfos.getInputVariableNames(); - VariableInfo[] outputInfos = fragmentVariableInfos.getOutputVariableNames(); - if (/*outputInfos.length > 1 ||*/ - outputInfos.length == 1 && returnStatements.size() > 0) { - String message = GroovyRefactoringBundle.message("multiple.output.values"); - showErrorMessage(message, project, editor); - return false; - } - - boolean hasInterruptingStatements = false; - - for (GrStatement statement : statements) { - if (hasInterruptingStatements = - GroovyRefactoringUtil.hasWrongBreakStatements(statement) || - GroovyRefactoringUtil.haswrongContinueStatements(statement)) { - break; - } - } - // must be replaced by return statement - boolean hasReturns = returnStatements.size() > 0; - List returnStatementsCopy = new ArrayList(returnStatements.size()); - returnStatementsCopy.addAll(returnStatements); - boolean isReturnStatement = ExtractMethodUtil.isReturnStatement(statements[statements.length - 1], returnStatementsCopy); - boolean isLastStatementOfMethod = isLastStatementOfMethodOrClosure(statements); - if (hasReturns && !isLastStatementOfMethod && !isReturnStatement || hasInterruptingStatements) { - String message = GroovyRefactoringBundle.message("refactoring.is.not.supported.when.return.statement.interrupts.the.execution.flow"); - showErrorMessage(message, project, editor); - return false; - } - - boolean canBeStatic = ExtractMethodUtil.canBeStatic(statement0); - - ExtractMethodInfoHelper helper = new ExtractMethodInfoHelper(inputInfos, outputInfos, elements, statements, owner, canBeStatic, returnStatements); - - final String methodName; - if (!ApplicationManager.getApplication().isUnitTestMode()) { - GroovyExtractMethodDialog dialog = getDialog(helper); - if (!dialog.isOK()) { - return false; - } - ExtractMethodSettings settings = dialog.getSettings(); - methodName = settings.getEnteredName(); - helper = settings.getHelper(); - } else { - methodName = "testMethod"; - } - - assert methodName != null; - runRefactoring(methodName, helper, owner, declarationOwner, editor, statement0); - - return true; - } - - private static boolean isLastStatementOfMethodOrClosure(GrStatement[] statements) { - final GrStatement statement0 = statements[0]; - - PsiElement returnFrom = PsiTreeUtil.getParentOfType(statement0, GrMethod.class, GrClosableBlock.class, GroovyFile.class); - if (returnFrom instanceof GrMethod) { - returnFrom = ((GrMethod)returnFrom).getBlock(); - } - LOG.assertTrue(returnFrom instanceof GrStatementOwner); - - final GrStatement[] blockStatements = ((GrStatementOwner)returnFrom).getStatements(); - final GrStatement lastFromBlock = ArrayUtil.getLastElement(blockStatements); - final GrStatement lastStatement = ArrayUtil.getLastElement(statements); - return statement0.getManager().areElementsEquivalent(lastFromBlock, lastStatement); - } - - private static void runRefactoring(final String methodName, - @NotNull final ExtractMethodInfoHelper helper, - @NotNull final GrMemberOwner owner, - final GrStatementOwner declarationOwner, - final Editor editor, - final PsiElement startElement) { - - final GrMethod method = ExtractMethodUtil.createMethodByHelper(methodName, helper); - final Runnable runnable = new Runnable() { - public void run() { - try { - PsiElement anchor = ExtractMethodUtil.calculateAnchorToInsertBefore(owner, startElement); - GrMethod newMethod = owner.addMemberDeclaration(method, anchor); - ExtractMethodUtil.renameParameterOccurrences(newMethod, helper); - GrReferenceAdjuster.shortenReferences(newMethod); - GrStatement realStatement; - - if (declarationOwner != null && !ExtractMethodUtil.isSingleExpression(helper.getStatements())) { - // Replace set of statements - final GrStatement[] newStatement = ExtractMethodUtil.createResultStatement(helper, methodName); - // add call statement - final GrStatement[] statements = helper.getStatements(); - assert statements.length > 0; - realStatement = null; - for (GrStatement statement : newStatement) { - realStatement = declarationOwner.addStatementBefore(statement, statements[0]); - } - assert realStatement != null; - // remove old statements - ExtractMethodUtil.removeOldStatements(declarationOwner, helper); - PsiImplUtil.removeNewLineAfter(realStatement); - } else { - // Expression call replace - GrExpression methodCall = ExtractMethodUtil.createMethodCallByHelper(methodName, helper); - GrExpression oldExpr = (GrExpression) helper.getStatements()[0]; - realStatement = oldExpr.replaceWithExpression(methodCall, true); - } - GrReferenceAdjuster.shortenReferences(realStatement); - - PsiElement prev = newMethod.getPrevSibling(); - IElementType elementType = prev.getNode().getElementType(); - if (!TokenSets.WHITE_SPACES_SET.contains(elementType) || !prev.getText().contains("\n")) { - newMethod.getParent().getNode().addLeaf(GroovyTokenTypes.mNLS, "\n", newMethod.getNode()); - } - - // move to offset - if (editor != null) { - PsiDocumentManager.getInstance(helper.getProject()).commitDocument(editor.getDocument()); - editor.getCaretModel().moveToOffset(ExtractMethodUtil.getCaretOffset(realStatement)); - } - - } catch (IncorrectOperationException e) { - LOG.error(e); - } - } - }; - - Project project = helper.getProject(); - CommandProcessor.getInstance().executeCommand( - project, - new Runnable() { - public void run() { - ApplicationManager.getApplication().runWriteAction(runnable); - editor.getSelectionModel().removeSelection(); - } - }, REFACTORING_NAME, null); - - - } - - private static GroovyExtractMethodDialog getDialog(@NotNull final ExtractMethodInfoHelper helper) { - GroovyExtractMethodDialog dialog = new GroovyExtractMethodDialog(helper, helper.getProject()); - dialog.show(); - return dialog; - } - - - public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) { - // does nothing - } - - public String getInvokeResult() { - return myInvokeResult; - } -} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/VisibilityPanel.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/VisibilityPanel.java deleted file mode 100644 index 407a17fac6f8..000000000000 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extractMethod/VisibilityPanel.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2000-2009 JetBrains s.r.o. - * - * Licensed 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.jetbrains.plugins.groovy.refactoring.extractMethod; - -import com.intellij.psi.PsiModifier; -import com.intellij.ui.IdeBorderFactory; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle; - -import javax.swing.*; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; -import java.awt.event.KeyEvent; -import java.util.EventListener; - -/** - * @author ilyas - */ -public class VisibilityPanel extends JPanel { - private final JRadioButton myRbPrivate; - private final JRadioButton myRbProtected; - private final JRadioButton myRbPublic; - - public VisibilityPanel() { - setBorder(IdeBorderFactory.createTitledBorder(GroovyRefactoringBundle.message("visibility.border.title"), false, true, true)); - setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - ButtonGroup bg = new ButtonGroup(); - - ItemListener listener = new ItemListener() { - public void itemStateChanged(ItemEvent e) { - if(e.getStateChange() == ItemEvent.SELECTED) { - fireStateChanged(); - } - } - }; - - myRbPrivate = new JRadioButton(); - myRbPrivate.setText(GroovyRefactoringBundle.message("visibility.private")); - myRbPrivate.addItemListener(listener); - myRbPrivate.setFocusable(false); - myRbPrivate.setMnemonic(KeyEvent.VK_V); - add(myRbPrivate); - bg.add(myRbPrivate); - - - myRbProtected = new JRadioButton(); - myRbProtected.setText(GroovyRefactoringBundle.message("visibility.protected")); - myRbProtected.addItemListener(listener); - myRbProtected.setFocusable(false); - myRbProtected.setMnemonic(KeyEvent.VK_O); - add(myRbProtected); - bg.add(myRbProtected); - - myRbPublic = new JRadioButton(); - myRbPublic.setText(GroovyRefactoringBundle.message("visibility.public")); - myRbPublic.addItemListener(listener); - myRbPublic.setFocusable(false); - myRbPublic.setMnemonic(KeyEvent.VK_B); - add(myRbPublic); - bg.add(myRbPublic); - } - - - @NotNull - public String getVisibility() { - if (myRbPublic.isSelected()) { - return PsiModifier.PUBLIC; - } - if (myRbProtected.isSelected()) { - return PsiModifier.PROTECTED; - } - if (myRbPrivate.isSelected()) { - return PsiModifier.PRIVATE; - } - return PsiModifier.PRIVATE; - } - - public void setVisibilityEnabled(String visibility, boolean value) { - if(PsiModifier.PRIVATE.equals(visibility)) myRbPrivate.setEnabled(value); - else if(PsiModifier.PROTECTED.equals(visibility)) myRbProtected.setEnabled(value); - else if(PsiModifier.PUBLIC.equals(visibility)) myRbPublic.setEnabled(value); - } - - public void setVisibility(String visibility) { - if (PsiModifier.PUBLIC.equals(visibility)) { - myRbPublic.setSelected(true); - } - else if (PsiModifier.PROTECTED.equals(visibility)) { - myRbProtected.setSelected(true); - } - else if (PsiModifier.PRIVATE.equals(visibility)) { - myRbPrivate.setSelected(true); - } - } - - public static interface VisibilityStateChanged extends EventListener { - void visibilityChanged(String newVisibility); - } - - public void addStateChangedListener(VisibilityStateChanged l) { - listenerList.add(VisibilityStateChanged.class, l); - } - - public void fireStateChanged() { - Object[] list = listenerList.getListenerList(); - - String visibility = getVisibility(); - for (Object obj : list) { - if (obj instanceof VisibilityStateChanged) { - ((VisibilityStateChanged)obj).visibilityChanged(visibility); - } - } - } -} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/ui/GrMethodSignatureComponent.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/ui/GrMethodSignatureComponent.java new file mode 100644 index 000000000000..a196e063bec5 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/ui/GrMethodSignatureComponent.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed 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.jetbrains.plugins.groovy.refactoring.ui; + +import com.intellij.openapi.project.Project; +import com.intellij.refactoring.ui.MethodSignatureComponent; +import org.jetbrains.plugins.groovy.GroovyFileType; + +/** + * @author Max Medvedev + */ +public class GrMethodSignatureComponent extends MethodSignatureComponent { + private final String myFileName; + + public GrMethodSignatureComponent(String signature, Project project) { + super(signature, project, GroovyFileType.GROOVY_FILE_TYPE); + myFileName = "dummy." + GroovyFileType.GROOVY_FILE_TYPE.getDefaultExtension(); + } + + @Override + protected String getFileName() { + return myFileName; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/ui/GroovyComboboxVisibilityPanel.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/ui/GroovyComboboxVisibilityPanel.java new file mode 100644 index 000000000000..4081f7aa0cab --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/ui/GroovyComboboxVisibilityPanel.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed 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.jetbrains.plugins.groovy.refactoring.ui; + +import com.intellij.refactoring.ui.ComboBoxVisibilityPanel; + +import static com.intellij.psi.PsiModifier.*; +import static com.intellij.util.VisibilityUtil.toPresentableText; + +/** + * @author Max Medvedev + */ +public class GroovyComboboxVisibilityPanel extends ComboBoxVisibilityPanel { + private static final String[] MODIFIERS = {PRIVATE, PROTECTED, PUBLIC}; + + private static final String[] PRESENTABLE_NAMES = { + toPresentableText(PRIVATE), + toPresentableText(PROTECTED), + toPresentableText(PUBLIC) + }; + + public GroovyComboboxVisibilityPanel() { + super(MODIFIERS, PRESENTABLE_NAMES); + } +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodTest.java similarity index 93% rename from plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodTest.java rename to plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodTest.java index d27423497c2a..ca9a658db497 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extractMethod/ExtractMethodTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodTest.java @@ -1,5 +1,6 @@ /* - * Copyright 2000-2007 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. + * * Licensed 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 @@ -13,7 +14,7 @@ * limitations under the License. */ -package org.jetbrains.plugins.groovy.refactoring.extractMethod; +package org.jetbrains.plugins.groovy.refactoring.extract.method; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.impl.source.PostprocessReformattingAspect; @@ -34,7 +35,7 @@ public class ExtractMethodTest extends LightGroovyTestCase { private void doAntiTest(String errorMessage) throws Exception { GroovyExtractMethodHandler handler = configureFromText(readInput().get(0)); - assertFalse(handler.invokeOnEditor(getProject(), myFixture.getEditor(), myFixture.getFile())); + handler.invoke(getProject(), myFixture.getEditor(), myFixture.getFile()); assertEquals(errorMessage, handler.getInvokeResult()); } @@ -45,7 +46,7 @@ public class ExtractMethodTest extends LightGroovyTestCase { private void doTest() { final List data = readInput(); GroovyExtractMethodHandler handler = configureFromText(data.get(0)); - assertTrue(handler.invokeOnEditor(getProject(), myFixture.getEditor(), myFixture.getFile())); + handler.invoke(getProject(), myFixture.getEditor(), myFixture.getFile()); PostprocessReformattingAspect.getInstance(getProject()).doPostponedFormatting(); myFixture.checkResult(StringUtil.trimEnd(data.get(1), "\n")); } diff --git a/plugins/groovy/testdata/groovy/refactoring/extractMethod/forIn.test b/plugins/groovy/testdata/groovy/refactoring/extractMethod/forIn.test index a25df26b9779..3c6fde91bc6d 100644 --- a/plugins/groovy/testdata/groovy/refactoring/extractMethod/forIn.test +++ b/plugins/groovy/testdata/groovy/refactoring/extractMethod/forIn.test @@ -7,11 +7,11 @@ void aaa(Map map) { ----- void aaa(Map map) { for (Map.Entry versionEntry in map.entrySet()) { - testMethod(versionEntry); + testMethod(versionEntry) } } private testMethod(Map.Entry versionEntry) { String name = versionEntry.getKey(); - System.out.println(name) + System.out.println(name); }