Merge remote-tracking branch 'origin/master'

This commit is contained in:
peter
2015-01-14 16:06:30 +01:00
39 changed files with 831 additions and 288 deletions
@@ -1173,7 +1173,7 @@ public class GenericsHighlightUtil {
public static HighlightInfo checkEnumMustNotBeLocal(final PsiClass aClass) {
if (!aClass.isEnum()) return null;
PsiElement parent = aClass.getParent();
if (!(parent instanceof PsiClass || parent instanceof PsiFile)) {
if (!(parent instanceof PsiClass || parent instanceof PsiFile || parent instanceof PsiClassLevelDeclarationStatement)) {
String description = JavaErrorMessages.message("local.enum");
TextRange textRange = HighlightNamesUtil.getClassDeclarationTextRange(aClass);
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create();
@@ -20,6 +20,7 @@
*/
package com.intellij.codeInspection.reference;
import com.intellij.codeInsight.ExceptionUtil;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
@@ -30,6 +31,9 @@ import com.intellij.util.VisibilityUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
public class RefJavaUtilImpl extends RefJavaUtil{
@Override
@@ -114,6 +118,29 @@ public class RefJavaUtilImpl extends RefJavaUtil{
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(aClass);
if (interfaceMethod != null) {
refFrom.addReference(refFrom.getRefManager().getReference(interfaceMethod), interfaceMethod, psiFrom, false, true, null);
PsiElement body = null;
PsiElement topElement = null;
if (expression instanceof PsiLambdaExpression) {
body = ((PsiLambdaExpression)expression).getBody();
topElement = expression;
}
else {
final PsiElement resolve = ((PsiMethodReferenceExpression)expression).resolve();
if (resolve instanceof PsiMethod) {
body = ((PsiMethod)resolve).getBody();
topElement = resolve;
}
}
final Collection<PsiClassType> exceptionTypes = body != null ? ExceptionUtil.collectUnhandledExceptions(body, topElement, false)
: Collections.<PsiClassType>emptyList();
RefElement refResolved = refFrom.getRefManager().getReference(interfaceMethod);
if (refResolved instanceof RefMethodImpl) {
for (final PsiClassType exceptionType : exceptionTypes) {
((RefMethodImpl)refResolved).updateThrowsList(exceptionType);
}
}
}
}
}
@@ -18,6 +18,7 @@ package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.generation.*;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.codeInspection.ex.GlobalInspectionContextBase;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.Key;
@@ -30,10 +31,7 @@ import com.intellij.util.VisibilityUtil;
import com.intellij.util.containers.ContainerUtil;
import javax.swing.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.*;
import static com.intellij.patterns.PlatformPatterns.psiElement;
@@ -137,6 +135,17 @@ public class JavaGenerateMemberCompletionContributor {
List<PsiGenerationInfo<PsiMethod>> newInfos = GenerateMembersUtil
.insertMembersAtOffset(context.getFile(), context.getStartOffset(), infos);
if (!newInfos.isEmpty()) {
final List<PsiElement> elements = new ArrayList<PsiElement>();
for (GenerationInfo member : newInfos) {
if (!(member instanceof TemplateGenerationInfo)) {
final PsiMember psiMember = member.getPsiMember();
if (psiMember != null) {
elements.add(psiMember);
}
}
}
GlobalInspectionContextBase.cleanupElements(context.getProject(), null, elements.toArray(new PsiElement[elements.size()]));
newInfos.get(0).positionCaret(context.getEditor(), true);
}
}
@@ -171,8 +171,8 @@ public class AddExceptionToCatchFix extends BaseIntentionAction {
if (element == null) return null;
@SuppressWarnings({"unchecked"})
final PsiElement parent = PsiTreeUtil.getParentOfType(element, PsiTryStatement.class, PsiMethod.class);
if (parent == null || parent instanceof PsiMethod) return null;
final PsiElement parent = PsiTreeUtil.getParentOfType(element, PsiTryStatement.class, PsiMethod.class, PsiFunctionalExpression.class);
if (parent == null || parent instanceof PsiMethod || parent instanceof PsiFunctionalExpression) return null;
final PsiTryStatement statement = (PsiTryStatement) parent;
final PsiCodeBlock tryBlock = statement.getTryBlock();
@@ -63,7 +63,7 @@ public class GeneralizeCatchFix implements IntentionAction {
myTryStatement = (PsiTryStatement)element.getParent();
break;
}
if (element instanceof PsiMethod || (element instanceof PsiClass && !(element instanceof PsiAnonymousClass))) break;
if (element instanceof PsiMethod || element instanceof PsiFunctionalExpression || (element instanceof PsiClass && !(element instanceof PsiAnonymousClass))) break;
element = element.getParent();
}
if (myTryStatement == null) return false;
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -314,6 +314,10 @@ public class UnscrambleDialog extends DialogWrapper {
builder.append(trimSuffix(line)).append("\n");
continue;
}
if (line.startsWith("at breakpoint")) { // possible thread status mixed with "at ..."
builder.append(" ").append(trimSuffix(line));
continue;
}
if (!first && mustHaveNewLineBefore(line)) {
builder.append("\n");
if (line.startsWith("\"")) builder.append("\n"); // Additional line break for thread names
@@ -0,0 +1,25 @@
// "Add 'catch' clause(s)" "true"
import java.io.IOException;
import java.util.function.Supplier;
class C {
static Object get() throws Exception {
return null;
}
void method() {
try {
Supplier<Object> lambda1 = () -> {
try {
return C.get();
} catch (IOException e) {
throw new RuntimeException();
} catch (Exception e) {
e.printStackTrace();
}
};
} catch( Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,16 @@
// "Add 'catch' clause(s)" "false"
import java.util.function.Supplier;
class C {
static Object get() throws Exception {
return null;
}
void method() {
try {
Supplier<Object> lambda1 = () -> C.ge<caret>t();
} catch( Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,23 @@
// "Add 'catch' clause(s)" "true"
import java.io.IOException;
import java.util.function.Supplier;
class C {
static Object get() throws Exception {
return null;
}
void method() {
try {
Supplier<Object> lambda1 = () -> {
try {
return C.ge<caret>t();
} catch (IOException e) {
throw new RuntimeException();
}
};
} catch( Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,16 @@
// "Add 'catch' clause(s)" "false"
import java.util.function.Supplier;
class C {
static Object get() throws Exception {
return null;
}
void method() {
try {
Supplier<Object> lambda1 = C::g<caret>et;
} catch( Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,16 @@
// "Generalize catch for 'java.lang.Exception' to 'java.lang.Exception'" "false"
import java.util.function.Supplier;
class C {
static Object get() throws Exception {
return null;
}
void method() {
try {
Supplier<Object> lambda1 = () -> C.ge<caret>t();
} catch( Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,16 @@
// "Generalize catch for 'java.lang.Exception' to 'java.lang.Exception'" "false"
import java.util.function.Supplier;
class C {
static Object get() throws Exception {
return null;
}
void method() {
try {
Supplier<Object> lambda1 = C::g<caret>et;
} catch( Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>Foo.java</file>
<line>21</line>
<description>ObjectStreamException</description>
</problem>
</problems>
@@ -0,0 +1,23 @@
import java.io.*;
class ExceptionTest {
MyFunction method() {
return () -> {
throw new EOFException();
};
}
MyFunction method1() {
return this::e;
}
private void e() throws FileNotFoundException {
throw new FileNotFoundException();
}
@FunctionalInterface
private interface MyFunction {
void call() throws FileNotFoundException, EOFException, ObjectStreamException;
}
}
@@ -27,6 +27,7 @@ import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiMethod
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
import com.intellij.psi.codeStyle.CommonCodeStyleSettings
import com.siyeh.ig.style.UnqualifiedFieldAccessInspection
public class NormalCompletionTest extends LightFixtureCompletionTestCase {
@Override
@@ -1484,5 +1485,21 @@ class Bar {
myFixture.assertPreferredCompletionItems(0, "xcreateZoo", "xcreateElephant");
}
public void "test code cleanup during completion generation"() {
myFixture.configureByText "a.java", "class Foo {int i; ge<caret>}"
def inspection = new UnqualifiedFieldAccessInspection()
try {
myFixture.enableInspections(inspection)
myFixture.complete(CompletionType.BASIC)
myFixture.checkResult '''class Foo {int i;
public int getI() {
return this.i;
}
}'''
}
finally {
myFixture.disableInspections(inspection)
}
}
}
@@ -1,5 +1,8 @@
package com.intellij.codeInsight.daemon.quickFix;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.testFramework.IdeaTestUtil;
public class AddExceptionToCatchTest extends LightQuickFixParameterizedTestCase {
public void test() throws Exception {
doAllTests();
@@ -9,4 +12,9 @@ public class AddExceptionToCatchTest extends LightQuickFixParameterizedTestCase
protected String getBasePath() {
return "/codeInsight/daemonCodeAnalyzer/quickFix/addCatchBlock";
}
@Override
protected Sdk getProjectJDK() {
return IdeaTestUtil.getMockJdk18();
}
}
@@ -1,5 +1,8 @@
package com.intellij.codeInsight.daemon.quickFix;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.testFramework.IdeaTestUtil;
public class GeneralizeCatchTest extends LightQuickFixParameterizedTestCase {
public void test() throws Exception {
doAllTests();
@@ -9,4 +12,9 @@ public class GeneralizeCatchTest extends LightQuickFixParameterizedTestCase {
protected String getBasePath() {
return "/codeInsight/daemonCodeAnalyzer/quickFix/generalizeCatch";
}
@Override
protected Sdk getProjectJDK() {
return IdeaTestUtil.getMockJdk18();
}
}
@@ -17,6 +17,10 @@ package com.intellij.codeInspection;
import com.intellij.JavaTestUtil;
import com.intellij.codeInspection.unneededThrows.RedundantThrows;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.InspectionTestCase;
public class RedundantThrowTest extends InspectionTestCase {
@@ -60,4 +64,15 @@ public class RedundantThrowTest extends InspectionTestCase {
public void testSelfCall() throws Exception {
doTest();
}
public void testThrownClausesInFunctionalExpressions() throws Exception {
doTest();
}
@Override
protected Sdk getTestProjectSdk() {
Sdk sdk = IdeaTestUtil.getMockJdk17();
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_8);
return sdk;
}
}
@@ -438,7 +438,7 @@ public class GlobalInspectionContextBase extends UserDataHolderBase implements G
};
Application application = ApplicationManager.getApplication();
if (application.isWriteAccessAllowed()) {
if (application.isWriteAccessAllowed() && !application.isUnitTestMode()) {
application.invokeLater(cleanupRunnable);
}
else {
@@ -27,6 +27,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Collections;
@@ -40,6 +41,7 @@ public abstract class ListTableWithButtons<T> extends Observable {
private final List<T> myElements = ContainerUtil.newArrayList();
private final JPanel myPanel;
private final TableView<T> myTableView;
private final CommonActionsPanel myActionsPanel;
private boolean myIsEnabled = true;
protected ListTableWithButtons() {
@@ -55,6 +57,7 @@ public abstract class ListTableWithButtons<T> extends Observable {
final int column = myTableView.getEditingColumn();
final int row = myTableView.getEditingRow();
if (e.getModifiers() == 0 && (e.getKeyCode() == KeyEvent.VK_ENTER || e.getKeyCode() == KeyEvent.VK_TAB)) {
e.consume();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
@@ -69,6 +72,7 @@ public abstract class ListTableWithButtons<T> extends Observable {
nextRow = 0;
}
}
myTableView.scrollRectToVisible(myTableView.getCellRect(nextRow, nextColumn, true));
myTableView.editCellAt(nextRow, nextColumn);
}
});
@@ -79,19 +83,24 @@ public abstract class ListTableWithButtons<T> extends Observable {
}
};
myTableView.setRowHeight(new JTextField().getPreferredSize().height);
myTableView.setIntercellSpacing(new Dimension(0, 0));
myTableView.setStriped(true);
myTableView.getTableViewModel().setSortable(false);
myPanel = ToolbarDecorator.createDecorator(myTableView)
ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myTableView);
myPanel = decorator
.setAddAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
if (!myElements.isEmpty() && isEmpty(myElements.get(myElements.size() - 1))) return;
myTableView.stopEditing();
setModified();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
myElements.add(createElement());
myTableView.getTableViewModel().setItems(myElements);
if (myElements.isEmpty() || !isEmpty(myElements.get(myElements.size() - 1))) {
myElements.add(createElement());
myTableView.getTableViewModel().setItems(myElements);
}
myTableView.scrollRectToVisible(myTableView.getCellRect(myElements.size() - 1, 0, true));
myTableView.getComponent().editCellAt(myElements.size() - 1, 0);
}
@@ -105,6 +114,7 @@ public abstract class ListTableWithButtons<T> extends Observable {
T selected = getSelection();
if (selected != null) {
int selectedIndex = myElements.indexOf(selected);
myTableView.scrollRectToVisible(myTableView.getCellRect(selectedIndex, 0, true));
myElements.remove(selected);
myTableView.getTableViewModel().setItems(myElements);
@@ -133,6 +143,7 @@ public abstract class ListTableWithButtons<T> extends Observable {
}
});
myActionsPanel = decorator.getActionsPanel();
myTableView.getComponent().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
@@ -157,6 +168,10 @@ public abstract class ListTableWithButtons<T> extends Observable {
return myPanel;
}
public CommonActionsPanel getActionsPanel() {
return myActionsPanel;
}
public void setEnabled() {
myTableView.getComponent().setEnabled(true);
myIsEnabled = true;
@@ -450,6 +450,9 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data
else {
nothingToSearchFor();
}
if (mySearchField instanceof JTextArea) {
UIUtil.adjustRows((JTextArea)mySearchField, 2, 6);
}
}
public boolean isRegexp() {
@@ -637,6 +640,9 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data
private void replaceFieldDocumentChanged() {
setMatchesLimit(LivePreviewController.MATCHES_LIMIT);
myFindModel.setStringToReplace(myReplaceField.getText());
if (myReplaceField instanceof JTextArea) {
UIUtil.adjustRows((JTextArea)myReplaceField, 2, 6);
}
}
private boolean canReplaceCurrent() {
@@ -697,12 +703,17 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data
super.paintBorder(g);
paintBorderOfTextField(g);
}
@Override
public Dimension getPreferredSize() {
return super.getPreferredSize();
}
};
((JTextArea)editorTextField).setColumns(25);
((JTextArea)editorTextField).setRows(3);
((JTextArea)editorTextField).setRows(2);
final JScrollPane scrollPane = new JBScrollPane(editorTextField,
ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
myLeftComponent.add(scrollPane, constraint);
componentRef.set(scrollPane);
}
@@ -60,6 +60,7 @@ import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.table.JBTable;
import com.intellij.usageView.UsageInfo;
import com.intellij.usages.*;
import com.intellij.usages.impl.UsagePreviewPanel;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Consumer;
import com.intellij.util.Processor;
@@ -70,14 +71,14 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
@@ -123,7 +124,9 @@ public class FindDialog extends DialogWrapper {
private static boolean myPreviewResultsTabWasSelected;
private static final int RESULTS_PREVIEW_TAB_INDEX = 1;
private Splitter myPreviewSplitter;
private JBTable myResultsPreviewTable;
private UsagePreviewPanel myUsagePreviewPanel;
private TabbedPane myContent;
private volatile ProgressIndicatorBase myResultsPreviewSearchProgress;
@@ -173,6 +176,7 @@ public class FindDialog extends DialogWrapper {
@Override
protected void dispose() {
finishPreviousPreviewSearch();
if (myUsagePreviewPanel != null) Disposer.dispose(myUsagePreviewPanel);
for(Map.Entry<EditorTextField, DocumentAdapter> e: myComboBoxListeners.entrySet()) {
e.getKey().removeDocumentListener(e.getValue());
}
@@ -489,8 +493,29 @@ public class FindDialog extends DialogWrapper {
}
};
table.setShowColumns(false);
table.setShowGrid(false);
new NavigateToSourceListener().installOn(table);
Splitter previewSplitter = new Splitter(true, 0.5f, 0.1f, 0.9f);
myUsagePreviewPanel = new UsagePreviewPanel(myProject, new UsageViewPresentation());
myResultsPreviewTable = table;
myResultsPreviewTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting()) return;
int index = myResultsPreviewTable.getSelectionModel().getLeadSelectionIndex();
if (index != -1) {
UsageInfo usageInfo = ((UsageInfo2UsageAdapter)myResultsPreviewTable.getModel().getValueAt(index, 0)).getUsageInfo();
myUsagePreviewPanel.updateLayout(Collections.singletonList(usageInfo));
}
else {
myUsagePreviewPanel.updateLayout(null);
}
}
});
previewSplitter.setFirstComponent(new JBScrollPane(myResultsPreviewTable));
previewSplitter.setSecondComponent(myUsagePreviewPanel.createComponent());
myPreviewSplitter = previewSplitter;
}
}
else {
@@ -513,10 +538,10 @@ public class FindDialog extends DialogWrapper {
resultsOptionPanel.add(myCbToOpenInNewTab);
}
if (myResultsPreviewTable != null) {
if (myPreviewSplitter != null) {
TabbedPane pane = new TabbedPaneImpl(SwingConstants.TOP);
pane.insertTab("Options", null, optionsPanel, null, 0);
pane.insertTab("Preview", null, new JBScrollPane(myResultsPreviewTable), null, RESULTS_PREVIEW_TAB_INDEX);
pane.insertTab("Preview", null, myPreviewSplitter, null, RESULTS_PREVIEW_TAB_INDEX);
myContent = pane;
if (myPreviewResultsTabWasSelected) myContent.setSelectedIndex(RESULTS_PREVIEW_TAB_INDEX);
@@ -1389,36 +1414,46 @@ public class FindDialog extends DialogWrapper {
}
private static class UsageTableCellRenderer extends JPanel implements TableCellRenderer {
private SimpleColoredComponent myUsageRenderer = new SimpleColoredComponent();
private SimpleColoredComponent myFileAndLineNumber = new SimpleColoredComponent();
private ColoredTableCellRenderer myUsageRenderer = new ColoredTableCellRenderer() {
@Override
protected void customizeCellRenderer(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
if (value instanceof UsageInfo2UsageAdapter) {
TextChunk[] text = ((UsageInfo2UsageAdapter)value).getPresentation().getText();
// skip line number / file info
for (int i = 1; i < text.length; ++i) {
TextChunk textChunk = text[i];
myUsageRenderer.append(textChunk.getText(), textChunk.getSimpleAttributesIgnoreBackground());
}
}
setBorder(null);
}
};
private ColoredTableCellRenderer myFileAndLineNumber = new ColoredTableCellRenderer() {
@Override
protected void customizeCellRenderer(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
if (value instanceof UsageInfo2UsageAdapter) {
TextChunk[] text = ((UsageInfo2UsageAdapter)value).getPresentation().getText();
// line number / file info
append(((UsageInfo2UsageAdapter)value).getFile().getName() + " " + text[0].getText(), SimpleTextAttributes.GRAYED_ITALIC_ATTRIBUTES);
}
setBorder(null);
}
};
UsageTableCellRenderer() {
setLayout(new BorderLayout());
add(myUsageRenderer, BorderLayout.WEST);
add(myFileAndLineNumber, BorderLayout.EAST);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
myUsageRenderer.clear();
myFileAndLineNumber.clear();
setBackground(isSelected && hasFocus ? UIUtil.getTableSelectionBackground() : UIUtil.getTableBackground());
setBackground(UIUtil.getTableBackground(isSelected));
myUsageRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
myFileAndLineNumber.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (value instanceof UsageInfo2UsageAdapter) {
UsageInfo2UsageAdapter usageAdapter = (UsageInfo2UsageAdapter)value;
UsagePresentation presentation = usageAdapter.getPresentation();
TextChunk[] text = presentation.getText();
// put line number / file info at the right
for (int i = 1; i < text.length; ++i) {
TextChunk textChunk = text[i];
SimpleTextAttributes simples = textChunk.getSimpleAttributesIgnoreBackground();
myUsageRenderer.append(textChunk.getText(), simples);
}
myFileAndLineNumber.append(usageAdapter.getFile().getName() + " " + text[0].getText(),
SimpleTextAttributes.GRAYED_ITALIC_ATTRIBUTES);
}
return this;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -158,6 +158,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
private JBList myList;
private JCheckBox myNonProjectCheckBox;
private AnActionEvent myActionEvent;
private Set<AnAction> myDisabledActions = new HashSet<AnAction>();
private Component myContextComponent;
private CalcThread myCalcThread;
private static AtomicBoolean ourShiftIsPressed = new AtomicBoolean(false);
@@ -1040,6 +1041,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
}
};
SearchEverywherePsiRenderer myFileRenderer = new SearchEverywherePsiRenderer(myList);
ListCellRenderer myActionsRenderer = new GotoActionModel.GotoActionListCellRenderer(Function.TO_STRING);
private String myLocationString;
private DefaultPsiElementCellRenderer myPsiRenderer = new DefaultPsiElementCellRenderer() {
@@ -1080,6 +1082,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
} else if (value instanceof PsiElement) {
myFileRenderer.setPatternMatcher(matcher);
cmp = myFileRenderer.getListCellRendererComponent(list, value, index, isSelected, isSelected);
} else if (value instanceof GotoActionModel.ActionWrapper) {
cmp = myActionsRenderer.getListCellRendererComponent(list, new GotoActionModel.MatchedValue(((GotoActionModel.ActionWrapper)value), pattern), index, isSelected, isSelected);
} else {
cmp = super.getListCellRendererComponent(list, value, index, isSelected, isSelected);
final JPanel p = new JPanel(new BorderLayout());
@@ -1464,7 +1468,10 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
result.add(object);
}
} else if (actions && !isToolWindowAction(object) && isActionValue(object)) {
result.add(object);
AnAction action = object instanceof AnAction ? ((AnAction)object) : ((GotoActionModel.ActionWrapper)object).getAction();
if (isEnabled(action)) {
result.add(object);
}
}
return result.size() <= max;
}
@@ -1905,19 +1912,9 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
public void run() {
if (isCanceled()) return;
for (Object element : new ArrayList(elements)) {
if (element instanceof AnAction) {
final AnAction action = (AnAction)element;
final AnActionEvent e = new AnActionEvent(myActionEvent.getInputEvent(),
myActionEvent.getDataContext(),
myActionEvent.getPlace(),
action.getTemplatePresentation(),
myActionEvent.getActionManager(),
myActionEvent.getModifiers());
ActionUtil.performDumbAwareUpdate(action, e, false);
final Presentation presentation = e.getPresentation();
if (!presentation.isEnabled() || !presentation.isVisible() || StringUtil.isEmpty(presentation.getText())) {
if (!isEnabled((AnAction)element)) {
elements.remove(element);
}
if (isCanceled()) return;
@@ -1933,6 +1930,29 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
}
}
protected boolean isEnabled(final AnAction action) {
if (myDisabledActions.contains(action)) return false;
final AnActionEvent e = new AnActionEvent(myActionEvent.getInputEvent(),
myActionEvent.getDataContext(),
myActionEvent.getPlace(),
action.getTemplatePresentation(),
myActionEvent.getActionManager(),
myActionEvent.getModifiers());
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
ActionUtil.performDumbAwareUpdate(action, e, false);
}
});
final Presentation presentation = e.getPresentation();
final boolean enabled = presentation.isEnabled() && presentation.isVisible() && !StringUtil.isEmpty(presentation.getText());
if (!enabled) {
myDisabledActions.add(action);
}
return enabled;
}
private synchronized void checkModelsUpToDate() {
if (myClassModel == null) {
myClassModel = new GotoClassModel2(project);
@@ -2165,6 +2185,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
myEditor = null;
myFileEditor = null;
myStructureModel = null;
myDisabledActions.clear();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -41,6 +41,7 @@ import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.OnOffButton;
import com.intellij.ui.speedSearch.SpeedSearchUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.ui.EmptyIcon;
@@ -144,7 +145,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
@NotNull public final Comparable value;
@NotNull final String pattern;
MatchedValue(@NotNull Comparable value, @NotNull String pattern) {
public MatchedValue(@NotNull Comparable value, @NotNull String pattern) {
this.value = value;
this.pattern = pattern;
}
@@ -208,121 +209,12 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
@Override
public ListCellRenderer getListCellRenderer() {
return new DefaultListCellRenderer() {
return new GotoActionListCellRenderer(new Function<OptionDescription, String>() {
@Override
public Component getListCellRendererComponent(@NotNull final JList list,
final Object matchedValue,
final int index, final boolean isSelected, final boolean cellHasFocus) {
final JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(IdeBorderFactory.createEmptyBorder(2));
panel.setOpaque(true);
Color bg = UIUtil.getListBackground(isSelected);
panel.setBackground(bg);
if (matchedValue instanceof String) { //...
final JBLabel label = new JBLabel((String)matchedValue);
label.setIcon(EMPTY_ICON);
panel.add(label, BorderLayout.WEST);
return panel;
}
Color groupFg = isSelected ? UIUtil.getListSelectionForeground() : UIUtil.getLabelDisabledForeground();
final Object value = ((MatchedValue) matchedValue).value;
String pattern = ((MatchedValue)matchedValue).pattern;
SimpleColoredComponent nameComponent = new SimpleColoredComponent();
nameComponent.setBackground(bg);
panel.add(nameComponent, BorderLayout.CENTER);
if (value instanceof ActionWrapper) {
final ActionWrapper actionWithParentGroup = (ActionWrapper)value;
final AnAction anAction = actionWithParentGroup.getAction();
final Presentation presentation = anAction.getTemplatePresentation();
boolean toggle = anAction instanceof ToggleAction;
String groupName = actionWithParentGroup.getAction() instanceof ApplyIntentionAction ? null : actionWithParentGroup.getGroupName();
final Color fg = defaultActionForeground(isSelected, actionWithParentGroup.getPresentation());
panel.add(createIconLabel(presentation.getIcon()), BorderLayout.WEST);
appendWithColoredMatches(nameComponent, getName(presentation.getText(), groupName, toggle), pattern, fg, isSelected);
final Shortcut shortcut = preferKeyboardShortcut(KeymapManager.getInstance().getActiveKeymap().getShortcuts(getActionId(anAction)));
if (shortcut != null) {
nameComponent.append(" (" + KeymapUtil.getShortcutText(shortcut) + ")", new SimpleTextAttributes(STYLE_PLAIN, groupFg));
}
if (toggle) {
final OnOffButton button = new OnOffButton();
AnActionEvent event = new AnActionEvent(null, ((ActionWrapper)value).myDataContext,
ActionPlaces.UNKNOWN, new Presentation(), ActionManager.getInstance(),
0);
button.setSelected(((ToggleAction)anAction).isSelected(event));
panel.add(button, BorderLayout.EAST);
panel.setBorder(IdeBorderFactory.createEmptyBorder());
}
else {
if (groupName != null) {
final JLabel groupLabel = new JLabel(groupName);
groupLabel.setBackground(bg);
groupLabel.setForeground(groupFg);
panel.add(groupLabel, BorderLayout.EAST);
}
}
}
else if (value instanceof OptionDescription) {
if (!isSelected && !(value instanceof BooleanOptionDescription)) {
Color descriptorBg = UIUtil.isUnderDarcula() ? ColorUtil.brighter(UIUtil.getListBackground(), 1) : LightColors.SLIGHTLY_GRAY;
panel.setBackground(descriptorBg);
nameComponent.setBackground(descriptorBg);
}
String hit = ((OptionDescription)value).getHit();
if (hit == null) {
hit = ((OptionDescription)value).getOption();
}
hit = StringUtil.unescapeXml(hit);
hit = hit.replace(" ", " "); // avoid extra spaces from mnemonics and xml conversion
String fullHit = hit;
hit = StringUtil.first(hit, 45, true);
final Color fg = UIUtil.getListForeground(isSelected);
appendWithColoredMatches(nameComponent, hit.trim(), pattern, fg, isSelected);
panel.add(new JLabel(EMPTY_ICON), BorderLayout.WEST);
panel.setToolTipText(fullHit);
if (value instanceof BooleanOptionDescription) {
final OnOffButton button = new OnOffButton();
button.setSelected(((BooleanOptionDescription)value).isOptionEnabled());
panel.add(button, BorderLayout.EAST);
panel.setBorder(IdeBorderFactory.createEmptyBorder());
}
else {
final JLabel settingsLabel = new JLabel(getGroupName((OptionDescription)value));
settingsLabel.setForeground(groupFg);
settingsLabel.setBackground(bg);
panel.add(settingsLabel, BorderLayout.EAST);
}
}
return panel;
public String fun(OptionDescription description) {
return getGroupName(description);
}
public String getName(String text, String groupName, boolean toggle) {
return toggle && StringUtil.isNotEmpty(groupName)? groupName + ": "+ text : text;
}
private void appendWithColoredMatches(SimpleColoredComponent nameComponent, String name, String pattern, Color fg, boolean selected) {
final SimpleTextAttributes plain = new SimpleTextAttributes(STYLE_PLAIN, fg);
final SimpleTextAttributes highlighted = new SimpleTextAttributes(null, fg, null, STYLE_SEARCH_MATCH);
List<TextRange> fragments = ContainerUtil.newArrayList();
if (selected) {
int matchStart = StringUtil.indexOfIgnoreCase(name, pattern, 0);
if (matchStart >= 0) {
fragments.add(TextRange.from(matchStart, pattern.length()));
}
}
SpeedSearchUtil.appendColoredFragments(nameComponent, name, fragments, plain, highlighted);
}
};
});
}
protected String getActionId(@NotNull final AnAction anAction) {
@@ -721,4 +613,130 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
return myAction.getTemplatePresentation().getText().hashCode();
}
}
public static class GotoActionListCellRenderer extends DefaultListCellRenderer {
private final Function<OptionDescription, String> myGroupNamer;
public GotoActionListCellRenderer(Function<OptionDescription, String> groupNamer) {
myGroupNamer = groupNamer;
}
@Override
public Component getListCellRendererComponent(@NotNull final JList list,
final Object matchedValue,
final int index, final boolean isSelected, final boolean cellHasFocus) {
final JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(IdeBorderFactory.createEmptyBorder(2));
panel.setOpaque(true);
Color bg = UIUtil.getListBackground(isSelected);
panel.setBackground(bg);
if (matchedValue instanceof String) { //...
final JBLabel label = new JBLabel((String)matchedValue);
label.setIcon(EMPTY_ICON);
panel.add(label, BorderLayout.WEST);
return panel;
}
Color groupFg = isSelected ? UIUtil.getListSelectionForeground() : UIUtil.getLabelDisabledForeground();
final Object value = ((MatchedValue) matchedValue).value;
String pattern = ((MatchedValue)matchedValue).pattern;
SimpleColoredComponent nameComponent = new SimpleColoredComponent();
nameComponent.setBackground(bg);
panel.add(nameComponent, BorderLayout.CENTER);
if (value instanceof ActionWrapper) {
final ActionWrapper actionWithParentGroup = (ActionWrapper)value;
final AnAction anAction = actionWithParentGroup.getAction();
final Presentation presentation = anAction.getTemplatePresentation();
boolean toggle = anAction instanceof ToggleAction;
String groupName = actionWithParentGroup.getAction() instanceof ApplyIntentionAction ? null : actionWithParentGroup.getGroupName();
final Color fg = defaultActionForeground(isSelected, actionWithParentGroup.getPresentation());
panel.add(createIconLabel(presentation.getIcon()), BorderLayout.WEST);
appendWithColoredMatches(nameComponent, getName(presentation.getText(), groupName, toggle), pattern, fg, isSelected);
final Shortcut shortcut = preferKeyboardShortcut(KeymapManager.getInstance().getActiveKeymap().getShortcuts(ActionManager.getInstance().getId(anAction)));
if (shortcut != null) {
nameComponent.append(" (" + KeymapUtil.getShortcutText(shortcut) + ")", new SimpleTextAttributes(STYLE_PLAIN, groupFg));
}
if (toggle) {
final OnOffButton button = new OnOffButton();
AnActionEvent event = new AnActionEvent(null, ((ActionWrapper)value).myDataContext,
ActionPlaces.UNKNOWN, new Presentation(), ActionManager.getInstance(),
0);
button.setSelected(((ToggleAction)anAction).isSelected(event));
panel.add(button, BorderLayout.EAST);
panel.setBorder(IdeBorderFactory.createEmptyBorder());
}
else {
if (groupName != null) {
final JLabel groupLabel = new JLabel(groupName);
groupLabel.setBackground(bg);
groupLabel.setForeground(groupFg);
panel.add(groupLabel, BorderLayout.EAST);
}
}
}
else if (value instanceof OptionDescription) {
if (!isSelected && !(value instanceof BooleanOptionDescription)) {
Color descriptorBg = UIUtil.isUnderDarcula() ? ColorUtil.brighter(UIUtil.getListBackground(), 1) : LightColors.SLIGHTLY_GRAY;
panel.setBackground(descriptorBg);
nameComponent.setBackground(descriptorBg);
}
String hit = ((OptionDescription)value).getHit();
if (hit == null) {
hit = ((OptionDescription)value).getOption();
}
hit = StringUtil.unescapeXml(hit);
hit = hit.replace(" ", " "); // avoid extra spaces from mnemonics and xml conversion
String fullHit = hit;
hit = StringUtil.first(hit, 45, true);
final Color fg = UIUtil.getListForeground(isSelected);
appendWithColoredMatches(nameComponent, hit.trim(), pattern, fg, isSelected);
panel.add(new JLabel(EMPTY_ICON), BorderLayout.WEST);
panel.setToolTipText(fullHit);
if (value instanceof BooleanOptionDescription) {
final OnOffButton button = new OnOffButton();
button.setSelected(((BooleanOptionDescription)value).isOptionEnabled());
panel.add(button, BorderLayout.EAST);
panel.setBorder(IdeBorderFactory.createEmptyBorder());
}
else {
final JLabel settingsLabel = new JLabel(myGroupNamer.fun((OptionDescription)value));
settingsLabel.setForeground(groupFg);
settingsLabel.setBackground(bg);
panel.add(settingsLabel, BorderLayout.EAST);
}
}
return panel;
}
public String getName(String text, String groupName, boolean toggle) {
return toggle && StringUtil.isNotEmpty(groupName)? groupName + ": "+ text : text;
}
private static void appendWithColoredMatches(SimpleColoredComponent nameComponent,
String name,
String pattern,
Color fg,
boolean selected) {
final SimpleTextAttributes plain = new SimpleTextAttributes(STYLE_PLAIN, fg);
final SimpleTextAttributes highlighted = new SimpleTextAttributes(null, fg, null, STYLE_SEARCH_MATCH);
List<TextRange> fragments = ContainerUtil.newArrayList();
if (selected) {
int matchStart = StringUtil.indexOfIgnoreCase(name, pattern, 0);
if (matchStart >= 0) {
fragments.add(TextRange.from(matchStart, pattern.length()));
}
}
SpeedSearchUtil.appendColoredFragments(nameComponent, name, fragments, plain, highlighted);
}
}
}
@@ -40,6 +40,8 @@ public interface IdeActions {
@NonNls String ACTION_EDITOR_BACKSPACE = "EditorBackSpace";
@NonNls String ACTION_EDITOR_MOVE_CARET_LEFT_WITH_SELECTION = "EditorLeftWithSelection";
@NonNls String ACTION_EDITOR_MOVE_CARET_RIGHT_WITH_SELECTION = "EditorRightWithSelection";
@NonNls String ACTION_EDITOR_MOVE_CARET_UP_WITH_SELECTION = "EditorUpWithSelection";
@NonNls String ACTION_EDITOR_MOVE_CARET_DOWN_WITH_SELECTION = "EditorDownWithSelection";
@NonNls String ACTION_EDITOR_MOVE_CARET_UP = "EditorUp";
@NonNls String ACTION_EDITOR_MOVE_CARET_LEFT = "EditorLeft";
@NonNls String ACTION_EDITOR_MOVE_CARET_DOWN = "EditorDown";
@@ -117,7 +117,7 @@ public class DarculaRadioButtonUI extends MetalRadioButtonUI {
if (b.isSelected()) {
final boolean enabled = b.isEnabled();
g.setColor(UIManager.getColor(enabled ? "RadioButton.darcula.selectionEnabledShadowColor" : "RadioButton.darcula.selectionDisabledShadowColor"));// ? Gray._30 : Gray._60);
final int yOff = UIUtil.isUnderDarcula() ? 2 : JBUI.scale(1);
final int yOff = 2;
g.fillOval(w/2 - rad/2, h/2 - rad/2 + yOff , rad, rad);
g.setColor(UIManager.getColor(enabled ? "RadioButton.darcula.selectionEnabledColor" : "RadioButton.darcula.selectionDisabledColor")); //Gray._170 : Gray._120);
g.fillOval(w/2 - rad/2, h/2 - rad/2 -1 + yOff, rad, rad);
@@ -248,6 +248,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
myEditor.getCaretModel().doWithCaretMerging(new Runnable() {
@Override
public void run() {
int oldOffset = myOffset;
final int leadSelectionOffset = getLeadSelectionOffset();
final VisualPosition leadSelectionPosition = getLeadSelectionPosition();
EditorSettings editorSettings = myEditor.getSettings();
@@ -370,7 +371,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret {
else {
int selectionStartToUse = leadSelectionOffset;
VisualPosition selectionStartPositionToUse = leadSelectionPosition;
if (isUnknownDirection()) {
if (isUnknownDirection() || oldOffset > getSelectionStart() && oldOffset < getSelectionEnd()) {
if (getOffset() > leadSelectionOffset ^ getSelectionStart() < getSelectionEnd()) {
selectionStartToUse = getSelectionEnd();
selectionStartPositionToUse = getSelectionEndPosition();
@@ -167,4 +167,24 @@ public class EditorActionTest extends AbstractEditorTest {
executeAction(IdeActions.ACTION_EDITOR_DELETE_TO_WORD_END);
checkResultByText("class Foo { String s = \"a\\<caret>b\"; }");
}
public void testUpWithSelectionOnCaretInsideSelection() throws Exception {
initText("blah blah\n" +
"blah <selection>bl<caret>ah</selection>\n" +
"blah blah");
executeAction(IdeActions.ACTION_EDITOR_MOVE_CARET_UP_WITH_SELECTION);
checkResultByText("blah bl<selection><caret>ah\n" +
"blah blah</selection>\n" +
"blah blah");
}
public void testDownWithSelectionOnCaretInsideSelection() throws Exception {
initText("blah blah\n" +
"blah <selection>bl<caret>ah</selection>\n" +
"blah blah");
executeAction(IdeActions.ACTION_EDITOR_MOVE_CARET_DOWN_WITH_SELECTION);
checkResultByText("blah blah\n" +
"blah <selection>blah\n" +
"blah bl<caret></selection>ah");
}
}
@@ -116,6 +116,7 @@ public class ListTableModel<Item> extends TableViewModel<Item> implements Editab
if (rowIndex < myItems.size()) {
myColumnInfos[columnIndex].setValue(getItem(rowIndex), aValue);
}
fireTableCellUpdated(rowIndex, columnIndex);
}
/**
@@ -3215,6 +3215,10 @@ public class UIUtil {
textComponent.getActionMap().put("redoKeystroke", REDO_ACTION);
}
public static void adjustRows(JTextArea area, int minRows, int maxRows) {
area.setRows(Math.max(minRows, Math.min(maxRows, area.getText().split("\n").length)));
}
public static void playSoundFromResource(final String resourceName) {
final Class callerClass = ReflectionUtil.getGrandCallerClass();
if (callerClass == null) return;
@@ -947,12 +947,12 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper {
if (myPatches.isEmpty() || (! myContainBasedChanges)) return;
final List<FilePatchInProgress.PatchChange> changes = getAllChanges();
Collections.sort(changes, myMyChangeComparator);
final List<FilePatchInProgress.PatchChange> selectedChanges = myChangesTreeList.getSelectedChanges();
List<FilePatchInProgress.PatchChange> selectedChanges = myChangesTreeList.getSelectedChanges();
int selectedIdx = 0;
final ArrayList<DiffRequestPresentable> diffRequestPresentables = new ArrayList<DiffRequestPresentable>(changes.size());
if (selectedChanges.isEmpty()) {
selectedChanges.addAll(changes);
selectedChanges = changes;
}
if (! selectedChanges.isEmpty()) {
final FilePatchInProgress.PatchChange c = selectedChanges.get(0);
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Future;
/**
* Use this interface to access information available in the VCS Log.
@@ -55,7 +56,8 @@ public interface VcsLog {
/**
* Selects the commit node defined by the given reference (commit hash, branch or tag).
*/
void jumpToReference(String reference);
@NotNull
Future<Boolean> jumpToReference(String reference);
/**
* Returns the VCS log toolbar component.
@@ -68,5 +70,4 @@ public interface VcsLog {
*/
@NotNull
Collection<VcsLogProvider> getLogProviders();
}
@@ -28,6 +28,7 @@ import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Future;
/**
*
@@ -84,8 +85,9 @@ public class VcsLogImpl implements VcsLog {
return myUi.getDataPack().getRefsModel().getAllRefs();
}
@NotNull
@Override
public void jumpToReference(final String reference) {
public Future<Boolean> jumpToReference(final String reference) {
Collection<VcsRef> references = getAllReferences();
VcsRef ref = ContainerUtil.find(references, new Condition<VcsRef>() {
@Override
@@ -94,10 +96,10 @@ public class VcsLogImpl implements VcsLog {
}
});
if (ref != null) {
myUi.jumpToCommit(ref.getCommitHash());
return myUi.jumpToCommit(ref.getCommitHash());
}
else {
myUi.jumpToCommitByPartOfHash(reference);
return myUi.jumpToCommitByPartOfHash(reference);
}
}
@@ -0,0 +1,125 @@
/*
* Copyright 2000-2015 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.vcs.log.ui;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.JBPopupListener;
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
import com.intellij.ui.components.JBTextField;
import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.util.Collection;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public class FindPopupWithProgress {
private static final Logger LOG = Logger.getInstance(FindPopupWithProgress.class);
@NotNull private final TextFieldWithProgress myTextField;
@NotNull private final Function<String, Future> myFunction;
@NotNull private final JBPopup myPopup;
@Nullable private Future myFuture;
public FindPopupWithProgress(@NotNull final Project project,
@NotNull Collection<String> variants,
@NotNull Function<String, Future> function) {
myFunction = function;
myTextField = new TextFieldWithProgress(project, variants) {
@Override
public void onOk() {
if (myFuture == null) {
final Future future = myFunction.fun(getText().trim());
myFuture = future;
showProgress();
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
try {
future.get();
ok();
}
catch (CancellationException ex) {
cancel();
}
catch (InterruptedException ex) {
cancel();
}
catch (ExecutionException ex) {
LOG.error(ex);
cancel();
}
}
});
}
}
};
myPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(myTextField, myTextField.getPreferableFocusComponent())
.setCancelOnClickOutside(true).setCancelOnWindowDeactivation(true).setCancelKeyEnabled(true).setRequestFocus(true).createPopup();
myPopup.addListener(new JBPopupListener.Adapter() {
@Override
public void onClosed(LightweightWindowEvent event) {
if (!event.isOk()) {
if (myFuture != null) {
myFuture.cancel(false);
myFuture = null;
}
}
}
});
final JBTextField field = new JBTextField(20);
final Dimension size = field.getPreferredSize();
final Insets insets = myTextField.getBorder().getBorderInsets(myTextField);
size.height += 6 + insets.top + insets.bottom;
size.width += 4 + insets.left + insets.right;
myPopup.setSize(size);
}
private void cancel() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
if (myFuture != null) myFuture = null;
myTextField.hideProgress();
myPopup.cancel();
}
});
}
private void ok() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
if (myFuture != null) myFuture = null;
myTextField.hideProgress();
myPopup.closeOk(null);
}
});
}
public void showUnderneathOf(@NotNull Component anchor) {
myPopup.showUnderneathOf(anchor);
}
}
@@ -18,9 +18,6 @@ package com.intellij.vcs.log.ui;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupListener;
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.VcsLog;
@@ -28,6 +25,7 @@ import com.intellij.vcs.log.VcsLogDataKeys;
import com.intellij.vcs.log.VcsRef;
import java.util.Collection;
import java.util.concurrent.Future;
public class GoToRefAction extends DumbAwareAction {
@@ -45,16 +43,12 @@ public class GoToRefAction extends DumbAwareAction {
return ref.getName();
}
});
final PopupWithTextFieldWithAutoCompletion textField = new PopupWithTextFieldWithAutoCompletion(project, refs);
JBPopup popup = textField.createPopup();
popup.addListener(new JBPopupListener.Adapter() {
@Override
public void onClosed(LightweightWindowEvent event) {
if (event.isOk()) {
log.jumpToReference(textField.getText().trim());
}
}
});
FindPopupWithProgress popup = new FindPopupWithProgress(project, refs, new Function<String, Future>() {
@Override
public Future fun(String text) {
return log.jumpToReference(text);
}
});
popup.showUnderneathOf(log.getToolbar());
}
@@ -1,85 +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.vcs.log.ui;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.spellchecker.ui.SpellCheckingEditorCustomization;
import com.intellij.ui.TextFieldWithAutoCompletion;
import com.intellij.ui.components.JBTextField;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.Collection;
public class PopupWithTextFieldWithAutoCompletion extends TextFieldWithAutoCompletion<String> {
@Nullable private JBPopup myPopup;
public PopupWithTextFieldWithAutoCompletion(@NotNull Project project, @NotNull Collection<String> variants) {
super(project, new StringsCompletionProvider(variants, null), false, null);
setBorder(new EmptyBorder(3, 3, 3, 3));
}
public JBPopup createPopup() {
myPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(this, this)
.setCancelOnClickOutside(true)
.setCancelOnWindowDeactivation(true)
.setCancelKeyEnabled(true)
.setRequestFocus(true)
.createPopup();
final JBTextField field = new JBTextField(20);
final Dimension size = field.getPreferredSize();
final Insets insets = getBorder().getBorderInsets(this);
size.height+=6 + insets.top + insets.bottom;
size.width +=4 + insets.left + insets.right;
myPopup.setSize(size);
return myPopup;
}
@Override
protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
if (myPopup != null) {
myPopup.closeOk(e);
}
return true;
}
else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
if (myPopup != null) {
myPopup.cancel(e);
}
return true;
}
return false;
}
@Override
protected EditorEx createEditor() {
// spell check is not needed
EditorEx editor = super.createEditor();
SpellCheckingEditorCustomization.getInstance(false).customize(editor);
return editor;
}
}
@@ -0,0 +1,104 @@
/*
* Copyright 2000-2015 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.vcs.log.ui;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.progress.PerformInBackgroundOption;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.spellchecker.ui.SpellCheckingEditorCustomization;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.TextFieldWithAutoCompletion;
import com.intellij.util.ui.AsyncProcessIcon;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.Collection;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public abstract class TextFieldWithProgress extends JPanel {
@NotNull private final TextFieldWithAutoCompletion<String> myTextField;
@NotNull private final AsyncProcessIcon myProgressIcon;
public TextFieldWithProgress(@NotNull Project project, @NotNull Collection<String> variants) {
super(new BorderLayout());
setBorder(IdeBorderFactory.createEmptyBorder(3));
myProgressIcon = new AsyncProcessIcon("Loading commits");
myTextField =
new TextFieldWithAutoCompletion<String>(project, new TextFieldWithAutoCompletion.StringsCompletionProvider(variants, null), false,
null) {
@Override
public void setBackground(Color bg) {
super.setBackground(bg);
myProgressIcon.setBackground(bg);
}
@Override
protected EditorEx createEditor() {
// spell check is not needed
EditorEx editor = super.createEditor();
SpellCheckingEditorCustomization.getInstance(false).customize(editor);
return editor;
}
@Override
protected boolean processKeyBinding(KeyStroke ks, final KeyEvent e, int condition, boolean pressed) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
onOk();
return true;
}
return false;
}
};
myTextField.setBorder(IdeBorderFactory.createEmptyBorder());
myProgressIcon.setOpaque(true);
myProgressIcon.setBackground(myTextField.getBackground());
add(myTextField, BorderLayout.CENTER);
add(myProgressIcon, BorderLayout.EAST);
hideProgress();
}
public JComponent getPreferableFocusComponent() {
return myTextField;
}
public void showProgress() {
myTextField.setEnabled(false);
myProgressIcon.setVisible(true);
}
public void hideProgress() {
myTextField.setEnabled(true);
myProgressIcon.setVisible(false);
}
public String getText() {
return myTextField.getText();
}
public abstract void onOk();
}
@@ -1,5 +1,6 @@
package com.intellij.vcs.log.ui;
import com.google.common.util.concurrent.SettableFuture;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
@@ -32,6 +33,7 @@ import javax.swing.table.TableModel;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.Future;
public class VcsLogUiImpl implements VcsLogUi, Disposable {
@@ -192,22 +194,28 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable {
return myUiProperties.isShowRootNames();
}
public void jumpToCommit(@NotNull Hash commitHash) {
@NotNull
public Future<Boolean> jumpToCommit(@NotNull Hash commitHash) {
SettableFuture<Boolean> future = SettableFuture.create();
jumpTo(commitHash, new PairFunction<GraphTableModel, Hash, Integer>() {
@Override
public Integer fun(GraphTableModel model, Hash hash) {
return model.getRowOfCommit(hash);
}
});
}, future);
return future;
}
public void jumpToCommitByPartOfHash(@NotNull String commitHash) {
@NotNull
public Future<Boolean> jumpToCommitByPartOfHash(@NotNull String commitHash) {
SettableFuture<Boolean> future = SettableFuture.create();
jumpTo(commitHash, new PairFunction<GraphTableModel, String, Integer>() {
@Override
public Integer fun(GraphTableModel model, String hash) {
return model.getRowOfCommitByPartOfHash(hash);
}
});
}, future);
return future;
}
public void handleAnswer(@Nullable GraphAnswer<Integer> answer, boolean dataCouldChange) {
@@ -235,13 +243,15 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable {
}
}
private <T> void jumpTo(@NotNull final T commitId, @NotNull final PairFunction<GraphTableModel, T, Integer> rowGetter) {
private <T> void jumpTo(@NotNull final T commitId, @NotNull final PairFunction<GraphTableModel, T, Integer> rowGetter, @NotNull final SettableFuture<Boolean> future) {
if (future.isCancelled()) return;
GraphTableModel model = getModel();
if (model == null) {
invokeOnChange(new Runnable() {
@Override
public void run() {
jumpTo(commitId, rowGetter);
jumpTo(commitId, rowGetter, future);
}
});
return;
@@ -250,12 +260,13 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable {
int row = rowGetter.fun(model, commitId);
if (row >= 0) {
myMainFrame.getGraphTable().jumpToRow(row);
future.set(true);
}
else if (model.canRequestMore()) {
model.requestToLoadMore(new Runnable() {
@Override
public void run() {
jumpTo(commitId, rowGetter);
jumpTo(commitId, rowGetter, future);
}
});
}
@@ -263,12 +274,13 @@ public class VcsLogUiImpl implements VcsLogUi, Disposable {
invokeOnChange(new Runnable() {
@Override
public void run() {
jumpTo(commitId, rowGetter);
jumpTo(commitId, rowGetter, future);
}
});
}
else {
commitNotFound(commitId.toString());
future.set(false);
}
}
@@ -2,6 +2,11 @@ package git4idea.history.wholeTree;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.PerformInBackgroundOption;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
@@ -22,7 +27,12 @@ import git4idea.i18n.GitBundle;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public class SelectRevisionInGitLogAction extends DumbAwareAction {
private static final Logger LOG = Logger.getInstance(SelectRevisionInGitLogAction.class);
public SelectRevisionInGitLogAction() {
super(GitBundle.getString("vcs.history.action.gitlog"), GitBundle.getString("vcs.history.action.gitlog"), null);
@@ -30,7 +40,7 @@ public class SelectRevisionInGitLogAction extends DumbAwareAction {
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
Project project = event.getRequiredData(CommonDataKeys.PROJECT);
final Project project = event.getRequiredData(CommonDataKeys.PROJECT);
final VcsRevisionNumber revision = getRevisionNumber(event);
if (revision == null) {
return;
@@ -60,7 +70,7 @@ public class SelectRevisionInGitLogAction extends DumbAwareAction {
Runnable selectCommit = new Runnable() {
@Override
public void run() {
log.jumpToReference(revision.asString());
jumpToRevisionUnderProgress(project, log, revision);
}
};
@@ -128,5 +138,25 @@ public class SelectRevisionInGitLogAction extends DumbAwareAction {
return null;
}
private static void jumpToRevisionUnderProgress(@NotNull Project project, @NotNull VcsLog log, @NotNull VcsRevisionNumber revision) {
final Future<Boolean> future = log.jumpToReference(revision.asString());
if (!future.isDone()) {
ProgressManager.getInstance().run(new Task.Backgroundable(project, "Searching for revision " + revision.asString(), false/*can not cancel*/,
PerformInBackgroundOption.ALWAYS_BACKGROUND) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
try {
future.get();
}
catch (CancellationException ignored) {
}
catch (InterruptedException ignored) {
}
catch (ExecutionException e) {
LOG.error(e);
}
}
});
}
}
}