diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java index 62999d5f611d..1c1cefe8ce8e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameCompletionContributor.java @@ -31,7 +31,6 @@ import com.intellij.psi.filters.ClassFilter; import com.intellij.psi.filters.ElementFilter; import com.intellij.psi.filters.TrueFilter; import com.intellij.psi.filters.element.ExcludeDeclaredFilter; -import com.intellij.psi.filters.types.AssignableFromFilter; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.Consumer; @@ -74,6 +73,9 @@ public class JavaClassNameCompletionContributor extends CompletionContributor { if (SkipAutopopupInStrings.isInStringLiteral(position)) { return true; } + if (PsiTreeUtil.getParentOfType(position, PsiComment.class, false) != null) { + return true; + } return false; } @@ -83,22 +85,8 @@ public class JavaClassNameCompletionContributor extends CompletionContributor { @NotNull final Consumer consumer) { final PsiElement insertedElement = parameters.getPosition(); - final ElementFilter filter; - if (JavaSmartCompletionContributor.AFTER_THROW_NEW.accepts(insertedElement) || - JavaCompletionContributor.INSIDE_METHOD_THROWS_CLAUSE.accepts(insertedElement) || - JavaCompletionContributor.IN_CATCH_TYPE.accepts(insertedElement) || - JavaCompletionContributor.IN_MULTI_CATCH_TYPE.accepts(insertedElement)) { - filter = new AssignableFromFilter(CommonClassNames.JAVA_LANG_THROWABLE); - } - else if (JavaCompletionContributor.IN_RESOURCE_TYPE.accepts(insertedElement)) { - filter = new AssignableFromFilter(CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE); - } - else if (IN_TYPE_PARAMETER.accepts(insertedElement)) { - filter = new ExcludeDeclaredFilter(new ClassFilter(PsiTypeParameter.class)); - } - else { - filter = TrueFilter.INSTANCE; - } + final ElementFilter filter = + IN_TYPE_PARAMETER.accepts(insertedElement) ? new ExcludeDeclaredFilter(new ClassFilter(PsiTypeParameter.class)) : TrueFilter.INSTANCE; final boolean inJavaContext = parameters.getPosition() instanceof PsiIdentifier; final boolean afterNew = AFTER_NEW.accepts(insertedElement); @@ -120,13 +108,10 @@ public class JavaClassNameCompletionContributor extends CompletionContributor { } } - final boolean lookingForAnnotations = psiElement().afterLeaf("@").accepts(insertedElement); final boolean pkgContext = JavaCompletionUtil.inSomePackage(insertedElement); AllClassesGetter.processJavaClasses(parameters, matcher, filterByScope, new Consumer() { @Override public void consume(PsiClass psiClass) { - if (lookingForAnnotations && !psiClass.isAnnotationType()) return; - if (filter.isAcceptable(psiClass, insertedElement)) { if (!inJavaContext) { consumer.consume(AllClassesGetter.createLookupItem(psiClass, AllClassesGetter.TRY_SHORTENING)); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java index c72c946efdaf..6a6cbad9b7f8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java @@ -628,7 +628,7 @@ public class JavaCompletionData extends JavaAwareCompletionData { return false; } - if (psiElement().withSuperParent(2, PsiConditionalExpression.class).accepts(position)) { + if (psiElement().withSuperParent(2, PsiConditionalExpression.class).andNot(psiElement().insideStarting(psiElement(PsiConditionalExpression.class))).accepts(position)) { return false; } diff --git a/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java b/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java index de25d9bb03f2..309fefcddba8 100644 --- a/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java +++ b/java/java-impl/src/com/intellij/codeInspection/defaultFileTemplateUsage/FileHeaderChecker.java @@ -49,11 +49,11 @@ import java.util.regex.Pattern; public class FileHeaderChecker { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.defaultFileTemplateUsage.FileHeaderChecker"); - static ProblemDescriptor checkFileHeader(final PsiFile file, final InspectionManager manager, boolean onTheFly) { + static ProblemDescriptor checkFileHeader(@NotNull final PsiFile file, final InspectionManager manager, boolean onTheFly) { FileTemplate template = FileTemplateManager.getInstance().getDefaultTemplate(FileTemplateManager.FILE_HEADER_TEMPLATE_NAME); TIntObjectHashMap offsetToProperty = new TIntObjectHashMap(); String templateText = template.getText().trim(); - String regex = templateToRegex(templateText, offsetToProperty); + String regex = templateToRegex(templateText, offsetToProperty, file.getProject()); regex = StringUtil.replace(regex, "with", "(?:with|by)"); regex = ".*("+regex+").*"; String fileText = file.getText(); @@ -144,9 +144,9 @@ public class FileHeaderChecker { return new LocalQuickFix[]{replaceTemplateFix,editFileTemplateFix}; } - private static String templateToRegex(final String text, TIntObjectHashMap offsetToProperty) { + private static String templateToRegex(final String text, TIntObjectHashMap offsetToProperty, Project project) { String regex = text; - @NonNls Collection properties = new ArrayList((Collection)FileTemplateManager.getInstance().getDefaultProperties().keySet()); + @NonNls Collection properties = new ArrayList((Collection)FileTemplateManager.getInstance().getDefaultProperties(project).keySet()); properties.add("PACKAGE_NAME"); regex = escapeRegexChars(regex); diff --git a/java/java-impl/src/com/intellij/psi/impl/file/JavaDirectoryServiceImpl.java b/java/java-impl/src/com/intellij/psi/impl/file/JavaDirectoryServiceImpl.java index dd2b6f2bb9e3..71593e1997a1 100644 --- a/java/java-impl/src/com/intellij/psi/impl/file/JavaDirectoryServiceImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/file/JavaDirectoryServiceImpl.java @@ -120,7 +120,7 @@ public class JavaDirectoryServiceImpl extends CoreJavaDirectoryService { FileTemplate template = FileTemplateManager.getInstance().getInternalTemplate(templateName); - Properties defaultProperties = FileTemplateManager.getInstance().getDefaultProperties(); + Properties defaultProperties = FileTemplateManager.getInstance().getDefaultProperties(dir.getProject()); Properties properties = new Properties(defaultProperties); properties.setProperty(FileTemplate.ATTRIBUTE_NAME, name); diff --git a/java/java-impl/src/com/intellij/psi/util/CreateClassUtil.java b/java/java-impl/src/com/intellij/psi/util/CreateClassUtil.java index c9e844fe7186..8f7f4f6e9335 100644 --- a/java/java-impl/src/com/intellij/psi/util/CreateClassUtil.java +++ b/java/java-impl/src/com/intellij/psi/util/CreateClassUtil.java @@ -187,14 +187,14 @@ public class CreateClassUtil { } @Nullable - public static PsiClass createClassNamed(String newClassName, String templateName, PsiDirectory directory) throws IncorrectOperationException { - return createClassNamed(newClassName, new Properties(FileTemplateManager.getInstance().getDefaultProperties()), templateName, directory); + public static PsiClass createClassNamed(String newClassName, String templateName, @NotNull PsiDirectory directory) throws IncorrectOperationException { + return createClassNamed(newClassName, FileTemplateManager.getInstance().getDefaultProperties(directory.getProject()), templateName, directory); } @Nullable - public static PsiClass createClassNamed(String newClassName, Map classProperties, String templateName, PsiDirectory directory) + public static PsiClass createClassNamed(String newClassName, Map classProperties, String templateName, @NotNull PsiDirectory directory) throws IncorrectOperationException { - Properties defaultProperties = FileTemplateManager.getInstance().getDefaultProperties(); + Properties defaultProperties = FileTemplateManager.getInstance().getDefaultProperties(directory.getProject()); Properties properties = new Properties(defaultProperties); properties.putAll(classProperties); @@ -235,7 +235,7 @@ public class CreateClassUtil { try { final Properties properties = ApplicationManager.getApplication().isUnitTestMode() ? new Properties() : - FileTemplateManager.getInstance().getDefaultProperties(); + FileTemplateManager.getInstance().getDefaultProperties(classDirectory.getProject()); return createClassNamed(className, new Properties(properties), templateName, classDirectory); } catch (IncorrectOperationException e) { diff --git a/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java index 9d318fee236f..69c6a3606114 100644 --- a/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java @@ -63,7 +63,7 @@ public class RenameJavaMethodProcessor extends RenameJavaMemberProcessor { PsiMethod method = (PsiMethod) psiElement; Set methodAndOverriders = new HashSet(); Set containingClasses = new HashSet(); - List renamedReferences = new ArrayList(); + LinkedHashSet renamedReferences = new LinkedHashSet(); List outerHides = new ArrayList(); List staticImportHides = new ArrayList(); diff --git a/java/java-psi-api/src/com/intellij/psi/util/InheritanceUtil.java b/java/java-psi-api/src/com/intellij/psi/util/InheritanceUtil.java index aac2fcbc77c7..2cd5c7446a52 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/InheritanceUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/InheritanceUtil.java @@ -53,7 +53,7 @@ public class InheritanceUtil { return isInheritorOrSelf(aClass, baseClass, checkDeep); } - public static boolean processSupers(@Nullable PsiClass aClass, boolean includeSelf, Processor superProcessor) { + public static boolean processSupers(@Nullable PsiClass aClass, boolean includeSelf, @NotNull Processor superProcessor) { if (aClass == null) return true; if (includeSelf && !superProcessor.process(aClass)) return false; @@ -61,7 +61,7 @@ public class InheritanceUtil { return processSupers(aClass, superProcessor, new THashSet()); } - private static boolean processSupers(@NotNull PsiClass aClass, Processor superProcessor, Set visited) { + private static boolean processSupers(@NotNull PsiClass aClass, @NotNull Processor superProcessor, @NotNull Set visited) { if (!visited.add(aClass)) return true; for (final PsiClass intf : aClass.getInterfaces()) { @@ -82,11 +82,11 @@ public class InheritanceUtil { return false; } - public static boolean isInheritor(@Nullable PsiClass psiClass, final String baseClassName) { + public static boolean isInheritor(@Nullable PsiClass psiClass, @NotNull final String baseClassName) { return isInheritor(psiClass, false, baseClassName); } - public static boolean isInheritor(@Nullable PsiClass psiClass, final boolean strict, final String baseClassName) { + public static boolean isInheritor(@Nullable PsiClass psiClass, final boolean strict, @NotNull final String baseClassName) { if (psiClass == null) { return false; } @@ -105,21 +105,22 @@ public class InheritanceUtil { * @param results * @param includeNonProject */ - public static void getSuperClasses(PsiClass aClass, Set results, boolean includeNonProject) { - getSuperClassesOfList(aClass.getSuperTypes(), results, includeNonProject); + public static void getSuperClasses(@NotNull PsiClass aClass, @NotNull Set results, boolean includeNonProject) { + getSuperClassesOfList(aClass.getSuperTypes(), results, includeNonProject, new THashSet(), aClass.getManager()); } - public static void getSuperClassesOfList(PsiClassType[] types, Set results, - boolean includeNonProject) { + private static void getSuperClassesOfList(@NotNull PsiClassType[] types, + @NotNull Set results, + boolean includeNonProject, + @NotNull Set visited, + @NotNull PsiManager manager) { for (PsiClassType type : types) { PsiClass resolved = type.resolve(); - if (resolved != null) { - if (!results.contains(resolved)) { - if (includeNonProject || resolved.getManager().isInProject(resolved)) { - results.add(resolved); - } - getSuperClasses(resolved, results, includeNonProject); + if (resolved != null && visited.add(resolved)) { + if (includeNonProject || manager.isInProject(resolved)) { + results.add(resolved); } + getSuperClassesOfList(resolved.getSuperTypes(), results, includeNonProject, visited, manager); } } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLiteralExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLiteralExpressionImpl.java index 53cc1246dba5..74d1350b3dc7 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLiteralExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLiteralExpressionImpl.java @@ -50,7 +50,7 @@ public class PsiLiteralExpressionImpl @Override public PsiType getType() { - final IElementType type = getFirstChildNode().getElementType(); + final IElementType type = getLiteralElementType(); if (type == JavaTokenType.INTEGER_LITERAL) { return PsiType.INT; } @@ -80,6 +80,10 @@ public class PsiLiteralExpressionImpl return null; } + public IElementType getLiteralElementType() { + return getFirstChildNode().getElementType(); + } + public String getCanonicalText() { final TreeElement literal = getFirstChildNode(); final IElementType type = literal.getElementType(); @@ -88,8 +92,7 @@ public class PsiLiteralExpressionImpl @Override public Object getValue() { - final TreeElement literal = getFirstChildNode(); - final IElementType type = literal.getElementType(); + final IElementType type = getLiteralElementType(); String text = NUMERIC_LITERALS.contains(type) ? getCanonicalText().toLowerCase() : getCanonicalText(); final int textLength = text.length(); @@ -172,19 +175,8 @@ public class PsiLiteralExpressionImpl return Character.valueOf(chars.charAt(0)); } if (type == JavaTokenType.STRING_LITERAL) { - if (StringUtil.endsWithChar(text, '\"')) { - if (textLength == 1) return null; - text = text.substring(1, textLength - 1); - } - else { - if (text.startsWith(QUOT) && text.endsWith(QUOT) && textLength > QUOT.length()) { - text = text.substring(QUOT.length(), textLength - QUOT.length()); - } - else { - return null; - } - } - return internedParseStringCharacters(text); + String innerText = getInnerText(); + return innerText == null ? null : internedParseStringCharacters(innerText); } if (type == JavaTokenType.TRUE_KEYWORD) { return Boolean.TRUE; @@ -196,6 +188,25 @@ public class PsiLiteralExpressionImpl return null; } + @Nullable + public String getInnerText() { + String text = getCanonicalText(); + int textLength = text.length(); + if (StringUtil.endsWithChar(text, '\"')) { + if (textLength == 1) return null; + text = text.substring(1, textLength - 1); + } + else { + if (text.startsWith(QUOT) && text.endsWith(QUOT) && textLength > QUOT.length()) { + text = text.substring(QUOT.length(), textLength - QUOT.length()); + } + else { + return null; + } + } + return text; + } + // convert text to number according to radix specified // if number is more than maxBits bits long, throws NumberFormatException private static long parseDigits(final String text, final int bitsInRadix, final int maxBits) throws NumberFormatException { diff --git a/java/java-tests/testData/codeInsight/completion/keywords/returnInTernary.java b/java/java-tests/testData/codeInsight/completion/keywords/returnInTernary.java new file mode 100644 index 000000000000..ad957a4ae4c8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/keywords/returnInTernary.java @@ -0,0 +1,5 @@ +public class Util { + int goo() { + retcond ? 1: 0; + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/ClassNameCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/ClassNameCompletionTest.java index 6c5768c0e9f1..ce660ae3cddb 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/ClassNameCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/ClassNameCompletionTest.java @@ -65,6 +65,7 @@ public class ClassNameCompletionTest extends LightFixtureCompletionTestCase { String path = "/afterNewThrowable"; configureByFile(path + "/before1.java"); + myFixture.type('\n'); checkResultByFile(path + "/after1.java"); } @@ -81,6 +82,7 @@ public class ClassNameCompletionTest extends LightFixtureCompletionTestCase { String path = "/afterNewThrowable"; configureByFile(path + "/before2.java"); + myFixture.type('\n'); checkResultByFile(path + "/after2.java"); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/KeywordCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/KeywordCompletionTest.java index 3a7f62eba3c3..f77bee9243e8 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/KeywordCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/KeywordCompletionTest.java @@ -92,6 +92,7 @@ public class KeywordCompletionTest extends LightCompletionTestCase { public void testNewInMethodRefs() throws Exception { doTest(false); } public void testAbstractInInterface() throws Exception { doTest(1, "abstract"); } public void testCharInAnnotatedParameter() throws Exception { doTest(1, "char"); } + public void testReturnInTernary() throws Exception { doTest(1, "return"); } public void testTryInExpression() throws Exception { configureByFile(BASE_PATH + "/" + getTestName(true) + ".java"); diff --git a/java/testFramework/testFramework-java.iml b/java/testFramework/testFramework-java.iml index 02287357986f..bcd446ef0028 100644 --- a/java/testFramework/testFramework-java.iml +++ b/java/testFramework/testFramework-java.iml @@ -20,6 +20,7 @@ + diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java index 7ba5054dd5fc..8a3e2902b3b3 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java @@ -17,7 +17,7 @@ import java.util.Set; * @author Eugene Zhuravlev * Date: 9/24/11 */ -class JavacFileManager extends ForwardingJavaFileManager { +class JavacFileManager extends ForwardingJavaFileManager implements StandardJavaFileManager{ private final Context myContext; private Map> myOutputsMap = Collections.emptyMap(); @@ -37,26 +37,36 @@ class JavacFileManager extends ForwardingJavaFileManager> outputDirToSrcRoots) { + public void setOutputDirectories(final Map> outputDirToSrcRoots) throws IOException{ for (File outputDir : outputDirToSrcRoots.keySet()) { // this will validate output dirs - if (!setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(outputDir))) { - return false; - } + setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(outputDir)); } myOutputsMap = outputDirToSrcRoots; - return true; } - public boolean setLocation(Location location, Iterable path) { - try { - getStdManager().setLocation(location, path); - } - catch (IOException e) { - myContext.reportMessage(Diagnostic.Kind.ERROR, e.getMessage()); - return false; - } - return true; + public void setLocation(Location location, Iterable path) throws IOException{ + getStdManager().setLocation(location, path); + } + + public Iterable getJavaFileObjectsFromFiles(Iterable files) { + return getStdManager().getJavaFileObjectsFromFiles(files); + } + + public Iterable getJavaFileObjects(File... files) { + return getStdManager().getJavaFileObjects(files); + } + + public Iterable getJavaFileObjectsFromStrings(Iterable names) { + return getStdManager().getJavaFileObjectsFromStrings(names); + } + + public Iterable getJavaFileObjects(String... names) { + return getStdManager().getJavaFileObjects(names); + } + + public Iterable getLocation(Location location) { + return getStdManager().getLocation(location); } public boolean isSameFile(FileObject a, FileObject b) { @@ -213,4 +223,8 @@ class JavacFileManager extends ForwardingJavaFileManager myArchives; - private final Map myIsFile = new ConcurrentHashMap(); + private final Map myIsFile = new HashMap(); private final Map> myContentCache = new HashMap>(); private final Map> myDirectoryCache = new HashMap>(); public static final File[] NULL_FILE_ARRAY = new File[0]; @@ -271,20 +270,12 @@ class OptimizedFileManager extends DefaultFileManager { } private class InputFileObject extends BaseFileObject { - /** The file's name. - */ - private String name; /** The underlying file. */ final File f; public InputFileObject(File f) { - this(f.getName(), f); - } - - public InputFileObject(String name, File f) { - this.name = name; this.f = f; } @@ -306,15 +297,16 @@ class OptimizedFileManager extends DefaultFileManager { @Deprecated public String getName() { - return name; + return f.getPath(); } - public boolean isNameCompatible(String cn, JavaFileObject.Kind kind) { - String n = cn + kind.extension; - if (name.equals(n)) { + public boolean isNameCompatible(String simpleName, JavaFileObject.Kind kind) { + final String n = simpleName + kind.extension; + final String fileName = f.getName(); + if (fileName.equals(n)) { return true; } - if (name.equalsIgnoreCase(n)) { + if (fileName.equalsIgnoreCase(n)) { try { // allow for Windows return (f.getCanonicalFile().getName().equals(n)); diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/OutputFileObject.java b/jps/jps-builders/src/org/jetbrains/jps/javac/OutputFileObject.java index c0495aea130e..9e75dc5d084d 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/OutputFileObject.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/OutputFileObject.java @@ -4,7 +4,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.incremental.Utils; -import javax.tools.*; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; import java.io.*; import java.net.URI; import java.util.Arrays; @@ -39,7 +40,7 @@ public final class OutputFileObject extends SimpleJavaFileObject { myOutputRoot = outputRoot; myRelativePath = relativePath; myFile = file; - myClassName = className; + myClassName = className != null? className.replace('/', '.') : null; mySourceFile = srcUri != null? Utils.convertToFile(srcUri) : null; } diff --git a/jps/lib/optimizedFileManager.jar b/jps/lib/optimizedFileManager.jar index a2d7bc671ed0..3444af80a7c9 100644 Binary files a/jps/lib/optimizedFileManager.jar and b/jps/lib/optimizedFileManager.jar differ diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java b/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java index 0871c7c67705..57ca1b0a4ec8 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java @@ -276,7 +276,7 @@ public class CompositeElement extends TreeElement { final int len = getTextLength(); if (startStamp != myModificationsCount) { - throw new AssertionError("Tree changed while calculating text"); + throw new AssertionError("Tree changed while calculating text. startStamp:"+startStamp+"; current:"+myModificationsCount+"; myHC:"+myHC+"; assertThreading:"+ASSERT_THREADING+"; Thread.holdsLock(START_OFFSET_LOCK):"+Thread.holdsLock(START_OFFSET_LOCK)+"; Thread.holdsLock(PSI_LOCK):"+Thread.holdsLock(PsiLock.LOCK)); } char[] buffer = new char[len]; diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/search/LowLevelSearchUtil.java b/platform/indexing-impl/src/com/intellij/psi/impl/search/LowLevelSearchUtil.java index bf0f4ba81f26..d083c0a4c2c1 100644 --- a/platform/indexing-impl/src/com/intellij/psi/impl/search/LowLevelSearchUtil.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/search/LowLevelSearchUtil.java @@ -181,7 +181,8 @@ public class LowLevelSearchUtil { } public static int searchWord(@NotNull CharSequence text, - char[] textArray, int startOffset, + char[] textArray, + int startOffset, int endOffset, @NotNull StringSearcher searcher, @Nullable ProgressIndicator progress) { diff --git a/platform/lang-api/src/com/intellij/patterns/PsiElementPattern.java b/platform/lang-api/src/com/intellij/patterns/PsiElementPattern.java index 155159353d10..6b784a258300 100644 --- a/platform/lang-api/src/com/intellij/patterns/PsiElementPattern.java +++ b/platform/lang-api/src/com/intellij/patterns/PsiElementPattern.java @@ -303,7 +303,7 @@ public abstract class PsiElementPattern ancestor) { + public Self insideStarting(final ElementPattern ancestor) { return with(new PatternCondition("insideStarting") { @Override public boolean accepts(@NotNull PsiElement start, ProcessingContext context) { diff --git a/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.form b/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.form index aab91296ed1b..c2c5ecf9f70b 100644 --- a/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.form +++ b/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.form @@ -304,7 +304,7 @@ - + @@ -339,9 +339,27 @@ - + + + + + + + + + + + + + + + + + + + diff --git a/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.java b/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.java index 362c056a8d2c..ddf8dcddd2a6 100644 --- a/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/editor/EditorOptionsPanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,8 +21,10 @@ import com.intellij.application.options.OptionsApplicabilityFilter; import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPass; +import com.intellij.codeInsight.documentation.QuickDocOnMouseOverManager; import com.intellij.ide.ui.UISettings; import com.intellij.openapi.application.ApplicationBundle; +import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.EditorFactory; @@ -83,6 +85,7 @@ public class EditorOptionsPanel { private JTextField myCustomSoftWrapIndent; private JCheckBox myCbShowAllSoftWraps; private JCheckBox myPreselectCheckBox; + private JCheckBox myCbShowQuickDocOnCheckBox; private final ErrorHighlightingPanel myErrorHighlightingPanel = new ErrorHighlightingPanel(); private final MyConfigurable myConfigurable; @@ -156,6 +159,7 @@ public class EditorOptionsPanel { } myCbEnsureBlankLineBeforeCheckBox.setSelected(editorSettings.isEnsureNewLineAtEOF()); + myCbShowQuickDocOnCheckBox.setSelected(editorSettings.isShowQuickDocOnMouseOverElement()); // Advanced mouse myCbEnableDnD.setSelected(editorSettings.isDndEnabled()); @@ -235,6 +239,12 @@ public class EditorOptionsPanel { editorSettings.setEnsureNewLineAtEOF(myCbEnsureBlankLineBeforeCheckBox.isSelected()); + if (myCbShowQuickDocOnCheckBox.isSelected() ^ editorSettings.isShowQuickDocOnMouseOverElement()) { + boolean enabled = myCbShowQuickDocOnCheckBox.isSelected(); + editorSettings.setShowQuickDocOnMouseOverElement(enabled); + ServiceManager.getService(QuickDocOnMouseOverManager.class).setEnabled(enabled); + } + editorSettings.setDndEnabled(myCbEnableDnD.isSelected()); editorSettings.setWheelFontChangeEnabled(myCbEnableWheelFontChange.isSelected()); @@ -341,6 +351,7 @@ public class EditorOptionsPanel { // Strip trailing spaces, ensure EOL on EOF on save isModified |= !getStripTrailingSpacesValue().equals(editorSettings.getStripTrailingSpaces()); isModified |= isModified(myCbEnsureBlankLineBeforeCheckBox, editorSettings.isEnsureNewLineAtEOF()); + isModified |= isModified(myCbShowQuickDocOnCheckBox, editorSettings.isShowQuickDocOnMouseOverElement()); // advanced mouse isModified |= isModified(myCbEnableDnD, editorSettings.isDndEnabled()); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/FileReferenceQuickFixProvider.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/FileReferenceQuickFixProvider.java index bfcb0efa774d..25443fb894d8 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/FileReferenceQuickFixProvider.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/quickFix/FileReferenceQuickFixProvider.java @@ -155,7 +155,7 @@ public class FileReferenceQuickFixProvider { FileTemplate template = FileTemplateManager.getInstance().getTemplate(templateName); if (template != null) { try { - return template.getText(FileTemplateManager.getInstance().getDefaultProperties()); + return template.getText(FileTemplateManager.getInstance().getDefaultProperties(directory.getProject())); } catch (IOException ex) { throw new RuntimeException(ex); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java index f356fa43587e..393e399f8254 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java @@ -146,7 +146,7 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr } { - enableEvents(KeyEvent.KEY_EVENT_MASK); + enableEvents(AWTEvent.KEY_EVENT_MASK); } protected void processKeyEvent(KeyEvent e) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java index 86c02c4ebaff..892e53cac7dc 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -154,7 +154,20 @@ public class DocumentationManager extends DockablePopupManager> actions = Collections.singletonList(Pair.create(new ActionListener() { + final List> actions = + Collections.singletonList(Pair.create(new ActionListener() { public void actionPerformed(ActionEvent e) { createToolWindow(element, originalElement); final JBPopup hint = getDocInfoHint(); @@ -314,63 +341,66 @@ public class DocumentationManager extends DockablePopupManager() { - public Boolean compute() { - if (fromQuickSearch()) { - ((ChooseByNameBase.JPanelProvider)myPreviouslyFocused.getParent()).unregisterHint(); - } - - Disposer.dispose(component); - myEditor = null; - myPreviouslyFocused = null; - myParameterInfoController = null; - return Boolean.TRUE; - } - }) - .createPopup(); - - - AbstractPopup oldHint = (AbstractPopup)getDocInfoHint(); - if (oldHint != null) { - DocumentationComponent oldComponent = (DocumentationComponent)oldHint.getComponent(); - PsiElement element1 = oldComponent.getElement(); - if (Comparing.equal(element, element1)) { - if (requestFocus) { - component.getComponent().requestFocus(); + .setRequestFocusCondition(project, NotLookupOrSearchCondition.INSTANCE) + .setProject(project) + .addListener(updateProcessor) + .addUserData(updateProcessor) + .setKeyboardActions(actions) + .setDimensionServiceKey(myProject, JAVADOC_LOCATION_AND_SIZE, false) + .setResizable(true) + .setMovable(true) + .setRequestFocus(requestFocus) + .setCancelOnClickOutside(!hasLookup) // otherwise selecting lookup items by mouse would close the doc + .setTitle(getTitle(element, false)) + .setCouldPin(pinCallback) + .setCancelCallback(new Computable() { + public Boolean compute() { + if (closeCallback != null) { + closeCallback.run(); } - return; + if (fromQuickSearch()) { + ((ChooseByNameBase.JPanelProvider)myPreviouslyFocused.getParent()).unregisterHint(); + } + + Disposer.dispose(component); + myEditor = null; + myPreviouslyFocused = null; + myParameterInfoController = null; + return Boolean.TRUE; } - oldHint.cancel(); + }) + .createPopup(); + + + AbstractPopup oldHint = (AbstractPopup)getDocInfoHint(); + if (oldHint != null) { + DocumentationComponent oldComponent = (DocumentationComponent)oldHint.getComponent(); + PsiElement element1 = oldComponent.getElement(); + if (Comparing.equal(element, element1)) { + if (requestFocus) { + component.getComponent().requestFocus(); + } + return; } + oldHint.cancel(); + } - component.setHint(hint); + component.setHint(hint); - if (myEditor == null) { - // subsequent invocation of javadoc popup from completion will have myEditor == null because of cancel invoked, - // so reevaluate the editor for proper popup placement - Lookup lookup = LookupManager.getInstance(myProject).getActiveLookup(); - myEditor = lookup != null ? lookup.getEditor() : null; - } - fetchDocInfo(getDefaultCollector(element, originalElement), component); + if (myEditor == null) { + // subsequent invocation of javadoc popup from completion will have myEditor == null because of cancel invoked, + // so reevaluate the editor for proper popup placement + Lookup lookup = LookupManager.getInstance(myProject).getActiveLookup(); + myEditor = lookup != null ? lookup.getEditor() : null; + } + fetchDocInfo(getDefaultCollector(element, originalElement), component); - myDocInfoHintRef = new WeakReference(hint); - myPreviouslyFocused = WindowManagerEx.getInstanceEx().getFocusedComponent(project); + myDocInfoHintRef = new WeakReference(hint); + myPreviouslyFocused = WindowManagerEx.getInstanceEx().getFocusedComponent(project); - if (fromQuickSearch()) { - ((ChooseByNameBase.JPanelProvider)myPreviouslyFocused.getParent()).registerHint(hint); - } + if (fromQuickSearch()) { + ((ChooseByNameBase.JPanelProvider)myPreviouslyFocused.getParent()).registerHint(hint); + } } private static String getTitle(@NotNull final PsiElement element, final boolean _short) { @@ -392,13 +422,19 @@ public class DocumentationManager extends DockablePopupManager + * Not thread-safe. + * + * @author Denis Zhdanov + * @since 7/2/12 9:09 AM + */ +public class QuickDocOnMouseOverManager { + + private static final long QUICK_DOC_DELAY_MILLIS; + static { + long delay = 500; + String property = System.getProperty("editor.auto.quick.doc.delay.ms"); + if (property != null) { + try { + long parsed = Long.parseLong(property); + if (parsed > 0) { + delay = parsed; + } + } + catch (Exception e) { + // Ignore. + } + } + QUICK_DOC_DELAY_MILLIS = delay; + } + + @NotNull private final EditorMouseMotionListener myEditorListener = new MyEditorMouseListener(); + @NotNull private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); + @NotNull private final Runnable myRequest = new MyShowQuickDocRequest(); + @NotNull private final Runnable myHintCloseCallback = new Runnable() { + @Override + public void run() { + myActiveElements.clear(); + myDocumentationManager = null; + } + }; + + private final Map myActiveElements + = new HashMap(); + + /** Holds a reference (if any) to the documentation manager used last time to show an 'auto quick doc' popup. */ + @Nullable private WeakReference myDocumentationManager; + + @Nullable private DelayedQuickDocInfo myDelayedQuickDocInfo; + private boolean myEnabled; + + public QuickDocOnMouseOverManager(@NotNull Application application) { + EditorFactory factory = EditorFactory.getInstance(); + if (factory != null) { + factory.addEditorFactoryListener(new MyEditorFactoryListener(), application); + } + } + + /** + * Instructs the manager to enable or disable 'show quick doc automatically when the mouse goes over an editor element' mode. + * + * @param enabled flag that identifies if quick doc should be automatically shown + */ + public void setEnabled(boolean enabled) { + myEnabled = enabled; + if (!enabled) { + closeAutoQuickDocComponentIfNecessary(); + myAlarm.cancelAllRequests(); + } + EditorFactory factory = EditorFactory.getInstance(); + if (factory == null) { + return; + } + for (Editor editor : factory.getAllEditors()) { + if (enabled) { + editor.addEditorMouseMotionListener(myEditorListener); + } + else { + editor.removeEditorMouseMotionListener(myEditorListener); + } + } + } + + private void processMouseMove(@NotNull EditorMouseEvent e) { + if (e.getArea() != EditorMouseEventArea.EDITING_AREA) { + // Skip if the mouse is not at the editing area. + closeAutoQuickDocComponentIfNecessary(); + return; + } + + Editor editor = e.getEditor(); + Project project = editor.getProject(); + if (project == null) { + return; + } + + DocumentationManager documentationManager = DocumentationManager.getInstance(project); + JBPopup hint = documentationManager.getDocInfoHint(); + if (hint != null) { + + // Skip the event if the control is shown because of explicit 'show quick doc' action call. + WeakReference ref = myDocumentationManager; + if (ref == null || ref.get() == null) { + return; + } + + // Skip the event if the mouse is under the opened quick doc control. + Point hintLocation = hint.getLocationOnScreen(); + Dimension hintSize = hint.getSize(); + int mouseX = e.getMouseEvent().getXOnScreen(); + int mouseY = e.getMouseEvent().getYOnScreen(); + if (mouseX >= hintLocation.x && mouseX <= hintLocation.x + hintSize.width && mouseY >= hintLocation.y + && mouseY <= hintLocation.y + hintSize.height) + { + return; + } + } + + PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); + if (psiFile == null) { + closeAutoQuickDocComponentIfNecessary(); + return; + } + + int mouseOffset = editor.logicalPositionToOffset(editor.xyToLogicalPosition(e.getMouseEvent().getPoint())); + PsiElement elementUnderMouse = psiFile.findElementAt(mouseOffset); + if (elementUnderMouse == null || elementUnderMouse instanceof PsiWhiteSpace) { + closeAutoQuickDocComponentIfNecessary(); + return; + } + + PsiElement targetElementUnderMouse = documentationManager.findTargetElement(editor, mouseOffset, psiFile, elementUnderMouse); + if (targetElementUnderMouse == null) { + // No PSI element is located under the current mouse position - close quick doc if any. + closeAutoQuickDocComponentIfNecessary(); + return; + } + + PsiElement activeElement = myActiveElements.get(editor); + if (targetElementUnderMouse.equals(activeElement) + && (myAlarm.getActiveRequestCount() > 0 // Request to show documentation for the target component has been already queued. + || hint != null)) // Documentation for the target component is being shown. + { + return; + } + closeAutoQuickDocComponentIfNecessary(); + myActiveElements.put(editor, targetElementUnderMouse); + myDelayedQuickDocInfo = new DelayedQuickDocInfo(documentationManager, editor, targetElementUnderMouse, elementUnderMouse); + + myAlarm.cancelAllRequests(); + myAlarm.addRequest(myRequest, QUICK_DOC_DELAY_MILLIS); + } + + private void closeAutoQuickDocComponentIfNecessary() { + myAlarm.cancelAllRequests(); + WeakReference ref = myDocumentationManager; + if (ref == null) { + return; + } + + DocumentationManager docManager = ref.get(); + if (docManager == null) { + return; + } + + JBPopup hint = docManager.getDocInfoHint(); + if (hint == null) { + return; + } + + hint.cancel(); + } + + private static class DelayedQuickDocInfo { + + @NotNull public final DocumentationManager docManager; + @NotNull public final Editor editor; + @NotNull public final PsiElement targetElement; + @NotNull public final PsiElement originalElement; + + private DelayedQuickDocInfo(@NotNull DocumentationManager docManager, + @NotNull Editor editor, @NotNull PsiElement targetElement, + @NotNull PsiElement originalElement) + { + this.docManager = docManager; + this.editor = editor; + this.targetElement = targetElement; + this.originalElement = originalElement; + } + } + + private class MyShowQuickDocRequest implements Runnable { + @Override + public void run() { + myAlarm.cancelAllRequests(); + + DelayedQuickDocInfo info = myDelayedQuickDocInfo; + if (info == null || !info.targetElement.equals(myActiveElements.get(info.editor))) { + return; + } + + info.editor.putUserData(PopupFactoryImpl.ANCHOR_POPUP_POSITION, + info.editor.offsetToVisualPosition(info.originalElement.getTextRange().getStartOffset())); + try { + info.docManager.showJavaDocInfo(info.editor, info.targetElement, info.originalElement, myHintCloseCallback); + myDocumentationManager = new WeakReference(info.docManager); + } + finally { + info.editor.putUserData(PopupFactoryImpl.ANCHOR_POPUP_POSITION, null); + } + } + } + + private class MyEditorFactoryListener implements EditorFactoryListener { + @Override + public void editorCreated(@NotNull EditorFactoryEvent event) { + if (myEnabled) { + event.getEditor().addEditorMouseMotionListener(myEditorListener); + } + } + + @Override + public void editorReleased(@NotNull EditorFactoryEvent event) { + event.getEditor().removeEditorMouseMotionListener(myEditorListener); + } + } + + private class MyEditorMouseListener extends EditorMouseMotionAdapter { + + @Override + public void mouseMoved(EditorMouseEvent e) { + processMouseMove(e); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverStartupActivity.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverStartupActivity.java new file mode 100644 index 000000000000..72ffe987ed41 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocOnMouseOverStartupActivity.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.documentation; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.editor.ex.EditorSettingsExternalizable; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.startup.StartupActivity; + +/** + * @author Denis Zhdanov + * @since 7/2/12 9:44 AM + */ +public class QuickDocOnMouseOverStartupActivity implements StartupActivity { + + @Override + public void runActivity(Project project) { + if (EditorSettingsExternalizable.getInstance().isShowQuickDocOnMouseOverElement()) { + ServiceManager.getService(QuickDocOnMouseOverManager.class).setEnabled(true); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteIndentProcessor.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteIndentProcessor.java index 1382508ea8b5..73887ff5c227 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteIndentProcessor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteIndentProcessor.java @@ -12,7 +12,6 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.util.text.CharArrayUtil; @@ -21,7 +20,6 @@ import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; -import java.util.List; /** * @author yole @@ -149,11 +147,7 @@ public class CopyPasteIndentProcessor implements CopyPastePostProcessor strings = StringUtil.split(pastedText, "\n"); - //if (strings.get(strings.size() - 1)) - - if (strings.get(0).trim().startsWith("def") || - strings.get(0).trim().startsWith("class")) endLine -=1; + if (caretColumn > value.getIndent()) endLine -=1; for (int i = startLine+1; i <= endLine; i++) { EditorActionUtil.indentLine(project, editor, i, value.getIndent()); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java index ae6e07323864..a9a3c2cee7d7 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java @@ -244,9 +244,11 @@ public class LookupCellRenderer implements ListCellRenderer { return getGrayedForeground(isSelected); } - final Color tailForeground = presentation.getTailForeground(); - if (tailForeground != null) { - return tailForeground; + if (!isSelected) { + final Color tailForeground = presentation.getTailForeground(); + if (tailForeground != null) { + return tailForeground; + } } return defaultForeground; diff --git a/platform/lang-impl/src/com/intellij/execution/actions/ChooseRunConfigurationPopup.java b/platform/lang-impl/src/com/intellij/execution/actions/ChooseRunConfigurationPopup.java index c54209e99ea6..072e2f81583f 100644 --- a/platform/lang-impl/src/com/intellij/execution/actions/ChooseRunConfigurationPopup.java +++ b/platform/lang-impl/src/com/intellij/execution/actions/ChooseRunConfigurationPopup.java @@ -362,8 +362,9 @@ public class ChooseRunConfigurationPopup { return new ItemWrapper(settings) { @Override public void perform(@NotNull Project project, @NotNull Executor executor, @NotNull DataContext context) { - RunManagerEx.getInstanceEx(project).setSelectedConfiguration(getValue()); - ProgramRunnerUtil.executeConfiguration(project, getValue(), executor); + RunnerAndConfigurationSettings config = getValue(); + RunManagerEx.getInstanceEx(project).setSelectedConfiguration(config); + doRunConfiguration(config, executor, project); } @Override @@ -470,7 +471,7 @@ public class ChooseRunConfigurationPopup { @Override public void perform(@NotNull final Project project, @NotNull final Executor executor, @NotNull DataContext context) { ExecutionTargetManager.setActiveTarget(project, eachTarget); - ProgramRunnerUtil.executeConfiguration(project, selectedConfiguration, executor); + doRunConfiguration(selectedConfiguration, executor, project); } @Override @@ -531,12 +532,7 @@ public class ChooseRunConfigurationPopup { if (dialog.isOK()) { SwingUtilities.invokeLater(new Runnable() { public void run() { - final RunnerAndConfigurationSettings configuration = RunManager.getInstance(project).getSelectedConfiguration(); - if (configuration instanceof RunnerAndConfigurationSettingsImpl) { - if (canRun(executor, configuration)) { - ProgramRunnerUtil.executeConfiguration(project, configuration, executor); - } - } + doRunConfiguration(RunManager.getInstance(project).getSelectedConfiguration(), executor, project); } }); } @@ -616,7 +612,7 @@ public class ChooseRunConfigurationPopup { public void perform(@NotNull Project project, @NotNull Executor executor, @NotNull DataContext context) { manager.setTemporaryConfiguration(configuration); RunManagerEx.getInstanceEx(project).setSelectedConfiguration(configuration); - ProgramRunnerUtil.executeConfiguration(project, configuration, executor); + doRunConfiguration(configuration, executor, project); } @Override @@ -729,6 +725,14 @@ public class ChooseRunConfigurationPopup { } } + private static void doRunConfiguration(RunnerAndConfigurationSettings configuration, Executor executor, Project project) { + if (configuration instanceof RunnerAndConfigurationSettingsImpl) { + if (canRun(executor, configuration)) { + ProgramRunnerUtil.executeConfiguration(project, configuration, executor); + } + } + } + private static final class ConfigurationActionsStep extends BaseListPopupStep { private ConfigurationActionsStep(@NotNull final Project project, ChooseRunConfigurationPopup action, @@ -761,7 +765,7 @@ public class ChooseRunConfigurationPopup { manager.setSelectedConfiguration(settings); ExecutionTargetManager.setActiveTarget(project, eachTarget); - ProgramRunnerUtil.executeConfiguration(project, settings, action.getCurrentExecutor(), eachTarget); + doRunConfiguration(settings, action.getCurrentExecutor(), project); } }); } @@ -776,7 +780,7 @@ public class ChooseRunConfigurationPopup { final RunManagerEx manager = RunManagerEx.getInstanceEx(project); if (dynamic) manager.setTemporaryConfiguration(settings); manager.setSelectedConfiguration(settings); - ProgramRunnerUtil.executeConfiguration(project, settings, executor); + doRunConfiguration(settings, executor, project); } }); isFirst = false; diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java index 8ffd8ce4362b..f075a93d183d 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java @@ -280,7 +280,7 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { EmptyAction.registerActionShortcuts(myHistoryViewer.getComponent(), myConsoleEditor.getComponent()); } - private boolean isFullEditorMode() { + public boolean isFullEditorMode() { return myPanel.getComponentCount() == 1; } diff --git a/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/GridCellImpl.java b/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/GridCellImpl.java index f8089fc12254..8fb769c791f1 100644 --- a/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/GridCellImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/GridCellImpl.java @@ -232,6 +232,7 @@ public class GridCellImpl implements GridCell { return info. setIcon(content.getIcon()). setText(content.getDisplayName()). + setTooltipText(content.getDescription()). setActionsContextComponent(content.getActionsContextComponent()). setActions(content.getActions(), content.getPlace()); } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/CreateFileFromTemplateAction.java b/platform/lang-impl/src/com/intellij/ide/actions/CreateFileFromTemplateAction.java index a24bc032f032..b92916337e1d 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/CreateFileFromTemplateAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/CreateFileFromTemplateAction.java @@ -20,6 +20,7 @@ import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.ide.fileTemplates.FileTemplateUtil; import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; @@ -42,23 +43,24 @@ public abstract class CreateFileFromTemplateAction extends CreateFromTemplateAct protected PsiFile createFileFromTemplate(String name, FileTemplate template, PsiDirectory dir) { PsiElement element; + Project project = dir.getProject(); try { element = FileTemplateUtil - .createFromTemplate(template, name, FileTemplateManager.getInstance().getDefaultProperties(), dir); + .createFromTemplate(template, name, FileTemplateManager.getInstance().getDefaultProperties(project), dir); final PsiFile psiFile = element.getContainingFile(); final VirtualFile virtualFile = psiFile.getVirtualFile(); if (virtualFile != null) { - FileEditorManager.getInstance(dir.getProject()).openFile(virtualFile, true); + FileEditorManager.getInstance(project).openFile(virtualFile, true); String property = getDefaultTemplateProperty(); if (property != null) { - PropertiesComponent.getInstance(dir.getProject()).setValue(property, template.getName()); + PropertiesComponent.getInstance(project).setValue(property, template.getName()); } return psiFile; } } catch (ParseException e) { - Messages.showErrorDialog(dir.getProject(), "Error parsing Velocity template: " + e.getMessage(), "Create File from Template"); + Messages.showErrorDialog(project, "Error parsing Velocity template: " + e.getMessage(), "Create File from Template"); return null; } catch (IncorrectOperationException e) { diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateManager.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateManager.java index 43a2404d1712..05830b86f967 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateManager.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateManager.java @@ -17,6 +17,7 @@ package com.intellij.ide.fileTemplates; import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -59,6 +60,13 @@ public abstract class FileTemplateManager{ @NotNull public abstract Properties getDefaultProperties(); + @NotNull + public Properties getDefaultProperties(Project project) { + Properties properties = getDefaultProperties(); + properties.setProperty("PROJECT_NAME", project.getName()); + return properties; + } + /** * Creates a new template with specified name. * @param name diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java index 747312d7ee40..5bc48a18089a 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/FileTemplateUtil.java @@ -266,7 +266,7 @@ public class FileTemplateUtil{ @Nullable ClassLoader classLoader) throws Exception { @NotNull final Project project = directory.getProject(); if (props == null) { - props = FileTemplateManager.getInstance().getDefaultProperties(); + props = FileTemplateManager.getInstance().getDefaultProperties(directory.getProject()); } FileTemplateManager.getInstance().addRecentName(template.getName()); fillDefaultProperties(props, directory); diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateConfigurable.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateConfigurable.java index 6472427c84f6..acaf61c2fe56 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateConfigurable.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateConfigurable.java @@ -357,7 +357,7 @@ public class FileTemplateConfigurable implements Configurable, Configurable.NoSc if (fileType == FileTypes.UNKNOWN) return null; final PsiFile file = PsiFileFactory.getInstance(myProject).createFileFromText(name + ".txt.ft", fileType, text, 0, true); - file.getViewProvider().putUserData(FileTemplateManager.DEFAULT_TEMPLATE_PROPERTIES, FileTemplateManager.getInstance().getDefaultProperties()); + file.getViewProvider().putUserData(FileTemplateManager.DEFAULT_TEMPLATE_PROPERTIES, FileTemplateManager.getInstance().getDefaultProperties(myProject)); return file; } diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java index 30f8972ec0e2..fe5b432f4cc2 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/ui/CreateFromTemplateDialog.java @@ -57,7 +57,7 @@ public class CreateFromTemplateDialog extends DialogWrapper { myTemplate = template; setTitle(IdeBundle.message("title.new.from.template", template.getName())); - myDefaultProperties = defaultProperties == null ? FileTemplateManager.getInstance().getDefaultProperties() : defaultProperties; + myDefaultProperties = defaultProperties == null ? FileTemplateManager.getInstance().getDefaultProperties(project) : defaultProperties; FileTemplateUtil.fillDefaultProperties(myDefaultProperties, directory); boolean mustEnterName = FileTemplateUtil.findHandler(template).isNameRequired(); if (attributesDefaults != null && attributesDefaults.isFixedName()) { diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java index 322404d59adb..73d2fbe52e83 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java @@ -580,7 +580,7 @@ public class SingleInspectionProfilePanel extends JPanel { } static String renderSeverity(HighlightSeverity severity) { - return severity.toString().toLowerCase(); + return StringUtil.capitalizeWords(severity.toString().toLowerCase(), true); } private void toggleToolNode(final InspectionConfigTreeNode toolNode) { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageManagerImpl.java index 250bcbed8cd1..af846dc238ed 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageManagerImpl.java @@ -124,7 +124,7 @@ public class InjectedLanguageManagerImpl extends InjectedLanguageManager impleme public void startRunInjectors(@NotNull final Document hostDocument, final boolean synchronously) { if (myProject.isDisposed()) return; - assert synchronously || !ApplicationManager.getApplication().isWriteAccessAllowed(); + if (!synchronously && ApplicationManager.getApplication().isWriteAccessAllowed()) return; // use cached to avoid recreate PSI in alien project final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject); final PsiFile hostPsiFile = documentManager.getCachedPsiFile(hostDocument); diff --git a/platform/lang-impl/src/com/intellij/tools/ToolAction.java b/platform/lang-impl/src/com/intellij/tools/ToolAction.java index 8417b1f7ade5..80e0d24cecf2 100644 --- a/platform/lang-impl/src/com/intellij/tools/ToolAction.java +++ b/platform/lang-impl/src/com/intellij/tools/ToolAction.java @@ -19,6 +19,7 @@ package com.intellij.tools; import com.intellij.ide.macro.MacroManager; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.project.DumbAware; /** @@ -34,11 +35,15 @@ public class ToolAction extends AnAction implements DumbAware { } public void actionPerformed(AnActionEvent e) { - MacroManager.getInstance().cacheMacrosPreview(e.getDataContext()); - final HackyDataContext dataContext = new HackyDataContext(e.getDataContext()); + runTool(myActionId, e.getDataContext()); + } + + static void runTool(String actionId, DataContext context) { + MacroManager.getInstance().cacheMacrosPreview(context); + final HackyDataContext dataContext = new HackyDataContext(context); Tool[] tools = ToolManager.getInstance().getTools(); for (Tool tool : tools) { - if (myActionId.equals(tool.getActionId())) { + if (actionId.equals(tool.getActionId())) { tool.execute(dataContext); break; } diff --git a/platform/lang-impl/src/com/intellij/tools/ToolBeforeRunTask.java b/platform/lang-impl/src/com/intellij/tools/ToolBeforeRunTask.java new file mode 100644 index 000000000000..61e889270fdd --- /dev/null +++ b/platform/lang-impl/src/com/intellij/tools/ToolBeforeRunTask.java @@ -0,0 +1,88 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.tools; + +import com.intellij.execution.BeforeRunTask; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.util.ui.UIUtil; +import org.jdom.Element; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.Nullable; + +public class ToolBeforeRunTask extends BeforeRunTask { + @NonNls private final static String ACTION_ID_ATTRIBUTE = "actionId"; + private String myToolActionId; + + protected ToolBeforeRunTask() { + super(ToolBeforeRunTaskProvider.ID); + } + + @Nullable + public String getToolActionId() { + return myToolActionId; + } + + public void setToolActionId(String toolActionId) { + myToolActionId = toolActionId; + } + + public boolean isExecutable() { + return myToolActionId != null; + } + + @Override + public void writeExternal(Element element) { + super.writeExternal(element); + if (myToolActionId != null) { + element.setAttribute(ACTION_ID_ATTRIBUTE, myToolActionId); + } + } + + @Override + public void readExternal(Element element) { + super.readExternal(element); + myToolActionId = element.getAttributeValue(ACTION_ID_ATTRIBUTE); + } + + @Override + public ToolBeforeRunTask clone() { + return (ToolBeforeRunTask)super.clone(); + } + + public void execute(final DataContext context) { + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + + @Override + public void run() { + ToolAction.runTool(myToolActionId, context); + } + }); + } + + @Nullable + public Tool findCorrespondingTool() { + if (myToolActionId == null) { + return null; + } + Tool[] tools = ToolManager.getInstance().getTools(); + for (Tool tool : tools) { + if (myToolActionId.equals(tool.getActionId())) { + return tool; + } + } + return null; + } +} diff --git a/platform/lang-impl/src/com/intellij/tools/ToolBeforeRunTaskProvider.java b/platform/lang-impl/src/com/intellij/tools/ToolBeforeRunTaskProvider.java new file mode 100644 index 000000000000..f0b4e362b45f --- /dev/null +++ b/platform/lang-impl/src/com/intellij/tools/ToolBeforeRunTaskProvider.java @@ -0,0 +1,105 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.tools; + +import com.intellij.execution.BeforeRunTaskProvider; +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.text.StringUtil; + +public class ToolBeforeRunTaskProvider extends BeforeRunTaskProvider { + static final Key ID = Key.create("ToolBeforeRunTask"); + private static final Logger LOG = Logger.getInstance("#" + ToolBeforeRunTaskProvider.class.getName()); + + + @Override + public Key getId() { + return ID; + } + + @Override + public String getName() { + return ToolsBundle.message("tools.before.run.provider.name"); + } + + @Override + public String getDescription(ToolBeforeRunTask task) { + final String actionId = task.getToolActionId(); + if (actionId == null) { + LOG.error("Null id"); + return ToolsBundle.message("tools.unknown.external.tool"); + } + Tool tool = task.findCorrespondingTool(); + if (tool == null) { + return ToolsBundle.message("tools.unknown.external.tool"); + } + String groupName = tool.getGroup(); + return ToolsBundle + .message("tools.before.run.description", StringUtil.isEmpty(groupName) ? tool.getName() : groupName + "/" + tool.getName()); + } + + /* + @Override //todo[lene] + public Icon getIcon() { + return ICON; + }*/ + + @Override + public boolean isConfigurable() { + return true; + } + + @Override + public ToolBeforeRunTask createTask(RunConfiguration runConfiguration) { + return new ToolBeforeRunTask(); + } + + @Override + public boolean configureTask(RunConfiguration runConfiguration, ToolBeforeRunTask task) { + final ToolSelectDialog dialog = new ToolSelectDialog(runConfiguration.getProject(), task); + dialog.show(); + if (!dialog.isOK()) { + return false; + } + boolean isModified = dialog.isModified(); + Tool selectedTool = dialog.getSelectedTool(); + LOG.assertTrue(selectedTool != null); + String selectedToolId = selectedTool.getActionId(); + String oldToolId = task.getToolActionId(); + if (oldToolId != null && oldToolId.equals(selectedToolId)) { + return isModified; + } + task.setToolActionId(selectedToolId); + return true; + } + + @Override + public boolean canExecuteTask(RunConfiguration configuration, ToolBeforeRunTask task) { + return task.isExecutable(); + } + + @Override + public boolean executeTask(DataContext context, RunConfiguration configuration, ExecutionEnvironment env, ToolBeforeRunTask task) { + if (!task.isExecutable()) { + return false; + } + task.execute(context); + return true; + } +} diff --git a/platform/lang-impl/src/com/intellij/tools/ToolSelectDialog.java b/platform/lang-impl/src/com/intellij/tools/ToolSelectDialog.java new file mode 100644 index 000000000000..17b2111f049c --- /dev/null +++ b/platform/lang-impl/src/com/intellij/tools/ToolSelectDialog.java @@ -0,0 +1,83 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.tools; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.ui.popup.Balloon; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.awt.RelativePoint; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import java.awt.*; +import java.io.IOException; + +class ToolSelectDialog extends DialogWrapper { + private final ToolsPanel myToolsPanel = new ToolsPanel(); + + protected ToolSelectDialog(@Nullable Project project, ToolBeforeRunTask task) { + super(project); + myToolsPanel.reset(); + myToolsPanel.addSelectionListener(new TreeSelectionListener() { + @Override + public void valueChanged(TreeSelectionEvent e) { + final Tool selectedTool = myToolsPanel.getSingleSelectedTool(); + boolean isOk = selectedTool != null; + setOKActionEnabled(isOk); + } + }); + init(); + pack(); + if(task.getToolActionId() != null){ + myToolsPanel.selectTool(task.getToolActionId()); + } + } + + @Override + protected void doOKAction() { + try { + myToolsPanel.apply(); + } + catch (IOException e) { + String message = ToolsBundle.message("tools.failed.to.save.changes.0", StringUtil.decapitalize(e.getMessage())); + final JLayeredPane pane = myToolsPanel.getRootPane().getLayeredPane(); + JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(message, MessageType.ERROR, null) + .setShowCallout(false).setFadeoutTime(3000).setHideOnAction(true).setHideOnClickOutside(true).setHideOnKeyOutside(true). + createBalloon().show(new RelativePoint(pane, new Point(pane.getWidth(), 0)), Balloon.Position.above); + return; + } + super.doOKAction(); + } + + @Override + protected JComponent createCenterPanel() { + return myToolsPanel; + } + + @Nullable + Tool getSelectedTool() { + return myToolsPanel.getSingleSelectedTool(); + } + + boolean isModified() { + return myToolsPanel.isModified(); + } +} diff --git a/platform/lang-impl/src/com/intellij/tools/ToolsPanel.java b/platform/lang-impl/src/com/intellij/tools/ToolsPanel.java index 3c5f35bbd326..e87e6fb5897e 100644 --- a/platform/lang-impl/src/com/intellij/tools/ToolsPanel.java +++ b/platform/lang-impl/src/com/intellij/tools/ToolsPanel.java @@ -33,6 +33,7 @@ import javax.swing.tree.*; import java.awt.*; import java.io.IOException; import java.util.ArrayList; +import java.util.List; class ToolsPanel extends JPanel { static enum Direction { @@ -488,4 +489,52 @@ class ToolsPanel extends JPanel { } return ArrayUtil.toStringArray(result); } + + void addSelectionListener(TreeSelectionListener listener) { + myTree.getSelectionModel().addTreeSelectionListener(listener); + } + + @Nullable + Tool getSingleSelectedTool() { + final TreePath[] selectionPaths = myTree.getSelectionPaths(); + if (selectionPaths == null || selectionPaths.length != 1) { + return null; + } + Object toolOrToolGroup = ((CheckedTreeNode)selectionPaths[0].getLastPathComponent()).getUserObject(); + if (toolOrToolGroup instanceof Tool) { + return (Tool)toolOrToolGroup; + } + return null; + } + + public void selectTool(final String actionId) { + Object root = myTree.getModel().getRoot(); + if (root == null || !(root instanceof CheckedTreeNode)) { + return; + } + final List nodes = new ArrayList(); + new Object() { + @SuppressWarnings("unchecked") + public void collect(CheckedTreeNode node) { + if (node.isLeaf()) { + Object userObject = node.getUserObject(); + if (userObject instanceof Tool && actionId.equals(((Tool)userObject).getActionId())) { + nodes.add(node); + } + } + else { + for (int i = 0; i < node.getChildCount(); i++) { + final TreeNode child = node.getChildAt(i); + if (child instanceof CheckedTreeNode) { + collect((CheckedTreeNode)child); + } + } + } + } + }.collect((CheckedTreeNode)root); + if (nodes.isEmpty()) { + return; + } + myTree.getSelectionModel().setSelectionPath(new TreePath(nodes.get(0).getPath())); + } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java b/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java index b9167e8129ec..7cc78437591f 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java @@ -50,13 +50,15 @@ public class IndexingStamp { private Timestamps(@Nullable DataInputStream stream) throws IOException { if (stream != null) { try { - long dominatingIndexStamp = DataInputOutputUtil.readTIME(stream); - while(stream.available() > 0) { - ID id = ID.findById(DataInputOutputUtil.readINT(stream)); - if (id != null) { - long stamp = IndexInfrastructure.getIndexCreationStamp(id); - if (myIndexStamps == null) myIndexStamps = new TObjectLongHashMap>(5, 0.98f); - if (stamp <= dominatingIndexStamp) myIndexStamps.put(id, stamp); + if (stream.available() > 0) { + long dominatingIndexStamp = DataInputOutputUtil.readTIME(stream); + while(stream.available() > 0) { + ID id = ID.findById(DataInputOutputUtil.readINT(stream)); + if (id != null) { + long stamp = IndexInfrastructure.getIndexCreationStamp(id); + if (myIndexStamps == null) myIndexStamps = new TObjectLongHashMap>(5, 0.98f); + if (stamp <= dominatingIndexStamp) myIndexStamps.put(id, stamp); + } } } } diff --git a/platform/platform-api/src/com/intellij/openapi/editor/EditorFactory.java b/platform/platform-api/src/com/intellij/openapi/editor/EditorFactory.java index 78c7ce26b9b0..9a231c30fbd2 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/EditorFactory.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/EditorFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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. @@ -36,6 +36,7 @@ public abstract class EditorFactory implements ApplicationComponent { * * @return the editor factory instance. */ + @Nullable public static EditorFactory getInstance() { final Application application = ApplicationManager.getApplication(); return application == null ? null : application.getComponent(EditorFactory.class); @@ -168,7 +169,7 @@ public abstract class EditorFactory implements ApplicationComponent { /** * Registers a listener for receiving notifications when editor instances are created and released - * and removes the listener when {@link parentDisposable} get disposed. + * and removes the listener when the 'parentDisposable' gets disposed. * * @param listener the listener instance. * @param parentDisposable the Disposable which triggers the removal of the listener @@ -176,7 +177,7 @@ public abstract class EditorFactory implements ApplicationComponent { public abstract void addEditorFactoryListener(@NotNull EditorFactoryListener listener, @NotNull Disposable parentDisposable); /** - * Unregisters a listener for receiving notifications when editor instances are created + * Un-registers a listener for receiving notifications when editor instances are created * and released. * * @param listener the listener instance. diff --git a/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java b/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java index b4b3d97e4f11..8640a6db9416 100644 --- a/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java +++ b/platform/platform-api/src/com/intellij/openapi/fileEditor/OpenFileDescriptor.java @@ -215,7 +215,7 @@ public class OpenFileDescriptor implements Navigatable { } } - private void unfoldCurrentLine(@NotNull final Editor editor) { + private static void unfoldCurrentLine(@NotNull final Editor editor) { final FoldRegion[] allRegions = editor.getFoldingModel().getAllFoldRegions(); final int offset = editor.getCaretModel().getOffset(); int line = editor.getDocument().getLineNumber(offset); @@ -226,7 +226,7 @@ public class OpenFileDescriptor implements Navigatable { @Override public void run() { for (FoldRegion region : allRegions) { - if (!region.isExpanded() && range.intersects(TextRange.create(region))) /*region.getStartOffset() <= offset && offset <= region.getEndOffset()*/ { + if (!region.isExpanded() && range.intersects(TextRange.create(region))) { region.setExpanded(true); } } @@ -240,14 +240,15 @@ public class OpenFileDescriptor implements Navigatable { @Override public boolean canNavigate() { - return myProject != null; + return myFile.isValid(); } @Override public boolean canNavigateToSource() { - return myProject != null; + return canNavigate(); } + @NotNull public Project getProject() { return myProject; } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/Messages.java b/platform/platform-api/src/com/intellij/openapi/ui/Messages.java index f7ac237dbc15..91699f132804 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/Messages.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/Messages.java @@ -814,7 +814,7 @@ public class Messages { textField.setText(textArea.getText()); } }); - String s = textField.getText().replaceAll("[ ]*=[ ]*", "=").replaceAll("\\-", "\\ \\-"); + String s = textField.getText().replaceAll("[ ]*=[ ]*", "=").replaceAll("=\\-", "=\\ \\-"); List lines = StringUtil.splitHonorQuotes(s, ' '); textArea.setText(StringUtil.join(lines, "\n")); InsertPathAction.copyFromTo(textField, textArea); diff --git a/platform/platform-api/src/com/intellij/util/Icons.java b/platform/platform-api/src/com/intellij/util/Icons.java new file mode 100644 index 000000000000..148d8bcc2ee0 --- /dev/null +++ b/platform/platform-api/src/com/intellij/util/Icons.java @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.util; + +/** + * @deprecated use {@link PlatformIcons} for generic icons and corresponding classes from plugins for plugin-specific icons + * @see PlatformIcons + */ +public abstract class Icons implements PlatformIcons { +} diff --git a/platform/platform-impl/src/com/intellij/featureStatistics/actions/ShowFeatureUsageStatisticsDialog.java b/platform/platform-impl/src/com/intellij/featureStatistics/actions/ShowFeatureUsageStatisticsDialog.java index e858374f0768..f1823069d2b4 100644 --- a/platform/platform-impl/src/com/intellij/featureStatistics/actions/ShowFeatureUsageStatisticsDialog.java +++ b/platform/platform-impl/src/com/intellij/featureStatistics/actions/ShowFeatureUsageStatisticsDialog.java @@ -149,12 +149,11 @@ public class ShowFeatureUsageStatisticsDialog extends DialogWrapper { long idleTime = app.getIdleTime(); final String uptimeS = FeatureStatisticsBundle.message("feature.statistics.application.uptime", - ApplicationNamesInfo.getInstance().getProductName(), + ApplicationNamesInfo.getInstance().getFullProductName(), DateFormatUtil.formatDuration(uptime)); - final String idleTimeS = FeatureStatisticsBundle .message("feature.statistics.application.idle.time", - ApplicationNamesInfo.getInstance().getProductName(), - DateFormatUtil.formatDuration(idleTime)); + final String idleTimeS = FeatureStatisticsBundle.message("feature.statistics.application.idle.time", + DateFormatUtil.formatDuration(idleTime)); String labelText = uptimeS + ", " + idleTimeS; CompletionStatistics stats = ((FeatureUsageTrackerImpl)FeatureUsageTracker.getInstance()).getCompletionStatistics(); diff --git a/platform/platform-impl/src/com/intellij/ide/ReopenProjectAction.java b/platform/platform-impl/src/com/intellij/ide/ReopenProjectAction.java index 1f4c9175a7fe..81d1725549c8 100644 --- a/platform/platform-impl/src/com/intellij/ide/ReopenProjectAction.java +++ b/platform/platform-impl/src/com/intellij/ide/ReopenProjectAction.java @@ -25,6 +25,7 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.io.FileUtil; import java.awt.event.InputEvent; +import java.io.File; /** * @author yole @@ -50,8 +51,9 @@ public class ReopenProjectAction extends AnAction implements DumbAware { final int modifiers = e.getModifiers(); final boolean forceOpenInNewFrame = (modifiers & InputEvent.CTRL_MASK) != 0 || (modifiers & InputEvent.SHIFT_MASK) != 0; Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext()); - if (!RecentProjectsManagerBase.isValidProjectPath(myProjectPath)) { - Messages.showErrorDialog(project, "The project path " + FileUtil.toSystemDependentName(myProjectPath) + " does not exist.\n" + + File file = new File(myProjectPath); + if (!file.exists() || !file.isDirectory()) { + Messages.showErrorDialog(project, "The directory " + FileUtil.toSystemDependentName(myProjectPath) + " does not exist.\n" + "If it is on a removable or network drive, please make sure that the drive is connected.", "Reopen Project"); return; diff --git a/platform/platform-impl/src/com/intellij/ide/ui/customization/CustomActionsSchema.java b/platform/platform-impl/src/com/intellij/ide/ui/customization/CustomActionsSchema.java index 0fd6ac8846b8..66d5703559f8 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/customization/CustomActionsSchema.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/customization/CustomActionsSchema.java @@ -70,6 +70,7 @@ public class CustomActionsSchema implements ExportableComponent, NamedJDOMExtern myIdToNameList.add(new Pair(IdeActions.GROUP_EDITOR_GUTTER, "Editor Gutter Popup Menu")); myIdToNameList.add(new Pair(IdeActions.GROUP_EDITOR_TAB_POPUP, ActionsTreeUtil.EDITOR_TAB_POPUP)); myIdToNameList.add(new Pair(IdeActions.GROUP_PROJECT_VIEW_POPUP, ActionsTreeUtil.PROJECT_VIEW_POPUP)); + myIdToNameList.add(new Pair(IdeActions.GROUP_SCOPE_VIEW_POPUP, "Scope View Popup Menu")); myIdToNameList.add(new Pair(IdeActions.GROUP_FAVORITES_VIEW_POPUP, ActionsTreeUtil.FAVORITES_POPUP)); myIdToNameList.add(new Pair(IdeActions.GROUP_COMMANDER_POPUP, ActionsTreeUtil.COMMANDER_POPUP)); myIdToNameList.add(new Pair(IdeActions.GROUP_J2EE_VIEW_POPUP, ActionsTreeUtil.J2EE_POPUP)); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorSettingsExternalizable.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorSettingsExternalizable.java index 20ee29d35212..b99fa22dce8c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorSettingsExternalizable.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/EditorSettingsExternalizable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.components.ExportableApplicationComponent; +import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces; import com.intellij.openapi.options.OptionsBundle; import com.intellij.openapi.util.DefaultJDOMExternalizer; @@ -50,6 +51,7 @@ public class EditorSettingsExternalizable implements NamedJDOMExternalizable, Ex public boolean IS_CARET_INSIDE_TABS; @NonNls public String STRIP_TRAILING_SPACES = "Changed"; public boolean IS_ENSURE_NEWLINE_AT_EOF = false; + public boolean SHOW_QUICK_DOC_ON_MOUSE_OVER_ELEMENT = false; public boolean IS_CARET_BLINKING = true; public int CARET_BLINKING_PERIOD = 500; public boolean IS_RIGHT_MARGIN_SHOWN = true; @@ -356,7 +358,7 @@ public class EditorSettingsExternalizable implements NamedJDOMExternalizable, Ex public void setEnsureNewLineAtEOF(boolean ensure) { myOptions.IS_ENSURE_NEWLINE_AT_EOF = ensure; } - + public String getStripTrailingSpaces() { return myOptions.STRIP_TRAILING_SPACES; } // TODO: move to CodeEditorManager or something else @@ -365,6 +367,14 @@ public class EditorSettingsExternalizable implements NamedJDOMExternalizable, Ex myOptions.STRIP_TRAILING_SPACES = stripTrailingSpaces; } + public boolean isShowQuickDocOnMouseOverElement() { + return myOptions.SHOW_QUICK_DOC_ON_MOUSE_OVER_ELEMENT; + } + + public void setShowQuickDocOnMouseOverElement(boolean show) { + myOptions.SHOW_QUICK_DOC_ON_MOUSE_OVER_ELEMENT = show; + } + public boolean isRefrainFromScrolling() { return myOptions.REFRAIN_FROM_SCROLLING; } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index c6f987bfe094..3fcf2dac7f1c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -2508,7 +2508,8 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi @NotNull Rectangle clip, @NotNull LogicalPosition clipStartPosition, int clipStartOffset, - int clipEndOffset) { + int clipEndOffset) + { myCurrentFontType = null; myLastCache = null; final int plainSpaceWidth = EditorUtil.getSpaceWidth(Font.PLAIN, this); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionsTree.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionsTree.java index ba1244039f7a..b0760c38b103 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionsTree.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldRegionsTree.java @@ -323,16 +323,17 @@ abstract class FoldRegionsTree { } public int getLastTopLevelIndexBefore(int offset) { - if (!isFoldingEnabledAndUpToDate()) return -1; + int[] endOffsets = myCachedEndOffsets; + if (!isFoldingEnabledAndUpToDate() || endOffsets == null) return -1; int start = 0; - int end = myCachedEndOffsets.length - 1; + int end = endOffsets.length - 1; while (start <= end) { int i = (start + end) / 2; - if (offset < myCachedEndOffsets[i]) { + if (offset < endOffsets[i]) { end = i - 1; - } else if (offset > myCachedEndOffsets[i]) { + } else if (offset > endOffsets[i]) { start = i + 1; } else { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java index 10693301cebc..7570353813d1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java @@ -589,6 +589,7 @@ public class SoftWrapApplianceManager implements SoftWrapFoldingListener, Docume myContext.currentPosition.offset--; myContext.currentPosition.logicalColumn -= columnsDiff; myContext.currentPosition.visualColumn -= columnsDiff; + myContext.currentPosition.x -= pixelsDiff; } } } @@ -899,6 +900,10 @@ public class SoftWrapApplianceManager implements SoftWrapFoldingListener, Docume return myListeners.add(listener); } + public boolean removeListener(@NotNull SoftWrapAwareDocumentParsingListener listener) { + return myListeners.remove(listener); + } + @SuppressWarnings({"ForLoopReplaceableByForEach"}) private void revertListeners(int offset, int visualLine) { for (int i = 0; i < myListeners.size(); i++) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapAwareDocumentParsingListenerAdapter.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapAwareDocumentParsingListenerAdapter.java index 4145c46d4e3a..09fdff87e83d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapAwareDocumentParsingListenerAdapter.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapAwareDocumentParsingListenerAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ import org.jetbrains.annotations.NotNull; * @author Denis Zhdanov * @since 11/23/11 7:04 PM */ -public class SoftWrapAwareDocumentParsingListenerAdapter implements SoftWrapAwareDocumentParsingListener { +public abstract class SoftWrapAwareDocumentParsingListenerAdapter implements SoftWrapAwareDocumentParsingListener { @Override public void onVisualLineStart(@NotNull EditorPosition position) { } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java index 376809278f80..994fc134d515 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java @@ -823,7 +823,7 @@ public class FSRecords implements Forceable { } } - public static void updateList(int id, int[] children) { + public static void updateList(int id, @NotNull int[] children) { try { w.lock(); DbConnection.markDirty(); diff --git a/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java b/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java index b2e4a8e5fed1..ea31ba758f63 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/AbstractPopup.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.VisualPosition; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.*; diff --git a/platform/platform-impl/src/com/intellij/ui/popup/PopupFactoryImpl.java b/platform/platform-impl/src/com/intellij/ui/popup/PopupFactoryImpl.java index 414c5ece580e..54cac050b66e 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/PopupFactoryImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/PopupFactoryImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,7 @@ import com.intellij.openapi.ui.popup.*; import com.intellij.openapi.ui.popup.util.BaseListPopupStep; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.EmptyRunnable; +import com.intellij.openapi.util.Key; import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.ex.WindowManagerEx; import com.intellij.openapi.wm.impl.IdeFrameImpl; @@ -65,6 +66,14 @@ import java.util.HashMap; import java.util.List; public class PopupFactoryImpl extends JBPopupFactory { + + /** + * Allows to get an editor position for which a popup with auxiliary information might be shown. + *

+ * Primary intention for this key is to hint popup position for the non-caret location. + */ + public static final Key ANCHOR_POPUP_POSITION = Key.create("popup.anchor.position"); + private static final Logger LOG = Logger.getInstance("#com.intellij.ui.popup.PopupFactoryImpl"); private static final Icon QUICK_LIST_ICON = AllIcons.Actions.QuickList; @@ -78,7 +87,7 @@ public class PopupFactoryImpl extends JBPopupFactory { } public JBPopup createMessage(String text) { - return createListPopup(new BaseListPopupStep(null, new String[]{text})); + return createListPopup(new BaseListPopupStep(null, new String[]{text})); } @Override @@ -98,28 +107,34 @@ public class PopupFactoryImpl extends JBPopupFactory { return null; } - public ListPopup createConfirmation(String title, final String yesText, String noText, final Runnable onYes, final Runnable onNo, int defaultOptionIndex) { + public ListPopup createConfirmation(String title, + final String yesText, + String noText, + final Runnable onYes, + final Runnable onNo, + int defaultOptionIndex) + { - final BaseListPopupStep step = new BaseListPopupStep(title, new String[]{yesText, noText}) { - public PopupStep onChosen(String selectedValue, final boolean finalChoice) { - if (selectedValue.equals(yesText)) { - onYes.run(); - } - else { - onNo.run(); - } - return FINAL_CHOICE; + final BaseListPopupStep step = new BaseListPopupStep(title, new String[]{yesText, noText}) { + public PopupStep onChosen(String selectedValue, final boolean finalChoice) { + if (selectedValue.equals(yesText)) { + onYes.run(); } - - public void canceled() { + else { onNo.run(); } + return FINAL_CHOICE; + } - public boolean isMnemonicsNavigationEnabled() { - return true; - } - }; - step.setDefaultOptionIndex(defaultOptionIndex); + public void canceled() { + onNo.run(); + } + + public boolean isMnemonicsNavigationEnabled() { + return true; + } + }; + step.setDefaultOptionIndex(defaultOptionIndex); final ApplicationEx app = ApplicationManagerEx.getApplicationEx(); return app == null || !app.isUnitTestMode() ? new ListPopupImpl(step) : new MockConfirmation(step, yesText); @@ -127,13 +142,13 @@ public class PopupFactoryImpl extends JBPopupFactory { private static ListPopup createActionGroupPopup(final String title, - final ActionGroup actionGroup, - @NotNull DataContext dataContext, - boolean showNumbers, - boolean useAlphaAsNumbers, - boolean showDisabledActions, - boolean honorActionMnemonics, - final Runnable disposeCallback, + final ActionGroup actionGroup, + @NotNull DataContext dataContext, + boolean showNumbers, + boolean useAlphaAsNumbers, + boolean showDisabledActions, + boolean honorActionMnemonics, + final Runnable disposeCallback, final int maxRowCount) { return createActionGroupPopup(title, actionGroup, dataContext, showNumbers, useAlphaAsNumbers, showDisabledActions, honorActionMnemonics, disposeCallback, maxRowCount, null, null); @@ -458,14 +473,18 @@ public class PopupFactoryImpl extends JBPopupFactory { } public RelativePoint guessBestPopupLocation(Editor editor) { - CaretModel caretModel = editor.getCaretModel(); - final VisualPosition visualPosition; - if (caretModel.isUpToDate()) { - visualPosition = caretModel.getVisualPosition(); - } - else { - visualPosition = editor.offsetToVisualPosition(caretModel.getOffset()); + VisualPosition visualPosition = editor.getUserData(ANCHOR_POPUP_POSITION); + + if (visualPosition == null) { + CaretModel caretModel = editor.getCaretModel(); + if (caretModel.isUpToDate()) { + visualPosition = caretModel.getVisualPosition(); + } + else { + visualPosition = editor.offsetToVisualPosition(caretModel.getOffset()); + } } + Point p = editor.visualPositionToXY(new VisualPosition(visualPosition.line + 1, visualPosition.column)); final Rectangle visibleArea = editor.getScrollingModel().getVisibleArea(); diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties index 977f08eb1ca7..3ecbbf068091 100644 --- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties +++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties @@ -372,6 +372,7 @@ checkbox.show.virtual.space.at.file.bottom=Show virtual space at file bottom checkbox.optimize.imports.on.the.fly=Optimize imports on the fly checkbox.add.unambiguous.imports.on.the.fly=Add unambiguous imports on the fly combobox.strip.trailing.spaces.on.save=Strip trailing spaces on Save: +checkbox.show.quick.doc.on.mouse.over=Show quick doc on mouse over element group.limits=Limits editbox.recent.files.limit=Recent files limit: editbox.console.history.limit=Console commands history size: diff --git a/platform/platform-resources-en/src/messages/FeatureStatisticsBundle.properties b/platform/platform-resources-en/src/messages/FeatureStatisticsBundle.properties index 14f3326d6b9d..490e76352d9d 100644 --- a/platform/platform-resources-en/src/messages/FeatureStatisticsBundle.properties +++ b/platform/platform-resources-en/src/messages/FeatureStatisticsBundle.properties @@ -24,7 +24,7 @@ feature.statistics.not.applicable=N/A # {0} - application name (IntelliJ IDEA or Visual Fabrique or RubyMine or WebStorm or PhpStorm or PyCharm or CIDR) # {1} - formatted duration. feature.statistics.application.uptime={0} uptime: {1} -feature.statistics.application.idle.time={0} idle time: {1} +feature.statistics.application.idle.time=idle time: {0} # Names of features in the feature statistics bundle navigation.popup.class=Go to class diff --git a/platform/platform-resources-en/src/messages/ToolsBundle.properties b/platform/platform-resources-en/src/messages/ToolsBundle.properties index c86d0ff4e4fd..270957c09c1c 100644 --- a/platform/platform-resources-en/src/messages/ToolsBundle.properties +++ b/platform/platform-resources-en/src/messages/ToolsBundle.properties @@ -50,4 +50,8 @@ tools.delete.confirmation=Do you want to delete the external tool(s)? tools.name.column=Name tools.group.column=Group tools.description.column=Description -tools.not.configured=No external tools configured \ No newline at end of file +tools.not.configured=No external tools configured +tools.unknown.external.tool=Unknown external tool +tools.before.run.description=External tool ''{0}'' +tools.failed.to.save.changes.0=Failed to save changes: {0} +tools.before.run.provider.name=Run External tool \ No newline at end of file diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 14c14f44a482..6f67fde3fb6a 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -362,6 +362,7 @@ + @@ -733,7 +734,10 @@ - + + + + diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java index bf71ec861559..959afe98b854 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java @@ -17,8 +17,12 @@ package com.intellij.openapi.editor.impl.softwrap.mapping; import com.intellij.codeInsight.folding.CodeFoldingManager; import com.intellij.openapi.editor.*; -import com.intellij.openapi.editor.impl.*; +import com.intellij.openapi.editor.impl.AbstractEditorProcessingOnDocumentModificationTest; +import com.intellij.openapi.editor.impl.DefaultEditorTextRepresentationHelper; +import com.intellij.openapi.editor.impl.EditorImpl; +import com.intellij.openapi.editor.impl.SoftWrapModelImpl; import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.util.Ref; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.testFramework.TestFileType; import gnu.trove.TIntHashSet; @@ -994,9 +998,37 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorP assertEquals(text.substring(0, text.indexOf("line")) + text.substring(text.indexOf('9')), myEditor.getDocument().getText()); assertEquals(position, caretModel.getVisualPosition()); } + + public void testNoUnnecessaryHorizontalScrollBar() throws IOException { + // Inspired by IDEA-87184 + final String text = "12345678 abcdefgh"; + init(15, 7, text); + myEditor.getCaretModel().moveToOffset(text.length()); + final Ref fail = new Ref(true); + SoftWrapApplianceManager applianceManager = ((SoftWrapModelImpl)myEditor.getSoftWrapModel()).getApplianceManager(); + SoftWrapAwareDocumentParsingListener listener = new SoftWrapAwareDocumentParsingListenerAdapter() { + @Override + public void beforeSoftWrapLineFeed(@NotNull EditorPosition position) { + if (position.x == text.indexOf("a") * 7) { + fail.set(false); + } + } + }; + applianceManager.addListener(listener); + try { + backspace(); + } + finally { + applianceManager.removeListener(listener); + } + assertFalse(fail.get()); + } private void init(final int visibleWidthInColumns, @NotNull String fileText) throws IOException { - int symbolWidthInPixels = 7; + init(visibleWidthInColumns, 7, fileText); + } + + private void init(final int visibleWidthInColumns, final int symbolWidthInPixels, @NotNull String fileText) throws IOException { init(visibleWidthInColumns * symbolWidthInPixels, fileText, symbolWidthInPixels); } diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java index 2b47564cdc7b..75460d2f4fab 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java @@ -588,14 +588,13 @@ public class DirectoryIndexImpl extends DirectoryIndex { } protected void fillMapWithOrderEntries(final VirtualFile root, - final Collection orderEntries, + @NotNull final Collection orderEntries, @Nullable final Module module, @Nullable final VirtualFile libraryClassRoot, @Nullable final VirtualFile librarySourceRoot, @Nullable final DirectoryInfo parentInfo, @Nullable final ProgressIndicator progress) { VfsUtilCore.visitChildrenRecursively(root, new DirectoryVisitor() { - private final Stack> myEntries = new Stack>(); @Override diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryInfo.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryInfo.java index 99b1d53db572..6d2b262ca8a7 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryInfo.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryInfo.java @@ -21,6 +21,7 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.roots.OrderEntry; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -80,12 +81,13 @@ public class DirectoryInfo { "}"; } + @NotNull public List getOrderEntries() { return orderEntries == null ? Collections.emptyList() : orderEntries; } @SuppressWarnings({"unchecked"}) - public void addOrderEntries(Collection orderEntries, + public void addOrderEntries(@NotNull Collection orderEntries, @Nullable final DirectoryInfo parentInfo, @Nullable final List oldParentEntries) { if (orderEntries.isEmpty()) { diff --git a/platform/util-rt/src/com/intellij/openapi/util/Comparing.java b/platform/util-rt/src/com/intellij/openapi/util/Comparing.java index 95c7d6df8676..bb0d90e2af5d 100644 --- a/platform/util-rt/src/com/intellij/openapi/util/Comparing.java +++ b/platform/util-rt/src/com/intellij/openapi/util/Comparing.java @@ -16,6 +16,8 @@ package com.intellij.openapi.util; import com.intellij.openapi.util.text.StringUtilRt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Arrays; import java.util.Collection; @@ -28,24 +30,22 @@ import java.util.Set; public class Comparing { private Comparing() { } - public static boolean equal(T arg1, T arg2){ + public static boolean equal(@Nullable T arg1, @Nullable T arg2){ if (arg1 == null || arg2 == null){ return arg1 == arg2; } - else if (arg1 instanceof Object[] && arg2 instanceof Object[]){ + if (arg1 instanceof Object[] && arg2 instanceof Object[]){ Object[] arr1 = (Object[])arg1; Object[] arr2 = (Object[])arg2; return Arrays.equals(arr1, arr2); } - else if (arg1 instanceof CharSequence && arg2 instanceof CharSequence) { + if (arg1 instanceof CharSequence && arg2 instanceof CharSequence) { return equal((CharSequence)arg1, (CharSequence)arg2, true); } - else{ - return arg1.equals(arg2); - } + return arg1.equals(arg2); } - public static boolean equal(T[] arr1, T[] arr2){ + public static boolean equal(@Nullable T[] arr1, @Nullable T[] arr2){ if (arr1 == null || arr2 == null){ return arr1 == arr2; } @@ -60,7 +60,7 @@ public class Comparing { return equal(arg1, arg2, true); } - public static boolean equal(CharSequence s1, CharSequence s2, boolean caseSensitive) { + public static boolean equal(@Nullable CharSequence s1, @Nullable CharSequence s2, boolean caseSensitive) { if (s1 == s2) return true; if (s1 == null || s2 == null) return false; @@ -84,7 +84,7 @@ public class Comparing { return true; } - public static boolean equal(String arg1, String arg2, boolean caseSensitive){ + public static boolean equal(@Nullable String arg1, @Nullable String arg2, boolean caseSensitive){ if (arg1 == null || arg2 == null){ return arg1 == arg2; } @@ -97,11 +97,11 @@ public class Comparing { return strEqual(arg1, arg2, true); } - public static boolean strEqual(String arg1, String arg2, boolean caseSensitive){ + public static boolean strEqual(@Nullable String arg1, @Nullable String arg2, boolean caseSensitive){ return equal(arg1 == null ? "" : arg1, arg2 == null ? "" : arg2, caseSensitive); } - public static boolean haveEqualElements(Collection a, Collection b) { + public static boolean haveEqualElements(@NotNull Collection a, @NotNull Collection b) { if (a.size() != b.size()) { return false; } @@ -115,7 +115,7 @@ public class Comparing { return true; } - public static boolean haveEqualElements(T[] a, T[] b) { + public static boolean haveEqualElements(@Nullable T[] a, @Nullable T[] b) { if (a == null || b == null) { return a == b; } @@ -133,7 +133,7 @@ public class Comparing { return true; } - public static int hashcode(Object obj) { return obj == null ? 0 : obj.hashCode(); } + public static int hashcode(@Nullable Object obj) { return obj == null ? 0 : obj.hashCode(); } public static int hashcode(Object obj1, Object obj2) { return hashcode(obj1) ^ hashcode(obj2); } public static int compare(byte o1, byte o2) { @@ -152,7 +152,7 @@ public class Comparing { return o1 < o2 ? -1 : o1 == o2 ? 0 : 1; } - public static int compare(byte[] o1, byte[] o2) { + public static int compare(@Nullable byte[] o1, @Nullable byte[] o2) { if (o1 == o2) return 0; if (o1 == null) return 1; if (o2 == null) return -1; @@ -167,7 +167,7 @@ public class Comparing { return 0; } - public static > int compare(final T o1, final T o2) { + public static > int compare(@Nullable final T o1, @Nullable final T o2) { if (o1 == null) return o2 == null ? 0 : -1; if (o2 == null) return 1; return o1.compareTo(o2); diff --git a/platform/util/src/com/intellij/execution/process/UnixProcessManager.java b/platform/util/src/com/intellij/execution/process/UnixProcessManager.java index b2374f7e1060..58f1857dfebf 100644 --- a/platform/util/src/com/intellij/execution/process/UnixProcessManager.java +++ b/platform/util/src/com/intellij/execution/process/UnixProcessManager.java @@ -15,6 +15,7 @@ */ package com.intellij.execution.process; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.SystemInfo; import com.intellij.util.Processor; @@ -45,6 +46,8 @@ public class UnixProcessManager { } } catch (Exception e) { + Logger log = Logger.getInstance(UnixProcessManager.class); + log.warn("Can't load c library", e); C_LIB = null; } } diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java index 084ac6b1fa1f..626d39698e20 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -1331,6 +1331,9 @@ public class StringUtil extends StringUtilRt { return value.indexOf(ch) >= 0; } + /** + * @deprecated use #capitalize(String) + */ @Nullable public static String firstLetterToUpperCase(@Nullable final String displayString) { if (displayString == null || displayString.isEmpty()) return displayString; @@ -1658,13 +1661,11 @@ public class StringUtil extends StringUtilRt { @NonNls private static final String[] REPLACES_REFS = {"<", ">", "&", "'", """}; @NonNls private static final String[] REPLACES_DISP = {"<", ">", "&", "'", "\""}; - @Nullable public static String unescapeXml(@Nullable final String text) { if (text == null) return null; return replace(text, REPLACES_REFS, REPLACES_DISP); } - @Nullable public static String escapeXml(@Nullable final String text) { if (text == null) return null; return replace(text, REPLACES_DISP, REPLACES_REFS); diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java b/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java index f33408cea62e..f817157db891 100644 --- a/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java +++ b/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java @@ -18,6 +18,7 @@ package com.intellij.util.containers; import com.intellij.util.ConcurrencyUtil; import gnu.trove.TObjectHashingStrategy; +import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.io.Serializable; @@ -592,6 +593,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur } // inherit Map javadoc + @Override public boolean isEmpty() { final Segment[] segments = this.segments; /* @@ -625,6 +627,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur } // inherit Map javadoc + @Override public int size() { final Segment[] segments = this.segments; long sum = 0; @@ -678,6 +681,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * @throws NullPointerException if the key is * null. */ + @Override public V get(Object key) { int hash = myHashingStrategy.computeHashCode((K)key); // throws NullPointerException if key null return segmentFor(hash).get((K)key, hash); @@ -693,6 +697,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * @throws NullPointerException if the key is * null. */ + @Override public boolean containsKey(Object key) { int hash = myHashingStrategy.computeHashCode((K)key); // throws NullPointerException if key null return segmentFor(hash).containsKey((K)key, hash); @@ -709,9 +714,8 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * specified value. * @throws NullPointerException if the value is null. */ - public boolean containsValue(Object value) { - if (value == null) - throw new NullPointerException(); + @Override + public boolean containsValue(@NotNull Object value) { // See explanation of modCount use above @@ -793,9 +797,8 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * @throws NullPointerException if the key or value is * null. */ - public V put(K key, V value) { - if (value == null) - throw new NullPointerException(); + @Override + public V put(K key, @NotNull V value) { int hash = myHashingStrategy.computeHashCode(key); return segmentFor(hash).put(key, hash, value, false); } @@ -818,9 +821,8 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * @throws NullPointerException if the specified key or value is * null. */ - public V putIfAbsent(K key, V value) { - if (value == null) - throw new NullPointerException(); + @Override + public V putIfAbsent(@NotNull K key, @NotNull V value) { int hash = myHashingStrategy.computeHashCode(key); return segmentFor(hash).put(key, hash, value, true); } @@ -834,6 +836,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * * @param t Mappings to be stored in this map. */ + @Override public void putAll(Map t) { for (Iterator> it = (Iterator>) t.entrySet().iterator(); it.hasNext(); ) { Entry e = it.next(); @@ -851,6 +854,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * @throws NullPointerException if the key is * null. */ + @Override public V remove(Object key) { int hash = myHashingStrategy.computeHashCode((K)key); return segmentFor(hash).remove((K)key, hash, null); @@ -872,7 +876,8 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * @throws NullPointerException if the specified key is * null. */ - public boolean remove(Object key, Object value) { + @Override + public boolean remove(@NotNull Object key, Object value) { int hash = myHashingStrategy.computeHashCode((K)key); return segmentFor(hash).remove((K)key, hash, value) != null; } @@ -895,9 +900,8 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * @throws NullPointerException if the specified key or values are * null. */ - public boolean replace(K key, V oldValue, V newValue) { - if (oldValue == null || newValue == null) - throw new NullPointerException(); + @Override + public boolean replace(@NotNull K key, @NotNull V oldValue, @NotNull V newValue) { int hash = myHashingStrategy.computeHashCode(key); return segmentFor(hash).replace(key, hash, oldValue, newValue); } @@ -918,9 +922,8 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * @throws NullPointerException if the specified key or value is * null. */ - public V replace(K key, V value) { - if (value == null) - throw new NullPointerException(); + @Override + public V replace(@NotNull K key, @NotNull V value) { int hash = myHashingStrategy.computeHashCode(key); return segmentFor(hash).replace(key, hash, value); } @@ -929,9 +932,9 @@ public class ConcurrentHashMap extends AbstractMap implements Concur /** * Removes all mappings from this map. */ + @Override public void clear() { - for (int i = 0; i < segments.length; ++i) - segments[i].clear(); + for (Segment segment : segments) segment.clear(); } /** @@ -950,6 +953,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * * @return a set view of the keys contained in this map. */ + @Override public Set keySet() { Set ks = keySet; return (ks != null) ? ks : (keySet = new KeySet()); @@ -972,6 +976,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * * @return a collection view of the values contained in this map. */ + @Override public Collection values() { Collection vs = values; return (vs != null) ? vs : (values = new Values()); @@ -995,6 +1000,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * * @return a collection view of the mappings contained in this map. */ + @Override public Set> entrySet() { Set> es = entrySet; return (es != null) ? es : (entrySet = (Set>) (Set) new EntrySet()); @@ -1080,12 +1086,16 @@ public class ConcurrentHashMap extends AbstractMap implements Concur } final class KeyIterator extends HashIterator implements Iterator, Enumeration { + @Override public K next() { return super.nextEntry().key; } + @Override public K nextElement() { return super.nextEntry().key; } } final class ValueIterator extends HashIterator implements Iterator, Enumeration { + @Override public V next() { return super.nextEntry().value; } + @Override public V nextElement() { return super.nextEntry().value; } } @@ -1098,23 +1108,27 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * itself acts as a forwarding pseudo-entry. */ final class EntryIterator extends HashIterator implements Entry, Iterator> { + @Override public Entry next() { nextEntry(); return this; } + @Override public K getKey() { if (lastReturned == null) throw new IllegalStateException("Entry was removed"); return lastReturned.key; } + @Override public V getValue() { if (lastReturned == null) throw new IllegalStateException("Entry was removed"); return ConcurrentHashMap.this.get(lastReturned.key); } + @Override public V setValue(V value) { if (lastReturned == null) throw new IllegalStateException("Entry was removed"); @@ -1159,27 +1173,34 @@ public class ConcurrentHashMap extends AbstractMap implements Concur } final class KeySet extends AbstractSet { + @Override public Iterator iterator() { return new KeyIterator(); } + @Override public int size() { return ConcurrentHashMap.this.size(); } + @Override public boolean contains(Object o) { return ConcurrentHashMap.this.containsKey(o); } + @Override public boolean remove(Object o) { return ConcurrentHashMap.this.remove(o) != null; } + @Override public void clear() { ConcurrentHashMap.this.clear(); } + @Override public Object[] toArray() { Collection c = new ArrayList(); for (Iterator i = iterator(); i.hasNext(); ) c.add(i.next()); return c.toArray(); } + @Override public T[] toArray(T[] a) { Collection c = new ArrayList(); for (Iterator i = iterator(); i.hasNext(); ) @@ -1189,24 +1210,30 @@ public class ConcurrentHashMap extends AbstractMap implements Concur } final class Values extends AbstractCollection { + @Override public Iterator iterator() { return new ValueIterator(); } + @Override public int size() { return ConcurrentHashMap.this.size(); } + @Override public boolean contains(Object o) { return ConcurrentHashMap.this.containsValue(o); } + @Override public void clear() { ConcurrentHashMap.this.clear(); } + @Override public Object[] toArray() { Collection c = new ArrayList(); for (Iterator i = iterator(); i.hasNext(); ) c.add(i.next()); return c.toArray(); } + @Override public T[] toArray(T[] a) { Collection c = new ArrayList(); for (Iterator i = iterator(); i.hasNext(); ) @@ -1216,9 +1243,11 @@ public class ConcurrentHashMap extends AbstractMap implements Concur } final class EntrySet extends AbstractSet> { + @Override public Iterator> iterator() { return new EntryIterator(); } + @Override public boolean contains(Object o) { if (!(o instanceof Entry)) return false; @@ -1226,18 +1255,22 @@ public class ConcurrentHashMap extends AbstractMap implements Concur V v = ConcurrentHashMap.this.get(e.getKey()); return v != null && v.equals(e.getValue()); } + @Override public boolean remove(Object o) { if (!(o instanceof Entry)) return false; Entry e = (Entry)o; return ConcurrentHashMap.this.remove(e.getKey(), e.getValue()); } + @Override public int size() { return ConcurrentHashMap.this.size(); } + @Override public void clear() { ConcurrentHashMap.this.clear(); } + @Override public Object[] toArray() { // Since we don't ordinarily have distinct Entry objects, we // must pack elements using exportable SimpleEntry @@ -1246,6 +1279,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur c.add(new SimpleEntry(i.next())); return c.toArray(); } + @Override public T[] toArray(T[] a) { Collection> c = new ArrayList>(size()); for (Iterator> i = iterator(); i.hasNext(); ) @@ -1273,14 +1307,17 @@ public class ConcurrentHashMap extends AbstractMap implements Concur this.value = e.getValue(); } + @Override public K getKey() { return key; } + @Override public V getValue() { return value; } + @Override public V setValue(V value) { V oldValue = this.value; this.value = value; @@ -1368,6 +1405,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur } } + @Override public int computeHashCode(final K object) { int h = object.hashCode(); h += ~(h << 9); @@ -1377,6 +1415,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur return h; } + @Override public boolean equals(final K o1, final K o2) { return o1.equals(o2); } diff --git a/platform/util/src/com/intellij/util/text/StringSearcher.java b/platform/util/src/com/intellij/util/text/StringSearcher.java index ce32dc0199b4..3a86ce5064a4 100644 --- a/platform/util/src/com/intellij/util/text/StringSearcher.java +++ b/platform/util/src/com/intellij/util/text/StringSearcher.java @@ -38,14 +38,14 @@ public class StringSearcher { } public StringSearcher(@NotNull String pattern, boolean caseSensitive, boolean forwardDirection) { - LOG.assertTrue(pattern.length() > 0); + LOG.assertTrue(!pattern.isEmpty()); myPattern = pattern; myCaseSensitive = caseSensitive; myForwardDirection = forwardDirection; myPatternArray = myCaseSensitive ? myPattern.toCharArray() : myPattern.toLowerCase().toCharArray(); myPatternLength = myPatternArray.length; Arrays.fill(mySearchTable, -1); - myJavaIdentifier = pattern.length() == 0 || + myJavaIdentifier = pattern.isEmpty() || Character.isJavaIdentifierPart(pattern.charAt(0)) && Character.isJavaIdentifierPart(pattern.charAt(pattern.length() - 1)); } diff --git a/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerBundle.java b/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerBundle.java index 6442f216e766..ca279cb87852 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerBundle.java +++ b/plugins/android-designer/src/com/intellij/android/designer/AndroidDesignerBundle.java @@ -40,7 +40,9 @@ public class AndroidDesignerBundle { private static ResourceBundle getBundle() { ResourceBundle bundle = null; - if (ourBundle != null) bundle = ourBundle.get(); + if (ourBundle != null) { + bundle = ourBundle.get(); + } if (bundle == null) { bundle = ResourceBundle.getBundle(BUNDLE); ourBundle = new SoftReference(bundle); diff --git a/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java b/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java index 149f5ec81f3b..a01afc543447 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java +++ b/plugins/android-designer/src/com/intellij/android/designer/designSurface/AndroidDesignerEditorPanel.java @@ -31,6 +31,7 @@ import com.intellij.designer.designSurface.selection.NonResizeSelectionDecorator import com.intellij.designer.designSurface.tools.ComponentCreationFactory; import com.intellij.designer.designSurface.tools.ComponentPasteFactory; import com.intellij.designer.model.RadComponent; +import com.intellij.designer.model.WrapInProvider; import com.intellij.designer.palette.DefaultPaletteItem; import com.intellij.designer.palette.PaletteGroup; import com.intellij.designer.palette.PaletteItem; @@ -77,6 +78,7 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { private volatile RenderSession mySession; private boolean myParseTime; private int myProfileLastVersion; + private WrapInProvider myWrapInProvider; public AndroidDesignerEditorPanel(@NotNull DesignerEditor editor, @NotNull Project project, @@ -464,6 +466,14 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel { return myTreeDecorator; } + @Override + public WrapInProvider getWrapInProvider() { + if (myWrapInProvider == null) { + myWrapInProvider = new AndroidWrapInProvider(getProject()); + } + return myWrapInProvider; + } + private static final ComponentDecorator NON_RESIZE_DECORATOR = new NonResizeSelectionDecorator(Color.RED, 2); @Override diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/AndroidWrapInProvider.java b/plugins/android-designer/src/com/intellij/android/designer/model/AndroidWrapInProvider.java new file mode 100644 index 000000000000..46e20f726d8c --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/model/AndroidWrapInProvider.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.android.designer.model; + +import com.intellij.designer.model.MetaModel; +import com.intellij.designer.model.RadComponent; +import com.intellij.designer.model.WrapInProvider; +import com.intellij.openapi.project.Project; + +import java.util.List; + +/** + * @author Alexander Lobas + */ +public final class AndroidWrapInProvider extends WrapInProvider { + public AndroidWrapInProvider(Project project) { + super(ViewsMetaManager.getInstance(project)); + } + + @Override + public RadComponent wrapIn(RadViewComponent parent, List components, MetaModel target) throws Exception { + RadViewComponent newParent = ModelParser.createComponent(null, target); + + ModelParser.addComponent(parent, newParent, components.get(0)); + + for (RadViewComponent component : components) { + ModelParser.moveComponent(newParent, component, null); + } + + RadViewLayout layout = (RadViewLayout)parent.getLayout(); + layout.wrapIn(newParent, components); + + return newParent; + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewLayout.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewLayout.java index 20a36399f595..08165feb0f80 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewLayout.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewLayout.java @@ -43,4 +43,7 @@ public class RadViewLayout extends RadLayout { JComponent shortcuts, List selection) { } + + public void wrapIn(RadViewComponent newParent, List components) throws Exception { + } } \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/layout/RadLinearLayout.java b/plugins/android-designer/src/com/intellij/android/designer/model/layout/RadLinearLayout.java index 516c15bf3f3f..37c8d7ed6ae1 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/layout/RadLinearLayout.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/layout/RadLinearLayout.java @@ -21,6 +21,7 @@ import com.intellij.android.designer.designSurface.layout.actions.LayoutMarginOp import com.intellij.android.designer.designSurface.layout.actions.LayoutWeightOperation; import com.intellij.android.designer.designSurface.layout.actions.ResizeOperation; import com.intellij.android.designer.designSurface.layout.flow.FlowStaticDecorator; +import com.intellij.android.designer.model.ModelParser; import com.intellij.android.designer.model.RadViewComponent; import com.intellij.android.designer.model.RadViewLayoutWithData; import com.intellij.android.designer.model.layout.actions.AbstractGravityAction; @@ -34,6 +35,7 @@ import com.intellij.designer.model.RadComponent; import com.intellij.designer.utils.Position; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.util.Pair; import org.jetbrains.annotations.NotNull; @@ -280,4 +282,71 @@ public class RadLinearLayout extends RadViewLayoutWithData implements ILayoutDec actionGroup.add(new OrientationAction(designer, components, horizontal, override)); } + + @Override + public boolean isWrapIn(List components) { + List children = myContainer.getChildren(); + + int[] indexes = new int[components.size()]; + for (int i = 0; i < indexes.length; i++) { + indexes[i] = children.indexOf(components.get(i)); + } + Arrays.sort(indexes); + + for (int i = 0; i < indexes.length - 1; i++) { + if (indexes[i + 1] - indexes[i] != 1) { + return false; + } + } + + return true; + } + + @Override + public void wrapIn(final RadViewComponent newParent, final List components) throws Exception { + final boolean horizontal = isHorizontal(); + RadViewComponent firstComponent = components.get(0); + boolean single = components.size() == 1; + String layoutWidth = single ? firstComponent.getTag().getAttributeValue("android:layout_width") : "wrap_content"; + String layoutHeight = single ? firstComponent.getTag().getAttributeValue("android:layout_height") : "wrap_content"; + String layoutGravity = firstComponent.getTag().getAttributeValue("android:layout_gravity"); + + if (horizontal) { + for (RadViewComponent component : components.subList(1, components.size())) { + String height = component.getTag().getAttributeValue("android:layout_height"); + if ("fill_parent".equals(height) || "match_parent".equals(height)) { + layoutHeight = "fill_parent"; + layoutGravity = null; + } + if (layoutGravity != null && layoutGravity.equals(component.getTag().getAttributeValue("android:layout_gravity"))) { + + } + } + } + else { + + } + + if (newParent.getLayout() instanceof RadLinearLayout) { + RadLinearLayout layout = (RadLinearLayout)newParent.getLayout(); + if (horizontal != layout.isHorizontal()) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + newParent.getTag().setAttribute("android:orientation", horizontal ? "horizontal" : "vertical"); + } + }); + } + } + else { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + for (RadViewComponent component : components) { + ModelParser.deleteAttribute(component.getTag(), "android:layout_gravity"); + } + } + }); + } + } } \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml index eb369e8a4e9d..0311d7976093 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml +++ b/plugins/android-designer/src/com/intellij/android/designer/model/views-meta-model.xml @@ -1447,6 +1447,15 @@ + + + + + + + + + diff --git a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceDialog.java b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceDialog.java index e9ff9e1096fc..ac83779ee551 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceDialog.java +++ b/plugins/android-designer/src/com/intellij/android/designer/propertyTable/editors/ResourceDialog.java @@ -210,7 +210,7 @@ public class ResourceDialog extends DialogWrapper implements TreeSelectionListen } } myExtractStyleAction.getTemplatePresentation().setEnabled(enabled); - actionGroup.add(myExtractStyleAction); + //actionGroup.add(myExtractStyleAction); // XXX } return actionManager.createActionPopupMenu(ActionPlaces.UNKNOWN, actionGroup); @@ -366,7 +366,7 @@ public class ResourceDialog extends DialogWrapper implements TreeSelectionListen myResultResourceName = prefix + element.getName(); } - panel.showPreview(element, isProjectPanel); + //panel.showPreview(element, isProjectPanel); // XXX } } @@ -447,7 +447,7 @@ public class ResourceDialog extends DialogWrapper implements TreeSelectionListen myComponent.add(ScrollPaneFactory.createScrollPane(myTree), BorderLayout.CENTER); myPreviewPanel = new JPanel(new CardLayout()); - myComponent.add(myPreviewPanel, BorderLayout.SOUTH); + //myComponent.add(myPreviewPanel, BorderLayout.SOUTH); // XXX myTextArea = new JTextArea(5, 20); myPreviewPanel.add(ScrollPaneFactory.createScrollPane(myTextArea), TEXT); diff --git a/plugins/android/src/org/jetbrains/android/AndroidFileTemplateProvider.java b/plugins/android/src/org/jetbrains/android/AndroidFileTemplateProvider.java index 61f0c9069fe9..b2f24459633c 100644 --- a/plugins/android/src/org/jetbrains/android/AndroidFileTemplateProvider.java +++ b/plugins/android/src/org/jetbrains/android/AndroidFileTemplateProvider.java @@ -84,18 +84,18 @@ public class AndroidFileTemplateProvider implements FileTemplateGroupDescriptorF @NotNull VirtualFile rootDir, @NotNull String templateName, @NotNull String fileName) throws Exception { - return createFromTemplate(project, rootDir, templateName, fileName, FileTemplateManager.getInstance().getDefaultProperties()); + return createFromTemplate(project, rootDir, templateName, fileName, FileTemplateManager.getInstance().getDefaultProperties(project)); } - public static PsiElement createFromTemplate(String templateName, String fileName, PsiDirectory directory, Properties properties) + public static PsiElement createFromTemplate(String templateName, String fileName, @NotNull PsiDirectory directory, Properties properties) throws Exception { FileTemplateManager manager = FileTemplateManager.getInstance(); FileTemplate template = manager.getJ2eeTemplate(templateName); return FileTemplateUtil.createFromTemplate(template, fileName, properties, directory); } - public static PsiElement createFromTemplate(String templateName, String fileName, PsiDirectory directory) throws Exception { - return createFromTemplate(templateName, fileName, directory, FileTemplateManager.getInstance().getDefaultProperties()); + public static PsiElement createFromTemplate(String templateName, String fileName, @NotNull PsiDirectory directory) throws Exception { + return createFromTemplate(templateName, fileName, directory, FileTemplateManager.getInstance().getDefaultProperties(directory.getProject())); } @NotNull diff --git a/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java b/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java index 294eb2c69281..3c0f589128e6 100644 --- a/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java +++ b/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java @@ -459,7 +459,7 @@ public class AndroidModuleBuilder extends JavaModuleBuilder { return; } - Properties properties = FileTemplateManager.getInstance().getDefaultProperties(); + Properties properties = FileTemplateManager.getInstance().getDefaultProperties(project); properties.setProperty("TARGET", platform.getTarget().hashString()); AndroidFileTemplateProvider.createFromTemplate(project, contentRoot, AndroidFileTemplateProvider.DEFAULT_PROPERTIES_TEMPLATE, SdkConstants.FN_PROJECT_PROPERTIES, properties); diff --git a/plugins/git4idea/src/git4idea/config/GitVcsSettings.java b/plugins/git4idea/src/git4idea/config/GitVcsSettings.java index 3dfbca3a803f..2a0df2f5481e 100644 --- a/plugins/git4idea/src/git4idea/config/GitVcsSettings.java +++ b/plugins/git4idea/src/git4idea/config/GitVcsSettings.java @@ -69,7 +69,7 @@ public class GitVcsSettings implements PersistentStateComponent { - public static final String DEFAULT_GITHUB_HOST = "github.com"; - private static final String GITHUB_SETTINGS_TAG = "GithubSettings"; private static final String LOGIN = "Login"; private static final String HOST = "Host"; @@ -154,7 +153,7 @@ public class GithubSettings implements PersistentStateComponent { } public String getHost() { - return myHost != null ? myHost : DEFAULT_GITHUB_HOST; + return myHost != null ? myHost : GithubApiUtil.DEFAULT_GITHUB_HOST; } public boolean isAnonymous() { @@ -187,7 +186,7 @@ public class GithubSettings implements PersistentStateComponent { } public void setHost(final String host) { - myHost = host != null ? host : DEFAULT_GITHUB_HOST; + myHost = host != null ? host : GithubApiUtil.DEFAULT_GITHUB_HOST; } public void setAnonymousGist(final boolean anonymousGist) { diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java index fe1806b8bd50..14957e7b7374 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java @@ -39,6 +39,7 @@ import com.intellij.openapi.vcs.changes.ChangeListManagerImpl; import com.intellij.openapi.vcs.changes.InvokeAfterUpdateMode; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.tasks.github.GithubApiUtil; import com.intellij.util.concurrency.Semaphore; import com.intellij.util.containers.HashSet; import git4idea.GitDeprecatedRemote; @@ -161,7 +162,7 @@ public class GithubShareAction extends DumbAwareAction { @NotNull String description, boolean aPrivate) throws IOException { String path = "/user/repos"; String requestBody = prepareRequest(name, description, aPrivate); - JsonElement result = GithubUtil.postRequest(host, login, password, path, requestBody); + JsonElement result = GithubApiUtil.postRequest(host, login, password, path, requestBody); if (result == null) { return false; } diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java b/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java index 52e9e6fcb215..ae7c4add6729 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java @@ -17,8 +17,6 @@ package org.jetbrains.plugins.github; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.JsonSyntaxException; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; @@ -30,19 +28,12 @@ import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.net.HttpConfigurable; +import com.intellij.tasks.github.GithubApiUtil; import git4idea.config.GitVcsApplicationSettings; import git4idea.config.GitVersion; import git4idea.i18n.GitBundle; import git4idea.repo.GitRemote; import git4idea.repo.GitRepository; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpMethod; -import org.apache.commons.httpclient.UsernamePasswordCredentials; -import org.apache.commons.httpclient.auth.AuthScope; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.commons.httpclient.methods.PostMethod; -import org.apache.commons.httpclient.methods.StringRequestEntity; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.github.ui.GithubLoginDialog; @@ -68,7 +59,7 @@ public class GithubUtil { static final String GITHUB_NOTIFICATION_GROUP = "github"; /** - * @deprecated The host may be defined in different formats. Use {@link #getApiUrl(String)} instead. + * @deprecated The host may be defined in different formats. Use {@link com.intellij.tasks.github.GithubApiUtil#getApiUrl(String)} instead. */ @Deprecated public static String getHttpsUrl() { @@ -101,132 +92,6 @@ public class GithubUtil { }); } - @Nullable - public static JsonElement getRequest(@NotNull String host, @NotNull String login, @NotNull String password, - @NotNull String path) throws IOException { - return request(host, login, password, path, null, false); - } - - @Nullable - public static JsonElement postRequest(@NotNull String host, @Nullable String login, @Nullable String password, - @NotNull String path, @Nullable String requestBody) throws IOException { - return request(host, login, password, path, requestBody, true); - } - - @Nullable - private static JsonElement request(@NotNull String host, @Nullable String login, @Nullable String password, - @NotNull String path, @Nullable String requestBody, boolean post) throws IOException { - HttpMethod method = null; - try { - method = doREST(host, login, password, path, requestBody, post); - String resp = method.getResponseBodyAsString(); - if (resp == null) { - LOG.info(String.format("Unexpectedly empty response: %s", resp)); - return null; - } - return parseResponse(resp); - } - finally { - if (method != null) { - method.releaseConnection(); - } - } - } - - @NotNull - private static HttpMethod doREST(@NotNull String host, @Nullable String login, @Nullable String password, @NotNull String path, - @Nullable String requestBody, final boolean post) throws IOException { - final HttpClient client = getHttpClient(login, password); - final String uri = getApiUrl(host) + path; - final HttpMethod method; - if (post) { - method = new PostMethod(uri); - if (requestBody != null) { - ((PostMethod)method).setRequestEntity(new StringRequestEntity(requestBody, "application/json", "UTF-8")); - } - } - else { - method = new GetMethod(uri); - } - - client.executeMethod(method); - return method; - } - - @NotNull - private static String removeProtocolPrefix(final String url) { - if (url.startsWith("https://")) { - return url.substring(8); - } - else if (url.startsWith("http://")) { - return url.substring(7); - } - else if (url.startsWith("git@")) { - return url.substring(4); - } - else { - return url; - } - } - - @NotNull - private static String getApiUrl(@NotNull String urlFromSettings) { - return "https://" + getApiUrlWithoutProtocol(urlFromSettings); - } - - /* - All API access is over HTTPS, and accessed from the api.github.com domain - (or through yourdomain.com/api/v3/ for enterprise). - http://developer.github.com/v3/ - */ - @NotNull - private static String getApiUrlWithoutProtocol(String urlFromSettings) { - String url = removeTrailingSlash(removeProtocolPrefix(urlFromSettings)); - final String API_PREFIX = "api."; - final String ENTERPRISE_API_SUFFIX = "/api/v3"; - - if (url.equals(GithubSettings.DEFAULT_GITHUB_HOST)) { - return API_PREFIX + url; - } - else if (url.equals(API_PREFIX + GithubSettings.DEFAULT_GITHUB_HOST)) { - return url; - } - else if (url.endsWith(ENTERPRISE_API_SUFFIX)) { - return url; - } - else { - return url + ENTERPRISE_API_SUFFIX; - } - } - - private static String removeTrailingSlash(String s) { - if (s.endsWith("/")) { - return s.substring(0, s.length() - 1); - } - return s; - } - - @NotNull - private static HttpClient getHttpClient(@Nullable final String login, @Nullable final String password) { - final HttpClient client = new HttpClient(); - client.getParams().setContentCharset("UTF-8"); - // Configure proxySettings if it is required - final HttpConfigurable proxySettings = HttpConfigurable.getInstance(); - if (proxySettings.USE_HTTP_PROXY){ - client.getHostConfiguration().setProxy(proxySettings.PROXY_HOST, proxySettings.PROXY_PORT); - if (proxySettings.PROXY_AUTHENTICATION) { - client.getState().setProxyCredentials(AuthScope.ANY, new UsernamePasswordCredentials(proxySettings.PROXY_LOGIN, - proxySettings.getPlainProxyPassword())); - } - } - if (login != null && password != null) { - client.getParams().setCredentialCharset("UTF-8"); - client.getParams().setAuthenticationPreemptive(true); - client.getState().setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(login, password)); - } - return client; - } - private static boolean testConnection(final String url, final String login, final String password) { GithubUser user = retrieveCurrentUserInfo(url, login, password); return user != null; @@ -235,7 +100,7 @@ public class GithubUtil { @Nullable private static GithubUser retrieveCurrentUserInfo(@NotNull String url, @NotNull String login, @NotNull String password) { try { - JsonElement result = getRequest(url, login, password, "/user"); + JsonElement result = GithubApiUtil.getRequest(url, login, password, "/user"); return parseUserInfo(result); } catch (IOException e) { @@ -270,22 +135,12 @@ public class GithubUtil { return GithubUser.Plan.fromString(plan.getAsJsonObject().get("name").getAsString()); } - @NotNull - private static JsonElement parseResponse(@NotNull String githubResponse) throws IOException { - try { - return new JsonParser().parse(githubResponse); - } - catch (JsonSyntaxException jse) { - throw new IOException(String.format("Couldn't parse GitHub response:%n%s", githubResponse), jse); - } - } - @NotNull private static List getAvailableRepos(@NotNull String url, @NotNull String login, @NotNull String password, boolean ownOnly) { final String request = (ownOnly ? "/user/repos" : "/user/watched"); try { - JsonElement result = getRequest(url, login, password, request); + JsonElement result = GithubApiUtil.getRequest(url, login, password, request); if (result == null) { return Collections.emptyList(); } @@ -328,7 +183,7 @@ public class GithubUtil { @NotNull String owner, @NotNull String name) { try { final String request = "/repos/" + owner + "/" + name; - JsonElement jsonObject = getRequest(url, login, password, request); + JsonElement jsonObject = GithubApiUtil.getRequest(url, login, password, request); if (jsonObject == null) { LOG.info(String.format("Information about repository is unavailable. Owner: %s, Name: %s", owner, name)); return null; diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index d76c850c98e0..bb36d902c000 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -260,7 +260,7 @@ - + org.jetbrains.plugins.groovy.codeInspection.local.GroovyUnusedImportsPassFactory - org.jetbrains.plugins.groovy.annotator.KeywordHighlightFactory + org.jetbrains.plugins.groovy.annotator.GrKeywordAndDeclarationHighlightFactory + + + org.jetbrains.plugins.groovy.annotator.GrReferenceHighlighterFactory org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicManager diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/GroovyTemplatesFactory.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/GroovyTemplatesFactory.java index e3fe731bb084..070b33f95d2b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/GroovyTemplatesFactory.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/GroovyTemplatesFactory.java @@ -80,7 +80,7 @@ public class GroovyTemplatesFactory implements FileTemplateGroupDescriptorFactor @NonNls String... parameters) throws IncorrectOperationException { final FileTemplate template = FileTemplateManager.getInstance().getInternalTemplate(templateName); - Properties properties = new Properties(FileTemplateManager.getInstance().getDefaultProperties()); + Properties properties = new Properties(FileTemplateManager.getInstance().getDefaultProperties(directory.getProject())); JavaTemplateUtil.setPackageNameAttribute(properties, directory); properties.setProperty(NAME_TEMPLATE_PROPERTY, name); properties.setProperty(LOW_CASE_NAME_TEMPLATE_PROPERTY, name.substring(0, 1).toLowerCase() + name.substring(1)); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GrHighlightUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GrHighlightUtil.java new file mode 100644 index 000000000000..2405d391627b --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GrHighlightUtil.java @@ -0,0 +1,186 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.annotator; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.colors.TextAttributesKey; +import com.intellij.openapi.util.TextRange; +import com.intellij.pom.PomDeclarationSearcher; +import com.intellij.pom.PomTarget; +import com.intellij.psi.*; +import com.intellij.psi.search.LocalSearchScope; +import com.intellij.psi.search.searches.ReferencesSearch; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.CollectConsumer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.extensions.GroovyUnresolvedHighlightFilter; +import org.jetbrains.plugins.groovy.highlighter.DefaultHighlighter; +import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; +import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod; +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; +import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; + +/** + * @author Max Medvedev + */ +public class GrHighlightUtil { + private static final Logger LOG = Logger.getInstance(GrHighlightUtil.class); + + static boolean isReassigned(GrVariable var) { + PsiMethod method = PsiTreeUtil.getParentOfType(var, PsiMethod.class); + PsiNamedElement scope = method == null ? var.getContainingFile() : method; + if (scope == null) { + return false; + } + boolean hasAssignment = var.getInitializerGroovy() != null || var instanceof GrParameter; + for (PsiReference reference : ReferencesSearch.search(var, new LocalSearchScope(scope)).findAll()) { + if (reference instanceof GrReferenceExpression && + (PsiUtil.isLValue((GrReferenceExpression)reference) || + ((GrReferenceExpression)reference).getParent() instanceof GrUnaryExpression && + ((GrUnaryExpression)((GrReferenceExpression)reference).getParent()).isPostfix())) { + if (hasAssignment) { + return true; + } + hasAssignment = true; + } + } + return false; + } + + @Nullable + static TextAttributesKey getDeclarationHighlightingAttribute(PsiElement resolved) { + if (resolved instanceof PsiField || resolved instanceof GrVariable && ResolveUtil.isScriptField((GrVariable)resolved)) { + boolean isStatic = ((PsiVariable)resolved).hasModifierProperty(PsiModifier.STATIC); + return isStatic ? DefaultHighlighter.STATIC_FIELD : DefaultHighlighter.INSTANCE_FIELD; + } + else if (resolved instanceof GrAccessorMethod) { + boolean isStatic = ((GrAccessorMethod)resolved).hasModifierProperty(PsiModifier.STATIC); + return isStatic ? DefaultHighlighter.STATIC_PROPERTY_REFERENCE : DefaultHighlighter.INSTANCE_PROPERTY_REFERENCE; + } + else if (resolved instanceof PsiMethod) { + if (!((PsiMethod)resolved).isConstructor()) { + boolean isStatic = ((PsiMethod)resolved).hasModifierProperty(PsiModifier.STATIC); + if (GroovyPropertyUtils.isSimplePropertyAccessor((PsiMethod)resolved)) { + return isStatic ? DefaultHighlighter.STATIC_PROPERTY_REFERENCE : DefaultHighlighter.INSTANCE_PROPERTY_REFERENCE; + } + else { + return isStatic ? DefaultHighlighter.STATIC_METHOD_ACCESS : DefaultHighlighter.METHOD_CALL; + } + } + } + else if (resolved instanceof PsiTypeParameter) { + return DefaultHighlighter.TYPE_PARAMETER; + } + else if (resolved instanceof PsiClass) { + if (((PsiClass)resolved).isAnnotationType()) { + return DefaultHighlighter.ANNOTATION; + } + else { + return DefaultHighlighter.CLASS_REFERENCE; + } + } + else if (resolved instanceof GrParameter) { + boolean reassigned = isReassigned((GrParameter)resolved); + return reassigned ? DefaultHighlighter.REASSIGNED_PARAMETER : DefaultHighlighter.PARAMETER; + } + else if (resolved instanceof GrVariable) { + boolean reassigned = isReassigned((GrVariable)resolved); + return reassigned ? DefaultHighlighter.REASSIGNED_LOCAL_VARIABLE : DefaultHighlighter.LOCAL_VARIABLE; + } + return null; + } + + public static boolean isDeclarationAssignment(GrReferenceExpression refExpr) { + if (isAssignmentLhs(refExpr)) { + return isExpandoQualified(refExpr); + } + return false; + } + + private static boolean isAssignmentLhs(GrReferenceExpression refExpr) { + return refExpr.getParent() instanceof GrAssignmentExpression && + refExpr.equals(((GrAssignmentExpression)refExpr.getParent()).getLValue()); + } + + private static boolean isExpandoQualified(GrReferenceExpression refExpr) { + final GrExpression qualifier = refExpr.getQualifierExpression(); + if (qualifier == null) { + final PsiClass clazz = PsiTreeUtil.getParentOfType(refExpr, PsiClass.class); + if (clazz == null) { //script + return true; + } + return false; //in class, a property should normally be defined, so it's not a declaration + } + + final PsiType type = qualifier.getType(); + if (type instanceof PsiClassType) { + final PsiClassType classType = (PsiClassType)type; + final PsiClass psiClass = classType.resolve(); + if (psiClass instanceof GroovyScriptClass) { + return true; + } + } + return false; + } + + public static boolean shouldHighlightAsUnresolved(@NotNull GrReferenceExpression referenceExpression) { + PsiElement refNameElement = referenceExpression.getReferenceNameElement(); + if (refNameElement != null && referenceExpression.getQualifier() == null) { + final IElementType type = refNameElement.getNode().getElementType(); + if (TokenSets.STRING_LITERAL_SET.contains(type)) return false; + } + + if (!GroovyUnresolvedHighlightFilter.shouldHighlight(referenceExpression)) return false; + + CollectConsumer consumer = new CollectConsumer(); + + for (PomDeclarationSearcher searcher : PomDeclarationSearcher.EP_NAME.getExtensions()) { + searcher.findDeclarationsAt(referenceExpression, 0, consumer); + if (consumer.getResult().size() > 0) return false; + } + + return true; + } + + public static TextRange getMethodHeaderTextRange(PsiMethod method) { + final PsiModifierList modifierList = method.getModifierList(); + final PsiParameterList parameterList = method.getParameterList(); + + final TextRange textRange = modifierList.getTextRange(); + LOG.assertTrue(textRange != null, method.getClass() + ":" + method.getText()); + int startOffset = textRange.getStartOffset(); + int endOffset = parameterList.getTextRange().getEndOffset() + 1; + + return new TextRange(startOffset, endOffset); + } + + @NotNull + public static PsiElement getElementToHighlight(@NotNull GrReferenceElement refElement) { + final PsiElement refNameElement = refElement.getReferenceNameElement(); + return refNameElement != null ? refNameElement : refElement; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GrKeywordAndDeclarationHighlightFactory.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GrKeywordAndDeclarationHighlightFactory.java new file mode 100644 index 000000000000..7bae467223bf --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GrKeywordAndDeclarationHighlightFactory.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.annotator; + +import com.intellij.codeHighlighting.TextEditorHighlightingPass; +import com.intellij.codeHighlighting.TextEditorHighlightingPassFactory; +import com.intellij.codeHighlighting.TextEditorHighlightingPassRegistrar; +import com.intellij.openapi.components.AbstractProjectComponent; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; + +/** + * @author Max Medvedev + */ +public class GrKeywordAndDeclarationHighlightFactory extends AbstractProjectComponent implements TextEditorHighlightingPassFactory { + protected GrKeywordAndDeclarationHighlightFactory(Project project) { + super(project); + + TextEditorHighlightingPassRegistrar.getInstance(project).registerTextEditorHighlightingPass(this, null, null, false, -1); + } + + + @Override + public TextEditorHighlightingPass createHighlightingPass(@NotNull PsiFile file, @NotNull Editor editor) { + if (!(file instanceof GroovyFile)) return null; + return new GrKeywordAndDeclarationHighlighter((GroovyFile)file, editor.getDocument()); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/KeywordHighlighter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GrKeywordAndDeclarationHighlighter.java similarity index 66% rename from plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/KeywordHighlighter.java rename to plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GrKeywordAndDeclarationHighlighter.java index 9ee5fbf48d10..4b28c58c38b9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/KeywordHighlighter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GrKeywordAndDeclarationHighlighter.java @@ -20,16 +20,20 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.HighlightInfoType; import com.intellij.codeInsight.daemon.impl.UpdateHighlightersUtil; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiRecursiveElementVisitor; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.highlighter.DefaultHighlighter; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; +import org.jetbrains.plugins.groovy.lang.psi.GrNamedElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; @@ -40,12 +44,12 @@ import java.util.List; /** * @author Max Medvedev */ -public class KeywordHighlighter extends TextEditorHighlightingPass { +public class GrKeywordAndDeclarationHighlighter extends TextEditorHighlightingPass { private final GroovyFile myFile; private List toHighlight; - protected KeywordHighlighter(GroovyFile file, Document document) { + protected GrKeywordAndDeclarationHighlighter(GroovyFile file, Document document) { super(file.getProject(), document); myFile = file; } @@ -58,7 +62,15 @@ public class KeywordHighlighter extends TextEditorHighlightingPass { public void visitElement(PsiElement element) { IElementType tokenType = element.getNode().getElementType(); if (TokenSets.KEYWORDS.contains(tokenType)) { - highlightKeyword(element, result, tokenType); + if (highlightKeyword(element, tokenType)) { + result.add(HighlightInfo.createHighlightInfo(HighlightInfoType.INFORMATION, element, null, DefaultHighlighter.KEYWORD)); + } + } + else if (!(element instanceof GroovyPsiElement)) { + final TextAttributesKey attribute = getDeclarationAttribute(element); + if (attribute != null) { + result.add(HighlightInfo.createHighlightInfo(HighlightInfoType.INFORMATION, element, null, attribute)); + } } else { super.visitElement(element); @@ -68,20 +80,20 @@ public class KeywordHighlighter extends TextEditorHighlightingPass { toHighlight = result; } - private static void highlightKeyword(PsiElement element, List result, IElementType token) { + private static boolean highlightKeyword(PsiElement element, IElementType token) { final PsiElement parent = element.getParent(); - if (parent instanceof GrArgumentLabel) return; //don't highlight: print (void:'foo') + if (parent instanceof GrArgumentLabel) return false; //don't highlight: print (void:'foo') if (PsiTreeUtil.getParentOfType(element, GrCodeReferenceElement.class) != null) { if (token == GroovyTokenTypes.kDEF || token == GroovyTokenTypes.kIN || token == GroovyTokenTypes.kAS) { - return; //It is allowed to name packages 'as', 'in' or 'def' + return false; //It is allowed to name packages 'as', 'in' or 'def' } } else if (parent instanceof GrReferenceExpression && element == ((GrReferenceExpression)parent).getReferenceNameElement()) { - return; //don't highlight foo.def + return false; //don't highlight foo.def } - result.add(HighlightInfo.createHighlightInfo(HighlightInfoType.INFORMATION, element, null, DefaultHighlighter.KEYWORD)); + return true; } @@ -90,4 +102,14 @@ public class KeywordHighlighter extends TextEditorHighlightingPass { if (toHighlight == null) return; UpdateHighlightersUtil.setHighlightersToEditor(myProject, myDocument, 0, myFile.getTextLength(), toHighlight, getColorsScheme(), getId()); } + + @Nullable + private static TextAttributesKey getDeclarationAttribute(PsiElement element) { + PsiElement parent = element.getParent(); + if (!(parent instanceof GrNamedElement) || ((GrNamedElement)parent).getNameIdentifierGroovy() != element) { + return null; + } + + return GrHighlightUtil.getDeclarationHighlightingAttribute(parent); + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GrReferenceHighlighter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GrReferenceHighlighter.java new file mode 100644 index 000000000000..12e948067d6b --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GrReferenceHighlighter.java @@ -0,0 +1,88 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.annotator; + +import com.intellij.codeHighlighting.TextEditorHighlightingPass; +import com.intellij.codeInsight.daemon.impl.HighlightInfo; +import com.intellij.codeInsight.daemon.impl.HighlightInfoType; +import com.intellij.codeInsight.daemon.impl.UpdateHighlightersUtil; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.colors.TextAttributesKey; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; +import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor; +import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Max Medvedev + */ +public class GrReferenceHighlighter extends TextEditorHighlightingPass { + @NotNull private final GroovyFile myFile; + @Nullable private List myInfos = null; + + protected GrReferenceHighlighter(@Nullable Document document, @NotNull GroovyFile file) { + super(file.getProject(), document); + myFile = file; + } + + @Override + public void doCollectInformation(@NotNull ProgressIndicator progress) { + myInfos = new ArrayList(); + myFile.accept(new GroovyRecursiveElementVisitor() { + @Override + public void visitReferenceExpression(GrReferenceExpression referenceExpression) { + super.visitReferenceExpression(referenceExpression); + visit(referenceExpression); + } + + private void visit(GrReferenceElement element) { + final PsiElement resolved = element.resolve(); + final TextAttributesKey attribute = GrHighlightUtil.getDeclarationHighlightingAttribute(resolved); + if (attribute != null) { + final PsiElement refNameElement = GrHighlightUtil.getElementToHighlight(element); + myInfos.add(HighlightInfo.createHighlightInfo(HighlightInfoType.INFORMATION, refNameElement, null, attribute)); + } + } + + @Override + public void visitCodeReferenceElement(GrCodeReferenceElement refElement) { + super.visitCodeReferenceElement(refElement); + visit(refElement); + } + + @Override + public void visitAnnotation(GrAnnotation annotation) { + super.visitAnnotation(annotation); + visit(annotation.getClassReference()); + } + }); + } + + @Override + public void doApplyInformationToEditor() { + if (myInfos == null) return; + UpdateHighlightersUtil.setHighlightersToEditor(myProject, myDocument, 0, myFile.getTextLength(), myInfos, getColorsScheme(), getId()); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/KeywordHighlightFactory.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GrReferenceHighlighterFactory.java similarity index 85% rename from plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/KeywordHighlightFactory.java rename to plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GrReferenceHighlighterFactory.java index 64582fe22579..3d623c041ec3 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/KeywordHighlightFactory.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GrReferenceHighlighterFactory.java @@ -28,17 +28,15 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; /** * @author Max Medvedev */ -public class KeywordHighlightFactory extends AbstractProjectComponent implements TextEditorHighlightingPassFactory { - protected KeywordHighlightFactory(Project project) { +public class GrReferenceHighlighterFactory extends AbstractProjectComponent implements TextEditorHighlightingPassFactory { + protected GrReferenceHighlighterFactory(Project project) { super(project); - TextEditorHighlightingPassRegistrar.getInstance(project).registerTextEditorHighlightingPass(this, null, null, false, -1); } - @Override public TextEditorHighlightingPass createHighlightingPass(@NotNull PsiFile file, @NotNull Editor editor) { if (!(file instanceof GroovyFile)) return null; - return new KeywordHighlighter((GroovyFile)file, editor.getDocument()); + return new GrReferenceHighlighter(editor.getDocument(), (GroovyFile)file); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java index 7700348cc93c..514b211716e9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java @@ -38,19 +38,14 @@ import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.pom.PomDeclarationSearcher; -import com.intellij.pom.PomTarget; import com.intellij.psi.*; import com.intellij.psi.impl.light.LightElement; import com.intellij.psi.infos.CandidateInfo; -import com.intellij.psi.search.LocalSearchScope; -import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.search.searches.SuperMethodsSearch; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.MethodSignature; import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.CollectConsumer; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashSet; import com.intellij.util.containers.MultiMap; @@ -64,7 +59,6 @@ import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicProperty import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection; import org.jetbrains.plugins.groovy.config.GroovyConfigUtils; import org.jetbrains.plugins.groovy.debugger.fragments.GroovyCodeFragment; -import org.jetbrains.plugins.groovy.extensions.GroovyUnresolvedHighlightFilter; import org.jetbrains.plugins.groovy.highlighter.DefaultHighlighter; import org.jetbrains.plugins.groovy.lang.documentation.GroovyPresentationUtil; import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocReferenceElement; @@ -95,7 +89,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.*; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; @@ -111,7 +104,6 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrScriptField; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.lang.resolve.noncode.GrInheritConstructorContributor; @@ -137,104 +129,8 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } myHolder = null; } - else { - highlightDeclaration(element, holder); - } } - private static void highlightDeclaration(PsiElement element, AnnotationHolder holder) { - PsiElement parent = element.getParent(); - if (!(parent instanceof GrNamedElement) || ((GrNamedElement)parent).getNameIdentifierGroovy() != element) { - return; - } - - - if (parent instanceof GrTypeParameter) { - final Annotation annotation = holder.createInfoAnnotation(element, null); - annotation.setTextAttributes(DefaultHighlighter.TYPE_PARAMETER); - } - else if (parent instanceof GrAnnotationTypeDefinition) { - final Annotation annotation = holder.createInfoAnnotation(element, null); - annotation.setTextAttributes(DefaultHighlighter.ANNOTATION); - } - else if (parent instanceof PsiClass) { - final Annotation annotation = holder.createInfoAnnotation(element, null); - annotation.setTextAttributes(DefaultHighlighter.CLASS_REFERENCE); - } - else if (parent instanceof PsiMethod) { - if (!((PsiMethod)parent).isConstructor()) { - final Annotation annotation = holder.createInfoAnnotation(element, null); - annotation.setTextAttributes(DefaultHighlighter.METHOD_DECLARATION); - } - } - else if (parent instanceof PsiField || parent instanceof GrVariable && ResolveUtil.isScriptField((GrVariable)parent)) { - final boolean isStatic = ((PsiVariable)parent).hasModifierProperty(PsiModifier.STATIC); - final Annotation annotation = holder.createInfoAnnotation(element, null); - annotation.setTextAttributes(isStatic ? DefaultHighlighter.STATIC_FIELD : DefaultHighlighter.INSTANCE_FIELD); - } - else if (parent instanceof GrParameter) { - boolean reassigned = isReassigned((GrParameter)parent); - final Annotation annotation = holder.createInfoAnnotation(element, null); - annotation.setTextAttributes(reassigned ? DefaultHighlighter.REASSIGNED_PARAMETER : DefaultHighlighter.PARAMETER); - } - else if (parent instanceof GrVariable) { - boolean reassigned = isReassigned((GrVariable)parent); - final Annotation annotation = holder.createInfoAnnotation(element, null); - annotation.setTextAttributes(reassigned ? DefaultHighlighter.REASSIGNED_LOCAL_VARIABLE : DefaultHighlighter.LOCAL_VARIABLE); - } - } - - private static void highlightResolved(AnnotationHolder holder, GrReferenceElement refElement, PsiElement resolved) { - final PsiElement refNameElement = getElementToHighlight(refElement); - - if (resolved instanceof PsiField || resolved instanceof GrVariable && ResolveUtil.isScriptField((GrVariable)resolved)) { - boolean isStatic = ((PsiVariable)resolved).hasModifierProperty(PsiModifier.STATIC); - Annotation annotation = holder.createInfoAnnotation(refNameElement, null); - annotation.setTextAttributes(isStatic ? DefaultHighlighter.STATIC_FIELD : DefaultHighlighter.INSTANCE_FIELD); - } - else if (resolved instanceof GrAccessorMethod) { - boolean isStatic = ((GrAccessorMethod)resolved).hasModifierProperty(PsiModifier.STATIC); - Annotation annotation = holder.createInfoAnnotation(refNameElement, null); - annotation.setTextAttributes(isStatic ? DefaultHighlighter.STATIC_PROPERTY_REFERENCE : DefaultHighlighter.INSTANCE_PROPERTY_REFERENCE); - } - else if (resolved instanceof PsiMethod) { - boolean isStatic = ((PsiMethod)resolved).hasModifierProperty(PsiModifier.STATIC); - if (GroovyPropertyUtils.isSimplePropertyAccessor((PsiMethod)resolved)) { - Annotation annotation = holder.createInfoAnnotation(refNameElement, null); - annotation.setTextAttributes(isStatic ? DefaultHighlighter.STATIC_PROPERTY_REFERENCE : DefaultHighlighter.INSTANCE_PROPERTY_REFERENCE); - } - else { - Annotation annotation = holder.createInfoAnnotation(refNameElement, null); - annotation.setTextAttributes(isStatic ? DefaultHighlighter.STATIC_METHOD_ACCESS : DefaultHighlighter.METHOD_CALL); - } - } - else if (resolved instanceof PsiTypeParameter) { - Annotation annotation = holder.createInfoAnnotation(refNameElement, null); - annotation.setTextAttributes(DefaultHighlighter.TYPE_PARAMETER); - } - else if (resolved instanceof PsiClass) { - if (((PsiClass)resolved).isAnnotationType()) { - Annotation annotation = holder.createInfoAnnotation(refNameElement, null); - annotation.setTextAttributes(DefaultHighlighter.ANNOTATION); - } - else { - Annotation annotation = holder.createInfoAnnotation(refNameElement, null); - annotation.setTextAttributes(DefaultHighlighter.CLASS_REFERENCE); - } - } - else if (resolved instanceof GrParameter) { - boolean reassigned = isReassigned((GrParameter)resolved); - Annotation annotation = holder.createInfoAnnotation(refNameElement, null); - annotation.setTextAttributes(reassigned ? DefaultHighlighter.REASSIGNED_PARAMETER : DefaultHighlighter.PARAMETER); - } - else if (resolved instanceof GrVariable) { - boolean reassigned = isReassigned((GrVariable)resolved); - Annotation annotation = holder.createInfoAnnotation(refNameElement, null); - annotation.setTextAttributes(reassigned ? DefaultHighlighter.REASSIGNED_LOCAL_VARIABLE : DefaultHighlighter.LOCAL_VARIABLE); - } - } - - @Override public void visitTypeArgumentList(GrTypeArgumentList typeArgumentList) { PsiElement parent = typeArgumentList.getParent(); @@ -319,8 +215,6 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { return; } - highlightResolved(myHolder, refElement, resolveResult.getElement()); - checkSingleResolvedElement(myHolder, refElement, resolveResult, true); if (resolveResult.getElement() == null) { @@ -408,8 +302,6 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { final PsiElement parent = referenceExpression.getParent(); if (resolved != null) { - highlightResolved(myHolder, referenceExpression, resolved); - if (!resolveResult.isStaticsOK() && resolved instanceof PsiModifierListOwner) { if (!((PsiModifierListOwner)resolved).hasModifierProperty(PsiModifier.STATIC)) { Annotation annotation = myHolder.createInfoAnnotation(referenceExpression, GroovyBundle.message("cannot.reference.nonstatic", referenceExpression.getReferenceName())); @@ -419,7 +311,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } else { GrExpression qualifier = referenceExpression.getQualifierExpression(); - if (qualifier == null && isDeclarationAssignment(referenceExpression)) return; + if (qualifier == null && GrHighlightUtil.isDeclarationAssignment(referenceExpression)) return; if (qualifier != null && referenceExpression.getDotTokenType() == GroovyTokenTypes.mMEMBER_POINTER) { if (results.length > 0) { @@ -447,9 +339,9 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { resolved = results[0].getElement(); } } - if (isDeclarationAssignment(referenceExpression) || resolved instanceof PsiPackage) return; + if (GrHighlightUtil.isDeclarationAssignment(referenceExpression) || resolved instanceof PsiPackage) return; - if (resolved == null && shouldHighlightAsUnresolved(referenceExpression)) { + if (resolved == null && GrHighlightUtil.shouldHighlightAsUnresolved(referenceExpression)) { PsiElement refNameElement = referenceExpression.getReferenceNameElement(); PsiElement elt = refNameElement == null ? referenceExpression : refNameElement; @@ -490,46 +382,6 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { return context instanceof PsiMethod && context.hasModifierProperty(PsiModifier.STATIC); } - private static boolean isReassigned(GrVariable var) { - PsiMethod method = PsiTreeUtil.getParentOfType(var, PsiMethod.class); - PsiNamedElement scope = method == null ? var.getContainingFile() : method; - if (scope == null) { - return false; - } - boolean hasAssignment = var.getInitializerGroovy() != null || var instanceof GrParameter; - for (PsiReference reference : ReferencesSearch.search(var, new LocalSearchScope(scope)).findAll()) { - if (reference instanceof GrReferenceExpression && - (PsiUtil.isLValue((GrReferenceExpression)reference) || - ((GrReferenceExpression)reference).getParent() instanceof GrUnaryExpression && - ((GrUnaryExpression)((GrReferenceExpression)reference).getParent()).isPostfix())) { - if (hasAssignment) { - return true; - } - hasAssignment = true; - } - } - return false; - } - - public static boolean shouldHighlightAsUnresolved(@NotNull GrReferenceExpression referenceExpression) { - PsiElement refNameElement = referenceExpression.getReferenceNameElement(); - if (refNameElement != null && referenceExpression.getQualifier() == null) { - final IElementType type = refNameElement.getNode().getElementType(); - if (TokenSets.STRING_LITERAL_SET.contains(type)) return false; - } - - if (!GroovyUnresolvedHighlightFilter.shouldHighlight(referenceExpression)) return false; - - CollectConsumer consumer = new CollectConsumer(); - - for (PomDeclarationSearcher searcher : PomDeclarationSearcher.EP_NAME.getExtensions()) { - searcher.findDeclarationsAt(referenceExpression, 0, consumer); - if (consumer.getResult().size() > 0) return false; - } - - return true; - } - private void checkStringNameIdentifier(GrReferenceExpression ref) { final PsiElement nameElement = ref.getReferenceNameElement(); if (nameElement == null) return; @@ -543,41 +395,6 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } } - /* - private static void registerAccessFix(Annotation annotation, PsiElement place, PsiMember refElement) { - if (refElement instanceof PsiCompiledElement) return; - PsiModifierList modifierList = refElement.getModifierList(); - if (modifierList == null) return; - - try { - Project project = refElement.getProject(); - JavaPsiFacade facade = JavaPsiFacade.getInstance(project); - PsiModifierList modifierListCopy = facade.getElementFactory().createFieldFromText("int a;", null).getModifierList(); - modifierListCopy.setModifierProperty(PsiModifier.STATIC, modifierList.hasModifierProperty(PsiModifier.STATIC)); - @Modifier String minModifier = PsiModifier.PROTECTED; - if (refElement.hasModifierProperty(PsiModifier.PROTECTED)) { - minModifier = PsiModifier.PUBLIC; - } - String[] modifiers = {PsiModifier.PROTECTED, PsiModifier.PUBLIC, PsiModifier.PACKAGE_LOCAL}; - PsiClass accessObjectClass = PsiTreeUtil.getParentOfType(place, PsiClass.class, false); - if (accessObjectClass == null) { - accessObjectClass = ((GroovyFile)place.getContainingFile()).getScriptClass(); - } - for (int i = ArrayUtil.indexOf(modifiers, minModifier); i < modifiers.length; i++) { - String modifier = modifiers[i]; - modifierListCopy.setModifierProperty(modifier, true); - if (facade.getResolveHelper().isAccessible(refElement, modifierListCopy, place, accessObjectClass, null)) { - IntentionAction fix = new GrModifierFix(refElement, refElement.getModifierList(), modifier, true, true); - annotation.registerFix(fix); - } - } - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - } - */ - private static void registerStaticImportFix(GrReferenceExpression referenceExpression, Annotation annotation) { final String referenceName = referenceExpression.getReferenceName(); //noinspection ConstantConditions @@ -650,7 +467,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } if (!hasImplicitDefConstructor && (defConstructor == null || !PsiUtil.isAccessible(typeDefinition, defConstructor))) { - holder.createErrorAnnotation(getMethodHeaderTextRange(method), + holder.createErrorAnnotation(GrHighlightUtil.getMethodHeaderTextRange(method), GroovyBundle.message("there.is.no.default.constructor.available.in.class.0", qName)); } } @@ -710,7 +527,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { if (constructor != null) { PsiMethod circleStart = constructor; do { - holder.createErrorAnnotation(getMethodHeaderTextRange(constructor), + holder.createErrorAnnotation(GrHighlightUtil.getMethodHeaderTextRange(constructor), GroovyBundle.message("recursive.constructor.invocation")); constructor = nodes.get(constructor); } @@ -719,18 +536,6 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } } - public static TextRange getMethodHeaderTextRange(PsiMethod method) { - final PsiModifierList modifierList = method.getModifierList(); - final PsiParameterList parameterList = method.getParameterList(); - - final TextRange textRange = modifierList.getTextRange(); - LOG.assertTrue(textRange != null, method.getClass() + ":" + method.getText()); - int startOffset = textRange.getStartOffset(); - int endOffset = parameterList.getTextRange().getEndOffset() + 1; - - return new TextRange(startOffset, endOffset); - } - @Override public void visitMethod(GrMethod method) { @@ -1316,8 +1121,6 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { if (resolved == null) return; assert resolved instanceof PsiClass; - highlightResolved(myHolder, ref, resolved); - PsiClass anno = (PsiClass) resolved; if (!anno.isAnnotationType()) { myHolder.createErrorAnnotation(ref, GroovyBundle.message("class.is.not.annotation", ((PsiClass)resolved).getQualifiedName())); @@ -1692,7 +1495,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { String signaturePresentation = GroovyPresentationUtil.getSignaturePresentation(signature); for (PsiMethod method : methods) { //noinspection ConstantConditions - holder.createErrorAnnotation(getMethodHeaderTextRange(method), GroovyBundle + holder.createErrorAnnotation(GrHighlightUtil.getMethodHeaderTextRange(method), GroovyBundle .message("method.duplicate", signaturePresentation, method.getContainingClass().getName())); } } @@ -1901,46 +1704,12 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } } - - public static boolean isDeclarationAssignment(GrReferenceExpression refExpr) { - if (isAssignmentLhs(refExpr)) { - return isExpandoQualified(refExpr); - } - return false; - } - - private static boolean isAssignmentLhs(GrReferenceExpression refExpr) { - return refExpr.getParent() instanceof GrAssignmentExpression && - refExpr.equals(((GrAssignmentExpression)refExpr.getParent()).getLValue()); - } - - private static boolean isExpandoQualified(GrReferenceExpression refExpr) { - final GrExpression qualifier = refExpr.getQualifierExpression(); - if (qualifier == null) { - final PsiClass clazz = PsiTreeUtil.getParentOfType(refExpr, PsiClass.class); - if (clazz == null) { //script - return true; - } - return false; //in class, a property should normally be defined, so it's not a declaration - } - - final PsiType type = qualifier.getType(); - if (type instanceof PsiClassType) { - final PsiClassType classType = (PsiClassType)type; - final PsiClass psiClass = classType.resolve(); - if (psiClass instanceof GroovyScriptClass) { - return true; - } - } - return false; - } - private static void checkSingleResolvedElement(AnnotationHolder holder, GrReferenceElement refElement, GroovyResolveResult resolveResult, boolean highlightError) { final PsiElement resolved = resolveResult.getElement(); - final PsiElement toHighlight = getElementToHighlight(refElement); + final PsiElement toHighlight = GrHighlightUtil.getElementToHighlight(refElement); if (resolved == null) { String message = GroovyBundle.message("cannot.resolve", refElement.getReferenceName()); @@ -1968,13 +1737,6 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { } } - @NotNull - public static PsiElement getElementToHighlight(@NotNull GrReferenceElement refElement) { - final PsiElement refNameElement = refElement.getReferenceNameElement(); - return refNameElement != null ? refNameElement : refElement; - } - - private static void registerAddImportFixes(GrReferenceElement refElement, Annotation annotation) { final String referenceName = refElement.getReferenceName(); //noinspection ConstantConditions diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java index 3adbb4d303d7..9765f36b0cb3 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/assignment/GroovyAssignabilityCheckInspection.java @@ -35,7 +35,7 @@ import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyBundle; -import org.jetbrains.plugins.groovy.annotator.GroovyAnnotator; +import org.jetbrains.plugins.groovy.annotator.GrHighlightUtil; import org.jetbrains.plugins.groovy.codeInspection.BaseInspection; import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor; import org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle; @@ -448,7 +448,7 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection { PsiElement resolved = resolveResult.getElement(); if (resolved == null) { GrExpression qualifier = referenceExpression.getQualifierExpression(); - if (qualifier == null && GroovyAnnotator.isDeclarationAssignment(referenceExpression)) return; + if (qualifier == null && GrHighlightUtil.isDeclarationAssignment(referenceExpression)) return; } if (!checkCannotInferArgumentTypes(referenceExpression)) return; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GroovyUnresolvedAccessInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GroovyUnresolvedAccessInspection.java index 9b661072510b..4ed40b9190b5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GroovyUnresolvedAccessInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GroovyUnresolvedAccessInspection.java @@ -20,7 +20,7 @@ import com.intellij.psi.*; import com.intellij.util.containers.CollectionFactory; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.groovy.annotator.GroovyAnnotator; +import org.jetbrains.plugins.groovy.annotator.GrHighlightUtil; import org.jetbrains.plugins.groovy.codeInspection.BaseInspection; import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor; import org.jetbrains.plugins.groovy.gpp.GppTypeConverter; @@ -34,7 +34,7 @@ import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import java.util.Iterator; import java.util.List; -import static org.jetbrains.plugins.groovy.annotator.GroovyAnnotator.isDeclarationAssignment; +import static org.jetbrains.plugins.groovy.annotator.GrHighlightUtil.isDeclarationAssignment; /** * @author Maxim.Medvedev @@ -76,7 +76,7 @@ public class GroovyUnresolvedAccessInspection extends BaseInspection { PsiElement parent = refExpr.getParent(); if (!(parent instanceof GrCall) && ResolveUtil.isKeyOfMap(refExpr)) return; // It's a key of map. - if (!GroovyAnnotator.shouldHighlightAsUnresolved(refExpr)) return; + if (!GrHighlightUtil.shouldHighlightAsUnresolved(refExpr)) return; if (qualifier != null && isBuilderInvocation(refExpr)) return; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GroovyUntypedAccessInspection.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GroovyUntypedAccessInspection.java index 673798ef4c91..d0b051e31d60 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GroovyUntypedAccessInspection.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GroovyUntypedAccessInspection.java @@ -28,7 +28,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; -import static org.jetbrains.plugins.groovy.annotator.GroovyAnnotator.isDeclarationAssignment; +import static org.jetbrains.plugins.groovy.annotator.GrHighlightUtil.isDeclarationAssignment; /** * @author Maxim.Medvedev diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrHighlightExitPointHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrHighlightExitPointHandler.java new file mode 100644 index 000000000000..27a148105e1d --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrHighlightExitPointHandler.java @@ -0,0 +1,77 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.findUsages; + +import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerBase; +import com.intellij.featureStatistics.FeatureUsageTracker; +import com.intellij.featureStatistics.ProductivityFeatureNames; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.util.Consumer; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; +import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrThrowStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction; + +import java.util.Collections; +import java.util.List; + +/** + * @author Max Medvedev + */ +public class GrHighlightExitPointHandler extends HighlightUsagesHandlerBase { + private final PsiElement myTarget; + + protected GrHighlightExitPointHandler(Editor editor, PsiFile file, PsiElement target) { + super(editor, file); + myTarget = target; + } + + @Override + public List getTargets() { + return Collections.singletonList(myTarget); + } + + @Override + protected void selectTargets(List targets, Consumer> selectionConsumer) { + selectionConsumer.consume(targets); + } + + @Override + public void computeUsages(List targets) { + FeatureUsageTracker.getInstance().triggerFeatureUsed(ProductivityFeatureNames.CODEASSISTS_HIGHLIGHT_RETURN); + + PsiElement parent = myTarget.getParent(); + if (!(parent instanceof GrReturnStatement) && !(parent instanceof GrThrowStatement)) return; + + final GrControlFlowOwner flowOwner = ControlFlowUtils.findControlFlowOwner(parent); + ControlFlowUtils.visitAllExitPoints(flowOwner, new ControlFlowUtils.ExitPointVisitor() { + @Override + public boolean visitExitPoint(Instruction instruction, @Nullable GrExpression returnValue) { + final PsiElement returnElement = instruction.getElement(); + if (returnElement == null) return true; + final TextRange range = returnElement.getTextRange(); + myReadUsages.add(range); + return true; + } + }); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrHighlightOverridingMethodsHandlerFactory.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrHighlightHandlerFactory.java similarity index 90% rename from plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrHighlightOverridingMethodsHandlerFactory.java rename to plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrHighlightHandlerFactory.java index 702bd4ce55cd..bcc29dbe498b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrHighlightOverridingMethodsHandlerFactory.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GrHighlightHandlerFactory.java @@ -30,7 +30,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefini /** * @author Max Medvedev */ -public class GrHighlightOverridingMethodsHandlerFactory implements HighlightUsagesHandlerFactory { +public class GrHighlightHandlerFactory implements HighlightUsagesHandlerFactory { @Override public HighlightUsagesHandlerBase createHighlightUsagesHandler(Editor editor, PsiFile file) { int offset = TargetElementUtilBase.adjustOffset(editor.getDocument(), editor.getCaretModel().getOffset()); @@ -48,6 +48,9 @@ public class GrHighlightOverridingMethodsHandlerFactory implements HighlightUsag if (!(grand instanceof GrTypeDefinition)) return null; return new GrHighlightOverridingMethodsHandler(editor, file, target, (GrTypeDefinition)grand); } + else if (type == GroovyTokenTypes.kRETURN || type == GroovyTokenTypes.kTHROW) { + return new GrHighlightExitPointHandler(editor, file, target); + } return null; } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/style/AddReturnTypeFix.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/style/AddReturnTypeFix.java index bfec8dc90320..30ddaf551caf 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/style/AddReturnTypeFix.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/style/AddReturnTypeFix.java @@ -26,7 +26,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.groovy.annotator.GroovyAnnotator; +import org.jetbrains.plugins.groovy.annotator.GrHighlightUtil; import org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; @@ -82,7 +82,7 @@ public class AddReturnTypeFix implements IntentionAction { } final GrMethod method = PsiTreeUtil.getParentOfType(at, GrMethod.class, false, GrTypeDefinition.class, GrClosableBlock.class); - if (method != null && GroovyAnnotator.getMethodHeaderTextRange(method).contains(offset)) { + if (method != null && GrHighlightUtil.getMethodHeaderTextRange(method).contains(offset)) { if (method.getReturnTypeElementGroovy() == null) { return method; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java index 6d0ad639e0fc..f433e8c8897f 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java @@ -34,10 +34,7 @@ import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.SuggestedNameInfo; import com.intellij.psi.codeStyle.VariableKind; -import com.intellij.psi.filters.ElementFilter; import com.intellij.psi.filters.FilterPositionUtil; -import com.intellij.psi.filters.TrueFilter; -import com.intellij.psi.filters.types.AssignableFromFilter; import com.intellij.psi.impl.source.tree.LeafPsiElement; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.util.InheritanceUtil; @@ -177,8 +174,8 @@ public class GroovyCompletionContributor extends CompletionContributor { private static final ElementPattern AFTER_NUMBER_LITERAL = psiElement().afterLeaf( psiElement().withElementType(elementType().oneOf(mNUM_DOUBLE, mNUM_INT, mNUM_LONG, mNUM_FLOAT, mNUM_BIG_INT, mNUM_BIG_DECIMAL))); - private static final ElementPattern AFTER_AT = psiElement().afterLeaf("@"); - private static final ElementPattern IN_CATCH_TYPE = psiElement().afterLeaf(psiElement().withText("(").withParent(GrCatchClause.class)); + public static final ElementPattern AFTER_AT = psiElement().afterLeaf("@"); + public static final ElementPattern IN_CATCH_TYPE = psiElement().afterLeaf(psiElement().withText("(").withParent(GrCatchClause.class)); private static void addAllClasses(CompletionParameters parameters, final CompletionResultSet result, final InheritorsHolder inheritors) { @@ -194,7 +191,6 @@ public class GroovyCompletionContributor extends CompletionContributor { final Consumer consumer, final InheritorsHolder inheritors, final PrefixMatcher matcher) { final PsiElement position = parameters.getPosition(); - final ElementFilter filter = getClassFilter(position); final boolean afterNew = JavaClassNameCompletionContributor.AFTER_NEW.accepts(position); AllClassesGetter.processJavaClasses(parameters, matcher, parameters.getInvocationCount() <= 1, new Consumer() { @Override @@ -203,7 +199,7 @@ public class GroovyCompletionContributor extends CompletionContributor { .createClassLookupItems(psiClass, afterNew, new GroovyClassNameInsertHandler(), new Condition() { @Override public boolean value(PsiClass psiClass) { - return !inheritors.alreadyProcessed(psiClass) && filter.isAcceptable(psiClass, position); + return !inheritors.alreadyProcessed(psiClass); } })) { consumer.consume(element); @@ -212,16 +208,6 @@ public class GroovyCompletionContributor extends CompletionContributor { }); } - private static ElementFilter getClassFilter(PsiElement position) { - if (AFTER_AT.accepts(position)) { - return new AssignableFromFilter(CommonClassNames.JAVA_LANG_ANNOTATION_ANNOTATION); - } - if (IN_CATCH_TYPE.accepts(position)) { - return new AssignableFromFilter(CommonClassNames.JAVA_LANG_THROWABLE); - } - return TrueFilter.INSTANCE; - } - public GroovyCompletionContributor() { //provide 'this' and 'super' completions in ClassName. extend(CompletionType.BASIC, AFTER_DOT, new CompletionProvider() { @@ -378,10 +364,6 @@ public class GroovyCompletionContributor extends CompletionContributor { } public static boolean isClassNamePossible(PsiElement position) { - if (PsiJavaPatterns.psiElement().inside(GrImportStatement.class).accepts(position)) { - return false; - } - if (position instanceof PsiComment) return false; PsiElement parent = position.getParent(); if (parent instanceof GrReferenceElement) { return ((GrReferenceElement)parent).getQualifier() == null; @@ -431,8 +413,6 @@ public class GroovyCompletionContributor extends CompletionContributor { } }; - final PsiElement position = parameters.getPosition(); - final Map staticMembers = hashMap(); final PsiElement qualifier = reference.getQualifier(); final PsiType qualifierType = qualifier instanceof GrExpression ? ((GrExpression)qualifier).getType() : null; @@ -455,8 +435,6 @@ public class GroovyCompletionContributor extends CompletionContributor { unresolvedProps = Collections.emptySet(); } - final ElementFilter classFilter = getClassFilter(position); - final List zeroPriority = arrayList(); reference.processVariants(matcher, parameters, new Consumer() { public void consume(LookupElement lookupElement) { @@ -489,9 +467,6 @@ public class GroovyCompletionContributor extends CompletionContributor { staticMembers.put(CompletionUtil.getOriginalOrSelf((PsiModifierListOwner)object), lookupElement); } } - if (object instanceof PsiClass && !classFilter.isAcceptable(object, position)) { - return; - } PrioritizedLookupElement prio = lookupElement.as(PrioritizedLookupElement.CLASS_CONDITION_KEY); if (prio == null || prio.getPriority() == 0) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/weighers/GrKindWeigher.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/weighers/GrKindWeigher.java index dd469ca38610..f29092426b24 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/weighers/GrKindWeigher.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/weighers/GrKindWeigher.java @@ -21,11 +21,13 @@ import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.PsiTypeLookupItem; import com.intellij.psi.*; import com.intellij.psi.impl.light.LightElement; +import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.containers.CollectionFactory; import com.intellij.util.containers.hash.HashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.extensions.NamedArgumentDescriptor; +import org.jetbrains.plugins.groovy.lang.completion.GroovyCompletionContributor; import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; @@ -86,6 +88,15 @@ public class GrKindWeigher extends CompletionWeigher { if (isPriorityKeyword(o)) return NotQualifiedKind.local; if (isLightElement(o)) return NotQualifiedKind.unknown; + if (o instanceof PsiClass) { + if (((PsiClass)o).isAnnotationType() && GroovyCompletionContributor.AFTER_AT.accepts(position)) { + return NotQualifiedKind.restrictedClass; + } + if (GroovyCompletionContributor.IN_CATCH_TYPE.accepts(position) && + InheritanceUtil.isInheritor((PsiClass)o, CommonClassNames.JAVA_LANG_THROWABLE)) { + return NotQualifiedKind.restrictedClass; + } + } if (o instanceof PsiMember) { final PsiClass containingClass = ((PsiMember)o).getContainingClass(); if (isAccessor((PsiMember)o)) return NotQualifiedKind.accessor; @@ -145,18 +156,19 @@ public class GrKindWeigher extends CompletionWeigher { return qualifier.getManager().areElementsEquivalent(member.getContainingClass(), psiClass); } - private static enum NotQualifiedKind { + private enum NotQualifiedKind { arrayType, innerClass, unknown, accessor, member, currentClassMember, + restrictedClass, local, onTop } - private static enum QualifiedKind { + private enum QualifiedKind { innerClass, unknown, accessor, diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy index 85f67928e500..e1a55656376f 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy @@ -30,6 +30,9 @@ import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiFile import com.intellij.testFramework.TestLoggerFactory import junit.framework.AssertionFailedError +import com.intellij.openapi.vfs.VirtualFileManager +import com.intellij.openapi.vfs.newvfs.BulkFileListener +import com.intellij.openapi.vfs.newvfs.events.VFileEvent /** * @author peter @@ -244,9 +247,21 @@ public abstract class GroovyCompilerTest extends GroovyCompilerTestCase { public void testMakeInTests() throws Throwable { setupTestSources(); + myFixture.project.messageBus.connect(testRootDisposable).subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { + @Override + void before(List events) { + } + + @Override + void after(List events) { + println events + } + }) myFixture.addFileToProject("tests/Super.groovy", "class Super {}"); assertEmpty(make()); + println 'after first make' + def sub = myFixture.addFileToProject("tests/Sub.groovy", "class Sub {\n" + " Super xxx() {}\n" + " static void main(String[] args) {" + diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java index b2983364fcb1..d29f3b2e6927 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java @@ -224,6 +224,7 @@ public abstract class GroovyCompilerTestCase extends JavaCodeInsightFixtureTestC file.setBinaryContent(file.contentsToByteArray(), file.getModificationStamp() + 1, file.getTimeStamp() + 1); File ioFile = VfsUtil.virtualToIoFile(file); assert ioFile.setLastModified(ioFile.lastModified() - 100000); + file.refresh(false, false); } protected static void setFileText(final PsiFile file, final String barText) throws IOException { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy index 87023a3ac2d8..cbab89c619f8 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyClassNameCompletionTest.groovy @@ -226,14 +226,14 @@ new Fxoo()\n""" myFixture.addClass "class AbcdClass {}; @interface AbcdAnno {}" myFixture.configureByText "a.groovy", "@Abcd" complete() - myFixture.checkResult "@AbcdAnno" + assert myFixture.lookupElementStrings[0] == 'AbcdAnno' } public void testOnlyExceptionsInCatch() { myFixture.addClass "class AbcdClass {}; class AbcdException extends Throwable {}" myFixture.configureByText "a.groovy", "try {} catch (Abcd" complete() - myFixture.checkResult "try {} catch (AbcdException" + assert myFixture.lookupElementStrings[0] == 'AbcdException' } public void testClassNameInMultilineString() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy index d84a161f0306..e480ac9d4cd3 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy @@ -712,17 +712,17 @@ format()""" } public void testOnlyAnnotationsAfterAt() { - myFixture.addClass "class AbcdClass {}; @interface AbcdAnno {}" + myFixture.addClass "class AbcdClass {}; @interface AbcdXAnno {}" myFixture.configureByText "a.groovy", "@Abcd class A {}" myFixture.completeBasic() - myFixture.checkResult "@AbcdAnno class A {}" + assert myFixture.lookupElementStrings[0] == 'AbcdXAnno' } public void testOnlyAnnotationsAfterAtInMethodParameters() { myFixture.addClass "class AbcdClass {}; @interface AbcdAnno {}" myFixture.configureByText "a.groovy", "def foo(@Abcd ) {}" myFixture.completeBasic() - myFixture.checkResult "def foo(@AbcdAnno ) {}" + assert myFixture.lookupElementStrings[0] == 'AbcdAnno' } public void testNoCompletionInClassBodyComments() { @@ -767,6 +767,8 @@ try {} catch (AbcdException""" myFixture.addClass "class AbcdClass {}; class AbcdException extends Throwable {}" myFixture.configureByText "a.groovy", "try {} catch (Abcd e) {}" myFixture.completeBasic() + assert myFixture.lookupElementStrings[0] == 'AbcdException' + myFixture.type('\n') myFixture.checkResult "try {} catch (AbcdException e) {}" } diff --git a/plugins/java-i18n/src/com/intellij/spellchecker/LiteralExpressionTokenizer.java b/plugins/java-i18n/src/com/intellij/spellchecker/LiteralExpressionTokenizer.java index 3302bca5a96f..bb603058649d 100644 --- a/plugins/java-i18n/src/com/intellij/spellchecker/LiteralExpressionTokenizer.java +++ b/plugins/java-i18n/src/com/intellij/spellchecker/LiteralExpressionTokenizer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,13 @@ package com.intellij.spellchecker; import com.intellij.codeInsight.AnnotationUtil; -import com.intellij.psi.PsiClassType; +import com.intellij.psi.JavaTokenType; import com.intellij.psi.PsiLiteralExpression; import com.intellij.psi.PsiModifierListOwner; +import com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.spellchecker.inspections.PlainTextSplitter; +import com.intellij.spellchecker.tokenizer.EscapeSequenceTokenizer; import com.intellij.spellchecker.tokenizer.TokenConsumer; import com.intellij.spellchecker.tokenizer.Tokenizer; import org.jetbrains.annotations.NotNull; @@ -35,7 +37,8 @@ import java.util.Collections; public class LiteralExpressionTokenizer extends Tokenizer { @Override public void tokenize(@NotNull PsiLiteralExpression element, TokenConsumer consumer) { - if (!(element.getType() instanceof PsiClassType)) { + PsiLiteralExpressionImpl literalExpression = (PsiLiteralExpressionImpl) element; + if (literalExpression.getLiteralElementType() != JavaTokenType.STRING_LITERAL) { return; // not a string literal } @@ -44,6 +47,23 @@ public class LiteralExpressionTokenizer extends Tokenizer return; } - consumer.consumeToken(element, PlainTextSplitter.getInstance()); + String text = literalExpression.getInnerText(); + if (text == null) { + return; + } + if (!text.contains("\\")) { + consumer.consumeToken(element, PlainTextSplitter.getInstance()); + } + else { + processTextWithEscapeSequences(element, text, consumer); + } + } + + public static void processTextWithEscapeSequences(PsiLiteralExpression element, String text, TokenConsumer consumer) { + StringBuilder unescapedText = new StringBuilder(); + int[] offsets = new int[text.length()+1]; + PsiLiteralExpressionImpl.parseStringCharacters(text, unescapedText, offsets); + + EscapeSequenceTokenizer.processTextWithOffsets(element, consumer, unescapedText, offsets); } } diff --git a/plugins/java-i18n/testData/inspection/stringWithMistakes/idea50496.java b/plugins/java-i18n/testData/inspection/stringWithMistakes/idea50496.java new file mode 100644 index 000000000000..b4f807524985 --- /dev/null +++ b/plugins/java-i18n/testData/inspection/stringWithMistakes/idea50496.java @@ -0,0 +1,19 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +class Idea50496 { + public static final String FOO = "\nclass"; + public static final String s2 = "\nfooquux"; +} diff --git a/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/ClassNameWithMistakesInspectionTest.java b/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/ClassNameWithMistakesInspectionTest.java index 37d068858ab2..f240d1addb8d 100644 --- a/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/ClassNameWithMistakesInspectionTest.java +++ b/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/ClassNameWithMistakesInspectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ public class ClassNameWithMistakesInspectionTest extends JavaSpellcheckerInspect } public void testJava() throws Throwable { - doTest("TestUpgade.java", SpellcheckerInspectionTestCase.getInspectionTools()); + doTest("TestUpgade.java"); } diff --git a/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/DocCommentWithMistakesInspectionTest.java b/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/DocCommentWithMistakesInspectionTest.java index e9d9752cbc0a..1c7cb22e0532 100644 --- a/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/DocCommentWithMistakesInspectionTest.java +++ b/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/DocCommentWithMistakesInspectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,6 @@ public class DocCommentWithMistakesInspectionTest extends JavaSpellcheckerInspec } public void testJava() throws Throwable { - doTest("SPITest6.java", SpellcheckerInspectionTestCase.getInspectionTools()); + doTest("SPITest6.java"); } } \ No newline at end of file diff --git a/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/FieldNameWithMistakesInspectionTest.java b/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/FieldNameWithMistakesInspectionTest.java index ae0dd22b1079..7327147ad6f6 100644 --- a/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/FieldNameWithMistakesInspectionTest.java +++ b/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/FieldNameWithMistakesInspectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ public class FieldNameWithMistakesInspectionTest extends JavaSpellcheckerInspect } public void testJava() throws Throwable { - doTest("SPITest2.java", SpellcheckerInspectionTestCase.getInspectionTools()); + doTest("SPITest2.java"); } } \ No newline at end of file diff --git a/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/JavaSpellcheckerInspectionTestCase.java b/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/JavaSpellcheckerInspectionTestCase.java index 1612ba5ee58f..77289aff05d1 100644 --- a/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/JavaSpellcheckerInspectionTestCase.java +++ b/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/JavaSpellcheckerInspectionTestCase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 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. @@ -15,7 +15,6 @@ */ package com.intellij.spellchecker.inspection; -import com.intellij.codeInspection.LocalInspectionTool; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.application.PluginPathManager; import com.intellij.openapi.util.io.FileUtil; @@ -30,8 +29,8 @@ public abstract class JavaSpellcheckerInspectionTestCase extends JavaCodeInsight @NonNls protected String DATA_PATH = FileUtil.toSystemIndependentName(PathManager.getHomePath()) + "/plugins/spellchecker/core/tests/testData"; - protected void doTest(String file, LocalInspectionTool... tools) throws Throwable { - myFixture.enableInspections(tools); + protected void doTest(String file) { + myFixture.enableInspections(SpellcheckerInspectionTestCase.getInspectionTools()); myFixture.testHighlighting(false, false, true, file); } diff --git a/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/LiteralExpressionTokenizerTest.java b/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/LiteralExpressionTokenizerTest.java new file mode 100644 index 000000000000..6938f67d3693 --- /dev/null +++ b/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/LiteralExpressionTokenizerTest.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.spellchecker.inspection; + +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.intellij.spellchecker.LiteralExpressionTokenizer; +import com.intellij.spellchecker.inspections.Splitter; +import com.intellij.spellchecker.tokenizer.TokenConsumer; +import com.intellij.testFramework.UsefulTestCase; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author yole + */ +public class LiteralExpressionTokenizerTest extends UsefulTestCase { + private static class TokenCollector extends TokenConsumer { + private List myTokenTexts = new ArrayList(); + + @Override + public void consumeToken(PsiElement element, String text, boolean useRename, int offset, TextRange rangeToCheck, Splitter splitter) { + myTokenTexts.add(text); + } + + public List getTokenTexts() { + return myTokenTexts; + } + } + + public void testEscapeSequences() { + doTest("hello\\nworld", "hello", "world"); + } + + public void testEscapeSequences2() { + doTest("\\nhello\\nworld\\n", "hello", "world"); + } + + private static void doTest(final String text, final String... expected) { + TokenCollector collector = new TokenCollector(); + LiteralExpressionTokenizer.processTextWithEscapeSequences(null, text, collector); + assertOrderedEquals(collector.getTokenTexts(), expected); + } +} diff --git a/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/LocalVariableWithMistakesInspectionTest.java b/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/LocalVariableWithMistakesInspectionTest.java index 6f3478247645..930e82c2f89b 100644 --- a/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/LocalVariableWithMistakesInspectionTest.java +++ b/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/LocalVariableWithMistakesInspectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ public class LocalVariableWithMistakesInspectionTest extends JavaSpellcheckerIns } public void testJava() throws Throwable { - doTest("SPITest3.java", SpellcheckerInspectionTestCase.getInspectionTools()); + doTest("SPITest3.java"); } } \ No newline at end of file diff --git a/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/MethodNameWithMistakesInspectionTest.java b/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/MethodNameWithMistakesInspectionTest.java index 2ea3592fddbf..8f8b60f2ae03 100644 --- a/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/MethodNameWithMistakesInspectionTest.java +++ b/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/MethodNameWithMistakesInspectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ public class MethodNameWithMistakesInspectionTest extends JavaSpellcheckerInspec } public void testJava() throws Throwable { - doTest("SPITest4.java", SpellcheckerInspectionTestCase.getInspectionTools()); + doTest("SPITest4.java"); } } \ No newline at end of file diff --git a/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/StringWithMistakesInspectionTest.java b/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/StringWithMistakesInspectionTest.java index 8e86f8bd1108..edee55ddeb49 100644 --- a/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/StringWithMistakesInspectionTest.java +++ b/plugins/java-i18n/testSrc/com/intellij/spellchecker/inspection/StringWithMistakesInspectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,9 +28,11 @@ public class StringWithMistakesInspectionTest extends JavaSpellcheckerInspection } - public void testJava() throws Throwable { - doTest("SPITest5.java", SpellcheckerInspectionTestCase.getInspectionTools()); + public void testJava() { + doTest("SPITest5.java"); } - -} \ No newline at end of file + public void testEscapeSequence() { + doTest("idea50496.java"); + } +} diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenUtil.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenUtil.java index b71ddcff0e5d..333d73c3fb6c 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenUtil.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenUtil.java @@ -341,7 +341,7 @@ public class MavenUtil { boolean interactive) throws IOException { FileTemplateManager manager = FileTemplateManager.getInstance(); FileTemplate fileTemplate = manager.getJ2eeTemplate(templateName); - Properties allProperties = manager.getDefaultProperties(); + Properties allProperties = manager.getDefaultProperties(project); if (!interactive) { allProperties.putAll(properties); } diff --git a/plugins/properties/src/com/intellij/lang/properties/PropertiesDocumentationProvider.java b/plugins/properties/src/com/intellij/lang/properties/PropertiesDocumentationProvider.java index d1853fce045b..c7060b7dc22f 100644 --- a/plugins/properties/src/com/intellij/lang/properties/PropertiesDocumentationProvider.java +++ b/plugins/properties/src/com/intellij/lang/properties/PropertiesDocumentationProvider.java @@ -27,6 +27,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.ui.GuiUtils; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.awt.*; @@ -35,16 +36,25 @@ public class PropertiesDocumentationProvider extends AbstractDocumentationProvid @Nullable public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) { if (element instanceof IProperty) { - @NonNls String info = "\n\"" + ((IProperty)element).getValue() + "\""; - PsiFile file = element.getContainingFile(); - if (file != null) { - info += " [" + file.getName() + "]"; - } - return info; + return "\"" + renderPropertyValue((IProperty)element) + "\"" + getLocationString(element); } return null; } + private static String getLocationString(PsiElement element) { + PsiFile file = element.getContainingFile(); + return file != null ? " [" + file.getName() + "]" : ""; + } + + @NotNull + private static String renderPropertyValue(IProperty prop) { + String raw = prop.getValue(); + if (raw == null) { + return "empty"; + } + return StringUtil.escapeXml(raw); + } + public String generateDoc(final PsiElement element, final PsiElement originalElement) { if (element instanceof IProperty) { IProperty property = (IProperty)element; @@ -63,11 +73,8 @@ public class PropertiesDocumentationProvider extends AbstractDocumentationProvid info += ""; } } - info += "\n" + property.getName() + "=\"" + ((IProperty)element).getValue() + "\""; - PsiFile file = element.getContainingFile(); - if (file != null) { - info += " [" + file.getName() + "]"; - } + info += "\n" + property.getName() + "=\"" + renderPropertyValue(((IProperty)element)) + "\""; + info += getLocationString(element); return info; } return null; diff --git a/plugins/spellchecker/src/com/intellij/spellchecker/tokenizer/EscapeSequenceTokenizer.java b/plugins/spellchecker/src/com/intellij/spellchecker/tokenizer/EscapeSequenceTokenizer.java new file mode 100644 index 000000000000..5402f0032707 --- /dev/null +++ b/plugins/spellchecker/src/com/intellij/spellchecker/tokenizer/EscapeSequenceTokenizer.java @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.spellchecker.tokenizer; + +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiElement; +import com.intellij.spellchecker.inspections.PlainTextSplitter; + +/** + * @author yole + */ +public class EscapeSequenceTokenizer { + public static void processTextWithOffsets(PsiElement element, TokenConsumer consumer, StringBuilder unescapedText, + int[] offsets) { + StringBuilder currentToken = new StringBuilder(); + int currentTokenStart = 0; + for (int i = 0; i < unescapedText.length(); i++) { + if (offsets[i+1]-offsets[i] == 1) { + if (currentToken.length() == 0) { + currentTokenStart = offsets[i]; + } + currentToken.append(unescapedText.charAt(i)); + } + else { + if (currentToken.length() > 0) { + processCurrentToken(element, currentToken, currentTokenStart, consumer); + currentToken.setLength(0); + } + } + } + if (currentToken.length() > 0) { + processCurrentToken(element, currentToken, currentTokenStart, consumer); + } + } + + private static void processCurrentToken(PsiElement element, + StringBuilder currentToken, + int currentTokenStart, TokenConsumer consumer) { + final String token = currentToken.toString(); + // +1 for the starting quote of the string literal + consumer.consumeToken(element, token, false, currentTokenStart+1, TextRange.allOf(token), PlainTextSplitter.getInstance()); + } +} diff --git a/plugins/spellchecker/src/com/intellij/spellchecker/tokenizer/TokenConsumer.java b/plugins/spellchecker/src/com/intellij/spellchecker/tokenizer/TokenConsumer.java index ab5295019214..8a371a7ff00b 100644 --- a/plugins/spellchecker/src/com/intellij/spellchecker/tokenizer/TokenConsumer.java +++ b/plugins/spellchecker/src/com/intellij/spellchecker/tokenizer/TokenConsumer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,11 +27,6 @@ public abstract class TokenConsumer { consumeToken(element, false, splitter); } - public void consumeToken(PsiElement element, String value, int offset, Splitter splitter) { - String text = element.getText(); - consumeToken(element, value, false, offset, TextRange.allOf(text), splitter); - } - public void consumeToken(PsiElement element, boolean useRename, Splitter splitter) { String text = element.getText(); consumeToken(element, text, useRename, 0, TextRange.allOf(text), splitter); diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/github/GitHubRepository.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/github/GitHubRepository.java index f09fa7dd790a..21eae03e61cd 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/github/GitHubRepository.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/github/GitHubRepository.java @@ -1,5 +1,8 @@ package com.intellij.tasks.github; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; @@ -9,21 +12,13 @@ import com.intellij.tasks.TaskRepository; import com.intellij.tasks.TaskType; import com.intellij.tasks.impl.BaseRepository; import com.intellij.tasks.impl.BaseRepositoryImpl; -import com.intellij.tasks.pivotal.PivotalTrackerRepository; -import com.intellij.util.NullableFunction; -import com.intellij.util.containers.ContainerUtil; +import com.intellij.tasks.impl.TaskUtil; +import com.intellij.util.ArrayUtil; import com.intellij.util.xmlb.annotations.Tag; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpMethod; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.commons.httpclient.methods.PostMethod; -import org.jdom.Element; -import org.jdom.input.SAXBuilder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.io.InputStream; import java.text.ParseException; import java.util.ArrayList; import java.util.Date; @@ -81,26 +76,9 @@ public class GitHubRepository extends BaseRepositoryImpl { (!StringUtil.isEmpty(getRepoName()) ? "/" + getRepoName() : ""); } - private HttpMethod doREST(String request, boolean post) throws Exception { - final HttpClient client = getHttpClient(); - client.getParams().setContentCharset("UTF-8"); - String uri = getUrl() + request; - HttpMethod method = post ? new PostMethod(uri) : new GetMethod(uri); - configureHttpMethod(method); - client.executeMethod(method); - return method; - } - @Override public Task[] getIssues(@Nullable String query, int max, long since) throws Exception { - @SuppressWarnings({"unchecked"}) List children = getIssues(query); - List taskList = ContainerUtil.mapNotNull(children, new NullableFunction() { - public Task fun(Object o) { - return createIssue((Element)o, false); - } - }); - - return taskList.toArray(new Task[taskList.size()]); + return ArrayUtil.toObjectArray(getIssues(query), Task.class); } @Override @@ -108,44 +86,90 @@ public class GitHubRepository extends BaseRepositoryImpl { return GITHUB_HOST; } - private List getIssues(String query) throws Exception { - String url; - if (!StringUtil.isEmpty(query)) { - url = buildUrl("/search/") + "/open/"; - url += encodeUrl(query); - } else { - url = buildUrl("/list/") + "/open"; + @NotNull + private List getIssues(String query) throws Exception { + String path; + boolean noQuery = StringUtil.isEmpty(query); + if (!noQuery) { + query = encodeUrl(query); + path = "/legacy/issues/search/" + getRepoAuthor() + "/" + getRepoName() + "/open/" + encodeUrl(query); } - HttpMethod method = doREST(url, false); - InputStream stream = method.getResponseBodyAsStream(); - Element element = new SAXBuilder(false).build(stream).getRootElement(); - - if (!"issues".equals(element.getName())) { - LOG.warn("Error fetching issues for: " + url + ", HTTP status code: " + method.getStatusCode()); - throw new Exception("Error fetching issues for: " + url + ", HTTP status code: " + method.getStatusCode() + - "\n" + element.getText()); + else { + path = "/repos/" + getRepoAuthor() + "/" + getRepoName() + "/issues"; } - return element.getChildren("issue"); + JsonElement response = GithubApiUtil.getRequest(getUrl(), getUsername(), getPassword(), path); + + JsonArray issuesArray; + if (noQuery) { + if (response == null || !response.isJsonArray()) { + throw errorFetchingIssues(response); + } + issuesArray = response.getAsJsonArray(); + } + else { + if (response == null || !response.isJsonObject() || !response.getAsJsonObject().has("issues")) { + throw errorFetchingIssues(response); + } + issuesArray = response.getAsJsonObject().get("issues").getAsJsonArray(); + } + + return parseTasksFromArray(issuesArray); + } + + @NotNull + private List parseTasksFromArray(JsonArray issuesArray) { + List tasks = new ArrayList(); + for (JsonElement element : issuesArray) { + Task issue = createIssue(element.getAsJsonObject()); + if (issue == null) { + LOG.warn("Couldn't parse issue from " + element); + } + else { + tasks.add(issue); + } + } + return tasks; + } + + @NotNull + private Exception errorFetchingIssues(@Nullable JsonElement response) { + return new Exception(String.format("Error fetching issues for: %s%nResponse: %s", getUrl(), response)); } @Nullable - private Task createIssue(final Element element, boolean parseComments) { - final String id = element.getChildText("number"); + private Task createIssue(JsonObject issueObject) { + final JsonElement id = issueObject.get("number"); if (id == null) { return null; } - final String summary = element.getChildText("title"); + final JsonElement summary = issueObject.get("title"); if (summary == null) { return null; } - final boolean isClosed = !"open".equals(element.getChildText("state")); - final String description = element.getChildText("body"); + JsonElement state = issueObject.get("state"); + if (state == null) { + return null; + } + final boolean isClosed = !"open".equals(state.getAsString()); + final JsonElement description = issueObject.get("body"); final Ref updated = new Ref(); final Ref created = new Ref(); try { - updated.set(PivotalTrackerRepository.parseDate(element, "updated-at")); - created.set(PivotalTrackerRepository.parseDate(element, "created-at")); + JsonElement updatedAt = issueObject.get("updated_at"); + if (updatedAt != null) { + updated.set(TaskUtil.parseDate(updatedAt.getAsString())); + } + else { + LOG.warn("Couldn't find 'updated-at' field for the issue: " + issueObject); + } + JsonElement createdAt = issueObject.get("created_at"); + if (createdAt != null) { + created.set(TaskUtil.parseDate(createdAt.getAsString())); + } + else { + LOG.warn("Couldn't find 'created-at' field for the issue: " + issueObject); + } } catch (ParseException e) { LOG.warn(e); } @@ -171,18 +195,18 @@ public class GitHubRepository extends BaseRepositoryImpl { @NotNull @Override public String getSummary() { - return summary; + return summary.getAsString(); } public String getDescription() { - return description; + return description.getAsString(); } @NotNull @Override public Comment[] getComments() { try { - return fetchComments(id); + return fetchComments(id.getAsString()); } catch (Exception e) { LOG.warn("Error fetching comments for " + id, e); } @@ -228,30 +252,58 @@ public class GitHubRepository extends BaseRepositoryImpl { } private Comment[] fetchComments(final String id) throws Exception { - final String url = buildUrl("/comments/") + "/" + id; - final HttpMethod method = doREST(url, false); - final InputStream stream = method.getResponseBodyAsStream(); - final Element element = new SAXBuilder(false).build(stream).getRootElement(); - return element.getName().equals("comments") ? createComments(element) : Comment.EMPTY_ARRAY; + String path = "/repos/" + getRepoAuthor() + "/" + getRepoName() + "/issues/" + id + "/comments"; + JsonElement response = GithubApiUtil.getRequest(getUrl(), getUsername(), getPassword(), path); + if (response == null || !response.isJsonArray()) { + throw new Exception(String.format("Couldn't get information about issue %s%nResponse: %s", id, response)); + } + return createComments(response.getAsJsonArray()); } - private static Comment[] createComments(final Element element) { + private static Comment[] createComments(final JsonArray response) { final List comments = new ArrayList(); - //noinspection unchecked - for (Element comment : (List)element.getChildren("comment")) { - final String text = comment.getChildText("body"); - if (text == null) continue; - final String author = comment.getChildText("user"); - final String gravatarId = comment.getChildText("gravatar-id"); - final Ref date = new Ref(); - try { - date.set(PivotalTrackerRepository.parseDate(comment, "created-at")); - } catch (ParseException e) { - LOG.warn(e); + + for (JsonElement element : response) { + Comment comment = parseComment(element); + if (comment != null) { + comments.add(comment); + } + else { + LOG.warn("Couldn't parse comment from " + element); } - comments.add(new GitHubComment(date.get(), author, text, gravatarId)); } - return comments.toArray(new Comment[comments.size()]); + return ArrayUtil.toObjectArray(comments, Comment.class); + } + + @Nullable + private static Comment parseComment(JsonElement element) { + JsonObject commentObject = element.getAsJsonObject(); + final JsonElement text = commentObject.get("body"); + if (text == null) { + return null; + } + JsonElement user = commentObject.get("user"); + if (user == null || !user.isJsonObject()) { + return null; + } + + final JsonElement author = user.getAsJsonObject().get("login"); + final JsonElement gravatar = user.getAsJsonObject().get("gravatar_id"); + final Ref date = new Ref(); + try { + JsonElement createdAt = commentObject.get("created_at"); + if (createdAt != null) { + date.set(TaskUtil.parseDate(createdAt.getAsString())); + } + else { + LOG.warn("Couldn't get creation date for the comment: " + element); + } + } + catch (ParseException e) { + LOG.warn(e); + } + return new GitHubComment(date.get(), author == null ? null : author.getAsString(), + text.getAsString(), gravatar == null ? null : gravatar.getAsString()); } @Nullable @@ -268,16 +320,12 @@ public class GitHubRepository extends BaseRepositoryImpl { @Override public Task findTask(String id) throws Exception { - final String realId = getRealId(id); - if (realId == null) return null; - HttpMethod method = doREST(buildUrl("/show/") + "/" + realId, false); - InputStream stream = method.getResponseBodyAsStream(); - Element element = new SAXBuilder(false).build(stream).getRootElement(); - return element.getName().equals("issue") ? createIssue(element, true) : null; - } - - private String buildUrl(final String start) { - return API_URL + "/issues" + start + getRepoAuthor() + "/" + myRepoName; + String path = "/repos/" + getRepoAuthor() + "/" + getRepoName() + "/issues/" + id; + JsonElement response = GithubApiUtil.getRequest(getUrl(), getUsername(), getPassword(), path); + if (response == null || !response.isJsonObject()) { + throw new Exception(String.format("Couldn't get information about issue %s%nResponse: %s", id, response)); + } + return createIssue(response.getAsJsonObject()); } @Override diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/github/GithubApiUtil.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/github/GithubApiUtil.java new file mode 100644 index 000000000000..8e8c4863273c --- /dev/null +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/github/GithubApiUtil.java @@ -0,0 +1,182 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.tasks.github; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.tasks.config.TaskSettings; +import com.intellij.util.net.HttpConfigurable; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpMethod; +import org.apache.commons.httpclient.UsernamePasswordCredentials; +import org.apache.commons.httpclient.auth.AuthScope; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.StringRequestEntity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; + +/** + * @author Kirill Likhodedov + */ +public class GithubApiUtil { + + public static final String DEFAULT_GITHUB_HOST = "github.com"; + + private static final Logger LOG = Logger.getInstance(GithubApiUtil.class); + + @Nullable + public static JsonElement getRequest(@NotNull String host, @NotNull String login, @NotNull String password, + @NotNull String path) throws IOException { + return request(host, login, password, path, null, false); + } + + @Nullable + public static JsonElement postRequest(@NotNull String host, @Nullable String login, @Nullable String password, + @NotNull String path, @Nullable String requestBody) throws IOException { + return request(host, login, password, path, requestBody, true); + } + + @Nullable + private static JsonElement request(@NotNull String host, @Nullable String login, @Nullable String password, + @NotNull String path, @Nullable String requestBody, boolean post) throws IOException { + HttpMethod method = null; + try { + method = doREST(host, login, password, path, requestBody, post); + String resp = method.getResponseBodyAsString(); + if (resp == null) { + LOG.info(String.format("Unexpectedly empty response: %s", resp)); + return null; + } + return parseResponse(resp); + } + finally { + if (method != null) { + method.releaseConnection(); + } + } + } + + @NotNull + private static HttpMethod doREST(@NotNull String host, @Nullable String login, @Nullable String password, @NotNull String path, + @Nullable String requestBody, final boolean post) throws IOException { + final HttpClient client = getHttpClient(login, password); + final String uri = getApiUrl(host) + path; + final HttpMethod method; + if (post) { + method = new PostMethod(uri); + if (requestBody != null) { + ((PostMethod)method).setRequestEntity(new StringRequestEntity(requestBody, "application/json", "UTF-8")); + } + } + else { + method = new GetMethod(uri); + } + + client.executeMethod(method); + return method; + } + + @NotNull + private static String removeProtocolPrefix(final String url) { + if (url.startsWith("https://")) { + return url.substring(8); + } + else if (url.startsWith("http://")) { + return url.substring(7); + } + else if (url.startsWith("git@")) { + return url.substring(4); + } + else { + return url; + } + } + + @NotNull + private static String getApiUrl(@NotNull String urlFromSettings) { + return "https://" + getApiUrlWithoutProtocol(urlFromSettings); + } + + /* + All API access is over HTTPS, and accessed from the api.github.com domain + (or through yourdomain.com/api/v3/ for enterprise). + http://developer.github.com/v3/ + */ + @NotNull + private static String getApiUrlWithoutProtocol(String urlFromSettings) { + String url = removeTrailingSlash(removeProtocolPrefix(urlFromSettings)); + final String API_PREFIX = "api."; + final String ENTERPRISE_API_SUFFIX = "/api/v3"; + + if (url.equals(DEFAULT_GITHUB_HOST)) { + return API_PREFIX + url; + } + else if (url.equals(API_PREFIX + DEFAULT_GITHUB_HOST)) { + return url; + } + else if (url.endsWith(ENTERPRISE_API_SUFFIX)) { + return url; + } + else { + return url + ENTERPRISE_API_SUFFIX; + } + } + + private static String removeTrailingSlash(String s) { + if (s.endsWith("/")) { + return s.substring(0, s.length() - 1); + } + return s; + } + + @NotNull + private static HttpClient getHttpClient(@Nullable final String login, @Nullable final String password) { + final HttpClient client = new HttpClient(); + client.getParams().setConnectionManagerTimeout(3000); + client.getParams().setSoTimeout(TaskSettings.getInstance().CONNECTION_TIMEOUT); + client.getParams().setContentCharset("UTF-8"); + // Configure proxySettings if it is required + final HttpConfigurable proxySettings = HttpConfigurable.getInstance(); + if (proxySettings.USE_HTTP_PROXY){ + client.getHostConfiguration().setProxy(proxySettings.PROXY_HOST, proxySettings.PROXY_PORT); + if (proxySettings.PROXY_AUTHENTICATION) { + client.getState().setProxyCredentials(AuthScope.ANY, new UsernamePasswordCredentials(proxySettings.PROXY_LOGIN, + proxySettings.getPlainProxyPassword())); + } + } + if (login != null && password != null) { + client.getParams().setCredentialCharset("UTF-8"); + client.getParams().setAuthenticationPreemptive(true); + client.getState().setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(login, password)); + } + return client; + } + + @NotNull + private static JsonElement parseResponse(@NotNull String githubResponse) throws IOException { + try { + return new JsonParser().parse(githubResponse); + } + catch (JsonSyntaxException jse) { + throw new IOException(String.format("Couldn't parse GitHub response:%n%s", githubResponse), jse); + } + } +} diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskUtil.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskUtil.java index 8a44e76d2716..d7ea26f4b3bb 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskUtil.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskUtil.java @@ -22,11 +22,21 @@ import com.intellij.tasks.Task; import com.intellij.tasks.TaskRepository; import org.jetbrains.annotations.Nullable; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * @author Dmitry Avdeev */ public class TaskUtil { + private static final Pattern DATE_PATTERN = Pattern.compile("(\\d\\d\\d\\d[/-]\\d\\d[/-]\\d\\d).*(\\d\\d:\\d\\d:\\d\\d).*"); + private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + public static String formatTask(Task task, String format) { return format.replace("{id}", task.getId()).replace("{number}", task.getNumber()) .replace("{project}", task.getProject()).replace("{summary}", task.getSummary()); @@ -50,4 +60,13 @@ public class TaskUtil { } return StringUtil.first(text, 60, true); } + + @Nullable + public static Date parseDate(String date) throws ParseException { + final Matcher m = DATE_PATTERN.matcher(date); + if (m.find()) { + return DATE_FORMAT.parse(m.group(1).replace('-', '/') + " " + m.group(2)); + } + return null; + } } diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/pivotal/PivotalTrackerRepository.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/pivotal/PivotalTrackerRepository.java index 962d6a1c1b7b..4e84c6c6e4fd 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/pivotal/PivotalTrackerRepository.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/pivotal/PivotalTrackerRepository.java @@ -9,6 +9,7 @@ import com.intellij.tasks.*; import com.intellij.tasks.impl.BaseRepository; import com.intellij.tasks.impl.BaseRepositoryImpl; import com.intellij.tasks.impl.SimpleComment; +import com.intellij.tasks.impl.TaskUtil; import com.intellij.util.NullableFunction; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.net.HTTPMethod; @@ -25,9 +26,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.io.InputStream; -import java.text.DateFormat; import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -41,8 +40,6 @@ import java.util.regex.Pattern; public class PivotalTrackerRepository extends BaseRepositoryImpl { private static final Logger LOG = Logger.getInstance("#com.intellij.tasks.pivotal.PivotalTrackerRepository"); private static final String API_URL = "/services/v3"; - private static final Pattern DATE_PATTERN = Pattern.compile("(\\d\\d\\d\\d[/-]\\d\\d[/-]\\d\\d).*(\\d\\d:\\d\\d:\\d\\d).*"); - private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); private Pattern myPattern; private String myProjectId; @@ -246,12 +243,9 @@ public class PivotalTrackerRepository extends BaseRepositoryImpl { } @Nullable - public static Date parseDate(final Element element, final String name) throws ParseException { - final Matcher m = DATE_PATTERN.matcher(element.getChildText(name)); - if (m.find()) { - return DATE_FORMAT.parse(m.group(1).replace('-', '/') + " " + m.group(2)); - } - return null; + private static Date parseDate(final Element element, final String name) throws ParseException { + String date = element.getChildText(name); + return TaskUtil.parseDate(date); } private HttpMethod doREST(final String request, final HTTPMethod type) throws Exception { diff --git a/plugins/tasks/tasks-core/tasks-core.iml b/plugins/tasks/tasks-core/tasks-core.iml index e09e93513452..369f3f1feeb8 100644 --- a/plugins/tasks/tasks-core/tasks-core.iml +++ b/plugins/tasks/tasks-core/tasks-core.iml @@ -37,6 +37,7 @@ + diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerBundle.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerBundle.java index d6ce8f409be6..fe7f687d0a08 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerBundle.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/DesignerBundle.java @@ -40,7 +40,9 @@ public class DesignerBundle { private static ResourceBundle getBundle() { ResourceBundle bundle = null; - if (ourBundle != null) bundle = ourBundle.get(); + if (ourBundle != null) { + bundle = ourBundle.get(); + } if (bundle == null) { bundle = ResourceBundle.getBundle(BUNDLE); ourBundle = new SoftReference(bundle); diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/actions/DesignerActionPanel.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/actions/DesignerActionPanel.java index 86c813b7cadc..24a15a36953b 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/actions/DesignerActionPanel.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/actions/DesignerActionPanel.java @@ -177,6 +177,7 @@ public class DesignerActionPanel implements DataProvider { myDynamicPopupGroup.removeAll(); } + WrapInAction.fill(myDesigner, myDynamicPopupGroup, area); MorphingAction.fill(myDesigner, myDynamicPopupGroup, area); return myPopupGroup; diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/actions/WrapInAction.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/actions/WrapInAction.java new file mode 100644 index 000000000000..e6b32d9a92c0 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/actions/WrapInAction.java @@ -0,0 +1,104 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.designer.actions; + +import com.intellij.designer.designSurface.DesignerEditorPanel; +import com.intellij.designer.designSurface.EditableArea; +import com.intellij.designer.model.MetaModel; +import com.intellij.designer.model.RadComponent; +import com.intellij.designer.model.RadLayout; +import com.intellij.designer.model.WrapInProvider; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DefaultActionGroup; +import com.intellij.util.ThrowableRunnable; + +import java.util.List; +import java.util.Set; + +/** + * @author Alexander Lobas + */ +public class WrapInAction extends AnAction { + private final DesignerEditorPanel myDesigner; + private final EditableArea myArea; + private final WrapInProvider myProvider; + private final RadComponent myParent; + private final List myComponents; + private final MetaModel myTarget; + + public WrapInAction(DesignerEditorPanel designer, + EditableArea area, + WrapInProvider provider, + RadComponent parent, + List components, + MetaModel target) { + super(target.getTag(), null, target.getIcon()); + myDesigner = designer; + myArea = area; + myProvider = provider; + myParent = parent; + myComponents = components; + myTarget = target; + } + + @Override + public void actionPerformed(AnActionEvent e) { + myDesigner.getToolProvider().execute(new ThrowableRunnable() { + @Override + public void run() throws Exception { + myArea.select(myProvider.wrapIn(myParent, myComponents, myTarget)); + } + }, "Run Wrap In action", true); + } + + public static void fill(DesignerEditorPanel designer, DefaultActionGroup group, EditableArea area) { + List selection = area.getSelection(); + if (selection.isEmpty()) { + return; + } + + Set parents = RadComponent.getParents(selection); + if (parents.size() != 1) { + return; + } + + RadComponent parent = parents.iterator().next(); + if (selection.size() > 1) { + RadLayout layout = parent.getLayout(); + if (layout != null && !layout.isWrapIn(selection)) { + return; + } + } + + WrapInProvider provider = designer.getWrapInProvider(); + if (provider == null) { + return; + } + + List models = provider.getModels(); + if (models.isEmpty()) { + return; + } + + DefaultActionGroup wrapGroup = new DefaultActionGroup("Wrap In", true); + for (MetaModel wrapModel : models) { + wrapGroup.add(new WrapInAction(designer, area, provider, parent, selection, wrapModel)); + } + + //group.add(wrapGroup); // XXX + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java index b6dd0ebf50a4..3ec787cd1d48 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java @@ -24,6 +24,7 @@ import com.intellij.designer.componentTree.TreeComponentDecorator; import com.intellij.designer.designSurface.tools.*; import com.intellij.designer.model.FindComponentVisitor; import com.intellij.designer.model.RadComponent; +import com.intellij.designer.model.WrapInProvider; import com.intellij.designer.palette.PaletteGroup; import com.intellij.designer.palette.PaletteItem; import com.intellij.designer.palette.PaletteToolWindowManager; @@ -729,6 +730,11 @@ public abstract class DesignerEditorPanel extends JPanel implements DataProvider Disposer.dispose(myProgressIcon); } + @Nullable + public WrapInProvider getWrapInProvider() { + return null; + } + public RadComponent getRootComponent() { return myRootComponent; } diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaManager.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaManager.java index a66a1c751b8b..3b06ba5944e7 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaManager.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaManager.java @@ -43,12 +43,14 @@ public abstract class MetaManager { private static final String NAME = "name"; private static final String ITEM = "item"; private static final String TAG = "tag"; + private static final String WRAP_IN = "wrap-in"; - private static final Logger LOG = Logger.getInstance("#com.intellij.designer.model.MetaManager"); + protected static final Logger LOG = Logger.getInstance("#com.intellij.designer.model.MetaManager"); private final Map myTag2Model = new HashMap(); private final Map myTarget2Model = new HashMap(); private final List myPaletteGroups = new ArrayList(); + private final List myWrapModels = new ArrayList(); private PropertyChangeSupport myPaletteChangeSupport; @@ -73,6 +75,14 @@ public abstract class MetaManager { loadGroup((Element)element); } + Element wrapInElement = rootElement.getChild(WRAP_IN); + if (wrapInElement != null) { + for (Object element : wrapInElement.getChildren(ITEM)) { + Element item = (Element)element; + myWrapModels.add(myTag2Model.get(item.getAttributeValue("tag"))); + } + } + for (Map.Entry> entry : modelToMorphing.entrySet()) { MetaModel meta = entry.getKey(); List morphingModels = new ArrayList(); @@ -101,7 +111,7 @@ public abstract class MetaManager { String target = element.getAttributeValue("class"); String tag = element.getAttributeValue(TAG); - MetaModel meta = new MetaModel(model, target, tag); + MetaModel meta = createModel(model, target, tag); String layout = element.getAttributeValue("layout"); if (layout != null) { @@ -134,35 +144,7 @@ public abstract class MetaManager { Element properties = element.getChild("properties"); if (properties != null) { - Attribute inplace = properties.getAttribute("inplace"); - if (inplace != null) { - meta.setInplaceProperties(StringUtil.split(inplace.getValue(), " ")); - } - - Attribute top = properties.getAttribute("top"); - if (top != null) { - meta.setTopProperties(StringUtil.split(top.getValue(), " ")); - } - - Attribute normal = properties.getAttribute("normal"); - if (normal != null) { - meta.setNormalProperties(StringUtil.split(normal.getValue(), " ")); - } - - Attribute important = properties.getAttribute("important"); - if (important != null) { - meta.setImportantProperties(StringUtil.split(important.getValue(), " ")); - } - - Attribute expert = properties.getAttribute("expert"); - if (expert != null) { - meta.setExpertProperties(StringUtil.split(expert.getValue(), " ")); - } - - Attribute deprecated = properties.getAttribute("deprecated"); - if (deprecated != null) { - meta.setDeprecatedProperties(StringUtil.split(deprecated.getValue(), " ")); - } + loadProperties(meta, properties); } Element morphing = element.getChild("morphing"); @@ -170,6 +152,8 @@ public abstract class MetaManager { modelToMorphing.put(meta, StringUtil.split(morphing.getAttribute("to").getValue(), " ")); } + loadOther(meta, element); + if (tag != null) { myTag2Model.put(tag, meta); } @@ -179,6 +163,45 @@ public abstract class MetaManager { } } + protected MetaModel createModel(Class model, String target, String tag) throws Exception { + return new MetaModel(model, target, tag); + } + + protected void loadProperties(MetaModel meta, Element properties) throws Exception { + Attribute inplace = properties.getAttribute("inplace"); + if (inplace != null) { + meta.setInplaceProperties(StringUtil.split(inplace.getValue(), " ")); + } + + Attribute top = properties.getAttribute("top"); + if (top != null) { + meta.setTopProperties(StringUtil.split(top.getValue(), " ")); + } + + Attribute normal = properties.getAttribute("normal"); + if (normal != null) { + meta.setNormalProperties(StringUtil.split(normal.getValue(), " ")); + } + + Attribute important = properties.getAttribute("important"); + if (important != null) { + meta.setImportantProperties(StringUtil.split(important.getValue(), " ")); + } + + Attribute expert = properties.getAttribute("expert"); + if (expert != null) { + meta.setExpertProperties(StringUtil.split(expert.getValue(), " ")); + } + + Attribute deprecated = properties.getAttribute("deprecated"); + if (deprecated != null) { + meta.setDeprecatedProperties(StringUtil.split(deprecated.getValue(), " ")); + } + } + + protected void loadOther(MetaModel meta, Element element) throws Exception { + } + private void loadGroup(Element element) throws Exception { PaletteGroup group = new PaletteGroup(element.getAttributeValue(NAME)); @@ -209,6 +232,10 @@ public abstract class MetaManager { return myTarget2Model.get(target); } + public List getWrapInModels() { + return myWrapModels; + } + public List getPaletteGroups() { return myPaletteGroups; } diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaModel.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaModel.java index 15769877d2a2..1c55f90cbba6 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaModel.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/MetaModel.java @@ -35,8 +35,8 @@ public class MetaModel { private final String myTag; private DefaultPaletteItem myPaletteItem; private String myTitle; - private String myIconPath; - private Icon myIcon; + protected String myIconPath; + protected Icon myIcon; private String myCreation; private boolean myDelete = true; private List myInplaceProperties = Collections.emptyList(); diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java index c5ceb44c64ab..72ae7bd8ad26 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadComponent.java @@ -265,6 +265,11 @@ public abstract class RadComponent { return null; } + @Nullable + public RadComponent wrapIn(MetaModel target) throws Exception { + return null; + } + ////////////////////////////////////////////////////////////////////////////////////////// // // Utils diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadLayout.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadLayout.java index d0c8f518da47..46feaa509946 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadLayout.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/RadLayout.java @@ -62,4 +62,8 @@ public abstract class RadLayout { public ICaption getCaption(RadComponent component) { return null; } + + public boolean isWrapIn(List components) { + return true; + } } \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/WrapInProvider.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/WrapInProvider.java new file mode 100644 index 000000000000..7ff3aa8a06fd --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/model/WrapInProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.designer.model; + +import java.util.List; + +/** + * @author Alexander Lobas + */ +public abstract class WrapInProvider { + private final List myModels; + + public WrapInProvider(MetaManager metaManager) { + myModels = metaManager.getWrapInModels(); + } + + public List getModels() { + return myModels; + } + + public abstract RadComponent wrapIn(T parent, List components, MetaModel target) throws Exception; +} \ No newline at end of file diff --git a/resources-en/src/fileTemplates/default.html b/resources-en/src/fileTemplates/default.html index 1aeab4531d8e..1611291258b1 100644 --- a/resources-en/src/fileTemplates/default.html +++ b/resources-en/src/fileTemplates/default.html @@ -62,6 +62,11 @@   current minute + + ${PROJECT_NAME} +   + the name of the current project + \ No newline at end of file diff --git a/resources-en/src/fileTemplates/includes/File Header.java.html b/resources-en/src/fileTemplates/includes/File Header.java.html index 194c35846877..91afe6f619ea 100644 --- a/resources-en/src/fileTemplates/includes/File Header.java.html +++ b/resources-en/src/fileTemplates/includes/File Header.java.html @@ -58,6 +58,11 @@   current minute + + ${PROJECT_NAME} +   + the name of the current project + \ No newline at end of file diff --git a/resources-en/src/fileTemplates/includes/default.html b/resources-en/src/fileTemplates/includes/default.html index deca6c3d2351..98339f55aeea 100644 --- a/resources-en/src/fileTemplates/includes/default.html +++ b/resources-en/src/fileTemplates/includes/default.html @@ -59,6 +59,11 @@   current minute + + ${PROJECT_NAME} +   + the name of the current project + \ No newline at end of file diff --git a/resources-en/src/fileTemplates/internal/Class.java.html b/resources-en/src/fileTemplates/internal/Class.java.html index 8e886b640a72..0d7c83af7352 100644 --- a/resources-en/src/fileTemplates/internal/Class.java.html +++ b/resources-en/src/fileTemplates/internal/Class.java.html @@ -65,6 +65,11 @@   current minute + + ${PROJECT_NAME} +   + the name of the current project + \ No newline at end of file diff --git a/resources-en/src/fileTemplates/internal/Interface.java.html b/resources-en/src/fileTemplates/internal/Interface.java.html index 250e2c92b37b..fe0bdae1833b 100644 --- a/resources-en/src/fileTemplates/internal/Interface.java.html +++ b/resources-en/src/fileTemplates/internal/Interface.java.html @@ -65,6 +65,11 @@   current minute + + ${PROJECT_NAME} +   + the name of the current project + \ No newline at end of file