From aa2a0487bd9602b63ea03a2d252f4bd5ace656fa Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 3 Dec 2014 17:54:21 +0100 Subject: [PATCH 01/33] light nullity inference from source: allow several invocations of the same delegate method --- .../dataFlow/NullityInference.java | 18 +++++++++++------- .../NullityInferenceFromSourceTestCase.groovy | 11 +++++++++++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java index 5da9974a638e..84c10fa61781 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java @@ -26,7 +26,7 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -68,7 +68,7 @@ public class NullityInference { final AtomicBoolean hasNotNulls = new AtomicBoolean(); final AtomicBoolean hasNulls = new AtomicBoolean(); final AtomicBoolean hasUnknowns = new AtomicBoolean(); - final List calls = ContainerUtil.newArrayList(); + final Set delegates = ContainerUtil.newLinkedHashSet(); body.accept(new JavaRecursiveElementWalkingVisitor() { @Override public void visitReturnStatement(PsiReturnStatement statement) { @@ -87,7 +87,12 @@ public class NullityInference { hasNotNulls.set(true); } else if (value instanceof PsiMethodCallExpression) { - calls.add((PsiMethodCallExpression)value); + PsiMethod target = ((PsiMethodCallExpression)value).resolveMethod(); + if (target == null) { + hasUnknowns.set(true); + } else { + delegates.add(target); + } } else { hasUnknowns.set(true); @@ -106,13 +111,12 @@ public class NullityInference { return Nullness.NULLABLE; } - if (calls.size() > 1) { + if (delegates.size() > 1) { return Nullness.UNKNOWN; } - if (calls.size() == 1) { - PsiMethod target = calls.get(0).resolveMethod(); - if (target != null && NullableNotNullManager.isNotNull(target)) { + if (delegates.size() == 1) { + if (NullableNotNullManager.isNotNull(delegates.iterator().next())) { return Nullness.NOT_NULL; } return Nullness.UNKNOWN; diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/NullityInferenceFromSourceTestCase.groovy b/java/java-tests/testSrc/com/intellij/codeInspection/NullityInferenceFromSourceTestCase.groovy index 4e85aa7db68d..e7b38c11d53d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/NullityInferenceFromSourceTestCase.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInspection/NullityInferenceFromSourceTestCase.groovy @@ -42,6 +42,17 @@ abstract class NullityInferenceFromSourceTestCase extends LightCodeInsightFixtur assert inferNullity(parse('String foo() { return bar(); }; String bar() { return "z"; }; ')) == NOT_NULL } + void "test same delegate method invoked twice"() { + assert inferNullity(parse(''' +String foo() { + if (equals(2)) return bar(); + if (equals(3)) return bar(); + return "abc"; +} +String bar() { return "z"; } +''')) == NOT_NULL + } + void "test if branch returns null"() { assert inferNullity(parse('String bar() { if (equals(2)) return null; return "a"; }; ')) == NULLABLE } From 92828e12325beabe3e99f815781a338049459bdf Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 3 Dec 2014 18:20:28 +0100 Subject: [PATCH 02/33] light nullity inference from source: don't infer when there are errors --- .../intellij/codeInspection/dataFlow/NullityInference.java | 2 +- .../NullityInferenceFromSourceTestCase.groovy | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java index 84c10fa61781..e77a9478334b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullityInference.java @@ -111,7 +111,7 @@ public class NullityInference { return Nullness.NULLABLE; } - if (delegates.size() > 1) { + if (hasErrors.get() || delegates.size() > 1) { return Nullness.UNKNOWN; } diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/NullityInferenceFromSourceTestCase.groovy b/java/java-tests/testSrc/com/intellij/codeInspection/NullityInferenceFromSourceTestCase.groovy index e7b38c11d53d..c6b6bfd65149 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/NullityInferenceFromSourceTestCase.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInspection/NullityInferenceFromSourceTestCase.groovy @@ -75,7 +75,7 @@ String bar() { return "z"; } protected abstract Nullness inferNullity(PsiMethod method) - private PsiMethod parse(String method) { + protected PsiMethod parse(String method) { return myFixture.addClass("final class Foo { $method }").methods[0] } @@ -83,6 +83,10 @@ String bar() { return "z"; } Nullness inferNullity(PsiMethod method) { return NullableNotNullManager.isNotNull(method) ? NOT_NULL : NullableNotNullManager.isNullable(method) ? NULLABLE : UNKNOWN } + + void "test skip when errors"() { + assert inferNullity(parse('String foo() { if(); return 2; } ')) == UNKNOWN + } } static class DfaInferenceTest extends NullityInferenceFromSourceTestCase { From 381ef3565f3e30dab2179966cc503b9202c09312 Mon Sep 17 00:00:00 2001 From: Elizaveta Shashkova Date: Wed, 3 Dec 2014 20:42:39 +0300 Subject: [PATCH 03/33] add tests for PyQt debugging --- python/testData/debug/test_pyqt1.py | 15 +++ python/testData/debug/test_pyqt2.py | 23 ++++ python/testData/debug/test_pyqt3.py | 19 ++++ .../env/python/PythonDebuggerTest.java | 106 ++++++++++++++++++ 4 files changed, 163 insertions(+) create mode 100644 python/testData/debug/test_pyqt1.py create mode 100644 python/testData/debug/test_pyqt2.py create mode 100644 python/testData/debug/test_pyqt3.py diff --git a/python/testData/debug/test_pyqt1.py b/python/testData/debug/test_pyqt1.py new file mode 100644 index 000000000000..5a11f2fa66f5 --- /dev/null +++ b/python/testData/debug/test_pyqt1.py @@ -0,0 +1,15 @@ +from PyQt5 import QtCore +import sys + + +class AThread(QtCore.QThread): + + def run(self): + for i in range(3): + print("ping %d" % i) + +app = QtCore.QCoreApplication([]) +thread = AThread() +thread.finished.connect(app.exit) +thread.start() +sys.exit(app.exec_()) diff --git a/python/testData/debug/test_pyqt2.py b/python/testData/debug/test_pyqt2.py new file mode 100644 index 000000000000..e8785fcf280a --- /dev/null +++ b/python/testData/debug/test_pyqt2.py @@ -0,0 +1,23 @@ +from PyQt5 import QtCore +import sys + + +class SomeObject(QtCore.QObject): + + finished = QtCore.pyqtSignal() + + def longRunning(self): + for i in range(3): + print("ping %d" % i) + self.finished.emit() + + +app = QtCore.QCoreApplication([]) +objThread = QtCore.QThread() +obj = SomeObject() +obj.moveToThread(objThread) +obj.finished.connect(objThread.quit) +objThread.started.connect(obj.longRunning) +objThread.finished.connect(app.exit) +objThread.start() +sys.exit(app.exec_()) \ No newline at end of file diff --git a/python/testData/debug/test_pyqt3.py b/python/testData/debug/test_pyqt3.py new file mode 100644 index 000000000000..a505b0070e21 --- /dev/null +++ b/python/testData/debug/test_pyqt3.py @@ -0,0 +1,19 @@ +from PyQt5 import QtCore +import sys + + +class Runnable(QtCore.QRunnable): + + def run(self): + app = QtCore.QCoreApplication.instance() + for i in range(3): + print("ping %d" % i) + app.quit() + + +app = QtCore.QCoreApplication([]) +runnable = Runnable() +QtCore.QThreadPool.globalInstance().start(runnable) +sys.exit(app.exec_()) + + diff --git a/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java b/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java index 628c3826c807..4e0c3177a5e5 100644 --- a/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java +++ b/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java @@ -510,6 +510,112 @@ public class PythonDebuggerTest extends PyEnvTestCase { }); } + public void testPyQtQThreadInheritor() throws Exception { + runPythonTest(new PyDebuggerTask("/debug", "test_pyqt1.py") { + @Override + protected void init() { + setMultiprocessDebug(true); + } + + @Override + public void before() throws Exception { + toggleBreakpoint(getScriptPath(), 8); + } + + @Override + public void testing() throws Exception { + + waitForPause(); + + eval("i").hasValue("0"); + + resume(); + + waitForPause(); + + eval("i").hasValue("1"); + + resume(); + } + + @Override + public Set getTags() { + return Sets.newHashSet("pyqt5"); + } + }); + } + + public void testPyQtMoveToThread() throws Exception { + runPythonTest(new PyDebuggerTask("/debug", "test_pyqt2.py") { + @Override + protected void init() { + setMultiprocessDebug(true); + } + + @Override + public void before() throws Exception { + toggleBreakpoint(getScriptPath(), 10); + } + + @Override + public void testing() throws Exception { + + waitForPause(); + + eval("i").hasValue("0"); + + resume(); + + waitForPause(); + + eval("i").hasValue("1"); + + resume(); + } + + @Override + public Set getTags() { + return Sets.newHashSet("pyqt5"); + } + }); + } + + + public void testPyQtQRunnableInheritor() throws Exception { + runPythonTest(new PyDebuggerTask("/debug", "test_pyqt3.py") { + @Override + protected void init() { + setMultiprocessDebug(true); + } + + @Override + public void before() throws Exception { + toggleBreakpoint(getScriptPath(), 9); + } + + @Override + public void testing() throws Exception { + + waitForPause(); + + eval("i").hasValue("0"); + + resume(); + + waitForPause(); + + eval("i").hasValue("1"); + + resume(); + } + + @Override + public Set getTags() { + return Sets.newHashSet("pyqt5"); + } + }); + } + //TODO: fix me as I don't work properly sometimes (something connected with process termination on agent) //public void testResume() throws Exception { From 74640f828ccfc9e2405e771294a835efb008204b Mon Sep 17 00:00:00 2001 From: Sergey Savenko Date: Tue, 2 Dec 2014 19:43:49 +0300 Subject: [PATCH 04/33] JBListTable javax swing Timer-based row resize animator --- .../src/com/intellij/ui/Animated.java | 25 -- .../intellij/ui/TableToolbarDecorator.java | 5 +- .../intellij/util/ui/table/JBListTable.java | 261 ++++++++++-------- .../util/ui/table/TableModelEditor.java | 4 +- .../util/src/com/intellij/ui/TableUtil.java | 8 +- 5 files changed, 149 insertions(+), 154 deletions(-) delete mode 100644 platform/platform-api/src/com/intellij/ui/Animated.java diff --git a/platform/platform-api/src/com/intellij/ui/Animated.java b/platform/platform-api/src/com/intellij/ui/Animated.java deleted file mode 100644 index 26c6b0bc3a40..000000000000 --- a/platform/platform-api/src/com/intellij/ui/Animated.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2000-2013 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 com.intellij.ui; - -/** - * Indicates that component, or cell editor, or cell renderer performs - * some animations and side effects may occur because of changes of the bounds - * - * @author Konstantin Bulenkov - */ -public interface Animated { -} diff --git a/platform/platform-api/src/com/intellij/ui/TableToolbarDecorator.java b/platform/platform-api/src/com/intellij/ui/TableToolbarDecorator.java index 980d6ae50af6..af62010bc1c0 100644 --- a/platform/platform-api/src/com/intellij/ui/TableToolbarDecorator.java +++ b/platform/platform-api/src/com/intellij/ui/TableToolbarDecorator.java @@ -120,8 +120,7 @@ class TableToolbarDecorator extends ToolbarDecorator { table.setColumnSelectionInterval(0, 0); table.editCellAt(index, 0); - boolean temporaryHideVerticalScrollBar = table.getCellEditor() instanceof Animated; - TableUtil.updateScroller(table, temporaryHideVerticalScrollBar); + TableUtil.updateScroller(table); //noinspection SSBasedInspection SwingUtilities.invokeLater(new Runnable() { @Override @@ -145,7 +144,7 @@ class TableToolbarDecorator extends ToolbarDecorator { if (TableUtil.doRemoveSelectedItems(table, tableModel, null)) { updateButtons(); table.requestFocus(); - TableUtil.updateScroller(table, false); + TableUtil.updateScroller(table); } } }; diff --git a/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java b/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java index 4ab92f15293b..a776e2129942 100644 --- a/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java +++ b/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java @@ -19,11 +19,18 @@ import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorFontType; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Ref; -import com.intellij.ui.*; +import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.ui.DottedBorder; +import com.intellij.ui.EditorSettingsProvider; +import com.intellij.ui.EditorTextField; +import com.intellij.ui.TableUtil; import com.intellij.ui.table.JBTable; import com.intellij.util.ui.AbstractTableCellEditor; import com.intellij.util.ui.UIUtil; +import gnu.trove.TIntArrayList; +import gnu.trove.TIntObjectHashMap; +import gnu.trove.TIntObjectProcedure; +import gnu.trove.TIntProcedure; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -31,9 +38,9 @@ import javax.swing.event.ChangeEvent; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; import java.awt.*; -import java.awt.event.KeyEvent; -import java.awt.event.MouseEvent; +import java.awt.event.*; import java.util.List; import static java.awt.event.KeyEvent.*; @@ -44,9 +51,10 @@ import static java.awt.event.KeyEvent.*; public abstract class JBListTable extends JPanel { protected final JTable myInternalTable; private final JBTable mainTable; - private final Ref myLastEditorIndex = Ref.create(null); + private final RowResizeAnimator myRowResizeAnimator; private MouseEvent myMouseEvent; private MyCellEditor myCellEditor; + private int myLastFocusedEditorComponentIdx = -1; public JBListTable(@NotNull final JTable t) { super(new BorderLayout()); @@ -64,7 +72,7 @@ public abstract class JBListTable extends JPanel { @Override public void addRow() { - myLastEditorIndex.set(null); + myLastFocusedEditorComponentIdx = -1; super.addRow(); } }; @@ -199,6 +207,16 @@ public abstract class JBListTable extends JPanel { return super.processKeyBinding(ks, e, condition, pressed); } + @Override + public void columnMarginChanged(ChangeEvent e) { + // we don't stop editing (it prevents editor removal when scrollbar is added) + TableColumn resizingColumn = tableHeader != null ? tableHeader.getResizingColumn() : null; + if (resizingColumn != null && autoResizeMode == AUTO_RESIZE_OFF) { + resizingColumn.setPreferredWidth(resizingColumn.getWidth()); + } + resizeAndRepaint(); + } + @Override public TableCellEditor getCellEditor(final int row, int column) { final JBTableRowEditor editor = getRowEditor(row); @@ -224,8 +242,15 @@ public abstract class JBListTable extends JPanel { boolean isSelected = isCellSelected(row, column); return editor.getTableCellEditorComponent(this, value, isSelected, row, column); } + + @Override + public void removeNotify() { + super.removeNotify(); + myRowResizeAnimator.stopAnimation(); + } }; mainTable.setStriped(true); + myRowResizeAnimator = new RowResizeAnimator(mainTable); } public void stopEditing() { @@ -296,118 +321,49 @@ public abstract class JBListTable extends JPanel { return panel; } - private static class RowResizeAnimator extends Thread { - private final JTable myTable; - private final int myRow; - private final JScrollPane myScrollPane; - private int neededHeight; - private final JBTableRowEditor myEditor; - private final Ref myIndex; - private int step = 5; - private int currentHeight; - - private RowResizeAnimator(JTable table, int row, int height, JBTableRowEditor editor, @NotNull Ref index) { - super("Row Animator"); - myTable = table; - myRow = row; - neededHeight = height; - myEditor = editor; - myIndex = index; - currentHeight = myTable.getRowHeight(myRow); - myScrollPane = UIUtil.getParentOfType(JScrollPane.class, myTable); - } - - @Override - public void run() { - final boolean exitEditing = currentHeight > neededHeight; - try { - sleep(50); - final JScrollBar bar = myScrollPane.getVerticalScrollBar(); - if (bar == null || !bar.isVisible()) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - myScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); - } - }); - sleep(15); - } - while (currentHeight != neededHeight) { - if (Math.abs(currentHeight - neededHeight) < step) { - currentHeight = neededHeight; - } - else { - currentHeight += currentHeight < neededHeight ? step : -step; - } - SwingUtilities.invokeLater(new Runnable() { - public void run() { - myTable.setRowHeight(myRow, currentHeight); - } - }); - sleep(15); - } - if (myEditor != null) { - JComponent[] components = myEditor.getFocusableComponents(); - JComponent focus = null; - if (myIndex.get() != null) { - int index = myIndex.get().intValue(); - if (0 <= index && index < components.length) { - focus = components[index]; - } - } - if (focus == null) { - focus = myEditor.getPreferredFocusedComponent(); - } - if (focus != null) { - focus.requestFocus(); - } - } - } - catch (InterruptedException ignore) { - } finally { - //noinspection SSBasedInspection - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - TableUtil.scrollSelectionToVisible(myTable); - if (exitEditing && !myTable.isEditing()) { - myScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); - } - } - }); - } - } - } - - private class MyCellEditor extends AbstractTableCellEditor implements Animated { - JTable curTable; + private class MyCellEditor extends AbstractTableCellEditor { private final JBTableRowEditor myEditor; public MyCellEditor(JBTableRowEditor editor) { myEditor = editor; - curTable = null; } @Override public Component getTableCellEditorComponent(final JTable table, Object value, boolean isSelected, final int row, int column) { - curTable = table; final JPanel p = new JPanel(new BorderLayout()) { @Override public void addNotify() { super.addNotify(); - final int height = (int)getPreferredSize().getHeight(); + int height = getPreferredSize().height; if (height > table.getRowHeight(row)) { - new RowResizeAnimator(table, row, height, myEditor, myMouseEvent == null ? myLastEditorIndex : Ref.create(null)).start(); + myRowResizeAnimator.resize(row, height); } } public void removeNotify() { if (myCellEditor != null) myCellEditor.saveFocusIndex(); super.removeNotify(); - new RowResizeAnimator(table, row, table.getRowHeight(), null, myMouseEvent == null ? myLastEditorIndex : Ref.create(null)).start(); + myRowResizeAnimator.resize(row, table.getRowHeight()); } }; + p.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + IdeFocusManager focusManager = IdeFocusManager.findInstanceByComponent(p); + focusManager.requestFocus(getComponentToFocus(), true); + } + + private Component getComponentToFocus() { + if (myLastFocusedEditorComponentIdx >= 0) { + JComponent[] focusableComponents = myEditor.getFocusableComponents(); + if (myLastFocusedEditorComponentIdx < focusableComponents.length) { + return focusableComponents[myLastFocusedEditorComponentIdx]; + } + } + return myEditor.getPreferredFocusedComponent(); + } + }); p.add(myEditor, BorderLayout.CENTER); - p.setFocusable(false); return p; } @@ -422,31 +378,102 @@ public abstract class JBListTable extends JPanel { return super.stopCellEditing(); } - private void removeEmptyRow() { - final int row = curTable.getSelectedRow(); - if (row != -1 && isRowEmpty(row)) { - final JBListTableModel model = (JBListTableModel)curTable.getModel(); - final int count = model.getRowCount(); - model.removeRow(row); - int newRow = count == row + 1 ? row - 1 : row; - curTable.setRowSelectionInterval(newRow, newRow); - } - } - - public void saveFocusIndex() { - JComponent[] components = myEditor.getFocusableComponents(); - for (int i = 0; i < components.length; i++) { - if (components[i].hasFocus()) { - JBListTable.this.myLastEditorIndex.set(i); - break; - } - } - } - @Override public void cancelCellEditing() { saveFocusIndex(); super.cancelCellEditing(); } + + private void saveFocusIndex() { + JComponent[] components = myEditor.getFocusableComponents(); + for (int i = 0; i < components.length; i++) { + if (components[i].hasFocus()) { + myLastFocusedEditorComponentIdx = i; + break; + } + } + } + } + + private static class RowResizeAnimator implements ActionListener { + private static final int ANIMATION_STEP_MILLIS = 15; + private static final int RESIZE_AMOUNT_PER_STEP = 5; + + private final TIntObjectHashMap myRowAnimationStates = new TIntObjectHashMap(); + private final Timer myAnimationTimer = new Timer(ANIMATION_STEP_MILLIS, this); + private final JTable myTable; + + public RowResizeAnimator(JTable table) { + myTable = table; + } + + public void resize(int row, int targetHeight) { + myRowAnimationStates.put(row, new RowAnimationState(row, targetHeight)); + startAnimation(); + } + + @Override + public void actionPerformed(final ActionEvent e) { + doAnimationStep(e.getWhen()); + } + + private void startAnimation() { + if (!myAnimationTimer.isRunning()) { + myAnimationTimer.start(); + } + } + + private void stopAnimation() { + myAnimationTimer.stop(); + } + + private void doAnimationStep(final long updateTime) { + final TIntArrayList completeRows = new TIntArrayList(myRowAnimationStates.size()); + myRowAnimationStates.forEachEntry(new TIntObjectProcedure() { + @Override + public boolean execute(int row, RowAnimationState animationState) { + if (animationState.doAnimationStep(updateTime)) { + completeRows.add(row); + } + return true; + } + }); + completeRows.forEach(new TIntProcedure() { + @Override + public boolean execute(int row) { + myRowAnimationStates.remove(row); + return true; + } + }); + if (myRowAnimationStates.isEmpty()) { + stopAnimation(); + } + } + + private class RowAnimationState { + private final int myRow; + private final int myTargetHeight; + private long myLastUpdateTime; + + public RowAnimationState(int row, int targetHeight) { + myRow = row; + myTargetHeight = targetHeight; + myLastUpdateTime = System.currentTimeMillis(); + } + + /** + * @return whether this row animation is complete + */ + public boolean doAnimationStep(long currentTime) { + int currentRowHeight = myTable.getRowHeight(myRow); + int resizeAbs = (int) (RESIZE_AMOUNT_PER_STEP * ((currentTime - myLastUpdateTime) / (double)ANIMATION_STEP_MILLIS)); + int leftToAnimate = myTargetHeight - currentRowHeight; + int newHeight = Math.abs(leftToAnimate) <= Math.abs(resizeAbs) ? myTargetHeight : + currentRowHeight + (leftToAnimate < 0 ? -resizeAbs : resizeAbs); + myTable.setRowHeight(myRow, newHeight); + myLastUpdateTime = currentTime; + return myTargetHeight == newHeight; + } + } } } diff --git a/platform/platform-impl/src/com/intellij/util/ui/table/TableModelEditor.java b/platform/platform-impl/src/com/intellij/util/ui/table/TableModelEditor.java index 63d38ed57fcb..48c07843ab99 100644 --- a/platform/platform-impl/src/com/intellij/util/ui/table/TableModelEditor.java +++ b/platform/platform-impl/src/com/intellij/util/ui/table/TableModelEditor.java @@ -371,7 +371,7 @@ public class TableModelEditor implements ElementProducer { } table.requestFocus(); - TableUtil.updateScroller(table, false); + TableUtil.updateScroller(table); } } ).createPanel(); @@ -440,7 +440,7 @@ public class TableModelEditor implements ElementProducer { public void run(AnActionButton button) { if (TableUtil.doRemoveSelectedItems(table, model, this)) { table.requestFocus(); - TableUtil.updateScroller(table, false); + TableUtil.updateScroller(table); } } diff --git a/platform/util/src/com/intellij/ui/TableUtil.java b/platform/util/src/com/intellij/ui/TableUtil.java index 53d55d3b78b9..070acf4cec19 100644 --- a/platform/util/src/com/intellij/ui/TableUtil.java +++ b/platform/util/src/com/intellij/ui/TableUtil.java @@ -244,15 +244,9 @@ public class TableUtil { column.setMinWidth(checkboxWidth); } - public static void updateScroller(@NotNull JTable table, boolean temporaryHideVerticalScrollBar) { + public static void updateScroller(@NotNull JTable table) { JScrollPane scrollPane = UIUtil.getParentOfType(JScrollPane.class, table); if (scrollPane != null) { - if (temporaryHideVerticalScrollBar) { - final JScrollBar bar = scrollPane.getVerticalScrollBar(); - if (bar == null || !bar.isVisible()) { - scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); - } - } scrollPane.revalidate(); scrollPane.repaint(); } From 99b4ca165cadb8ebe36051d4cd0e1736226b4e33 Mon Sep 17 00:00:00 2001 From: Sergey Savenko Date: Wed, 3 Dec 2014 18:50:20 +0300 Subject: [PATCH 05/33] DocumentMarkupModel: use interface --- .../intellij/openapi/editor/impl/DocumentMarkupModel.java | 2 +- .../openapi/editor/impl/DocumentMarkupModelManager.java | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/DocumentMarkupModel.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/DocumentMarkupModel.java index 21c4674b2497..6888366740c5 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/DocumentMarkupModel.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/DocumentMarkupModel.java @@ -84,7 +84,7 @@ public class DocumentMarkupModel { if (create && model == null) { MarkupModelImpl newModel = new MarkupModelImpl((DocumentEx)document); if ((model = ConcurrencyUtil.cacheOrGet(markupModelMap, project, newModel)) == newModel) { - documentMarkupModelManager.registerDocument((DocumentImpl)document); + documentMarkupModelManager.registerDocument(document); } else { newModel.dispose(); diff --git a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/DocumentMarkupModelManager.java b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/DocumentMarkupModelManager.java index deb03faf7e0f..05eb145860dc 100644 --- a/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/DocumentMarkupModelManager.java +++ b/platform/editor-ui-ex/src/com/intellij/openapi/editor/impl/DocumentMarkupModelManager.java @@ -18,6 +18,7 @@ package com.intellij.openapi.editor.impl; import com.intellij.openapi.Disposable; import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.util.containers.WeakList; @@ -29,7 +30,7 @@ import org.jetbrains.annotations.NotNull; public class DocumentMarkupModelManager extends AbstractProjectComponent { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.DocumentMarkupModelManager"); - private final WeakList myDocumentSet = new WeakList(); + private final WeakList myDocumentSet = new WeakList(); private volatile boolean myDisposed; public static DocumentMarkupModelManager getInstance(Project project) { @@ -46,7 +47,7 @@ public class DocumentMarkupModelManager extends AbstractProjectComponent { }); } - public void registerDocument(DocumentImpl document) { + public void registerDocument(Document document) { LOG.assertTrue(!myDisposed); myDocumentSet.add(document); } @@ -58,7 +59,7 @@ public class DocumentMarkupModelManager extends AbstractProjectComponent { private void cleanupProjectMarkups() { if (!myDisposed) { myDisposed = true; - for (DocumentImpl document : myDocumentSet.toStrongList()) { + for (Document document : myDocumentSet.toStrongList()) { DocumentMarkupModel.removeMarkupModel(document, myProject); } } From d5bb8fe893362a289e3dcb16f5224b7d2362904e Mon Sep 17 00:00:00 2001 From: Sergey Savenko Date: Wed, 3 Dec 2014 18:52:06 +0300 Subject: [PATCH 06/33] EditorTextFieldCellRenderer: improve reusability --- .../ui/EditorTextFieldCellRenderer.java | 77 ++++++++++++++----- 1 file changed, 56 insertions(+), 21 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java b/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java index e4a30d230ea9..122003fc9419 100644 --- a/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java +++ b/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java @@ -20,6 +20,7 @@ import com.intellij.openapi.editor.EditorFactory; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.editor.colors.EditorColors; +import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.colors.impl.DelegateColorScheme; import com.intellij.openapi.editor.event.DocumentListener; @@ -30,7 +31,9 @@ import com.intellij.openapi.editor.impl.RangeMarkerTree; import com.intellij.openapi.editor.markup.HighlighterLayer; import com.intellij.openapi.editor.markup.HighlighterTargetArea; import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypes; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.LineTokenizer; import com.intellij.openapi.util.text.StringUtil; @@ -56,31 +59,54 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, private static final Key MY_PANEL_PROPERTY = Key.create("EditorTextFieldCellRenderer.MyEditorPanel"); - public EditorTextFieldCellRenderer(Disposable parent) { + private final Project myProject; + private final boolean myInheritFontFromLaF; + + protected EditorTextFieldCellRenderer(@Nullable Project project, @NotNull Disposable parent) { + this(project, true, parent); + } + + protected EditorTextFieldCellRenderer(@Nullable Project project, boolean inheritFontFromLaF, @NotNull Disposable parent) { + myProject = project; + myInheritFontFromLaF = inheritFontFromLaF; Disposer.register(parent, this); } - protected abstract EditorColorsScheme getColorScheme(); - - protected abstract String getText(FontMetrics fontMetrics, JTable table, Object value, int row, int column); + protected abstract String getText(JTable table, Object value, int row, int column); @Nullable - protected abstract TextAttributes getTextAttributes(Object value, boolean selected, int row, int col); + protected TextAttributes getTextAttributes(JTable table, Object value, boolean selected, boolean focused, int row, int col) { + return null; + } + + protected Color getCellBackground(JTable table, Object value, boolean selected, boolean focused, int row, int column) { + return UIUtil.getTableBackground(selected); + } + + @Nullable + protected FileType getFileType() { + return null; + } + + @NotNull + protected EditorColorsScheme getColorScheme() { + return EditorColorsManager.getInstance().getGlobalScheme(); + } @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean focused, int row, int column) { MyPanel panel = getEditorPanel(table); EditorEx editor = panel.myEditor; editor.getColorsScheme().setEditorFontSize(table.getFont().getSize()); - String text = getText(((EditorImpl)editor).getFontMetrics(Font.PLAIN), table, value, row, column); - TextAttributes textAttributes = getTextAttributes(value, isSelected, row, column); + String text = getText(table, value, row, column); + TextAttributes textAttributes = getTextAttributes(table, value, selected, focused, row, column); panel.setText(text, textAttributes); - ((EditorImpl)editor).setPaintSelection(isSelected); - editor.getSelectionModel().setSelection(0, isSelected ? editor.getDocument().getTextLength() : 0); + ((EditorImpl)editor).setPaintSelection(selected); + editor.getSelectionModel().setSelection(0, selected ? editor.getDocument().getTextLength() : 0); editor.getColorsScheme().setColor(EditorColors.SELECTION_BACKGROUND_COLOR, table.getSelectionBackground()); editor.getColorsScheme().setColor(EditorColors.SELECTION_FOREGROUND_COLOR, table.getSelectionForeground()); - editor.setBackgroundColor(getCellBackgroundColor(getColorScheme(), table, isSelected, row)); + editor.setBackgroundColor(getCellBackground(table, value, selected, focused, row, column)); panel.setOpaque(!Comparing.equal(editor.getBackgroundColor(), table.getBackground())); panel.setBorder(null); // prevents double border painting when ExtendedItemRendererComponentWrapper is used @@ -88,14 +114,8 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, return panel; } - public static Color getCellBackgroundColor(EditorColorsScheme colorsScheme, JTable table, boolean isSelected, int row) { - return isSelected ? table.getSelectionBackground() : - table.getSelectionModel().getLeadSelectionIndex() == row ? colorsScheme.getColor(EditorColors.CARET_ROW_COLOR) : - table.getBackground(); - } - @NotNull - private MyPanel getEditorPanel(JTable table) { + private MyPanel getEditorPanel(final JTable table) { MyPanel panel = UIUtil.getClientProperty(table, MY_PANEL_PROPERTY); if (panel != null) { DelegateColorScheme scheme = (DelegateColorScheme)panel.myEditor.getColorsScheme(); @@ -103,10 +123,10 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, return panel; } - // reuse EditorTextField initialization logic - EditorTextField field = new EditorTextField(new MyDocument(), null, FileTypes.PLAIN_TEXT, false, false); + FileType fileType = ObjectUtils.notNull(getFileType(), FileTypes.PLAIN_TEXT); + EditorTextField field = new EditorTextField(new MyDocument(), myProject, fileType, false, false); field.setSupplementary(true); - field.setFontInheritedFromLAF(false); + field.setFontInheritedFromLAF(myInheritFontFromLaF); field.addNotify(); // creates editor EditorEx editor = (EditorEx)ObjectUtils.assertNotNull(field.getEditor()); @@ -119,6 +139,12 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, panel = new MyPanel(editor); Disposer.register(this, panel); + Disposer.register(this, new Disposable() { + @Override + public void dispose() { + UIUtil.putClientProperty(table, MY_PANEL_PROPERTY, null); + } + }); table.putClientProperty(MY_PANEL_PROPERTY, panel); return panel; @@ -157,6 +183,15 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, recalculatePreferredSize(); } + @Override + public void setBackground(Color bg) { + // allows for striped tables + if (myEditor != null) { + myEditor.setBackgroundColor(bg); + } + super.setBackground(bg); + } + @Override public Dimension getPreferredSize() { return myPreferredSize; From 13ec591a2052fc9182eaab41c7d1d7488f83ee0c Mon Sep 17 00:00:00 2001 From: Sergey Savenko Date: Wed, 3 Dec 2014 19:13:18 +0300 Subject: [PATCH 07/33] wildcards --- platform/util/src/com/intellij/util/ui/ColumnInfo.java | 2 +- platform/util/src/com/intellij/util/ui/ListTableModel.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/util/src/com/intellij/util/ui/ColumnInfo.java b/platform/util/src/com/intellij/util/ui/ColumnInfo.java index 2ad54e6f81b9..1be6e451deea 100644 --- a/platform/util/src/com/intellij/util/ui/ColumnInfo.java +++ b/platform/util/src/com/intellij/util/ui/ColumnInfo.java @@ -55,7 +55,7 @@ public abstract class ColumnInfo { return myName; } - public Class getColumnClass() { + public Class getColumnClass() { return String.class; } diff --git a/platform/util/src/com/intellij/util/ui/ListTableModel.java b/platform/util/src/com/intellij/util/ui/ListTableModel.java index 9577ab235735..8e01d89374cc 100644 --- a/platform/util/src/com/intellij/util/ui/ListTableModel.java +++ b/platform/util/src/com/intellij/util/ui/ListTableModel.java @@ -62,7 +62,7 @@ public class ListTableModel extends TableViewModel implements Editab } @Override - public Class getColumnClass(int columnIndex) { + public Class getColumnClass(int columnIndex) { return myColumnInfos[columnIndex].getColumnClass(); } From 3f9421ed1bdd9a39779b420c5bfc67984f9e6bb1 Mon Sep 17 00:00:00 2001 From: Sergey Savenko Date: Wed, 3 Dec 2014 19:24:05 +0300 Subject: [PATCH 08/33] JBListTable: introduce JBTableRowRenderer --- .../ChangeSignatureDialogBase.java | 105 ++++++++++++------ .../intellij/util/ui/table/JBListTable.java | 13 +-- .../util/ui/table/JBTableRowRenderer.java | 22 ++++ 3 files changed, 102 insertions(+), 38 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/util/ui/table/JBTableRowRenderer.java diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDialogBase.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDialogBase.java index a6b7e42bed02..f06ffa405197 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDialogBase.java +++ b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDialogBase.java @@ -51,6 +51,7 @@ import com.intellij.util.PlatformIcons; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.table.JBListTable; import com.intellij.util.ui.table.JBTableRowEditor; +import com.intellij.util.ui.table.JBTableRowRenderer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -458,37 +459,7 @@ public abstract class ChangeSignatureDialogBase items = myParametersTable.getItems(); - return getRowPresentation(items.get(row), selected, focused); - } - - @Override - protected boolean isRowEmpty(int row) { - final List items = myParametersTable.getItems(); - return isEmptyRow(items.get(row)); - } - - @Override - protected JBTableRowEditor getRowEditor(final int row) { - final List items = myParametersTable.getItems(); - JBTableRowEditor editor = getTableEditor(myParametersList.getTable(), items.get(row)); - LOG.assertTrue(editor != null); - editor.addDocumentListener(new JBTableRowEditor.RowDocumentListener() { - @Override - public void documentChanged(DocumentEvent e, int column) { - if (myParametersTableModel.getColumnClass(column).equals(String.class)) { - myParametersTableModel.setValueAtWithoutUpdate(e.getDocument().getText(), row, column); - } - - updateSignature(); - } - }); - return editor; - } - }; + myParametersList = createParametersListTable(); final JPanel buttonsPanel = ToolbarDecorator.createDecorator(myParametersList.getTable()) .addExtraAction(myPropagateParamChangesButton) .createPanel(); @@ -512,15 +483,56 @@ public abstract class ChangeSignatureDialogBase item) { + JBTableRowEditor editor = ChangeSignatureDialogBase.this.getTableEditor(getTable(), item); + LOG.assertTrue(editor != null); + return editor; + } + + @Override + protected boolean isRowEmpty(int row) { + return ChangeSignatureDialogBase.this.isEmptyRow(getRowItem(row)); + } + }; + } + + /** + * @deprecated override {@link #createParametersListTable} instead. + */ + @Deprecated @Nullable protected JBTableRowEditor getTableEditor(JTable table, ParameterTableModelItemBase item) { return null; } + /** + * @deprecated override {@link #createParametersListTable} instead. + */ + @Deprecated protected boolean isEmptyRow(ParameterTableModelItemBase row) { return false; } + /** + * @deprecated override {@link #createParametersListTable} instead. + */ + @Deprecated @Nullable protected JComponent getRowPresentation(ParameterTableModelItemBase item, boolean selected, boolean focused) { return null; @@ -673,4 +685,35 @@ public abstract class ChangeSignatureDialogBase item); + + @Override + protected abstract boolean isRowEmpty(int row); + + protected ParameterTableModelItem getRowItem(int row) { + return myParametersTable.getItems().get(row); + } + } } diff --git a/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java b/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java index a776e2129942..0ac60e071a61 100644 --- a/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java +++ b/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java @@ -35,7 +35,6 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.event.ChangeEvent; -import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; @@ -48,7 +47,7 @@ import static java.awt.event.KeyEvent.*; /** * @author Konstantin Bulenkov */ -public abstract class JBListTable extends JPanel { +public abstract class JBListTable { protected final JTable myInternalTable; private final JBTable mainTable; private final RowResizeAnimator myRowResizeAnimator; @@ -57,7 +56,6 @@ public abstract class JBListTable extends JPanel { private int myLastFocusedEditorComponentIdx = -1; public JBListTable(@NotNull final JTable t) { - super(new BorderLayout()); myInternalTable = t; final JBListTableModel model = new JBListTableModel(t.getModel()) { @Override @@ -122,10 +120,11 @@ public abstract class JBListTable extends JPanel { @Override public TableCellRenderer getCellRenderer(int row, int column) { - return new DefaultTableCellRenderer() { + final JBTableRowRenderer rowRenderer = getRowRenderer(row); + return new TableCellRenderer() { @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean hasFocus, int row, int col) { - return getRowRenderer(t, row, selected, hasFocus); + public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean focused, int row, int col) { + return rowRenderer.getRowRendererComponent(t, row, selected, focused); } }; } @@ -269,7 +268,7 @@ public abstract class JBListTable extends JPanel { return mainTable; } - protected abstract JComponent getRowRenderer(JTable table, int row, boolean selected, boolean focused); + protected abstract JBTableRowRenderer getRowRenderer(int row); protected abstract JBTableRowEditor getRowEditor(int row); diff --git a/platform/platform-impl/src/com/intellij/util/ui/table/JBTableRowRenderer.java b/platform/platform-impl/src/com/intellij/util/ui/table/JBTableRowRenderer.java new file mode 100644 index 000000000000..25630353c298 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/util/ui/table/JBTableRowRenderer.java @@ -0,0 +1,22 @@ +/* + * Copyright 2000-2014 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 com.intellij.util.ui.table; + +import javax.swing.*; + +public interface JBTableRowRenderer { + JComponent getRowRendererComponent(JTable table, int row, boolean selected, boolean focused); +} From 31c058bf22455d5108999ac93df185203c129af3 Mon Sep 17 00:00:00 2001 From: Sergey Savenko Date: Wed, 3 Dec 2014 19:29:30 +0300 Subject: [PATCH 09/33] introduce EditorTextFieldJBTableRowRenderer --- .../EditorTextFieldJBTableRowRenderer.java | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 platform/platform-impl/src/com/intellij/util/ui/table/EditorTextFieldJBTableRowRenderer.java diff --git a/platform/platform-impl/src/com/intellij/util/ui/table/EditorTextFieldJBTableRowRenderer.java b/platform/platform-impl/src/com/intellij/util/ui/table/EditorTextFieldJBTableRowRenderer.java new file mode 100644 index 000000000000..5c64391669ec --- /dev/null +++ b/platform/platform-impl/src/com/intellij/util/ui/table/EditorTextFieldJBTableRowRenderer.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2014 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 com.intellij.util.ui.table; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.project.Project; +import com.intellij.ui.EditorTextFieldCellRenderer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; + +public abstract class EditorTextFieldJBTableRowRenderer extends EditorTextFieldCellRenderer implements JBTableRowRenderer { + protected EditorTextFieldJBTableRowRenderer(@Nullable Project project, @NotNull Disposable parent) { + super(project, parent); + } + + @Override + public final JComponent getRowRendererComponent(JTable table, int row, boolean selected, boolean focused) { + return (JComponent)getTableCellRendererComponent(table, null, selected, focused, row, 0); + } + + @Override + protected final String getText(JTable table, Object value, int row, int column) { + return getText(table, row); + } + + @Override + protected final Color getCellBackground(JTable table, Object value, boolean selected, boolean focused, int row, int column) { + return getRowBackground(table, selected, focused, row); + } + + @Nullable + @Override + protected final TextAttributes getTextAttributes(JTable table, Object value, boolean selected, boolean focused, int row, int col) { + return getTextAttributes(table, row); + } + + protected abstract String getText(JTable table, int row); + + @Nullable + protected TextAttributes getTextAttributes(JTable table, int row) { + return null; + } + + protected Color getRowBackground(JTable table, boolean selected, boolean focused, int row) { + return super.getCellBackground(table, null, selected, focused, row, 0); + } +} From 61f38c0d3857757e4f135a591717debb660c2e85 Mon Sep 17 00:00:00 2001 From: Sergey Savenko Date: Wed, 3 Dec 2014 19:43:02 +0300 Subject: [PATCH 10/33] JavaChangeSignatureDialog: improve rendering performance --- .../JavaChangeSignatureDialog.java | 320 ++++++++++-------- 1 file changed, 171 insertions(+), 149 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java index 80941aabfc9e..724aab3358d0 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java @@ -25,6 +25,7 @@ import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorFontType; import com.intellij.openapi.editor.event.DocumentAdapter; import com.intellij.openapi.editor.event.DocumentEvent; +import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; @@ -56,9 +57,10 @@ import com.intellij.ui.treeStructure.Tree; import com.intellij.util.*; import com.intellij.util.ui.DialogUtil; import com.intellij.util.ui.UIUtil; -import com.intellij.util.ui.table.JBListTable; +import com.intellij.util.ui.table.EditorTextFieldJBTableRowRenderer; import com.intellij.util.ui.table.JBTableRow; import com.intellij.util.ui.table.JBTableRowEditor; +import com.intellij.util.ui.table.JBTableRowRenderer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -72,6 +74,7 @@ import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Set; import static com.intellij.refactoring.changeSignature.ChangeSignatureHandler.REFACTORING_NAME; @@ -220,32 +223,175 @@ public class JavaChangeSignatureDialog extends ChangeSignatureDialogBase row) { - if (!StringUtil.isEmpty(row.parameter.getName())) return false; - if (!StringUtil.isEmpty(row.parameter.getTypeText())) return false; - return true; - } + protected ParametersListTable createParametersListTable() { + return new ParametersListTable() { + private final EditorTextFieldJBTableRowRenderer myRowRenderer = new EditorTextFieldJBTableRowRenderer(getProject(), myDisposable) { + @Override + protected String getText(JTable table, int row) { + ParameterTableModelItemBase item = getRowItem(row); + final String typeText = item.typeCodeFragment.getText(); + final String separator = StringUtil.repeatSymbol(' ', getTypesMaxLength() - typeText.length() + 1); + String text = typeText + separator + item.parameter.getName(); + final String defaultValue = item.defaultValueCodeFragment.getText(); + String tail = ""; + if (StringUtil.isNotEmpty(defaultValue)) { + tail += " default value = " + defaultValue; + } + if (item.parameter.isUseAnySingleVariable()) { + if (StringUtil.isNotEmpty(defaultValue)) { + tail += ";"; + } + tail += " Use any var."; + } + if (!StringUtil.isEmpty(tail)) { + text += " //" + tail; + } + return " " + text; + } - @Override - protected JComponent getRowPresentation(ParameterTableModelItemBase item, boolean selected, final boolean focused) { - final String typeText = item.typeCodeFragment.getText(); - final String separator = StringUtil.repeatSymbol(' ', getTypesMaxLength() - typeText.length() + 1); - String text = typeText + separator + item.parameter.getName(); - final String defaultValue = item.defaultValueCodeFragment.getText(); - String tail = ""; - if (StringUtil.isNotEmpty(defaultValue)) { - tail += " default value = " + defaultValue; - } - if (item.parameter.isUseAnySingleVariable()) { - if (StringUtil.isNotEmpty(defaultValue)) { - tail += ";"; + @Nullable + @Override + protected FileType getFileType() { + return JavaChangeSignatureDialog.this.getFileType(); + } + }; + + @Override + protected JBTableRowRenderer getRowRenderer(int row) { + return myRowRenderer; } - tail += " Use any var."; - } - if (!StringUtil.isEmpty(tail)) { - text += " //" + tail; - } - return JBListTable.createEditorTextFieldPresentation(getProject(), getFileType(), " " + text, selected, focused); + + @NotNull + @Override + protected JBTableRowEditor getRowEditor(final ParameterTableModelItemBase item) { + return new JBTableRowEditor() { + private EditorTextField myTypeEditor; + private EditorTextField myNameEditor; + private EditorTextField myDefaultValueEditor; + private JCheckBox myAnyVar; + + @Override + public void prepareEditor(JTable table, int row) { + setLayout(new BorderLayout()); + final Document document = PsiDocumentManager.getInstance(getProject()).getDocument(item.typeCodeFragment); + myTypeEditor = new EditorTextField(document, getProject(), getFileType()); + myTypeEditor.addDocumentListener(mySignatureUpdater); + myTypeEditor.setPreferredWidth(getTable().getWidth() / 2); + myTypeEditor.addDocumentListener(new RowEditorChangeListener(0)); + add(createLabeledPanel("Type:", myTypeEditor), BorderLayout.WEST); + + myNameEditor = new EditorTextField(item.parameter.getName(), getProject(), getFileType()); + myNameEditor.addDocumentListener(mySignatureUpdater); + myNameEditor.addDocumentListener(new RowEditorChangeListener(1)); + add(createLabeledPanel("Name:", myNameEditor), BorderLayout.CENTER); + new TextFieldCompletionProvider() { + + @Override + protected void addCompletionVariants(@NotNull String text, + int offset, + @NotNull String prefix, + @NotNull CompletionResultSet result) { + final PsiCodeFragment fragment = item.typeCodeFragment; + if (fragment instanceof PsiTypeCodeFragment) { + final PsiType type; + try { + type = ((PsiTypeCodeFragment)fragment).getType(); + } + catch (Exception e) { + return; + } + final SuggestedNameInfo info = JavaCodeStyleManager.getInstance(myProject) + .suggestVariableName(VariableKind.PARAMETER, null, null, type); + + for (String completionVariant : info.names) { + final LookupElementBuilder element = LookupElementBuilder.create(completionVariant); + result.addElement(element.withLookupString(completionVariant.toLowerCase(Locale.ENGLISH))); + } + } + } + }.apply(myNameEditor, item.parameter.getName()); + + if (!item.isEllipsisType() && item.parameter.getOldIndex() == -1) { + final JPanel additionalPanel = new JPanel(new BorderLayout()); + final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(item.defaultValueCodeFragment); + myDefaultValueEditor = new EditorTextField(doc, getProject(), getFileType()); + ((PsiExpressionCodeFragment)item.defaultValueCodeFragment).setExpectedType(getRowType(item)); + myDefaultValueEditor.setPreferredWidth(getTable().getWidth() / 2); + myDefaultValueEditor.addDocumentListener(new RowEditorChangeListener(2)); + additionalPanel.add(createLabeledPanel("Default value:", myDefaultValueEditor), BorderLayout.WEST); + + if (!isGenerateDelegate()) { + myAnyVar = new JCheckBox("&Use Any Var"); + UIUtil.applyStyle(UIUtil.ComponentStyle.SMALL, myAnyVar); + DialogUtil.registerMnemonic(myAnyVar, '&'); + myAnyVar.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + item.parameter.setUseAnySingleVariable(myAnyVar.isSelected()); + } + }); + final JPanel anyVarPanel = new JPanel(new BorderLayout()); + anyVarPanel.add(myAnyVar, BorderLayout.SOUTH); + UIUtil.addInsets(anyVarPanel, new Insets(0,0,8,0)); + additionalPanel.add(anyVarPanel, BorderLayout.CENTER); + //additionalPanel.setPreferredSize(new Dimension(t.getWidth() / 3, -1)); + } + add(additionalPanel, BorderLayout.SOUTH); + } + } + + @Override + public JBTableRow getValue() { + return new JBTableRow() { + @Override + public Object getValueAt(int column) { + switch (column) { + case 0: return item.typeCodeFragment; + case 1: return myNameEditor.getText().trim(); + case 2: return item.defaultValueCodeFragment; + case 3: return myAnyVar != null && myAnyVar.isSelected(); + } + return null; + } + }; + } + + @Override + public JComponent getPreferredFocusedComponent() { + final MouseEvent me = getMouseEvent(); + if (me == null) { + return myTypeEditor.getFocusTarget(); + } + final double x = me.getPoint().getX(); + return x <= getTypesColumnWidth() + ? myTypeEditor.getFocusTarget() + : myDefaultValueEditor == null || x <= getNamesColumnWidth() + ? myNameEditor.getFocusTarget() + : myDefaultValueEditor.getFocusTarget(); + } + + @Override + public JComponent[] getFocusableComponents() { + final List focusable = new ArrayList(); + focusable.add(myTypeEditor.getFocusTarget()); + focusable.add(myNameEditor.getFocusTarget()); + if (myDefaultValueEditor != null) { + focusable.add(myDefaultValueEditor.getFocusTarget()); + } + if (myAnyVar != null) { + focusable.add(myAnyVar); + } + return focusable.toArray(new JComponent[focusable.size()]); + } + }; + } + + @Override + protected boolean isRowEmpty(int row) { + ParameterInfoImpl parameter = getRowItem(row).parameter; + return StringUtil.isEmpty(parameter.getName()) && StringUtil.isEmpty(parameter.getTypeText()); + } + }; } private int getTypesMaxLength() { @@ -281,130 +427,6 @@ public class JavaChangeSignatureDialog extends ChangeSignatureDialogBase item) { - return new JBTableRowEditor() { - private EditorTextField myTypeEditor; - private EditorTextField myNameEditor; - private EditorTextField myDefaultValueEditor; - private JCheckBox myAnyVar; - - @Override - public void prepareEditor(JTable table, int row) { - setLayout(new BorderLayout()); - final Document document = PsiDocumentManager.getInstance(getProject()).getDocument(item.typeCodeFragment); - myTypeEditor = new EditorTextField(document, getProject(), getFileType()); - myTypeEditor.addDocumentListener(mySignatureUpdater); - myTypeEditor.setPreferredWidth(t.getWidth() / 2); - myTypeEditor.addDocumentListener(new RowEditorChangeListener(0)); - add(createLabeledPanel("Type:", myTypeEditor), BorderLayout.WEST); - - myNameEditor = new EditorTextField(item.parameter.getName(), getProject(), getFileType()); - myNameEditor.addDocumentListener(mySignatureUpdater); - myNameEditor.addDocumentListener(new RowEditorChangeListener(1)); - add(createLabeledPanel("Name:", myNameEditor), BorderLayout.CENTER); - new TextFieldCompletionProvider() { - - @Override - protected void addCompletionVariants(@NotNull String text, - int offset, - @NotNull String prefix, - @NotNull CompletionResultSet result) { - final PsiCodeFragment fragment = item.typeCodeFragment; - if (fragment instanceof PsiTypeCodeFragment) { - final PsiType type; - try { - type = ((PsiTypeCodeFragment)fragment).getType(); - } - catch (Exception e) { - return; - } - final SuggestedNameInfo info = JavaCodeStyleManager.getInstance(myProject) - .suggestVariableName(VariableKind.PARAMETER, null, null, type); - - for (String completionVariant : info.names) { - final LookupElementBuilder element = LookupElementBuilder.create(completionVariant); - result.addElement(element.withLookupString(completionVariant.toLowerCase())); - } - } - } - }.apply(myNameEditor, item.parameter.getName()); - - if (!item.isEllipsisType() && item.parameter.getOldIndex() == -1) { - final JPanel additionalPanel = new JPanel(new BorderLayout()); - final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(item.defaultValueCodeFragment); - myDefaultValueEditor = new EditorTextField(doc, getProject(), getFileType()); - ((PsiExpressionCodeFragment)item.defaultValueCodeFragment).setExpectedType(getRowType(item)); - myDefaultValueEditor.setPreferredWidth(t.getWidth() / 2); - myDefaultValueEditor.addDocumentListener(new RowEditorChangeListener(2)); - additionalPanel.add(createLabeledPanel("Default value:", myDefaultValueEditor), BorderLayout.WEST); - - if (!isGenerateDelegate()) { - myAnyVar = new JCheckBox("&Use Any Var"); - UIUtil.applyStyle(UIUtil.ComponentStyle.SMALL, myAnyVar); - DialogUtil.registerMnemonic(myAnyVar, '&'); - myAnyVar.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - item.parameter.setUseAnySingleVariable(myAnyVar.isSelected()); - } - }); - final JPanel anyVarPanel = new JPanel(new BorderLayout()); - anyVarPanel.add(myAnyVar, BorderLayout.SOUTH); - UIUtil.addInsets(anyVarPanel, new Insets(0,0,8,0)); - additionalPanel.add(anyVarPanel, BorderLayout.CENTER); - //additionalPanel.setPreferredSize(new Dimension(t.getWidth() / 3, -1)); - } - add(additionalPanel, BorderLayout.SOUTH); - } - } - - @Override - public JBTableRow getValue() { - return new JBTableRow() { - @Override - public Object getValueAt(int column) { - switch (column) { - case 0: return item.typeCodeFragment; - case 1: return myNameEditor.getText().trim(); - case 2: return item.defaultValueCodeFragment; - case 3: return myAnyVar != null && myAnyVar.isSelected(); - } - return null; - } - }; - } - - @Override - public JComponent getPreferredFocusedComponent() { - final MouseEvent me = getMouseEvent(); - if (me == null) { - return myTypeEditor.getFocusTarget(); - } - final double x = me.getPoint().getX(); - return x <= getTypesColumnWidth() - ? myTypeEditor.getFocusTarget() - : myDefaultValueEditor == null || x <= getNamesColumnWidth() - ? myNameEditor.getFocusTarget() - : myDefaultValueEditor.getFocusTarget(); - } - - @Override - public JComponent[] getFocusableComponents() { - final List focusable = new ArrayList(); - focusable.add(myTypeEditor.getFocusTarget()); - focusable.add(myNameEditor.getFocusTarget()); - if (myDefaultValueEditor != null) { - focusable.add(myDefaultValueEditor.getFocusTarget()); - } - if (myAnyVar != null) { - focusable.add(myAnyVar); - } - return focusable.toArray(new JComponent[focusable.size()]); - } - }; - } - @Nullable private static PsiType getRowType(ParameterTableModelItemBase item) { try { From 8eb19ff2856c75ef7331c7eafcc2341314a6321e Mon Sep 17 00:00:00 2001 From: Sergey Savenko Date: Wed, 3 Dec 2014 21:13:12 +0300 Subject: [PATCH 11/33] RestClientRequestPanel: improve painting performance --- .../intellij/util/ui/table/JBListTable.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java b/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java index 0ac60e071a61..9c341e6e3960 100644 --- a/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java +++ b/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java @@ -15,10 +15,12 @@ */ package com.intellij.util.ui.table; +import com.intellij.openapi.Disposable; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorFontType; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.ui.DottedBorder; import com.intellij.ui.EditorSettingsProvider; @@ -51,12 +53,14 @@ public abstract class JBListTable { protected final JTable myInternalTable; private final JBTable mainTable; private final RowResizeAnimator myRowResizeAnimator; + private final Disposable myOnRemoveDisposable; private MouseEvent myMouseEvent; private MyCellEditor myCellEditor; private int myLastFocusedEditorComponentIdx = -1; public JBListTable(@NotNull final JTable t) { myInternalTable = t; + myOnRemoveDisposable = Disposer.newDisposable(); final JBListTableModel model = new JBListTableModel(t.getModel()) { @Override public JBTableRow getRow(int index) { @@ -245,17 +249,22 @@ public abstract class JBListTable { @Override public void removeNotify() { super.removeNotify(); - myRowResizeAnimator.stopAnimation(); + Disposer.dispose(myOnRemoveDisposable); } }; mainTable.setStriped(true); myRowResizeAnimator = new RowResizeAnimator(mainTable); + Disposer.register(myOnRemoveDisposable, myRowResizeAnimator); } public void stopEditing() { TableUtil.stopEditing(mainTable); } + public Disposable getOnRemoveDisposable() { + return myOnRemoveDisposable; + } + private static void installPaddingAndBordersForEditors(JBTableRowEditor editor) { final List editors = UIUtil.findComponentsOfType(editor, EditorTextField.class); for (EditorTextField textField : editors) { @@ -394,7 +403,7 @@ public abstract class JBListTable { } } - private static class RowResizeAnimator implements ActionListener { + private static class RowResizeAnimator implements ActionListener, Disposable { private static final int ANIMATION_STEP_MILLIS = 15; private static final int RESIZE_AMOUNT_PER_STEP = 5; @@ -416,6 +425,11 @@ public abstract class JBListTable { doAnimationStep(e.getWhen()); } + @Override + public void dispose() { + stopAnimation(); + } + private void startAnimation() { if (!myAnimationTimer.isRunning()) { myAnimationTimer.start(); From 895b26ade9528af490bd7d64c5f463db3d4d1fec Mon Sep 17 00:00:00 2001 From: Sergey Savenko Date: Wed, 3 Dec 2014 21:24:53 +0300 Subject: [PATCH 12/33] JBListTable: prevent a memory leak A memory leak occurring when the following is true: 1) JBListTable object was created but never added 2) It's onRemoveDisposable was not registered as a child of another disposable --- .../src/com/intellij/util/ui/table/JBListTable.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java b/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java index 9c341e6e3960..89cd47453b92 100644 --- a/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java +++ b/platform/platform-impl/src/com/intellij/util/ui/table/JBListTable.java @@ -246,6 +246,12 @@ public abstract class JBListTable { return editor.getTableCellEditorComponent(this, value, isSelected, row, column); } + @Override + public void addNotify() { + super.addNotify(); + Disposer.register(myOnRemoveDisposable, myRowResizeAnimator); + } + @Override public void removeNotify() { super.removeNotify(); @@ -254,7 +260,6 @@ public abstract class JBListTable { }; mainTable.setStriped(true); myRowResizeAnimator = new RowResizeAnimator(mainTable); - Disposer.register(myOnRemoveDisposable, myRowResizeAnimator); } public void stopEditing() { From 63a990847a72faadebde2527dc175c483593d3c2 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Wed, 3 Dec 2014 22:02:09 +0300 Subject: [PATCH 13/33] IDEA-133657 Settings: artefacts on search when page does not fit dialog size --- .../openapi/options/ex/GlassPanel.java | 53 ++++++++----------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/GlassPanel.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/GlassPanel.java index c80a222ffd96..fdfeaaf29afa 100644 --- a/platform/platform-impl/src/com/intellij/openapi/options/ex/GlassPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/options/ex/GlassPanel.java @@ -17,10 +17,9 @@ package com.intellij.openapi.options.ex; import com.intellij.ide.ui.search.SearchUtil; -import com.intellij.openapi.ui.GraphicsConfig; import com.intellij.ui.ColorUtil; +import com.intellij.ui.JBColor; import com.intellij.ui.components.JBTabbedPane; -import com.intellij.util.ui.GraphicsUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.Nullable; @@ -30,7 +29,6 @@ import java.awt.geom.Area; import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; import java.awt.image.Kernel; -import java.util.ArrayList; import java.util.HashSet; import java.util.Set; @@ -60,19 +58,15 @@ public class GlassPanel extends JComponent { public void paintSpotlight(final Graphics g, final JComponent surfaceComponent) { Dimension size = surfaceComponent.getSize(); if (myLightComponents.size() > 0) { - int width = size.width - 1; - int height = size.height - 1; + int stroke = 2; - Rectangle2D screen = new Rectangle2D.Double(0, 0, width, height); final Rectangle visibleRect = myPanel.getVisibleRect(); final Point leftPoint = SwingUtilities.convertPoint(myPanel, new Point(visibleRect.x, visibleRect.y), surfaceComponent); Area innerPanel = new Area(new Rectangle2D.Double(leftPoint.x, leftPoint.y, visibleRect.width, visibleRect.height)); - Area mask = new Area(screen); - ArrayList components = new ArrayList(); + Area mask = new Area(new Rectangle(-stroke, -stroke, 2 * stroke + size.width, 2 * stroke + size.height)); for (JComponent lightComponent : myLightComponents) { final Area area = getComponentArea(surfaceComponent, lightComponent, 1); if (area == null) continue; - components.add(lightComponent); if (lightComponent instanceof JLabel) { final JLabel label = (JLabel)lightComponent; @@ -80,7 +74,6 @@ public class GlassPanel extends JComponent { if (labelFor instanceof JComponent) { final Area labelForArea = getComponentArea(surfaceComponent, (JComponent)labelFor, 1); if (labelForArea != null) { - components.add((JComponent)labelFor); area.add(labelForArea); } } @@ -89,35 +82,28 @@ public class GlassPanel extends JComponent { area.intersect(innerPanel); mask.subtract(area); } + Graphics clip = g.create(0, 0, size.width, size.height); + try { + Graphics2D g2 = (Graphics2D)clip; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE); - Graphics2D g2 = (Graphics2D)g; + Color background = surfaceComponent.getBackground(); + g2.setColor(ColorUtil.toAlpha(background == null ? null : background.darker(), 100)); + g2.fill(mask); - Color shieldColor = new Color(0.0f, 0.0f, 0.0f, 0.20f); - Color boundsColor = Color.gray; - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2.setColor(shieldColor); - g2.fill(mask); - - g2.setColor(ColorUtil.toAlpha(Color.orange, 25)); - GraphicsConfig config = GraphicsUtil.setupAAPainting(g2); - for (int i = 2; i > 0; i--) { - g2.setStroke(new BasicStroke(i)); - Area arrr = new Area(); - for (JComponent component : components) { - Area area = getComponentArea(surfaceComponent, component, i-1); - if (area != null) { - arrr.add(area); - } - } - g2.draw(arrr); + g2.setStroke(new BasicStroke(stroke)); + g2.setColor(ColorUtil.toAlpha(JBColor.ORANGE, 100)); + g2.draw(mask); + } + finally { + clip.dispose(); } - - config.restore(); } } @Nullable - private Area getComponentArea(final JComponent surfaceComponent, final JComponent lightComponent, int offset) { + private static Area getComponentArea(final JComponent surfaceComponent, final JComponent lightComponent, int offset) { if (!lightComponent.isShowing()) return null; final Point panelPoint = SwingUtilities.convertPoint(lightComponent, new Point(0, 0), surfaceComponent); @@ -173,6 +159,9 @@ public class GlassPanel extends JComponent { public void removeSpotlight(final JComponent component){ myLightComponents.remove(component); + if (myLightComponents.isEmpty()) { + setVisible(false); + } } public void clear() { From 47b7aec8f7acd45a03b08bbcd9fa052abcb54c13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20C=C3=A9bron?= Date: Wed, 3 Dec 2014 20:05:08 +0100 Subject: [PATCH 14/33] SuggestionTest -> LightPlatformCodeInsightFixtureTestCase --- .../inspector/SuggestionTest.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/spellchecker/testSrc/com/intellij/spellchecker/inspector/SuggestionTest.java b/spellchecker/testSrc/com/intellij/spellchecker/inspector/SuggestionTest.java index fc4c8971f206..552e3eb22976 100644 --- a/spellchecker/testSrc/com/intellij/spellchecker/inspector/SuggestionTest.java +++ b/spellchecker/testSrc/com/intellij/spellchecker/inspector/SuggestionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -16,38 +16,38 @@ package com.intellij.spellchecker.inspector; import com.intellij.spellchecker.SpellCheckerManager; -import com.intellij.testFramework.fixtures.CodeInsightFixtureTestCase; +import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; import java.util.List; -public class SuggestionTest extends CodeInsightFixtureTestCase { +public class SuggestionTest extends LightPlatformCodeInsightFixtureTestCase { private SpellCheckerManager spManager; - private SpellCheckerManager getManager(){ - if (spManager==null){ + + private SpellCheckerManager getManager() { + if (spManager == null) { spManager = SpellCheckerManager.getInstance(myFixture.getProject()); } - assert spManager!=null; + assert spManager != null; return spManager; } - public void testSuggestions(){ + public void testSuggestions() { List result = getManager().getSuggestions("upgade"); - assertEquals("upgrade",result.get(0)); + assertEquals("upgrade", result.get(0)); } - public void testFirstLetterUppercaseSuggestions(){ + public void testFirstLetterUppercaseSuggestions() { List result = getManager().getSuggestions("Upgade"); - assertEquals("Upgrade",result.get(0)); + assertEquals("Upgrade", result.get(0)); } - public void testCamelCaseSuggestions(){ + public void testCamelCaseSuggestions() { SpellCheckerManager manager = SpellCheckerManager.getInstance(myFixture.getProject()); - assert manager!=null; + assert manager != null; List result = manager.getSuggestions("TestUpgade"); - assertEquals("TestUpgrade",result.get(0)); + assertEquals("TestUpgrade", result.get(0)); } - } From 621eb75cb6111bef16db3dd4b9dad457ef2453e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20C=C3=A9bron?= Date: Wed, 3 Dec 2014 20:14:21 +0100 Subject: [PATCH 15/33] XmlSchemaPrefixTest -> LightCodeInsightFixtureTestCase --- .../src/com/intellij/xml/XmlSchemaPrefixTest.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/xml/tests/src/com/intellij/xml/XmlSchemaPrefixTest.java b/xml/tests/src/com/intellij/xml/XmlSchemaPrefixTest.java index 74aefe81ad47..029d4fdce16f 100644 --- a/xml/tests/src/com/intellij/xml/XmlSchemaPrefixTest.java +++ b/xml/tests/src/com/intellij/xml/XmlSchemaPrefixTest.java @@ -15,14 +15,14 @@ */ package com.intellij.xml; -import com.intellij.testFramework.fixtures.CodeInsightFixtureTestCase; import com.intellij.testFramework.fixtures.CodeInsightTestUtil; +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; import com.intellij.xml.refactoring.SchemaPrefixRenameHandler; /** * @author Konstantin Bulenkov */ -public class XmlSchemaPrefixTest extends CodeInsightFixtureTestCase { +public class XmlSchemaPrefixTest extends LightCodeInsightFixtureTestCase { public void testPrefixUsages() throws Exception { doFindUsages("usages.xml", 16); @@ -49,14 +49,8 @@ public class XmlSchemaPrefixTest extends CodeInsightFixtureTestCase { return "/xml/tests/testData/schemaPrefix"; } - @Override - protected boolean isCommunity() { - return true; - } - protected void doFindUsages(String filename, int usages) { - final int size = myFixture.testFindUsages(filename).size(); - assert size == usages : "Threre should be " + usages + " usages, but found " + size + ". File: " + filename; + assertSize(usages, myFixture.testFindUsages(filename)); } } From 6fb1b58b3f9c33ef48c58022cdc516eb26650c5b Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 3 Dec 2014 19:17:27 +0100 Subject: [PATCH 16/33] detect jdk version by place (IDEA-133801) --- java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java index 2369bf3ccdcb..3c6e04fb1ad2 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java @@ -514,7 +514,8 @@ public final class PsiUtil extends PsiUtilCore { PsiType lastParmType = getParameterType(lastParameter, languageLevel, substitutorForMethod); if (!(lastParmType instanceof PsiArrayType)) return ApplicabilityLevel.NOT_APPLICABLE; lastParmType = ((PsiArrayType)lastParmType).getComponentType(); - if (lastParmType instanceof PsiCapturedWildcardType && !JavaVersionService.getInstance().isAtLeast(lastParameter, JavaSdkVersion.JDK_1_8)) { + if (lastParmType instanceof PsiCapturedWildcardType && + !JavaVersionService.getInstance().isAtLeast(((PsiCapturedWildcardType)lastParmType).getContext(), JavaSdkVersion.JDK_1_8)) { lastParmType = ((PsiCapturedWildcardType)lastParmType).getWildcard(); } for (int i = parms.length - 1; i < args.length; i++) { From b7902c44e740c30e6a69408177b818ce980c0158 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 3 Dec 2014 19:30:52 +0100 Subject: [PATCH 17/33] lambda: do not reassign variable outside lambda body --- .../refactoring/introduceVariable/ReassignVariableUtil.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/ReassignVariableUtil.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/ReassignVariableUtil.java index 28da2a95e3b6..fb356601ae45 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/ReassignVariableUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/ReassignVariableUtil.java @@ -118,7 +118,10 @@ public class ReassignVariableUtil { }; PsiElement scope = declaration; while (scope != null) { - if (scope instanceof PsiFile || scope instanceof PsiMethod || scope instanceof PsiClassInitializer) break; + if (scope instanceof PsiFile || + scope instanceof PsiMethod || + scope instanceof PsiLambdaExpression || + scope instanceof PsiClassInitializer) break; scope = scope.getParent(); } if (scope == null) return proc; From 2eb2847f112e48f3526547e19f56501856e26ec9 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 3 Dec 2014 20:27:46 +0100 Subject: [PATCH 18/33] more debug info on stub-ast mismatch (EA-63154) --- .../src/com/intellij/psi/impl/source/PsiFileImpl.java | 3 +++ .../src/com/intellij/psi/stubs/CoreStubTreeLoader.java | 5 +++++ .../core-impl/src/com/intellij/psi/stubs/StubTreeLoader.java | 2 ++ .../src/com/intellij/psi/stubs/StubTreeLoaderImpl.java | 5 +++++ 4 files changed, 15 insertions(+) diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java index cc0be29ae7e3..d82c91ae3928 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java @@ -324,6 +324,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF VirtualFile file = viewProvider.getVirtualFile(); msg += "; file stamp: " + file.getModificationStamp(); msg += "; file modCount: " + file.getModificationCount(); + msg += "; file length: " + file.getLength(); Document document = FileDocumentManager.getInstance().getCachedDocument(file); if (document != null) { @@ -332,6 +333,8 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF msg += "; doc size: " + document.getTextLength(); msg += "; committed: " + PsiDocumentManager.getInstance(getProject()).isCommitted(document); } + + msg += "\nindexing info: " + StubTreeLoader.getInstance().getIndexingStampDebugInfo(file); throw new AssertionError(msg + "\n------------\n"); } diff --git a/platform/core-impl/src/com/intellij/psi/stubs/CoreStubTreeLoader.java b/platform/core-impl/src/com/intellij/psi/stubs/CoreStubTreeLoader.java index c3c1bfcc3e5d..11bafacf153c 100644 --- a/platform/core-impl/src/com/intellij/psi/stubs/CoreStubTreeLoader.java +++ b/platform/core-impl/src/com/intellij/psi/stubs/CoreStubTreeLoader.java @@ -87,4 +87,9 @@ public class CoreStubTreeLoader extends StubTreeLoader { } return false; } + + @Override + public String getIndexingStampDebugInfo(VirtualFile file) { + return ""; + } } diff --git a/platform/core-impl/src/com/intellij/psi/stubs/StubTreeLoader.java b/platform/core-impl/src/com/intellij/psi/stubs/StubTreeLoader.java index 5a3b921b4a9c..4ca76612854b 100644 --- a/platform/core-impl/src/com/intellij/psi/stubs/StubTreeLoader.java +++ b/platform/core-impl/src/com/intellij/psi/stubs/StubTreeLoader.java @@ -41,4 +41,6 @@ public abstract class StubTreeLoader { public abstract long getStubTreeTimestamp(VirtualFile vFile); public abstract boolean canHaveStub(VirtualFile file); + + public abstract String getIndexingStampDebugInfo(VirtualFile file); } diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubTreeLoaderImpl.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubTreeLoaderImpl.java index eefbba7e512b..e3e4616ee5de 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubTreeLoaderImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubTreeLoaderImpl.java @@ -167,4 +167,9 @@ public class StubTreeLoaderImpl extends StubTreeLoader { public boolean canHaveStub(VirtualFile file) { return StubUpdatingIndex.canHaveStub(file); } + + @Override + public String getIndexingStampDebugInfo(VirtualFile file) { + return StubUpdatingIndex.getIndexingStampInfo(file); + } } From df6c6da9e09df08896796591a58f1e4427ad9585 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 3 Dec 2014 20:36:40 +0100 Subject: [PATCH 19/33] IndexTest: separate assertions --- java/java-tests/testSrc/com/intellij/index/IndexTest.groovy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy b/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy index 64492f94d62a..9f4de6950d72 100644 --- a/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy +++ b/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy @@ -252,7 +252,8 @@ public class IndexTest extends JavaCodeInsightFixtureTestCase { ((VirtualFileSystemEntry)vFile).setModificationStamp(0); // as unchanged file final Document document = FileDocumentManager.getInstance().getDocument(vFile); - assertTrue(document != null && document.getModificationStamp() == 0); + assertTrue(document != null); + assert document.getModificationStamp() == 0; assertNotNull(findClass("Foo")); WriteCommandAction.runWriteCommandAction(getProject(), new Runnable() { From 2414bc34a0b74ba2050492505e2ae6e17ef0d53f Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 3 Dec 2014 20:44:25 +0100 Subject: [PATCH 20/33] EA-62649 - IAE: Disposer.dispose --- .../platform-impl/src/com/intellij/ui/SpeedSearchBase.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java index 6f20a456c4c7..6ee1ded56642 100644 --- a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java +++ b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java @@ -525,8 +525,10 @@ public abstract class SpeedSearchBase extends SpeedSear myPopupLayeredPane.validate(); myPopupLayeredPane.repaint(); myPopupLayeredPane = null; - - Disposer.dispose(myListenerDisposable); + + if (myListenerDisposable != null) { + Disposer.dispose(myListenerDisposable); + } myListenerDisposable = null; } else if (searchPopup != null) { From 576a557376c7a06a4accef5973e7d27ffbd5671f Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Wed, 3 Dec 2014 20:46:49 +0100 Subject: [PATCH 21/33] removing redundant code; make sure the file is not added twice --- .../ant/config/actions/AddAntBuildFile.java | 97 ++++++++----------- 1 file changed, 42 insertions(+), 55 deletions(-) diff --git a/plugins/ant/src/com/intellij/lang/ant/config/actions/AddAntBuildFile.java b/plugins/ant/src/com/intellij/lang/ant/config/actions/AddAntBuildFile.java index 25f82d1e9d68..1e81f9b5c746 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/actions/AddAntBuildFile.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/actions/AddAntBuildFile.java @@ -16,6 +16,7 @@ package com.intellij.lang.ant.config.actions; import com.intellij.lang.ant.AntBundle; +import com.intellij.lang.ant.config.AntBuildFile; import com.intellij.lang.ant.config.AntConfiguration; import com.intellij.lang.ant.config.AntConfigurationBase; import com.intellij.lang.ant.config.AntNoFileException; @@ -30,35 +31,31 @@ import com.intellij.psi.PsiManager; import com.intellij.psi.xml.XmlDocument; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; +import org.jetbrains.annotations.NotNull; import java.util.Arrays; import java.util.HashSet; import java.util.Set; public class AddAntBuildFile extends AnAction { - public void actionPerformed(AnActionEvent event) { + public void actionPerformed(@NotNull AnActionEvent event) { final DataContext dataContext = event.getDataContext(); final Project project = CommonDataKeys.PROJECT.getData(dataContext); if (project == null) { return; } - - final Set files = new HashSet(); - - VirtualFile[] contextFiles = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext); - if (contextFiles != null) { - files.addAll(Arrays.asList(contextFiles)); - } - final VirtualFile singleFile = CommonDataKeys.VIRTUAL_FILE.getData(dataContext); - if (singleFile != null) { - files.add(singleFile); - } - - if (files.isEmpty()) { + final VirtualFile[] contextFiles = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext); + if (contextFiles == null || contextFiles.length == 0) { return; } - final AntConfiguration antConfiguration = AntConfiguration.getInstance(project); + + final Set files = new HashSet(); + files.addAll(Arrays.asList(contextFiles)); + for (AntBuildFile buildFile : antConfiguration.getBuildFiles()) { + files.remove(buildFile.getVirtualFile()); + } + int filesAdded = 0; final StringBuilder errors = new StringBuilder(); @@ -87,51 +84,41 @@ public class AddAntBuildFile extends AnAction { } } - public void update(AnActionEvent e) { + public void update(@NotNull AnActionEvent e) { final DataContext dataContext = e.getDataContext(); final Presentation presentation = e.getPresentation(); final Project project = CommonDataKeys.PROJECT.getData(dataContext); - if (project == null) { - disable(presentation); - return; + if (project != null) { + final VirtualFile[] files = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext); + if (files != null && files.length > 0) { + for (VirtualFile file : files) { + final PsiFile psiFile = PsiManager.getInstance(project).findFile(file); + if (!(psiFile instanceof XmlFile)) { + continue; + } + final XmlFile xmlFile = (XmlFile)psiFile; + final XmlDocument document = xmlFile.getDocument(); + if (document == null) { + continue; + } + final XmlTag rootTag = document.getRootTag(); + if (rootTag == null) { + continue; + } + if (!"project".equals(rootTag.getName())) { + continue; + } + if (AntConfigurationBase.getInstance(project).getAntBuildFile(psiFile) != null) { + continue; + } + // found at least one candidate file + enable(presentation); + return; + } + } } - final VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(dataContext); - if (file == null) { - disable(presentation); - return; - } - - final PsiFile psiFile = PsiManager.getInstance(project).findFile(file); - if (!(psiFile instanceof XmlFile)) { - disable(presentation); - return; - } - - final XmlFile xmlFile = (XmlFile)psiFile; - final XmlDocument document = xmlFile.getDocument(); - if (document == null) { - disable(presentation); - return; - } - - final XmlTag rootTag = document.getRootTag(); - if (rootTag == null) { - disable(presentation); - return; - } - - if (!"project".equals(rootTag.getName())) { - disable(presentation); - return; - } - - if (AntConfigurationBase.getInstance(project).getAntBuildFile(psiFile) != null) { - disable(presentation); - return; - } - - enable(presentation); + disable(presentation); } private static void enable(Presentation presentation) { From f32bb651215353e70924fec6cf68828d7b7e5e0e Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Wed, 3 Dec 2014 20:52:06 +0100 Subject: [PATCH 22/33] do not create empty dependencies list for a CachedValue --- .../com/intellij/lang/ant/config/impl/AntBuildModelImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntBuildModelImpl.java b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntBuildModelImpl.java index 673985667e3f..13ad8455ebd0 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/impl/AntBuildModelImpl.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/impl/AntBuildModelImpl.java @@ -208,6 +208,9 @@ public class AntBuildModelImpl implements AntBuildModelBase { } }.fillTargets(list, model, project, sourceFile); } + if (dependencies.isEmpty()) { + dependencies.add(PsiModificationTracker.MODIFICATION_COUNT); + } return new Pair, Collection>(list, dependencies); } From b91d183ec2b23a9e54da8cf26edffa14c6480e4c Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Wed, 3 Dec 2014 21:37:09 +0100 Subject: [PATCH 23/33] additional disposed check --- .../impl/src/com/intellij/compiler/server/BuildManager.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index 219678ffadbe..a4dc856755bd 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -1304,11 +1304,14 @@ public class BuildManager implements ApplicationComponent{ // this will ensure that we'll be able to obtain VirtualFile for existing roots CompilerUtil.refreshOutputDirectories(rootFiles, false); - final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); final LocalFileSystem lfs = LocalFileSystem.getInstance(); final Set filesToRefresh = new HashSet(); ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { + if (project.isDisposed()) { + return; + } + final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); for (File root : rootFiles) { final VirtualFile rootFile = lfs.findFileByIoFile(root); if (rootFile != null && fileIndex.isInSourceContent(rootFile)) { From f6705e7ba0239402fd78a65d5f9b40cb0a30a6f8 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Wed, 3 Dec 2014 22:00:14 +0100 Subject: [PATCH 24/33] fixing test data: perforce tasks were removed from 1.9 ant distribution --- plugins/ant/tests/data/psi/resolve/PropValueInAttributeB.ant | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ant/tests/data/psi/resolve/PropValueInAttributeB.ant b/plugins/ant/tests/data/psi/resolve/PropValueInAttributeB.ant index 52de75ace212..170c92ef0faf 100644 --- a/plugins/ant/tests/data/psi/resolve/PropValueInAttributeB.ant +++ b/plugins/ant/tests/data/psi/resolve/PropValueInAttributeB.ant @@ -1,5 +1,5 @@ - + From 1150aac4cb2abd28827b6a0ce14db25b2ab3fd65 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 3 Dec 2014 22:28:16 +0100 Subject: [PATCH 25/33] correct place for suite start tracking --- platform/testFramework/src/_FirstInSuiteTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/testFramework/src/_FirstInSuiteTest.java b/platform/testFramework/src/_FirstInSuiteTest.java index e4a49dd490b6..b66fc2af5d82 100644 --- a/platform/testFramework/src/_FirstInSuiteTest.java +++ b/platform/testFramework/src/_FirstInSuiteTest.java @@ -28,6 +28,7 @@ public class _FirstInSuiteTest extends TestCase { public static long suiteStarted = 0L; public void testNothing() throws Exception { + suiteStarted = System.nanoTime(); SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { @@ -48,7 +49,6 @@ public class _FirstInSuiteTest extends TestCase { // performance tests public void testNothingPerformance() throws Exception { - suiteStarted = System.nanoTime(); testNothing(); } } From ceab4677ced94e2f942742b6923684a6288d54f2 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 13 Nov 2014 23:18:54 +0100 Subject: [PATCH 26/33] Cleanup (dead code; l10n; formatting) --- .../platform/LocationNameFieldsBinding.java | 49 +++-- .../platform/NewDirectoryProjectAction.java | 1 + .../platform/NewDirectoryProjectDialog.form | 66 +++--- .../platform/NewDirectoryProjectDialog.java | 203 ++++++------------ .../src/messages/IdeBundle.properties | 6 + 5 files changed, 118 insertions(+), 207 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/platform/LocationNameFieldsBinding.java b/platform/platform-impl/src/com/intellij/platform/LocationNameFieldsBinding.java index 42556dd45175..06222c8a472a 100644 --- a/platform/platform-impl/src/com/intellij/platform/LocationNameFieldsBinding.java +++ b/platform/platform-impl/src/com/intellij/platform/LocationNameFieldsBinding.java @@ -18,7 +18,7 @@ package com.intellij.platform; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.ComponentWithBrowseButton; +import com.intellij.openapi.ui.ComponentWithBrowseButton.BrowseFolderActionListener; import com.intellij.openapi.ui.TextComponentAccessor; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.io.FileUtil; @@ -35,9 +35,9 @@ import javax.swing.text.PlainDocument; import java.io.File; /** - * User: catherine - *

* Logic for updating 2 fields: name for new directory and it's base location + * + * @author catherine */ public class LocationNameFieldsBinding { private boolean myModifyingLocation = false; @@ -46,60 +46,59 @@ public class LocationNameFieldsBinding { private String myBaseDir; private String mySuggestedProjectName; - public LocationNameFieldsBinding(@Nullable Project project, final TextFieldWithBrowseButton locationTextField, - final JTextField nameTextField, String baseDir, final String browseFolderTitle) { - + public LocationNameFieldsBinding(@Nullable Project project, + final TextFieldWithBrowseButton locationField, + final JTextField nameField, + String baseDir, + String title) { myBaseDir = baseDir; File suggestedProjectDirectory = FileUtil.findSequentNonexistentFile(new File(baseDir), "untitled", ""); - locationTextField.setText(suggestedProjectDirectory.toString()); - nameTextField.setDocument(new NameFieldDocument(nameTextField, locationTextField)); + locationField.setText(suggestedProjectDirectory.toString()); + nameField.setDocument(new NameFieldDocument(nameField, locationField)); mySuggestedProjectName = suggestedProjectDirectory.getName(); - nameTextField.setText(mySuggestedProjectName); - nameTextField.selectAll(); + nameField.setText(mySuggestedProjectName); + nameField.selectAll(); FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); - ComponentWithBrowseButton.BrowseFolderActionListener listener = - new ComponentWithBrowseButton.BrowseFolderActionListener(browseFolderTitle, "", locationTextField, - project, - descriptor, - TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT) { + BrowseFolderActionListener listener = + new BrowseFolderActionListener(title, "", locationField, project, descriptor, TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT) { @Override protected void onFileChosen(@NotNull VirtualFile chosenFile) { myBaseDir = chosenFile.getPath(); - if (isProjectNameChanged(nameTextField.getText()) && !nameTextField.getText().equals(chosenFile.getName())) { + if (isProjectNameChanged(nameField.getText()) && !nameField.getText().equals(chosenFile.getName())) { myExternalModify = true; - locationTextField.setText(new File(chosenFile.getPath(), nameTextField.getText()).toString()); + locationField.setText(new File(chosenFile.getPath(), nameField.getText()).toString()); myExternalModify = false; } else { myExternalModify = true; - locationTextField.setText(chosenFile.getPath()); - nameTextField.setText(chosenFile.getName()); + locationField.setText(chosenFile.getPath()); + nameField.setText(chosenFile.getName()); myExternalModify = false; } } }; - locationTextField.addActionListener(listener); - locationTextField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { + locationField.addActionListener(listener); + locationField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { @Override protected void textChanged(DocumentEvent e) { if (myExternalModify) { return; } myModifyingLocation = true; - String path = locationTextField.getText().trim(); + String path = locationField.getText().trim(); if (path.endsWith(File.separator)) { path = path.substring(0, path.length() - File.separator.length()); } int ind = path.lastIndexOf(File.separator); if (ind != -1) { String projectName = path.substring(ind + 1, path.length()); - if (!nameTextField.getText().trim().isEmpty()) { + if (!nameField.getText().trim().isEmpty()) { myBaseDir = path.substring(0, ind); } - if (!projectName.equals(nameTextField.getText())) { + if (!projectName.equals(nameField.getText())) { if (!myModifyingProjectName) { - nameTextField.setText(projectName); + nameField.setText(projectName); } } } diff --git a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectAction.java b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectAction.java index ef4198b5deae..fc50287afd54 100644 --- a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectAction.java +++ b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectAction.java @@ -47,6 +47,7 @@ import java.io.File; public class NewDirectoryProjectAction extends AnAction implements DumbAware { private static final Logger LOG = Logger.getInstance(NewDirectoryProjectAction.class); + @Override public void actionPerformed(@NotNull AnActionEvent e) { Project project = e.getProject(); NewDirectoryProjectDialog dlg = new NewDirectoryProjectDialog(project); diff --git a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.form b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.form index 4b1d4deab6d2..e38949ac3713 100644 --- a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.form +++ b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.form @@ -1,6 +1,6 @@

- + @@ -17,19 +17,6 @@ - - - - - - - - - - - - - @@ -38,45 +25,40 @@ + + + + + + + + - - + - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + - + - - - - + diff --git a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java index 757782851e80..9f7e6eb9ca74 100644 --- a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java +++ b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -15,9 +15,8 @@ */ package com.intellij.platform; -import com.intellij.facet.ui.FacetEditorValidator; -import com.intellij.facet.ui.FacetValidatorsManager; import com.intellij.facet.ui.ValidationResult; +import com.intellij.ide.IdeBundle; import com.intellij.ide.impl.ProjectUtil; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; @@ -31,7 +30,6 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.DocumentEvent; -import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.List; @@ -40,143 +38,93 @@ import java.util.List; * @author yole */ public class NewDirectoryProjectDialog extends DialogWrapper { - private JTextField myProjectNameTextField; - private TextFieldWithBrowseButton myLocationField; - protected JPanel myRootPane; - protected JComboBox myProjectTypeComboBox; - private JPanel myProjectTypePanel; - private JLabel myLocationLabel; - - protected JPanel getPlaceHolder() { - return myPlaceHolder; - } - - private JPanel myPlaceHolder; - private static final Object EMPTY_PROJECT_GENERATOR = new Object(); - private final DirectoryProjectGenerator myGeneratorBeforeSeparator; - protected NewDirectoryProjectDialog(Project project) { + private JPanel myRootPane; + private JTextField myProjectNameTextField; + private JLabel myLocationLabel; + private TextFieldWithBrowseButton myLocationField; + private JComboBox myProjectTypeComboBox; + + @SuppressWarnings("unchecked") + protected NewDirectoryProjectDialog(@Nullable Project project) { super(project, true); - setTitle("Create New Project"); + setTitle(IdeBundle.message("new.dir.project.title")); init(); myLocationLabel.setLabelFor(myLocationField.getChildComponent()); - new LocationNameFieldsBinding(project, myLocationField, myProjectNameTextField, ProjectUtil.getBaseDir(), "Select Location for Project Directory"); + String title = IdeBundle.message("new.dir.project.chooser.title"); + new LocationNameFieldsBinding(project, myLocationField, myProjectNameTextField, ProjectUtil.getBaseDir(), title); - final DirectoryProjectGenerator[] generators = getGenerators(); - if (generators.length == 0) { - myProjectTypePanel.setVisible(false); - myGeneratorBeforeSeparator = null; - } - else { - DefaultComboBoxModel model = new DefaultComboBoxModel(); - model.addElement(getEmptyProjectGenerator()); + DefaultComboBoxModel model = new DefaultComboBoxModel(); + model.addElement(EMPTY_PROJECT_GENERATOR); + + DirectoryProjectGenerator[] generators = Extensions.getExtensions(DirectoryProjectGenerator.EP_NAME); + if (generators.length > 0) { List primaryGenerators = ContainerUtil.newArrayList(); List otherGenerators = ContainerUtil.newArrayList(); for (DirectoryProjectGenerator generator : generators) { - if (generator instanceof HideableProjectGenerator) { - if (((HideableProjectGenerator)generator).isHidden()) { - continue; - } + if (generator instanceof HideableProjectGenerator && ((HideableProjectGenerator)generator).isHidden()) { + continue; } - boolean primary = true; - if (generator instanceof WebProjectGenerator) { - primary = ((WebProjectGenerator) generator).isPrimaryGenerator(); - } - if (primary) { + if (generator instanceof WebProjectGenerator && ((WebProjectGenerator)generator).isPrimaryGenerator()) { primaryGenerators.add(generator); - } else { + } + else { otherGenerators.add(generator); } } - if (!primaryGenerators.isEmpty() && !otherGenerators.isEmpty()) { - myGeneratorBeforeSeparator = primaryGenerators.get(primaryGenerators.size() - 1); - } - else { - myGeneratorBeforeSeparator = null; - } - for (DirectoryProjectGenerator generator : primaryGenerators) { - model.addElement(generator); - } - for (DirectoryProjectGenerator generator : otherGenerators) { - model.addElement(generator); - } - myProjectTypeComboBox.setModel(model); - myProjectTypeComboBox.setRenderer(createProjectTypeListCellRenderer(myProjectTypeComboBox.getRenderer())); + for (DirectoryProjectGenerator generator : primaryGenerators) model.addElement(generator); + for (DirectoryProjectGenerator generator : otherGenerators) model.addElement(generator); } + myProjectTypeComboBox.setModel(model); + myProjectTypeComboBox.setRenderer(createProjectTypeListCellRenderer()); - registerValidators(new FacetValidatorsManager() { - public void registerValidator(FacetEditorValidator validator, JComponent... componentsToWatch) { + myLocationField.getTextField().getDocument().addDocumentListener(new DocumentAdapter() { + @Override + protected void textChanged(DocumentEvent e) { + checkValid(); } - - public void validate() { + }); + myProjectTypeComboBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(@NotNull ActionEvent e) { checkValid(); } }); } @NotNull - private ListCellRenderer createProjectTypeListCellRenderer(@NotNull final ListCellRenderer originalRenderer) { - ListCellRenderer intermediate = myGeneratorBeforeSeparator == null ? originalRenderer : new ListCellRenderer() { - - private final JSeparator mySeparator = new JSeparator(SwingConstants.HORIZONTAL); - private final JPanel myComponentWithSeparator = new JPanel(new BorderLayout(0, 0)); - + private static ListCellRendererWrapper createProjectTypeListCellRenderer() { + return new ListCellRendererWrapper() { @Override - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - Component original = originalRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); - if (index != -1 && value == myGeneratorBeforeSeparator - && value instanceof DirectoryProjectGenerator && original instanceof JLabel) { - myComponentWithSeparator.removeAll(); - - JLabel label = (JLabel) original; - label.setText(((DirectoryProjectGenerator) value).getName()); - myComponentWithSeparator.add(label, BorderLayout.CENTER); - myComponentWithSeparator.add(mySeparator, BorderLayout.SOUTH); - - myComponentWithSeparator.revalidate(); - myComponentWithSeparator.repaint(); - return myComponentWithSeparator; - } - return original; - } - }; - return new ListCellRendererWrapper() { - @Override - public void customize(final JList list, final Object value, final int index, final boolean selected, final boolean cellHasFocus) { - if (value == null) return; + public void customize(JList list, Object value, int index, boolean selected, boolean cellHasFocus) { if (value == EMPTY_PROJECT_GENERATOR) { - setText("Empty project"); + setText(IdeBundle.message("new.dir.project.default.generator")); } - else { + else if (value != null) { setText(((DirectoryProjectGenerator)value).getName()); } } }; } - protected Object getEmptyProjectGenerator() { - return EMPTY_PROJECT_GENERATOR; - } - - protected DirectoryProjectGenerator[] getGenerators() { - return Extensions.getExtensions(DirectoryProjectGenerator.EP_NAME); - } - - protected void checkValid() { + private void checkValid() { String projectName = myProjectNameTextField.getText(); + if (projectName.trim().isEmpty()) { setOKActionEnabled(false); - setErrorText("Project name can't be empty"); + setErrorText(IdeBundle.message("new.dir.project.error.empty")); return; } + if (myLocationField.getText().indexOf('$') >= 0) { setOKActionEnabled(false); - setErrorText("Project directory name must not contain the $ character"); + setErrorText(IdeBundle.message("new.dir.project.error.buck")); return; } + DirectoryProjectGenerator generator = getProjectGenerator(); if (generator != null) { String baseDirPath = myLocationField.getTextField().getText(); @@ -187,58 +135,33 @@ public class NewDirectoryProjectDialog extends DialogWrapper { return; } } + setOKActionEnabled(true); setErrorText(null); } - private void registerValidators(final FacetValidatorsManager validatorsManager) { - validateOnTextChange(validatorsManager, myLocationField.getTextField()); - validateOnSelectionChange(validatorsManager, myProjectTypeComboBox); - } - - private static void validateOnSelectionChange(final FacetValidatorsManager validatorsManager, final JComboBox projectNameTextField) { - projectNameTextField.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - validatorsManager.validate(); - } - }); - } - - private static void validateOnTextChange(final FacetValidatorsManager validatorsManager, final JTextField textField) { - textField.getDocument().addDocumentListener(new DocumentAdapter() { - @Override - protected void textChanged(DocumentEvent e) { - validatorsManager.validate(); - } - }); - } - - protected JComponent createCenterPanel() { - return myRootPane; - } - - public String getNewProjectLocation() { - return myLocationField.getText(); - } - - public String getNewProjectName() { - return myProjectNameTextField.getText(); - } - - @Nullable - public DirectoryProjectGenerator getProjectGenerator() { - final Object selItem = myProjectTypeComboBox.getSelectedItem(); - if (selItem == EMPTY_PROJECT_GENERATOR) return null; - return (DirectoryProjectGenerator)selItem; - } - + @Override public JComponent getPreferredFocusedComponent() { return myProjectNameTextField; } + @Override + protected JComponent createCenterPanel() { + return myRootPane; + } + @Override protected String getHelpId() { return "create_new_project_dialog"; } + + public String getNewProjectLocation() { + return myLocationField.getText(); + } + + @Nullable + public DirectoryProjectGenerator getProjectGenerator() { + Object item = myProjectTypeComboBox.getSelectedItem(); + return item == EMPTY_PROJECT_GENERATOR ? null : (DirectoryProjectGenerator)item; + } } diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index 1e25c84ddf16..53aa439998a3 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -1155,3 +1155,9 @@ presentation.mode.fon.size=Font size\: update.available.group=Update Checker loading.editors=Loading files... + +new.dir.project.title=Create New Project +new.dir.project.chooser.title=Select Location for Project Directory +new.dir.project.default.generator=Empty project +new.dir.project.error.empty=Project name can't be empty +new.dir.project.error.buck=Project directory name must not contain the ''$'' character From 8302b920e1a9e9dde5d54be5fb7e10f544cd445c Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 3 Dec 2014 22:45:09 +0100 Subject: [PATCH 27/33] IDEA-119594 (input sanitizing instead of rejection) --- .../platform/LocationNameFieldsBinding.java | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/platform/LocationNameFieldsBinding.java b/platform/platform-impl/src/com/intellij/platform/LocationNameFieldsBinding.java index 06222c8a472a..f4b719465ddc 100644 --- a/platform/platform-impl/src/com/intellij/platform/LocationNameFieldsBinding.java +++ b/platform/platform-impl/src/com/intellij/platform/LocationNameFieldsBinding.java @@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComponentWithBrowseButton.BrowseFolderActionListener; import com.intellij.openapi.ui.TextComponentAccessor; import com.intellij.openapi.ui.TextFieldWithBrowseButton; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.DocumentAdapter; @@ -111,7 +112,6 @@ public class LocationNameFieldsBinding { return !currentName.equals(mySuggestedProjectName); } - private class NameFieldDocument extends PlainDocument { public NameFieldDocument(final JTextField projectNameTextField, final TextFieldWithBrowseButton locationField) { addDocumentListener(new DocumentAdapter() { @@ -128,14 +128,25 @@ public class LocationNameFieldsBinding { @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { - boolean ok = true; - for (int idx = 0; idx < str.length() && ok; idx++) { - char ch = str.charAt(idx); - ok = ch != File.separatorChar && ch != '\\' && ch != '/' && ch != '|' && ch != ':'; + StringBuilder sb = null; + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + boolean replace = c == '\\' || c == '/' || SystemInfo.isWindows && (c == '|' || c == ':'); + if (replace) { + if (sb == null) { + sb = new StringBuilder(str.length()); + sb.append(str.substring(0, i)); + } + sb.append('_'); + } + else if (sb != null) { + sb.append(c); + } } - if (ok) { - super.insertString(offs, str, a); + if (sb != null) { + str = sb.toString(); } + super.insertString(offs, str, a); } } } From 0aa0260983cbf9c1444665c7f0cdc2378f1c9e5f Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Thu, 4 Dec 2014 11:57:30 +0300 Subject: [PATCH 28/33] Extract base class for CompilingEvaluator to reuse it in Kotlin --- .../ui/impl/watch/CompilingEvaluator.java | 86 ++------------ .../ui/impl/watch/CompilingEvaluatorImpl.java | 109 ++++++++++++++++++ .../ui/impl/watch/EvaluationDescriptor.java | 4 +- 3 files changed, 120 insertions(+), 79 deletions(-) create mode 100644 java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluatorImpl.java diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java index f35dafc1d666..93e1ff136ad1 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java @@ -27,19 +27,12 @@ import com.intellij.debugger.engine.evaluation.expression.Modifier; import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.debugger.jdi.VirtualMachineProxyImpl; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.JavaSdkVersion; import com.intellij.openapi.projectRoots.JdkVersionUtil; -import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.refactoring.extractMethodObject.ExtractLightMethodObjectHandler; -import com.intellij.util.PathsList; import com.sun.jdi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.org.objectweb.asm.ClassReader; @@ -55,9 +48,9 @@ import java.util.*; /** * @author egor */ -public class CompilingEvaluator implements ExpressionEvaluator { - @NotNull private final PsiElement myPsiContext; - @NotNull private final ExtractLightMethodObjectHandler.ExtractedData myData; +public abstract class CompilingEvaluator implements ExpressionEvaluator { + @NotNull protected final PsiElement myPsiContext; + @NotNull protected final ExtractLightMethodObjectHandler.ExtractedData myData; public CompilingEvaluator(@NotNull PsiElement context, @NotNull ExtractLightMethodObjectHandler.ExtractedData data) { myPsiContext = context; @@ -203,25 +196,8 @@ public class CompilingEvaluator implements ExpressionEvaluator { //private static final String GEN_CLASS_FULL_NAME = GEN_CLASS_PACKAGE + '.' + GEN_CLASS_NAME; //private static final String GEN_METHOD_NAME = "invoke"; - private String getClassCode() { - return ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public String compute() { - return myData.getGeneratedInnerClass().getContainingFile().getText(); - } - }); - } - private String getMainClassName() { - return ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public String compute() { - return FileUtil.getNameWithoutExtension(myData.getGeneratedInnerClass().getContainingFile().getName()); - } - }); - } - - private String getGenClassQName() { + protected String getGenClassQName() { return ApplicationManager.getApplication().runReadAction(new Computable() { @Override public String compute() { @@ -250,57 +226,13 @@ public class CompilingEvaluator implements ExpressionEvaluator { ///////////////// Compiler stuff @NotNull - private Collection compile(String target) throws EvaluateException { - if (!SystemInfo.isJavaVersionAtLeast(target)) { - throw new EvaluateException("Unable to compile for target level " + target + ". Need to run IDEA on java version at least " + target + ", currently running on " + SystemInfo.JAVA_RUNTIME_VERSION); - } - JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - MemoryFileManager manager = new MemoryFileManager(compiler); - DiagnosticCollector diagnostic = new DiagnosticCollector(); - Module module = ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public Module compute() { - return ModuleUtilCore.findModuleForPsiElement(myPsiContext); - } - }); - List options = new ArrayList(); - if (module != null) { - options.add("-cp"); - PathsList cp = ModuleRootManager.getInstance(module).orderEntries().compileOnly().recursively().exportedOnly().withoutSdk().getPathsList(); - options.add(cp.getPathsString()); - } - if (!StringUtil.isEmpty(target)) { - options.add("-source"); - options.add(target); - options.add("-target"); - options.add(target); - } - try { - if (!compiler.getTask(null, - manager, - diagnostic, - options, - null, - Collections.singletonList(new SourceFileObject(getMainClassName(), JavaFileObject.Kind.SOURCE, getClassCode())) - ).call()) { - StringBuilder res = new StringBuilder("Compilation failed:\n"); - for (Diagnostic d : diagnostic.getDiagnostics()) { - res.append(d); - } - throw new EvaluateException(res.toString()); - } - } - catch (Exception e) { - throw new EvaluateException(e.getMessage()); - } - return manager.classes; - } + protected abstract Collection compile(String target) throws EvaluateException; private static URI getUri(String name, JavaFileObject.Kind kind) { return URI.create("memo:///" + name.replace('.', '/') + kind.extension); } - private static class SourceFileObject extends SimpleJavaFileObject { + protected static class SourceFileObject extends SimpleJavaFileObject { private final String myContent; SourceFileObject(String name, Kind kind, String content) { @@ -314,7 +246,7 @@ public class CompilingEvaluator implements ExpressionEvaluator { } } - private static class OutputFileObject extends SimpleJavaFileObject { + protected static class OutputFileObject extends SimpleJavaFileObject { private final ByteArrayOutputStream myStream = new ByteArrayOutputStream(); private final String myOrigName; @@ -333,8 +265,8 @@ public class CompilingEvaluator implements ExpressionEvaluator { } } - private static class MemoryFileManager extends ForwardingJavaFileManager { - private final Collection classes = new ArrayList(); + protected static class MemoryFileManager extends ForwardingJavaFileManager { + protected final Collection classes = new ArrayList(); MemoryFileManager(JavaCompiler compiler) { super(compiler.getStandardFileManager(null, null, null)); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluatorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluatorImpl.java new file mode 100644 index 000000000000..e7e2b8d62e5b --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluatorImpl.java @@ -0,0 +1,109 @@ +/* + * Copyright 2000-2014 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 com.intellij.debugger.ui.impl.watch; + +import com.intellij.debugger.engine.evaluation.EvaluateException; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtilCore; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; +import com.intellij.refactoring.extractMethodObject.ExtractLightMethodObjectHandler; +import com.intellij.util.PathsList; +import org.jetbrains.annotations.NotNull; + +import javax.tools.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public class CompilingEvaluatorImpl extends CompilingEvaluator { + + public CompilingEvaluatorImpl(@NotNull PsiElement context, @NotNull ExtractLightMethodObjectHandler.ExtractedData data) { + super(context, data); + } + + @Override + @NotNull + protected Collection compile(String target) throws EvaluateException { + if (!SystemInfo.isJavaVersionAtLeast(target)) { + throw new EvaluateException("Unable to compile for target level " + target + ". Need to run IDEA on java version at least " + target + ", currently running on " + SystemInfo.JAVA_RUNTIME_VERSION); + } + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + MemoryFileManager manager = new MemoryFileManager(compiler); + DiagnosticCollector diagnostic = new DiagnosticCollector(); + Module module = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public Module compute() { + return ModuleUtilCore.findModuleForPsiElement(myPsiContext); + } + }); + List options = new ArrayList(); + if (module != null) { + options.add("-cp"); + PathsList cp = ModuleRootManager.getInstance(module).orderEntries().compileOnly().recursively().exportedOnly().withoutSdk().getPathsList(); + options.add(cp.getPathsString()); + } + if (!StringUtil.isEmpty(target)) { + options.add("-source"); + options.add(target); + options.add("-target"); + options.add(target); + } + try { + if (!compiler.getTask(null, + manager, + diagnostic, + options, + null, + Collections.singletonList(new SourceFileObject(getMainClassName(), JavaFileObject.Kind.SOURCE, getClassCode())) + ).call()) { + StringBuilder res = new StringBuilder("Compilation failed:\n"); + for (Diagnostic d : diagnostic.getDiagnostics()) { + res.append(d); + } + throw new EvaluateException(res.toString()); + } + } + catch (Exception e) { + throw new EvaluateException(e.getMessage()); + } + return manager.classes; + } + + protected String getClassCode() { + return ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public String compute() { + return myData.getGeneratedInnerClass().getContainingFile().getText(); + } + }); + } + + protected String getMainClassName() { + return ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public String compute() { + return FileUtil.getNameWithoutExtension(myData.getGeneratedInnerClass().getContainingFile().getName()); + } + }); + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java index 20708864c104..f26d81292e35 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -101,7 +101,7 @@ public abstract class EvaluationDescriptor extends ValueDescriptorImpl{ ExtractLightMethodObjectHandler.ExtractedData data = ExtractLightMethodObjectHandler.extractLightMethodObject(myProject, psiFile, fragment, CompilingEvaluator.getGeneratedClassName()); if (data != null) { - return new CompilingEvaluator(psiContext, data); + return new CompilingEvaluatorImpl(psiContext, data); } } catch (PrepareFailedException e) { From 1e3844c5cf01e8d7045c14345f5fbd8b2030ea91 Mon Sep 17 00:00:00 2001 From: nik Date: Thu, 4 Dec 2014 12:13:25 +0300 Subject: [PATCH 29/33] add support for frameworks: select first suitable version for implicitly selected frameworks --- .../newProjectWizard/impl/FrameworkSupportModelBase.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/impl/FrameworkSupportModelBase.java b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/impl/FrameworkSupportModelBase.java index 6c281b0def27..89de3dec0b24 100644 --- a/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/impl/FrameworkSupportModelBase.java +++ b/java/idea-ui/src/com/intellij/ide/util/newProjectWizard/impl/FrameworkSupportModelBase.java @@ -109,6 +109,13 @@ public abstract class FrameworkSupportModelBase extends UserDataHolderBase imple node.setChecked(enable); // ensure configurable to be created and registered to disposer node.getConfigurable(); + if (myFrameworkVersions.get(providerId) == null) { + for (FrameworkVersion version : node.getUserObject().getFrameworkType().getVersions()) { + if (version.getAvailabilityCondition().isAvailableFor(this)) { + setSelectedVersion(providerId, version); + } + } + } } } From cab9d9a5e328aa01a2218d66d1a9399f870916f8 Mon Sep 17 00:00:00 2001 From: Nikolay Tropin Date: Thu, 4 Dec 2014 12:25:38 +0300 Subject: [PATCH 30/33] interface should be public --- .../src/com/intellij/debugger/engine/SimpleGetterProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/SimpleGetterProvider.java b/java/debugger/openapi/src/com/intellij/debugger/engine/SimpleGetterProvider.java index b776d91e2174..452d49e7f558 100644 --- a/java/debugger/openapi/src/com/intellij/debugger/engine/SimpleGetterProvider.java +++ b/java/debugger/openapi/src/com/intellij/debugger/engine/SimpleGetterProvider.java @@ -22,7 +22,7 @@ import com.intellij.psi.*; * Nikolay.Tropin * 2014-11-25 */ -interface SimpleGetterProvider { +public interface SimpleGetterProvider { ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.debugger.simpleGetterProvider"); boolean isSimpleGetter(PsiMethod method); From e13047d703d34fce8ccfc653925f46f41a544be0 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 4 Dec 2014 10:51:10 +0100 Subject: [PATCH 31/33] extract method: suggest return type by unique variable defined in extracted code (IDEA-108296) --- .../extractMethod/ControlFlowWrapper.java | 3 ++ .../extractMethod/ExtractMethodDialog.java | 17 ++++++- .../extractMethod/ExtractMethodProcessor.java | 45 +++++++++++++++++-- .../ui/TypeSelectorManagerImpl.java | 2 +- .../MakeVoidMethodReturnVariable.java | 5 +++ .../MakeVoidMethodReturnVariable_after.java | 10 +++++ ...nMethodNoReturnStatementAndAssignment.java | 7 +++ ...dNoReturnStatementAndAssignment_after.java | 11 +++++ .../refactoring/ExtractMethodTest.java | 9 ++++ 9 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 java/java-tests/testData/refactoring/extractMethod/MakeVoidMethodReturnVariable.java create mode 100644 java/java-tests/testData/refactoring/extractMethod/MakeVoidMethodReturnVariable_after.java create mode 100644 java/java-tests/testData/refactoring/extractMethod/MultipleVarsInMethodNoReturnStatementAndAssignment.java create mode 100644 java/java-tests/testData/refactoring/extractMethod/MultipleVarsInMethodNoReturnStatementAndAssignment_after.java diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ControlFlowWrapper.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ControlFlowWrapper.java index a6a7063947ef..062c1457e818 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ControlFlowWrapper.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ControlFlowWrapper.java @@ -28,6 +28,7 @@ import com.intellij.psi.util.PsiUtil; import com.intellij.refactoring.RefactoringBundle; import com.intellij.util.containers.HashSet; import com.intellij.util.containers.IntArrayList; +import org.jetbrains.annotations.NotNull; import java.util.*; @@ -142,10 +143,12 @@ public class ControlFlowWrapper { public static class ExitStatementsNotSameException extends Exception {} + @NotNull public PsiVariable[] getOutputVariables() { return getOutputVariables(myGenerateConditionalExit); } + @NotNull public PsiVariable[] getOutputVariables(boolean collectVariablesAtExitPoints) { PsiVariable[] myOutputVariables = ControlFlowUtil.getOutputVariables(myControlFlow, myFlowStart, myFlowEnd, myExitPoints.toArray()); if (collectVariablesAtExitPoints) { diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java index 70b6536c3cf9..a2d768b7513b 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java @@ -41,6 +41,7 @@ import com.intellij.ui.EditorTextField; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.NonFocusableCheckBox; import com.intellij.ui.SeparatorFactory; +import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.VisibilityUtil; import com.intellij.util.containers.MultiMap; @@ -240,14 +241,28 @@ public class ExtractMethodDialog extends DialogWrapper implements AbstractExtrac return main; } + protected boolean isVoidReturn() { + return false; + } + @Nullable private JPanel createReturnTypePanel() { if (TypeConversionUtil.isPrimitiveWrapper(myReturnType) && myNullness == Nullness.NULLABLE) { return null; } - mySelector = new TypeSelectorManagerImpl(myProject, myReturnType, findOccurrences(), areTypesDirected()).getTypeSelector(); + final TypeSelectorManagerImpl manager = new TypeSelectorManagerImpl(myProject, myReturnType, findOccurrences(), areTypesDirected()) { + @Override + public PsiType[] getTypesForAll(boolean direct) { + final PsiType[] types = super.getTypesForAll(direct); + return !isVoidReturn() ? types : ArrayUtil.prepend(PsiType.VOID, types); + } + }; + mySelector = manager.getTypeSelector(); final JComponent component = mySelector.getComponent(); if (component instanceof JComboBox) { + if (isVoidReturn()) { + mySelector.selectType(PsiType.VOID); + } final JPanel returnTypePanel = new JPanel(new BorderLayout(2, 0)); final JLabel label = new JLabel(RefactoringBundle.message("changeSignature.return.type.prompt")); returnTypePanel.add(label, BorderLayout.NORTH); diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java index 8dae3d6ff389..5c9701ab8621 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java @@ -53,6 +53,8 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.controlFlow.ControlFlowUtil; import com.intellij.psi.impl.source.codeStyle.JavaCodeStyleManagerImpl; +import com.intellij.psi.scope.processor.VariablesProcessor; +import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.PsiElementProcessor; @@ -112,6 +114,7 @@ public class ExtractMethodProcessor implements MatchProvider { protected InputVariables myInputVariables; // input variables protected PsiVariable[] myOutputVariables; // output variables protected PsiVariable myOutputVariable; // the only output variable + private PsiVariable myArtificialOutputVariable; private Collection myExitStatements; private boolean myHasReturnStatement; // there is a return statement @@ -339,6 +342,23 @@ public class ExtractMethodProcessor implements MatchProvider { : null; } + @Nullable + private PsiVariable getArtificialOutputVariable() { + if (myOutputVariables.length == 0) { + final VariablesProcessor processor = new VariablesProcessor(true) { + @Override + protected boolean check(PsiVariable var, ResolveState state) { + return isDeclaredInside(var); + } + }; + PsiScopesUtil.treeWalkUp(processor, myElements[myElements.length - 1], myCodeFragmentMember); + if (processor.size() == 1) { + return processor.getResult(0); + } + } + return null; + } + private boolean areAllExitPointsAreNotNull(PsiType returnStatementType) { if (insertNotNullCheckIfPossible() && myControlFlowWrapper.getOutputVariables(false).length == 0) { boolean isNotNull = returnStatementType != null && returnStatementType != PsiType.VOID; @@ -508,7 +528,9 @@ public class ExtractMethodProcessor implements MatchProvider { final List variables = myInputVariables.getInputVariables(); myVariableDatum = variables.toArray(new VariableData[variables.size()]); myNullness = initNullness(); - return new ExtractMethodDialog(myProject, myTargetClass, myInputVariables, myReturnType, getTypeParameterList(), + myArtificialOutputVariable = PsiType.VOID.equals(myReturnType) ? getArtificialOutputVariable() : null; + final PsiType returnType = myArtificialOutputVariable != null ? myArtificialOutputVariable.getType() : myReturnType; + return new ExtractMethodDialog(myProject, myTargetClass, myInputVariables, returnType, getTypeParameterList(), getThrownExceptions(), isStatic(), isCanBeStatic(), myCanBeChainedConstructor, suggestInitialMethodName(), myRefactoringName, myHelpId, myNullness, myElements) { @@ -526,6 +548,10 @@ public class ExtractMethodProcessor implements MatchProvider { return ExtractMethodProcessor.this.isOutputVariable(var); } + protected boolean isVoidReturn() { + return myArtificialOutputVariable != null; + } + @Override protected void checkMethodConflicts(MultiMap conflicts) { super.checkMethodConflicts(conflicts); @@ -669,6 +695,9 @@ public class ExtractMethodProcessor implements MatchProvider { myInputVariables.setPassFields(true); myStatic = true; } + if (PsiType.VOID.equals(myReturnType)) { + myArtificialOutputVariable = getArtificialOutputVariable(); + } testPrepare(); if (returnType != null) { myReturnType = returnType; @@ -850,9 +879,14 @@ public class ExtractMethodProcessor implements MatchProvider { myMethodCall = (PsiMethodCallExpression)((PsiReturnStatement)statement).getReturnValue().replace(myMethodCall); } else { - PsiStatement statement = myElementFactory.createStatementFromText("x();", null); - statement = (PsiStatement)addToMethodCallLocation(statement); - myMethodCall = (PsiMethodCallExpression)((PsiExpressionStatement)statement).getExpression().replace(myMethodCall); + if (myArtificialOutputVariable != null && myReturnType != PsiType.VOID) { + declareVariableAtMethodCallLocation(myArtificialOutputVariable.getName()); + } + else { + PsiStatement statement = myElementFactory.createStatementFromText("x();", null); + statement = (PsiStatement)addToMethodCallLocation(statement); + myMethodCall = (PsiMethodCallExpression)((PsiExpressionStatement)statement).getExpression().replace(myMethodCall); + } } if (myHasReturnStatement && !myHasReturnStatementOutput && !hasNormalExit()) { PsiStatement statement = myElementFactory.createStatementFromText("return;", null); @@ -1012,6 +1046,9 @@ public class ExtractMethodProcessor implements MatchProvider { } } } + else if (myArtificialOutputVariable != null && !PsiType.VOID.equals(myReturnType)) { + body.add(myElementFactory.createStatementFromText("return " + myArtificialOutputVariable.getName() + ";", null)); + } return exitStatementCopy; } diff --git a/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java b/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java index 6d0f184056df..b43a5e7f240c 100644 --- a/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java +++ b/java/java-impl/src/com/intellij/refactoring/ui/TypeSelectorManagerImpl.java @@ -205,7 +205,7 @@ public class TypeSelectorManagerImpl implements TypeSelectorManager { } } - private PsiType[] getTypesForAll(final boolean areTypesDirected) { + protected PsiType[] getTypesForAll(final boolean areTypesDirected) { final ArrayList expectedTypesFromAll = new ArrayList(); for (PsiExpression occurrence : myOccurrences) { final ExpectedTypeInfo[] expectedTypes = ExpectedTypesProvider.getExpectedTypes(occurrence, false, myOccurrenceClassProvider, isUsedAfter()); diff --git a/java/java-tests/testData/refactoring/extractMethod/MakeVoidMethodReturnVariable.java b/java/java-tests/testData/refactoring/extractMethod/MakeVoidMethodReturnVariable.java new file mode 100644 index 000000000000..894c81cfd965 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/MakeVoidMethodReturnVariable.java @@ -0,0 +1,5 @@ +class X { + void foo() { + int x = 0; + } +} diff --git a/java/java-tests/testData/refactoring/extractMethod/MakeVoidMethodReturnVariable_after.java b/java/java-tests/testData/refactoring/extractMethod/MakeVoidMethodReturnVariable_after.java new file mode 100644 index 000000000000..bd8821fd26b1 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/MakeVoidMethodReturnVariable_after.java @@ -0,0 +1,10 @@ +class X { + void foo() { + int x = newMethod(); + } + + private int newMethod() { + int x = 0; + return x; + } +} diff --git a/java/java-tests/testData/refactoring/extractMethod/MultipleVarsInMethodNoReturnStatementAndAssignment.java b/java/java-tests/testData/refactoring/extractMethod/MultipleVarsInMethodNoReturnStatementAndAssignment.java new file mode 100644 index 000000000000..6f57cbf63da3 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/MultipleVarsInMethodNoReturnStatementAndAssignment.java @@ -0,0 +1,7 @@ +class X { + void foo() { + int x = 0; + int y = 42; + + } +} diff --git a/java/java-tests/testData/refactoring/extractMethod/MultipleVarsInMethodNoReturnStatementAndAssignment_after.java b/java/java-tests/testData/refactoring/extractMethod/MultipleVarsInMethodNoReturnStatementAndAssignment_after.java new file mode 100644 index 000000000000..86dabe6e8d91 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethod/MultipleVarsInMethodNoReturnStatementAndAssignment_after.java @@ -0,0 +1,11 @@ +class X { + void foo() { + newMethod(); + + } + + private int newMethod() { + int x = 0; + int y = 42; + } +} diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java index 33f473437ffe..97d58a12ae6d 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodTest.java @@ -629,6 +629,15 @@ public class ExtractMethodTest extends LightCodeInsightTestCase { doTestReturnTypeChanged(PsiType.getJavaLangObject(getPsiManager(), GlobalSearchScope.allScope(getProject()))); } + public void testMakeVoidMethodReturnVariable() throws Exception { + doTestReturnTypeChanged(PsiType.INT); + } + + public void testMultipleVarsInMethodNoReturnStatementAndAssignment() throws Exception { + //return type should not be suggested but still + doTestReturnTypeChanged(PsiType.INT); + } + public void testPassFieldAsParameterAndMakeStatic() throws Exception { doTestPassFieldsAsParams(); } From 5a37bee62c923484c3dd3c1f6ef7d15f0aeaadc7 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Thu, 4 Dec 2014 13:04:11 +0300 Subject: [PATCH 32/33] IDEA-133866 step into on a line with lambda lead to the constructor of ClassWriter --- resources/src/DebuggerSettings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/resources/src/DebuggerSettings.xml b/resources/src/DebuggerSettings.xml index 0fb05d9e667c..e1371944741b 100644 --- a/resources/src/DebuggerSettings.xml +++ b/resources/src/DebuggerSettings.xml @@ -52,6 +52,10 @@