Merge branch 'master' of git.labs.intellij.net:idea/community

This commit is contained in:
Vladislav.Soroka
2014-04-22 16:04:41 +04:00
59 changed files with 1428 additions and 1171 deletions
@@ -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);
}
@@ -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) {
@@ -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) {
@@ -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(".")));
}
}
@@ -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())));
}
}
}
@@ -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;
}
@@ -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));
}
}
@@ -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);
}
}
}
@@ -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));
}
}
@@ -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);
}
@@ -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);
}
@@ -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);
@@ -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;
@@ -0,0 +1,7 @@
class A {
}
class B extends A {
void m() {
Class<? extends A> c = getClass();<caret>
}
}
@@ -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']
}
}
@@ -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();
@@ -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) {
@@ -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);
@@ -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();
}
};
}
}
}
@@ -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();
@@ -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)) {
@@ -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;
}
@@ -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);
}
}
}
});
@@ -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;
}
}
}
@@ -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) {
}
}
@@ -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
@@ -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);
@@ -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);
@@ -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);
}
@@ -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"/>
@@ -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);
}
}
}
@@ -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>
@@ -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
}}
@@ -36,90 +36,6 @@
<description>&lt;code&gt;j%1&lt;/code&gt; 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>&lt;code&gt;k&lt;=Integer.MAX_VALUE&lt;/code&gt; 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>&lt;code&gt;k&gt;=Integer.MIN_VALUE&lt;/code&gt; 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>&lt;code&gt;k&gt;Integer.MAX_VALUE&lt;/code&gt; 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>&lt;code&gt;k&lt;Integer.MIN_VALUE&lt;/code&gt; 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>&lt;code&gt;Integer.MAX_VALUE &gt;= k&lt;/code&gt; 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>&lt;code&gt;Integer.MIN_VALUE &lt;= k&lt;/code&gt; 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>&lt;code&gt;Integer.MAX_VALUE &lt; k&lt;/code&gt; 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>&lt;code&gt;Integer.MIN_VALUE &gt; k&lt;/code&gt; 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>&lt;code&gt;i &gt; Integer.MAX_VALUE&lt;/code&gt; 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>&lt;code&gt;i &lt;= Integer.MAX_VALUE&lt;/code&gt; 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>&lt;code&gt;i &gt;= Integer.MIN_VALUE&lt;/code&gt; 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>&lt;code&gt;i &lt; Integer.MIN_VALUE&lt;/code&gt; 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>();
@@ -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>
+8 -26
View File
@@ -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>