mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'master' of git.labs.intellij.net:idea/community
This commit is contained in:
@@ -33,6 +33,7 @@ import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import com.intellij.util.CommonProcessors;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -75,13 +76,7 @@ public class ModuleCompileScope extends FileIndexCompileScope {
|
||||
}
|
||||
|
||||
private void buildScopeModulesSet(Module module) {
|
||||
myScopeModules.add(module);
|
||||
final Module[] dependencies = ModuleRootManager.getInstance(module).getDependencies();
|
||||
for (Module dependency : dependencies) {
|
||||
if (!myScopeModules.contains(dependency)) { // may be in case of module circular dependencies
|
||||
buildScopeModulesSet(dependency);
|
||||
}
|
||||
}
|
||||
ModuleRootManager.getInstance(module).orderEntries().recursively().compileOnly().forEachModule(new CommonProcessors.CollectProcessor<Module>(myScopeModules));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -171,7 +171,15 @@ public abstract class BaseCompilerTestCase extends ModuleTestCase {
|
||||
}
|
||||
|
||||
protected CompilationLog make(Module... modules) {
|
||||
return make(getCompilerManager().createModulesCompileScope(modules, false), CompilerFilter.ALL);
|
||||
return make(false, modules);
|
||||
}
|
||||
|
||||
protected CompilationLog makeWithDependencies(Module... modules) {
|
||||
return make(true, modules);
|
||||
}
|
||||
|
||||
private CompilationLog make(boolean includeDependentModules, Module... modules) {
|
||||
return make(getCompilerManager().createModulesCompileScope(modules, includeDependentModules), CompilerFilter.ALL);
|
||||
}
|
||||
|
||||
protected CompilationLog recompile(Module... modules) {
|
||||
|
||||
@@ -25,8 +25,8 @@ import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.platform.ProjectTemplate;
|
||||
import com.intellij.platform.templates.ArchivedProjectTemplate;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.SingleSelectionModel;
|
||||
import com.intellij.ui.CollectionListModel;
|
||||
import com.intellij.ui.IdeBorderFactory;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import com.intellij.ui.popup.list.GroupedItemsListRenderer;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -100,7 +100,6 @@ public class ProjectTemplateList extends JPanel {
|
||||
}
|
||||
};
|
||||
myList.setCellRenderer(renderer);
|
||||
myList.setSelectionModel(new SingleSelectionModel());
|
||||
myList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
@@ -136,7 +135,9 @@ public class ProjectTemplateList extends JPanel {
|
||||
int index = preserveSelection ? myList.getSelectedIndex() : -1;
|
||||
//noinspection unchecked
|
||||
myList.setModel(new CollectionListModel(list));
|
||||
myList.setSelectedIndex(index == -1 ? 0 : index);
|
||||
if (myList.isEnabled()) {
|
||||
myList.setSelectedIndex(index == -1 ? 0 : index);
|
||||
}
|
||||
updateSelection();
|
||||
}
|
||||
|
||||
@@ -149,6 +150,12 @@ public class ProjectTemplateList extends JPanel {
|
||||
public void setEnabled(boolean enabled) {
|
||||
super.setEnabled(enabled);
|
||||
myList.setEnabled(enabled);
|
||||
if (!enabled) {
|
||||
myList.clearSelection();
|
||||
}
|
||||
else {
|
||||
myList.setSelectedIndex(0);
|
||||
}
|
||||
myDescriptionPane.setEnabled(enabled);
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -553,6 +553,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
|
||||
if ((!result.isAccessible() || !result.isStaticsScopeCorrect()) &&
|
||||
!HighlightMethodUtil.isDummyConstructorCall(expression, myResolveHelper, list, referenceExpression) &&
|
||||
// this check is for fake expression from JspMethodCallImpl
|
||||
referenceExpression.getParent() == expression) {
|
||||
try {
|
||||
myHolder.add(HighlightMethodUtil.checkAmbiguousMethodCallArguments(referenceExpression, results, list, resolved, result, expression, myResolveHelper));
|
||||
|
||||
@@ -22,20 +22,20 @@ import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.RangeMarker;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.search.AllClassesSearchExecutor;
|
||||
import com.intellij.psi.impl.source.PostprocessReformattingAspect;
|
||||
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.searches.AllClassesSearch;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.Processor;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -184,18 +184,17 @@ public class AllClassesGetter {
|
||||
@NotNull Project project,
|
||||
@NotNull GlobalSearchScope scope,
|
||||
@NotNull Processor<PsiClass> processor) {
|
||||
AllClassesSearch.search(scope, project, new Condition<String>() {
|
||||
final Set<String> names = new THashSet<String>(10000);
|
||||
AllClassesSearchExecutor.processClassNames(project, scope, new Consumer<String>() {
|
||||
@Override
|
||||
public boolean value(String s) {
|
||||
return prefixMatcher.isStartMatch(s);
|
||||
public void consume(String s) {
|
||||
if (prefixMatcher.prefixMatches(s)) {
|
||||
names.add(s);
|
||||
}
|
||||
}
|
||||
}).forEach(processor);
|
||||
AllClassesSearch.search(scope, project, new Condition<String>() {
|
||||
@Override
|
||||
public boolean value(String s) {
|
||||
return prefixMatcher.prefixMatches(s);
|
||||
}
|
||||
}).forEach(processor);
|
||||
});
|
||||
LinkedHashSet<String> sorted = CompletionUtil.sortMatching(prefixMatcher, names);
|
||||
AllClassesSearchExecutor.processClassesByNames(project, scope, sorted, processor);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -144,10 +144,8 @@ public class PreferByKindWeigher extends LookupElementWeigher {
|
||||
}
|
||||
}
|
||||
|
||||
if (myCompletionType == CompletionType.SMART) {
|
||||
if (object instanceof PsiLocalVariable || object instanceof PsiParameter || object instanceof PsiThisExpression) {
|
||||
return MyResult.localOrParameter;
|
||||
}
|
||||
if (object instanceof PsiLocalVariable || object instanceof PsiParameter || object instanceof PsiThisExpression) {
|
||||
return MyResult.localOrParameter;
|
||||
}
|
||||
|
||||
if (object instanceof String && item.getUserData(JavaCompletionUtil.SUPER_METHOD_PARAMETERS) == Boolean.TRUE) {
|
||||
|
||||
+23
-5
@@ -25,6 +25,7 @@ import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.filters.ElementFilter;
|
||||
import com.intellij.psi.impl.light.LightMethodBuilder;
|
||||
import com.intellij.psi.impl.source.resolve.JavaResolveUtil;
|
||||
import com.intellij.psi.infos.CandidateInfo;
|
||||
import com.intellij.psi.scope.BaseScopeProcessor;
|
||||
@@ -100,14 +101,11 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme
|
||||
if (qualifier instanceof PsiSuperExpression) {
|
||||
final PsiJavaCodeReferenceElement qSuper = ((PsiSuperExpression)qualifier).getQualifier();
|
||||
if (qSuper == null) {
|
||||
myQualifierClass = JavaResolveUtil.getContextClass( myElement);
|
||||
myQualifierClass = JavaResolveUtil.getContextClass(myElement);
|
||||
} else {
|
||||
final PsiElement target = qSuper.resolve();
|
||||
myQualifierClass = target instanceof PsiClass ? (PsiClass)target : null;
|
||||
}
|
||||
if (myQualifierClass != null) {
|
||||
myQualifierType = JavaPsiFacade.getInstance(element.getProject()).getElementFactory().createType(myQualifierClass);
|
||||
}
|
||||
}
|
||||
else if (qualifier != null) {
|
||||
setQualifierType(qualifier.getType());
|
||||
@@ -117,8 +115,13 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme
|
||||
myQualifierClass = (PsiClass)target;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
myQualifierClass = JavaResolveUtil.getContextClass(myElement);
|
||||
}
|
||||
}
|
||||
if (myQualifierClass != null && myQualifierType == null) {
|
||||
myQualifierType = JavaPsiFacade.getElementFactory(element.getProject()).createType(myQualifierClass);
|
||||
}
|
||||
|
||||
if (myOptions.checkInitialized) {
|
||||
myNonInitializedFields.addAll(getNonInitializedFields(element));
|
||||
@@ -219,6 +222,19 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme
|
||||
return true;
|
||||
}
|
||||
|
||||
if (element instanceof PsiMethod) {
|
||||
PsiMethod method = (PsiMethod)element;
|
||||
if (PsiTypesUtil.isGetClass(method) && PsiUtil.isLanguageLevel5OrHigher(myElement)) {
|
||||
PsiType patchedType = PsiTypesUtil.createJavaLangClassType(myElement, myQualifierType, false);
|
||||
if (patchedType != null) {
|
||||
element = new LightMethodBuilder(element.getManager(), method.getName()).
|
||||
addModifier(PsiModifier.PUBLIC).
|
||||
setMethodReturnType(patchedType).
|
||||
setContainingClass(method.getContainingClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (satisfies(element, state) && isAccessible(element)) {
|
||||
CompletionElement element1 = new CompletionElement(element, state.get(PsiSubstitutor.KEY));
|
||||
if (myResultNames.add(element1.getUniqueId())) {
|
||||
@@ -288,7 +304,9 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme
|
||||
if (!(element instanceof PsiMember)) return true;
|
||||
|
||||
PsiMember member = (PsiMember)element;
|
||||
return JavaPsiFacade.getInstance(element.getProject()).getResolveHelper().isAccessible(member, member.getModifierList(), myElement, myQualifierClass, myDeclarationHolder);
|
||||
PsiClass accessObjectClass = member instanceof PsiClass ? null : myQualifierClass;
|
||||
return JavaPsiFacade.getInstance(element.getProject()).getResolveHelper().isAccessible(member, member.getModifierList(), myElement,
|
||||
accessObjectClass, myDeclarationHolder);
|
||||
}
|
||||
|
||||
public void setCompletionElements(@NotNull Object[] elements) {
|
||||
|
||||
+3
-18
@@ -21,34 +21,19 @@ import com.intellij.codeInsight.template.CustomLiveTemplate;
|
||||
import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
|
||||
import com.intellij.codeInsight.template.postfix.templates.PostfixLiveTemplate;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.patterns.ElementPattern;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.patterns.PlatformPatterns;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.impl.source.tree.ElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
|
||||
import static com.intellij.patterns.StandardPatterns.string;
|
||||
|
||||
public class PostfixTemplateCompletionContributor extends CompletionContributor {
|
||||
private static final TokenSet SUITABLE_ELEMENTS = TokenSet.orSet(ElementType.KEYWORD_BIT_SET,
|
||||
ElementType.LITERAL_BIT_SET,
|
||||
TokenSet.create(JavaTokenType.IDENTIFIER));
|
||||
|
||||
public PostfixTemplateCompletionContributor() {
|
||||
extend(CompletionType.BASIC, identifierAfterDot(), new PostfixTemplatesCompletionProvider());
|
||||
extend(CompletionType.BASIC, PlatformPatterns.psiElement(), new PostfixTemplatesCompletionProvider());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PostfixLiveTemplate getPostfixLiveTemplate(@NotNull PsiFile file, @NotNull Editor editor) {
|
||||
public static PostfixLiveTemplate getPostfixLiveTemplate(@NotNull PsiFile file, @NotNull Editor editor) {
|
||||
PostfixLiveTemplate postfixLiveTemplate = CustomLiveTemplate.EP_NAME.findExtension(PostfixLiveTemplate.class);
|
||||
return postfixLiveTemplate != null && TemplateManagerImpl.isApplicable(postfixLiveTemplate, editor, file) ? postfixLiveTemplate : null;
|
||||
}
|
||||
|
||||
private static ElementPattern<? extends PsiElement> identifierAfterDot() {
|
||||
return psiElement().withElementType(SUITABLE_ELEMENTS).afterLeaf(psiElement().withText(string().contains(".")));
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -42,11 +42,12 @@ class PostfixTemplatesCompletionProvider extends CompletionProvider<CompletionPa
|
||||
PostfixLiveTemplate postfixLiveTemplate = getPostfixLiveTemplate(parameters.getOriginalFile(), parameters.getEditor());
|
||||
if (postfixLiveTemplate != null) {
|
||||
postfixLiveTemplate.addCompletions(parameters, result.withPrefixMatcher(new MyPrefixMatcher(result.getPrefixMatcher().getPrefix())));
|
||||
CharSequence documentContent = parameters.getEditor().getDocument().getCharsSequence();
|
||||
String possibleKey = postfixLiveTemplate.computeTemplateKeyWithoutContextChecking(documentContent, parameters.getOffset());
|
||||
String possibleKey = postfixLiveTemplate
|
||||
.computeTemplateKeyWithoutContextChecking(parameters.getOriginalFile(), parameters.getEditor(), parameters.getOffset());
|
||||
if (possibleKey != null) {
|
||||
result = result.withPrefixMatcher(possibleKey);
|
||||
result.restartCompletionOnPrefixChange(StandardPatterns.string().oneOf(postfixLiveTemplate.getAllTemplateKeys()));
|
||||
result.restartCompletionOnPrefixChange(
|
||||
StandardPatterns.string().oneOf(postfixLiveTemplate.getAllTemplateKeys(parameters.getOriginalFile(), parameters.getOffset())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
-3
@@ -19,7 +19,11 @@ import com.intellij.application.options.editor.EditorOptionsProvider;
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.codeInsight.template.impl.LiveTemplateCompletionContributor;
|
||||
import com.intellij.codeInsight.template.impl.TemplateSettings;
|
||||
import com.intellij.codeInsight.template.postfix.templates.LanguagePostfixTemplate;
|
||||
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplate;
|
||||
import com.intellij.codeInsight.template.postfix.templates.PostfixTemplateProvider;
|
||||
import com.intellij.lang.LanguageExtensionPoint;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.options.Configurable;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.options.SearchableConfigurable;
|
||||
@@ -34,8 +38,9 @@ import javax.swing.*;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class PostfixTemplatesConfigurable implements SearchableConfigurable, EditorOptionsProvider, Configurable.NoScroll {
|
||||
@Nullable
|
||||
@@ -61,7 +66,14 @@ public class PostfixTemplatesConfigurable implements SearchableConfigurable, Edi
|
||||
}
|
||||
|
||||
myTemplatesSettings = settings;
|
||||
List<PostfixTemplate> templates = Arrays.asList(PostfixTemplate.EP_NAME.getExtensions());
|
||||
|
||||
LanguageExtensionPoint[] extensions = new ExtensionPointName<LanguageExtensionPoint>(LanguagePostfixTemplate.EP_NAME).getExtensions();
|
||||
|
||||
List<PostfixTemplate> templates = ContainerUtil.newArrayList();
|
||||
for (LanguageExtensionPoint extension : extensions) {
|
||||
templates.addAll(((PostfixTemplateProvider)extension.getInstance()).getTemplates());
|
||||
}
|
||||
|
||||
ContainerUtil.sort(templates, new Comparator<PostfixTemplate>() {
|
||||
@Override
|
||||
public int compare(PostfixTemplate o1, PostfixTemplate o2) {
|
||||
@@ -184,7 +196,7 @@ public class PostfixTemplatesConfigurable implements SearchableConfigurable, Edi
|
||||
private static String shortcutToString(char shortcut) {
|
||||
if (shortcut == TemplateSettings.SPACE_CHAR) {
|
||||
return SPACE;
|
||||
}
|
||||
}
|
||||
if (shortcut == TemplateSettings.ENTER_CHAR) {
|
||||
return ENTER;
|
||||
}
|
||||
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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.codeInsight.template.postfix.templates;
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionInitializationContext;
|
||||
import com.intellij.codeInsight.completion.JavaCompletionContributor;
|
||||
import com.intellij.codeInsight.template.CustomTemplateCallback;
|
||||
import com.intellij.codeInsight.template.postfix.util.Aliases;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class JavaPostfixTemplateProvider implements PostfixTemplateProvider {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(JavaPostfixTemplateProvider.class);
|
||||
|
||||
private final Map<String, PostfixTemplate> myMapTemplates;
|
||||
|
||||
public JavaPostfixTemplateProvider() {
|
||||
myMapTemplates = ContainerUtil.newHashMap();
|
||||
for (PostfixTemplate template : getInitializeTemplateSet()) {
|
||||
register(template.getKey(), template);
|
||||
Aliases aliases = template.getClass().getAnnotation(Aliases.class);
|
||||
if (aliases != null) {
|
||||
for (String key : aliases.value()) {
|
||||
register(key, template);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected Set<PostfixTemplate> getInitializeTemplateSet() {
|
||||
return ContainerUtil.newHashSet(new AssertStatementPostfixTemplate(),
|
||||
new CastExpressionPostfixTemplate(),
|
||||
new ElseStatementPostfixTemplate(),
|
||||
new ForAscendingPostfixTemplate(),
|
||||
new ForDescendingPostfixTemplate(),
|
||||
new ForeachPostfixTemplate(),
|
||||
new FormatPostfixTemplate(),
|
||||
new IfStatementPostfixTemplate(),
|
||||
new InstanceofExpressionPostfixTemplate(),
|
||||
new IntroduceFieldPostfixTemplate(),
|
||||
new IntroduceVariablePostfixTemplate(),
|
||||
new IsNullCheckPostfixTemplate(),
|
||||
new NotExpressionPostfixTemplate(),
|
||||
new NotNullCheckPostfixTemplate(),
|
||||
new ParenthesizedExpressionPostfixTemplate(),
|
||||
new ReturnStatementPostfixTemplate(),
|
||||
new SoutPostfixTemplate(),
|
||||
new SwitchStatementPostfixTemplate(),
|
||||
new SynchronizedStatementPostfixTemplate(),
|
||||
new ThrowExceptionPostfixTemplate(),
|
||||
new TryStatementPostfixTemplate(),
|
||||
new TryWithResourcesPostfixTemplate(),
|
||||
new WhileStatementPostfixTemplate());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<PostfixTemplate> getTemplates() {
|
||||
return ContainerUtil.newHashSet(myMapTemplates.values());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<String> getKeys() {
|
||||
return myMapTemplates.keySet();
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PostfixTemplate get(@Nullable String key) {
|
||||
return myMapTemplates.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTerminalSymbol(char currentChar) {
|
||||
return currentChar == '.' || currentChar == '!';
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement preExpand(@NotNull Editor editor, @NotNull PsiElement context, int offset, @NotNull final String key) {
|
||||
|
||||
return addSemicolonIfNeeded(editor, editor.getDocument(), context, offset - key.length());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiFile preCheck(@NotNull Editor editor, @NotNull PsiFile file, int currentOffset) {
|
||||
Document document = file.getViewProvider().getDocument();
|
||||
assert document != null;
|
||||
CharSequence sequence = document.getCharsSequence();
|
||||
StringBuilder fileContentWithoutKey = new StringBuilder(sequence);
|
||||
if (isSemicolonNeeded(file, editor)) {
|
||||
fileContentWithoutKey.insert(currentOffset, ';');
|
||||
file = PostfixLiveTemplate.copyFile(file, fileContentWithoutKey);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
private void register(@NotNull String key, @NotNull PostfixTemplate template) {
|
||||
PostfixTemplate registered = myMapTemplates.put(key, template);
|
||||
if (registered != null) {
|
||||
LOG.error("Can't register postfix template. Duplicated key: " + template.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiElement addSemicolonIfNeeded(@NotNull final Editor editor,
|
||||
@NotNull final Document document,
|
||||
@NotNull final PsiElement context,
|
||||
final int offset) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
|
||||
final Ref<PsiElement> newContext = Ref.create(context);
|
||||
final PsiFile file = context.getContainingFile();
|
||||
if (isSemicolonNeeded(file, editor)) {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() {
|
||||
public void run() {
|
||||
document.insertString(offset, ";");
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document);
|
||||
newContext.set(CustomTemplateCallback.getContext(file, offset - 1));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return newContext.get();
|
||||
}
|
||||
|
||||
private static boolean isSemicolonNeeded(@NotNull PsiFile file, @NotNull Editor editor) {
|
||||
return JavaCompletionContributor.semicolonNeeded(editor, file, CompletionInitializationContext.calcStartOffset(editor));
|
||||
}
|
||||
}
|
||||
+9
-9
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2011 Dave Griffith, Bas Leijdekkers
|
||||
* 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.
|
||||
@@ -13,15 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.siyeh.ig.classlayout;
|
||||
package com.intellij.codeInsight.template.postfix.templates;
|
||||
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import com.siyeh.ig.fixes.MoveClassFix;
|
||||
import com.intellij.lang.LanguageExtension;
|
||||
|
||||
public class ClassInTopLevelPackageInspection extends ClassInTopLevelPackageInspectionBase {
|
||||
public class LanguagePostfixTemplate extends LanguageExtension<PostfixTemplateProvider> {
|
||||
public static final LanguagePostfixTemplate INSTANCE = new LanguagePostfixTemplate();
|
||||
public static final String EP_NAME = "com.intellij.codeInsight.template.postfixTemplateProvider";
|
||||
|
||||
@Override
|
||||
protected InspectionGadgetsFix buildFix(Object... infos) {
|
||||
return new MoveClassFix();
|
||||
private LanguagePostfixTemplate() {
|
||||
super(EP_NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
+175
-148
@@ -15,17 +15,15 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.template.postfix.templates;
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionInitializationContext;
|
||||
import com.intellij.codeInsight.completion.JavaCompletionContributor;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.codeInsight.template.CustomLiveTemplateBase;
|
||||
import com.intellij.codeInsight.template.CustomTemplateCallback;
|
||||
import com.intellij.codeInsight.template.impl.CustomLiveTemplateLookupElement;
|
||||
import com.intellij.codeInsight.template.impl.TemplateSettings;
|
||||
import com.intellij.codeInsight.template.postfix.completion.PostfixTemplateLookupElement;
|
||||
import com.intellij.codeInsight.template.postfix.settings.PostfixTemplatesSettings;
|
||||
import com.intellij.codeInsight.template.postfix.util.Aliases;
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.command.undo.UndoConstants;
|
||||
@@ -33,7 +31,6 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiDocumentManager;
|
||||
@@ -42,71 +39,53 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiFileFactory;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
public class PostfixLiveTemplate extends CustomLiveTemplateBase {
|
||||
public static final String POSTFIX_TEMPLATE_ID = "POSTFIX_TEMPLATE_ID";
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(PostfixLiveTemplate.class);
|
||||
private final HashMap<String, PostfixTemplate> myTemplates = ContainerUtil.newHashMap();
|
||||
private static final LanguagePostfixTemplate templates = LanguagePostfixTemplate.INSTANCE;
|
||||
|
||||
public PostfixLiveTemplate() {
|
||||
for (PostfixTemplate template : PostfixTemplate.EP_NAME.getExtensions()) {
|
||||
register(template.getKey(), template);
|
||||
Aliases aliases = template.getClass().getAnnotation(Aliases.class);
|
||||
if (aliases != null) {
|
||||
for (String key : aliases.value()) {
|
||||
register(key, template);
|
||||
}
|
||||
@NotNull
|
||||
public Set<String> getAllTemplateKeys(PsiFile file, int offset) {
|
||||
Set<String> keys = Sets.newHashSet();
|
||||
Language language = PsiUtilCore.getLanguageAtOffset(file, offset);
|
||||
|
||||
for (PostfixTemplateProvider provider : templates.allForLanguage(language)) {
|
||||
keys.addAll(provider.getKeys());
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
public boolean hasNotEmptyKey(PsiFile file, int offset) {
|
||||
Language language = PsiUtilCore.getLanguageAtOffset(file, offset);
|
||||
for (PostfixTemplateProvider provider : templates.allForLanguage(language)) {
|
||||
if (StringUtil
|
||||
.isNotEmpty(computeTemplateKeyWithoutContextChecking(provider, file.getText(), offset + 1))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void register(@NotNull String key, @NotNull PostfixTemplate template) {
|
||||
PostfixTemplate registered = myTemplates.put(key, template);
|
||||
if (registered != null) {
|
||||
LOG.error("Can't register postfix template. Duplicated key: " + template.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String computeTemplateKey(@NotNull CustomTemplateCallback callback) {
|
||||
Editor editor = callback.getEditor();
|
||||
String key = computeTemplateKeyWithoutContextChecking(editor.getDocument().getCharsSequence(), editor.getCaretModel().getOffset());
|
||||
if (key == null) return null;
|
||||
return isApplicableTemplate(getTemplateByKey(key), key, callback.getContext().getContainingFile(), editor) ? key : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String computeTemplateKeyWithoutContextChecking(@NotNull CustomTemplateCallback callback) {
|
||||
Editor editor = callback.getEditor();
|
||||
return computeTemplateKeyWithoutContextChecking(editor.getDocument().getCharsSequence(), editor.getCaretModel().getOffset());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsMultiCaret() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String computeTemplateKeyWithoutContextChecking(@NotNull CharSequence documentContent, int currentOffset) {
|
||||
public String computeTemplateKeyWithoutContextChecking(PostfixTemplateProvider provider,
|
||||
@NotNull CharSequence documentContent,
|
||||
int currentOffset) {
|
||||
int startOffset = currentOffset;
|
||||
if (documentContent.length() < startOffset) {
|
||||
return null;
|
||||
}
|
||||
|
||||
while (startOffset > 0) {
|
||||
char currentChar = documentContent.charAt(startOffset - 1);
|
||||
if (!Character.isJavaIdentifierPart(currentChar)) {
|
||||
if (currentChar != '.' && currentChar != '!') {
|
||||
if (!provider.isTerminalSymbol(currentChar)) {
|
||||
return null;
|
||||
}
|
||||
startOffset--;
|
||||
@@ -117,19 +96,82 @@ public class PostfixLiveTemplate extends CustomLiveTemplateBase {
|
||||
return String.valueOf(documentContent.subSequence(startOffset, currentOffset));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String computeTemplateKey(@NotNull CustomTemplateCallback callback) {
|
||||
Editor editor = callback.getEditor();
|
||||
CharSequence charsSequence = editor.getDocument().getCharsSequence();
|
||||
int offset = editor.getCaretModel().getOffset();
|
||||
Language language = getLanguage(callback);
|
||||
for (PostfixTemplateProvider provider : templates.allForLanguage(language)) {
|
||||
String key = computeTemplateKeyWithoutContextChecking(provider, charsSequence, offset);
|
||||
if (key != null && isApplicableTemplate(provider, key, callback.getFile(), editor)) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String computeTemplateKeyWithoutContextChecking(@NotNull CustomTemplateCallback callback) {
|
||||
Editor editor = callback.getEditor();
|
||||
return computeTemplateKeyWithoutContextChecking(callback.getFile(), editor, editor.getCaretModel().getOffset());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsMultiCaret() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String computeTemplateKeyWithoutContextChecking(PsiFile file, Editor editor, int currentOffset) {
|
||||
Language language = PsiUtilCore.getLanguageAtOffset(file, currentOffset);
|
||||
for (PostfixTemplateProvider provider : templates.allForLanguage(language)) {
|
||||
String key = computeTemplateKeyWithoutContextChecking(provider, editor.getDocument().getCharsSequence(), currentOffset);
|
||||
if (key != null) return key;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expand(@NotNull final String key, @NotNull final CustomTemplateCallback callback) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
|
||||
FeatureUsageTracker.getInstance().triggerFeatureUsed("editing.completion.postfix");
|
||||
|
||||
final PostfixTemplate template = getTemplateByKey(key);
|
||||
Editor editor = callback.getEditor();
|
||||
Language language = getLanguage(callback);
|
||||
for (PostfixTemplateProvider provider : templates.allForLanguage(language)) {
|
||||
PostfixTemplate postfixTemplate = provider.get(key);
|
||||
if (postfixTemplate != null) {
|
||||
expandForProvider(provider, key, callback);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// don't care about errors in multiCaret mode
|
||||
if (editor.getCaretModel().getAllCarets().size() == 1) {
|
||||
LOG.error("Template not found by key: " + key);
|
||||
}
|
||||
}
|
||||
|
||||
private static Language getLanguage(CustomTemplateCallback callback) {
|
||||
return PsiUtilCore.getLanguageAtOffset(callback.getFile(), callback.getEditor().getCaretModel().getOffset());
|
||||
}
|
||||
|
||||
public void expandForProvider(
|
||||
@NotNull PostfixTemplateProvider provider,
|
||||
@NotNull final String key,
|
||||
@NotNull final CustomTemplateCallback callback) {
|
||||
final Editor editor = callback.getEditor();
|
||||
final PsiFile file = callback.getContext().getContainingFile();
|
||||
if (isApplicableTemplate(template, key, file, editor)) {
|
||||
if (isApplicableTemplate(provider, key, file, editor)) {
|
||||
int currentOffset = editor.getCaretModel().getOffset();
|
||||
PsiElement newContext = deleteTemplateKey(file, editor.getDocument(), currentOffset, key);
|
||||
newContext = addSemicolonIfNeeded(editor, editor.getDocument(), newContext, currentOffset - key.length());
|
||||
newContext = provider.preExpand(editor, newContext, currentOffset, key);
|
||||
PostfixTemplate template = provider.get(key);
|
||||
assert template != null;
|
||||
expandTemplate(template, editor, newContext);
|
||||
}
|
||||
// don't care about errors in multiCaret mode
|
||||
@@ -141,11 +183,10 @@ public class PostfixLiveTemplate extends CustomLiveTemplateBase {
|
||||
@Override
|
||||
public boolean isApplicable(PsiFile file, int offset, boolean wrapping) {
|
||||
PostfixTemplatesSettings settings = PostfixTemplatesSettings.getInstance();
|
||||
if (wrapping || file == null || settings == null || !settings.isPostfixTemplatesEnabled() ||
|
||||
PsiUtilCore.getLanguageAtOffset(file, offset) != JavaLanguage.INSTANCE) {
|
||||
if (wrapping || file == null || settings == null || !settings.isPostfixTemplatesEnabled()) {
|
||||
return false;
|
||||
}
|
||||
return StringUtil.isNotEmpty(computeTemplateKeyWithoutContextChecking(file.getText(), offset + 1));
|
||||
return hasNotEmptyKey(file, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -177,35 +218,46 @@ public class PostfixLiveTemplate extends CustomLiveTemplateBase {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<? extends CustomLiveTemplateLookupElement> getLookupElements(@NotNull PsiFile file, @NotNull Editor editor, int offset) {
|
||||
String key = computeTemplateKeyWithoutContextChecking(editor.getDocument().getCharsSequence(), offset);
|
||||
public Collection<? extends CustomLiveTemplateLookupElement> getLookupElements(@NotNull PsiFile file,
|
||||
@NotNull Editor editor,
|
||||
int offset) {
|
||||
Collection<CustomLiveTemplateLookupElement> result = ContainerUtil.newHashSet();
|
||||
Language language = PsiUtilCore.getLanguageAtOffset(file, editor.getCaretModel().getOffset());
|
||||
for (PostfixTemplateProvider provider : templates.allForLanguage(language)) {
|
||||
result.addAll(getLookupElementsForProvider(provider, file, editor, offset));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Collection<? extends CustomLiveTemplateLookupElement> getLookupElementsForProvider(
|
||||
@NotNull PostfixTemplateProvider provider,
|
||||
@NotNull PsiFile file,
|
||||
@NotNull Editor editor,
|
||||
int offset) {
|
||||
String key = computeTemplateKeyWithoutContextChecking(file, editor, offset);
|
||||
if (key != null && editor.getCaretModel().getCaretCount() == 1) {
|
||||
Collection<CustomLiveTemplateLookupElement> result = ContainerUtil.newHashSet();
|
||||
Condition<PostfixTemplate> isApplicationTemplateFunction = createIsApplicationTemplateFunction(key, file, editor);
|
||||
for (Map.Entry<String, PostfixTemplate> entry : myTemplates.entrySet()) {
|
||||
PostfixTemplate postfixTemplate = entry.getValue();
|
||||
|
||||
Condition<PostfixTemplate> isApplicationTemplateFunction = createIsApplicationTemplateFunction(provider, key, file, editor);
|
||||
for (String postfixKey : provider.getKeys()) {
|
||||
PostfixTemplate postfixTemplate = provider.get(postfixKey);
|
||||
assert postfixTemplate != null;
|
||||
if (isApplicationTemplateFunction.value(postfixTemplate)) {
|
||||
result.add(new PostfixTemplateLookupElement(this, postfixTemplate, entry.getKey(), false));
|
||||
result.add(new PostfixTemplateLookupElement(this, postfixTemplate, postfixKey, false));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return super.getLookupElements(file, editor, offset);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<String> getAllTemplateKeys() {
|
||||
return myTemplates.keySet();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PostfixTemplate getTemplateByKey(@NotNull String key) {
|
||||
return myTemplates.get(key);
|
||||
}
|
||||
|
||||
private static void expandTemplate(@NotNull final PostfixTemplate template,
|
||||
@NotNull final Editor editor,
|
||||
@NotNull final PsiElement context) {
|
||||
private static void expandTemplate(
|
||||
@NotNull final PostfixTemplate template,
|
||||
@NotNull final Editor editor,
|
||||
@NotNull final PsiElement context) {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -218,56 +270,6 @@ public class PostfixLiveTemplate extends CustomLiveTemplateBase {
|
||||
});
|
||||
}
|
||||
|
||||
@Contract("null, _, _, _ -> false")
|
||||
private static boolean isApplicableTemplate(@Nullable PostfixTemplate template, @NotNull String key, @NotNull PsiFile file, @NotNull Editor editor) {
|
||||
return createIsApplicationTemplateFunction(key, file, editor).value(template);
|
||||
}
|
||||
|
||||
private static Condition<PostfixTemplate> createIsApplicationTemplateFunction(@NotNull String key, @NotNull PsiFile file, @NotNull Editor editor) {
|
||||
int currentOffset = editor.getCaretModel().getOffset();
|
||||
final int newOffset = currentOffset - key.length();
|
||||
CharSequence fileContent = editor.getDocument().getCharsSequence();
|
||||
|
||||
StringBuilder fileContentWithoutKey = new StringBuilder();
|
||||
fileContentWithoutKey.append(fileContent.subSequence(0, newOffset));
|
||||
fileContentWithoutKey.append(fileContent.subSequence(currentOffset, fileContent.length()));
|
||||
PsiFile copyFile = copyFile(file, fileContentWithoutKey);
|
||||
Document copyDocument = copyFile.getViewProvider().getDocument();
|
||||
if (copyDocument == null) {
|
||||
//noinspection unchecked
|
||||
return Condition.FALSE;
|
||||
}
|
||||
|
||||
if (isSemicolonNeeded(copyFile, editor)) {
|
||||
fileContentWithoutKey.insert(newOffset, ';');
|
||||
copyFile = copyFile(file, fileContentWithoutKey);
|
||||
copyDocument = copyFile.getViewProvider().getDocument();
|
||||
if (copyDocument == null) {
|
||||
//noinspection unchecked
|
||||
return Condition.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
final PsiElement context = CustomTemplateCallback.getContext(copyFile, newOffset > 0 ? newOffset - 1 : newOffset);
|
||||
final Document finalCopyDocument = copyDocument;
|
||||
return new Condition<PostfixTemplate>() {
|
||||
@Override
|
||||
public boolean value(PostfixTemplate template) {
|
||||
return template != null && template.isEnabled() && template.isApplicable(context, finalCopyDocument, newOffset);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiFile copyFile(@NotNull PsiFile file, @NotNull StringBuilder fileContentWithoutKey) {
|
||||
final PsiFileFactory psiFileFactory = PsiFileFactory.getInstance(file.getProject());
|
||||
PsiFile copy = psiFileFactory.createFileFromText(file.getName(), file.getFileType(), fileContentWithoutKey);
|
||||
VirtualFile vFile = copy.getVirtualFile();
|
||||
if (vFile != null) {
|
||||
vFile.putUserData(UndoConstants.DONT_RECORD_UNDO, Boolean.TRUE);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiElement deleteTemplateKey(@NotNull final PsiFile file,
|
||||
@@ -291,33 +293,58 @@ public class PostfixLiveTemplate extends CustomLiveTemplateBase {
|
||||
return CustomTemplateCallback.getContext(file, startOffset > 0 ? startOffset - 1 : startOffset);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiElement addSemicolonIfNeeded(@NotNull final Editor editor,
|
||||
@NotNull final Document document,
|
||||
@NotNull final PsiElement context,
|
||||
final int offset) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
|
||||
final Ref<PsiElement> newContext = Ref.create(context);
|
||||
final PsiFile file = context.getContainingFile();
|
||||
if (isSemicolonNeeded(file, editor)) {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() {
|
||||
public void run() {
|
||||
document.insertString(offset, ";");
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document);
|
||||
newContext.set(CustomTemplateCallback.getContext(file, offset - 1));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
private static Condition<PostfixTemplate> createIsApplicationTemplateFunction(
|
||||
@NotNull PostfixTemplateProvider provider,
|
||||
@NotNull String key,
|
||||
@NotNull PsiFile file,
|
||||
@NotNull Editor editor) {
|
||||
int currentOffset = editor.getCaretModel().getOffset();
|
||||
final int newOffset = currentOffset - key.length();
|
||||
CharSequence fileContent = editor.getDocument().getCharsSequence();
|
||||
StringBuilder fileContentWithoutKey = new StringBuilder();
|
||||
fileContentWithoutKey.append(fileContent.subSequence(0, newOffset));
|
||||
fileContentWithoutKey.append(fileContent.subSequence(currentOffset, fileContent.length()));
|
||||
PsiFile copyFile = copyFile(file, fileContentWithoutKey);
|
||||
Document copyDocument = copyFile.getViewProvider().getDocument();
|
||||
if (copyDocument == null) {
|
||||
//noinspection unchecked
|
||||
return Condition.FALSE;
|
||||
}
|
||||
return newContext.get();
|
||||
|
||||
copyFile = provider.preCheck(editor, copyFile, newOffset);
|
||||
copyDocument = copyFile.getViewProvider().getDocument();
|
||||
if (copyDocument == null) {
|
||||
//noinspection unchecked
|
||||
return Condition.FALSE;
|
||||
}
|
||||
|
||||
final PsiElement context = CustomTemplateCallback.getContext(copyFile, newOffset > 0 ? newOffset - 1 : newOffset);
|
||||
final Document finalCopyDocument = copyDocument;
|
||||
return new Condition<PostfixTemplate>() {
|
||||
@Override
|
||||
public boolean value(PostfixTemplate template) {
|
||||
return template != null && template.isEnabled() && template.isApplicable(context, finalCopyDocument, newOffset);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isSemicolonNeeded(@NotNull PsiFile file, @NotNull Editor editor) {
|
||||
return JavaCompletionContributor.semicolonNeeded(editor, file, CompletionInitializationContext.calcStartOffset(editor));
|
||||
|
||||
@NotNull
|
||||
public static PsiFile copyFile(@NotNull PsiFile file, @NotNull StringBuilder fileContentWithoutKey) {
|
||||
final PsiFileFactory psiFileFactory = PsiFileFactory.getInstance(file.getProject());
|
||||
PsiFile copy = psiFileFactory.createFileFromText(file.getName(), file.getFileType(), fileContentWithoutKey);
|
||||
VirtualFile vFile = copy.getVirtualFile();
|
||||
if (vFile != null) {
|
||||
vFile.putUserData(UndoConstants.DONT_RECORD_UNDO, Boolean.TRUE);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
public static boolean isApplicableTemplate(
|
||||
@NotNull PostfixTemplateProvider provider,
|
||||
@NotNull String key,
|
||||
@NotNull PsiFile file,
|
||||
@NotNull Editor editor) {
|
||||
return createIsApplicationTemplateFunction(provider, key, file, editor).value(provider.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
-4
@@ -18,7 +18,6 @@ package com.intellij.codeInsight.template.postfix.templates;
|
||||
import com.intellij.codeInsight.template.postfix.settings.PostfixTemplatesSettings;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiExpression;
|
||||
import com.intellij.psi.PsiExpressionStatement;
|
||||
@@ -32,9 +31,6 @@ public abstract class PostfixTemplate {
|
||||
@NotNull private final String myDescription;
|
||||
@NotNull private final String myExample;
|
||||
|
||||
@NotNull
|
||||
public static final ExtensionPointName<PostfixTemplate> EP_NAME = ExtensionPointName.create("com.intellij.postfixTemplate");
|
||||
|
||||
protected PostfixTemplate(@NotNull String name, @NotNull String description, @NotNull String example) {
|
||||
this(name, "." + name, description, example);
|
||||
}
|
||||
|
||||
+64
@@ -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.codeInsight.template.postfix.templates;
|
||||
|
||||
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface PostfixTemplateProvider {
|
||||
|
||||
/**
|
||||
* Return all templates registered in the provider
|
||||
*/
|
||||
@NotNull
|
||||
Set<PostfixTemplate> getTemplates();
|
||||
|
||||
/**
|
||||
* Return all keys registered in the provider
|
||||
*/
|
||||
@NotNull
|
||||
Set<String> getKeys();
|
||||
|
||||
/**
|
||||
* Return postfix template for key
|
||||
*/
|
||||
@Nullable
|
||||
PostfixTemplate get(@Nullable String key);
|
||||
|
||||
/**
|
||||
* Check symbol can separate template keys
|
||||
*/
|
||||
boolean isTerminalSymbol(char currentChar);
|
||||
|
||||
/**
|
||||
* Prepare original file content for template expanding
|
||||
*/
|
||||
@NotNull
|
||||
PsiElement preExpand(@NotNull Editor editor, @NotNull PsiElement context, int currentOffset, @NotNull String key);
|
||||
|
||||
/**
|
||||
* Do some actions with the file content before check applicable.
|
||||
* Return new copy of file because we should not change original file
|
||||
*/
|
||||
@NotNull
|
||||
PsiFile preCheck(@NotNull Editor editor, @NotNull PsiFile file, int currentOffset);
|
||||
}
|
||||
+3
-1
@@ -26,6 +26,7 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.impl.file.JavaDirectoryServiceImpl;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -100,8 +101,9 @@ public class JavaCreateFromTemplateHandler implements CreateFromTemplateHandler
|
||||
return fileType.equals(StdFileTypes.JAVA) && !FileTemplateUtil.INTERNAL_PACKAGE_INFO_TEMPLATE_NAME.equals(template.getName());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiElement createFromTemplate(final Project project, final PsiDirectory directory, final String fileName, FileTemplate template,
|
||||
String templateText, Map<String, Object> props) throws IncorrectOperationException {
|
||||
String templateText, @NotNull Map<String, Object> props) throws IncorrectOperationException {
|
||||
String extension = template.getExtension();
|
||||
PsiElement result = createClassOrInterface(project, directory, templateText, template.isReformatCode(), extension);
|
||||
hackAwayEmptyPackage((PsiJavaFile)result.getContainingFile(), template, props);
|
||||
|
||||
+37
-25
@@ -30,6 +30,7 @@ import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.PsiShortNamesCache;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.psi.search.searches.AllClassesSearch;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.QueryExecutor;
|
||||
import com.intellij.util.indexing.IdFilter;
|
||||
@@ -57,39 +58,28 @@ public class AllClassesSearchExecutor implements QueryExecutor<PsiClass, AllClas
|
||||
private static boolean processAllClassesInGlobalScope(@NotNull final GlobalSearchScope scope,
|
||||
@NotNull final AllClassesSearch.SearchParameters parameters,
|
||||
@NotNull Processor<PsiClass> processor) {
|
||||
Project project = parameters.getProject();
|
||||
final PsiShortNamesCache cache = PsiShortNamesCache.getInstance(project);
|
||||
final ProgressIndicator indicator = ProgressIndicatorProvider.getGlobalProgressIndicator();
|
||||
|
||||
final Set<String> names = new THashSet<String>(10000);
|
||||
cache.processAllClassNames(new Processor<String>() {
|
||||
int i = 0;
|
||||
|
||||
processClassNames(parameters.getProject(), scope, new Consumer<String>() {
|
||||
@Override
|
||||
public boolean process(String s) {
|
||||
if (indicator != null && i++ % 512 == 0) {
|
||||
indicator.checkCanceled();
|
||||
}
|
||||
public void consume(String s) {
|
||||
if (parameters.nameMatches(s)) {
|
||||
names.add(s);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}, scope, IdFilter.getProjectIdFilter(project, true));
|
||||
|
||||
if (indicator != null) {
|
||||
indicator.checkCanceled();
|
||||
}
|
||||
|
||||
List<String> sorted = new ArrayList<String>(names);
|
||||
Collections.sort(sorted, new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(final String o1, final String o2) {
|
||||
return o1.compareToIgnoreCase(o2);
|
||||
}
|
||||
});
|
||||
|
||||
for (final String name : sorted) {
|
||||
List<String> sorted = new ArrayList<String>(names);
|
||||
Collections.sort(sorted, String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
return processClassesByNames(parameters.getProject(), scope, sorted, processor);
|
||||
}
|
||||
|
||||
public static boolean processClassesByNames(Project project,
|
||||
final GlobalSearchScope scope,
|
||||
Collection<String> names,
|
||||
Processor<PsiClass> processor) {
|
||||
final PsiShortNamesCache cache = PsiShortNamesCache.getInstance(project);
|
||||
for (final String name : names) {
|
||||
ProgressIndicatorProvider.checkCanceled();
|
||||
final PsiClass[] classes = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass[]>() {
|
||||
@Override
|
||||
@@ -107,6 +97,28 @@ public class AllClassesSearchExecutor implements QueryExecutor<PsiClass, AllClas
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Project processClassNames(Project project, GlobalSearchScope scope, final Consumer<String> consumer) {
|
||||
final ProgressIndicator indicator = ProgressIndicatorProvider.getGlobalProgressIndicator();
|
||||
|
||||
PsiShortNamesCache.getInstance(project).processAllClassNames(new Processor<String>() {
|
||||
int i = 0;
|
||||
|
||||
@Override
|
||||
public boolean process(String s) {
|
||||
if (indicator != null && i++ % 512 == 0) {
|
||||
indicator.checkCanceled();
|
||||
}
|
||||
consumer.consume(s);
|
||||
return true;
|
||||
}
|
||||
}, scope, IdFilter.getProjectIdFilter(project, true));
|
||||
|
||||
if (indicator != null) {
|
||||
indicator.checkCanceled();
|
||||
}
|
||||
return project;
|
||||
}
|
||||
|
||||
private static boolean processScopeRootForAllClasses(@NotNull final PsiElement scopeRoot, @NotNull final Processor<PsiClass> processor) {
|
||||
final boolean[] stopped = {false};
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -151,9 +150,7 @@ public class PsiTypesUtil {
|
||||
@Nullable Condition<IElementType> condition,
|
||||
@NotNull LanguageLevel languageLevel) {
|
||||
//JLS3 15.8.2
|
||||
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_5) &&
|
||||
GET_CLASS_METHOD.equals(method.getName()) &&
|
||||
CommonClassNames.JAVA_LANG_OBJECT.equals(method.getContainingClass().getQualifiedName())) {
|
||||
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_5) && isGetClass(method)) {
|
||||
PsiExpression qualifier = methodExpression.getQualifierExpression();
|
||||
PsiType qualifierType = null;
|
||||
final Project project = call.getProject();
|
||||
@@ -169,18 +166,28 @@ public class PsiTypesUtil {
|
||||
qualifierType = JavaPsiFacade.getInstance(project).getElementFactory().createType((PsiClass)parent.getPsi());
|
||||
}
|
||||
}
|
||||
if (qualifierType != null) {
|
||||
PsiClass javaLangClass = JavaPsiFacade.getInstance(project).findClass(CommonClassNames.JAVA_LANG_CLASS, call.getResolveScope());
|
||||
if (javaLangClass != null && javaLangClass.getTypeParameters().length == 1) {
|
||||
Map<PsiTypeParameter, PsiType> map = new HashMap<PsiTypeParameter, PsiType>();
|
||||
map.put(javaLangClass.getTypeParameters()[0], PsiWildcardType.createExtends(call.getManager(), qualifierType));
|
||||
PsiSubstitutor substitutor = JavaPsiFacade.getInstance(project).getElementFactory().createSubstitutor(map);
|
||||
final PsiClassType classType = JavaPsiFacade.getInstance(project).getElementFactory()
|
||||
.createType(javaLangClass, substitutor, languageLevel);
|
||||
final PsiElement parent = call.getParent();
|
||||
return parent instanceof PsiReferenceExpression && parent.getParent() instanceof PsiMethodCallExpression || parent instanceof PsiExpressionList
|
||||
? PsiUtil.captureToplevelWildcards(classType, methodExpression) : classType;
|
||||
}
|
||||
PsiElement parent = call.getParent();
|
||||
boolean captureTopLevelWildcards = parent instanceof PsiReferenceExpression && parent.getParent() instanceof PsiMethodCallExpression ||
|
||||
parent instanceof PsiExpressionList;
|
||||
return createJavaLangClassType(methodExpression, qualifierType, captureTopLevelWildcards);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isGetClass(PsiMethod method) {
|
||||
return GET_CLASS_METHOD.equals(method.getName()) && CommonClassNames.JAVA_LANG_OBJECT.equals(method.getContainingClass().getQualifiedName());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiType createJavaLangClassType(@NotNull PsiElement context, @Nullable PsiType qualifierType, boolean captureTopLevelWildcards) {
|
||||
if (qualifierType != null) {
|
||||
JavaPsiFacade facade = JavaPsiFacade.getInstance(context.getProject());
|
||||
PsiClass javaLangClass = facade.findClass(CommonClassNames.JAVA_LANG_CLASS, context.getResolveScope());
|
||||
if (javaLangClass != null && javaLangClass.getTypeParameters().length == 1) {
|
||||
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY.
|
||||
put(javaLangClass.getTypeParameters()[0], PsiWildcardType.createExtends(context.getManager(), qualifierType));
|
||||
final PsiClassType classType = facade.getElementFactory().createType(javaLangClass, substitutor, PsiUtil.getLanguageLevel(context));
|
||||
return captureTopLevelWildcards ? PsiUtil.captureToplevelWildcards(classType, context) : classType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
class A {
|
||||
}
|
||||
class B extends A {
|
||||
void m() {
|
||||
Class<? extends A> c = getClass();<caret>
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
class A {
|
||||
}
|
||||
class B extends A {
|
||||
void m() {
|
||||
Class<? extends A> c = g<caret>
|
||||
}
|
||||
}
|
||||
@@ -1624,4 +1624,15 @@ class Foo {
|
||||
def tabKeyPresentation = KeyEvent.getKeyText(TemplateSettings.TAB_CHAR as int)
|
||||
assert p.typeText == " [$tabKeyPresentation] "
|
||||
}
|
||||
|
||||
public void "test autopopup after package completion"() {
|
||||
myFixture.addClass("package foo.bar.goo; class Foo {}")
|
||||
myFixture.configureByText "a.java", "class Foo { { foo.b<caret> } }"
|
||||
myFixture.completeBasic()
|
||||
assert myFixture.editor.document.text.contains('foo.bar. ')
|
||||
joinAutopopup()
|
||||
joinCompletion()
|
||||
assert lookup
|
||||
assert myFixture.lookupElementStrings == ['goo']
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -1022,6 +1022,7 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase {
|
||||
public void testDuplicateMembersFromSuperClass() throws Throwable { doTest(); }
|
||||
public void testInnerAfterNew() throws Throwable { doTest(); }
|
||||
public void testEverythingInStringConcatenation() throws Throwable { doTest(); }
|
||||
public void testGetClassWhenClassExpected() { doTest(); }
|
||||
|
||||
public void testMemberImportStatically() {
|
||||
configureByTestName();
|
||||
|
||||
+9
-5
@@ -19,7 +19,10 @@ package com.intellij.application.options.colors;
|
||||
import com.intellij.application.options.colors.highlighting.HighlightData;
|
||||
import com.intellij.application.options.colors.highlighting.HighlightsExtractor;
|
||||
import com.intellij.ide.highlighter.HighlighterFactory;
|
||||
import com.intellij.openapi.editor.*;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.editor.LogicalPosition;
|
||||
import com.intellij.openapi.editor.ScrollType;
|
||||
import com.intellij.openapi.editor.colors.CodeInsightColors;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsScheme;
|
||||
import com.intellij.openapi.editor.colors.TextAttributesKey;
|
||||
@@ -42,10 +45,7 @@ import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseMotionAdapter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
public class SimpleEditorPreview implements PreviewPanel{
|
||||
@@ -91,6 +91,10 @@ public class SimpleEditorPreview implements PreviewPanel{
|
||||
}
|
||||
}
|
||||
|
||||
public EditorEx getEditor() {
|
||||
return myEditor;
|
||||
}
|
||||
|
||||
private void addMouseMotionListener(final Editor view,
|
||||
final SyntaxHighlighter highlighter,
|
||||
final HighlightData[] data, final boolean isBackgroundImportant) {
|
||||
|
||||
+2
-1
@@ -430,7 +430,8 @@ public class CodeCompletionHandlerBase {
|
||||
|
||||
// the insert handler may have started a live template with completion
|
||||
if (CompletionService.getCompletionService().getCurrentCompletion() == null &&
|
||||
!ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
// ...or scheduled another autopopup
|
||||
!CompletionServiceImpl.isPhase(CompletionPhase.CommittingDocuments.class)) {
|
||||
CompletionServiceImpl.setCompletionPhase(hasModifiers? new CompletionPhase.InsertedSingleItem(indicator, restorePrefix) : CompletionPhase.NoCompletion);
|
||||
}
|
||||
checkNotSync(indicator, items);
|
||||
|
||||
+1
-1
@@ -206,7 +206,7 @@ public class OffsetsElementSignatureProvider extends AbstractElementSignaturePro
|
||||
buffer.append(ELEMENT_TOKENS_SEPARATOR).append(index);
|
||||
PsiFile containingFile = element.getContainingFile();
|
||||
if (containingFile != null && containingFile.getViewProvider().getLanguages().size() > 1) {
|
||||
buffer.append(ELEMENT_TOKENS_SEPARATOR).append(element.getLanguage().getID());
|
||||
buffer.append(ELEMENT_TOKENS_SEPARATOR).append(containingFile.getLanguage().getID());
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package com.intellij.codeInsight.lookup.impl;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.codeInsight.FileModificationService;
|
||||
import com.intellij.codeInsight.completion.CodeCompletionFeatures;
|
||||
import com.intellij.codeInsight.completion.CompletionLookupArranger;
|
||||
@@ -27,25 +26,19 @@ import com.intellij.codeInsight.hint.HintManager;
|
||||
import com.intellij.codeInsight.hint.HintManagerImpl;
|
||||
import com.intellij.codeInsight.lookup.*;
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.ide.IdeEventQueue;
|
||||
import com.intellij.ide.ui.UISettings;
|
||||
import com.intellij.lang.LangBundle;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.*;
|
||||
import com.intellij.openapi.editor.event.*;
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
import com.intellij.openapi.keymap.KeymapUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.JBPopup;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
@@ -57,20 +50,12 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.impl.DebugUtil;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.ui.components.JBLayeredPane;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.ui.plaf.beg.BegPopupMenuBorder;
|
||||
import com.intellij.ui.popup.AbstractPopup;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.CollectConsumer;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
import com.intellij.util.containers.ConcurrentHashMap;
|
||||
import com.intellij.util.containers.ConcurrentWeakHashMap;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.AbstractLayoutManager;
|
||||
import com.intellij.util.ui.AsyncProcessIcon;
|
||||
import com.intellij.util.ui.ButtonlessScrollBarUI;
|
||||
import com.intellij.util.ui.update.Activatable;
|
||||
import com.intellij.util.ui.update.UiNotifyConnector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -78,13 +63,11 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.LineBorder;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -120,8 +103,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
return myExtender;
|
||||
}
|
||||
};
|
||||
private final LookupCellRenderer myCellRenderer;
|
||||
private Boolean myPositionedAbove = null;
|
||||
final LookupCellRenderer myCellRenderer;
|
||||
|
||||
private final List<LookupListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
|
||||
@@ -131,12 +113,10 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
private boolean myHidden = false;
|
||||
private boolean mySelectionTouched;
|
||||
private FocusDegree myFocusDegree = FocusDegree.FOCUSED;
|
||||
private final AsyncProcessIcon myProcessIcon = new AsyncProcessIcon("Completion progress");
|
||||
private final JPanel myIconPanel = new JPanel(new BorderLayout());
|
||||
private volatile boolean myCalculating;
|
||||
private final Advertiser myAdComponent;
|
||||
private volatile String myAdText;
|
||||
private volatile int myLookupTextWidth = 50;
|
||||
volatile int myLookupTextWidth = 50;
|
||||
private boolean myChangeGuard;
|
||||
private volatile LookupArranger myArranger;
|
||||
private LookupArranger myPresentableArranger;
|
||||
@@ -144,18 +124,11 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
ContainerUtil.<LookupElement>identityStrategy());
|
||||
private final Map<LookupElement, Font> myCustomFonts = new ConcurrentWeakHashMap<LookupElement, Font>(
|
||||
ContainerUtil.<LookupElement>identityStrategy());
|
||||
private LookupHint myElementHint = null;
|
||||
private final Alarm myHintAlarm = new Alarm();
|
||||
private final JLabel mySortingLabel = new JLabel();
|
||||
private final JScrollPane myScrollPane;
|
||||
final LookupLayeredPane myLayeredPane = new LookupLayeredPane();
|
||||
private final JButton myScrollBarIncreaseButton;
|
||||
private boolean myStartCompletionWhenNothingMatches;
|
||||
private boolean myResizePending;
|
||||
private int myMaximumHeight = Integer.MAX_VALUE;
|
||||
boolean myResizePending;
|
||||
private boolean myFinishing;
|
||||
private boolean myUpdating;
|
||||
private final ModalityState myModalityState;
|
||||
boolean myUpdating;
|
||||
private LookupUi myUi;
|
||||
|
||||
public LookupImpl(Project project, Editor editor, @NotNull LookupArranger arranger) {
|
||||
super(new JPanel(new BorderLayout()));
|
||||
@@ -169,7 +142,6 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
myArranger = arranger;
|
||||
myPresentableArranger = arranger;
|
||||
|
||||
myIconPanel.setVisible(false);
|
||||
myCellRenderer = new LookupCellRenderer(this);
|
||||
myList.setCellRenderer(myCellRenderer);
|
||||
|
||||
@@ -181,36 +153,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
|
||||
myList.getExpandableItemsHandler();
|
||||
|
||||
myScrollBarIncreaseButton = new JButton();
|
||||
myScrollBarIncreaseButton.setFocusable(false);
|
||||
myScrollBarIncreaseButton.setRequestFocusEnabled(false);
|
||||
|
||||
myScrollPane = new JBScrollPane(myList);
|
||||
myScrollPane.setViewportBorder(new EmptyBorder(0, 0, 0, 0));
|
||||
myScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
myScrollPane.getVerticalScrollBar().setPreferredSize(new Dimension(13, -1));
|
||||
myScrollPane.getVerticalScrollBar().setUI(new ButtonlessScrollBarUI() {
|
||||
@Override
|
||||
protected JButton createIncreaseButton(int orientation) {
|
||||
return myScrollBarIncreaseButton;
|
||||
}
|
||||
});
|
||||
getComponent().add(myLayeredPane, BorderLayout.CENTER);
|
||||
|
||||
//IDEA-82111
|
||||
fixMouseCheaters();
|
||||
|
||||
myLayeredPane.mainPanel.add(myScrollPane, BorderLayout.CENTER);
|
||||
myScrollPane.setBorder(null);
|
||||
|
||||
myAdComponent = new Advertiser();
|
||||
JComponent adComponent = myAdComponent.getAdComponent();
|
||||
adComponent.setBorder(new EmptyBorder(0, 1, 1, 2 + AllIcons.Ide.LookupRelevance.getIconWidth()));
|
||||
myLayeredPane.mainPanel.add(adComponent, BorderLayout.SOUTH);
|
||||
getComponent().setBorder(new BegPopupMenuBorder());
|
||||
|
||||
myIconPanel.setBackground(Color.LIGHT_GRAY);
|
||||
myIconPanel.add(myProcessIcon);
|
||||
|
||||
myOffsets = new LookupOffsets(editor);
|
||||
|
||||
@@ -218,14 +161,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
addEmptyItem(model);
|
||||
updateListHeight(model);
|
||||
|
||||
|
||||
addListeners();
|
||||
|
||||
mySortingLabel.setBorder(new LineBorder(new JBColor(Color.LIGHT_GRAY, JBColor.background())));
|
||||
mySortingLabel.setOpaque(true);
|
||||
new ChangeLookupSorting().installOn(mySortingLabel);
|
||||
updateSorting();
|
||||
myModalityState = ModalityState.stateForComponent(getComponent());
|
||||
}
|
||||
|
||||
private CollectionListModel<LookupElement> getListModel() {
|
||||
@@ -233,34 +169,6 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
return (CollectionListModel<LookupElement>)myList.getModel();
|
||||
}
|
||||
|
||||
//Yes, it's possible to move focus to the hint. It's inconvenient, it doesn't make sense, but it's possible.
|
||||
// This fix is for those jerks
|
||||
private void fixMouseCheaters() {
|
||||
getComponent().addFocusListener(new FocusAdapter() {
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) {
|
||||
final ActionCallback done = IdeFocusManager.getInstance(myProject).requestFocus(myEditor.getContentComponent(), true);
|
||||
IdeFocusManager.getInstance(myProject).typeAheadUntil(done);
|
||||
new Alarm(LookupImpl.this).addRequest(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!done.isDone()) {
|
||||
done.setDone();
|
||||
}
|
||||
}
|
||||
}, 300, myModalityState);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void updateSorting() {
|
||||
final boolean lexi = UISettings.getInstance().SORT_LOOKUP_ELEMENTS_LEXICOGRAPHICALLY;
|
||||
mySortingLabel.setIcon(lexi ? AllIcons.Ide.LookupAlphanumeric : AllIcons.Ide.LookupRelevance);
|
||||
mySortingLabel.setToolTipText(lexi ? "Click to sort variants by relevance" : "Click to sort variants alphabetically");
|
||||
|
||||
resort(false);
|
||||
}
|
||||
|
||||
public void setArranger(LookupArranger arranger) {
|
||||
myArranger = arranger;
|
||||
}
|
||||
@@ -284,22 +192,8 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
|
||||
public void setCalculating(final boolean calculating) {
|
||||
myCalculating = calculating;
|
||||
Runnable setVisible = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myIconPanel.setVisible(myCalculating);
|
||||
}
|
||||
};
|
||||
if (myCalculating) {
|
||||
new Alarm(this).addRequest(setVisible, 100, myModalityState);
|
||||
} else {
|
||||
setVisible.run();
|
||||
}
|
||||
|
||||
if (calculating) {
|
||||
myProcessIcon.resume();
|
||||
} else {
|
||||
myProcessIcon.suspend();
|
||||
if (myUi != null) {
|
||||
myUi.setCalculating(calculating);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -564,50 +458,6 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
return myMatchers.get(item);
|
||||
}
|
||||
|
||||
// in layered pane coordinate system.
|
||||
private Rectangle calculatePosition() {
|
||||
Dimension dim = getComponent().getPreferredSize();
|
||||
int lookupStart = getLookupStart();
|
||||
if (lookupStart < 0 || lookupStart > myEditor.getDocument().getTextLength()) {
|
||||
LOG.error(lookupStart + "; offset=" + myEditor.getCaretModel().getOffset() + "; element=" +
|
||||
getPsiElement());
|
||||
}
|
||||
|
||||
LogicalPosition pos = myEditor.offsetToLogicalPosition(lookupStart);
|
||||
Point location = myEditor.logicalPositionToXY(pos);
|
||||
location.y += myEditor.getLineHeight();
|
||||
location.x -= myCellRenderer.getIconIndent() + getComponent().getInsets().left;
|
||||
|
||||
SwingUtilities.convertPointToScreen(location, myEditor.getContentComponent());
|
||||
final Rectangle screenRectangle = ScreenUtil.getScreenRectangle(location);
|
||||
|
||||
if (!isPositionedAboveCaret()) {
|
||||
int shiftLow = screenRectangle.height - (location.y + dim.height);
|
||||
myPositionedAbove = shiftLow < 0 && shiftLow < location.y - dim.height && location.y >= dim.height;
|
||||
}
|
||||
if (isPositionedAboveCaret()) {
|
||||
location.y -= dim.height + myEditor.getLineHeight();
|
||||
if (pos.line == 0) {
|
||||
location.y += 1;
|
||||
//otherwise the lookup won't intersect with the editor and every editor's resize (e.g. after typing in console) will close the lookup
|
||||
}
|
||||
}
|
||||
|
||||
if (!screenRectangle.contains(location)) {
|
||||
location = ScreenUtil.findNearestPointOnBorder(screenRectangle, location);
|
||||
}
|
||||
|
||||
final JRootPane rootPane = myEditor.getComponent().getRootPane();
|
||||
if (rootPane == null) {
|
||||
LOG.error(myEditor.isDisposed() + "; shown=" + myShown + "; disposed=" + myDisposed + "; editorShowing=" + myEditor.getContentComponent().isShowing());
|
||||
}
|
||||
Rectangle candidate = new Rectangle(location, dim);
|
||||
ScreenUtil.cropRectangleToFitTheScreen(candidate);
|
||||
|
||||
SwingUtilities.convertPointFromScreen(location, rootPane.getLayeredPane());
|
||||
return new Rectangle(location.x, location.y, dim.width, candidate.height);
|
||||
}
|
||||
|
||||
public void finishLookup(final char completionChar) {
|
||||
finishLookup(completionChar, (LookupElement)myList.getSelectedValue());
|
||||
}
|
||||
@@ -794,7 +644,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
return false;
|
||||
}
|
||||
if (isVisible()) {
|
||||
updateLookupLocation();
|
||||
HintManagerImpl.updateLocation(this, myEditor, myUi.calculatePosition().getLocation());
|
||||
}
|
||||
checkValid();
|
||||
return true;
|
||||
@@ -835,12 +685,9 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
|
||||
myAdComponent.showRandomText();
|
||||
|
||||
getComponent().setBorder(null);
|
||||
updateScrollbarVisibility();
|
||||
|
||||
Rectangle bounds = calculatePosition();
|
||||
myMaximumHeight = bounds.height;
|
||||
Point p = bounds.getLocation();
|
||||
myUi = new LookupUi(this, myAdComponent, myList, myProject);
|
||||
myUi.setCalculating(myCalculating);
|
||||
Point p = myUi.calculatePosition().getLocation();
|
||||
HintManagerImpl.getInstanceImpl().showEditorHint(this, myEditor, p, HintManager.HIDE_BY_ESCAPE | HintManager.UPDATE_BY_SCROLLING, 0, false,
|
||||
HintManagerImpl.createHintHint(myEditor, p, this, HintManager.UNDER).setAwtTooltip(false));
|
||||
|
||||
@@ -923,8 +770,6 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e){
|
||||
myHintAlarm.cancelAllRequests();
|
||||
|
||||
final LookupElement item = getCurrentItem();
|
||||
if (oldItem != item && !myList.isEmpty()) { // do not update on temporary model wipe
|
||||
fireCurrentItemChanged(item);
|
||||
@@ -933,9 +778,6 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
}
|
||||
oldItem = item;
|
||||
}
|
||||
if (item != null) {
|
||||
updateHint(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -956,53 +798,6 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
return true;
|
||||
}
|
||||
}.installOn(myList);
|
||||
|
||||
final Alarm alarm = new Alarm(this);
|
||||
myScrollPane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
|
||||
@Override
|
||||
public void adjustmentValueChanged(AdjustmentEvent e) {
|
||||
if (!myShown || myUpdating || myDisposed) return;
|
||||
alarm.addRequest(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
refreshUi(false, false);
|
||||
}
|
||||
}, 300, myModalityState);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateHint(@NotNull final LookupElement item) {
|
||||
checkValid();
|
||||
if (myElementHint != null) {
|
||||
myLayeredPane.remove(myElementHint);
|
||||
myElementHint = null;
|
||||
final JRootPane rootPane = getComponent().getRootPane();
|
||||
if (rootPane != null) {
|
||||
rootPane.revalidate();
|
||||
rootPane.repaint();
|
||||
}
|
||||
}
|
||||
if (!isFocused()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Collection<LookupElementAction> actions = getActionsFor(item);
|
||||
if (!actions.isEmpty()) {
|
||||
myHintAlarm.addRequest(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
assert !myDisposed;
|
||||
if (!ShowHideIntentionIconLookupAction.shouldShowLookupHint() ||
|
||||
((CompletionExtender)myList.getExpandableItemsHandler()).isShowing()) {
|
||||
return;
|
||||
}
|
||||
myElementHint = new LookupHint();
|
||||
myLayeredPane.add(myElementHint, 20, 0);
|
||||
myLayeredPane.layoutHint();
|
||||
}
|
||||
}, 500, myModalityState);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1075,7 +870,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
}
|
||||
}
|
||||
|
||||
private void fireCurrentItemChanged(LookupElement item){
|
||||
void fireCurrentItemChanged(LookupElement item){
|
||||
if (!myListeners.isEmpty()){
|
||||
LookupEvent event = new LookupEvent(this, item, (char)0);
|
||||
for (LookupListener listener : myListeners) {
|
||||
@@ -1208,7 +1003,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
|
||||
@Override
|
||||
public boolean isPositionedAboveCaret(){
|
||||
return myPositionedAbove != null && myPositionedAbove.booleanValue();
|
||||
return myUi != null && myUi.isPositionedAboveCaret();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1279,8 +1074,6 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
}
|
||||
|
||||
myOffsets.disposeMarkers();
|
||||
Disposer.dispose(myProcessIcon);
|
||||
Disposer.dispose(myHintAlarm);
|
||||
myDisposed = true;
|
||||
disposeTrace = DebugUtil.currentStackTrace() + "\n============";
|
||||
//noinspection AssignmentToStaticFieldFromInstanceMethod
|
||||
@@ -1291,59 +1084,19 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
assert !myUpdating;
|
||||
myUpdating = true;
|
||||
try {
|
||||
doRefreshUi(mayCheckReused, onExplicitAction);
|
||||
final boolean reused = mayCheckReused && checkReused();
|
||||
boolean selectionVisible = isSelectionVisible();
|
||||
boolean itemsChanged = updateList(onExplicitAction, reused);
|
||||
if (isVisible()) {
|
||||
LOG.assertTrue(!ApplicationManager.getApplication().isUnitTestMode());
|
||||
myUi.refreshUi(selectionVisible, itemsChanged, reused, onExplicitAction);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
myUpdating = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void doRefreshUi(boolean mayCheckReused, boolean onExplicitAction) {
|
||||
final boolean reused = mayCheckReused && checkReused();
|
||||
|
||||
boolean selectionVisible = isSelectionVisible();
|
||||
|
||||
boolean itemsChanged = updateList(onExplicitAction, reused);
|
||||
|
||||
if (isVisible()) {
|
||||
LOG.assertTrue(!ApplicationManager.getApplication().isUnitTestMode());
|
||||
|
||||
if (myEditor.getComponent().getRootPane() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateScrollbarVisibility();
|
||||
|
||||
if (myResizePending || itemsChanged) {
|
||||
myMaximumHeight = Integer.MAX_VALUE;
|
||||
}
|
||||
Rectangle rectangle = calculatePosition();
|
||||
myMaximumHeight = rectangle.height;
|
||||
|
||||
if (myResizePending || itemsChanged) {
|
||||
myResizePending = false;
|
||||
pack();
|
||||
}
|
||||
HintManagerImpl.updateLocation(this, myEditor, rectangle.getLocation());
|
||||
|
||||
if (reused || selectionVisible || onExplicitAction) {
|
||||
ensureSelectionVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateLookupLocation() {
|
||||
Rectangle rectangle = calculatePosition();
|
||||
myMaximumHeight = rectangle.height;
|
||||
HintManagerImpl.updateLocation(this, myEditor, rectangle.getLocation());
|
||||
}
|
||||
|
||||
private void updateScrollbarVisibility() {
|
||||
boolean showSorting = isCompletion() && getListModel().getSize() >= 3;
|
||||
mySortingLabel.setVisible(showSorting);
|
||||
myScrollPane.setVerticalScrollBarPolicy(showSorting ? ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS : ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
|
||||
}
|
||||
|
||||
public void markReused() {
|
||||
myAdComponent.clearAdvertisements();
|
||||
synchronized (myList) {
|
||||
@@ -1368,7 +1121,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
if (ApplicationManager.getApplication().isDispatchThread()) {
|
||||
runnable.run();
|
||||
} else {
|
||||
ApplicationManager.getApplication().invokeLater(runnable, myModalityState);
|
||||
ApplicationManager.getApplication().invokeLater(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1406,155 +1159,12 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
|
||||
return true;
|
||||
}
|
||||
|
||||
private class LookupLayeredPane extends JBLayeredPane {
|
||||
final JPanel mainPanel = new JPanel(new BorderLayout());
|
||||
|
||||
private LookupLayeredPane() {
|
||||
add(mainPanel, 0, 0);
|
||||
add(myIconPanel, 42, 0);
|
||||
add(mySortingLabel, 10, 0);
|
||||
|
||||
setLayout(new AbstractLayoutManager() {
|
||||
@Override
|
||||
public Dimension preferredLayoutSize(@Nullable Container parent) {
|
||||
int maxCellWidth = myLookupTextWidth + myCellRenderer.getIconIndent();
|
||||
int scrollBarWidth = myScrollPane.getPreferredSize().width - myScrollPane.getViewport().getPreferredSize().width;
|
||||
int listWidth = Math.min(scrollBarWidth + maxCellWidth, UISettings.getInstance().MAX_LOOKUP_WIDTH2);
|
||||
|
||||
Dimension adSize = myAdComponent.getAdComponent().getPreferredSize();
|
||||
|
||||
int panelHeight = myList.getPreferredScrollableViewportSize().height + adSize.height;
|
||||
if (getListModel().getSize() > myList.getVisibleRowCount() && myList.getVisibleRowCount() >= 5) {
|
||||
panelHeight -= myList.getFixedCellHeight() / 2;
|
||||
}
|
||||
return new Dimension(Math.max(listWidth, adSize.width), Math.min(panelHeight, myMaximumHeight));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void layoutContainer(Container parent) {
|
||||
Dimension size = getSize();
|
||||
mainPanel.setSize(size);
|
||||
mainPanel.validate();
|
||||
|
||||
if (!myResizePending) {
|
||||
Dimension preferredSize = preferredLayoutSize(null);
|
||||
if (preferredSize.width != size.width) {
|
||||
UISettings.getInstance().MAX_LOOKUP_WIDTH2 = Math.max(500, size.width);
|
||||
}
|
||||
|
||||
int listHeight = myList.getLastVisibleIndex() - myList.getFirstVisibleIndex() + 1;
|
||||
if (listHeight != getListModel().getSize() && listHeight != myList.getVisibleRowCount() && preferredSize.height != size.height) {
|
||||
UISettings.getInstance().MAX_LOOKUP_LIST_HEIGHT = Math.max(5, listHeight);
|
||||
}
|
||||
}
|
||||
|
||||
myList.setFixedCellWidth(myScrollPane.getViewport().getWidth());
|
||||
layoutStatusIcons();
|
||||
layoutHint();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void layoutStatusIcons() {
|
||||
int adHeight = myAdComponent.getAdComponent().getPreferredSize().height;
|
||||
Dimension buttonSize = adHeight > 0 || !mySortingLabel.isVisible() ? new Dimension(0, 0) : new Dimension(
|
||||
AllIcons.Ide.LookupRelevance.getIconWidth(), AllIcons.Ide.LookupRelevance.getIconHeight());
|
||||
myScrollBarIncreaseButton.setPreferredSize(buttonSize);
|
||||
myScrollBarIncreaseButton.setMinimumSize(buttonSize);
|
||||
myScrollBarIncreaseButton.setMaximumSize(buttonSize);
|
||||
JScrollBar scrollBar = myScrollPane.getVerticalScrollBar();
|
||||
scrollBar.revalidate();
|
||||
scrollBar.repaint();
|
||||
|
||||
final Dimension iconSize = myProcessIcon.getPreferredSize();
|
||||
myIconPanel.setBounds(getWidth() - iconSize.width - (scrollBar.isVisible() ? scrollBar.getWidth() : 0), 0, iconSize.width, iconSize.height);
|
||||
|
||||
final Dimension sortSize = mySortingLabel.getPreferredSize();
|
||||
final Point sbLocation = SwingUtilities.convertPoint(scrollBar, 0, 0, myLayeredPane);
|
||||
|
||||
final int sortHeight = Math.max(adHeight, mySortingLabel.getPreferredSize().height);
|
||||
mySortingLabel.setBounds(sbLocation.x, getHeight() - sortHeight, sortSize.width, sortHeight);
|
||||
}
|
||||
|
||||
void layoutHint() {
|
||||
if (myElementHint != null && getCurrentItem() != null) {
|
||||
final Rectangle bounds = getCurrentItemBounds();
|
||||
myElementHint.setSize(myElementHint.getPreferredSize());
|
||||
|
||||
JScrollBar sb = myScrollPane.getVerticalScrollBar();
|
||||
int x = bounds.x + bounds.width - myElementHint.getWidth() + (sb.isVisible() ? sb.getWidth() : 0);
|
||||
x = Math.min(x, getWidth() - myElementHint.getWidth());
|
||||
myElementHint.setLocation(new Point(x, bounds.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class LookupHint extends JLabel {
|
||||
private final Border INACTIVE_BORDER = BorderFactory.createEmptyBorder(2, 2, 2, 2);
|
||||
private final Border ACTIVE_BORDER = BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.BLACK, 1), BorderFactory.createEmptyBorder(1, 1, 1, 1));
|
||||
private LookupHint() {
|
||||
setOpaque(false);
|
||||
setBorder(INACTIVE_BORDER);
|
||||
setIcon(AllIcons.Actions.IntentionBulb);
|
||||
String acceleratorsText = KeymapUtil.getFirstKeyboardShortcutText(
|
||||
ActionManager.getInstance().getAction(IdeActions.ACTION_SHOW_INTENTION_ACTIONS));
|
||||
if (acceleratorsText.length() > 0) {
|
||||
setToolTipText(CodeInsightBundle.message("lightbulb.tooltip", acceleratorsText));
|
||||
}
|
||||
|
||||
addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
setBorder(ACTIVE_BORDER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e) {
|
||||
setBorder(INACTIVE_BORDER);
|
||||
}
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if (!e.isPopupTrigger() && e.getButton() == MouseEvent.BUTTON1) {
|
||||
showElementActions();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public Map<LookupElement,StringBuilder> getRelevanceStrings() {
|
||||
synchronized (myList) {
|
||||
return myPresentableArranger.getRelevanceStrings();
|
||||
}
|
||||
}
|
||||
|
||||
private class ChangeLookupSorting extends ClickListener {
|
||||
|
||||
@Override
|
||||
public boolean onClick(@NotNull MouseEvent e, int clickCount) {
|
||||
DataContext context = DataManager.getInstance().getDataContext(mySortingLabel);
|
||||
DefaultActionGroup group = new DefaultActionGroup();
|
||||
group.add(createSortingAction(true));
|
||||
group.add(createSortingAction(false));
|
||||
JBPopupFactory.getInstance().createActionGroupPopup("Change sorting", group, context, JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, false).showInBestPositionFor(
|
||||
context);
|
||||
return true;
|
||||
}
|
||||
|
||||
private AnAction createSortingAction(boolean checked) {
|
||||
boolean currentSetting = UISettings.getInstance().SORT_LOOKUP_ELEMENTS_LEXICOGRAPHICALLY;
|
||||
final boolean newSetting = checked ? currentSetting : !currentSetting;
|
||||
return new AnAction(newSetting ? "Sort lexicographically" : "Sort by relevance", null, checked ? PlatformIcons.CHECK_ICON : null) {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_CHANGE_SORTING);
|
||||
UISettings.getInstance().SORT_LOOKUP_ELEMENTS_LEXICOGRAPHICALLY = newSetting;
|
||||
updateSorting();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public enum FocusDegree { FOCUSED, SEMI_FOCUSED, UNFOCUSED }
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,466 @@
|
||||
/*
|
||||
* 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.codeInsight.lookup.impl;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.codeInsight.completion.CodeCompletionFeatures;
|
||||
import com.intellij.codeInsight.completion.ShowHideIntentionIconLookupAction;
|
||||
import com.intellij.codeInsight.hint.HintManagerImpl;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementAction;
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.ide.ui.UISettings;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.LogicalPosition;
|
||||
import com.intellij.openapi.keymap.KeymapUtil;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.util.ActionCallback;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.wm.IdeFocusManager;
|
||||
import com.intellij.ui.ClickListener;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.ScreenUtil;
|
||||
import com.intellij.ui.components.JBLayeredPane;
|
||||
import com.intellij.ui.components.JBList;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
import com.intellij.util.ui.AbstractLayoutManager;
|
||||
import com.intellij.util.ui.AsyncProcessIcon;
|
||||
import com.intellij.util.ui.ButtonlessScrollBarUI;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.LineBorder;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
class LookupUi {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.lookup.impl.LookupUi");
|
||||
private final LookupImpl myLookup;
|
||||
private final Advertiser myAdvertiser;
|
||||
private final JBList myList;
|
||||
private final Project myProject;
|
||||
private final ModalityState myModalityState;
|
||||
private final Alarm myHintAlarm = new Alarm();
|
||||
private final JLabel mySortingLabel = new JLabel();
|
||||
private final JScrollPane myScrollPane;
|
||||
private final JButton myScrollBarIncreaseButton;
|
||||
private final AsyncProcessIcon myProcessIcon = new AsyncProcessIcon("Completion progress");
|
||||
private final JPanel myIconPanel = new JPanel(new BorderLayout());
|
||||
private final LookupLayeredPane myLayeredPane = new LookupLayeredPane();
|
||||
|
||||
private LookupHint myElementHint = null;
|
||||
private int myMaximumHeight = Integer.MAX_VALUE;
|
||||
private Boolean myPositionedAbove = null;
|
||||
|
||||
LookupUi(LookupImpl lookup, Advertiser advertiser, JBList list, Project project) {
|
||||
myLookup = lookup;
|
||||
myAdvertiser = advertiser;
|
||||
myList = list;
|
||||
myProject = project;
|
||||
|
||||
myIconPanel.setVisible(false);
|
||||
myIconPanel.setBackground(Color.LIGHT_GRAY);
|
||||
myIconPanel.add(myProcessIcon);
|
||||
|
||||
JComponent adComponent = advertiser.getAdComponent();
|
||||
adComponent.setBorder(new EmptyBorder(0, 1, 1, 2 + AllIcons.Ide.LookupRelevance.getIconWidth()));
|
||||
myLayeredPane.mainPanel.add(adComponent, BorderLayout.SOUTH);
|
||||
|
||||
myScrollBarIncreaseButton = new JButton();
|
||||
myScrollBarIncreaseButton.setFocusable(false);
|
||||
myScrollBarIncreaseButton.setRequestFocusEnabled(false);
|
||||
|
||||
myScrollPane = new JBScrollPane(lookup.getList());
|
||||
myScrollPane.setViewportBorder(new EmptyBorder(0, 0, 0, 0));
|
||||
myScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
myScrollPane.getVerticalScrollBar().setPreferredSize(new Dimension(13, -1));
|
||||
myScrollPane.getVerticalScrollBar().setUI(new ButtonlessScrollBarUI() {
|
||||
@Override
|
||||
protected JButton createIncreaseButton(int orientation) {
|
||||
return myScrollBarIncreaseButton;
|
||||
}
|
||||
});
|
||||
lookup.getComponent().add(myLayeredPane, BorderLayout.CENTER);
|
||||
|
||||
//IDEA-82111
|
||||
fixMouseCheaters();
|
||||
|
||||
myLayeredPane.mainPanel.add(myScrollPane, BorderLayout.CENTER);
|
||||
myScrollPane.setBorder(null);
|
||||
|
||||
mySortingLabel.setBorder(new LineBorder(new JBColor(Color.LIGHT_GRAY, JBColor.background())));
|
||||
mySortingLabel.setOpaque(true);
|
||||
new ChangeLookupSorting().installOn(mySortingLabel);
|
||||
updateSorting();
|
||||
myModalityState = ModalityState.stateForComponent(myLookup.getComponent());
|
||||
|
||||
addListeners();
|
||||
|
||||
updateScrollbarVisibility();
|
||||
|
||||
Disposer.register(lookup, myProcessIcon);
|
||||
Disposer.register(lookup, myHintAlarm);
|
||||
}
|
||||
|
||||
private void addListeners() {
|
||||
myList.addListSelectionListener(new ListSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
myHintAlarm.cancelAllRequests();
|
||||
|
||||
final LookupElement item = myLookup.getCurrentItem();
|
||||
if (item != null) {
|
||||
updateHint(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
final Alarm alarm = new Alarm(myLookup);
|
||||
myScrollPane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
|
||||
@Override
|
||||
public void adjustmentValueChanged(AdjustmentEvent e) {
|
||||
if (myLookup.myUpdating || myLookup.isLookupDisposed()) return;
|
||||
alarm.addRequest(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myLookup.refreshUi(false, false);
|
||||
}
|
||||
}, 300, myModalityState);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateScrollbarVisibility() {
|
||||
boolean showSorting = myLookup.isCompletion() && myList.getModel().getSize() >= 3;
|
||||
mySortingLabel.setVisible(showSorting);
|
||||
myScrollPane.setVerticalScrollBarPolicy(showSorting ? ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS : ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
|
||||
}
|
||||
|
||||
private void updateHint(@NotNull final LookupElement item) {
|
||||
myLookup.checkValid();
|
||||
if (myElementHint != null) {
|
||||
myLayeredPane.remove(myElementHint);
|
||||
myElementHint = null;
|
||||
final JRootPane rootPane = myLookup.getComponent().getRootPane();
|
||||
if (rootPane != null) {
|
||||
rootPane.revalidate();
|
||||
rootPane.repaint();
|
||||
}
|
||||
}
|
||||
if (!myLookup.isFocused()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Collection<LookupElementAction> actions = myLookup.getActionsFor(item);
|
||||
if (!actions.isEmpty()) {
|
||||
myHintAlarm.addRequest(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!ShowHideIntentionIconLookupAction.shouldShowLookupHint() ||
|
||||
((CompletionExtender)myList.getExpandableItemsHandler()).isShowing()) {
|
||||
return;
|
||||
}
|
||||
myElementHint = new LookupHint();
|
||||
myLayeredPane.add(myElementHint, 20, 0);
|
||||
myLayeredPane.layoutHint();
|
||||
}
|
||||
}, 500, myModalityState);
|
||||
}
|
||||
}
|
||||
|
||||
//Yes, it's possible to move focus to the hint. It's inconvenient, it doesn't make sense, but it's possible.
|
||||
// This fix is for those jerks
|
||||
private void fixMouseCheaters() {
|
||||
myLookup.getComponent().addFocusListener(new FocusAdapter() {
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) {
|
||||
final ActionCallback done = IdeFocusManager.getInstance(myProject).requestFocus(myLookup.getEditor().getContentComponent(), true);
|
||||
IdeFocusManager.getInstance(myProject).typeAheadUntil(done);
|
||||
new Alarm(myLookup).addRequest(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!done.isDone()) {
|
||||
done.setDone();
|
||||
}
|
||||
}
|
||||
}, 300, myModalityState);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void setCalculating(final boolean calculating) {
|
||||
Runnable setVisible = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myIconPanel.setVisible(myLookup.isCalculating());
|
||||
}
|
||||
};
|
||||
if (myLookup.isCalculating()) {
|
||||
new Alarm(myLookup).addRequest(setVisible, 100, myModalityState);
|
||||
} else {
|
||||
setVisible.run();
|
||||
}
|
||||
|
||||
if (calculating) {
|
||||
myProcessIcon.resume();
|
||||
} else {
|
||||
myProcessIcon.suspend();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSorting() {
|
||||
final boolean lexi = UISettings.getInstance().SORT_LOOKUP_ELEMENTS_LEXICOGRAPHICALLY;
|
||||
mySortingLabel.setIcon(lexi ? AllIcons.Ide.LookupAlphanumeric : AllIcons.Ide.LookupRelevance);
|
||||
mySortingLabel.setToolTipText(lexi ? "Click to sort variants by relevance" : "Click to sort variants alphabetically");
|
||||
|
||||
myLookup.resort(false);
|
||||
}
|
||||
|
||||
void refreshUi(boolean selectionVisible, boolean itemsChanged, boolean reused, boolean onExplicitAction) {
|
||||
if (myLookup.getEditor().getComponent().getRootPane() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateScrollbarVisibility();
|
||||
|
||||
if (myLookup.myResizePending || itemsChanged) {
|
||||
myMaximumHeight = Integer.MAX_VALUE;
|
||||
}
|
||||
Rectangle rectangle = calculatePosition();
|
||||
myMaximumHeight = rectangle.height;
|
||||
|
||||
if (myLookup.myResizePending || itemsChanged) {
|
||||
myLookup.myResizePending = false;
|
||||
myLookup.pack();
|
||||
}
|
||||
HintManagerImpl.updateLocation(myLookup, myLookup.getEditor(), rectangle.getLocation());
|
||||
|
||||
if (reused || selectionVisible || onExplicitAction) {
|
||||
myLookup.ensureSelectionVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
boolean isPositionedAboveCaret() {
|
||||
return myPositionedAbove != null && myPositionedAbove.booleanValue();
|
||||
}
|
||||
|
||||
// in layered pane coordinate system.
|
||||
Rectangle calculatePosition() {
|
||||
Dimension dim = myLookup.getComponent().getPreferredSize();
|
||||
int lookupStart = myLookup.getLookupStart();
|
||||
Editor editor = myLookup.getEditor();
|
||||
if (lookupStart < 0 || lookupStart > editor.getDocument().getTextLength()) {
|
||||
LOG.error(lookupStart + "; offset=" + editor.getCaretModel().getOffset() + "; element=" +
|
||||
myLookup.getPsiElement());
|
||||
}
|
||||
|
||||
LogicalPosition pos = editor.offsetToLogicalPosition(lookupStart);
|
||||
Point location = editor.logicalPositionToXY(pos);
|
||||
location.y += editor.getLineHeight();
|
||||
location.x -= myLookup.myCellRenderer.getIconIndent() + myLookup.getComponent().getInsets().left;
|
||||
|
||||
SwingUtilities.convertPointToScreen(location, editor.getContentComponent());
|
||||
final Rectangle screenRectangle = ScreenUtil.getScreenRectangle(location);
|
||||
|
||||
if (!isPositionedAboveCaret()) {
|
||||
int shiftLow = screenRectangle.height - (location.y + dim.height);
|
||||
myPositionedAbove = shiftLow < 0 && shiftLow < location.y - dim.height && location.y >= dim.height;
|
||||
}
|
||||
if (isPositionedAboveCaret()) {
|
||||
location.y -= dim.height + editor.getLineHeight();
|
||||
if (pos.line == 0) {
|
||||
location.y += 1;
|
||||
//otherwise the lookup won't intersect with the editor and every editor's resize (e.g. after typing in console) will close the lookup
|
||||
}
|
||||
}
|
||||
|
||||
if (!screenRectangle.contains(location)) {
|
||||
location = ScreenUtil.findNearestPointOnBorder(screenRectangle, location);
|
||||
}
|
||||
|
||||
final JRootPane rootPane = editor.getComponent().getRootPane();
|
||||
if (rootPane == null) {
|
||||
LOG.error("editor.disposed=" + editor.isDisposed() + "; lookup.disposed=" + myLookup.isLookupDisposed() + "; editorShowing=" + editor.getContentComponent().isShowing());
|
||||
}
|
||||
Rectangle candidate = new Rectangle(location, dim);
|
||||
ScreenUtil.cropRectangleToFitTheScreen(candidate);
|
||||
|
||||
SwingUtilities.convertPointFromScreen(location, rootPane.getLayeredPane());
|
||||
myMaximumHeight = candidate.height;
|
||||
return new Rectangle(location.x, location.y, dim.width, candidate.height);
|
||||
}
|
||||
|
||||
private class LookupLayeredPane extends JBLayeredPane {
|
||||
final JPanel mainPanel = new JPanel(new BorderLayout());
|
||||
|
||||
private LookupLayeredPane() {
|
||||
add(mainPanel, 0, 0);
|
||||
add(myIconPanel, 42, 0);
|
||||
add(mySortingLabel, 10, 0);
|
||||
|
||||
setLayout(new AbstractLayoutManager() {
|
||||
@Override
|
||||
public Dimension preferredLayoutSize(@Nullable Container parent) {
|
||||
int maxCellWidth = myLookup.myLookupTextWidth + myLookup.myCellRenderer.getIconIndent();
|
||||
int scrollBarWidth = myScrollPane.getPreferredSize().width - myScrollPane.getViewport().getPreferredSize().width;
|
||||
int listWidth = Math.min(scrollBarWidth + maxCellWidth, UISettings.getInstance().MAX_LOOKUP_WIDTH2);
|
||||
|
||||
Dimension adSize = myAdvertiser.getAdComponent().getPreferredSize();
|
||||
|
||||
int panelHeight = myList.getPreferredScrollableViewportSize().height + adSize.height;
|
||||
if (myList.getModel().getSize() > myList.getVisibleRowCount() && myList.getVisibleRowCount() >= 5) {
|
||||
panelHeight -= myList.getFixedCellHeight() / 2;
|
||||
}
|
||||
return new Dimension(Math.max(listWidth, adSize.width), Math.min(panelHeight, myMaximumHeight));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void layoutContainer(Container parent) {
|
||||
Dimension size = getSize();
|
||||
mainPanel.setSize(size);
|
||||
mainPanel.validate();
|
||||
|
||||
if (!myLookup.myResizePending) {
|
||||
Dimension preferredSize = preferredLayoutSize(null);
|
||||
if (preferredSize.width != size.width) {
|
||||
UISettings.getInstance().MAX_LOOKUP_WIDTH2 = Math.max(500, size.width);
|
||||
}
|
||||
|
||||
int listHeight = myList.getLastVisibleIndex() - myList.getFirstVisibleIndex() + 1;
|
||||
if (listHeight != myList.getModel().getSize() && listHeight != myList.getVisibleRowCount() && preferredSize.height != size.height) {
|
||||
UISettings.getInstance().MAX_LOOKUP_LIST_HEIGHT = Math.max(5, listHeight);
|
||||
}
|
||||
}
|
||||
|
||||
myList.setFixedCellWidth(myScrollPane.getViewport().getWidth());
|
||||
layoutStatusIcons();
|
||||
layoutHint();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void layoutStatusIcons() {
|
||||
int adHeight = myAdvertiser.getAdComponent().getPreferredSize().height;
|
||||
Dimension buttonSize = adHeight > 0 || !mySortingLabel.isVisible() ? new Dimension(0, 0) : new Dimension(
|
||||
AllIcons.Ide.LookupRelevance.getIconWidth(), AllIcons.Ide.LookupRelevance.getIconHeight());
|
||||
myScrollBarIncreaseButton.setPreferredSize(buttonSize);
|
||||
myScrollBarIncreaseButton.setMinimumSize(buttonSize);
|
||||
myScrollBarIncreaseButton.setMaximumSize(buttonSize);
|
||||
JScrollBar scrollBar = myScrollPane.getVerticalScrollBar();
|
||||
scrollBar.revalidate();
|
||||
scrollBar.repaint();
|
||||
|
||||
final Dimension iconSize = myProcessIcon.getPreferredSize();
|
||||
myIconPanel.setBounds(getWidth() - iconSize.width - (scrollBar.isVisible() ? scrollBar.getWidth() : 0), 0, iconSize.width, iconSize.height);
|
||||
|
||||
final Dimension sortSize = mySortingLabel.getPreferredSize();
|
||||
final Point sbLocation = SwingUtilities.convertPoint(scrollBar, 0, 0, myLayeredPane);
|
||||
|
||||
final int sortHeight = Math.max(adHeight, mySortingLabel.getPreferredSize().height);
|
||||
mySortingLabel.setBounds(sbLocation.x, getHeight() - sortHeight, sortSize.width, sortHeight);
|
||||
}
|
||||
|
||||
void layoutHint() {
|
||||
if (myElementHint != null && myLookup.getCurrentItem() != null) {
|
||||
final Rectangle bounds = myLookup.getCurrentItemBounds();
|
||||
myElementHint.setSize(myElementHint.getPreferredSize());
|
||||
|
||||
JScrollBar sb = myScrollPane.getVerticalScrollBar();
|
||||
int x = bounds.x + bounds.width - myElementHint.getWidth() + (sb.isVisible() ? sb.getWidth() : 0);
|
||||
x = Math.min(x, getWidth() - myElementHint.getWidth());
|
||||
myElementHint.setLocation(new Point(x, bounds.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class LookupHint extends JLabel {
|
||||
private final Border INACTIVE_BORDER = BorderFactory.createEmptyBorder(2, 2, 2, 2);
|
||||
private final Border ACTIVE_BORDER = BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.BLACK, 1), BorderFactory.createEmptyBorder(1, 1, 1, 1));
|
||||
private LookupHint() {
|
||||
setOpaque(false);
|
||||
setBorder(INACTIVE_BORDER);
|
||||
setIcon(AllIcons.Actions.IntentionBulb);
|
||||
String acceleratorsText = KeymapUtil.getFirstKeyboardShortcutText(
|
||||
ActionManager.getInstance().getAction(IdeActions.ACTION_SHOW_INTENTION_ACTIONS));
|
||||
if (acceleratorsText.length() > 0) {
|
||||
setToolTipText(CodeInsightBundle.message("lightbulb.tooltip", acceleratorsText));
|
||||
}
|
||||
|
||||
addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
setBorder(ACTIVE_BORDER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e) {
|
||||
setBorder(INACTIVE_BORDER);
|
||||
}
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if (!e.isPopupTrigger() && e.getButton() == MouseEvent.BUTTON1) {
|
||||
myLookup.showElementActions();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private class ChangeLookupSorting extends ClickListener {
|
||||
|
||||
@Override
|
||||
public boolean onClick(@NotNull MouseEvent e, int clickCount) {
|
||||
DataContext context = DataManager.getInstance().getDataContext(mySortingLabel);
|
||||
DefaultActionGroup group = new DefaultActionGroup();
|
||||
group.add(createSortingAction(true));
|
||||
group.add(createSortingAction(false));
|
||||
JBPopupFactory.getInstance().createActionGroupPopup("Change sorting", group, context, JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, false).showInBestPositionFor(
|
||||
context);
|
||||
return true;
|
||||
}
|
||||
|
||||
private AnAction createSortingAction(boolean checked) {
|
||||
boolean currentSetting = UISettings.getInstance().SORT_LOOKUP_ELEMENTS_LEXICOGRAPHICALLY;
|
||||
final boolean newSetting = checked ? currentSetting : !currentSetting;
|
||||
return new DumbAwareAction(newSetting ? "Sort lexicographically" : "Sort by relevance", null, checked ? PlatformIcons.CHECK_ICON : null) {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_CHANGE_SORTING);
|
||||
UISettings.getInstance().SORT_LOOKUP_ELEMENTS_LEXICOGRAPHICALLY = newSetting;
|
||||
updateSorting();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiDirectory;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -31,8 +32,10 @@ public interface CreateFromTemplateHandler {
|
||||
ExtensionPointName<CreateFromTemplateHandler> EP_NAME = ExtensionPointName.create("com.intellij.createFromTemplateHandler");
|
||||
|
||||
boolean handlesTemplate(FileTemplate template);
|
||||
|
||||
@NotNull
|
||||
PsiElement createFromTemplate(Project project, PsiDirectory directory, final String fileName, FileTemplate template, String templateText,
|
||||
Map<String, Object> props) throws IncorrectOperationException;
|
||||
@NotNull Map<String, Object> props) throws IncorrectOperationException;
|
||||
|
||||
boolean canCreate(final PsiDirectory[] dirs);
|
||||
boolean isNameRequired();
|
||||
|
||||
+3
-1
@@ -27,6 +27,7 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiFileFactory;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -39,10 +40,11 @@ public class DefaultCreateFromTemplateHandler implements CreateFromTemplateHandl
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement createFromTemplate(final Project project, final PsiDirectory directory, String fileName, final FileTemplate template,
|
||||
final String templateText,
|
||||
final Map<String, Object> props) throws IncorrectOperationException {
|
||||
@NotNull final Map<String, Object> props) throws IncorrectOperationException {
|
||||
fileName = checkAppendExtension(fileName, template);
|
||||
|
||||
if (FileTypeManager.getInstance().isFileIgnored(fileName)) {
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ public class NetBeansCustomFoldingProvider extends CustomFoldingProvider {
|
||||
|
||||
@Override
|
||||
public String getPlaceholderText(String elementText) {
|
||||
String customText = elementText.replaceFirst(".*desc\\s*=\\s*\"(.*)\".*", "$1").trim();
|
||||
String customText = elementText.replaceFirst(".*desc\\s*=\\s*\"([^\"]*)\".*", "$1").trim();
|
||||
return customText.isEmpty() ? "..." : customText;
|
||||
}
|
||||
|
||||
|
||||
-1
@@ -89,7 +89,6 @@ public class HtmlTransferableData extends AbstractSyntaxAwareReaderTransferableD
|
||||
}
|
||||
finally {
|
||||
myResultBuffer = null;
|
||||
myRawText = null;
|
||||
myColorRegistry = null;
|
||||
myFontNameRegistry = null;
|
||||
myColors.clear();
|
||||
|
||||
@@ -44,7 +44,8 @@ public class InstalledPackagesPanel extends JPanel {
|
||||
|
||||
protected final JBTable myPackagesTable;
|
||||
private DefaultTableModel myPackagesTableModel;
|
||||
protected PackageManagementService myPackageManagementService;
|
||||
// can be accessed from any thread
|
||||
protected volatile PackageManagementService myPackageManagementService;
|
||||
protected final Project myProject;
|
||||
protected final PackagesNotificationPanel myNotificationArea;
|
||||
protected final List<Consumer<Sdk>> myPathChangedListeners = ContainerUtil.createLockFreeCopyOnWriteList();
|
||||
@@ -424,7 +425,7 @@ public class InstalledPackagesPanel extends JPanel {
|
||||
final boolean shouldFetchLatestVersionsForOnlyInstalledPackages = shouldFetchLatestVersionsForOnlyInstalledPackages();
|
||||
if (cache.isEmpty()) {
|
||||
if (!shouldFetchLatestVersionsForOnlyInstalledPackages) {
|
||||
refreshLatestVersions();
|
||||
refreshLatestVersions(packageManagementService);
|
||||
}
|
||||
}
|
||||
UIUtil.invokeLaterIfNeeded(new Runnable() {
|
||||
@@ -514,28 +515,30 @@ public class InstalledPackagesPanel extends JPanel {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void refreshLatestVersions() {
|
||||
private void refreshLatestVersions(@NotNull final PackageManagementService packageManagementService) {
|
||||
final Application application = ApplicationManager.getApplication();
|
||||
application.executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
List<RepoPackage> packages = myPackageManagementService.reloadAllPackages();
|
||||
final Map<String, RepoPackage> packageMap = buildNameToPackageMap(packages);
|
||||
application.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i != myPackagesTableModel.getRowCount(); ++i) {
|
||||
final InstalledPackage pyPackage = (InstalledPackage)myPackagesTableModel.getValueAt(i, 0);
|
||||
final RepoPackage repoPackage = packageMap.get(pyPackage.getName());
|
||||
myPackagesTableModel.setValueAt(repoPackage == null ? null : repoPackage.getLatestVersion(), i, 2);
|
||||
if (packageManagementService == myPackageManagementService) {
|
||||
try {
|
||||
List<RepoPackage> packages = packageManagementService.reloadAllPackages();
|
||||
final Map<String, RepoPackage> packageMap = buildNameToPackageMap(packages);
|
||||
application.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i != myPackagesTableModel.getRowCount(); ++i) {
|
||||
final InstalledPackage pyPackage = (InstalledPackage)myPackagesTableModel.getValueAt(i, 0);
|
||||
final RepoPackage repoPackage = packageMap.get(pyPackage.getName());
|
||||
myPackagesTableModel.setValueAt(repoPackage == null ? null : repoPackage.getLatestVersion(), i, 2);
|
||||
}
|
||||
myPackagesTable.setPaintBusy(false);
|
||||
}
|
||||
myPackagesTable.setPaintBusy(false);
|
||||
}
|
||||
}, ModalityState.stateForComponent(myPackagesTable));
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
myPackagesTable.setPaintBusy(false);
|
||||
}, ModalityState.stateForComponent(myPackagesTable));
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
myPackagesTable.setPaintBusy(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+18
-2
@@ -22,7 +22,7 @@ import java.util.Map;
|
||||
* @author yole
|
||||
*/
|
||||
public class PackagesNotificationPanel {
|
||||
private final JEditorPane myEditorPane = new JEditorPane();
|
||||
private final JEditorPane myEditorPane = new MyNotificationPane();
|
||||
private final Project myProject;
|
||||
private final Map<String, Runnable> myLinkHandlers = new HashMap<String, Runnable>();
|
||||
private String myErrorTitle;
|
||||
@@ -91,6 +91,10 @@ public class PackagesNotificationPanel {
|
||||
myLinkHandlers.put(key, handler);
|
||||
}
|
||||
|
||||
public void removeAllLinkHandlers() {
|
||||
myLinkHandlers.clear();
|
||||
}
|
||||
|
||||
public JComponent getComponent() {
|
||||
return myEditorPane;
|
||||
}
|
||||
@@ -101,7 +105,8 @@ public class PackagesNotificationPanel {
|
||||
|
||||
private void showContent(String text, final Color background) {
|
||||
myEditorPane.removeAll();
|
||||
myEditorPane.setText(UIUtil.toHtml(text));
|
||||
String htmlText = text.startsWith("<html>") ? text : UIUtil.toHtml(text);
|
||||
myEditorPane.setText(htmlText);
|
||||
myEditorPane.setBackground(background);
|
||||
myEditorPane.setVisible(true);
|
||||
myErrorTitle = null;
|
||||
@@ -125,4 +130,15 @@ public class PackagesNotificationPanel {
|
||||
public boolean hasLinkHandler(String key) {
|
||||
return myLinkHandlers.containsKey(key);
|
||||
}
|
||||
|
||||
private static class MyNotificationPane extends JEditorPane {
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
// This trick makes text component to carry text over to the next line
|
||||
// iff the text line width exceeds parent's width
|
||||
Dimension dimension = super.getPreferredSize();
|
||||
dimension.width = 0;
|
||||
return dimension;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-5
@@ -29,11 +29,11 @@ import java.awt.event.MouseEvent;
|
||||
public abstract class AbstractCustomizeWizardStep extends JPanel {
|
||||
protected static final int GAP = 20;
|
||||
|
||||
abstract String getTitle();
|
||||
protected abstract String getTitle();
|
||||
|
||||
abstract String getHTMLHeader();
|
||||
protected abstract String getHTMLHeader();
|
||||
|
||||
abstract String getHTMLFooter();
|
||||
protected abstract String getHTMLFooter();
|
||||
|
||||
private static Color getSelectionBackground() {
|
||||
return ColorUtil.mix(UIUtil.getListSelectionBackground(), UIUtil.getLabelBackground(), .75);
|
||||
@@ -46,18 +46,23 @@ public abstract class AbstractCustomizeWizardStep extends JPanel {
|
||||
return anchorButton.isSelected() ? getSelectionBackground() : super.getBackground();
|
||||
}
|
||||
};
|
||||
panel.setOpaque(true);
|
||||
panel.setOpaque(anchorButton.isSelected());
|
||||
new ClickListener() {
|
||||
@Override
|
||||
public boolean onClick(@NotNull MouseEvent event, int clickCount) {
|
||||
anchorButton.setSelected(true);
|
||||
action.run();
|
||||
return true;
|
||||
}
|
||||
}.installOn(panel);
|
||||
anchorButton.addItemListener(new ItemListener() {
|
||||
boolean curState = anchorButton.isSelected();
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
if (e.getStateChange() == ItemEvent.SELECTED && curState != anchorButton.isSelected()) {
|
||||
action.run();
|
||||
}
|
||||
curState = anchorButton.isSelected();
|
||||
panel.setOpaque(curState);
|
||||
panel.repaint();
|
||||
}
|
||||
});
|
||||
@@ -67,4 +72,7 @@ public abstract class AbstractCustomizeWizardStep extends JPanel {
|
||||
Component getDefaultFocusedComponent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void beforeShown(boolean forward) {
|
||||
}
|
||||
}
|
||||
|
||||
+73
-20
@@ -16,14 +16,22 @@
|
||||
package com.intellij.ide.customize;
|
||||
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptor;
|
||||
import com.intellij.ide.plugins.PluginNode;
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
|
||||
import com.intellij.openapi.ui.VerticalFlowLayout;
|
||||
import com.intellij.openapi.updateSettings.impl.PluginDownloader;
|
||||
import com.intellij.ui.ColorUtil;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.border.CustomLineBorder;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.ui.components.labels.LinkLabel;
|
||||
import com.intellij.ui.components.labels.LinkListener;
|
||||
import com.intellij.util.ConcurrencyUtil;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.CompoundBorder;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
@@ -32,22 +40,29 @@ import java.util.Map;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardStep {
|
||||
private static ScheduledExecutorService ourService = new ScheduledThreadPoolExecutor(4, ConcurrencyUtil.newNamedThreadFactory("FeaturedPlugins", true, Thread.NORM_PRIORITY));
|
||||
private static final int COLS = 3;
|
||||
private static ScheduledExecutorService ourService = new ScheduledThreadPoolExecutor(4, ConcurrencyUtil.newNamedThreadFactory(
|
||||
"FeaturedPlugins", true, Thread.NORM_PRIORITY));
|
||||
|
||||
public CustomizeFeaturedPluginsStepPanel() {
|
||||
setLayout(new GridLayout(0, 3, GAP, GAP));
|
||||
JPanel gridPanel = new JPanel(new GridLayout(0, 3, GAP, GAP));
|
||||
public final AtomicBoolean myCanceled = new AtomicBoolean(false);
|
||||
|
||||
|
||||
public CustomizeFeaturedPluginsStepPanel() throws OfflineException {
|
||||
setLayout(new GridLayout(1, 1));
|
||||
JPanel gridPanel = new JPanel(new GridLayout(0, 3));
|
||||
JBScrollPane scrollPane =
|
||||
new JBScrollPane(gridPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
scrollPane.getVerticalScrollBar().setUnitIncrement(10);
|
||||
|
||||
Map<String, String> config = PluginGroups.getInstance().getFeaturedPlugins();
|
||||
boolean isEmptyOrOffline = true;
|
||||
List<IdeaPluginDescriptor> pluginsFromRepository = PluginGroups.getInstance().getPluginsFromRepository();
|
||||
for (Map.Entry<String, String> entry : config.entrySet()) {
|
||||
JPanel groupPanel = new JPanel(new GridBagLayout());
|
||||
GridBagConstraints gbc = new GridBagConstraints();
|
||||
gbc.insets = new Insets(0, 0, 10, 0);
|
||||
gbc.fill = GridBagConstraints.BOTH;
|
||||
gbc.anchor = GridBagConstraints.WEST;
|
||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||
@@ -61,10 +76,10 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt
|
||||
final String description = s.substring(i + 1, j);
|
||||
final String pluginId = s.substring(j + 1);
|
||||
IdeaPluginDescriptor foundDescriptor = null;
|
||||
List<IdeaPluginDescriptor> pluginsFromRepository = PluginGroups.getInstance().getPluginsFromRepository();
|
||||
for (IdeaPluginDescriptor descriptor : pluginsFromRepository) {
|
||||
if (descriptor.getPluginId().getIdString().equals(pluginId)) {
|
||||
foundDescriptor = descriptor;
|
||||
isEmptyOrOffline = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -88,13 +103,26 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt
|
||||
final JButton installButton = new JButton("Install");
|
||||
final JProgressBar progressBar = new JProgressBar(0, 100);
|
||||
progressBar.setStringPainted(true);
|
||||
buttonWrapper.add(installButton, "button");
|
||||
buttonWrapper.add(progressBar, "progress");
|
||||
JPanel progressPanel = new JPanel(new VerticalFlowLayout(true, false));
|
||||
progressPanel.add(progressBar);
|
||||
final LinkLabel cancelLink = new LinkLabel("Cancel", AllIcons.Actions.Cancel);
|
||||
JPanel linkWrapper = new JPanel(new FlowLayout(FlowLayout.CENTER));
|
||||
linkWrapper.add(cancelLink);
|
||||
progressPanel.add(linkWrapper);
|
||||
|
||||
JPanel buttonPanel = new JPanel(new VerticalFlowLayout());
|
||||
buttonPanel.add(installButton);
|
||||
|
||||
buttonWrapper.add(buttonPanel, "button");
|
||||
buttonWrapper.add(progressPanel, "progress");
|
||||
|
||||
wrapperLayout.show(buttonWrapper, "button");
|
||||
|
||||
final ProgressIndicatorBase indicator = new ProgressIndicatorBase(true) {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
myCanceled.set(false);
|
||||
super.start();
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
@@ -104,18 +132,15 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIndeterminate(boolean indeterminate) {
|
||||
super.setIndeterminate(indeterminate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processFinish() {
|
||||
super.processFinish();
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
progressBar.setString("Installed");
|
||||
wrapperLayout.show(buttonWrapper, "button");
|
||||
installButton.setEnabled(false);
|
||||
installButton.setText("Installed");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -135,11 +160,14 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
stop();
|
||||
myCanceled.set(true);
|
||||
super.cancel();
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
wrapperLayout.show(buttonWrapper, "button");
|
||||
progressBar.setValue(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -152,6 +180,7 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
indicator.start();
|
||||
PluginNode node = new PluginNode(descriptor.getPluginId());
|
||||
node.setUrl(descriptor.getUrl());
|
||||
PluginDownloader downloader = PluginDownloader.createDownloader(node);
|
||||
@@ -160,7 +189,9 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt
|
||||
indicator.processFinish();
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
onFail();
|
||||
if (!myCanceled.get()) {
|
||||
onFail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,28 +200,48 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
indicator.stop();
|
||||
wrapperLayout.show(buttonWrapper, "progress");
|
||||
progressBar.setString("Cannot download plugin");
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 0, TimeUnit.SECONDS);
|
||||
//PluginGroups.getInstance().setFeaturedPluginEnabled(pluginId, installButton.isSelected());
|
||||
}
|
||||
});
|
||||
cancelLink.setListener(new LinkListener() {
|
||||
@Override
|
||||
public void linkSelected(LinkLabel aSource, Object aLinkData) {
|
||||
indicator.cancel();
|
||||
}
|
||||
}, null);
|
||||
gbc.insets.bottom = -5;
|
||||
groupPanel.add(titleLabel, gbc);
|
||||
gbc.insets.bottom = 10;
|
||||
groupPanel.add(topicLabel, gbc);
|
||||
groupPanel.add(descriptionLabel, gbc);
|
||||
gbc.weighty = 1;
|
||||
groupPanel.add(Box.createVerticalGlue(), gbc);
|
||||
gbc.weighty = 0;
|
||||
groupPanel.add(buttonWrapper, gbc);
|
||||
gbc.weighty = 1;
|
||||
groupPanel.add(Box.createVerticalGlue(), gbc);
|
||||
groupPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
|
||||
gridPanel.add(groupPanel);
|
||||
}
|
||||
setLayout(new GridLayout(1, 1));
|
||||
int cursor = 0;
|
||||
Component[] components = gridPanel.getComponents();
|
||||
int rowCount = components.length / COLS;
|
||||
for (Component component : components) {
|
||||
((JComponent)component).setBorder(
|
||||
new CompoundBorder(new CustomLineBorder(ColorUtil.withAlpha(JBColor.foreground(), .2), 0, 0, cursor / 3 < rowCount ? 1 : 0,
|
||||
cursor % COLS != COLS - 1 ? 1 : 0) {
|
||||
@Override
|
||||
protected Color getColor() {
|
||||
return ColorUtil.withAlpha(JBColor.foreground(), .2);
|
||||
}
|
||||
}, BorderFactory.createEmptyBorder(GAP, GAP, 0, GAP)));
|
||||
cursor++;
|
||||
}
|
||||
|
||||
if (isEmptyOrOffline) throw new OfflineException();
|
||||
add(scrollPane);
|
||||
}
|
||||
|
||||
@@ -210,4 +261,6 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt
|
||||
public String getHTMLFooter() {
|
||||
return "New plugins can also be downloaded in " + CommonBundle.settingsTitle() + " | Plugins";
|
||||
}
|
||||
|
||||
static class OfflineException extends Exception {};
|
||||
}
|
||||
|
||||
@@ -70,7 +70,12 @@ public class CustomizeIDEWizardDialog extends DialogWrapper implements ActionLis
|
||||
mySteps.add(new CustomizeKeyboardSchemeStepPanel());
|
||||
}
|
||||
mySteps.add(new CustomizePluginsStepPanel());
|
||||
mySteps.add(new CustomizeFeaturedPluginsStepPanel());
|
||||
try {
|
||||
mySteps.add(new CustomizeFeaturedPluginsStepPanel());
|
||||
}
|
||||
catch (CustomizeFeaturedPluginsStepPanel.OfflineException e) {
|
||||
//skip featured step if we're offline
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+27
-17
@@ -60,20 +60,19 @@ public class CustomizePluginsStepPanel extends AbstractCustomizeWizardStep imple
|
||||
add(scrollPane, MAIN);
|
||||
add(myCustomizePanel, CUSTOMIZE);
|
||||
|
||||
//PluginManager.loadDisabledPlugins(new File(PathManager.getConfigPath()).getPath(), myDisabledPluginIds);
|
||||
//for (IdeaPluginDescriptor pluginDescriptor : myAllPlugins) {
|
||||
// if (pluginDescriptor.getPluginId().getIdString().equals("com.intellij")) {
|
||||
//// skip 'IDEA CORE' plugin
|
||||
//continue;
|
||||
//}
|
||||
// //PluginManager.initClassLoader(PluginGroups.class.getClassLoader(), (IdeaPluginDescriptorImpl)pluginDescriptor);
|
||||
//}
|
||||
Map<String, List<String>> groups = PluginGroups.getInstance().getTree();
|
||||
for (Map.Entry<String, List<String>> entry : groups.entrySet()) {
|
||||
final String group = entry.getKey();
|
||||
if (PluginGroups.CORE.equals(group)) continue;
|
||||
|
||||
JPanel groupPanel = new JPanel(new GridBagLayout());
|
||||
JPanel groupPanel = new JPanel(new GridBagLayout()) {
|
||||
@Override
|
||||
public Color getBackground() {
|
||||
Color color = UIManager.getColor("Panel.background");
|
||||
return isGroupEnabled(group)? color : ColorUtil.darker(color, 1);
|
||||
}
|
||||
};
|
||||
gridPanel.setOpaque(true);
|
||||
GridBagConstraints gbc = new GridBagConstraints();
|
||||
gbc.insets = new Insets(0, 0, 10, 0);
|
||||
gbc.fill = GridBagConstraints.BOTH;
|
||||
@@ -113,6 +112,7 @@ public class CustomizePluginsStepPanel extends AbstractCustomizeWizardStep imple
|
||||
}
|
||||
else {
|
||||
JPanel buttonsPanel = new JPanel(new GridLayout(1, 2, 10, 5));
|
||||
buttonsPanel.setOpaque(false);
|
||||
LinkLabel customizeButton = createLink(CUSTOMIZE_COMMAND + ":" + group, CUSTOMIZE_TEXT_PROVIDER);
|
||||
buttonsPanel.add(customizeButton);
|
||||
LinkLabel disableAllButton = createLink(SWITCH_COMMAND + ":" + group, getGroupSwitchTextProvider(group));
|
||||
@@ -213,22 +213,20 @@ public class CustomizePluginsStepPanel extends AbstractCustomizeWizardStep imple
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private class IdSetPanel extends JPanel {
|
||||
private class IdSetPanel extends JPanel implements LinkListener<String> {
|
||||
private JLabel myTitleLabel = new JLabel();
|
||||
private JPanel myContentPanel = new JPanel(new GridLayout(0, 3, 5, 5));
|
||||
private JButton mySaveButton = new JButton("Save Changes and Go Back");
|
||||
private String myGroup;
|
||||
|
||||
private IdSetPanel() {
|
||||
setLayout(new VerticalFlowLayout(VerticalFlowLayout.TOP, 0, GAP, true, false));
|
||||
add(myTitleLabel);
|
||||
add(myContentPanel);
|
||||
JPanel buttonPanel = new JPanel(new BorderLayout());
|
||||
buttonPanel.add(mySaveButton, BorderLayout.WEST);
|
||||
buttonPanel.add(Box.createHorizontalGlue(), BorderLayout.CENTER);
|
||||
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 25, 5));
|
||||
buttonPanel.add(mySaveButton);
|
||||
buttonPanel.add(new LinkLabel<String>("Enable All", null, this, "enable"));
|
||||
buttonPanel.add(new LinkLabel<String>("Disable All", null, this, "disable"));
|
||||
add(buttonPanel);
|
||||
mySaveButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
@@ -238,7 +236,19 @@ public class CustomizePluginsStepPanel extends AbstractCustomizeWizardStep imple
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void linkSelected(LinkLabel aSource, String command) {
|
||||
if (myGroup == null) return;
|
||||
boolean enable = "enable".equals(command);
|
||||
List<IdSet> idSets = PluginGroups.getInstance().getSets(myGroup);
|
||||
for (IdSet set : idSets) {
|
||||
PluginGroups.getInstance().setIdSetEnabled(set, enable);
|
||||
}
|
||||
CustomizePluginsStepPanel.this.repaint();
|
||||
}
|
||||
|
||||
void update(String group) {
|
||||
myGroup = group;
|
||||
myTitleLabel.setText("<html><body><h2 style=\"text-align:left;\">" + group + "</h2></body></html>");
|
||||
myContentPanel.removeAll();
|
||||
List<IdSet> idSets = PluginGroups.getInstance().getSets(group);
|
||||
|
||||
+3
-10
@@ -26,12 +26,11 @@ import com.intellij.openapi.util.IconLoader;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.util.IconUtil;
|
||||
import com.intellij.util.PlatformUtils;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -101,13 +100,6 @@ public class CustomizeUIThemeStepPanel extends AbstractCustomizeWizardStep {
|
||||
};
|
||||
label.setVerticalAlignment(SwingConstants.TOP);
|
||||
panel.add(label, BorderLayout.CENTER);
|
||||
radioButton.addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
if (e.getStateChange() != ItemEvent.SELECTED) return;
|
||||
applyLaf(lafName, CustomizeUIThemeStepPanel.this);
|
||||
}
|
||||
});
|
||||
|
||||
group.add(radioButton);
|
||||
buttonsPanel.add(panel);
|
||||
@@ -161,6 +153,7 @@ public class CustomizeUIThemeStepPanel extends AbstractCustomizeWizardStep {
|
||||
}
|
||||
Window window = SwingUtilities.getWindowAncestor(component);
|
||||
if (window != null) {
|
||||
window.setBackground(new Color(UIUtil.getPanelBackground().getRGB()));
|
||||
SwingUtilities.updateComponentTreeUI(window);
|
||||
}
|
||||
if (ApplicationManager.getApplication() != null) {
|
||||
@@ -187,7 +180,7 @@ public class CustomizeUIThemeStepPanel extends AbstractCustomizeWizardStep {
|
||||
|
||||
@Nullable
|
||||
private static UIManager.LookAndFeelInfo getLookAndFeelInfo(String name) {
|
||||
if (DEFAULT.equals(name)) return new UIManager.LookAndFeelInfo(DEFAULT, "apple.laf.AquaLookAndFeel");
|
||||
if (DEFAULT.equals(name)) return new UIManager.LookAndFeelInfo(DEFAULT, "com.apple.laf.AquaLookAndFeel");
|
||||
if (DARCULA.equals(name)) return new UIManager.LookAndFeelInfo(DARCULA, DarculaLaf.class.getName());
|
||||
if (INTELLIJ.equals(name)) return new UIManager.LookAndFeelInfo(INTELLIJ, IntelliJLaf.class.getName());
|
||||
if (ALLOY.equals(name)) return new UIManager.LookAndFeelInfo(ALLOY, "com.incors.plaf.alloy.AlloyIdea");
|
||||
|
||||
@@ -32,7 +32,7 @@ import java.util.*;
|
||||
|
||||
class PluginGroups {
|
||||
static final String CORE = "Core";
|
||||
private static final int MAX_DESCR_LENGTH = 80;
|
||||
private static final int MAX_DESCR_LENGTH = 50;
|
||||
|
||||
|
||||
private static PluginGroups instance = null;
|
||||
@@ -62,7 +62,7 @@ class PluginGroups {
|
||||
myPluginsFromRepository.addAll(RepositoryHelper.loadPluginsFromRepository(null));
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
//OK, it's offline
|
||||
}
|
||||
PluginManager.loadDisabledPlugins(new File(PathManager.getConfigPath()).getPath(), myDisabledPluginIds);
|
||||
|
||||
|
||||
+2
-2
@@ -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.
|
||||
@@ -24,7 +24,7 @@ import javax.swing.*;
|
||||
* @author Konstantin Bulenkov
|
||||
*/
|
||||
public class DarculaLookAndFeelInfo extends UIManager.LookAndFeelInfo {
|
||||
@NonNls public static final String CLASS_NAME = "idea.dark.laf.classname";
|
||||
@NonNls public static final String CLASS_NAME = DarculaLaf.class.getName();
|
||||
public DarculaLookAndFeelInfo(){
|
||||
super(IdeBundle.message("idea.dark.look.and.feel"), CLASS_NAME);
|
||||
}
|
||||
|
||||
+3
@@ -89,6 +89,9 @@ public class DarculaProgressBarUI extends BasicProgressBarUI {
|
||||
}
|
||||
area.subtract(new Area(new RoundRectangle2D.Double(0,0,w, h, 9,9)));
|
||||
((Graphics2D)g).setPaint(c.getParent().getBackground());
|
||||
if (c.isOpaque()) {
|
||||
((Graphics2D)g).fill(area);
|
||||
}
|
||||
g.drawRoundRect(1,1, w-3, h-3, 8,8);
|
||||
g.translate(0, -(c.getHeight() - h)/2);
|
||||
|
||||
|
||||
@@ -27,9 +27,9 @@ import com.intellij.openapi.project.DumbAwareRunnable;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.project.ex.ProjectManagerEx;
|
||||
import com.intellij.openapi.roots.ContentEntry;
|
||||
import com.intellij.openapi.roots.ModifiableRootModel;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.startup.StartupManager;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
@@ -199,6 +199,8 @@ public class PlatformProjectOpenProcessor extends ProjectOpenProcessor {
|
||||
@Override
|
||||
public void run() {
|
||||
ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel();
|
||||
ContentEntry[] entries = model.getContentEntries();
|
||||
if (entries.length == 1) model.removeContentEntry(entries[0]); // remove custom content entry created for temp directory
|
||||
model.addContentEntry(virtualFile);
|
||||
model.commit();
|
||||
}
|
||||
|
||||
@@ -15,14 +15,7 @@ public enum ValueType {
|
||||
ARRAY,
|
||||
NODE,
|
||||
|
||||
/**
|
||||
* undefined type.
|
||||
*/
|
||||
UNDEFINED,
|
||||
|
||||
/**
|
||||
* null type. This is a bogus type that doesn't exist in JavaScript.
|
||||
*/
|
||||
NULL;
|
||||
|
||||
private static final ValueType[] VALUE_TYPES = ValueType.values();
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.intellij.util.ReflectionUtil;
|
||||
import com.intellij.util.RetinaImage;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.WeakHashMap;
|
||||
import com.intellij.util.ui.JBImageIcon;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -33,7 +34,6 @@ import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.FilteredImageSource;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.awt.image.ImageProducer;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.reflect.Field;
|
||||
@@ -98,7 +98,7 @@ public final class IconLoader {
|
||||
|
||||
@Deprecated
|
||||
public static Icon getIcon(@NotNull final Image image) {
|
||||
return new MyImageIcon(image);
|
||||
return new JBImageIcon(image);
|
||||
}
|
||||
|
||||
public static void setUseDarkIcons(boolean useDarkIcons) {
|
||||
@@ -279,7 +279,7 @@ public final class IconLoader {
|
||||
Image img = createDisabled(image);
|
||||
if (UIUtil.isRetina()) img = RetinaImage.createFrom(img, 2, ImageLoader.ourComponent);
|
||||
|
||||
disabledIcon = new MyImageIcon(img);
|
||||
disabledIcon = new JBImageIcon(img);
|
||||
ourIcon2DisabledIcon.put(icon, disabledIcon);
|
||||
}
|
||||
return disabledIcon;
|
||||
@@ -383,19 +383,6 @@ public final class IconLoader {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MyImageIcon extends ImageIcon {
|
||||
public MyImageIcon(final Image image) {
|
||||
super(image);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final synchronized void paintIcon(final Component c, final Graphics g, final int x, final int y) {
|
||||
final ImageObserver observer = getImageObserver();
|
||||
|
||||
UIUtil.drawImage(g, getImage(), x, y, observer == null ? c : observer);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class LazyIcon implements Icon {
|
||||
private boolean myWasComputed;
|
||||
private Icon myIcon;
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.ImageObserver;
|
||||
|
||||
/**
|
||||
* HiDPI-aware image icon
|
||||
*
|
||||
* @author Konstantin Bulenkov
|
||||
*/
|
||||
public class JBImageIcon extends ImageIcon {
|
||||
public JBImageIcon(Image image) {
|
||||
super(image);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final synchronized void paintIcon(final Component c, final Graphics g, final int x, final int y) {
|
||||
final ImageObserver observer = getImageObserver();
|
||||
|
||||
UIUtil.drawImage(g, getImage(), x, y, observer == null ? c : observer);
|
||||
}
|
||||
}
|
||||
@@ -84,8 +84,7 @@ public class ContentRevisionVirtualFile extends AbstractVcsVirtualFile {
|
||||
|
||||
myModificationStamp++;
|
||||
setRevision(myContentRevision.getRevisionNumber().asString());
|
||||
final ByteBuffer byteBuffer = getCharset().encode(content);
|
||||
myContent = byteBuffer.compact().array();
|
||||
myContent = content.getBytes(getCharset());
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
public void run() {
|
||||
vcsFileSystem.fireContentsChanged(this, ContentRevisionVirtualFile.this, 0);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -62,8 +62,7 @@ public class FilePathImpl implements FilePath {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static File fileFromVirtual(VirtualFile virtualParent, final VirtualFile child, @NotNull String name) {
|
||||
private static File fileFromVirtual(VirtualFile virtualParent, final VirtualFile child, String name) {
|
||||
assert virtualParent != null || child != null;
|
||||
if (virtualParent != null) {
|
||||
return new File(virtualParent.getPath(), name);
|
||||
@@ -72,12 +71,12 @@ public class FilePathImpl implements FilePath {
|
||||
}
|
||||
|
||||
@Heavy
|
||||
public FilePathImpl(@NotNull VirtualFile virtualParent, @NotNull String name, final boolean isDirectory) {
|
||||
public FilePathImpl(@NotNull VirtualFile virtualParent, String name, final boolean isDirectory) {
|
||||
this(virtualParent, name, isDirectory, null, false);
|
||||
}
|
||||
|
||||
@Heavy
|
||||
private FilePathImpl(@NotNull VirtualFile virtualParent, @NotNull String name, final boolean isDirectory, final boolean forDeleted) {
|
||||
private FilePathImpl(@NotNull VirtualFile virtualParent, String name, final boolean isDirectory, final boolean forDeleted) {
|
||||
this(virtualParent, name, isDirectory, null, forDeleted);
|
||||
}
|
||||
|
||||
@@ -96,15 +95,15 @@ public class FilePathImpl implements FilePath {
|
||||
this(virtualFile.getParent(), virtualFile.getName(), virtualFile.isDirectory(), virtualFile, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FilePath createChild(final String subPath, final boolean isDirectory) {
|
||||
if (StringUtil.isEmptyOrSpaces(subPath)) return this;
|
||||
|
||||
VirtualFile virtualFile = getVirtualFile();
|
||||
if (virtualFile != null && subPath.indexOf('/') == -1 && subPath.indexOf('\\') == -1) {
|
||||
return new FilePathImpl(virtualFile, subPath, isDirectory, true);
|
||||
if (getVirtualFile() != null && subPath.indexOf('/') == -1 && subPath.indexOf('\\') == -1) {
|
||||
return new FilePathImpl(getVirtualFile(), subPath, isDirectory, true);
|
||||
}
|
||||
else {
|
||||
return new FilePathImpl(new File(getIOFile(), subPath), isDirectory);
|
||||
}
|
||||
return new FilePathImpl(new File(getIOFile(), subPath), isDirectory);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
@@ -115,13 +114,13 @@ public class FilePathImpl implements FilePath {
|
||||
if (!(o instanceof FilePath)) {
|
||||
return false;
|
||||
}
|
||||
if (!isSpecialName(myName) && !isSpecialName(((FilePath)o).getName()) &&
|
||||
!Comparing.equal(myName, ((FilePath)o).getName())) {
|
||||
return false;
|
||||
else {
|
||||
if (! isSpecialName(myName) && ! isSpecialName(((FilePath)o).getName()) &&
|
||||
! Comparing.equal(myName, ((FilePath)o).getName())) return false;
|
||||
return myFile.equals(((FilePath)o).getIOFile());
|
||||
}
|
||||
return myFile.equals(((FilePath)o).getIOFile());
|
||||
}
|
||||
|
||||
|
||||
private static boolean isSpecialName(final String name) {
|
||||
return ".".equals(name) || "..".equals(name);
|
||||
}
|
||||
@@ -129,29 +128,31 @@ public class FilePathImpl implements FilePath {
|
||||
@Override
|
||||
public void refresh() {
|
||||
if (myLocal) {
|
||||
VirtualFile virtualParent = getVirtualFileParent();
|
||||
myVirtualFile = virtualParent == null ? LocalFileSystem.getInstance().findFileByIoFile(myFile) : virtualParent.findChild(myName);
|
||||
if (myVirtualParent == null) {
|
||||
myVirtualFile = LocalFileSystem.getInstance().findFileByIoFile(myFile);
|
||||
}
|
||||
else {
|
||||
myVirtualFile = myVirtualParent.findChild(myName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hardRefresh() {
|
||||
if (myLocal) {
|
||||
VirtualFile virtualFile = getVirtualFile();
|
||||
if (virtualFile == null || !virtualFile.isValid()) {
|
||||
myVirtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(myFile);
|
||||
}
|
||||
if (myLocal && (myVirtualFile == null || ! myVirtualFile.isValid())) {
|
||||
myVirtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(myFile);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getPath() {
|
||||
final VirtualFile virtualFile = getVirtualFile();
|
||||
final VirtualFile virtualFile = myVirtualFile;
|
||||
if (virtualFile != null && virtualFile.isValid()) {
|
||||
return virtualFile.getPath();
|
||||
}
|
||||
return myFile.getPath();
|
||||
else {
|
||||
return myFile.getPath();
|
||||
}
|
||||
}
|
||||
|
||||
public void setIsDirectory(boolean isDirectory) {
|
||||
@@ -160,17 +161,20 @@ public class FilePathImpl implements FilePath {
|
||||
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
VirtualFile virtualFile = getVirtualFile();
|
||||
return virtualFile == null ? myIsDirectory : virtualFile.isDirectory();
|
||||
if (myVirtualFile == null) {
|
||||
return myIsDirectory;
|
||||
}
|
||||
else {
|
||||
return myVirtualFile.isDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnder(@NotNull FilePath parent, boolean strict) {
|
||||
VirtualFile virtualFile = getVirtualFile();
|
||||
if (virtualFile != null) {
|
||||
public boolean isUnder(FilePath parent, boolean strict) {
|
||||
if (myVirtualFile != null) {
|
||||
final VirtualFile parentFile = parent.getVirtualFile();
|
||||
if (parentFile != null) {
|
||||
return VfsUtilCore.isAncestor(parentFile, virtualFile, strict);
|
||||
return VfsUtilCore.isAncestor(parentFile, myVirtualFile, strict);
|
||||
}
|
||||
}
|
||||
return FileUtil.isAncestor(parent.getIOFile(), getIOFile(), strict);
|
||||
@@ -178,9 +182,8 @@ public class FilePathImpl implements FilePath {
|
||||
|
||||
@Override
|
||||
public FilePath getParentPath() {
|
||||
VirtualFile virtualParent = getVirtualFileParent();
|
||||
if (virtualParent != null && virtualParent.getParent() != null) {
|
||||
return new FilePathImpl(virtualParent);
|
||||
if (myVirtualParent != null && myVirtualParent.isValid() && myVirtualParent.getParent() != null) {
|
||||
return new FilePathImpl(myVirtualParent);
|
||||
}
|
||||
|
||||
// can't use File.getParentPath() because the path may not correspond to an actual file on disk,
|
||||
@@ -197,25 +200,19 @@ public class FilePathImpl implements FilePath {
|
||||
@Override
|
||||
@Nullable
|
||||
public VirtualFile getVirtualFile() {
|
||||
VirtualFile virtualFile = myVirtualFile;
|
||||
if (virtualFile != null && !virtualFile.isValid()) {
|
||||
myVirtualFile = virtualFile = null;
|
||||
if (myVirtualFile != null && !myVirtualFile.isValid()) {
|
||||
myVirtualFile = null;
|
||||
}
|
||||
if (virtualFile == null) {
|
||||
refresh();
|
||||
virtualFile = myVirtualFile;
|
||||
}
|
||||
return virtualFile;
|
||||
return myVirtualFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public VirtualFile getVirtualFileParent() {
|
||||
VirtualFile virtualParent = myVirtualParent;
|
||||
if (virtualParent != null && !virtualParent.isValid()) {
|
||||
myVirtualParent = virtualParent = null;
|
||||
if (myVirtualParent != null && !myVirtualParent.isValid()) {
|
||||
myVirtualParent = null;
|
||||
}
|
||||
return virtualParent;
|
||||
return myVirtualParent;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -224,7 +221,6 @@ public class FilePathImpl implements FilePath {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return myName;
|
||||
@@ -232,21 +228,21 @@ public class FilePathImpl implements FilePath {
|
||||
|
||||
@Override
|
||||
public String getPresentableUrl() {
|
||||
VirtualFile virtualFile = getVirtualFile();
|
||||
if (virtualFile == null || !virtualFile.isValid()) {
|
||||
if (myVirtualFile == null || !myVirtualFile.isValid()) {
|
||||
return myFile.getAbsolutePath();
|
||||
}
|
||||
return virtualFile.getPresentableUrl();
|
||||
else {
|
||||
return myVirtualFile.getPresentableUrl();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Document getDocument() {
|
||||
VirtualFile virtualFile = getVirtualFile();
|
||||
if (virtualFile == null || virtualFile.getFileType().isBinary()) {
|
||||
if (myVirtualFile == null || myVirtualFile.getFileType().isBinary()) {
|
||||
return null;
|
||||
}
|
||||
return FileDocumentManager.getInstance().getDocument(virtualFile);
|
||||
return FileDocumentManager.getInstance().getDocument(myVirtualFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -257,8 +253,7 @@ public class FilePathImpl implements FilePath {
|
||||
@Override
|
||||
public Charset getCharset(Project project) {
|
||||
// try to find existing virtual file
|
||||
VirtualFile virtualFile = getVirtualFile();
|
||||
VirtualFile existing = virtualFile != null && virtualFile.isValid() ? virtualFile : null;
|
||||
VirtualFile existing = myVirtualFile != null && myVirtualFile.isValid() ? myVirtualFile : null;
|
||||
if (existing == null) {
|
||||
LocalFileSystem lfs = LocalFileSystem.getInstance();
|
||||
for (File f = myFile; f != null; f = f.getParentFile()) {
|
||||
@@ -283,8 +278,7 @@ public class FilePathImpl implements FilePath {
|
||||
|
||||
@Override
|
||||
public FileType getFileType() {
|
||||
VirtualFile virtualFile = getVirtualFile();
|
||||
return virtualFile != null ? virtualFile.getFileType() : FileTypeManager.getInstance().getFileTypeByFileName(myFile.getName());
|
||||
return myVirtualFile != null ? myVirtualFile.getFileType() : FileTypeManager.getInstance().getFileTypeByFileName(myFile.getName());
|
||||
}
|
||||
|
||||
public static FilePathImpl create(VirtualFile file) {
|
||||
@@ -322,52 +316,59 @@ public class FilePathImpl implements FilePath {
|
||||
if (virtualFileParent != null) {
|
||||
return new FilePathImpl(virtualFileParent, selectedFile.getName(), isDirectory, true);
|
||||
}
|
||||
return new FilePathImpl(selectedFile, isDirectory);
|
||||
else {
|
||||
return new FilePathImpl(selectedFile, isDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
public static FilePath createOn(@NotNull String s) {
|
||||
public static FilePath createOn(String s) {
|
||||
File ioFile = new File(s);
|
||||
final LocalFileSystem localFileSystem = LocalFileSystem.getInstance();
|
||||
VirtualFile virtualFile = localFileSystem.findFileByIoFile(ioFile);
|
||||
if (virtualFile != null) {
|
||||
return new FilePathImpl(virtualFile);
|
||||
}
|
||||
VirtualFile virtualFileParent = localFileSystem.findFileByIoFile(ioFile.getParentFile());
|
||||
if (virtualFileParent == null) return null;
|
||||
return new FilePathImpl(virtualFileParent, ioFile.getName(), false);
|
||||
else {
|
||||
VirtualFile virtualFileParent = localFileSystem.findFileByIoFile(ioFile.getParentFile());
|
||||
if (virtualFileParent != null) {
|
||||
return new FilePathImpl(virtualFileParent, ioFile.getName(), false);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final Constructor<File> ourFileStringConstructor;
|
||||
static {
|
||||
// avoid filename normalization (IDEADEV-10548)
|
||||
Constructor<File> constructor = null; // new File(String, int)
|
||||
try {
|
||||
constructor = File.class.getDeclaredConstructor(String.class, int.class);
|
||||
constructor.setAccessible(true);
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
}
|
||||
ourFileStringConstructor = constructor;
|
||||
}
|
||||
private static Constructor<File> ourFileStringConstructor;
|
||||
private static boolean ourFileStringConstructorInitialized;
|
||||
|
||||
@NotNull
|
||||
public static FilePath createNonLocal(@NotNull String path, final boolean directory) {
|
||||
public static FilePath createNonLocal(String path, final boolean directory) {
|
||||
path = path.replace('/', File.separatorChar);
|
||||
File file = createIoFile(path);
|
||||
return new FilePathImpl(file, directory, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static File createIoFile(@NotNull String path) {
|
||||
if (ourFileStringConstructor != null) {
|
||||
// avoid filename normalization (IDEADEV-10548)
|
||||
if (!ourFileStringConstructorInitialized) {
|
||||
ourFileStringConstructorInitialized = true;
|
||||
try {
|
||||
return ourFileStringConstructor.newInstance(path, 1);
|
||||
ourFileStringConstructor = File.class.getDeclaredConstructor(String.class, int.class);
|
||||
ourFileStringConstructor.setAccessible(true);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// reflection call failed, try regular call
|
||||
ourFileStringConstructor = null;
|
||||
}
|
||||
}
|
||||
return new File(path);
|
||||
File file = null;
|
||||
try {
|
||||
if (ourFileStringConstructor != null) {
|
||||
file = ourFileStringConstructor.newInstance(path, 1);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// reflection call failed, try regular call
|
||||
}
|
||||
if (file == null) {
|
||||
file = new File(path);
|
||||
}
|
||||
return new FilePathImpl(file, directory, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -504,7 +504,8 @@ public class TreeModelBuilder {
|
||||
|
||||
ChangesBrowserNode parentNode = myFoldersCache.get(parentPath.getKey());
|
||||
if (parentNode == null) {
|
||||
parentNode = ChangesBrowserNode.create(myProject, new FilePathImpl(new File(parentPath.getPath()), true));
|
||||
FilePathImpl filePath = parentPath.getVf() == null ? new FilePathImpl(new File(parentPath.getPath()), true) : new FilePathImpl(parentPath.getVf());
|
||||
parentNode = ChangesBrowserNode.create(myProject, filePath);
|
||||
ChangesBrowserNode grandPa = getParentNodeFor(parentPath, policy, rootNode);
|
||||
model.insertNodeInto(parentNode, grandPa, grandPa.getChildCount());
|
||||
myFoldersCache.put(parentPath.getKey(), parentNode);
|
||||
|
||||
@@ -394,10 +394,6 @@
|
||||
<localInspection language="JAVA" shortName="AnonymousInnerClass" bundle="com.siyeh.InspectionGadgetsBundle" key="anonymous.inner.class.display.name"
|
||||
groupBundle="messages.InspectionsBundle" groupKey="group.names.class.structure" enabledByDefault="false"
|
||||
level="WARNING" implementationClass="com.siyeh.ig.classlayout.AnonymousInnerClassInspection"/>
|
||||
<localInspection language="JAVA" suppressId="ClassWithoutPackageStatement" shortName="ClassInTopLevelPackage" bundle="com.siyeh.InspectionGadgetsBundle"
|
||||
key="class.in.top.level.package.display.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.class.structure" enabledByDefault="false" level="WARNING"
|
||||
implementationClass="com.siyeh.ig.classlayout.ClassInTopLevelPackageInspection"/>
|
||||
<localInspection language="JAVA" suppressId="NonStaticInitializer" shortName="ClassInitializer" bundle="com.siyeh.InspectionGadgetsBundle"
|
||||
key="class.initializer.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.class.structure"
|
||||
enabledByDefault="false" level="WARNING" implementationClass="com.siyeh.ig.classlayout.ClassInitializerInspection"/>
|
||||
|
||||
-81
@@ -1,81 +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.siyeh.ig.classlayout;
|
||||
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiJavaFile;
|
||||
import com.intellij.psi.util.FileTypeUtils;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.psiutils.ClassUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ClassInTopLevelPackageInspectionBase extends BaseInspection {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getID() {
|
||||
return "ClassWithoutPackageStatement";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDisplayName() {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"class.in.top.level.package.display.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message(
|
||||
"class.in.top.level.package.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean buildQuickFixesOnlyForOnTheFlyErrors() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new ClassInTopLevelPackageVisitor();
|
||||
}
|
||||
|
||||
private static class ClassInTopLevelPackageVisitor
|
||||
extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitClass(@NotNull PsiClass aClass) {
|
||||
// no call to super, so that it doesn't drill down to inner classes
|
||||
if (FileTypeUtils.isInServerPageFile(aClass)) {
|
||||
return;
|
||||
}
|
||||
if (ClassUtils.isInnerClass(aClass)) {
|
||||
return;
|
||||
}
|
||||
final PsiFile file = aClass.getContainingFile();
|
||||
if (!(file instanceof PsiJavaFile)) {
|
||||
return;
|
||||
}
|
||||
if (((PsiJavaFile)file).getPackageStatement() != null) {
|
||||
return;
|
||||
}
|
||||
registerClassError(aClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-88
@@ -20,8 +20,8 @@ import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.ConstantExpressionUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
@@ -116,20 +116,19 @@ public class PointlessArithmeticExpressionInspection
|
||||
}
|
||||
else if (tokenType.equals(JavaTokenType.ASTERISK) && isZero(operand) ||
|
||||
tokenType.equals(JavaTokenType.PERC) && (isOne(operand) || EquivalenceChecker.expressionsAreEquivalent(previousOperand, operand))) {
|
||||
return PsiType.LONG.equals(polyadicExpression.getType()) ? "0L" : "0";
|
||||
}
|
||||
else if (tokenType.equals(JavaTokenType.LE) || tokenType.equals(JavaTokenType.GE) ||
|
||||
tokenType.equals(JavaTokenType.LT) || tokenType.equals(JavaTokenType.GT)) {
|
||||
return (tokenType.equals(JavaTokenType.LT) || tokenType.equals(JavaTokenType.GT)) ? "false" : "true";
|
||||
fromTarget = operands[0];
|
||||
untilTarget = operands[length - 1];
|
||||
replacement = PsiType.LONG.equals(polyadicExpression.getType()) ? "0L" : "0";
|
||||
break;
|
||||
}
|
||||
|
||||
previousOperand = operand;
|
||||
}
|
||||
return buildReplacementExpression(polyadicExpression, fromTarget, untilTarget, replacement).trim();
|
||||
return getText(polyadicExpression, fromTarget, untilTarget, replacement).trim();
|
||||
}
|
||||
|
||||
public static String buildReplacementExpression(PsiPolyadicExpression expression, PsiElement fromTarget, PsiElement untilTarget,
|
||||
String replacement) {
|
||||
public static String getText(PsiPolyadicExpression expression, PsiElement fromTarget, PsiElement untilTarget,
|
||||
@NotNull @NonNls String replacement) {
|
||||
final StringBuilder result = new StringBuilder();
|
||||
boolean stop = false;
|
||||
for (PsiElement child : expression.getChildren()) {
|
||||
@@ -198,13 +197,10 @@ public class PointlessArithmeticExpressionInspection
|
||||
if (!arithmeticTokens.contains(expression.getOperationTokenType())) {
|
||||
return;
|
||||
}
|
||||
if (ExpressionUtils.hasStringType(expression)) {
|
||||
if (ExpressionUtils.hasStringType(expression) || PsiUtilCore.hasErrorElementChild(expression)) {
|
||||
return;
|
||||
}
|
||||
final PsiExpression[] operands = expression.getOperands();
|
||||
if (operands.length < 2) {
|
||||
return;
|
||||
}
|
||||
final IElementType tokenType = expression.getOperationTokenType();
|
||||
final boolean isPointless;
|
||||
if (tokenType.equals(JavaTokenType.PLUS)) {
|
||||
@@ -222,14 +218,6 @@ public class PointlessArithmeticExpressionInspection
|
||||
else if (tokenType.equals(JavaTokenType.PERC)) {
|
||||
isPointless = modExpressionIsPointless(operands);
|
||||
}
|
||||
else if (tokenType.equals(JavaTokenType.LE) ||
|
||||
tokenType.equals(JavaTokenType.GE) ||
|
||||
tokenType.equals(JavaTokenType.GT) ||
|
||||
tokenType.equals(JavaTokenType.LT)) {
|
||||
final PsiExpression lhs = operands[0];
|
||||
final PsiExpression rhs = operands[1];
|
||||
isPointless = comparisonExpressionIsPointless(lhs, rhs, tokenType);
|
||||
}
|
||||
else {
|
||||
isPointless = false;
|
||||
}
|
||||
@@ -292,45 +280,6 @@ public class PointlessArithmeticExpressionInspection
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean comparisonExpressionIsPointless(
|
||||
PsiExpression lhs, PsiExpression rhs, IElementType comparison) {
|
||||
if (PsiType.INT.equals(lhs.getType()) &&
|
||||
PsiType.INT.equals(rhs.getType())) {
|
||||
return intComparisonIsPointless(lhs, rhs, comparison);
|
||||
}
|
||||
else if (PsiType.LONG.equals(lhs.getType()) &&
|
||||
PsiType.LONG.equals(rhs.getType())) {
|
||||
return longComparisonIsPointless(lhs, rhs, comparison);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean intComparisonIsPointless(
|
||||
PsiExpression lhs, PsiExpression rhs, IElementType comparison) {
|
||||
if (isMaxInt(lhs) || isMinInt(rhs)) {
|
||||
return JavaTokenType.GE.equals(comparison) ||
|
||||
JavaTokenType.LT.equals(comparison);
|
||||
}
|
||||
if (isMinInt(lhs) || isMaxInt(rhs)) {
|
||||
return JavaTokenType.LE.equals(comparison) ||
|
||||
JavaTokenType.GT.equals(comparison);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean longComparisonIsPointless(
|
||||
PsiExpression lhs, PsiExpression rhs, IElementType comparison) {
|
||||
if (isMaxLong(lhs) || isMinLong(rhs)) {
|
||||
return JavaTokenType.GE.equals(comparison) ||
|
||||
JavaTokenType.LT.equals(comparison);
|
||||
}
|
||||
if (isMinLong(lhs) || isMaxLong(rhs)) {
|
||||
return JavaTokenType.LE.equals(comparison) ||
|
||||
JavaTokenType.GT.equals(comparison);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isZero(PsiExpression expression) {
|
||||
@@ -346,32 +295,4 @@ public class PointlessArithmeticExpressionInspection
|
||||
}
|
||||
return ExpressionUtils.isOne(expression);
|
||||
}
|
||||
|
||||
private static boolean isMinInt(PsiExpression expression) {
|
||||
final Integer value = (Integer)
|
||||
ConstantExpressionUtil.computeCastTo(
|
||||
expression, PsiType.INT);
|
||||
return value != null && value.intValue() == Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
private static boolean isMaxInt(PsiExpression expression) {
|
||||
final Integer value = (Integer)
|
||||
ConstantExpressionUtil.computeCastTo(
|
||||
expression, PsiType.INT);
|
||||
return value != null && value.intValue() == Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
private static boolean isMinLong(PsiExpression expression) {
|
||||
final Long value = (Long)
|
||||
ConstantExpressionUtil.computeCastTo(
|
||||
expression, PsiType.LONG);
|
||||
return value != null && value.longValue() == Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
private static boolean isMaxLong(PsiExpression expression) {
|
||||
final Long value = (Long)
|
||||
ConstantExpressionUtil.computeCastTo(
|
||||
expression, PsiType.LONG);
|
||||
return value != null && value.longValue() == Long.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
Reports any classes which do not contain package declarations.
|
||||
<!-- tooltip end -->
|
||||
<p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
+1
@@ -123,4 +123,5 @@ class Expanded {{
|
||||
System.out.println(u * 1);
|
||||
long g = 8L / 8L;
|
||||
long h = 9L * 0L;
|
||||
int a = 8 * 0 * 8 * ; // don't warn
|
||||
}}
|
||||
-84
@@ -36,90 +36,6 @@
|
||||
<description><code>j%1</code> can be replaced with '0' #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>PointlessArithmeticExpression.java</file>
|
||||
<line>30</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class>
|
||||
<description><code>k<=Integer.MAX_VALUE</code> can be replaced with 'true' #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>PointlessArithmeticExpression.java</file>
|
||||
<line>34</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class>
|
||||
<description><code>k>=Integer.MIN_VALUE</code> can be replaced with 'true' #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>PointlessArithmeticExpression.java</file>
|
||||
<line>38</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class>
|
||||
<description><code>k>Integer.MAX_VALUE</code> can be replaced with 'false' #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>PointlessArithmeticExpression.java</file>
|
||||
<line>42</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class>
|
||||
<description><code>k<Integer.MIN_VALUE</code> can be replaced with 'false' #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>PointlessArithmeticExpression.java</file>
|
||||
<line>46</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class>
|
||||
<description><code>Integer.MAX_VALUE >= k</code> can be replaced with 'true' #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>PointlessArithmeticExpression.java</file>
|
||||
<line>50</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class>
|
||||
<description><code>Integer.MIN_VALUE <= k</code> can be replaced with 'true' #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>PointlessArithmeticExpression.java</file>
|
||||
<line>54</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class>
|
||||
<description><code>Integer.MAX_VALUE < k</code> can be replaced with 'false' #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>PointlessArithmeticExpression.java</file>
|
||||
<line>58</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class>
|
||||
<description><code>Integer.MIN_VALUE > k</code> can be replaced with 'false' #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>PointlessArithmeticExpression.java</file>
|
||||
<line>70</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class>
|
||||
<description><code>i > Integer.MAX_VALUE</code> can be replaced with 'false' #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>PointlessArithmeticExpression.java</file>
|
||||
<line>76</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class>
|
||||
<description><code>i <= Integer.MAX_VALUE</code> can be replaced with 'true' #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>PointlessArithmeticExpression.java</file>
|
||||
<line>80</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class>
|
||||
<description><code>i >= Integer.MIN_VALUE</code> can be replaced with 'true' #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>PointlessArithmeticExpression.java</file>
|
||||
<line>83</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Pointless arithmetic expression</problem_class>
|
||||
<description><code>i < Integer.MIN_VALUE</code> can be replaced with 'false' #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>PointlessArithmeticExpression.java</file>
|
||||
<line>93</line>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.jetbrains.python.documentation;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.execution.process.ProcessOutput;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.module.Module;
|
||||
@@ -50,7 +51,11 @@ public class PyStructuredDocstringFormatter {
|
||||
@Nullable
|
||||
public static List<String> formatDocstring(@NotNull final PsiElement element, @NotNull final String docstring) {
|
||||
Module module = ModuleUtilCore.findModuleForPsiElement(element);
|
||||
if (module == null) module = ModuleManager.getInstance(element.getProject()).getModules()[0];
|
||||
if (module == null) {
|
||||
final Module[] modules = ModuleManager.getInstance(element.getProject()).getModules();
|
||||
if (modules.length == 0) return Lists.newArrayList();
|
||||
module = modules[0];
|
||||
}
|
||||
|
||||
final PyDocumentationSettings documentationSettings = PyDocumentationSettings.getInstance(module);
|
||||
final List<String> result = new ArrayList<String>();
|
||||
|
||||
@@ -81,7 +81,10 @@ public class PyProtectedMemberInspection extends PyInspection {
|
||||
public void visitPyImportElement(PyImportElement node) {
|
||||
final PyStatement statement = node.getContainingImportStatement();
|
||||
if (!(statement instanceof PyFromImportStatement)) return;
|
||||
checkReference(node.getImportReferenceExpression(), ((PyFromImportStatement)statement).getImportSource());
|
||||
final PyReferenceExpression importReferenceExpression = node.getImportReferenceExpression();
|
||||
final PyReferenceExpression importSource = ((PyFromImportStatement)statement).getImportSource();
|
||||
if (importReferenceExpression != null && importSource != null)
|
||||
checkReference(importReferenceExpression, importSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -91,7 +94,7 @@ public class PyProtectedMemberInspection extends PyInspection {
|
||||
checkReference(node, qualifier);
|
||||
}
|
||||
|
||||
private void checkReference(PyReferenceExpression node, PyExpression qualifier) {
|
||||
private void checkReference(@NotNull final PyReferenceExpression node, @NotNull final PyExpression qualifier) {
|
||||
if (myTypeEvalContext.getType(qualifier) instanceof PyNamedTupleType) return;
|
||||
final String name = node.getName();
|
||||
final List<LocalQuickFix> quickFixes = new ArrayList<LocalQuickFix>();
|
||||
|
||||
+1
-2
@@ -41,8 +41,7 @@ public class PythonNoseTestConfigurationProducer extends
|
||||
module = modules[0];
|
||||
}
|
||||
final Sdk sdk = PythonSdkType.findPythonSdk(module);
|
||||
return (TestRunnerService.getInstance(module).getProjectConfiguration().equals(
|
||||
PythonTestConfigurationsModel.PYTHONS_NOSETEST_NAME) && sdk != null);
|
||||
return (PythonTestConfigurationsModel.PYTHONS_NOSETEST_NAME.equals(TestRunnerService.getInstance(module).getProjectConfiguration()) && sdk != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
<font face="verdana" size="-1">Detects package statements that do not correspond to the project directory structure.</font>
|
||||
<font face="verdana" size="-1">Detects <b>package</b> statements that do not correspond to the project directory structure
|
||||
and reports classes without <b>package</b> statements.</font>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,41 +1,23 @@
|
||||
<idea-plugin version="2">
|
||||
<extensionPoints>
|
||||
<extensionPoint name="postfixTemplate" interface="com.intellij.codeInsight.template.postfix.templates.PostfixTemplate"/>
|
||||
<extensionPoint name="codeInsight.template.postfixTemplateProvider"
|
||||
beanClass="com.intellij.lang.LanguageExtensionPoint">
|
||||
<with attribute="implementationClass" implements="com.intellij.codeInsight.template.postfix.templates.PostfixTemplateProvider"/>
|
||||
</extensionPoint>
|
||||
</extensionPoints>
|
||||
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.ElseStatementPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.IntroduceVariablePostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.NotNullCheckPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.IsNullCheckPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.NotExpressionPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.ForeachPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.WhileStatementPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.CastExpressionPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.IfStatementPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.ForAscendingPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.ForDescendingPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.IntroduceFieldPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.ParenthesizedExpressionPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.ReturnStatementPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.SwitchStatementPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.ThrowExceptionPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.AssertStatementPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.SynchronizedStatementPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.InstanceofExpressionPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.SoutPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.FormatPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.TryStatementPostfixTemplate"/>
|
||||
<postfixTemplate implementation="com.intellij.codeInsight.template.postfix.templates.TryWithResourcesPostfixTemplate"/>
|
||||
<codeInsight.template.postfixTemplateProvider language="JAVA" implementationClass="com.intellij.codeInsight.template.postfix.templates.JavaPostfixTemplateProvider"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<applicationService id="postfixCompletionSettings" serviceImplementation="com.intellij.codeInsight.template.postfix.settings.PostfixTemplatesSettings"/>
|
||||
<customLiveTemplate implementation="com.intellij.codeInsight.template.postfix.templates.PostfixLiveTemplate"/>
|
||||
|
||||
|
||||
<completion.contributor language="JAVA" implementationClass="com.intellij.codeInsight.template.postfix.completion.PostfixTemplateCompletionContributor"/>
|
||||
<lookup.actionProvider implementation="com.intellij.codeInsight.template.postfix.completion.PostfixTemplateLookupActionProvider"/>
|
||||
|
||||
|
||||
<editorOptionsProvider id="editing.postfixCompletion" instance="com.intellij.codeInsight.template.postfix.settings.PostfixTemplatesConfigurable"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
Reference in New Issue
Block a user